if_pflog.c revision 1.16 1 /* $NetBSD: if_pflog.c,v 1.16 2010/01/19 22:08:00 pooka Exp $ */
2 /* $OpenBSD: if_pflog.c,v 1.24 2007/05/26 17:13:30 jason Exp $ */
3
4 /*
5 * The authors of this code are John Ioannidis (ji (at) tla.org),
6 * Angelos D. Keromytis (kermit (at) csd.uch.gr) and
7 * Niels Provos (provos (at) physnet.uni-hamburg.de).
8 *
9 * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
10 * in November 1995.
11 *
12 * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
13 * by Angelos D. Keromytis.
14 *
15 * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
16 * and Niels Provos.
17 *
18 * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis
19 * and Niels Provos.
20 * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos.
21 *
22 * Permission to use, copy, and modify this software with or without fee
23 * is hereby granted, provided that this entire notice is included in
24 * all copies of any software which is or includes a copy or
25 * modification of this software.
26 * You may use this code under the GNU public license if you so wish. Please
27 * contribute changes back to the authors under this freer than GPL license
28 * so that we may further the use of strong encryption without limitations to
29 * all.
30 *
31 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
32 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
33 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
34 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
35 * PURPOSE.
36 */
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: if_pflog.c,v 1.16 2010/01/19 22:08:00 pooka Exp $");
40
41 #ifdef _KERNEL_OPT
42 #include "opt_inet.h"
43 #endif
44
45 #include "pflog.h"
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/mbuf.h>
50 #include <sys/proc.h>
51 #include <sys/socket.h>
52 #include <sys/ioctl.h>
53
54 #include <net/if.h>
55 #include <net/if_types.h>
56 #include <net/route.h>
57 #include <net/bpf.h>
58
59 #ifdef INET
60 #include <netinet/in.h>
61 #include <netinet/in_var.h>
62 #include <netinet/in_systm.h>
63 #include <netinet/ip.h>
64 #endif
65
66 #ifdef INET6
67 #ifndef INET
68 #include <netinet/in.h>
69 #endif
70 #include <netinet6/nd6.h>
71 #endif /* INET6 */
72
73 #include <net/pfvar.h>
74 #include <net/if_pflog.h>
75
76 #define PFLOGMTU (32768 + MHLEN + MLEN)
77
78 #ifdef PFLOGDEBUG
79 #define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0)
80 #else
81 #define DPRINTF(x)
82 #endif
83
84 void pflogattach(int);
85 int pflogoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
86 struct rtentry *);
87 int pflogioctl(struct ifnet *, u_long, void *);
88 void pflogstart(struct ifnet *);
89 int pflog_clone_create(struct if_clone *, int);
90 int pflog_clone_destroy(struct ifnet *);
91
92 LIST_HEAD(, pflog_softc) pflogif_list;
93 struct if_clone pflog_cloner =
94 IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy);
95
96 struct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */
97
98 void
99 pflogattach(int npflog)
100 {
101 int i;
102
103 LIST_INIT(&pflogif_list);
104 for (i = 0; i < PFLOGIFS_MAX; i++)
105 pflogifs[i] = NULL;
106 if_clone_attach(&pflog_cloner);
107 }
108
109 int
110 pflog_clone_create(struct if_clone *ifc, int unit)
111 {
112 struct ifnet *ifp;
113 struct pflog_softc *pflogif;
114 int s;
115
116 if (unit >= PFLOGIFS_MAX)
117 return (EINVAL);
118
119 if ((pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
120 return (ENOMEM);
121
122 pflogif->sc_unit = unit;
123 ifp = &pflogif->sc_if;
124 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit);
125 ifp->if_softc = pflogif;
126 ifp->if_mtu = PFLOGMTU;
127 ifp->if_ioctl = pflogioctl;
128 ifp->if_output = pflogoutput;
129 ifp->if_start = pflogstart;
130 ifp->if_type = IFT_PFLOG;
131 #ifndef __NetBSD__
132 ifp->if_snd.ifq_maxlen = ifqmaxlen;
133 #endif /* !__NetBSD__ */
134 ifp->if_hdrlen = PFLOG_HDRLEN;
135 if_attach(ifp);
136 if_alloc_sadl(ifp);
137
138 #ifdef __NetBSD__
139 bpf_ops->bpf_attach(ifp, DLT_PFLOG, PFLOG_HDRLEN, &ifp->if_bpf);
140 #else
141 bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN);
142 #endif /* !__NetBSD__ */
143
144 s = splnet();
145 LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list);
146 pflogifs[unit] = ifp;
147 splx(s);
148
149 return (0);
150 }
151
152 int
153 pflog_clone_destroy(struct ifnet *ifp)
154 {
155 struct pflog_softc *pflogif = ifp->if_softc;
156 int s;
157
158 s = splnet();
159 pflogifs[pflogif->sc_unit] = NULL;
160 LIST_REMOVE(pflogif, sc_list);
161 splx(s);
162
163 bpf_ops->bpf_detach(ifp);
164 if_detach(ifp);
165 free(pflogif, M_DEVBUF);
166 return (0);
167 }
168
169 /*
170 * Start output on the pflog interface.
171 */
172 void
173 pflogstart(struct ifnet *ifp)
174 {
175 struct mbuf *m;
176 int s;
177
178 for (;;) {
179 s = splnet();
180 IF_DROP(&ifp->if_snd);
181 IF_DEQUEUE(&ifp->if_snd, m);
182 splx(s);
183
184 if (m == NULL)
185 return;
186 else
187 m_freem(m);
188 }
189 }
190
191 int
192 pflogoutput(struct ifnet *ifp, struct mbuf *m,
193 const struct sockaddr *dst, struct rtentry *rt)
194 {
195 m_freem(m);
196 return (0);
197 }
198
199 /* ARGSUSED */
200 int
201 pflogioctl(struct ifnet *ifp, u_long cmd, void *data)
202 {
203 int error = 0;
204
205 switch (cmd) {
206 case SIOCSIFFLAGS:
207 if ((error = ifioctl_common(ifp, cmd, data)) != 0)
208 break;
209 /*FALLTHROUGH*/
210 case SIOCINITIFADDR:
211 case SIOCAIFADDR:
212 case SIOCSIFDSTADDR:
213 if (ifp->if_flags & IFF_UP)
214 ifp->if_flags |= IFF_RUNNING;
215 else
216 ifp->if_flags &= ~IFF_RUNNING;
217 break;
218 default:
219 error = ifioctl_common(ifp, cmd, data);
220 }
221
222 return error;
223 }
224
225 int
226 pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
227 u_int8_t reason, struct pf_rule *rm, struct pf_rule *am,
228 struct pf_ruleset *ruleset, struct pf_pdesc *pd)
229 {
230 struct ifnet *ifn;
231 struct pfloghdr hdr;
232
233 if (kif == NULL || m == NULL || rm == NULL || pd == NULL)
234 return (-1);
235
236 if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf)
237 return (0);
238
239 bzero(&hdr, sizeof(hdr));
240 hdr.length = PFLOG_REAL_HDRLEN;
241 hdr.af = af;
242 hdr.action = rm->action;
243 hdr.reason = reason;
244 memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname));
245
246 if (am == NULL) {
247 hdr.rulenr = htonl(rm->nr);
248 hdr.subrulenr = -1;
249 } else {
250 hdr.rulenr = htonl(am->nr);
251 hdr.subrulenr = htonl(rm->nr);
252 if (ruleset != NULL && ruleset->anchor != NULL)
253 strlcpy(hdr.ruleset, ruleset->anchor->name,
254 sizeof(hdr.ruleset));
255 }
256 if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done)
257 pd->lookup.done = pf_socket_lookup(dir, pd);
258 if (pd->lookup.done > 0) {
259 hdr.uid = pd->lookup.uid;
260 hdr.pid = pd->lookup.pid;
261 } else {
262 hdr.uid = UID_MAX;
263 hdr.pid = NO_PID;
264 }
265 hdr.rule_uid = rm->cuid;
266 hdr.rule_pid = rm->cpid;
267 hdr.dir = dir;
268
269 #ifdef INET
270 if (af == AF_INET && dir == PF_OUT) {
271 struct ip *ip;
272
273 ip = mtod(m, struct ip *);
274 ip->ip_sum = 0;
275 ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
276 }
277 #endif /* INET */
278
279 ifn->if_opackets++;
280 ifn->if_obytes += m->m_pkthdr.len;
281
282 #ifdef __NetBSD__
283 bpf_ops->bpf_mtap2(ifn->if_bpf, &hdr, PFLOG_HDRLEN, m);
284 #else
285 bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m,
286 BPF_DIRECTION_OUT);
287 #endif /* !__NetBSD__ */
288
289
290 return (0);
291 }
292