if_pflog.c revision 126261
1164856Sdds/* $FreeBSD: head/sys/contrib/pf/net/if_pflog.c 126261 2004-02-26 02:34:12Z mlaier $ */ 2164856Sdds/* $OpenBSD: if_pflog.c,v 1.9 2003/05/14 08:42:00 canacar Exp $ */ 3164856Sdds/* 4164856Sdds * The authors of this code are John Ioannidis (ji@tla.org), 5164856Sdds * Angelos D. Keromytis (kermit@csd.uch.gr) and 6164856Sdds * Niels Provos (provos@physnet.uni-hamburg.de). 7164856Sdds * 8164856Sdds * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 9164856Sdds * in November 1995. 10164856Sdds * 11 * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 12 * by Angelos D. Keromytis. 13 * 14 * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 15 * and Niels Provos. 16 * 17 * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis 18 * and Niels Provos. 19 * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos. 20 * 21 * Permission to use, copy, and modify this software with or without fee 22 * is hereby granted, provided that this entire notice is included in 23 * all copies of any software which is or includes a copy or 24 * modification of this software. 25 * You may use this code under the GNU public license if you so wish. Please 26 * contribute changes back to the authors under this freer than GPL license 27 * so that we may further the use of strong encryption without limitations to 28 * all. 29 * 30 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 31 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 32 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 33 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 34 * PURPOSE. 35 */ 36 37#if defined(__FreeBSD__) 38#include "opt_inet.h" 39#include "opt_inet6.h" 40#endif 41 42#if !defined(__FreeBSD__) 43#include "bpfilter.h" 44#include "pflog.h" 45#elif __FreeBSD__ >= 5 46#include "opt_bpf.h" 47#define NBPFILTER DEV_BPF 48#include "opt_pf.h" 49#define NPFLOG DEV_PFLOG 50#endif 51 52#include <sys/param.h> 53#include <sys/systm.h> 54#include <sys/mbuf.h> 55#include <sys/socket.h> 56#if defined(__FreeBSD__) 57#include <sys/kernel.h> 58#include <sys/malloc.h> 59#include <sys/sockio.h> 60#else 61#include <sys/ioctl.h> 62#endif 63 64#include <net/if.h> 65#include <net/if_types.h> 66#include <net/route.h> 67#include <net/bpf.h> 68 69#ifdef INET 70#include <netinet/in.h> 71#include <netinet/in_var.h> 72#include <netinet/in_systm.h> 73#include <netinet/ip.h> 74#endif 75 76#if defined(__FreeBSD__) 77#include <machine/in_cksum.h> 78#endif 79 80#ifdef INET6 81#ifndef INET 82#include <netinet/in.h> 83#endif 84#include <netinet6/nd6.h> 85#endif /* INET6 */ 86 87#include <net/pfvar.h> 88#include <net/if_pflog.h> 89 90#if defined(__FreeBSD__) 91#define PFLOGNAME "pflog" 92#endif 93 94#define PFLOGMTU (32768 + MHLEN + MLEN) 95 96#ifdef PFLOGDEBUG 97#define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0) 98#else 99#define DPRINTF(x) 100#endif 101 102#if !defined(__FreeBSD__) 103struct pflog_softc pflogif[NPFLOG]; 104#endif 105 106#if defined(__FreeBSD__) 107void pflog_clone_destroy(struct ifnet *); 108int pflog_clone_create(struct if_clone *, int); 109#else 110void pflogattach(int); 111#endif 112int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 113 struct rtentry *); 114int pflogioctl(struct ifnet *, u_long, caddr_t); 115void pflogrtrequest(int, struct rtentry *, struct sockaddr *); 116void pflogstart(struct ifnet *); 117 118#if !defined(__FreeBSD__) 119extern int ifqmaxlen; 120#endif 121 122#if defined(__FreeBSD__) 123static MALLOC_DEFINE(M_PFLOG, PFLOGNAME, "Packet Filter Logging Interface"); 124static LIST_HEAD(pflog_list, pflog_softc) pflog_list; 125struct if_clone pflog_cloner = IF_CLONE_INITIALIZER(PFLOGNAME, 126 pflog_clone_create, pflog_clone_destroy, 1, IF_MAXUNIT); 127 128void 129pflog_clone_destroy(struct ifnet *ifp) 130{ 131 struct pflog_softc *sc; 132 133 sc = ifp->if_softc; 134 135 /* 136 * Does we really need this? 137 */ 138 IF_DRAIN(&ifp->if_snd); 139 140 bpfdetach(ifp); 141 if_detach(ifp); 142 LIST_REMOVE(sc, sc_next); 143 free(sc, M_PFLOG); 144} 145#endif /* __FreeBSD__ */ 146 147#if defined(__FreeBSD__) 148int 149pflog_clone_create(struct if_clone *ifc, int unit) 150{ 151 struct pflog_softc *sc; 152 153 MALLOC(sc, struct pflog_softc *, sizeof(*sc), M_PFLOG, M_WAITOK|M_ZERO); 154 155#if (__FreeBSD_version < 501113) 156 sc->sc_if.if_name = PFLOGNAME; 157 sc->sc_if.if_unit = unit; 158#else 159 if_initname(&sc->sc_if, ifc->ifc_name, unit); 160#endif 161 sc->sc_if.if_mtu = PFLOGMTU; 162 sc->sc_if.if_ioctl = pflogioctl; 163 sc->sc_if.if_output = pflogoutput; 164 sc->sc_if.if_start = pflogstart; 165 sc->sc_if.if_type = IFT_PFLOG; 166 sc->sc_if.if_snd.ifq_maxlen = ifqmaxlen; 167 sc->sc_if.if_hdrlen = PFLOG_HDRLEN; 168 sc->sc_if.if_softc = sc; 169 /* 170 * We would get a message like 171 * "in6_ifattach: pflog0 is not multicast capable, IPv6 not enabled". 172 * We need a patch to in6_ifattach() to exclude interface type 173 * IFT_PFLOG. 174 */ 175 if_attach(&sc->sc_if); 176 177 LIST_INSERT_HEAD(&pflog_list, sc, sc_next); 178#if NBPFILTER > 0 179 bpfattach(&sc->sc_if, DLT_PFLOG, PFLOG_HDRLEN); 180#endif 181 182 return (0); 183} 184#else /* !__FreeBSD__ */ 185void 186pflogattach(int npflog) 187{ 188 struct ifnet *ifp; 189 int i; 190 191 bzero(pflogif, sizeof(pflogif)); 192 193 for (i = 0; i < NPFLOG; i++) { 194 ifp = &pflogif[i].sc_if; 195 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", i); 196 ifp->if_softc = &pflogif[i]; 197 ifp->if_mtu = PFLOGMTU; 198 ifp->if_ioctl = pflogioctl; 199 ifp->if_output = pflogoutput; 200 ifp->if_start = pflogstart; 201 ifp->if_type = IFT_PFLOG; 202 ifp->if_snd.ifq_maxlen = ifqmaxlen; 203 ifp->if_hdrlen = PFLOG_HDRLEN; 204 if_attach(ifp); 205 if_alloc_sadl(ifp); 206 207#if NBPFILTER > 0 208 bpfattach(&pflogif[i].sc_if.if_bpf, ifp, DLT_PFLOG, 209 PFLOG_HDRLEN); 210#endif 211 } 212} 213#endif /* __FreeBSD__ */ 214 215/* 216 * Start output on the pflog interface. 217 */ 218void 219pflogstart(struct ifnet *ifp) 220{ 221 struct mbuf *m; 222#if defined(__FreeBSD__) && defined(ALTQ) 223 struct ifaltq *ifq; 224#else 225 struct ifqueue *ifq; 226#endif 227 int s; 228 229#if defined(__FreeBSD__) 230 ifq = &ifp->if_snd; 231#endif 232 for (;;) { 233 s = splimp(); 234#if defined(__FreeBSD__) 235 IF_LOCK(ifq); 236 _IF_DROP(ifq); 237 _IF_DEQUEUE(ifq, m); 238 IF_UNLOCK(ifq); 239#else 240 IF_DROP(&ifp->if_snd); 241 IF_DEQUEUE(&ifp->if_snd, m); 242#endif 243 splx(s); 244 if (m == NULL) 245 return; 246 else 247 m_freem(m); 248 } 249} 250 251int 252pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 253 struct rtentry *rt) 254{ 255 m_freem(m); 256 return (0); 257} 258 259/* ARGSUSED */ 260void 261pflogrtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa) 262{ 263 if (rt) 264 rt->rt_rmx.rmx_mtu = PFLOGMTU; 265} 266 267/* ARGSUSED */ 268int 269pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 270{ 271 switch (cmd) { 272 case SIOCSIFADDR: 273 case SIOCAIFADDR: 274 case SIOCSIFDSTADDR: 275 case SIOCSIFFLAGS: 276 if (ifp->if_flags & IFF_UP) 277 ifp->if_flags |= IFF_RUNNING; 278 else 279 ifp->if_flags &= ~IFF_RUNNING; 280 break; 281 default: 282 return (EINVAL); 283 } 284 285 return (0); 286} 287 288int 289pflog_packet(struct ifnet *ifp, struct mbuf *m, sa_family_t af, u_int8_t dir, 290 u_int8_t reason, struct pf_rule *rm, struct pf_rule *am, 291 struct pf_ruleset *ruleset) 292{ 293#if NBPFILTER > 0 294 struct ifnet *ifn; 295 struct pfloghdr hdr; 296 struct mbuf m1; 297 298 if (ifp == NULL || m == NULL || rm == NULL) 299 return (-1); 300 301 hdr.length = PFLOG_REAL_HDRLEN; 302 hdr.af = af; 303 hdr.action = rm->action; 304 hdr.reason = reason; 305#if defined(__FreeBSD__) && (__FreeBSD_version < 501113) 306 snprintf(hdr.ifname, IFNAMSIZ, "%s%d", ifp->if_name, ifp->if_unit); 307#else 308 memcpy(hdr.ifname, ifp->if_xname, sizeof(hdr.ifname)); 309#endif 310 311 if (am == NULL) { 312 hdr.rulenr = htonl(rm->nr); 313 hdr.subrulenr = -1; 314 bzero(hdr.ruleset, sizeof(hdr.ruleset)); 315 } else { 316 hdr.rulenr = htonl(am->nr); 317 hdr.subrulenr = htonl(rm->nr); 318 if (ruleset == NULL) 319 bzero(hdr.ruleset, sizeof(hdr.ruleset)); 320 else 321 memcpy(hdr.ruleset, ruleset->name, 322 sizeof(hdr.ruleset)); 323 324 325 } 326 hdr.dir = dir; 327 328#ifdef INET 329 if (af == AF_INET && dir == PF_OUT) { 330 struct ip *ip; 331 332 ip = mtod(m, struct ip *); 333 ip->ip_sum = 0; 334 ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 335 } 336#endif /* INET */ 337 338 m1.m_next = m; 339 m1.m_len = PFLOG_HDRLEN; 340 m1.m_data = (char *) &hdr; 341 342#if defined(__FreeBSD__) 343 KASSERT((!LIST_EMPTY(&pflog_list)), ("pflog: no interface")); 344 ifn = &LIST_FIRST(&pflog_list)->sc_if; 345#else 346 ifn = &(pflogif[0].sc_if); 347#endif 348 349 if (ifn->if_bpf) 350 bpf_mtap(ifn->if_bpf, &m1); 351#endif 352 353 return (0); 354} 355 356#if defined(__FreeBSD__) 357static int 358pflog_modevent(module_t mod, int type, void *data) 359{ 360 int error = 0; 361 362 switch (type) { 363 case MOD_LOAD: 364 LIST_INIT(&pflog_list); 365 if_clone_attach(&pflog_cloner); 366 printf("pflog: $Name: $\n"); 367 break; 368 369 case MOD_UNLOAD: 370 if_clone_detach(&pflog_cloner); 371 while (!LIST_EMPTY(&pflog_list)) 372 pflog_clone_destroy( 373 &LIST_FIRST(&pflog_list)->sc_if); 374 break; 375 376 default: 377 error = EINVAL; 378 break; 379 } 380 381 return error; 382} 383 384static moduledata_t pflog_mod = { 385 "pflog", 386 pflog_modevent, 387 0 388}; 389 390#define PFLOG_MODVER 1 391 392DECLARE_MODULE(pflog, pflog_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 393MODULE_VERSION(pflog, PFLOG_MODVER); 394#endif /* __FreeBSD__ */ 395