if_pflog.c revision 126258
1/*	$OpenBSD: if_pflog.c,v 1.9 2003/05/14 08:42:00 canacar 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#include "bpfilter.h"
37#include "pflog.h"
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/mbuf.h>
42#include <sys/socket.h>
43#include <sys/ioctl.h>
44
45#include <net/if.h>
46#include <net/if_types.h>
47#include <net/route.h>
48#include <net/bpf.h>
49
50#ifdef	INET
51#include <netinet/in.h>
52#include <netinet/in_var.h>
53#include <netinet/in_systm.h>
54#include <netinet/ip.h>
55#endif
56
57#ifdef INET6
58#ifndef INET
59#include <netinet/in.h>
60#endif
61#include <netinet6/nd6.h>
62#endif /* INET6 */
63
64#include <net/pfvar.h>
65#include <net/if_pflog.h>
66
67#define PFLOGMTU	(32768 + MHLEN + MLEN)
68
69#ifdef PFLOGDEBUG
70#define DPRINTF(x)    do { if (pflogdebug) printf x ; } while (0)
71#else
72#define DPRINTF(x)
73#endif
74
75struct pflog_softc pflogif[NPFLOG];
76
77void	pflogattach(int);
78int	pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
79	    	       struct rtentry *);
80int	pflogioctl(struct ifnet *, u_long, caddr_t);
81void	pflogrtrequest(int, struct rtentry *, struct sockaddr *);
82void	pflogstart(struct ifnet *);
83
84extern int ifqmaxlen;
85
86void
87pflogattach(int npflog)
88{
89	struct ifnet *ifp;
90	int i;
91
92	bzero(pflogif, sizeof(pflogif));
93
94	for (i = 0; i < NPFLOG; i++) {
95		ifp = &pflogif[i].sc_if;
96		snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", i);
97		ifp->if_softc = &pflogif[i];
98		ifp->if_mtu = PFLOGMTU;
99		ifp->if_ioctl = pflogioctl;
100		ifp->if_output = pflogoutput;
101		ifp->if_start = pflogstart;
102		ifp->if_type = IFT_PFLOG;
103		ifp->if_snd.ifq_maxlen = ifqmaxlen;
104		ifp->if_hdrlen = PFLOG_HDRLEN;
105		if_attach(ifp);
106		if_alloc_sadl(ifp);
107
108#if NBPFILTER > 0
109		bpfattach(&pflogif[i].sc_if.if_bpf, ifp, DLT_PFLOG,
110			  PFLOG_HDRLEN);
111#endif
112	}
113}
114
115/*
116 * Start output on the pflog interface.
117 */
118void
119pflogstart(struct ifnet *ifp)
120{
121	struct mbuf *m;
122	int s;
123
124	for (;;) {
125		s = splimp();
126		IF_DROP(&ifp->if_snd);
127		IF_DEQUEUE(&ifp->if_snd, m);
128		splx(s);
129
130		if (m == NULL)
131			return;
132		else
133			m_freem(m);
134	}
135}
136
137int
138pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
139	struct rtentry *rt)
140{
141	m_freem(m);
142	return (0);
143}
144
145/* ARGSUSED */
146void
147pflogrtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa)
148{
149	if (rt)
150		rt->rt_rmx.rmx_mtu = PFLOGMTU;
151}
152
153/* ARGSUSED */
154int
155pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
156{
157	switch (cmd) {
158	case SIOCSIFADDR:
159	case SIOCAIFADDR:
160	case SIOCSIFDSTADDR:
161	case SIOCSIFFLAGS:
162		if (ifp->if_flags & IFF_UP)
163			ifp->if_flags |= IFF_RUNNING;
164		else
165			ifp->if_flags &= ~IFF_RUNNING;
166		break;
167	default:
168		return (EINVAL);
169	}
170
171	return (0);
172}
173
174int
175pflog_packet(struct ifnet *ifp, struct mbuf *m, sa_family_t af, u_int8_t dir,
176    u_int8_t reason, struct pf_rule *rm, struct pf_rule *am,
177    struct pf_ruleset *ruleset)
178{
179#if NBPFILTER > 0
180	struct ifnet *ifn;
181	struct pfloghdr hdr;
182	struct mbuf m1;
183
184	if (ifp == NULL || m == NULL || rm == NULL)
185		return (-1);
186
187	hdr.length = PFLOG_REAL_HDRLEN;
188	hdr.af = af;
189	hdr.action = rm->action;
190	hdr.reason = reason;
191	memcpy(hdr.ifname, ifp->if_xname, sizeof(hdr.ifname));
192
193	if (am == NULL) {
194		hdr.rulenr = htonl(rm->nr);
195		hdr.subrulenr = -1;
196		bzero(hdr.ruleset, sizeof(hdr.ruleset));
197	} else {
198		hdr.rulenr = htonl(am->nr);
199		hdr.subrulenr = htonl(rm->nr);
200		if (ruleset == NULL)
201			bzero(hdr.ruleset, sizeof(hdr.ruleset));
202		else
203			memcpy(hdr.ruleset, ruleset->name,
204			    sizeof(hdr.ruleset));
205
206
207	}
208	hdr.dir = dir;
209
210#ifdef INET
211	if (af == AF_INET && dir == PF_OUT) {
212		struct ip *ip;
213
214		ip = mtod(m, struct ip *);
215		ip->ip_sum = 0;
216		ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
217	}
218#endif /* INET */
219
220	m1.m_next = m;
221	m1.m_len = PFLOG_HDRLEN;
222	m1.m_data = (char *) &hdr;
223
224	ifn = &(pflogif[0].sc_if);
225
226	if (ifn->if_bpf)
227		bpf_mtap(ifn->if_bpf, &m1);
228#endif
229
230	return (0);
231}
232