if_pfsync.c revision 126259
1/* $OpenBSD: if_pfsync.c,v 1.6 2003/06/21 09:07:01 djm 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) 65int pfsyncdebug; 66#else 67#define DPRINTF(x) 68#endif 69 70struct pfsync_softc pfsyncif; 71 72void pfsyncattach(int); 73void pfsync_setmtu(struct pfsync_softc *sc, int); 74int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 75 struct rtentry *); 76int pfsyncioctl(struct ifnet *, u_long, caddr_t); 77void pfsyncstart(struct ifnet *); 78 79struct mbuf *pfsync_get_mbuf(struct pfsync_softc *sc, u_int8_t action); 80int pfsync_sendout(struct pfsync_softc *sc); 81void pfsync_timeout(void *v); 82 83extern int ifqmaxlen; 84 85void 86pfsyncattach(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 */ 116void 117pfsyncstart(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 135int 136pfsyncoutput(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 */ 144int 145pfsyncioctl(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 179void 180pfsync_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 190struct mbuf * 191pfsync_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 231int 232pfsync_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 = st->rule.ptr; 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 == NULL) 292 sp->rule.nr = htonl(-1); 293 else 294 sp->rule.nr = htonl(r->nr); 295 sp->af = st->af; 296 sp->proto = st->proto; 297 sp->direction = st->direction; 298 sp->log = st->log; 299 sp->allow_opts = st->allow_opts; 300 301 ret = 0; 302 if (h->count == sc->sc_count) 303 ret = pfsync_sendout(sc); 304 305 splx(s); 306 return (0); 307} 308 309int 310pfsync_clear_state(st) 311 struct pf_state *st; 312{ 313 struct ifnet *ifp = &pfsyncif.sc_if; 314 struct pfsync_softc *sc = ifp->if_softc; 315 struct mbuf *m = sc->sc_mbuf; 316 int s, ret; 317 318 s = splnet(); 319 if (m == NULL && (m = pfsync_get_mbuf(sc, PFSYNC_ACT_CLR)) == NULL) { 320 splx(s); 321 return (ENOMEM); 322 } 323 324 ret = (pfsync_sendout(sc)); 325 splx(s); 326 return (ret); 327} 328 329void 330pfsync_timeout(void *v) 331{ 332 struct pfsync_softc *sc = v; 333 int s; 334 335 s = splnet(); 336 pfsync_sendout(sc); 337 splx(s); 338} 339 340int 341pfsync_sendout(sc) 342 struct pfsync_softc *sc; 343{ 344 struct ifnet *ifp = &sc->sc_if; 345 struct mbuf *m = sc->sc_mbuf; 346 347 timeout_del(&sc->sc_tmo); 348 sc->sc_mbuf = NULL; 349 sc->sc_ptr = NULL; 350 351#if NBPFILTER > 0 352 if (ifp->if_bpf) 353 bpf_mtap(ifp->if_bpf, m); 354#endif 355 356 m_freem(m); 357 358 return (0); 359} 360