if_pfsync.c revision 126258
1126258Smlaier/*	$OpenBSD: if_pfsync.c,v 1.6 2003/06/21 09:07:01 djm Exp $	*/
2126258Smlaier
3126258Smlaier/*
4126258Smlaier * Copyright (c) 2002 Michael Shalayeff
5126258Smlaier * All rights reserved.
6126258Smlaier *
7126258Smlaier * Redistribution and use in source and binary forms, with or without
8126258Smlaier * modification, are permitted provided that the following conditions
9126258Smlaier * are met:
10126258Smlaier * 1. Redistributions of source code must retain the above copyright
11126258Smlaier *    notice, this list of conditions and the following disclaimer.
12126258Smlaier * 2. Redistributions in binary form must reproduce the above copyright
13126258Smlaier *    notice, this list of conditions and the following disclaimer in the
14126258Smlaier *    documentation and/or other materials provided with the distribution.
15126258Smlaier *
16126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17126258Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18126258Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19126258Smlaier * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20126258Smlaier * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21126258Smlaier * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22126258Smlaier * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23126258Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24126258Smlaier * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25126258Smlaier * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26126258Smlaier * THE POSSIBILITY OF SUCH DAMAGE.
27126258Smlaier */
28126258Smlaier
29126258Smlaier#include "bpfilter.h"
30126258Smlaier#include "pfsync.h"
31126258Smlaier
32126258Smlaier#include <sys/param.h>
33126258Smlaier#include <sys/systm.h>
34126258Smlaier#include <sys/time.h>
35126258Smlaier#include <sys/mbuf.h>
36126258Smlaier#include <sys/socket.h>
37126258Smlaier#include <sys/ioctl.h>
38126258Smlaier#include <sys/timeout.h>
39126258Smlaier
40126258Smlaier#include <net/if.h>
41126258Smlaier#include <net/if_types.h>
42126258Smlaier#include <net/route.h>
43126258Smlaier#include <net/bpf.h>
44126258Smlaier
45126258Smlaier#ifdef	INET
46126258Smlaier#include <netinet/in.h>
47126258Smlaier#include <netinet/in_var.h>
48126258Smlaier#endif
49126258Smlaier
50126258Smlaier#ifdef INET6
51126258Smlaier#ifndef INET
52126258Smlaier#include <netinet/in.h>
53126258Smlaier#endif
54126258Smlaier#include <netinet6/nd6.h>
55126258Smlaier#endif /* INET6 */
56126258Smlaier
57126258Smlaier#include <net/pfvar.h>
58126258Smlaier#include <net/if_pfsync.h>
59126258Smlaier
60126258Smlaier#define PFSYNC_MINMTU	\
61126258Smlaier    (sizeof(struct pfsync_header) + sizeof(struct pf_state))
62126258Smlaier
63126258Smlaier#ifdef PFSYNCDEBUG
64126258Smlaier#define DPRINTF(x)    do { if (pfsyncdebug) printf x ; } while (0)
65126258Smlaierint pfsyncdebug;
66126258Smlaier#else
67126258Smlaier#define DPRINTF(x)
68126258Smlaier#endif
69126258Smlaier
70126258Smlaierstruct pfsync_softc pfsyncif;
71126258Smlaier
72126258Smlaiervoid	pfsyncattach(int);
73126258Smlaiervoid	pfsync_setmtu(struct pfsync_softc *sc, int);
74126258Smlaierint	pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
75126258Smlaier	       struct rtentry *);
76126258Smlaierint	pfsyncioctl(struct ifnet *, u_long, caddr_t);
77126258Smlaiervoid	pfsyncstart(struct ifnet *);
78126258Smlaier
79126258Smlaierstruct mbuf *pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action);
80126258Smlaierint	pfsync_sendout(struct pfsync_softc *sc);
81126258Smlaiervoid	pfsync_timeout(void *v);
82126258Smlaier
83126258Smlaierextern int ifqmaxlen;
84126258Smlaier
85126258Smlaiervoid
86126258Smlaierpfsyncattach(int npfsync)
87126258Smlaier{
88126258Smlaier	struct ifnet *ifp;
89126258Smlaier
90126258Smlaier	pfsyncif.sc_mbuf = NULL;
91126258Smlaier	pfsyncif.sc_ptr = NULL;
92126258Smlaier	pfsyncif.sc_count = 8;
93126258Smlaier	ifp = &pfsyncif.sc_if;
94126258Smlaier	strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
95126258Smlaier	ifp->if_softc = &pfsyncif;
96126258Smlaier	ifp->if_ioctl = pfsyncioctl;
97126258Smlaier	ifp->if_output = pfsyncoutput;
98126258Smlaier	ifp->if_start = pfsyncstart;
99126258Smlaier	ifp->if_type = IFT_PFSYNC;
100126258Smlaier	ifp->if_snd.ifq_maxlen = ifqmaxlen;
101126258Smlaier	ifp->if_hdrlen = PFSYNC_HDRLEN;
102126258Smlaier	ifp->if_baudrate = IF_Mbps(100);
103126258Smlaier	pfsync_setmtu(&pfsyncif, MCLBYTES);
104126258Smlaier	timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
105126258Smlaier	if_attach(ifp);
106126258Smlaier	if_alloc_sadl(ifp);
107126258Smlaier
108126258Smlaier#if NBPFILTER > 0
109126258Smlaier	bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
110126258Smlaier#endif
111126258Smlaier}
112126258Smlaier
113126258Smlaier/*
114126258Smlaier * Start output on the pfsync interface.
115126258Smlaier */
116126258Smlaiervoid
117126258Smlaierpfsyncstart(struct ifnet *ifp)
118126258Smlaier{
119126258Smlaier	struct mbuf *m;
120126258Smlaier	int s;
121126258Smlaier
122126258Smlaier	for (;;) {
123126258Smlaier		s = splimp();
124126258Smlaier		IF_DROP(&ifp->if_snd);
125126258Smlaier		IF_DEQUEUE(&ifp->if_snd, m);
126126258Smlaier		splx(s);
127126258Smlaier
128126258Smlaier		if (m == NULL)
129126258Smlaier			return;
130126258Smlaier		else
131126258Smlaier			m_freem(m);
132126258Smlaier	}
133126258Smlaier}
134126258Smlaier
135126258Smlaierint
136126258Smlaierpfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
137126258Smlaier	struct rtentry *rt)
138126258Smlaier{
139126258Smlaier	m_freem(m);
140126258Smlaier	return (0);
141126258Smlaier}
142126258Smlaier
143126258Smlaier/* ARGSUSED */
144126258Smlaierint
145126258Smlaierpfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
146126258Smlaier{
147126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
148126258Smlaier	struct ifreq *ifr = (struct ifreq *)data;
149126258Smlaier	int s;
150126258Smlaier
151126258Smlaier	switch (cmd) {
152126258Smlaier	case SIOCSIFADDR:
153126258Smlaier	case SIOCAIFADDR:
154126258Smlaier	case SIOCSIFDSTADDR:
155126258Smlaier	case SIOCSIFFLAGS:
156126258Smlaier		if (ifp->if_flags & IFF_UP)
157126258Smlaier			ifp->if_flags |= IFF_RUNNING;
158126258Smlaier		else
159126258Smlaier			ifp->if_flags &= ~IFF_RUNNING;
160126258Smlaier		break;
161126258Smlaier	case SIOCSIFMTU:
162126258Smlaier		if (ifr->ifr_mtu < PFSYNC_MINMTU)
163126258Smlaier			return (EINVAL);
164126258Smlaier		if (ifr->ifr_mtu > MCLBYTES)
165126258Smlaier			ifr->ifr_mtu = MCLBYTES;
166126258Smlaier		s = splnet();
167126258Smlaier		if (ifr->ifr_mtu < ifp->if_mtu)
168126258Smlaier			pfsync_sendout(sc);
169126258Smlaier		pfsync_setmtu(sc, ifr->ifr_mtu);
170126258Smlaier		splx(s);
171126258Smlaier		break;
172126258Smlaier	default:
173126258Smlaier		return (ENOTTY);
174126258Smlaier	}
175126258Smlaier
176126258Smlaier	return (0);
177126258Smlaier}
178126258Smlaier
179126258Smlaiervoid
180126258Smlaierpfsync_setmtu(sc, mtu)
181126258Smlaier	struct pfsync_softc *sc;
182126258Smlaier	int mtu;
183126258Smlaier{
184126258Smlaier	sc->sc_count = (mtu - sizeof(struct pfsync_header)) /
185126258Smlaier	    sizeof(struct pf_state);
186126258Smlaier	sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
187126258Smlaier	    sc->sc_count * sizeof(struct pf_state);
188126258Smlaier}
189126258Smlaier
190126258Smlaierstruct mbuf *
191126258Smlaierpfsync_get_mbuf(sc, action)
192126258Smlaier	struct pfsync_softc *sc;
193126258Smlaier	u_int8_t action;
194126258Smlaier{
195126258Smlaier	extern int hz;
196126258Smlaier	struct pfsync_header *h;
197126258Smlaier	struct mbuf *m;
198126258Smlaier	int len;
199126258Smlaier
200126258Smlaier	MGETHDR(m, M_DONTWAIT, MT_DATA);
201126258Smlaier	if (m == NULL) {
202126258Smlaier		sc->sc_if.if_oerrors++;
203126258Smlaier		return (NULL);
204126258Smlaier	}
205126258Smlaier
206126258Smlaier	len = sc->sc_if.if_mtu;
207126258Smlaier	if (len > MHLEN) {
208126258Smlaier		MCLGET(m, M_DONTWAIT);
209126258Smlaier		if ((m->m_flags & M_EXT) == 0) {
210126258Smlaier			m_free(m);
211126258Smlaier			sc->sc_if.if_oerrors++;
212126258Smlaier			return (NULL);
213126258Smlaier		}
214126258Smlaier	}
215126258Smlaier	m->m_pkthdr.rcvif = NULL;
216126258Smlaier	m->m_pkthdr.len = m->m_len = len;
217126258Smlaier
218126258Smlaier	h = mtod(m, struct pfsync_header *);
219126258Smlaier	h->version = PFSYNC_VERSION;
220126258Smlaier	h->af = 0;
221126258Smlaier	h->count = 0;
222126258Smlaier	h->action = action;
223126258Smlaier
224126258Smlaier	sc->sc_mbuf = m;
225126258Smlaier	sc->sc_ptr = (struct pf_state *)((char *)h + PFSYNC_HDRLEN);
226126258Smlaier	timeout_add(&sc->sc_tmo, hz);
227126258Smlaier
228126258Smlaier	return (m);
229126258Smlaier}
230126258Smlaier
231126258Smlaierint
232126258Smlaierpfsync_pack_state(action, st)
233126258Smlaier	u_int8_t action;
234126258Smlaier	struct pf_state *st;
235126258Smlaier{
236126258Smlaier	extern struct timeval time;
237126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
238126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
239126258Smlaier	struct pfsync_header *h;
240126258Smlaier	struct pf_state *sp;
241126258Smlaier	struct pf_rule *r = st->rule.ptr;
242126258Smlaier	struct mbuf *m;
243126258Smlaier	u_long secs;
244126258Smlaier	int s, ret;
245126258Smlaier
246126258Smlaier	if (action >= PFSYNC_ACT_MAX)
247126258Smlaier		return (EINVAL);
248126258Smlaier
249126258Smlaier	s = splnet();
250126258Smlaier	m = sc->sc_mbuf;
251126258Smlaier	if (m == NULL) {
252126258Smlaier		if ((m = pfsync_get_mbuf(sc, action)) == NULL) {
253126258Smlaier			splx(s);
254126258Smlaier			return (ENOMEM);
255126258Smlaier		}
256126258Smlaier		h = mtod(m, struct pfsync_header *);
257126258Smlaier	} else {
258126258Smlaier		h = mtod(m, struct pfsync_header *);
259126258Smlaier		if (h->action != action) {
260126258Smlaier			pfsync_sendout(sc);
261126258Smlaier			if ((m = pfsync_get_mbuf(sc, action)) == NULL) {
262126258Smlaier				splx(s);
263126258Smlaier				return (ENOMEM);
264126258Smlaier			}
265126258Smlaier			h = mtod(m, struct pfsync_header *);
266126258Smlaier		}
267126258Smlaier	}
268126258Smlaier
269126258Smlaier	sp = sc->sc_ptr++;
270126258Smlaier	h->count++;
271126258Smlaier	bzero(sp, sizeof(*sp));
272126258Smlaier
273126258Smlaier	bcopy(&st->lan, &sp->lan, sizeof(sp->lan));
274126258Smlaier	bcopy(&st->gwy, &sp->gwy, sizeof(sp->gwy));
275126258Smlaier	bcopy(&st->ext, &sp->ext, sizeof(sp->ext));
276126258Smlaier
277126258Smlaier	pf_state_peer_hton(&st->src, &sp->src);
278126258Smlaier	pf_state_peer_hton(&st->dst, &sp->dst);
279126258Smlaier
280126258Smlaier	bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
281126258Smlaier	secs = time.tv_sec;
282126258Smlaier	sp->creation = htonl(secs - st->creation);
283126258Smlaier	if (st->expire <= secs)
284126258Smlaier		sp->expire = htonl(0);
285126258Smlaier	else
286126258Smlaier		sp->expire = htonl(st->expire - secs);
287126258Smlaier	sp->packets[0] = htonl(st->packets[0]);
288126258Smlaier	sp->packets[1] = htonl(st->packets[1]);
289126258Smlaier	sp->bytes[0] = htonl(st->bytes[0]);
290126258Smlaier	sp->bytes[1] = htonl(st->bytes[1]);
291126258Smlaier	if (r == NULL)
292126258Smlaier		sp->rule.nr = htonl(-1);
293126258Smlaier	else
294126258Smlaier		sp->rule.nr = htonl(r->nr);
295126258Smlaier	sp->af = st->af;
296126258Smlaier	sp->proto = st->proto;
297126258Smlaier	sp->direction = st->direction;
298126258Smlaier	sp->log = st->log;
299126258Smlaier	sp->allow_opts = st->allow_opts;
300126258Smlaier
301126258Smlaier	ret = 0;
302126258Smlaier	if (h->count == sc->sc_count)
303126258Smlaier		ret = pfsync_sendout(sc);
304126258Smlaier
305126258Smlaier	splx(s);
306126258Smlaier	return (0);
307126258Smlaier}
308126258Smlaier
309126258Smlaierint
310126258Smlaierpfsync_clear_state(st)
311126258Smlaier	struct pf_state *st;
312126258Smlaier{
313126258Smlaier	struct ifnet *ifp = &pfsyncif.sc_if;
314126258Smlaier	struct pfsync_softc *sc = ifp->if_softc;
315126258Smlaier	struct mbuf *m = sc->sc_mbuf;
316126258Smlaier	int s, ret;
317126258Smlaier
318126258Smlaier	s = splnet();
319126258Smlaier	if (m == NULL && (m = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR)) == NULL) {
320126258Smlaier		splx(s);
321126258Smlaier		return (ENOMEM);
322126258Smlaier	}
323126258Smlaier
324126258Smlaier	ret = (pfsync_sendout(sc));
325126258Smlaier	splx(s);
326126258Smlaier	return (ret);
327126258Smlaier}
328126258Smlaier
329126258Smlaiervoid
330126258Smlaierpfsync_timeout(void *v)
331126258Smlaier{
332126258Smlaier	struct pfsync_softc *sc = v;
333126258Smlaier	int s;
334126258Smlaier
335126258Smlaier	s = splnet();
336126258Smlaier	pfsync_sendout(sc);
337126258Smlaier	splx(s);
338126258Smlaier}
339126258Smlaier
340126258Smlaierint
341126258Smlaierpfsync_sendout(sc)
342126258Smlaier	struct pfsync_softc *sc;
343126258Smlaier{
344126258Smlaier	struct ifnet *ifp = &sc->sc_if;
345126258Smlaier	struct mbuf *m = sc->sc_mbuf;
346126258Smlaier
347126258Smlaier	timeout_del(&sc->sc_tmo);
348126258Smlaier	sc->sc_mbuf = NULL;
349126258Smlaier	sc->sc_ptr = NULL;
350126258Smlaier
351126258Smlaier#if NBPFILTER > 0
352126258Smlaier	if (ifp->if_bpf)
353126258Smlaier		bpf_mtap(ifp->if_bpf, m);
354126258Smlaier#endif
355126258Smlaier
356126258Smlaier	m_freem(m);
357126258Smlaier
358126258Smlaier	return (0);
359126258Smlaier}
360