pf: Update packet filter to the version that comes with OpenBSD 4.1
[dragonfly.git] / sys / net / pf / if_pflog.c
1 /*      $FreeBSD: src/sys/contrib/pf/net/if_pflog.c,v 1.9 2004/06/22 20:13:24 brooks Exp $      */
2 /*      $OpenBSD: if_pflog.c,v 1.11 2003/12/31 11:18:25 cedric Exp $    */
3 /*      $DragonFly: src/sys/net/pf/if_pflog.c,v 1.6 2006/12/22 23:44:57 swildner Exp $ */
4 /*      $OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto Exp $      */
5 /*
6  * The authors of this code are John Ioannidis (ji@tla.org),
7  * Angelos D. Keromytis (kermit@csd.uch.gr) and 
8  * Niels Provos (provos@physnet.uni-hamburg.de).
9  *
10  * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 
11  * in November 1995.
12  *
13  * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
14  * by Angelos D. Keromytis.
15  *
16  * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
17  * and Niels Provos.
18  *
19  * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis
20  * and Niels Provos.
21  * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos.
22  *
23  * Copyright (c) 2004 The DragonFly Project.  All rights reserved.
24  *
25  * Permission to use, copy, and modify this software with or without fee
26  * is hereby granted, provided that this entire notice is included in
27  * all copies of any software which is or includes a copy or
28  * modification of this software. 
29  * You may use this code under the GNU public license if you so wish. Please
30  * contribute changes back to the authors under this freer than GPL license
31  * so that we may further the use of strong encryption without limitations to
32  * all.
33  *
34  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
35  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
36  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
37  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
38  * PURPOSE.
39  */
40
41 #include "opt_inet.h"
42 #include "opt_inet6.h"
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/in_cksum.h>
47 #include <sys/mbuf.h>
48 #include <sys/proc.h>
49 #include <sys/socket.h>
50 #include <sys/kernel.h>
51 #include <sys/malloc.h>
52 #include <sys/module.h>
53 #include <sys/sockio.h>
54 #include <sys/thread2.h>
55 #include <vm/vm_zone.h>
56
57 #include <net/if.h>
58 #include <net/if_types.h>
59 #include <net/route.h>
60 #include <net/bpf.h>
61
62 #ifdef  INET
63 #include <netinet/in.h>
64 #include <netinet/in_var.h>
65 #include <netinet/in_systm.h>
66 #include <netinet/ip.h>
67 #endif
68
69 #ifdef INET6
70 #ifndef INET
71 #include <netinet/in.h>
72 #endif
73 #include <netinet6/nd6.h>
74 #endif /* INET6 */
75
76 #include <net/pf/pfvar.h>
77 #include <net/pf/if_pflog.h>
78
79 #define PFLOGNAME       "pflog"
80
81 #define PFLOGMTU        (32768 + MHLEN + MLEN)
82
83 #ifdef PFLOGDEBUG
84 #define DPRINTF(x)    do { if (pflogdebug) kprintf x ; } while (0)
85 #else
86 #define DPRINTF(x)
87 #endif
88
89 void    pflogattach(int);
90 int     pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
91                        struct rtentry *);
92 int     pflogioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
93 void    pflogrtrequest(int, struct rtentry *, struct sockaddr *);
94 void    pflogstart(struct ifnet *);
95
96 int     pflog_clone_create(struct if_clone *, int, caddr_t);
97 void pflog_clone_destroy(struct ifnet *);
98
99 LIST_HEAD(, pflog_softc)        pflogif_list;
100 struct if_clone pflog_cloner =
101     IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy, 1, 1);
102
103 struct ifnet    *pflogifs[PFLOGIFS_MAX];        /* for fast access */
104
105 void
106 pflogattach(int npflog)
107 {
108         int     i;
109         LIST_INIT(&pflogif_list);
110         for (i = 0; i < PFLOGIFS_MAX; i++)
111                 pflogifs[i] = NULL;
112         (void) pflog_clone_create(&pflog_cloner, 0, NULL);
113         if_clone_attach(&pflog_cloner);
114 }
115
116 int
117 pflog_clone_create(struct if_clone *ifc, int unit, caddr_t param __unused)
118 {
119         struct ifnet *ifp;
120         struct pflog_softc *pflogif;
121
122         if (unit >= PFLOGIFS_MAX)
123                 return (EINVAL);
124
125         if ((pflogif = kmalloc(sizeof(*pflogif), M_DEVBUF, M_WAITOK)) == NULL)
126                 return (ENOMEM);
127         bzero(pflogif, sizeof(*pflogif));
128
129         pflogif->sc_unit = unit;
130         ifp = &pflogif->sc_if;
131         ksnprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit);
132         ifp->if_softc = pflogif;
133         ifp->if_mtu = PFLOGMTU;
134         ifp->if_ioctl = pflogioctl;
135         ifp->if_output = pflogoutput;
136         ifp->if_start = pflogstart;
137         ifp->if_type = IFT_PFLOG;
138         ifp->if_snd.ifq_maxlen = ifqmaxlen;
139         ifp->if_hdrlen = PFLOG_HDRLEN;
140         if_attach(ifp, NULL);
141
142         bpfattach(&pflogif->sc_if, DLT_PFLOG, PFLOG_HDRLEN);
143
144         crit_enter();
145         LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list);
146         pflogifs[unit] = ifp;
147         crit_exit();
148
149         return (0);
150 }
151
152 void
153 pflog_clone_destroy(struct ifnet *ifp)
154 {
155         struct pflog_softc      *pflogif = ifp->if_softc;
156
157         crit_enter();
158         pflogifs[pflogif->sc_unit] = NULL;
159         LIST_REMOVE(pflogif, sc_list);
160         crit_exit();
161
162 #if NBPFILTER > 0
163         bpfdetach(ifp);
164 #endif
165         if_detach(ifp);
166         kfree(pflogif, M_DEVBUF);
167 }
168
169 /*
170  * Start output on the pflog interface.
171  */
172 void
173 pflogstart(struct ifnet *ifp)
174 {
175         struct mbuf *m;
176
177         for (;;) {
178                 crit_enter();
179                 IF_DROP(&ifp->if_snd);
180                 IF_DEQUEUE(&ifp->if_snd, m);
181                 crit_exit();
182
183                 if (m == NULL)
184                         return;
185                 else
186                         m_freem(m);
187         }
188 }
189
190 int
191 pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
192         struct rtentry *rt)
193 {
194         m_freem(m);
195         return (0);
196 }
197
198 /* ARGSUSED */
199 void
200 pflogrtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa)
201 {
202         if (rt)
203                 rt->rt_rmx.rmx_mtu = PFLOGMTU;
204 }
205
206 /* ARGSUSED */
207 int
208 pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
209 {
210         switch (cmd) {
211         case SIOCSIFADDR:
212         case SIOCAIFADDR:
213         case SIOCSIFDSTADDR:
214         case SIOCSIFFLAGS:
215                 if (ifp->if_flags & IFF_UP)
216                         ifp->if_flags |= IFF_RUNNING;
217                 else
218                         ifp->if_flags &= ~IFF_RUNNING;
219                 break;
220         default:
221                 return (EINVAL);
222         }
223
224         return (0);
225 }
226
227 int
228 pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
229     u_int8_t reason, struct pf_rule *rm, struct pf_rule *am,
230     struct pf_ruleset *ruleset, struct pf_pdesc *pd)
231 {
232         struct ifnet *ifn = NULL;
233         struct pfloghdr hdr;
234
235         if (kif == NULL || m == NULL || rm == NULL)
236                 return (-1);
237
238         if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf)
239                 return (0);
240
241         bzero(&hdr, sizeof(hdr));
242         hdr.length = PFLOG_REAL_HDRLEN;
243         hdr.af = af;
244         hdr.action = rm->action;
245         hdr.reason = reason;
246         memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname));
247
248         if (am == NULL) {
249                 hdr.rulenr = htonl(rm->nr);
250                 hdr.subrulenr = -1;
251         } else {
252                 hdr.rulenr = htonl(am->nr);
253                 hdr.subrulenr = htonl(rm->nr);
254                 if (ruleset != NULL && ruleset->anchor != NULL) {
255                         strlcpy(hdr.ruleset, ruleset->anchor->name,
256                             sizeof(hdr.ruleset));
257                 }
258         }
259         if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done)
260                 pd->lookup.done = pf_socket_lookup(dir, pd, NULL);
261         if (pd->lookup.done > 0) {
262                 hdr.uid = pd->lookup.uid;
263                 hdr.pid = pd->lookup.pid;
264         } else {
265                 hdr.uid = UID_MAX;
266                 hdr.pid = NO_PID;
267         }
268         hdr.rule_uid = rm->cuid;
269         hdr.rule_pid = rm->cpid;
270         hdr.dir = dir;
271
272 #ifdef INET
273         if (af == AF_INET) {
274                 struct ip *ip;
275                 ip = mtod(m, struct ip *);      
276                 ip->ip_len = htons(ip->ip_len);
277                 ip->ip_off = htons(ip->ip_off);
278
279                 if (dir == PF_OUT) {
280                         ip->ip_sum = 0;
281                         ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
282                 }                               
283         }
284 #endif /* INET */
285
286         ifn->if_opackets++;
287         ifn->if_obytes += m->m_pkthdr.len;
288         bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m,
289             BPF_DIRECTION_OUT);
290
291 #ifdef INET
292         if (af == AF_INET) {
293                 struct ip *ip = mtod(m, struct ip *);
294
295                 ip->ip_len = ntohs(ip->ip_len);
296                 ip->ip_off = ntohs(ip->ip_off);
297         }
298 #endif /* INET */
299
300         return (0);
301 }
302
303 static int
304 pflog_modevent(module_t mod, int type, void *data)
305 {
306         int error = 0;
307
308         switch (type) {
309         case MOD_LOAD:
310                 LIST_INIT(&pflogif_list);
311                 if_clone_attach(&pflog_cloner);
312                 break;
313
314         case MOD_UNLOAD:
315                 if_clone_detach(&pflog_cloner);
316                 while (!LIST_EMPTY(&pflogif_list)) {
317                         pflog_clone_destroy(
318                                 &LIST_FIRST(&pflogif_list)->sc_if);
319                 }
320                 break;
321
322         default:
323                 error = EINVAL;
324                 break;
325         }
326
327         return error;
328 }
329
330 static moduledata_t pflog_mod = {
331         "pflog",
332         pflog_modevent,
333         0
334 };
335
336 #define PFLOG_MODVER 1
337
338 DECLARE_MODULE(pflog, pflog_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
339 MODULE_VERSION(pflog, PFLOG_MODVER);