if_pflog.c revision 240233
174429Sorion/*	$OpenBSD: if_pflog.c,v 1.26 2007/10/18 21:58:18 mpf Exp $	*/
274429Sorion/*
374429Sorion * The authors of this code are John Ioannidis (ji@tla.org),
474429Sorion * Angelos D. Keromytis (kermit@csd.uch.gr) and
574429Sorion * Niels Provos (provos@physnet.uni-hamburg.de).
674429Sorion *
774429Sorion * This code was written by John Ioannidis for BSD/OS in Athens, Greece,
874429Sorion * in November 1995.
974429Sorion *
1074429Sorion * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
1174429Sorion * by Angelos D. Keromytis.
1274429Sorion *
1374429Sorion * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
1474429Sorion * and Niels Provos.
1574429Sorion *
1674429Sorion * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis
1774429Sorion * and Niels Provos.
1874429Sorion * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos.
1974429Sorion *
2074429Sorion * Permission to use, copy, and modify this software with or without fee
2174429Sorion * is hereby granted, provided that this entire notice is included in
2274429Sorion * all copies of any software which is or includes a copy or
2374429Sorion * modification of this software.
2474429Sorion * You may use this code under the GNU public license if you so wish. Please
2574429Sorion * contribute changes back to the authors under this freer than GPL license
2674429Sorion * so that we may further the use of strong encryption without limitations to
2774429Sorion * all.
2874429Sorion *
2974429Sorion * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
3074429Sorion * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
3174429Sorion * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
3274429Sorion * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
3374429Sorion * PURPOSE.
3474429Sorion */
3574429Sorion
3674429Sorion#include <sys/cdefs.h>
3774429Sorion__FBSDID("$FreeBSD: head/sys/contrib/pf/net/if_pflog.c 240233 2012-09-08 06:41:54Z glebius $");
3874429Sorion
3974429Sorion#include "opt_inet.h"
4074429Sorion#include "opt_inet6.h"
4174429Sorion#include "opt_bpf.h"
4274429Sorion#include "opt_pf.h"
4374429Sorion
4474429Sorion#include <sys/param.h>
4574429Sorion#include <sys/kernel.h>
4674429Sorion#include <sys/mbuf.h>
4774429Sorion#include <sys/module.h>
4874429Sorion#include <sys/proc.h>
4974429Sorion#include <sys/socket.h>
5074429Sorion#include <sys/sockio.h>
5174429Sorion
5274429Sorion#include <net/bpf.h>
5374429Sorion#include <net/if.h>
5474429Sorion#include <net/if_clone.h>
5574429Sorion#include <net/if_pflog.h>
5674429Sorion#include <net/if_types.h>
5774429Sorion#include <net/pfvar.h>
5874429Sorion
5974429Sorion#if defined(INET) || defined(INET6)
6074429Sorion#include <netinet/in.h>
6174429Sorion#endif
6274429Sorion#ifdef	INET
6374429Sorion#include <netinet/in_var.h>
6474429Sorion#include <netinet/ip.h>
6574429Sorion#endif
6674429Sorion
6774429Sorion#ifdef INET6
6874429Sorion#include <netinet6/in6_var.h>
6974429Sorion#include <netinet6/nd6.h>
7074429Sorion#endif /* INET6 */
7174429Sorion
7274429Sorion#ifdef INET
7374429Sorion#include <machine/in_cksum.h>
7474429Sorion#endif /* INET */
7574429Sorion
7674429Sorion#define PFLOGMTU	(32768 + MHLEN + MLEN)
7774429Sorion
7874429Sorion#ifdef PFLOGDEBUG
7974429Sorion#define DPRINTF(x)    do { if (pflogdebug) printf x ; } while (0)
8074429Sorion#else
8174429Sorion#define DPRINTF(x)
8274429Sorion#endif
8374429Sorion
8474429Sorionstatic int	pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
8574429Sorion		    struct route *);
8674429Sorionstatic void	pflogattach(int);
8774429Sorionstatic int	pflogioctl(struct ifnet *, u_long, caddr_t);
8874429Sorionstatic void	pflogstart(struct ifnet *);
8974429Sorionstatic int	pflog_clone_create(struct if_clone *, int, caddr_t);
9074429Sorionstatic void	pflog_clone_destroy(struct ifnet *);
9174429Sorion
9274429SorionIFC_SIMPLE_DECLARE(pflog, 1);
9374429Sorion
9474429Sorionstruct ifnet	*pflogifs[PFLOGIFS_MAX];	/* for fast access */
9574429Sorion
9674429Sorionstatic void
9774429Sorionpflogattach(int npflog)
9874429Sorion{
9974429Sorion	int	i;
10074429Sorion	for (i = 0; i < PFLOGIFS_MAX; i++)
10174429Sorion		pflogifs[i] = NULL;
10274429Sorion	if_clone_attach(&pflog_cloner);
10374429Sorion}
10474429Sorion
10574429Sorionstatic int
10674429Sorionpflog_clone_create(struct if_clone *ifc, int unit, caddr_t param)
10774429Sorion{
10874429Sorion	struct ifnet *ifp;
10974429Sorion
11074429Sorion	if (unit >= PFLOGIFS_MAX)
11174429Sorion		return (EINVAL);
11274429Sorion
11374429Sorion	ifp = if_alloc(IFT_PFLOG);
11474429Sorion	if (ifp == NULL) {
11574429Sorion		return (ENOSPC);
11674429Sorion	}
11774429Sorion	if_initname(ifp, ifc->ifc_name, unit);
11874429Sorion	ifp->if_mtu = PFLOGMTU;
11974429Sorion	ifp->if_ioctl = pflogioctl;
12074429Sorion	ifp->if_output = pflogoutput;
12174429Sorion	ifp->if_start = pflogstart;
12274429Sorion	ifp->if_snd.ifq_maxlen = ifqmaxlen;
12374429Sorion	ifp->if_hdrlen = PFLOG_HDRLEN;
12474429Sorion	if_attach(ifp);
12574429Sorion
12674429Sorion	bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN);
12774429Sorion
12874429Sorion	pflogifs[unit] = ifp;
12974429Sorion
13074429Sorion	return (0);
13174429Sorion}
13274429Sorion
13374429Sorionstatic void
13474429Sorionpflog_clone_destroy(struct ifnet *ifp)
13574429Sorion{
13674429Sorion	int i;
13774429Sorion
13874429Sorion	for (i = 0; i < PFLOGIFS_MAX; i++)
13974429Sorion		if (pflogifs[i] == ifp)
14074429Sorion			pflogifs[i] = NULL;
14174429Sorion
14274429Sorion	bpfdetach(ifp);
14374429Sorion	if_detach(ifp);
14474429Sorion	if_free(ifp);
14574429Sorion}
14674429Sorion
14774429Sorion/*
14874429Sorion * Start output on the pflog interface.
14974429Sorion */
15074429Sorionstatic void
15174429Sorionpflogstart(struct ifnet *ifp)
15274429Sorion{
15374429Sorion	struct mbuf *m;
15474429Sorion
15574429Sorion	for (;;) {
15674429Sorion		IF_LOCK(&ifp->if_snd);
15774429Sorion		_IF_DROP(&ifp->if_snd);
15874429Sorion		_IF_DEQUEUE(&ifp->if_snd, m);
15974429Sorion		IF_UNLOCK(&ifp->if_snd);
16074429Sorion
16174429Sorion		if (m == NULL)
16274429Sorion			return;
16374429Sorion		else
16474429Sorion			m_freem(m);
16574429Sorion	}
16674429Sorion}
16774429Sorion
16874429Sorionstatic int
16974429Sorionpflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
17074429Sorion	struct route *rt)
17174429Sorion{
17274429Sorion	m_freem(m);
17374429Sorion	return (0);
17474429Sorion}
17574429Sorion
17674429Sorion/* ARGSUSED */
17774429Sorionstatic int
17874429Sorionpflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
17974429Sorion{
18074429Sorion	switch (cmd) {
18174429Sorion	case SIOCSIFFLAGS:
18274429Sorion		if (ifp->if_flags & IFF_UP)
18374429Sorion			ifp->if_drv_flags |= IFF_DRV_RUNNING;
18474429Sorion		else
18574429Sorion			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
18674429Sorion		break;
18774429Sorion	default:
18874429Sorion		return (ENOTTY);
18974429Sorion	}
19074429Sorion
19174429Sorion	return (0);
19274429Sorion}
19374429Sorion
19474429Sorionstatic int
19574429Sorionpflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir,
19674429Sorion    u_int8_t reason, struct pf_rule *rm, struct pf_rule *am,
19774429Sorion    struct pf_ruleset *ruleset, struct pf_pdesc *pd, int lookupsafe)
19874429Sorion{
19974429Sorion	struct ifnet *ifn;
20074429Sorion	struct pfloghdr hdr;
20174429Sorion
20274429Sorion	if (kif == NULL || m == NULL || rm == NULL || pd == NULL)
20374429Sorion		return ( 1);
20474429Sorion
20574429Sorion	if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf)
20674429Sorion		return (0);
20774429Sorion
20874429Sorion	bzero(&hdr, sizeof(hdr));
20974429Sorion	hdr.length = PFLOG_REAL_HDRLEN;
21074429Sorion	hdr.af = af;
21174429Sorion	hdr.action = rm->action;
21274429Sorion	hdr.reason = reason;
21374429Sorion	memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname));
21474429Sorion
21574429Sorion	if (am == NULL) {
21674429Sorion		hdr.rulenr = htonl(rm->nr);
21774429Sorion		hdr.subrulenr =  1;
21874429Sorion	} else {
21974429Sorion		hdr.rulenr = htonl(am->nr);
22074429Sorion		hdr.subrulenr = htonl(rm->nr);
22174429Sorion		if (ruleset != NULL && ruleset->anchor != NULL)
22274429Sorion			strlcpy(hdr.ruleset, ruleset->anchor->name,
22374429Sorion			    sizeof(hdr.ruleset));
22474429Sorion	}
22574429Sorion	/*
22674429Sorion	 * XXXGL: we avoid pf_socket_lookup() when we are holding
22774429Sorion	 * state lock, since this leads to unsafe LOR.
22874429Sorion	 * These conditions are very very rare, however.
22974429Sorion	 */
23074429Sorion	if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done && lookupsafe)
23174429Sorion		pd->lookup.done = pf_socket_lookup(dir, pd, m);
23274429Sorion	if (pd->lookup.done > 0)
23374429Sorion		hdr.uid = pd->lookup.uid;
23474429Sorion	else
23574429Sorion		hdr.uid = UID_MAX;
23674429Sorion	hdr.pid = NO_PID;
23774429Sorion	hdr.rule_uid = rm->cuid;
23874429Sorion	hdr.rule_pid = rm->cpid;
23974429Sorion	hdr.dir = dir;
24074429Sorion
24174429Sorion#ifdef INET
24274429Sorion	if (af == AF_INET && dir == PF_OUT) {
24374429Sorion		struct ip *ip;
24474429Sorion
24574429Sorion		ip = mtod(m, struct ip *);
24674429Sorion		ip->ip_sum = 0;
24774429Sorion		ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
24874429Sorion	}
24974429Sorion#endif /* INET */
25074429Sorion
25174429Sorion	ifn->if_opackets++;
25274429Sorion	ifn->if_obytes += m->m_pkthdr.len;
25374429Sorion	BPF_MTAP2(ifn, &hdr, PFLOG_HDRLEN, m);
25474429Sorion
25574429Sorion	return (0);
25674429Sorion}
25774429Sorion
25874429Sorionstatic int
25974429Sorionpflog_modevent(module_t mod, int type, void *data)
26074429Sorion{
26174429Sorion	int error = 0;
26274429Sorion
26374429Sorion	switch (type) {
26474429Sorion	case MOD_LOAD:
26574429Sorion		pflogattach(1);
26674429Sorion		PF_RULES_WLOCK();
26774429Sorion		pflog_packet_ptr = pflog_packet;
26874429Sorion		PF_RULES_WUNLOCK();
26974429Sorion		break;
27074429Sorion	case MOD_UNLOAD:
27174429Sorion		PF_RULES_WLOCK();
27274429Sorion		pflog_packet_ptr = NULL;
27374429Sorion		PF_RULES_WUNLOCK();
27474429Sorion		if_clone_detach(&pflog_cloner);
27574429Sorion		break;
27674429Sorion	default:
27774429Sorion		error = EINVAL;
27874429Sorion		break;
27974429Sorion	}
28074429Sorion
28174429Sorion	return error;
28274429Sorion}
28374429Sorion
28474429Sorionstatic moduledata_t pflog_mod = { "pflog", pflog_modevent, 0 };
28574429Sorion
28674429Sorion#define PFLOG_MODVER 1
28774429Sorion
28874429SorionDECLARE_MODULE(pflog, pflog_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
28974429SorionMODULE_VERSION(pflog, PFLOG_MODVER);
29074429SorionMODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER);
29174429Sorion