if_pflog.c revision 155337
1/* $FreeBSD: head/sys/contrib/pf/net/if_pflog.c 155337 2006-02-05 17:17:32Z mlaier $ */ 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 50#ifdef DEV_BPF 51#define NBPFILTER DEV_BPF 52#else 53#define NBPFILTER 0 54#endif 55 56#ifdef DEV_PFLOG 57#define NPFLOG DEV_PFLOG 58#else 59#define NPFLOG 0 60#endif 61 62#endif 63 64#include <sys/param.h> 65#include <sys/systm.h> 66#include <sys/mbuf.h> 67#include <sys/socket.h> 68#ifdef __FreeBSD__ 69#include <sys/kernel.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#if defined(__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 __FreeBSD__ 93#include <machine/in_cksum.h> 94#endif 95 96#ifdef INET6 97#ifndef INET 98#include <netinet/in.h> 99#endif 100#include <netinet6/nd6.h> 101#endif /* INET6 */ 102 103#include <net/pfvar.h> 104#include <net/if_pflog.h> 105 106#ifdef __FreeBSD__ 107#define PFLOGNAME "pflog" 108#endif 109 110#define PFLOGMTU (32768 + MHLEN + MLEN) 111 112#ifdef PFLOGDEBUG 113#define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0) 114#else 115#define DPRINTF(x) 116#endif 117 118#ifndef __FreeBSD__ 119struct pflog_softc pflogif[NPFLOG]; 120#endif 121 122#ifdef __FreeBSD__ 123static void pflog_clone_destroy(struct ifnet *); 124static int pflog_clone_create(struct if_clone *, int); 125#else 126void pflogattach(int); 127#endif 128int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 129 struct rtentry *); 130int pflogioctl(struct ifnet *, u_long, caddr_t); 131void pflogrtrequest(int, struct rtentry *, struct sockaddr *); 132void pflogstart(struct ifnet *); 133 134#ifndef __FreeBSD__ 135extern int ifqmaxlen; 136#endif 137 138#ifdef __FreeBSD__ 139static MALLOC_DEFINE(M_PFLOG, PFLOGNAME, "Packet Filter Logging Interface"); 140static LIST_HEAD(pflog_list, pflog_softc) pflog_list; 141#define SCP2IFP(sc) ((sc)->sc_ifp) 142IFC_SIMPLE_DECLARE(pflog, 1); 143 144static void 145pflog_clone_destroy(struct ifnet *ifp) 146{ 147 struct pflog_softc *sc; 148 149 sc = ifp->if_softc; 150 151 /* 152 * Does we really need this? 153 */ 154 IF_DRAIN(&ifp->if_snd); 155 156 bpfdetach(ifp); 157 if_detach(ifp); 158 if_free(ifp); 159 LIST_REMOVE(sc, sc_next); 160 free(sc, M_PFLOG); 161} 162 163static int 164pflog_clone_create(struct if_clone *ifc, int unit) 165{ 166 struct pflog_softc *sc; 167 struct ifnet *ifp; 168 169 MALLOC(sc, struct pflog_softc *, sizeof(*sc), M_PFLOG, M_WAITOK|M_ZERO); 170 ifp = sc->sc_ifp = if_alloc(IFT_PFLOG); 171 if (ifp == NULL) { 172 free(sc, M_PFLOG); 173 return (ENOSPC); 174 } 175 176 if_initname(ifp, ifc->ifc_name, unit); 177 ifp->if_mtu = PFLOGMTU; 178 ifp->if_ioctl = pflogioctl; 179 ifp->if_output = pflogoutput; 180 ifp->if_start = pflogstart; 181 ifp->if_snd.ifq_maxlen = ifqmaxlen; 182 ifp->if_hdrlen = PFLOG_HDRLEN; 183 ifp->if_softc = sc; 184 if_attach(ifp); 185 186 LIST_INSERT_HEAD(&pflog_list, sc, sc_next); 187#if NBPFILTER > 0 188 bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN); 189#endif 190 191 return (0); 192} 193#else /* !__FreeBSD__ */ 194void 195pflogattach(int npflog) 196{ 197 struct ifnet *ifp; 198 int i; 199 200 bzero(pflogif, sizeof(pflogif)); 201 202 for (i = 0; i < NPFLOG; i++) { 203 ifp = &pflogif[i].sc_if; 204 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", i); 205 ifp->if_softc = &pflogif[i]; 206 ifp->if_mtu = PFLOGMTU; 207 ifp->if_ioctl = pflogioctl; 208 ifp->if_output = pflogoutput; 209 ifp->if_start = pflogstart; 210 ifp->if_type = IFT_PFLOG; 211 ifp->if_snd.ifq_maxlen = ifqmaxlen; 212 ifp->if_hdrlen = PFLOG_HDRLEN; 213 if_attach(ifp); 214 if_alloc_sadl(ifp); 215 216#if NBPFILTER > 0 217 bpfattach(&pflogif[i].sc_if.if_bpf, ifp, DLT_PFLOG, 218 PFLOG_HDRLEN); 219#endif 220 } 221} 222#endif /* __FreeBSD__ */ 223 224/* 225 * Start output on the pflog interface. 226 */ 227void 228pflogstart(struct ifnet *ifp) 229{ 230 struct mbuf *m; 231#ifndef __FreeBSD__ 232 int s; 233#endif 234 235 for (;;) { 236#ifdef __FreeBSD__ 237 IF_LOCK(&ifp->if_snd); 238 _IF_DROP(&ifp->if_snd); 239 _IF_DEQUEUE(&ifp->if_snd, m); 240 if (m == NULL) { 241 IF_UNLOCK(&ifp->if_snd); 242 return; 243 } 244 else 245 m_freem(m); 246 IF_UNLOCK(&ifp->if_snd); 247#else 248 s = splimp(); 249 IF_DROP(&ifp->if_snd); 250 IF_DEQUEUE(&ifp->if_snd, m); 251 splx(s); 252 if (m == NULL) 253 return; 254 else 255 m_freem(m); 256#endif 257 } 258} 259 260int 261pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 262 struct rtentry *rt) 263{ 264 m_freem(m); 265 return (0); 266} 267 268/* ARGSUSED */ 269void 270pflogrtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa) 271{ 272 if (rt) 273 rt->rt_rmx.rmx_mtu = PFLOGMTU; 274} 275 276/* ARGSUSED */ 277int 278pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 279{ 280 switch (cmd) { 281 case SIOCSIFADDR: 282 case SIOCAIFADDR: 283 case SIOCSIFDSTADDR: 284 case SIOCSIFFLAGS: 285#ifdef __FreeBSD__ 286 if (ifp->if_flags & IFF_UP) 287 ifp->if_drv_flags |= IFF_DRV_RUNNING; 288 else 289 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 290#else 291 if (ifp->if_flags & IFF_UP) 292 ifp->if_flags |= IFF_RUNNING; 293 else 294 ifp->if_flags &= ~IFF_RUNNING; 295#endif 296 break; 297 default: 298 return (EINVAL); 299 } 300 301 return (0); 302} 303 304int 305pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, 306 u_int8_t reason, struct pf_rule *rm, struct pf_rule *am, 307 struct pf_ruleset *ruleset) 308{ 309#if NBPFILTER > 0 310 struct ifnet *ifn; 311 struct pfloghdr hdr; 312#ifndef __FreeBSD__ 313 struct mbuf m1; 314#endif 315 316 if (kif == NULL || m == NULL || rm == NULL) 317 return (-1); 318 319 bzero(&hdr, sizeof(hdr)); 320 hdr.length = PFLOG_REAL_HDRLEN; 321 hdr.af = af; 322 hdr.action = rm->action; 323 hdr.reason = reason; 324 memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname)); 325 326 if (am == NULL) { 327 hdr.rulenr = htonl(rm->nr); 328 hdr.subrulenr = -1; 329 } else { 330 hdr.rulenr = htonl(am->nr); 331 hdr.subrulenr = htonl(rm->nr); 332 if (ruleset != NULL && ruleset->anchor != NULL) 333 strlcpy(hdr.ruleset, ruleset->anchor->name, 334 sizeof(hdr.ruleset)); 335 } 336 hdr.dir = dir; 337 338#ifdef INET 339 if (af == AF_INET && dir == PF_OUT) { 340 struct ip *ip; 341 342 ip = mtod(m, struct ip *); 343 ip->ip_sum = 0; 344 ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 345 } 346#endif /* INET */ 347 348#ifndef __FreeBSD__ 349 m1.m_next = m; 350 m1.m_len = PFLOG_HDRLEN; 351 m1.m_data = (char *) &hdr; 352#endif 353 354#ifdef __FreeBSD__ 355 KASSERT((!LIST_EMPTY(&pflog_list)), ("pflog: no interface")); 356 ifn = SCP2IFP(LIST_FIRST(&pflog_list)); 357 BPF_MTAP2(ifn, &hdr, sizeof(hdr), m); 358#else 359 ifn = &(pflogif[0].sc_if); 360 361 if (ifn->if_bpf) 362 bpf_mtap(ifn->if_bpf, &m1); 363#endif 364#endif 365 366 return (0); 367} 368 369#ifdef __FreeBSD__ 370static int 371pflog_modevent(module_t mod, int type, void *data) 372{ 373 int error = 0; 374 375 switch (type) { 376 case MOD_LOAD: 377 LIST_INIT(&pflog_list); 378 if_clone_attach(&pflog_cloner); 379 PF_LOCK(); 380 pflog_packet_ptr = pflog_packet; 381 PF_UNLOCK(); 382 break; 383 384 case MOD_UNLOAD: 385 PF_LOCK(); 386 pflog_packet_ptr = NULL; 387 PF_UNLOCK(); 388 if_clone_detach(&pflog_cloner); 389 break; 390 391 default: 392 error = EINVAL; 393 break; 394 } 395 396 return error; 397} 398 399static moduledata_t pflog_mod = { 400 "pflog", 401 pflog_modevent, 402 0 403}; 404 405#define PFLOG_MODVER 1 406 407DECLARE_MODULE(pflog, pflog_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 408MODULE_VERSION(pflog, PFLOG_MODVER); 409MODULE_DEPEND(pflog, pf, PF_MODVER, PF_MODVER, PF_MODVER); 410#endif /* __FreeBSD__ */ 411