1/* 2 * Copyright (c) 2007-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29/* $apfw: if_pflog.c,v 1.4 2008/08/27 00:01:32 jhw Exp $ */ 30/* $OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto Exp $ */ 31/* 32 * The authors of this code are John Ioannidis (ji@tla.org), 33 * Angelos D. Keromytis (kermit@csd.uch.gr) and 34 * Niels Provos (provos@physnet.uni-hamburg.de). 35 * 36 * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 37 * in November 1995. 38 * 39 * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 40 * by Angelos D. Keromytis. 41 * 42 * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 43 * and Niels Provos. 44 * 45 * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis 46 * and Niels Provos. 47 * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos. 48 * 49 * Permission to use, copy, and modify this software with or without fee 50 * is hereby granted, provided that this entire notice is included in 51 * all copies of any software which is or includes a copy or 52 * modification of this software. 53 * You may use this code under the GNU public license if you so wish. Please 54 * contribute changes back to the authors under this freer than GPL license 55 * so that we may further the use of strong encryption without limitations to 56 * all. 57 * 58 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 59 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 60 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 61 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 62 * PURPOSE. 63 */ 64 65#include <sys/param.h> 66#include <sys/systm.h> 67#include <sys/mbuf.h> 68#include <sys/proc_internal.h> 69#include <sys/socket.h> 70#include <sys/ioctl.h> 71#include <sys/mcache.h> 72 73#include <net/if.h> 74#include <net/if_var.h> 75#include <net/if_types.h> 76#include <net/route.h> 77#include <net/bpf.h> 78 79#if INET 80#include <netinet/in.h> 81#include <netinet/in_var.h> 82#include <netinet/in_systm.h> 83#include <netinet/ip.h> 84#endif 85 86#if INET6 87#if !INET 88#include <netinet/in.h> 89#endif 90#include <netinet6/nd6.h> 91#endif /* INET6 */ 92 93#include <net/pfvar.h> 94#include <net/if_pflog.h> 95 96#define PFLOGNAME "pflog" 97#define PFLOGMTU (32768 + MHLEN + MLEN) 98 99#ifdef PFLOGDEBUG 100#define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0) 101#else 102#define DPRINTF(x) 103#endif 104 105static int pflog_clone_create(struct if_clone *, u_int32_t, void *); 106static int pflog_clone_destroy(struct ifnet *); 107static errno_t pflogoutput(struct ifnet *, struct mbuf *); 108static errno_t pflogioctl(struct ifnet *, unsigned long, void *); 109static errno_t pflogdemux(struct ifnet *, struct mbuf *, char *, 110 protocol_family_t *); 111static errno_t pflogaddproto(struct ifnet *, protocol_family_t, 112 const struct ifnet_demux_desc *, u_int32_t); 113static errno_t pflogdelproto(struct ifnet *, protocol_family_t); 114static void pflogfree(struct ifnet *); 115 116static LIST_HEAD(, pflog_softc) pflogif_list; 117static struct if_clone pflog_cloner = 118 IF_CLONE_INITIALIZER(PFLOGNAME, pflog_clone_create, pflog_clone_destroy, 119 0, (PFLOGIFS_MAX - 1)); 120 121struct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */ 122 123void 124pfloginit(void) 125{ 126 int i; 127 128 LIST_INIT(&pflogif_list); 129 for (i = 0; i < PFLOGIFS_MAX; i++) 130 pflogifs[i] = NULL; 131 132 (void) if_clone_attach(&pflog_cloner); 133} 134 135static int 136pflog_clone_create(struct if_clone *ifc, u_int32_t unit, __unused void *params) 137{ 138 struct pflog_softc *pflogif; 139 struct ifnet_init_params pf_init; 140 int error = 0; 141 142 if (unit >= PFLOGIFS_MAX) { 143 /* Either the interface cloner or our initializer is broken */ 144 panic("%s: unit (%d) exceeds max (%d)", __func__, unit, 145 PFLOGIFS_MAX); 146 /* NOTREACHED */ 147 } 148 149 if ((pflogif = _MALLOC(sizeof (*pflogif), 150 M_DEVBUF, M_WAITOK|M_ZERO)) == NULL) { 151 error = ENOMEM; 152 goto done; 153 } 154 155 bzero(&pf_init, sizeof (pf_init)); 156 pf_init.name = ifc->ifc_name; 157 pf_init.unit = unit; 158 pf_init.type = IFT_PFLOG; 159 pf_init.family = IFNET_FAMILY_LOOPBACK; 160 pf_init.output = pflogoutput; 161 pf_init.demux = pflogdemux; 162 pf_init.add_proto = pflogaddproto; 163 pf_init.del_proto = pflogdelproto; 164 pf_init.softc = pflogif; 165 pf_init.ioctl = pflogioctl; 166 pf_init.detach = pflogfree; 167 168 bzero(pflogif, sizeof (*pflogif)); 169 pflogif->sc_unit = unit; 170 171 error = ifnet_allocate(&pf_init, &pflogif->sc_if); 172 if (error != 0) { 173 printf("%s: ifnet_allocate failed - %d\n", __func__, error); 174 _FREE(pflogif, M_DEVBUF); 175 goto done; 176 } 177 178 ifnet_set_mtu(pflogif->sc_if, PFLOGMTU); 179 ifnet_set_flags(pflogif->sc_if, IFF_UP, IFF_UP); 180 181 error = ifnet_attach(pflogif->sc_if, NULL); 182 if (error != 0) { 183 printf("%s: ifnet_attach failed - %d\n", __func__, error); 184 ifnet_release(pflogif->sc_if); 185 _FREE(pflogif, M_DEVBUF); 186 goto done; 187 } 188 189#if NBPFILTER > 0 190 bpfattach(pflogif->sc_if, DLT_PFLOG, PFLOG_HDRLEN); 191#endif 192 193 lck_rw_lock_shared(pf_perim_lock); 194 lck_mtx_lock(pf_lock); 195 LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list); 196 pflogifs[unit] = pflogif->sc_if; 197 lck_mtx_unlock(pf_lock); 198 lck_rw_done(pf_perim_lock); 199 200done: 201 return (error); 202} 203 204static int 205pflog_clone_destroy(struct ifnet *ifp) 206{ 207 struct pflog_softc *pflogif = ifp->if_softc; 208 209 lck_rw_lock_shared(pf_perim_lock); 210 lck_mtx_lock(pf_lock); 211 pflogifs[pflogif->sc_unit] = NULL; 212 LIST_REMOVE(pflogif, sc_list); 213 lck_mtx_unlock(pf_lock); 214 lck_rw_done(pf_perim_lock); 215 216 /* bpfdetach() is taken care of as part of interface detach */ 217 (void) ifnet_detach(ifp); 218 219 return 0; 220} 221 222static errno_t 223pflogoutput(struct ifnet *ifp, struct mbuf *m) 224{ 225 printf("%s: freeing data for %s\n", __func__, if_name(ifp)); 226 m_freem(m); 227 return (ENOTSUP); 228} 229 230static errno_t 231pflogioctl(struct ifnet *ifp, unsigned long cmd, void *data) 232{ 233#pragma unused(data) 234 switch (cmd) { 235 case SIOCSIFADDR: 236 case SIOCAIFADDR: 237 case SIOCSIFDSTADDR: 238 case SIOCSIFFLAGS: 239 if (ifnet_flags(ifp) & IFF_UP) 240 ifnet_set_flags(ifp, IFF_RUNNING, IFF_RUNNING); 241 else 242 ifnet_set_flags(ifp, 0, IFF_RUNNING); 243 break; 244 default: 245 return (ENOTTY); 246 } 247 248 return (0); 249} 250 251static errno_t 252pflogdemux(struct ifnet *ifp, struct mbuf *m, char *h, protocol_family_t *ppf) 253{ 254#pragma unused(h, ppf) 255 printf("%s: freeing data for %s\n", __func__, if_name(ifp)); 256 m_freem(m); 257 return (EJUSTRETURN); 258} 259 260static errno_t 261pflogaddproto(struct ifnet *ifp, protocol_family_t pf, 262 const struct ifnet_demux_desc *d, u_int32_t cnt) 263{ 264#pragma unused(ifp, pf, d, cnt) 265 return (0); 266} 267 268static errno_t 269pflogdelproto(struct ifnet *ifp, protocol_family_t pf) 270{ 271#pragma unused(ifp, pf) 272 return (0); 273} 274 275static void 276pflogfree(struct ifnet *ifp) 277{ 278 _FREE(ifp->if_softc, M_DEVBUF); 279 ifp->if_softc = NULL; 280 (void) ifnet_release(ifp); 281} 282 283int 284pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, 285 u_int8_t reason, struct pf_rule *rm, struct pf_rule *am, 286 struct pf_ruleset *ruleset, struct pf_pdesc *pd) 287{ 288#if NBPFILTER > 0 289 struct ifnet *ifn; 290 struct pfloghdr hdr; 291 292 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 293 294 if (kif == NULL || m == NULL || rm == NULL || pd == NULL) 295 return (-1); 296 297 if (rm->logif >= PFLOGIFS_MAX || 298 (ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf) { 299 return (0); 300 } 301 302 bzero(&hdr, sizeof (hdr)); 303 hdr.length = PFLOG_REAL_HDRLEN; 304 hdr.af = af; 305 hdr.action = rm->action; 306 hdr.reason = reason; 307 memcpy(hdr.ifname, kif->pfik_name, sizeof (hdr.ifname)); 308 309 if (am == NULL) { 310 hdr.rulenr = htonl(rm->nr); 311 hdr.subrulenr = -1; 312 } else { 313 hdr.rulenr = htonl(am->nr); 314 hdr.subrulenr = htonl(rm->nr); 315 if (ruleset != NULL && ruleset->anchor != NULL) 316 strlcpy(hdr.ruleset, ruleset->anchor->name, 317 sizeof (hdr.ruleset)); 318 } 319 if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done) 320 pd->lookup.done = pf_socket_lookup(dir, pd); 321 if (pd->lookup.done > 0) { 322 hdr.uid = pd->lookup.uid; 323 hdr.pid = pd->lookup.pid; 324 } else { 325 hdr.uid = UID_MAX; 326 hdr.pid = NO_PID; 327 } 328 hdr.rule_uid = rm->cuid; 329 hdr.rule_pid = rm->cpid; 330 hdr.dir = dir; 331 332#if INET 333 if (af == AF_INET && dir == PF_OUT) { 334 struct ip *ip; 335 336 ip = mtod(m, struct ip *); 337 ip->ip_sum = 0; 338 ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 339 } 340#endif /* INET */ 341 342 atomic_add_64(&ifn->if_opackets, 1); 343 atomic_add_64(&ifn->if_obytes, m->m_pkthdr.len); 344 345 switch (dir) { 346 case PF_IN: 347 bpf_tap_in(ifn, DLT_PFLOG, m, &hdr, PFLOG_HDRLEN); 348 break; 349 350 case PF_OUT: 351 bpf_tap_out(ifn, DLT_PFLOG, m, &hdr, PFLOG_HDRLEN); 352 break; 353 354 default: 355 break; 356 } 357#endif /* NBPFILTER > 0 */ 358 return (0); 359} 360