1 /* $OpenBSD: if_pflog.c,v 1.61 2014/07/12 18:44:22 tedu Exp $ */ 2 /* 3 * The authors of this code are John Ioannidis (ji@tla.org), 4 * Angelos D. Keromytis (kermit@csd.uch.gr) and 5 * Niels Provos (provos@physnet.uni-hamburg.de). 6 * 7 * This code was written by John Ioannidis for BSD/OS in Athens, Greece, 8 * in November 1995. 9 * 10 * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996, 11 * by Angelos D. Keromytis. 12 * 13 * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis 14 * and Niels Provos. 15 * 16 * Copyright (C) 1995, 1996, 1997, 1998 by John Ioannidis, Angelos D. Keromytis 17 * and Niels Provos. 18 * Copyright (c) 2001, Angelos D. Keromytis, Niels Provos. 19 * Copyright (c) 2002 - 2010 Henning Brauer 20 * 21 * Permission to use, copy, and modify this software with or without fee 22 * is hereby granted, provided that this entire notice is included in 23 * all copies of any software which is or includes a copy or 24 * modification of this software. 25 * You may use this code under the GNU public license if you so wish. Please 26 * contribute changes back to the authors under this freer than GPL license 27 * so that we may further the use of strong encryption without limitations to 28 * all. 29 * 30 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR 31 * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY 32 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE 33 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR 34 * PURPOSE. 35 */ 36 37 #include "bpfilter.h" 38 #include "pflog.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/mbuf.h> 43 #include <sys/proc.h> 44 #include <sys/socket.h> 45 #include <sys/ioctl.h> 46 47 #include <net/if.h> 48 #include <net/if_types.h> 49 #include <net/route.h> 50 #include <net/bpf.h> 51 52 #ifdef INET 53 #include <netinet/in.h> 54 #include <netinet/in_systm.h> 55 #include <netinet/ip.h> 56 #include <netinet/tcp.h> 57 #include <netinet/udp.h> 58 #include <netinet/ip_icmp.h> 59 #endif 60 61 #ifdef INET6 62 #ifndef INET 63 #include <netinet/in.h> 64 #endif 65 #include <netinet/ip6.h> 66 #include <netinet/icmp6.h> 67 #endif /* INET6 */ 68 69 #include <net/pfvar.h> 70 #include <net/if_pflog.h> 71 72 #define PFLOGMTU (32768 + MHLEN + MLEN) 73 74 #ifdef PFLOGDEBUG 75 #define DPRINTF(x) do { if (pflogdebug) printf x ; } while (0) 76 #else 77 #define DPRINTF(x) 78 #endif 79 80 void pflogattach(int); 81 int pflogifs_resize(size_t); 82 int pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 83 struct rtentry *); 84 int pflogioctl(struct ifnet *, u_long, caddr_t); 85 void pflogstart(struct ifnet *); 86 int pflog_clone_create(struct if_clone *, int); 87 int pflog_clone_destroy(struct ifnet *); 88 void pflog_bpfcopy(const void *, void *, size_t); 89 90 LIST_HEAD(, pflog_softc) pflogif_list; 91 struct if_clone pflog_cloner = 92 IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy); 93 94 int npflogifs = 0; 95 struct ifnet **pflogifs = NULL; /* for fast access */ 96 struct mbuf *pflog_mhdr = NULL, *pflog_mptr = NULL; 97 98 void 99 pflogattach(int npflog) 100 { 101 LIST_INIT(&pflogif_list); 102 if (pflog_mhdr == NULL) 103 if ((pflog_mhdr = m_get(M_DONTWAIT, MT_HEADER)) == NULL) 104 panic("pflogattach: no mbuf"); 105 if (pflog_mptr == NULL) 106 if ((pflog_mptr = m_get(M_DONTWAIT, MT_DATA)) == NULL) 107 panic("pflogattach: no mbuf"); 108 if_clone_attach(&pflog_cloner); 109 } 110 111 int 112 pflogifs_resize(size_t n) 113 { 114 struct ifnet **p; 115 int i; 116 117 if (n > SIZE_MAX / sizeof(*p)) 118 return (EINVAL); 119 if (n == 0) 120 p = NULL; 121 else 122 if ((p = malloc(n * sizeof(*p), M_DEVBUF, 123 M_NOWAIT|M_ZERO)) == NULL) 124 return (ENOMEM); 125 for (i = 0; i < n; i++) 126 if (i < npflogifs) 127 p[i] = pflogifs[i]; 128 else 129 p[i] = NULL; 130 131 if (pflogifs) 132 free(pflogifs, M_DEVBUF, 0); 133 pflogifs = p; 134 npflogifs = n; 135 return (0); 136 } 137 138 int 139 pflog_clone_create(struct if_clone *ifc, int unit) 140 { 141 struct ifnet *ifp; 142 struct pflog_softc *pflogif; 143 int s; 144 145 if ((pflogif = malloc(sizeof(*pflogif), 146 M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) 147 return (ENOMEM); 148 149 pflogif->sc_unit = unit; 150 ifp = &pflogif->sc_if; 151 snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit); 152 ifp->if_softc = pflogif; 153 ifp->if_mtu = PFLOGMTU; 154 ifp->if_ioctl = pflogioctl; 155 ifp->if_output = pflogoutput; 156 ifp->if_start = pflogstart; 157 ifp->if_type = IFT_PFLOG; 158 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 159 ifp->if_hdrlen = PFLOG_HDRLEN; 160 if_attach(ifp); 161 if_alloc_sadl(ifp); 162 163 #if NBPFILTER > 0 164 bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN); 165 #endif 166 167 s = splnet(); 168 LIST_INSERT_HEAD(&pflogif_list, pflogif, sc_list); 169 if (unit + 1 > npflogifs && pflogifs_resize(unit + 1) != 0) { 170 splx(s); 171 return (ENOMEM); 172 } 173 pflogifs[unit] = ifp; 174 splx(s); 175 176 return (0); 177 } 178 179 int 180 pflog_clone_destroy(struct ifnet *ifp) 181 { 182 struct pflog_softc *pflogif = ifp->if_softc; 183 int s, i; 184 185 s = splnet(); 186 pflogifs[pflogif->sc_unit] = NULL; 187 LIST_REMOVE(pflogif, sc_list); 188 189 for (i = npflogifs; i > 0 && pflogifs[i - 1] == NULL; i--) 190 ; /* nothing */ 191 if (i < npflogifs) 192 pflogifs_resize(i); /* error harmless here */ 193 splx(s); 194 195 if_detach(ifp); 196 free(pflogif, M_DEVBUF, 0); 197 return (0); 198 } 199 200 /* 201 * Start output on the pflog interface. 202 */ 203 void 204 pflogstart(struct ifnet *ifp) 205 { 206 struct mbuf *m; 207 int s; 208 209 for (;;) { 210 s = splnet(); 211 IF_DROP(&ifp->if_snd); 212 IF_DEQUEUE(&ifp->if_snd, m); 213 splx(s); 214 215 if (m == NULL) 216 return; 217 else 218 m_freem(m); 219 } 220 } 221 222 int 223 pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 224 struct rtentry *rt) 225 { 226 m_freem(m); 227 return (0); 228 } 229 230 /* ARGSUSED */ 231 int 232 pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 233 { 234 switch (cmd) { 235 case SIOCSIFFLAGS: 236 if (ifp->if_flags & IFF_UP) 237 ifp->if_flags |= IFF_RUNNING; 238 else 239 ifp->if_flags &= ~IFF_RUNNING; 240 break; 241 default: 242 return (ENOTTY); 243 } 244 245 return (0); 246 } 247 248 int 249 pflog_packet(struct pf_pdesc *pd, u_int8_t reason, struct pf_rule *rm, 250 struct pf_rule *am, struct pf_ruleset *ruleset) 251 { 252 #if NBPFILTER > 0 253 struct ifnet *ifn; 254 struct pfloghdr hdr; 255 256 if (rm == NULL || pd == NULL || pd->kif == NULL || pd->m == NULL) 257 return (-1); 258 259 if (rm->logif >= npflogifs || (ifn = pflogifs[rm->logif]) == NULL || 260 !ifn->if_bpf) 261 return (0); 262 263 bzero(&hdr, sizeof(hdr)); 264 hdr.length = PFLOG_REAL_HDRLEN; 265 hdr.action = rm->action; 266 hdr.reason = reason; 267 memcpy(hdr.ifname, pd->kif->pfik_name, sizeof(hdr.ifname)); 268 269 if (am == NULL) { 270 hdr.rulenr = htonl(rm->nr); 271 hdr.subrulenr = -1; 272 } else { 273 hdr.rulenr = htonl(am->nr); 274 hdr.subrulenr = htonl(rm->nr); 275 if (ruleset != NULL && ruleset->anchor != NULL) 276 strlcpy(hdr.ruleset, ruleset->anchor->name, 277 sizeof(hdr.ruleset)); 278 } 279 if (rm->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done) 280 pd->lookup.done = pf_socket_lookup(pd); 281 if (pd->lookup.done > 0) { 282 hdr.uid = pd->lookup.uid; 283 hdr.pid = pd->lookup.pid; 284 } else { 285 hdr.uid = UID_MAX; 286 hdr.pid = NO_PID; 287 } 288 hdr.rule_uid = rm->cuid; 289 hdr.rule_pid = rm->cpid; 290 hdr.dir = pd->dir; 291 292 PF_ACPY(&hdr.saddr, &pd->nsaddr, pd->naf); 293 PF_ACPY(&hdr.daddr, &pd->ndaddr, pd->naf); 294 hdr.af = pd->af; 295 hdr.naf = pd->naf; 296 hdr.sport = pd->nsport; 297 hdr.dport = pd->ndport; 298 299 ifn->if_opackets++; 300 ifn->if_obytes += pd->m->m_pkthdr.len; 301 302 bpf_mtap_hdr(ifn->if_bpf, (caddr_t)&hdr, PFLOG_HDRLEN, pd->m, 303 BPF_DIRECTION_OUT, pflog_bpfcopy); 304 #endif 305 306 return (0); 307 } 308 309 void 310 pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len) 311 { 312 struct mbuf *m, *mp, *mhdr, *mptr; 313 struct pfloghdr *pfloghdr; 314 u_int count; 315 u_char *dst, *mdst; 316 u_short reason; 317 int afto, hlen, mlen, off; 318 union pf_headers { 319 struct tcphdr tcp; 320 struct udphdr udp; 321 struct icmp icmp; 322 #ifdef INET6 323 struct icmp6_hdr icmp6; 324 struct mld_hdr mld; 325 struct nd_neighbor_solicit nd_ns; 326 #endif /* INET6 */ 327 } pdhdrs; 328 329 struct pf_pdesc pd; 330 struct pf_addr osaddr, odaddr; 331 u_int16_t osport = 0, odport = 0; 332 u_int8_t proto = 0; 333 334 m = (struct mbuf *)src_arg; 335 dst = dst_arg; 336 337 mhdr = pflog_mhdr; 338 mptr = pflog_mptr; 339 340 if (m == NULL) 341 panic("pflog_bpfcopy got no mbuf"); 342 343 /* first mbuf holds struct pfloghdr */ 344 pfloghdr = mtod(m, struct pfloghdr *); 345 afto = pfloghdr->af != pfloghdr->naf; 346 count = min(m->m_len, len); 347 bcopy(pfloghdr, dst, count); 348 pfloghdr = (struct pfloghdr *)dst; 349 dst += count; 350 len -= count; 351 m = m->m_next; 352 353 if (len <= 0) 354 return; 355 356 /* second mbuf is pkthdr */ 357 if (m == NULL) 358 panic("no second mbuf"); 359 360 /* 361 * temporary mbuf will hold an ip/ip6 header and 8 bytes 362 * of the protocol header 363 */ 364 m_inithdr(mhdr); 365 mhdr->m_len = 0; /* XXX not done in m_inithdr() */ 366 367 #if INET && INET6 368 /* offset for a new header */ 369 if (afto && pfloghdr->af == AF_INET) 370 mhdr->m_data += sizeof(struct ip6_hdr) - 371 sizeof(struct ip); 372 #endif /* INET && INET6 */ 373 374 mdst = mtod(mhdr, char *); 375 switch (pfloghdr->af) { 376 case AF_INET: { 377 struct ip *h; 378 379 if (m->m_pkthdr.len < sizeof(*h)) 380 goto copy; 381 m_copydata(m, 0, sizeof(*h), mdst); 382 h = (struct ip *)mdst; 383 hlen = h->ip_hl << 2; 384 if (hlen > sizeof(*h) && (m->m_pkthdr.len >= hlen)) 385 m_copydata(m, sizeof(*h), hlen - sizeof(*h), 386 mdst + sizeof(*h)); 387 break; 388 } 389 #ifdef INET6 390 case AF_INET6: { 391 struct ip6_hdr *h; 392 393 if (m->m_pkthdr.len < sizeof(*h)) 394 goto copy; 395 hlen = sizeof(struct ip6_hdr); 396 m_copydata(m, 0, hlen, mdst); 397 h = (struct ip6_hdr *)mdst; 398 proto = h->ip6_nxt; 399 break; 400 } 401 #endif /* INET6 */ 402 default: 403 /* shouldn't happen ever :-) */ 404 goto copy; 405 } 406 407 if (m->m_pkthdr.len < hlen + 8 && proto != IPPROTO_NONE) 408 goto copy; 409 else if (proto != IPPROTO_NONE) { 410 /* copy 8 bytes of the protocol header */ 411 m_copydata(m, hlen, 8, mdst + hlen); 412 hlen += 8; 413 } 414 415 mhdr->m_len += hlen; 416 mhdr->m_pkthdr.len = mhdr->m_len; 417 418 /* create a chain mhdr -> mptr, mptr->m_data = (m->m_data+hlen) */ 419 mp = m_getptr(m, hlen, &off); 420 if (mp != NULL) { 421 bcopy(mp, mptr, sizeof(*mptr)); 422 mptr->m_data += off; 423 mptr->m_len -= off; 424 mptr->m_flags &= ~M_PKTHDR; 425 mhdr->m_next = mptr; 426 mhdr->m_pkthdr.len += m->m_pkthdr.len - hlen; 427 } 428 429 /* rewrite addresses if needed */ 430 if (pf_setup_pdesc(&pd, &pdhdrs, pfloghdr->af, pfloghdr->dir, NULL, 431 mhdr, &reason) != PF_PASS) 432 goto copy; 433 pd.naf = pfloghdr->naf; 434 435 PF_ACPY(&osaddr, pd.src, pd.af); 436 PF_ACPY(&odaddr, pd.dst, pd.af); 437 if (pd.sport) 438 osport = *pd.sport; 439 if (pd.dport) 440 odport = *pd.dport; 441 442 if (pd.virtual_proto != PF_VPROTO_FRAGMENT && 443 (pfloghdr->rewritten = pf_translate(&pd, &pfloghdr->saddr, 444 pfloghdr->sport, &pfloghdr->daddr, pfloghdr->dport, 0, 445 pfloghdr->dir))) { 446 m_copyback(pd.m, pd.off, min(pd.m->m_len - pd.off, pd.hdrlen), 447 pd.hdr.any, M_NOWAIT); 448 #if INET && INET6 449 if (afto) { 450 PF_ACPY(&pd.nsaddr, &pfloghdr->saddr, pd.naf); 451 PF_ACPY(&pd.ndaddr, &pfloghdr->daddr, pd.naf); 452 } 453 #endif /* INET && INET6 */ 454 PF_ACPY(&pfloghdr->saddr, &osaddr, pd.af); 455 PF_ACPY(&pfloghdr->daddr, &odaddr, pd.af); 456 pfloghdr->sport = osport; 457 pfloghdr->dport = odport; 458 } 459 460 pd.tot_len = min(pd.tot_len, len); 461 pd.tot_len -= pd.m->m_data - pd.m->m_pktdat; 462 463 #if INET && INET6 464 if (afto && pfloghdr->rewritten) 465 pf_translate_af(&pd); 466 #endif /* INET && INET6 */ 467 468 m = pd.m; 469 copy: 470 mlen = min(m->m_pkthdr.len, len); 471 m_copydata(m, 0, mlen, dst); 472 len -= mlen; 473 if (len > 0) 474 bzero(dst + mlen, len); 475 } 476