if_pflog.c revision 171168
1/*	$OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto 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 *
20 * Permission to use, copy, and modify this software with or without fee
21 * is hereby granted, provided that this entire notice is included in
22 * all copies of any software which is or includes a copy or
23 * modification of this software.
24 * You may use this code under the GNU public license if you so wish. Please
25 * contribute changes back to the authors under this freer than GPL license
26 * so that we may further the use of strong encryption without limitations to
27 * all.
28 *
29 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
30 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
31 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
32 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
33 * PURPOSE.
34 */
35
36#ifdef __FreeBSD__
37#include "opt_inet.h"
38#include "opt_inet6.h"
39#include "opt_bpf.h"
40#include "opt_pf.h"
41
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD: head/sys/contrib/pf/net/if_pflog.c 171168 2007-07-03 12:16:07Z mlaier $");
44
45#ifdef DEV_BPF
46#define	NBPFILTER	DEV_BPF
47#else
48#define	NBPFILTER	0
49#endif
50
51#ifdef DEV_PFLOG
52#define	NPFLOG		DEV_PFLOG
53#else
54#define	NPFLOG		0
55#endif
56
57#else /* ! __FreeBSD__ */
58#include "bpfilter.h"
59#include "pflog.h"
60#endif /* __FreeBSD__ */
61
62#include <sys/param.h>
63#include <sys/systm.h>
64#include <sys/mbuf.h>
65#include <sys/proc.h>
66#include <sys/socket.h>
67#ifdef __FreeBSD__
68#include <sys/kernel.h>
69#include <sys/limits.h>
70#include <sys/malloc.h>
71#include <sys/module.h>
72#include <sys/sockio.h>
73#else
74#include <sys/ioctl.h>
75#endif
76
77#include <net/if.h>
78#ifdef __FreeBSD__
79#include <net/if_clone.h>
80#endif
81#include <net/if_types.h>
82#include <net/route.h>
83#include <net/bpf.h>
84
85#ifdef	INET
86#include <netinet/in.h>
87#include <netinet/in_var.h>
88#include <netinet/in_systm.h>
89#include <netinet/ip.h>
90#endif
91
92#ifdef INET6
93#ifndef INET
94#include <netinet/in.h>
95#endif
96#include <netinet6/nd6.h>
97#endif /* INET6 */
98
99#include <net/pfvar.h>
100#include <net/if_pflog.h>
101
102#ifdef __FreeBSD__
103#include <machine/in_cksum.h>
104#endif
105
106#define PFLOGMTU	(32768 + MHLEN + MLEN)
107
108#ifdef PFLOGDEBUG
109#define DPRINTF(x)    do { if (pflogdebug) printf x ; } while (0)
110#else
111#define DPRINTF(x)
112#endif
113
114void	pflogattach(int);
115int	pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
116	    	       struct rtentry *);
117int	pflogioctl(struct ifnet *, u_long, caddr_t);
118void	pflogstart(struct ifnet *);
119#ifdef __FreeBSD__
120static int pflog_clone_create(struct if_clone *, int, caddr_t);
121static void pflog_clone_destroy(struct ifnet *);
122#else
123int	pflog_clone_create(struct if_clone *, int);
124int	pflog_clone_destroy(struct ifnet *);
125#endif
126
127LIST_HEAD(, pflog_softc)	pflogif_list;
128#ifdef __FreeBSD__
129IFC_SIMPLE_DECLARE(pflog, 1);
130#else
131struct if_clone	pflog_cloner =
132    IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy);
133#endif
134
135struct ifnet	*pflogifs[PFLOGIFS_MAX];	/* for fast access */
136
137#ifndef __FreeBSD__
138extern int ifqmaxlen;
139#endif
140
141void
142pflogattach(int npflog)
143{
144	int	i;
145	LIST_INIT(&pflogif_list);
146	for (i = 0; i < PFLOGIFS_MAX; i++)
147		pflogifs[i] = NULL;
148#ifndef __FreeBSD__
149	(void) pflog_clone_create(&pflog_cloner, 0);
150#endif
151	if_clone_attach(&pflog_cloner);
152}
153
154#ifdef __FreeBSD__
155static int
156pflog_clone_create(struct if_clone *ifc, int unit, caddr_t param)
157#else
158int
159pflog_clone_create(struct if_clone *ifc, int unit)
160#endif
161{
162	struct ifnet *ifp;
163	struct pflog_softc *pflogif;
164	int s;
165
166	if (unit >= PFLOGIFS_MAX)
167		return (EINVAL);
168
169	if ((pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_NOWAIT)) == NULL)
170		return (ENOMEM);
171	bzero(pflogif, sizeof(*pflogif));
172
173	pflogif->sc_unit = unit;
174#ifdef __FreeBSD__
175	ifp = pflogif->sc_ifp = if_alloc(IFT_PFLOG);
176	if (ifp == NULL) {
177		free(pflogif, M_DEVBUF);
178		return (ENOSPC);
179	}
180	if_initname(ifp, ifc->ifc_name, unit);
181#else
182	ifp = &pflogif->sc_if;
183	snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit);
184#endif
185	ifp->if_softc = pflogif;
186	ifp->if_mtu = PFLOGMTU;
187	ifp->if_ioctl = pflogioctl;
188	ifp->if_output = pflogoutput;
189	ifp->if_start = pflogstart;
190#ifndef __FreeBSD__
191	ifp->if_type = IFT_PFLOG;
192#endif
193	ifp->if_snd.ifq_maxlen = ifqmaxlen;
194	ifp->if_hdrlen = PFLOG_HDRLEN;
195	if_attach(ifp);
196#ifndef __FreeBSD__
197	if_alloc_sadl(ifp);
198#endif
199
200#if NBPFILTER > 0
201#ifdef __FreeBSD__
202	bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN);
203#else
204	bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN);
205#endif
206#endif
207
208	s = splnet();
209#ifdef __FreeBSD__
210	PF_LOCK();
211#endif
212	LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list);
213	pflogifs[unit] = ifp;
214#ifdef __FreeBSD__
215	PF_UNLOCK();
216#endif
217	splx(s);
218
219	return (0);
220}
221
222#ifdef __FreeBSD__
223static void
224pflog_clone_destroy(struct ifnet *ifp)
225#else
226int
227pflog_clone_destroy(struct ifnet *ifp)
228#endif
229{
230	struct pflog_softc	*pflogif = ifp->if_softc;
231	int			 s;
232
233	s = splnet();
234#ifdef __FreeBSD__
235	PF_LOCK();
236#endif
237	pflogifs[pflogif->sc_unit] = NULL;
238	LIST_REMOVE(pflogif, sc_list);
239#ifdef __FreeBSD__
240	PF_UNLOCK();
241#endif
242	splx(s);
243
244#if NBPFILTER > 0
245	bpfdetach(ifp);
246#endif
247	if_detach(ifp);
248#ifdef __FreeBSD__
249	if_free(ifp);
250#endif
251	free(pflogif, M_DEVBUF);
252#ifndef __FreeBSD__
253	return (0);
254#endif
255}
256
257/*
258 * Start output on the pflog interface.
259 */
260void
261pflogstart(struct ifnet *ifp)
262{
263	struct mbuf *m;
264#ifndef __FreeBSD__
265	int s;
266#endif
267
268	for (;;) {
269#ifdef __FreeBSD__
270		IF_LOCK(&ifp->if_snd);
271		_IF_DROP(&ifp->if_snd);
272		_IF_DEQUEUE(&ifp->if_snd, m);
273		IF_UNLOCK(&ifp->if_snd);
274#else
275		s = splnet();
276		IF_DROP(&ifp->if_snd);
277		IF_DEQUEUE(&ifp->if_snd, m);
278		splx(s);
279#endif
280
281		if (m == NULL)
282			return;
283		else
284			m_freem(m);
285	}
286}
287
288int
289pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
290	struct rtentry *rt)
291{
292	m_freem(m);
293	return (0);
294}
295
296/* ARGSUSED */
297int
298pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
299{
300	switch (cmd) {
301	case SIOCSIFADDR:
302	case SIOCAIFADDR:
303	case SIOCSIFDSTADDR:
304	case SIOCSIFFLAGS:
305#ifdef __FreeBSD__
306		if (ifp->if_flags & IFF_UP)
307			ifp->if_drv_flags |= IFF_DRV_RUNNING;
308		else
309			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
310#else
311		if (ifp->if_flags & IFF_UP)
312			ifp->if_flags |= IFF_RUNNING;
313		else
314			ifp->if_flags &= ~IFF_RUNNING;
315#endif
316		break;
317	default:
318		return (EINVAL);
319	}
320
321	return (0);
322}
323
324int
325pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
326    u_int8_t reason, struct pf_rule *rm, struct pf_rule *am,
327    struct pf_ruleset *ruleset, struct pf_pdesc *pd)
328{
329#if NBPFILTER > 0
330	struct ifnet *ifn;
331	struct pfloghdr hdr;
332
333	if (kif == NULL || m == NULL || rm == NULL || pd == NULL)
334		return (-1);
335
336	if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf)
337		return (0);
338
339	bzero(&hdr, sizeof(hdr));
340	hdr.length = PFLOG_REAL_HDRLEN;
341	hdr.af = af;
342	hdr.action = rm->action;
343	hdr.reason = reason;
344	memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname));
345
346	if (am == NULL) {
347		hdr.rulenr = htonl(rm->nr);
348		hdr.subrulenr = -1;
349	} else {
350		hdr.rulenr = htonl(am->nr);
351		hdr.subrulenr = htonl(rm->nr);
352		if (ruleset != NULL && ruleset->anchor != NULL)
353			strlcpy(hdr.ruleset, ruleset->anchor->name,
354			    sizeof(hdr.ruleset));
355	}
356	if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done)
357#ifdef __FreeBSD__
358		/*
359		 * XXX: This should not happen as we force an early lookup
360		 * via debug.pfugidhack
361		 */
362		 ; /* empty */
363#else
364		pd->lookup.done = pf_socket_lookup(dir, pd);
365#endif
366	if (pd->lookup.done > 0) {
367		hdr.uid = pd->lookup.uid;
368		hdr.pid = pd->lookup.pid;
369	} else {
370		hdr.uid = UID_MAX;
371		hdr.pid = NO_PID;
372	}
373	hdr.rule_uid = rm->cuid;
374	hdr.rule_pid = rm->cpid;
375	hdr.dir = dir;
376
377#ifdef INET
378	if (af == AF_INET && dir == PF_OUT) {
379		struct ip *ip;
380
381		ip = mtod(m, struct ip *);
382		ip->ip_sum = 0;
383		ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
384	}
385#endif /* INET */
386
387	ifn->if_opackets++;
388	ifn->if_obytes += m->m_pkthdr.len;
389#ifdef __FreeBSD__
390	BPF_MTAP2(ifn, &hdr, PFLOG_HDRLEN, m);
391#else
392	bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m,
393	    BPF_DIRECTION_OUT);
394#endif
395#endif
396
397	return (0);
398}
399
400#ifdef __FreeBSD__
401static int
402pflog_modevent(module_t mod, int type, void *data)
403{
404	int error = 0;
405
406	switch (type) {
407	case MOD_LOAD:
408		pflogattach(1);
409		PF_LOCK();
410		pflog_packet_ptr = pflog_packet;
411		PF_UNLOCK();
412		break;
413	case MOD_UNLOAD:
414		PF_LOCK();
415		pflog_packet_ptr = NULL;
416		PF_UNLOCK();
417		if_clone_detach(&pflog_cloner);
418		break;
419	default:
420		error = EINVAL;
421		break;
422	}
423
424	return error;
425}
426
427static moduledata_t pflog_mod = { "pflog", pflog_modevent, 0 };
428
429#define PFLOG_MODVER 1
430
431DECLARE_MODULE(pflog, pflog_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
432MODULE_VERSION(pflog, PFLOG_MODVER);
433MODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER);
434#endif /* __FreeBSD__ */
435