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