1 /* $NetBSD: if_pflog.c,v 1.16 2010/01/19 22:08:00 pooka Exp $ */ 2 /* $OpenBSD: if_pflog.c,v 1.24 2007/05/26 17:13:30 jason 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 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: if_pflog.c,v 1.16 2010/01/19 22:08:00 pooka Exp $"); 40 41 #ifdef _KERNEL_OPT 42 #include "opt_inet.h" 43 #endif 44 45 #include "pflog.h" 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/mbuf.h> 50 #include <sys/proc.h> 51 #include <sys/socket.h> 52 #include <sys/ioctl.h> 53 54 #include <net/if.h> 55 #include <net/if_types.h> 56 #include <net/route.h> 57 #include <net/bpf.h> 58 59 #ifdef INET 60 #include <netinet/in.h> 61 #include <netinet/in_var.h> 62 #include <netinet/in_systm.h> 63 #include <netinet/ip.h> 64 #endif 65 66 #ifdef INET6 67 #ifndef INET 68 #include <netinet/in.h> 69 #endif 70 #include <netinet6/nd6.h> 71 #endif /* INET6 */ 72 73 #include <net/pfvar.h> 74 #include <net/if_pflog.h> 75 76 #define PFLOGMTU (32768 + MHLEN + MLEN) 77 78 #ifdef PFLOGDEBUG 79 #define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0) 80 #else 81 #define DPRINTF(x) 82 #endif 83 84 void pflogattach(int); 85 int pflogoutput(struct ifnet *, struct mbuf *, const struct sockaddr *, 86 struct rtentry *); 87 int pflogioctl(struct ifnet *, u_long, void *); 88 void pflogstart(struct ifnet *); 89 int pflog_clone_create(struct if_clone *, int); 90 int pflog_clone_destroy(struct ifnet *); 91 92 LIST_HEAD(, pflog_softc) pflogif_list; 93 struct if_clone pflog_cloner = 94 IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy); 95 96 struct ifnet *pflogifs[PFLOGIFS_MAX]; /* for fast access */ 97 98 void 99 pflogattach(int npflog) 100 { 101 int i; 102 103 LIST_INIT(&pflogif_list); 104 for (i = 0; i < PFLOGIFS_MAX; i++) 105 pflogifs[i] = NULL; 106 if_clone_attach(&pflog_cloner); 107 } 108 109 int 110 pflog_clone_create(struct if_clone *ifc, int unit) 111 { 112 struct ifnet *ifp; 113 struct pflog_softc *pflogif; 114 int s; 115 116 if (unit >= PFLOGIFS_MAX) 117 return (EINVAL); 118 119 if ((pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 120 return (ENOMEM); 121 122 pflogif->sc_unit = unit; 123 ifp = &pflogif->sc_if; 124 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit); 125 ifp->if_softc = pflogif; 126 ifp->if_mtu = PFLOGMTU; 127 ifp->if_ioctl = pflogioctl; 128 ifp->if_output = pflogoutput; 129 ifp->if_start = pflogstart; 130 ifp->if_type = IFT_PFLOG; 131 #ifndef __NetBSD__ 132 ifp->if_snd.ifq_maxlen = ifqmaxlen; 133 #endif /* !__NetBSD__ */ 134 ifp->if_hdrlen = PFLOG_HDRLEN; 135 if_attach(ifp); 136 if_alloc_sadl(ifp); 137 138 #ifdef __NetBSD__ 139 bpf_ops->bpf_attach(ifp, DLT_PFLOG, PFLOG_HDRLEN, &ifp->if_bpf); 140 #else 141 bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN); 142 #endif /* !__NetBSD__ */ 143 144 s = splnet(); 145 LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list); 146 pflogifs[unit] = ifp; 147 splx(s); 148 149 return (0); 150 } 151 152 int 153 pflog_clone_destroy(struct ifnet *ifp) 154 { 155 struct pflog_softc *pflogif = ifp->if_softc; 156 int s; 157 158 s = splnet(); 159 pflogifs[pflogif->sc_unit] = NULL; 160 LIST_REMOVE(pflogif, sc_list); 161 splx(s); 162 163 bpf_ops->bpf_detach(ifp); 164 if_detach(ifp); 165 free(pflogif, M_DEVBUF); 166 return (0); 167 } 168 169 /* 170 * Start output on the pflog interface. 171 */ 172 void 173 pflogstart(struct ifnet *ifp) 174 { 175 struct mbuf *m; 176 int s; 177 178 for (;;) { 179 s = splnet(); 180 IF_DROP(&ifp->if_snd); 181 IF_DEQUEUE(&ifp->if_snd, m); 182 splx(s); 183 184 if (m == NULL) 185 return; 186 else 187 m_freem(m); 188 } 189 } 190 191 int 192 pflogoutput(struct ifnet *ifp, struct mbuf *m, 193 const struct sockaddr *dst, struct rtentry *rt) 194 { 195 m_freem(m); 196 return (0); 197 } 198 199 /* ARGSUSED */ 200 int 201 pflogioctl(struct ifnet *ifp, u_long cmd, void *data) 202 { 203 int error = 0; 204 205 switch (cmd) { 206 case SIOCSIFFLAGS: 207 if ((error = ifioctl_common(ifp, cmd, data)) != 0) 208 break; 209 /*FALLTHROUGH*/ 210 case SIOCINITIFADDR: 211 case SIOCAIFADDR: 212 case SIOCSIFDSTADDR: 213 if (ifp->if_flags & IFF_UP) 214 ifp->if_flags |= IFF_RUNNING; 215 else 216 ifp->if_flags &= ~IFF_RUNNING; 217 break; 218 default: 219 error = ifioctl_common(ifp, cmd, data); 220 } 221 222 return error; 223 } 224 225 int 226 pflog_packet(struct pfi_kif *kif, struct mbuf *m, sa_family_t af, u_int8_t dir, 227 u_int8_t reason, struct pf_rule *rm, struct pf_rule *am, 228 struct pf_ruleset *ruleset, struct pf_pdesc *pd) 229 { 230 struct ifnet *ifn; 231 struct pfloghdr hdr; 232 233 if (kif == NULL || m == NULL || rm == NULL || pd == NULL) 234 return (-1); 235 236 if ((ifn = pflogifs[rm->logif]) == NULL || !ifn->if_bpf) 237 return (0); 238 239 bzero(&hdr, sizeof(hdr)); 240 hdr.length = PFLOG_REAL_HDRLEN; 241 hdr.af = af; 242 hdr.action = rm->action; 243 hdr.reason = reason; 244 memcpy(hdr.ifname, kif->pfik_name, sizeof(hdr.ifname)); 245 246 if (am == NULL) { 247 hdr.rulenr = htonl(rm->nr); 248 hdr.subrulenr = -1; 249 } else { 250 hdr.rulenr = htonl(am->nr); 251 hdr.subrulenr = htonl(rm->nr); 252 if (ruleset != NULL && ruleset->anchor != NULL) 253 strlcpy(hdr.ruleset, ruleset->anchor->name, 254 sizeof(hdr.ruleset)); 255 } 256 if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done) 257 pd->lookup.done = pf_socket_lookup(dir, pd); 258 if (pd->lookup.done > 0) { 259 hdr.uid = pd->lookup.uid; 260 hdr.pid = pd->lookup.pid; 261 } else { 262 hdr.uid = UID_MAX; 263 hdr.pid = NO_PID; 264 } 265 hdr.rule_uid = rm->cuid; 266 hdr.rule_pid = rm->cpid; 267 hdr.dir = dir; 268 269 #ifdef INET 270 if (af == AF_INET && dir == PF_OUT) { 271 struct ip *ip; 272 273 ip = mtod(m, struct ip *); 274 ip->ip_sum = 0; 275 ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 276 } 277 #endif /* INET */ 278 279 ifn->if_opackets++; 280 ifn->if_obytes += m->m_pkthdr.len; 281 282 #ifdef __NetBSD__ 283 bpf_ops->bpf_mtap2(ifn->if_bpf, &hdr, PFLOG_HDRLEN, m); 284 #else 285 bpf_mtap_hdr(ifn->if_bpf, (char *)&hdr, PFLOG_HDRLEN, m, 286 BPF_DIRECTION_OUT); 287 #endif /* !__NetBSD__ */ 288 289 290 return (0); 291 } 292