Line data Source code
1 : /* $OpenBSD: if_pflog.c,v 1.81 2018/01/09 15:24:24 bluhm Exp $ */
2 : /*
3 : * The authors of this code are John Ioannidis (ji@tla.org),
4 : * Angelos D. Keromytis (kermit@csd.uch.gr) and
5 : * Niels Provos (provos@physnet.uni-hamburg.de).
6 : *
7 : * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
8 : * in November 1995.
9 : *
10 : * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
11 : * by Angelos D. Keromytis.
12 : *
13 : * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
14 : * and Niels Provos.
15 : *
16 : * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis
17 : * and Niels Provos.
18 : * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos.
19 : * Copyright (c) 2002 - 2010 Henning Brauer
20 : *
21 : * Permission to use, copy, and modify this software with or without fee
22 : * is hereby granted, provided that this entire notice is included in
23 : * all copies of any software which is or includes a copy or
24 : * modification of this software.
25 : * You may use this code under the GNU public license if you so wish. Please
26 : * contribute changes back to the authors under this freer than GPL license
27 : * so that we may further the use of strong encryption without limitations to
28 : * all.
29 : *
30 : * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
31 : * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
32 : * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
33 : * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
34 : * PURPOSE.
35 : */
36 :
37 : #include "bpfilter.h"
38 : #include "pflog.h"
39 :
40 : #include <sys/param.h>
41 : #include <sys/systm.h>
42 : #include <sys/mbuf.h>
43 : #include <sys/proc.h>
44 : #include <sys/socket.h>
45 : #include <sys/stdint.h>
46 : #include <sys/ioctl.h>
47 :
48 : #include <net/if.h>
49 : #include <net/if_var.h>
50 : #include <net/if_types.h>
51 : #include <net/bpf.h>
52 :
53 : #include <netinet/in.h>
54 : #include <netinet/ip.h>
55 : #include <netinet/ip_icmp.h>
56 : #include <netinet/tcp.h>
57 : #include <netinet/udp.h>
58 :
59 : #ifdef INET6
60 : #include <netinet/ip6.h>
61 : #include <netinet/icmp6.h>
62 : #endif /* INET6 */
63 :
64 : #include <net/pfvar.h>
65 : #include <net/pfvar_priv.h>
66 : #include <net/if_pflog.h>
67 :
68 : #define PFLOGMTU (32768 + MHLEN + MLEN)
69 :
70 : #ifdef PFLOGDEBUG
71 : #define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0)
72 : #else
73 : #define DPRINTF(x)
74 : #endif
75 :
76 : void pflogattach(int);
77 : int pflogifs_resize(size_t);
78 : int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
79 : struct rtentry *);
80 : int pflogioctl(struct ifnet *, u_long, caddr_t);
81 : void pflogstart(struct ifnet *);
82 : int pflog_clone_create(struct if_clone *, int);
83 : int pflog_clone_destroy(struct ifnet *);
84 : void pflog_bpfcopy(const void *, void *, size_t);
85 :
86 : struct if_clone pflog_cloner =
87 : IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy);
88 :
89 : int npflogifs = 0;
90 : struct ifnet **pflogifs = NULL; /* for fast access */
91 : struct mbuf *pflog_mhdr = NULL, *pflog_mptr = NULL;
92 :
93 : void
94 0 : pflogattach(int npflog)
95 : {
96 0 : if (pflog_mhdr == NULL)
97 0 : if ((pflog_mhdr = m_get(M_DONTWAIT, MT_HEADER)) == NULL)
98 0 : panic("pflogattach: no mbuf");
99 0 : if (pflog_mptr == NULL)
100 0 : if ((pflog_mptr = m_get(M_DONTWAIT, MT_DATA)) == NULL)
101 0 : panic("pflogattach: no mbuf");
102 0 : if_clone_attach(&pflog_cloner);
103 0 : }
104 :
105 : int
106 0 : pflogifs_resize(size_t n)
107 : {
108 : struct ifnet **p;
109 : int i;
110 :
111 0 : NET_ASSERT_LOCKED();
112 :
113 0 : if (n > SIZE_MAX / sizeof(*p))
114 0 : return (EINVAL);
115 0 : if (n == 0)
116 0 : p = NULL;
117 : else
118 0 : if ((p = mallocarray(n, sizeof(*p), M_DEVBUF,
119 0 : M_NOWAIT|M_ZERO)) == NULL)
120 0 : return (ENOMEM);
121 0 : for (i = 0; i < n; i++)
122 0 : if (i < npflogifs)
123 0 : p[i] = pflogifs[i];
124 : else
125 0 : p[i] = NULL;
126 :
127 0 : if (pflogifs)
128 0 : free(pflogifs, M_DEVBUF, 0);
129 0 : pflogifs = p;
130 0 : npflogifs = n;
131 0 : return (0);
132 0 : }
133 :
134 : int
135 0 : pflog_clone_create(struct if_clone *ifc, int unit)
136 : {
137 : struct ifnet *ifp;
138 : struct pflog_softc *pflogif;
139 :
140 0 : pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_WAITOK|M_ZERO);
141 0 : pflogif->sc_unit = unit;
142 0 : ifp = &pflogif->sc_if;
143 0 : snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit);
144 0 : ifp->if_softc = pflogif;
145 0 : ifp->if_mtu = PFLOGMTU;
146 0 : ifp->if_ioctl = pflogioctl;
147 0 : ifp->if_output = pflogoutput;
148 0 : ifp->if_start = pflogstart;
149 0 : ifp->if_xflags = IFXF_CLONED;
150 0 : ifp->if_type = IFT_PFLOG;
151 0 : IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
152 0 : ifp->if_hdrlen = PFLOG_HDRLEN;
153 0 : if_attach(ifp);
154 0 : if_alloc_sadl(ifp);
155 :
156 : #if NBPFILTER > 0
157 0 : bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN);
158 : #endif
159 :
160 0 : NET_LOCK();
161 0 : if (unit + 1 > npflogifs && pflogifs_resize(unit + 1) != 0) {
162 0 : NET_UNLOCK();
163 0 : return (ENOMEM);
164 : }
165 0 : pflogifs[unit] = ifp;
166 0 : NET_UNLOCK();
167 :
168 0 : return (0);
169 0 : }
170 :
171 : int
172 0 : pflog_clone_destroy(struct ifnet *ifp)
173 : {
174 0 : struct pflog_softc *pflogif = ifp->if_softc;
175 : int i;
176 :
177 0 : NET_LOCK();
178 0 : pflogifs[pflogif->sc_unit] = NULL;
179 0 : for (i = npflogifs; i > 0 && pflogifs[i - 1] == NULL; i--)
180 : ; /* nothing */
181 0 : if (i < npflogifs)
182 0 : pflogifs_resize(i); /* error harmless here */
183 0 : NET_UNLOCK();
184 :
185 0 : if_detach(ifp);
186 0 : free(pflogif, M_DEVBUF, 0);
187 0 : return (0);
188 : }
189 :
190 : /*
191 : * Start output on the pflog interface.
192 : */
193 : void
194 0 : pflogstart(struct ifnet *ifp)
195 : {
196 0 : IFQ_PURGE(&ifp->if_snd);
197 0 : }
198 :
199 : int
200 0 : pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
201 : struct rtentry *rt)
202 : {
203 0 : m_freem(m); /* drop packet */
204 0 : return (EAFNOSUPPORT);
205 : }
206 :
207 : int
208 0 : pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
209 : {
210 0 : switch (cmd) {
211 : case SIOCSIFFLAGS:
212 0 : if (ifp->if_flags & IFF_UP)
213 0 : ifp->if_flags |= IFF_RUNNING;
214 : else
215 0 : ifp->if_flags &= ~IFF_RUNNING;
216 : break;
217 : default:
218 0 : return (ENOTTY);
219 : }
220 :
221 0 : return (0);
222 0 : }
223 :
224 : int
225 0 : pflog_packet(struct pf_pdesc *pd, u_int8_t reason, struct pf_rule *rm,
226 : struct pf_rule *am, struct pf_ruleset *ruleset, struct pf_rule *trigger)
227 : {
228 : #if NBPFILTER > 0
229 : struct ifnet *ifn;
230 0 : struct pfloghdr hdr;
231 :
232 0 : if (rm == NULL || pd == NULL || pd->kif == NULL || pd->m == NULL)
233 0 : return (-1);
234 0 : if (trigger == NULL)
235 0 : trigger = rm;
236 :
237 0 : if (trigger->logif >= npflogifs || (ifn = pflogifs[trigger->logif]) ==
238 0 : NULL || !ifn->if_bpf)
239 0 : return (0);
240 :
241 0 : bzero(&hdr, sizeof(hdr));
242 0 : hdr.length = PFLOG_REAL_HDRLEN;
243 0 : hdr.action = rm->action;
244 0 : hdr.reason = reason;
245 0 : memcpy(hdr.ifname, pd->kif->pfik_name, sizeof(hdr.ifname));
246 :
247 0 : if (am == NULL) {
248 0 : hdr.rulenr = htonl(rm->nr);
249 0 : hdr.subrulenr = -1;
250 0 : } else {
251 0 : hdr.rulenr = htonl(am->nr);
252 0 : hdr.subrulenr = htonl(rm->nr);
253 0 : if (ruleset != NULL && ruleset->anchor != NULL)
254 0 : strlcpy(hdr.ruleset, ruleset->anchor->name,
255 : sizeof(hdr.ruleset));
256 : }
257 0 : if (trigger->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done)
258 0 : pd->lookup.done = pf_socket_lookup(pd);
259 0 : if (pd->lookup.done > 0) {
260 0 : hdr.uid = pd->lookup.uid;
261 0 : hdr.pid = pd->lookup.pid;
262 0 : } else {
263 0 : hdr.uid = UID_MAX;
264 0 : hdr.pid = NO_PID;
265 : }
266 0 : hdr.rule_uid = rm->cuid;
267 0 : hdr.rule_pid = rm->cpid;
268 0 : hdr.dir = pd->dir;
269 :
270 0 : PF_ACPY(&hdr.saddr, &pd->nsaddr, pd->naf);
271 0 : PF_ACPY(&hdr.daddr, &pd->ndaddr, pd->naf);
272 0 : hdr.af = pd->af;
273 0 : hdr.naf = pd->naf;
274 0 : hdr.sport = pd->nsport;
275 0 : hdr.dport = pd->ndport;
276 :
277 0 : ifn->if_opackets++;
278 0 : ifn->if_obytes += pd->m->m_pkthdr.len;
279 :
280 0 : bpf_mtap_hdr(ifn->if_bpf, (caddr_t)&hdr, PFLOG_HDRLEN, pd->m,
281 : BPF_DIRECTION_OUT, pflog_bpfcopy);
282 : #endif
283 :
284 0 : return (0);
285 0 : }
286 :
287 : void
288 0 : pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len)
289 : {
290 : struct mbuf *m, *mp, *mhdr, *mptr;
291 : struct pfloghdr *pfloghdr;
292 : u_int count;
293 : u_char *dst, *mdst;
294 0 : int afto, hlen, mlen, off;
295 :
296 0 : struct pf_pdesc pd;
297 0 : struct pf_addr osaddr, odaddr;
298 : u_int16_t osport = 0, odport = 0;
299 : u_int8_t proto = 0;
300 :
301 0 : m = (struct mbuf *)src_arg;
302 : dst = dst_arg;
303 :
304 0 : mhdr = pflog_mhdr;
305 0 : mptr = pflog_mptr;
306 :
307 0 : if (m == NULL)
308 0 : panic("pflog_bpfcopy got no mbuf");
309 :
310 : /* first mbuf holds struct pfloghdr */
311 0 : pfloghdr = mtod(m, struct pfloghdr *);
312 0 : afto = pfloghdr->af != pfloghdr->naf;
313 0 : count = min(m->m_len, len);
314 0 : bcopy(pfloghdr, dst, count);
315 0 : pfloghdr = (struct pfloghdr *)dst;
316 0 : dst += count;
317 0 : len -= count;
318 0 : m = m->m_next;
319 :
320 0 : if (len <= 0)
321 0 : return;
322 :
323 : /* second mbuf is pkthdr */
324 0 : if (m == NULL)
325 0 : panic("no second mbuf");
326 :
327 : /*
328 : * temporary mbuf will hold an ip/ip6 header and 8 bytes
329 : * of the protocol header
330 : */
331 0 : m_inithdr(mhdr);
332 0 : mhdr->m_len = 0; /* XXX not done in m_inithdr() */
333 :
334 : #ifdef INET6
335 : /* offset for a new header */
336 0 : if (afto && pfloghdr->af == AF_INET)
337 0 : mhdr->m_data += sizeof(struct ip6_hdr) -
338 : sizeof(struct ip);
339 : #endif /* INET6 */
340 :
341 0 : mdst = mtod(mhdr, char *);
342 0 : switch (pfloghdr->af) {
343 : case AF_INET: {
344 : struct ip *h;
345 :
346 0 : if (m->m_pkthdr.len < sizeof(*h))
347 0 : goto copy;
348 0 : m_copydata(m, 0, sizeof(*h), mdst);
349 0 : h = (struct ip *)mdst;
350 0 : hlen = h->ip_hl << 2;
351 0 : if (hlen > sizeof(*h) && (m->m_pkthdr.len >= hlen))
352 0 : m_copydata(m, sizeof(*h), hlen - sizeof(*h),
353 0 : mdst + sizeof(*h));
354 0 : break;
355 : }
356 : #ifdef INET6
357 : case AF_INET6: {
358 : struct ip6_hdr *h;
359 :
360 0 : if (m->m_pkthdr.len < sizeof(*h))
361 0 : goto copy;
362 : hlen = sizeof(struct ip6_hdr);
363 0 : m_copydata(m, 0, hlen, mdst);
364 0 : h = (struct ip6_hdr *)mdst;
365 0 : proto = h->ip6_nxt;
366 0 : break;
367 : }
368 : #endif /* INET6 */
369 : default:
370 : /* shouldn't happen ever :-) */
371 : goto copy;
372 : }
373 :
374 0 : if (m->m_pkthdr.len < hlen + 8 && proto != IPPROTO_NONE)
375 : goto copy;
376 0 : else if (proto != IPPROTO_NONE) {
377 : /* copy 8 bytes of the protocol header */
378 0 : m_copydata(m, hlen, 8, mdst + hlen);
379 : hlen += 8;
380 0 : }
381 :
382 0 : mhdr->m_len += hlen;
383 0 : mhdr->m_pkthdr.len = mhdr->m_len;
384 :
385 : /* create a chain mhdr -> mptr, mptr->m_data = (m->m_data+hlen) */
386 0 : mp = m_getptr(m, hlen, &off);
387 0 : if (mp != NULL) {
388 0 : bcopy(mp, mptr, sizeof(*mptr));
389 0 : mptr->m_data += off;
390 0 : mptr->m_len -= off;
391 0 : mptr->m_flags &= ~M_PKTHDR;
392 0 : mhdr->m_next = mptr;
393 0 : mhdr->m_pkthdr.len += m->m_pkthdr.len - hlen;
394 0 : }
395 :
396 : /*
397 : * Rewrite addresses if needed. Reason pointer must be NULL to avoid
398 : * counting the packet here again.
399 : */
400 0 : if (pf_setup_pdesc(&pd, pfloghdr->af, pfloghdr->dir, NULL,
401 0 : mhdr, NULL) != PF_PASS)
402 : goto copy;
403 0 : pd.naf = pfloghdr->naf;
404 :
405 0 : PF_ACPY(&osaddr, pd.src, pd.af);
406 0 : PF_ACPY(&odaddr, pd.dst, pd.af);
407 0 : if (pd.sport)
408 0 : osport = *pd.sport;
409 0 : if (pd.dport)
410 0 : odport = *pd.dport;
411 :
412 0 : if (pd.virtual_proto != PF_VPROTO_FRAGMENT &&
413 0 : (pfloghdr->rewritten = pf_translate(&pd, &pfloghdr->saddr,
414 0 : pfloghdr->sport, &pfloghdr->daddr, pfloghdr->dport, 0,
415 0 : pfloghdr->dir))) {
416 0 : m_copyback(pd.m, pd.off, min(pd.m->m_len - pd.off, pd.hdrlen),
417 0 : &pd.hdr, M_NOWAIT);
418 : #ifdef INET6
419 0 : if (afto) {
420 0 : PF_ACPY(&pd.nsaddr, &pfloghdr->saddr, pd.naf);
421 0 : PF_ACPY(&pd.ndaddr, &pfloghdr->daddr, pd.naf);
422 0 : }
423 : #endif /* INET6 */
424 0 : PF_ACPY(&pfloghdr->saddr, &osaddr, pd.af);
425 0 : PF_ACPY(&pfloghdr->daddr, &odaddr, pd.af);
426 0 : pfloghdr->sport = osport;
427 0 : pfloghdr->dport = odport;
428 0 : }
429 :
430 0 : pd.tot_len = min(pd.tot_len, len);
431 0 : pd.tot_len -= pd.m->m_data - pd.m->m_pktdat;
432 :
433 : #ifdef INET6
434 0 : if (afto && pfloghdr->rewritten)
435 0 : pf_translate_af(&pd);
436 : #endif /* INET6 */
437 :
438 0 : m = pd.m;
439 : copy:
440 0 : mlen = min(m->m_pkthdr.len, len);
441 0 : m_copydata(m, 0, mlen, dst);
442 0 : len -= mlen;
443 0 : if (len > 0)
444 0 : bzero(dst + mlen, len);
445 0 : }
|