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