if_pflog.c revision 223637
1/* $OpenBSD: if_pflog.c,v 1.26 2007/10/18 21:58:18 mpf Exp $ */ 2/* 3 * The authors of this code are John Ioannidis (ji@tla.org), 4 * Angelos D. Keromytis (kermit@csd.uch.gr) and 5 * Niels Provos (provos@physnet.uni-hamburg.de). 6 * 7 * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 8 * in November 1995. 9 * 10 * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 11 * by Angelos D. Keromytis. 12 * 13 * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 14 * and Niels Provos. 15 * 16 * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis 17 * and Niels Provos. 18 * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos. 19 * 20 * Permission to use, copy, and modify this software with or without fee 21 * is hereby granted, provided that this entire notice is included in 22 * all copies of any software which is or includes a copy or 23 * modification of this software. 24 * You may use this code under the GNU public license if you so wish. Please 25 * contribute changes back to the authors under this freer than GPL license 26 * so that we may further the use of strong encryption without limitations to 27 * all. 28 * 29 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 30 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 31 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 32 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 33 * PURPOSE. 34 */ 35 36#ifdef __FreeBSD__ 37#include "opt_inet.h" 38#include "opt_inet6.h" 39#include "opt_bpf.h" 40#include "opt_pf.h" 41 42#include <sys/cdefs.h> 43__FBSDID("$FreeBSD: head/sys/contrib/pf/net/if_pflog.c 223637 2011-06-28 11:57:25Z bz $"); 44 45#ifdef DEV_BPF 46#define NBPFILTER DEV_BPF 47#else 48#define NBPFILTER 0 49#endif 50 51#ifdef DEV_PFLOG 52#define NPFLOG DEV_PFLOG 53#else 54#define NPFLOG 0 55#endif 56 57#else /* ! __FreeBSD__ */ 58#include "bpfilter.h" 59#include "pflog.h" 60#endif /* __FreeBSD__ */ 61 62#include <sys/param.h> 63#include <sys/systm.h> 64#include <sys/mbuf.h> 65#include <sys/proc.h> 66#include <sys/socket.h> 67#ifdef __FreeBSD__ 68#include <sys/kernel.h> 69#include <sys/limits.h> 70#include <sys/malloc.h> 71#include <sys/module.h> 72#include <sys/sockio.h> 73#else 74#include <sys/ioctl.h> 75#endif 76 77#include <net/if.h> 78#ifdef __FreeBSD__ 79#include <net/if_clone.h> 80#endif 81#include <net/if_types.h> 82#include <net/route.h> 83#include <net/bpf.h> 84 85#if defined(INET) || defined(INET6) 86#include <netinet/in.h> 87#endif 88#ifdef INET 89#include <netinet/in_var.h> 90#include <netinet/in_systm.h> 91#include <netinet/ip.h> 92#endif 93 94#ifdef INET6 95#include <netinet6/in6_var.h> 96#include <netinet6/nd6.h> 97#endif /* INET6 */ 98 99#include <net/pfvar.h> 100#include <net/if_pflog.h> 101 102#ifdef __FreeBSD__ 103#ifdef INET 104#include <machine/in_cksum.h> 105#endif /* INET */ 106#endif /* __FreeBSD__ */ 107 108#define PFLOGMTU (32768 + MHLEN + MLEN) 109 110#ifdef PFLOGDEBUG 111#define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0) 112#else 113#define DPRINTF(x) 114#endif 115 116void pflogattach(int); 117int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 118#ifdef __FreeBSD__ 119 struct route *); 120#else 121 struct rtentry *); 122#endif 123int pflogioctl(struct ifnet *, u_long, caddr_t); 124void pflogstart(struct ifnet *); 125#ifdef __FreeBSD__ 126static int pflog_clone_create(struct if_clone *, int, caddr_t); 127static void pflog_clone_destroy(struct ifnet *); 128#else 129int pflog_clone_create(struct if_clone *, int); 130int pflog_clone_destroy(struct ifnet *); 131#endif 132 133LIST_HEAD(, pflog_softc) pflogif_list; 134#ifdef __FreeBSD__ 135IFC_SIMPLE_DECLARE(pflog, 1); 136#else 137struct if_clone pflog_cloner = 138 IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy); 139#endif 140 141struct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */ 142 143void 144pflogattach(int npflog) 145{ 146 int i; 147 LIST_INIT(&pflogif_list); 148 for (i = 0; i < PFLOGIFS_MAX; i++) 149 pflogifs[i] = NULL; 150 if_clone_attach(&pflog_cloner); 151} 152 153#ifdef __FreeBSD__ 154static int 155pflog_clone_create(struct if_clone *ifc, int unit, caddr_t param) 156#else 157int 158pflog_clone_create(struct if_clone *ifc, int unit) 159#endif 160{ 161 struct ifnet *ifp; 162 struct pflog_softc *pflogif; 163 int s; 164 165 if (unit >= PFLOGIFS_MAX) 166 return (EINVAL); 167 168 if ((pflogif = malloc(sizeof(*pflogif), 169 M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 170 return (ENOMEM); 171 172 pflogif->sc_unit = unit; 173#ifdef __FreeBSD__ 174 ifp = pflogif->sc_ifp = if_alloc(IFT_PFLOG); 175 if (ifp == NULL) { 176 free(pflogif, M_DEVBUF); 177 return (ENOSPC); 178 } 179 if_initname(ifp, ifc->ifc_name, unit); 180#else 181 ifp = &pflogif->sc_if; 182 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit); 183#endif 184 ifp->if_softc = pflogif; 185 ifp->if_mtu = PFLOGMTU; 186 ifp->if_ioctl = pflogioctl; 187 ifp->if_output = pflogoutput; 188 ifp->if_start = pflogstart; 189#ifndef __FreeBSD__ 190 ifp->if_type = IFT_PFLOG; 191#endif 192 ifp->if_snd.ifq_maxlen = ifqmaxlen; 193 ifp->if_hdrlen = PFLOG_HDRLEN; 194 if_attach(ifp); 195#ifndef __FreeBSD__ 196 if_alloc_sadl(ifp); 197#endif 198 199#if NBPFILTER > 0 200#ifdef __FreeBSD__ 201 bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN); 202#else 203 bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN); 204#endif 205#endif 206 207 s = splnet(); 208#ifdef __FreeBSD__ 209 /* XXX: Why pf(4) lock?! Better add a pflog lock?! */ 210 PF_LOCK(); 211#endif 212 LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list); 213 pflogifs[unit] = ifp; 214#ifdef __FreeBSD__ 215 PF_UNLOCK(); 216#endif 217 splx(s); 218 219 return (0); 220} 221 222#ifdef __FreeBSD__ 223static void 224pflog_clone_destroy(struct ifnet *ifp) 225#else 226int 227pflog_clone_destroy(struct ifnet *ifp) 228#endif 229{ 230 struct pflog_softc *pflogif = ifp->if_softc; 231 int s; 232 233 s = splnet(); 234#ifdef __FreeBSD__ 235 PF_LOCK(); 236#endif 237 pflogifs[pflogif->sc_unit] = NULL; 238 LIST_REMOVE(pflogif, sc_list); 239#ifdef __FreeBSD__ 240 PF_UNLOCK(); 241#endif 242 splx(s); 243 244#if NBPFILTER > 0 245 bpfdetach(ifp); 246#endif 247 if_detach(ifp); 248#ifdef __FreeBSD__ 249 if_free(ifp); 250#endif 251 free(pflogif, M_DEVBUF); 252#ifndef __FreeBSD__ 253 return (0); 254#endif 255} 256 257/* 258 * Start output on the pflog interface. 259 */ 260void 261pflogstart(struct ifnet *ifp) 262{ 263 struct mbuf *m; 264#ifndef __FreeBSD__ 265 int s; 266#endif 267 268 for (;;) { 269#ifdef __FreeBSD__ 270 IF_LOCK(&ifp->if_snd); 271 _IF_DROP(&ifp->if_snd); 272 _IF_DEQUEUE(&ifp->if_snd, m); 273 IF_UNLOCK(&ifp->if_snd); 274#else 275 s = splnet(); 276 IF_DROP(&ifp->if_snd); 277 IF_DEQUEUE(&ifp->if_snd, m); 278 splx(s); 279#endif 280 281 if (m == NULL) 282 return; 283 else 284 m_freem(m); 285 } 286} 287 288int 289pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 290#ifdef __FreeBSD__ 291 struct route *rt) 292#else 293 struct rtentry *rt) 294#endif 295{ 296 m_freem(m); 297 return (0); 298} 299 300/* ARGSUSED */ 301int 302pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 303{ 304 switch (cmd) { 305 case SIOCSIFFLAGS: 306#ifdef __FreeBSD__ 307 if (ifp->if_flags & IFF_UP) 308 ifp->if_drv_flags |= IFF_DRV_RUNNING; 309 else 310 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 311#else 312 if (ifp->if_flags & IFF_UP) 313 ifp->if_flags |= IFF_RUNNING; 314 else 315 ifp->if_flags &= ~IFF_RUNNING; 316#endif 317 break; 318 default: 319 return (ENOTTY); 320 } 321 322 return (0); 323} 324 325int 326pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, 327 u_int8_t reason, struct pf_rule *rm, struct pf_rule *am, 328 struct pf_ruleset *ruleset, struct pf_pdesc *pd) 329{ 330#if NBPFILTER > 0 331 struct ifnet *ifn; 332 struct pfloghdr hdr; 333 334 if (kif == NULL || m == NULL || rm == NULL || pd == NULL) 335 return ( 1); 336 337 if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf) 338 return (0); 339 340 bzero(&hdr, sizeof(hdr)); 341 hdr.length = PFLOG_REAL_HDRLEN; 342 hdr.af = af; 343 hdr.action = rm->action; 344 hdr.reason = reason; 345 memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname)); 346 347 if (am == NULL) { 348 hdr.rulenr = htonl(rm->nr); 349 hdr.subrulenr = 1; 350 } else { 351 hdr.rulenr = htonl(am->nr); 352 hdr.subrulenr = htonl(rm->nr); 353 if (ruleset != NULL && ruleset->anchor != NULL) 354 strlcpy(hdr.ruleset, ruleset->anchor->name, 355 sizeof(hdr.ruleset)); 356 } 357 if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done) 358#ifdef __FreeBSD__ 359 /* 360 * XXX: This should not happen as we force an early lookup 361 * via debug.pfugidhack 362 */ 363 ; /* empty */ 364#else 365 pd->lookup.done = pf_socket_lookup(dir, pd); 366#endif 367 if (pd->lookup.done > 0) { 368 hdr.uid = pd->lookup.uid; 369 hdr.pid = pd->lookup.pid; 370 } else { 371 hdr.uid = UID_MAX; 372 hdr.pid = NO_PID; 373 } 374 hdr.rule_uid = rm->cuid; 375 hdr.rule_pid = rm->cpid; 376 hdr.dir = dir; 377 378#ifdef INET 379 if (af == AF_INET && dir == PF_OUT) { 380 struct ip *ip; 381 382 ip = mtod(m, struct ip *); 383 ip->ip_sum = 0; 384 ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 385 } 386#endif /* INET */ 387 388 ifn->if_opackets++; 389 ifn->if_obytes += m->m_pkthdr.len; 390#ifdef __FreeBSD__ 391 BPF_MTAP2(ifn, &hdr, PFLOG_HDRLEN, m); 392#else 393 bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m, 394 BPF_DIRECTION_OUT); 395#endif 396#endif 397 398 return (0); 399} 400 401#ifdef __FreeBSD__ 402static int 403pflog_modevent(module_t mod, int type, void *data) 404{ 405 int error = 0; 406 407 switch (type) { 408 case MOD_LOAD: 409 pflogattach(1); 410 PF_LOCK(); 411 pflog_packet_ptr = pflog_packet; 412 PF_UNLOCK(); 413 break; 414 case MOD_UNLOAD: 415 PF_LOCK(); 416 pflog_packet_ptr = NULL; 417 PF_UNLOCK(); 418 if_clone_detach(&pflog_cloner); 419 break; 420 default: 421 error = EINVAL; 422 break; 423 } 424 425 return error; 426} 427 428static moduledata_t pflog_mod = { "pflog", pflog_modevent, 0 }; 429 430#define PFLOG_MODVER 1 431 432DECLARE_MODULE(pflog, pflog_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 433MODULE_VERSION(pflog, PFLOG_MODVER); 434MODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER); 435#endif /* __FreeBSD__ */ 436