1 /* $FreeBSD: src/sys/contrib/pf/net/if_pflog.c,v 1.9 2004/06/22 20:13:24 brooks Exp $ */ 2 /* $OpenBSD: if_pflog.c,v 1.11 2003/12/31 11:18:25 cedric Exp $ */ 3 /* $DragonFly: src/sys/net/pf/if_pflog.c,v 1.6 2006/12/22 23:44:57 swildner Exp $ */ 4 /* $OpenBSD: if_pflog.c,v 1.22 2006/12/15 09:31:20 otto Exp $ */ 5 /* 6 * The authors of this code are John Ioannidis (ji@tla.org), 7 * Angelos D. Keromytis (kermit@csd.uch.gr) and 8 * Niels Provos (provos@physnet.uni-hamburg.de). 9 * 10 * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 11 * in November 1995. 12 * 13 * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 14 * by Angelos D. Keromytis. 15 * 16 * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 17 * and Niels Provos. 18 * 19 * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis 20 * and Niels Provos. 21 * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos. 22 * 23 * Copyright (c) 2004 The DragonFly Project. All rights reserved. 24 * 25 * Permission to use, copy, and modify this software with or without fee 26 * is hereby granted, provided that this entire notice is included in 27 * all copies of any software which is or includes a copy or 28 * modification of this software. 29 * You may use this code under the GNU public license if you so wish. Please 30 * contribute changes back to the authors under this freer than GPL license 31 * so that we may further the use of strong encryption without limitations to 32 * all. 33 * 34 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 35 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 36 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 37 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 38 * PURPOSE. 39 */ 40 41 #include "opt_inet.h" 42 #include "opt_inet6.h" 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/in_cksum.h> 47 #include <sys/mbuf.h> 48 #include <sys/proc.h> 49 #include <sys/socket.h> 50 #include <sys/kernel.h> 51 #include <sys/malloc.h> 52 #include <sys/module.h> 53 #include <sys/sockio.h> 54 #include <sys/thread2.h> 55 #include <vm/vm_zone.h> 56 57 #include <net/if.h> 58 #include <net/if_types.h> 59 #include <net/route.h> 60 #include <net/bpf.h> 61 62 #ifdef INET 63 #include <netinet/in.h> 64 #include <netinet/in_var.h> 65 #include <netinet/in_systm.h> 66 #include <netinet/ip.h> 67 #endif 68 69 #ifdef INET6 70 #ifndef INET 71 #include <netinet/in.h> 72 #endif 73 #include <netinet6/nd6.h> 74 #endif /* INET6 */ 75 76 #include <net/pf/pfvar.h> 77 #include <net/pf/if_pflog.h> 78 79 #define PFLOGNAME "pflog" 80 81 #define PFLOGMTU (32768 + MHLEN + MLEN) 82 83 #ifdef PFLOGDEBUG 84 #define DPRINTF(x) do { if (pflogdebug) kprintf x ; } while (0) 85 #else 86 #define DPRINTF(x) 87 #endif 88 89 void pflogattach(int); 90 int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 91 struct rtentry *); 92 int pflogioctl(struct ifnet *, u_long, caddr_t, struct ucred *); 93 void pflogrtrequest(int, struct rtentry *, struct sockaddr *); 94 void pflogstart(struct ifnet *); 95 96 int pflog_clone_create(struct if_clone *, int, caddr_t); 97 void pflog_clone_destroy(struct ifnet *); 98 99 LIST_HEAD(, pflog_softc) pflogif_list; 100 struct if_clone pflog_cloner = 101 IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy, 1, 1); 102 103 struct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */ 104 105 void 106 pflogattach(int npflog) 107 { 108 int i; 109 LIST_INIT(&pflogif_list); 110 for (i = 0; i < PFLOGIFS_MAX; i++) 111 pflogifs[i] = NULL; 112 (void) pflog_clone_create(&pflog_cloner, 0, NULL); 113 if_clone_attach(&pflog_cloner); 114 } 115 116 int 117 pflog_clone_create(struct if_clone *ifc, int unit, caddr_t param __unused) 118 { 119 struct ifnet *ifp; 120 struct pflog_softc *pflogif; 121 122 if (unit >= PFLOGIFS_MAX) 123 return (EINVAL); 124 125 if ((pflogif = kmalloc(sizeof(*pflogif), M_DEVBUF, M_WAITOK)) == NULL) 126 return (ENOMEM); 127 bzero(pflogif, sizeof(*pflogif)); 128 129 pflogif->sc_unit = unit; 130 ifp = &pflogif->sc_if; 131 ksnprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit); 132 ifp->if_softc = pflogif; 133 ifp->if_mtu = PFLOGMTU; 134 ifp->if_ioctl = pflogioctl; 135 ifp->if_output = pflogoutput; 136 ifp->if_start = pflogstart; 137 ifp->if_type = IFT_PFLOG; 138 ifp->if_snd.ifq_maxlen = ifqmaxlen; 139 ifp->if_hdrlen = PFLOG_HDRLEN; 140 if_attach(ifp, NULL); 141 142 bpfattach(&pflogif->sc_if, DLT_PFLOG, PFLOG_HDRLEN); 143 144 crit_enter(); 145 LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list); 146 pflogifs[unit] = ifp; 147 crit_exit(); 148 149 return (0); 150 } 151 152 void 153 pflog_clone_destroy(struct ifnet *ifp) 154 { 155 struct pflog_softc *pflogif = ifp->if_softc; 156 157 crit_enter(); 158 pflogifs[pflogif->sc_unit] = NULL; 159 LIST_REMOVE(pflogif, sc_list); 160 crit_exit(); 161 162 #if NBPFILTER > 0 163 bpfdetach(ifp); 164 #endif 165 if_detach(ifp); 166 kfree(pflogif, M_DEVBUF); 167 } 168 169 /* 170 * Start output on the pflog interface. 171 */ 172 void 173 pflogstart(struct ifnet *ifp) 174 { 175 struct mbuf *m; 176 177 for (;;) { 178 crit_enter(); 179 IF_DROP(&ifp->if_snd); 180 IF_DEQUEUE(&ifp->if_snd, m); 181 crit_exit(); 182 183 if (m == NULL) 184 return; 185 else 186 m_freem(m); 187 } 188 } 189 190 int 191 pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 192 struct rtentry *rt) 193 { 194 m_freem(m); 195 return (0); 196 } 197 198 /* ARGSUSED */ 199 void 200 pflogrtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa) 201 { 202 if (rt) 203 rt->rt_rmx.rmx_mtu = PFLOGMTU; 204 } 205 206 /* ARGSUSED */ 207 int 208 pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 209 { 210 switch (cmd) { 211 case SIOCSIFADDR: 212 case SIOCAIFADDR: 213 case SIOCSIFDSTADDR: 214 case SIOCSIFFLAGS: 215 if (ifp->if_flags & IFF_UP) 216 ifp->if_flags |= IFF_RUNNING; 217 else 218 ifp->if_flags &= ~IFF_RUNNING; 219 break; 220 default: 221 return (EINVAL); 222 } 223 224 return (0); 225 } 226 227 int 228 pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, 229 u_int8_t reason, struct pf_rule *rm, struct pf_rule *am, 230 struct pf_ruleset *ruleset, struct pf_pdesc *pd) 231 { 232 struct ifnet *ifn = NULL; 233 struct pfloghdr hdr; 234 235 if (kif == NULL || m == NULL || rm == NULL) 236 return (-1); 237 238 if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf) 239 return (0); 240 241 bzero(&hdr, sizeof(hdr)); 242 hdr.length = PFLOG_REAL_HDRLEN; 243 hdr.af = af; 244 hdr.action = rm->action; 245 hdr.reason = reason; 246 memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname)); 247 248 if (am == NULL) { 249 hdr.rulenr = htonl(rm->nr); 250 hdr.subrulenr = -1; 251 } else { 252 hdr.rulenr = htonl(am->nr); 253 hdr.subrulenr = htonl(rm->nr); 254 if (ruleset != NULL && ruleset->anchor != NULL) { 255 strlcpy(hdr.ruleset, ruleset->anchor->name, 256 sizeof(hdr.ruleset)); 257 } 258 } 259 if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done) 260 pd->lookup.done = pf_socket_lookup(dir, pd, NULL); 261 if (pd->lookup.done > 0) { 262 hdr.uid = pd->lookup.uid; 263 hdr.pid = pd->lookup.pid; 264 } else { 265 hdr.uid = UID_MAX; 266 hdr.pid = NO_PID; 267 } 268 hdr.rule_uid = rm->cuid; 269 hdr.rule_pid = rm->cpid; 270 hdr.dir = dir; 271 272 #ifdef INET 273 if (af == AF_INET) { 274 struct ip *ip; 275 ip = mtod(m, struct ip *); 276 ip->ip_len = htons(ip->ip_len); 277 ip->ip_off = htons(ip->ip_off); 278 279 if (dir == PF_OUT) { 280 ip->ip_sum = 0; 281 ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 282 } 283 } 284 #endif /* INET */ 285 286 ifn->if_opackets++; 287 ifn->if_obytes += m->m_pkthdr.len; 288 bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m, 289 BPF_DIRECTION_OUT); 290 291 #ifdef INET 292 if (af == AF_INET) { 293 struct ip *ip = mtod(m, struct ip *); 294 295 ip->ip_len = ntohs(ip->ip_len); 296 ip->ip_off = ntohs(ip->ip_off); 297 } 298 #endif /* INET */ 299 300 return (0); 301 } 302 303 static int 304 pflog_modevent(module_t mod, int type, void *data) 305 { 306 int error = 0; 307 308 switch (type) { 309 case MOD_LOAD: 310 LIST_INIT(&pflogif_list); 311 if_clone_attach(&pflog_cloner); 312 break; 313 314 case MOD_UNLOAD: 315 if_clone_detach(&pflog_cloner); 316 while (!LIST_EMPTY(&pflogif_list)) { 317 pflog_clone_destroy( 318 &LIST_FIRST(&pflogif_list)->sc_if); 319 } 320 break; 321 322 default: 323 error = EINVAL; 324 break; 325 } 326 327 return error; 328 } 329 330 static moduledata_t pflog_mod = { 331 "pflog", 332 pflog_modevent, 333 0 334 }; 335 336 #define PFLOG_MODVER 1 337 338 DECLARE_MODULE(pflog, pflog_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 339 MODULE_VERSION(pflog, PFLOG_MODVER); 340