if_pflog.c revision 193900
1171168Smlaier/*	$OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto Exp $	*/
2126258Smlaier/*
3126258Smlaier * The authors of this code are John Ioannidis (ji@tla.org),
4126258Smlaier * Angelos D. Keromytis (kermit@csd.uch.gr) and
5126258Smlaier * Niels Provos (provos@physnet.uni-hamburg.de).
6126258Smlaier *
7126258Smlaier * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
8126258Smlaier * in November 1995.
9126258Smlaier *
10126258Smlaier * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
11126258Smlaier * by Angelos D. Keromytis.
12126258Smlaier *
13126258Smlaier * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
14126258Smlaier * and Niels Provos.
15126258Smlaier *
16126258Smlaier * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis
17126258Smlaier * and Niels Provos.
18126258Smlaier * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos.
19126258Smlaier *
20126258Smlaier * Permission to use, copy, and modify this software with or without fee
21126258Smlaier * is hereby granted, provided that this entire notice is included in
22126258Smlaier * all copies of any software which is or includes a copy or
23126258Smlaier * modification of this software.
24126258Smlaier * You may use this code under the GNU public license if you so wish. Please
25126258Smlaier * contribute changes back to the authors under this freer than GPL license
26126258Smlaier * so that we may further the use of strong encryption without limitations to
27126258Smlaier * all.
28126258Smlaier *
29126258Smlaier * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
30126258Smlaier * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
31126258Smlaier * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
32126258Smlaier * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
33126258Smlaier * PURPOSE.
34126258Smlaier */
35126258Smlaier
36127145Smlaier#ifdef __FreeBSD__
37126261Smlaier#include "opt_inet.h"
38126261Smlaier#include "opt_inet6.h"
39126261Smlaier#include "opt_bpf.h"
40126261Smlaier#include "opt_pf.h"
41153110Sru
42171168Smlaier#include <sys/cdefs.h>
43171168Smlaier__FBSDID("$FreeBSD: head/sys/contrib/pf/net/if_pflog.c 193900 2009-06-10 11:19:34Z bz $");
44171168Smlaier
45153110Sru#ifdef DEV_BPF
46127145Smlaier#define	NBPFILTER	DEV_BPF
47153110Sru#else
48153110Sru#define	NBPFILTER	0
49153110Sru#endif
50153110Sru
51153110Sru#ifdef DEV_PFLOG
52127145Smlaier#define	NPFLOG		DEV_PFLOG
53153110Sru#else
54153110Sru#define	NPFLOG		0
55126261Smlaier#endif
56126258Smlaier
57171168Smlaier#else /* ! __FreeBSD__ */
58171168Smlaier#include "bpfilter.h"
59171168Smlaier#include "pflog.h"
60171168Smlaier#endif /* __FreeBSD__ */
61153110Sru
62126258Smlaier#include <sys/param.h>
63126258Smlaier#include <sys/systm.h>
64126258Smlaier#include <sys/mbuf.h>
65171168Smlaier#include <sys/proc.h>
66126258Smlaier#include <sys/socket.h>
67127145Smlaier#ifdef __FreeBSD__
68126261Smlaier#include <sys/kernel.h>
69171168Smlaier#include <sys/limits.h>
70126261Smlaier#include <sys/malloc.h>
71129907Smlaier#include <sys/module.h>
72126261Smlaier#include <sys/sockio.h>
73126261Smlaier#else
74126258Smlaier#include <sys/ioctl.h>
75126261Smlaier#endif
76126258Smlaier
77126258Smlaier#include <net/if.h>
78171168Smlaier#ifdef __FreeBSD__
79130933Sbrooks#include <net/if_clone.h>
80130933Sbrooks#endif
81126258Smlaier#include <net/if_types.h>
82126258Smlaier#include <net/route.h>
83126258Smlaier#include <net/bpf.h>
84126258Smlaier
85126258Smlaier#ifdef	INET
86126258Smlaier#include <netinet/in.h>
87126258Smlaier#include <netinet/in_var.h>
88126258Smlaier#include <netinet/in_systm.h>
89126258Smlaier#include <netinet/ip.h>
90126258Smlaier#endif
91126258Smlaier
92126258Smlaier#ifdef INET6
93126258Smlaier#ifndef INET
94126258Smlaier#include <netinet/in.h>
95126258Smlaier#endif
96126258Smlaier#include <netinet6/nd6.h>
97126258Smlaier#endif /* INET6 */
98126258Smlaier
99126258Smlaier#include <net/pfvar.h>
100126258Smlaier#include <net/if_pflog.h>
101126258Smlaier
102193900Sbz#ifdef INET
103127145Smlaier#ifdef __FreeBSD__
104171168Smlaier#include <machine/in_cksum.h>
105126261Smlaier#endif
106193900Sbz#endif
107126261Smlaier
108126258Smlaier#define PFLOGMTU	(32768 + MHLEN + MLEN)
109126258Smlaier
110126258Smlaier#ifdef PFLOGDEBUG
111126258Smlaier#define DPRINTF(x)    do { if (pflogdebug) printf x ; } while (0)
112126258Smlaier#else
113126258Smlaier#define DPRINTF(x)
114126258Smlaier#endif
115126258Smlaier
116126258Smlaiervoid	pflogattach(int);
117126258Smlaierint	pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
118191148Skmacy    		       struct route *);
119126258Smlaierint	pflogioctl(struct ifnet *, u_long, caddr_t);
120126258Smlaiervoid	pflogstart(struct ifnet *);
121171168Smlaier#ifdef __FreeBSD__
122171168Smlaierstatic int pflog_clone_create(struct if_clone *, int, caddr_t);
123171168Smlaierstatic void pflog_clone_destroy(struct ifnet *);
124171168Smlaier#else
125171168Smlaierint	pflog_clone_create(struct if_clone *, int);
126171168Smlaierint	pflog_clone_destroy(struct ifnet *);
127171168Smlaier#endif
128126258Smlaier
129171168SmlaierLIST_HEAD(, pflog_softc)	pflogif_list;
130171168Smlaier#ifdef __FreeBSD__
131171168SmlaierIFC_SIMPLE_DECLARE(pflog, 1);
132171168Smlaier#else
133171168Smlaierstruct if_clone	pflog_cloner =
134171168Smlaier    IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy);
135171168Smlaier#endif
136171168Smlaier
137171168Smlaierstruct ifnet	*pflogifs[PFLOGIFS_MAX];	/* for fast access */
138171168Smlaier
139127145Smlaier#ifndef __FreeBSD__
140126258Smlaierextern int ifqmaxlen;
141126261Smlaier#endif
142126258Smlaier
143171168Smlaiervoid
144171168Smlaierpflogattach(int npflog)
145126261Smlaier{
146171168Smlaier	int	i;
147171168Smlaier	LIST_INIT(&pflogif_list);
148171168Smlaier	for (i = 0; i < PFLOGIFS_MAX; i++)
149171168Smlaier		pflogifs[i] = NULL;
150171168Smlaier#ifndef __FreeBSD__
151171168Smlaier	(void) pflog_clone_create(&pflog_cloner, 0);
152171168Smlaier#endif
153171168Smlaier	if_clone_attach(&pflog_cloner);
154126261Smlaier}
155126261Smlaier
156171168Smlaier#ifdef __FreeBSD__
157128209Sbrooksstatic int
158171168Smlaierpflog_clone_create(struct if_clone *ifc, int unit, caddr_t param)
159160195Ssam#else
160171168Smlaierint
161126261Smlaierpflog_clone_create(struct if_clone *ifc, int unit)
162160195Ssam#endif
163126261Smlaier{
164141584Smlaier	struct ifnet *ifp;
165171168Smlaier	struct pflog_softc *pflogif;
166171168Smlaier	int s;
167126261Smlaier
168171168Smlaier	if (unit >= PFLOGIFS_MAX)
169171168Smlaier		return (EINVAL);
170171168Smlaier
171171168Smlaier	if ((pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_NOWAIT)) == NULL)
172171168Smlaier		return (ENOMEM);
173171168Smlaier	bzero(pflogif, sizeof(*pflogif));
174171168Smlaier
175171168Smlaier	pflogif->sc_unit = unit;
176171168Smlaier#ifdef __FreeBSD__
177171168Smlaier	ifp = pflogif->sc_ifp = if_alloc(IFT_PFLOG);
178147256Sbrooks	if (ifp == NULL) {
179171168Smlaier		free(pflogif, M_DEVBUF);
180147256Sbrooks		return (ENOSPC);
181147256Sbrooks	}
182141584Smlaier	if_initname(ifp, ifc->ifc_name, unit);
183171168Smlaier#else
184171168Smlaier	ifp = &pflogif->sc_if;
185171168Smlaier	snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit);
186171168Smlaier#endif
187171168Smlaier	ifp->if_softc = pflogif;
188141584Smlaier	ifp->if_mtu = PFLOGMTU;
189141584Smlaier	ifp->if_ioctl = pflogioctl;
190141584Smlaier	ifp->if_output = pflogoutput;
191141584Smlaier	ifp->if_start = pflogstart;
192171168Smlaier#ifndef __FreeBSD__
193171168Smlaier	ifp->if_type = IFT_PFLOG;
194171168Smlaier#endif
195141584Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
196141584Smlaier	ifp->if_hdrlen = PFLOG_HDRLEN;
197141584Smlaier	if_attach(ifp);
198171168Smlaier#ifndef __FreeBSD__
199171168Smlaier	if_alloc_sadl(ifp);
200171168Smlaier#endif
201126261Smlaier
202126261Smlaier#if NBPFILTER > 0
203171168Smlaier#ifdef __FreeBSD__
204141584Smlaier	bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN);
205171168Smlaier#else
206171168Smlaier	bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN);
207126261Smlaier#endif
208171168Smlaier#endif
209126261Smlaier
210171168Smlaier	s = splnet();
211171168Smlaier#ifdef __FreeBSD__
212171168Smlaier	PF_LOCK();
213171168Smlaier#endif
214171168Smlaier	LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list);
215171168Smlaier	pflogifs[unit] = ifp;
216171168Smlaier#ifdef __FreeBSD__
217171168Smlaier	PF_UNLOCK();
218171168Smlaier#endif
219171168Smlaier	splx(s);
220171168Smlaier
221141584Smlaier	return (0);
222126261Smlaier}
223171168Smlaier
224171168Smlaier#ifdef __FreeBSD__
225171168Smlaierstatic void
226171168Smlaierpflog_clone_destroy(struct ifnet *ifp)
227171168Smlaier#else
228171168Smlaierint
229171168Smlaierpflog_clone_destroy(struct ifnet *ifp)
230171168Smlaier#endif
231126258Smlaier{
232171168Smlaier	struct pflog_softc	*pflogif = ifp->if_softc;
233171168Smlaier	int			 s;
234126258Smlaier
235171168Smlaier	s = splnet();
236171168Smlaier#ifdef __FreeBSD__
237171168Smlaier	PF_LOCK();
238171168Smlaier#endif
239171168Smlaier	pflogifs[pflogif->sc_unit] = NULL;
240171168Smlaier	LIST_REMOVE(pflogif, sc_list);
241171168Smlaier#ifdef __FreeBSD__
242171168Smlaier	PF_UNLOCK();
243171168Smlaier#endif
244171168Smlaier	splx(s);
245126258Smlaier
246126258Smlaier#if NBPFILTER > 0
247171168Smlaier	bpfdetach(ifp);
248126258Smlaier#endif
249171168Smlaier	if_detach(ifp);
250171168Smlaier#ifdef __FreeBSD__
251171168Smlaier	if_free(ifp);
252171168Smlaier#endif
253171168Smlaier	free(pflogif, M_DEVBUF);
254171168Smlaier#ifndef __FreeBSD__
255171168Smlaier	return (0);
256171168Smlaier#endif
257126258Smlaier}
258126258Smlaier
259126258Smlaier/*
260126258Smlaier * Start output on the pflog interface.
261126258Smlaier */
262126258Smlaiervoid
263126258Smlaierpflogstart(struct ifnet *ifp)
264126258Smlaier{
265126258Smlaier	struct mbuf *m;
266130613Smlaier#ifndef __FreeBSD__
267126258Smlaier	int s;
268130613Smlaier#endif
269126258Smlaier
270126258Smlaier	for (;;) {
271127145Smlaier#ifdef __FreeBSD__
272130475Smlaier		IF_LOCK(&ifp->if_snd);
273130475Smlaier		_IF_DROP(&ifp->if_snd);
274130475Smlaier		_IF_DEQUEUE(&ifp->if_snd, m);
275171168Smlaier		IF_UNLOCK(&ifp->if_snd);
276126261Smlaier#else
277171168Smlaier		s = splnet();
278126258Smlaier		IF_DROP(&ifp->if_snd);
279126258Smlaier		IF_DEQUEUE(&ifp->if_snd, m);
280126258Smlaier		splx(s);
281171168Smlaier#endif
282171168Smlaier
283126258Smlaier		if (m == NULL)
284126258Smlaier			return;
285126258Smlaier		else
286126258Smlaier			m_freem(m);
287126258Smlaier	}
288126258Smlaier}
289126258Smlaier
290126258Smlaierint
291126258Smlaierpflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
292191148Skmacy       struct route *ro)
293126258Smlaier{
294126258Smlaier	m_freem(m);
295126258Smlaier	return (0);
296126258Smlaier}
297126258Smlaier
298126258Smlaier/* ARGSUSED */
299126258Smlaierint
300126258Smlaierpflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
301126258Smlaier{
302126258Smlaier	switch (cmd) {
303126258Smlaier	case SIOCSIFADDR:
304126258Smlaier	case SIOCAIFADDR:
305126258Smlaier	case SIOCSIFDSTADDR:
306126258Smlaier	case SIOCSIFFLAGS:
307148891Smlaier#ifdef __FreeBSD__
308126258Smlaier		if (ifp->if_flags & IFF_UP)
309148887Srwatson			ifp->if_drv_flags |= IFF_DRV_RUNNING;
310126258Smlaier		else
311148887Srwatson			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
312148891Smlaier#else
313148891Smlaier		if (ifp->if_flags & IFF_UP)
314148891Smlaier			ifp->if_flags |= IFF_RUNNING;
315148891Smlaier		else
316148891Smlaier			ifp->if_flags &= ~IFF_RUNNING;
317148891Smlaier#endif
318126258Smlaier		break;
319126258Smlaier	default:
320126258Smlaier		return (EINVAL);
321126258Smlaier	}
322126258Smlaier
323126258Smlaier	return (0);
324126258Smlaier}
325126258Smlaier
326126258Smlaierint
327130613Smlaierpflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
328126258Smlaier    u_int8_t reason, struct pf_rule *rm, struct pf_rule *am,
329171168Smlaier    struct pf_ruleset *ruleset, struct pf_pdesc *pd)
330126258Smlaier{
331126258Smlaier#if NBPFILTER > 0
332126258Smlaier	struct ifnet *ifn;
333126258Smlaier	struct pfloghdr hdr;
334126258Smlaier
335171168Smlaier	if (kif == NULL || m == NULL || rm == NULL || pd == NULL)
336126258Smlaier		return (-1);
337126258Smlaier
338171168Smlaier	if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf)
339171168Smlaier		return (0);
340171168Smlaier
341130613Smlaier	bzero(&hdr, sizeof(hdr));
342126258Smlaier	hdr.length = PFLOG_REAL_HDRLEN;
343126258Smlaier	hdr.af = af;
344126258Smlaier	hdr.action = rm->action;
345126258Smlaier	hdr.reason = reason;
346130613Smlaier	memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname));
347126258Smlaier
348126258Smlaier	if (am == NULL) {
349126258Smlaier		hdr.rulenr = htonl(rm->nr);
350126258Smlaier		hdr.subrulenr = -1;
351126258Smlaier	} else {
352126258Smlaier		hdr.rulenr = htonl(am->nr);
353126258Smlaier		hdr.subrulenr = htonl(rm->nr);
354145836Smlaier		if (ruleset != NULL && ruleset->anchor != NULL)
355145836Smlaier			strlcpy(hdr.ruleset, ruleset->anchor->name,
356126258Smlaier			    sizeof(hdr.ruleset));
357126258Smlaier	}
358171168Smlaier	if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done)
359171168Smlaier#ifdef __FreeBSD__
360171168Smlaier		/*
361171168Smlaier		 * XXX: This should not happen as we force an early lookup
362171168Smlaier		 * via debug.pfugidhack
363171168Smlaier		 */
364171168Smlaier		 ; /* empty */
365171168Smlaier#else
366171168Smlaier		pd->lookup.done = pf_socket_lookup(dir, pd);
367171168Smlaier#endif
368171168Smlaier	if (pd->lookup.done > 0) {
369171168Smlaier		hdr.uid = pd->lookup.uid;
370171168Smlaier		hdr.pid = pd->lookup.pid;
371171168Smlaier	} else {
372171168Smlaier		hdr.uid = UID_MAX;
373171168Smlaier		hdr.pid = NO_PID;
374171168Smlaier	}
375171168Smlaier	hdr.rule_uid = rm->cuid;
376171168Smlaier	hdr.rule_pid = rm->cpid;
377126258Smlaier	hdr.dir = dir;
378126258Smlaier
379126258Smlaier#ifdef INET
380126258Smlaier	if (af == AF_INET && dir == PF_OUT) {
381126258Smlaier		struct ip *ip;
382126258Smlaier
383126258Smlaier		ip = mtod(m, struct ip *);
384126258Smlaier		ip->ip_sum = 0;
385126258Smlaier		ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
386126258Smlaier	}
387126258Smlaier#endif /* INET */
388126258Smlaier
389171168Smlaier	ifn->if_opackets++;
390171168Smlaier	ifn->if_obytes += m->m_pkthdr.len;
391127145Smlaier#ifdef __FreeBSD__
392171168Smlaier	BPF_MTAP2(ifn, &hdr, PFLOG_HDRLEN, m);
393126261Smlaier#else
394171168Smlaier	bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m,
395171168Smlaier	    BPF_DIRECTION_OUT);
396126258Smlaier#endif
397130613Smlaier#endif
398126258Smlaier
399126258Smlaier	return (0);
400126258Smlaier}
401126261Smlaier
402127145Smlaier#ifdef __FreeBSD__
403126261Smlaierstatic int
404126261Smlaierpflog_modevent(module_t mod, int type, void *data)
405126261Smlaier{
406126261Smlaier	int error = 0;
407126261Smlaier
408126261Smlaier	switch (type) {
409126261Smlaier	case MOD_LOAD:
410171168Smlaier		pflogattach(1);
411155337Smlaier		PF_LOCK();
412155337Smlaier		pflog_packet_ptr = pflog_packet;
413155337Smlaier		PF_UNLOCK();
414126261Smlaier		break;
415126261Smlaier	case MOD_UNLOAD:
416155337Smlaier		PF_LOCK();
417155337Smlaier		pflog_packet_ptr = NULL;
418155337Smlaier		PF_UNLOCK();
419126261Smlaier		if_clone_detach(&pflog_cloner);
420126261Smlaier		break;
421126261Smlaier	default:
422126261Smlaier		error = EINVAL;
423126261Smlaier		break;
424126261Smlaier	}
425126261Smlaier
426126261Smlaier	return error;
427126261Smlaier}
428126261Smlaier
429171168Smlaierstatic moduledata_t pflog_mod = { "pflog", pflog_modevent, 0 };
430126261Smlaier
431126261Smlaier#define PFLOG_MODVER 1
432126261Smlaier
433135196SmlaierDECLARE_MODULE(pflog, pflog_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
434126261SmlaierMODULE_VERSION(pflog, PFLOG_MODVER);
435155337SmlaierMODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER);
436126261Smlaier#endif /* __FreeBSD__ */
437