xref: /openbsd-src/sys/net/if_pfsync.c (revision 8500990981f885cbe5e6a4958549cacc238b5ae6)
1 /*	$OpenBSD: if_pfsync.c,v 1.7 2003/11/08 19:51:38 dhartmei Exp $	*/
2 
3 /*
4  * Copyright (c) 2002 Michael Shalayeff
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "bpfilter.h"
30 #include "pfsync.h"
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/time.h>
35 #include <sys/mbuf.h>
36 #include <sys/socket.h>
37 #include <sys/ioctl.h>
38 #include <sys/timeout.h>
39 
40 #include <net/if.h>
41 #include <net/if_types.h>
42 #include <net/route.h>
43 #include <net/bpf.h>
44 
45 #ifdef	INET
46 #include <netinet/in.h>
47 #include <netinet/in_var.h>
48 #endif
49 
50 #ifdef INET6
51 #ifndef INET
52 #include <netinet/in.h>
53 #endif
54 #include <netinet6/nd6.h>
55 #endif /* INET6 */
56 
57 #include <net/pfvar.h>
58 #include <net/if_pfsync.h>
59 
60 #define PFSYNC_MINMTU	\
61     (sizeof(struct pfsync_header) + sizeof(struct pf_state))
62 
63 #ifdef PFSYNCDEBUG
64 #define DPRINTF(x)    do { if (pfsyncdebug) printf x ; } while (0)
65 int pfsyncdebug;
66 #else
67 #define DPRINTF(x)
68 #endif
69 
70 struct pfsync_softc pfsyncif;
71 
72 void	pfsyncattach(int);
73 void	pfsync_setmtu(struct pfsync_softc *sc, int);
74 int	pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
75 	       struct rtentry *);
76 int	pfsyncioctl(struct ifnet *, u_long, caddr_t);
77 void	pfsyncstart(struct ifnet *);
78 
79 struct mbuf *pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action);
80 int	pfsync_sendout(struct pfsync_softc *sc);
81 void	pfsync_timeout(void *v);
82 
83 extern int ifqmaxlen;
84 
85 void
86 pfsyncattach(int npfsync)
87 {
88 	struct ifnet *ifp;
89 
90 	pfsyncif.sc_mbuf = NULL;
91 	pfsyncif.sc_ptr = NULL;
92 	pfsyncif.sc_count = 8;
93 	ifp = &pfsyncif.sc_if;
94 	strlcpy(ifp->if_xname, "pfsync0", sizeof ifp->if_xname);
95 	ifp->if_softc = &pfsyncif;
96 	ifp->if_ioctl = pfsyncioctl;
97 	ifp->if_output = pfsyncoutput;
98 	ifp->if_start = pfsyncstart;
99 	ifp->if_type = IFT_PFSYNC;
100 	ifp->if_snd.ifq_maxlen = ifqmaxlen;
101 	ifp->if_hdrlen = PFSYNC_HDRLEN;
102 	ifp->if_baudrate = IF_Mbps(100);
103 	pfsync_setmtu(&pfsyncif, MCLBYTES);
104 	timeout_set(&pfsyncif.sc_tmo, pfsync_timeout, &pfsyncif);
105 	if_attach(ifp);
106 	if_alloc_sadl(ifp);
107 
108 #if NBPFILTER > 0
109 	bpfattach(&pfsyncif.sc_if.if_bpf, ifp, DLT_PFSYNC, PFSYNC_HDRLEN);
110 #endif
111 }
112 
113 /*
114  * Start output on the pfsync interface.
115  */
116 void
117 pfsyncstart(struct ifnet *ifp)
118 {
119 	struct mbuf *m;
120 	int s;
121 
122 	for (;;) {
123 		s = splimp();
124 		IF_DROP(&ifp->if_snd);
125 		IF_DEQUEUE(&ifp->if_snd, m);
126 		splx(s);
127 
128 		if (m == NULL)
129 			return;
130 		else
131 			m_freem(m);
132 	}
133 }
134 
135 int
136 pfsyncoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
137 	struct rtentry *rt)
138 {
139 	m_freem(m);
140 	return (0);
141 }
142 
143 /* ARGSUSED */
144 int
145 pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
146 {
147 	struct pfsync_softc *sc = ifp->if_softc;
148 	struct ifreq *ifr = (struct ifreq *)data;
149 	int s;
150 
151 	switch (cmd) {
152 	case SIOCSIFADDR:
153 	case SIOCAIFADDR:
154 	case SIOCSIFDSTADDR:
155 	case SIOCSIFFLAGS:
156 		if (ifp->if_flags & IFF_UP)
157 			ifp->if_flags |= IFF_RUNNING;
158 		else
159 			ifp->if_flags &= ~IFF_RUNNING;
160 		break;
161 	case SIOCSIFMTU:
162 		if (ifr->ifr_mtu < PFSYNC_MINMTU)
163 			return (EINVAL);
164 		if (ifr->ifr_mtu > MCLBYTES)
165 			ifr->ifr_mtu = MCLBYTES;
166 		s = splnet();
167 		if (ifr->ifr_mtu < ifp->if_mtu)
168 			pfsync_sendout(sc);
169 		pfsync_setmtu(sc, ifr->ifr_mtu);
170 		splx(s);
171 		break;
172 	default:
173 		return (ENOTTY);
174 	}
175 
176 	return (0);
177 }
178 
179 void
180 pfsync_setmtu(sc, mtu)
181 	struct pfsync_softc *sc;
182 	int mtu;
183 {
184 	sc->sc_count = (mtu - sizeof(struct pfsync_header)) /
185 	    sizeof(struct pf_state);
186 	sc->sc_if.if_mtu = sizeof(struct pfsync_header) +
187 	    sc->sc_count * sizeof(struct pf_state);
188 }
189 
190 struct mbuf *
191 pfsync_get_mbuf(sc, action)
192 	struct pfsync_softc *sc;
193 	u_int8_t action;
194 {
195 	extern int hz;
196 	struct pfsync_header *h;
197 	struct mbuf *m;
198 	int len;
199 
200 	MGETHDR(m, M_DONTWAIT, MT_DATA);
201 	if (m == NULL) {
202 		sc->sc_if.if_oerrors++;
203 		return (NULL);
204 	}
205 
206 	len = sc->sc_if.if_mtu;
207 	if (len > MHLEN) {
208 		MCLGET(m, M_DONTWAIT);
209 		if ((m->m_flags & M_EXT) == 0) {
210 			m_free(m);
211 			sc->sc_if.if_oerrors++;
212 			return (NULL);
213 		}
214 	}
215 	m->m_pkthdr.rcvif = NULL;
216 	m->m_pkthdr.len = m->m_len = len;
217 
218 	h = mtod(m, struct pfsync_header *);
219 	h->version = PFSYNC_VERSION;
220 	h->af = 0;
221 	h->count = 0;
222 	h->action = action;
223 
224 	sc->sc_mbuf = m;
225 	sc->sc_ptr = (struct pf_state *)((char *)h + PFSYNC_HDRLEN);
226 	timeout_add(&sc->sc_tmo, hz);
227 
228 	return (m);
229 }
230 
231 int
232 pfsync_pack_state(action, st)
233 	u_int8_t action;
234 	struct pf_state *st;
235 {
236 	extern struct timeval time;
237 	struct ifnet *ifp = &pfsyncif.sc_if;
238 	struct pfsync_softc *sc = ifp->if_softc;
239 	struct pfsync_header *h;
240 	struct pf_state *sp;
241 	struct pf_rule *r;
242 	struct mbuf *m;
243 	u_long secs;
244 	int s, ret;
245 
246 	if (action >= PFSYNC_ACT_MAX)
247 		return (EINVAL);
248 
249 	s = splnet();
250 	m = sc->sc_mbuf;
251 	if (m == NULL) {
252 		if ((m = pfsync_get_mbuf(sc, action)) == NULL) {
253 			splx(s);
254 			return (ENOMEM);
255 		}
256 		h = mtod(m, struct pfsync_header *);
257 	} else {
258 		h = mtod(m, struct pfsync_header *);
259 		if (h->action != action) {
260 			pfsync_sendout(sc);
261 			if ((m = pfsync_get_mbuf(sc, action)) == NULL) {
262 				splx(s);
263 				return (ENOMEM);
264 			}
265 			h = mtod(m, struct pfsync_header *);
266 		}
267 	}
268 
269 	sp = sc->sc_ptr++;
270 	h->count++;
271 	bzero(sp, sizeof(*sp));
272 
273 	bcopy(&st->lan, &sp->lan, sizeof(sp->lan));
274 	bcopy(&st->gwy, &sp->gwy, sizeof(sp->gwy));
275 	bcopy(&st->ext, &sp->ext, sizeof(sp->ext));
276 
277 	pf_state_peer_hton(&st->src, &sp->src);
278 	pf_state_peer_hton(&st->dst, &sp->dst);
279 
280 	bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr));
281 	secs = time.tv_sec;
282 	sp->creation = htonl(secs - st->creation);
283 	if (st->expire <= secs)
284 		sp->expire = htonl(0);
285 	else
286 		sp->expire = htonl(st->expire - secs);
287 	sp->packets[0] = htonl(st->packets[0]);
288 	sp->packets[1] = htonl(st->packets[1]);
289 	sp->bytes[0] = htonl(st->bytes[0]);
290 	sp->bytes[1] = htonl(st->bytes[1]);
291 	if ((r = st->rule.ptr) == NULL)
292 		sp->rule.nr = htonl(-1);
293 	else
294 		sp->rule.nr = htonl(r->nr);
295 	if ((r = st->anchor.ptr) == NULL)
296 		sp->anchor.nr = htonl(-1);
297 	else
298 		sp->anchor.nr = htonl(r->nr);
299 	sp->af = st->af;
300 	sp->proto = st->proto;
301 	sp->direction = st->direction;
302 	sp->log = st->log;
303 	sp->allow_opts = st->allow_opts;
304 
305 	ret = 0;
306 	if (h->count == sc->sc_count)
307 		ret = pfsync_sendout(sc);
308 
309 	splx(s);
310 	return (0);
311 }
312 
313 int
314 pfsync_clear_state(st)
315 	struct pf_state *st;
316 {
317 	struct ifnet *ifp = &pfsyncif.sc_if;
318 	struct pfsync_softc *sc = ifp->if_softc;
319 	struct mbuf *m = sc->sc_mbuf;
320 	int s, ret;
321 
322 	s = splnet();
323 	if (m == NULL && (m = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR)) == NULL) {
324 		splx(s);
325 		return (ENOMEM);
326 	}
327 
328 	ret = (pfsync_sendout(sc));
329 	splx(s);
330 	return (ret);
331 }
332 
333 void
334 pfsync_timeout(void *v)
335 {
336 	struct pfsync_softc *sc = v;
337 	int s;
338 
339 	s = splnet();
340 	pfsync_sendout(sc);
341 	splx(s);
342 }
343 
344 int
345 pfsync_sendout(sc)
346 	struct pfsync_softc *sc;
347 {
348 	struct ifnet *ifp = &sc->sc_if;
349 	struct mbuf *m = sc->sc_mbuf;
350 
351 	timeout_del(&sc->sc_tmo);
352 	sc->sc_mbuf = NULL;
353 	sc->sc_ptr = NULL;
354 
355 #if NBPFILTER > 0
356 	if (ifp->if_bpf)
357 		bpf_mtap(ifp->if_bpf, m);
358 #endif
359 
360 	m_freem(m);
361 
362 	return (0);
363 }
364