if_pflog.c revision 171168
1/* $OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto 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 171168 2007-07-03 12:16:07Z mlaier $"); 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#ifdef INET 86#include <netinet/in.h> 87#include <netinet/in_var.h> 88#include <netinet/in_systm.h> 89#include <netinet/ip.h> 90#endif 91 92#ifdef INET6 93#ifndef INET 94#include <netinet/in.h> 95#endif 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#include <machine/in_cksum.h> 104#endif 105 106#define PFLOGMTU (32768 + MHLEN + MLEN) 107 108#ifdef PFLOGDEBUG 109#define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0) 110#else 111#define DPRINTF(x) 112#endif 113 114void pflogattach(int); 115int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 116 struct rtentry *); 117int pflogioctl(struct ifnet *, u_long, caddr_t); 118void pflogstart(struct ifnet *); 119#ifdef __FreeBSD__ 120static int pflog_clone_create(struct if_clone *, int, caddr_t); 121static void pflog_clone_destroy(struct ifnet *); 122#else 123int pflog_clone_create(struct if_clone *, int); 124int pflog_clone_destroy(struct ifnet *); 125#endif 126 127LIST_HEAD(, pflog_softc) pflogif_list; 128#ifdef __FreeBSD__ 129IFC_SIMPLE_DECLARE(pflog, 1); 130#else 131struct if_clone pflog_cloner = 132 IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy); 133#endif 134 135struct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */ 136 137#ifndef __FreeBSD__ 138extern int ifqmaxlen; 139#endif 140 141void 142pflogattach(int npflog) 143{ 144 int i; 145 LIST_INIT(&pflogif_list); 146 for (i = 0; i < PFLOGIFS_MAX; i++) 147 pflogifs[i] = NULL; 148#ifndef __FreeBSD__ 149 (void) pflog_clone_create(&pflog_cloner, 0); 150#endif 151 if_clone_attach(&pflog_cloner); 152} 153 154#ifdef __FreeBSD__ 155static int 156pflog_clone_create(struct if_clone *ifc, int unit, caddr_t param) 157#else 158int 159pflog_clone_create(struct if_clone *ifc, int unit) 160#endif 161{ 162 struct ifnet *ifp; 163 struct pflog_softc *pflogif; 164 int s; 165 166 if (unit >= PFLOGIFS_MAX) 167 return (EINVAL); 168 169 if ((pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_NOWAIT)) == NULL) 170 return (ENOMEM); 171 bzero(pflogif, sizeof(*pflogif)); 172 173 pflogif->sc_unit = unit; 174#ifdef __FreeBSD__ 175 ifp = pflogif->sc_ifp = if_alloc(IFT_PFLOG); 176 if (ifp == NULL) { 177 free(pflogif, M_DEVBUF); 178 return (ENOSPC); 179 } 180 if_initname(ifp, ifc->ifc_name, unit); 181#else 182 ifp = &pflogif->sc_if; 183 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit); 184#endif 185 ifp->if_softc = pflogif; 186 ifp->if_mtu = PFLOGMTU; 187 ifp->if_ioctl = pflogioctl; 188 ifp->if_output = pflogoutput; 189 ifp->if_start = pflogstart; 190#ifndef __FreeBSD__ 191 ifp->if_type = IFT_PFLOG; 192#endif 193 ifp->if_snd.ifq_maxlen = ifqmaxlen; 194 ifp->if_hdrlen = PFLOG_HDRLEN; 195 if_attach(ifp); 196#ifndef __FreeBSD__ 197 if_alloc_sadl(ifp); 198#endif 199 200#if NBPFILTER > 0 201#ifdef __FreeBSD__ 202 bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN); 203#else 204 bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN); 205#endif 206#endif 207 208 s = splnet(); 209#ifdef __FreeBSD__ 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 struct rtentry *rt) 291{ 292 m_freem(m); 293 return (0); 294} 295 296/* ARGSUSED */ 297int 298pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 299{ 300 switch (cmd) { 301 case SIOCSIFADDR: 302 case SIOCAIFADDR: 303 case SIOCSIFDSTADDR: 304 case SIOCSIFFLAGS: 305#ifdef __FreeBSD__ 306 if (ifp->if_flags & IFF_UP) 307 ifp->if_drv_flags |= IFF_DRV_RUNNING; 308 else 309 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 310#else 311 if (ifp->if_flags & IFF_UP) 312 ifp->if_flags |= IFF_RUNNING; 313 else 314 ifp->if_flags &= ~IFF_RUNNING; 315#endif 316 break; 317 default: 318 return (EINVAL); 319 } 320 321 return (0); 322} 323 324int 325pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, 326 u_int8_t reason, struct pf_rule *rm, struct pf_rule *am, 327 struct pf_ruleset *ruleset, struct pf_pdesc *pd) 328{ 329#if NBPFILTER > 0 330 struct ifnet *ifn; 331 struct pfloghdr hdr; 332 333 if (kif == NULL || m == NULL || rm == NULL || pd == NULL) 334 return (-1); 335 336 if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf) 337 return (0); 338 339 bzero(&hdr, sizeof(hdr)); 340 hdr.length = PFLOG_REAL_HDRLEN; 341 hdr.af = af; 342 hdr.action = rm->action; 343 hdr.reason = reason; 344 memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname)); 345 346 if (am == NULL) { 347 hdr.rulenr = htonl(rm->nr); 348 hdr.subrulenr = -1; 349 } else { 350 hdr.rulenr = htonl(am->nr); 351 hdr.subrulenr = htonl(rm->nr); 352 if (ruleset != NULL && ruleset->anchor != NULL) 353 strlcpy(hdr.ruleset, ruleset->anchor->name, 354 sizeof(hdr.ruleset)); 355 } 356 if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done) 357#ifdef __FreeBSD__ 358 /* 359 * XXX: This should not happen as we force an early lookup 360 * via debug.pfugidhack 361 */ 362 ; /* empty */ 363#else 364 pd->lookup.done = pf_socket_lookup(dir, pd); 365#endif 366 if (pd->lookup.done > 0) { 367 hdr.uid = pd->lookup.uid; 368 hdr.pid = pd->lookup.pid; 369 } else { 370 hdr.uid = UID_MAX; 371 hdr.pid = NO_PID; 372 } 373 hdr.rule_uid = rm->cuid; 374 hdr.rule_pid = rm->cpid; 375 hdr.dir = dir; 376 377#ifdef INET 378 if (af == AF_INET && dir == PF_OUT) { 379 struct ip *ip; 380 381 ip = mtod(m, struct ip *); 382 ip->ip_sum = 0; 383 ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 384 } 385#endif /* INET */ 386 387 ifn->if_opackets++; 388 ifn->if_obytes += m->m_pkthdr.len; 389#ifdef __FreeBSD__ 390 BPF_MTAP2(ifn, &hdr, PFLOG_HDRLEN, m); 391#else 392 bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m, 393 BPF_DIRECTION_OUT); 394#endif 395#endif 396 397 return (0); 398} 399 400#ifdef __FreeBSD__ 401static int 402pflog_modevent(module_t mod, int type, void *data) 403{ 404 int error = 0; 405 406 switch (type) { 407 case MOD_LOAD: 408 pflogattach(1); 409 PF_LOCK(); 410 pflog_packet_ptr = pflog_packet; 411 PF_UNLOCK(); 412 break; 413 case MOD_UNLOAD: 414 PF_LOCK(); 415 pflog_packet_ptr = NULL; 416 PF_UNLOCK(); 417 if_clone_detach(&pflog_cloner); 418 break; 419 default: 420 error = EINVAL; 421 break; 422 } 423 424 return error; 425} 426 427static moduledata_t pflog_mod = { "pflog", pflog_modevent, 0 }; 428 429#define PFLOG_MODVER 1 430 431DECLARE_MODULE(pflog, pflog_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 432MODULE_VERSION(pflog, PFLOG_MODVER); 433MODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER); 434#endif /* __FreeBSD__ */ 435