LCOV - code coverage report
Current view: top level - net - if_pflog.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 214 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 9 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_pflog.c,v 1.81 2018/01/09 15:24:24 bluhm 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/stdint.h>
      46             : #include <sys/ioctl.h>
      47             : 
      48             : #include <net/if.h>
      49             : #include <net/if_var.h>
      50             : #include <net/if_types.h>
      51             : #include <net/bpf.h>
      52             : 
      53             : #include <netinet/in.h>
      54             : #include <netinet/ip.h>
      55             : #include <netinet/ip_icmp.h>
      56             : #include <netinet/tcp.h>
      57             : #include <netinet/udp.h>
      58             : 
      59             : #ifdef INET6
      60             : #include <netinet/ip6.h>
      61             : #include <netinet/icmp6.h>
      62             : #endif /* INET6 */
      63             : 
      64             : #include <net/pfvar.h>
      65             : #include <net/pfvar_priv.h>
      66             : #include <net/if_pflog.h>
      67             : 
      68             : #define PFLOGMTU        (32768 + MHLEN + MLEN)
      69             : 
      70             : #ifdef PFLOGDEBUG
      71             : #define DPRINTF(x)    do { if (pflogdebug) printf x ; } while (0)
      72             : #else
      73             : #define DPRINTF(x)
      74             : #endif
      75             : 
      76             : void    pflogattach(int);
      77             : int     pflogifs_resize(size_t);
      78             : int     pflogoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
      79             :                        struct rtentry *);
      80             : int     pflogioctl(struct ifnet *, u_long, caddr_t);
      81             : void    pflogstart(struct ifnet *);
      82             : int     pflog_clone_create(struct if_clone *, int);
      83             : int     pflog_clone_destroy(struct ifnet *);
      84             : void    pflog_bpfcopy(const void *, void *, size_t);
      85             : 
      86             : struct if_clone pflog_cloner =
      87             :     IF_CLONE_INITIALIZER("pflog", pflog_clone_create, pflog_clone_destroy);
      88             : 
      89             : int               npflogifs = 0;
      90             : struct ifnet    **pflogifs = NULL;      /* for fast access */
      91             : struct mbuf      *pflog_mhdr = NULL, *pflog_mptr = NULL;
      92             : 
      93             : void
      94           0 : pflogattach(int npflog)
      95             : {
      96           0 :         if (pflog_mhdr == NULL)
      97           0 :                 if ((pflog_mhdr = m_get(M_DONTWAIT, MT_HEADER)) == NULL)
      98           0 :                         panic("pflogattach: no mbuf");
      99           0 :         if (pflog_mptr == NULL)
     100           0 :                 if ((pflog_mptr = m_get(M_DONTWAIT, MT_DATA)) == NULL)
     101           0 :                         panic("pflogattach: no mbuf");
     102           0 :         if_clone_attach(&pflog_cloner);
     103           0 : }
     104             : 
     105             : int
     106           0 : pflogifs_resize(size_t n)
     107             : {
     108             :         struct ifnet    **p;
     109             :         int               i;
     110             : 
     111           0 :         NET_ASSERT_LOCKED();
     112             : 
     113           0 :         if (n > SIZE_MAX / sizeof(*p))
     114           0 :                 return (EINVAL);
     115           0 :         if (n == 0)
     116           0 :                 p = NULL;
     117             :         else
     118           0 :                 if ((p = mallocarray(n, sizeof(*p), M_DEVBUF,
     119           0 :                     M_NOWAIT|M_ZERO)) == NULL)
     120           0 :                         return (ENOMEM);
     121           0 :         for (i = 0; i < n; i++)
     122           0 :                 if (i < npflogifs)
     123           0 :                         p[i] = pflogifs[i];
     124             :                 else
     125           0 :                         p[i] = NULL;
     126             : 
     127           0 :         if (pflogifs)
     128           0 :                 free(pflogifs, M_DEVBUF, 0);
     129           0 :         pflogifs = p;
     130           0 :         npflogifs = n;
     131           0 :         return (0);
     132           0 : }
     133             : 
     134             : int
     135           0 : pflog_clone_create(struct if_clone *ifc, int unit)
     136             : {
     137             :         struct ifnet *ifp;
     138             :         struct pflog_softc *pflogif;
     139             : 
     140           0 :         pflogif = malloc(sizeof(*pflogif), M_DEVBUF, M_WAITOK|M_ZERO);
     141           0 :         pflogif->sc_unit = unit;
     142           0 :         ifp = &pflogif->sc_if;
     143           0 :         snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflog%d", unit);
     144           0 :         ifp->if_softc = pflogif;
     145           0 :         ifp->if_mtu = PFLOGMTU;
     146           0 :         ifp->if_ioctl = pflogioctl;
     147           0 :         ifp->if_output = pflogoutput;
     148           0 :         ifp->if_start = pflogstart;
     149           0 :         ifp->if_xflags = IFXF_CLONED;
     150           0 :         ifp->if_type = IFT_PFLOG;
     151           0 :         IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
     152           0 :         ifp->if_hdrlen = PFLOG_HDRLEN;
     153           0 :         if_attach(ifp);
     154           0 :         if_alloc_sadl(ifp);
     155             : 
     156             : #if NBPFILTER > 0
     157           0 :         bpfattach(&pflogif->sc_if.if_bpf, ifp, DLT_PFLOG, PFLOG_HDRLEN);
     158             : #endif
     159             : 
     160           0 :         NET_LOCK();
     161           0 :         if (unit + 1 > npflogifs && pflogifs_resize(unit + 1) != 0) {
     162           0 :                 NET_UNLOCK();
     163           0 :                 return (ENOMEM);
     164             :         }
     165           0 :         pflogifs[unit] = ifp;
     166           0 :         NET_UNLOCK();
     167             : 
     168           0 :         return (0);
     169           0 : }
     170             : 
     171             : int
     172           0 : pflog_clone_destroy(struct ifnet *ifp)
     173             : {
     174           0 :         struct pflog_softc      *pflogif = ifp->if_softc;
     175             :         int                      i;
     176             : 
     177           0 :         NET_LOCK();
     178           0 :         pflogifs[pflogif->sc_unit] = NULL;
     179           0 :         for (i = npflogifs; i > 0 && pflogifs[i - 1] == NULL; i--)
     180             :                 ; /* nothing */
     181           0 :         if (i < npflogifs)
     182           0 :                 pflogifs_resize(i);     /* error harmless here */
     183           0 :         NET_UNLOCK();
     184             : 
     185           0 :         if_detach(ifp);
     186           0 :         free(pflogif, M_DEVBUF, 0);
     187           0 :         return (0);
     188             : }
     189             : 
     190             : /*
     191             :  * Start output on the pflog interface.
     192             :  */
     193             : void
     194           0 : pflogstart(struct ifnet *ifp)
     195             : {
     196           0 :         IFQ_PURGE(&ifp->if_snd);
     197           0 : }
     198             : 
     199             : int
     200           0 : pflogoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
     201             :         struct rtentry *rt)
     202             : {
     203           0 :         m_freem(m);     /* drop packet */
     204           0 :         return (EAFNOSUPPORT);
     205             : }
     206             : 
     207             : int
     208           0 : pflogioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
     209             : {
     210           0 :         switch (cmd) {
     211             :         case SIOCSIFFLAGS:
     212           0 :                 if (ifp->if_flags & IFF_UP)
     213           0 :                         ifp->if_flags |= IFF_RUNNING;
     214             :                 else
     215           0 :                         ifp->if_flags &= ~IFF_RUNNING;
     216             :                 break;
     217             :         default:
     218           0 :                 return (ENOTTY);
     219             :         }
     220             : 
     221           0 :         return (0);
     222           0 : }
     223             : 
     224             : int
     225           0 : pflog_packet(struct pf_pdesc *pd, u_int8_t reason, struct pf_rule *rm,
     226             :     struct pf_rule *am, struct pf_ruleset *ruleset, struct pf_rule *trigger)
     227             : {
     228             : #if NBPFILTER > 0
     229             :         struct ifnet *ifn;
     230           0 :         struct pfloghdr hdr;
     231             : 
     232           0 :         if (rm == NULL || pd == NULL || pd->kif == NULL || pd->m == NULL)
     233           0 :                 return (-1);
     234           0 :         if (trigger == NULL)
     235           0 :                 trigger = rm;
     236             : 
     237           0 :         if (trigger->logif >= npflogifs || (ifn = pflogifs[trigger->logif]) ==
     238           0 :             NULL || !ifn->if_bpf)
     239           0 :                 return (0);
     240             : 
     241           0 :         bzero(&hdr, sizeof(hdr));
     242           0 :         hdr.length = PFLOG_REAL_HDRLEN;
     243           0 :         hdr.action = rm->action;
     244           0 :         hdr.reason = reason;
     245           0 :         memcpy(hdr.ifname, pd->kif->pfik_name, sizeof(hdr.ifname));
     246             : 
     247           0 :         if (am == NULL) {
     248           0 :                 hdr.rulenr = htonl(rm->nr);
     249           0 :                 hdr.subrulenr = -1;
     250           0 :         } else {
     251           0 :                 hdr.rulenr = htonl(am->nr);
     252           0 :                 hdr.subrulenr = htonl(rm->nr);
     253           0 :                 if (ruleset != NULL && ruleset->anchor != NULL)
     254           0 :                         strlcpy(hdr.ruleset, ruleset->anchor->name,
     255             :                             sizeof(hdr.ruleset));
     256             :         }
     257           0 :         if (trigger->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done)
     258           0 :                 pd->lookup.done = pf_socket_lookup(pd);
     259           0 :         if (pd->lookup.done > 0) {
     260           0 :                 hdr.uid = pd->lookup.uid;
     261           0 :                 hdr.pid = pd->lookup.pid;
     262           0 :         } else {
     263           0 :                 hdr.uid = UID_MAX;
     264           0 :                 hdr.pid = NO_PID;
     265             :         }
     266           0 :         hdr.rule_uid = rm->cuid;
     267           0 :         hdr.rule_pid = rm->cpid;
     268           0 :         hdr.dir = pd->dir;
     269             : 
     270           0 :         PF_ACPY(&hdr.saddr, &pd->nsaddr, pd->naf);
     271           0 :         PF_ACPY(&hdr.daddr, &pd->ndaddr, pd->naf);
     272           0 :         hdr.af = pd->af;
     273           0 :         hdr.naf = pd->naf;
     274           0 :         hdr.sport = pd->nsport;
     275           0 :         hdr.dport = pd->ndport;
     276             : 
     277           0 :         ifn->if_opackets++;
     278           0 :         ifn->if_obytes += pd->m->m_pkthdr.len;
     279             : 
     280           0 :         bpf_mtap_hdr(ifn->if_bpf, (caddr_t)&hdr, PFLOG_HDRLEN, pd->m,
     281             :             BPF_DIRECTION_OUT, pflog_bpfcopy);
     282             : #endif
     283             : 
     284           0 :         return (0);
     285           0 : }
     286             : 
     287             : void
     288           0 : pflog_bpfcopy(const void *src_arg, void *dst_arg, size_t len)
     289             : {
     290             :         struct mbuf             *m, *mp, *mhdr, *mptr;
     291             :         struct pfloghdr         *pfloghdr;
     292             :         u_int                    count;
     293             :         u_char                  *dst, *mdst;
     294           0 :         int                      afto, hlen, mlen, off;
     295             : 
     296           0 :         struct pf_pdesc          pd;
     297           0 :         struct pf_addr           osaddr, odaddr;
     298             :         u_int16_t                osport = 0, odport = 0;
     299             :         u_int8_t                 proto = 0;
     300             : 
     301           0 :         m = (struct mbuf *)src_arg;
     302             :         dst = dst_arg;
     303             : 
     304           0 :         mhdr = pflog_mhdr;
     305           0 :         mptr = pflog_mptr;
     306             : 
     307           0 :         if (m == NULL)
     308           0 :                 panic("pflog_bpfcopy got no mbuf");
     309             : 
     310             :         /* first mbuf holds struct pfloghdr */
     311           0 :         pfloghdr = mtod(m, struct pfloghdr *);
     312           0 :         afto = pfloghdr->af != pfloghdr->naf;
     313           0 :         count = min(m->m_len, len);
     314           0 :         bcopy(pfloghdr, dst, count);
     315           0 :         pfloghdr = (struct pfloghdr *)dst;
     316           0 :         dst += count;
     317           0 :         len -= count;
     318           0 :         m = m->m_next;
     319             : 
     320           0 :         if (len <= 0)
     321           0 :                 return;
     322             : 
     323             :         /* second mbuf is pkthdr */
     324           0 :         if (m == NULL)
     325           0 :                 panic("no second mbuf");
     326             : 
     327             :         /*
     328             :          * temporary mbuf will hold an ip/ip6 header and 8 bytes
     329             :          * of the protocol header
     330             :          */
     331           0 :         m_inithdr(mhdr);
     332           0 :         mhdr->m_len = 0;     /* XXX not done in m_inithdr() */
     333             : 
     334             : #ifdef INET6
     335             :         /* offset for a new header */
     336           0 :         if (afto && pfloghdr->af == AF_INET)
     337           0 :                 mhdr->m_data += sizeof(struct ip6_hdr) -
     338             :                     sizeof(struct ip);
     339             : #endif /* INET6 */
     340             : 
     341           0 :         mdst = mtod(mhdr, char *);
     342           0 :         switch (pfloghdr->af) {
     343             :         case AF_INET: {
     344             :                 struct ip       *h;
     345             : 
     346           0 :                 if (m->m_pkthdr.len < sizeof(*h))
     347           0 :                         goto copy;
     348           0 :                 m_copydata(m, 0, sizeof(*h), mdst);
     349           0 :                 h = (struct ip *)mdst;
     350           0 :                 hlen = h->ip_hl << 2;
     351           0 :                 if (hlen > sizeof(*h) && (m->m_pkthdr.len >= hlen))
     352           0 :                         m_copydata(m, sizeof(*h), hlen - sizeof(*h),
     353           0 :                             mdst + sizeof(*h));
     354           0 :                 break;
     355             :             }
     356             : #ifdef INET6
     357             :         case AF_INET6: {
     358             :                 struct ip6_hdr  *h;
     359             : 
     360           0 :                 if (m->m_pkthdr.len < sizeof(*h))
     361           0 :                         goto copy;
     362             :                 hlen = sizeof(struct ip6_hdr);
     363           0 :                 m_copydata(m, 0, hlen, mdst);
     364           0 :                 h = (struct ip6_hdr *)mdst;
     365           0 :                 proto = h->ip6_nxt;
     366           0 :                 break;
     367             :             }
     368             : #endif /* INET6 */
     369             :         default:
     370             :                 /* shouldn't happen ever :-) */
     371             :                 goto copy;
     372             :         }
     373             : 
     374           0 :         if (m->m_pkthdr.len < hlen + 8 && proto != IPPROTO_NONE)
     375             :                 goto copy;
     376           0 :         else if (proto != IPPROTO_NONE) {
     377             :                 /* copy 8 bytes of the protocol header */
     378           0 :                 m_copydata(m, hlen, 8, mdst + hlen);
     379             :                 hlen += 8;
     380           0 :         }
     381             : 
     382           0 :         mhdr->m_len += hlen;
     383           0 :         mhdr->m_pkthdr.len = mhdr->m_len;
     384             : 
     385             :         /* create a chain mhdr -> mptr, mptr->m_data = (m->m_data+hlen) */
     386           0 :         mp = m_getptr(m, hlen, &off);
     387           0 :         if (mp != NULL) {
     388           0 :                 bcopy(mp, mptr, sizeof(*mptr));
     389           0 :                 mptr->m_data += off;
     390           0 :                 mptr->m_len -= off;
     391           0 :                 mptr->m_flags &= ~M_PKTHDR;
     392           0 :                 mhdr->m_next = mptr;
     393           0 :                 mhdr->m_pkthdr.len += m->m_pkthdr.len - hlen;
     394           0 :         }
     395             : 
     396             :         /*
     397             :          * Rewrite addresses if needed. Reason pointer must be NULL to avoid
     398             :          * counting the packet here again.
     399             :          */
     400           0 :         if (pf_setup_pdesc(&pd, pfloghdr->af, pfloghdr->dir, NULL,
     401           0 :             mhdr, NULL) != PF_PASS)
     402             :                 goto copy;
     403           0 :         pd.naf = pfloghdr->naf;
     404             : 
     405           0 :         PF_ACPY(&osaddr, pd.src, pd.af);
     406           0 :         PF_ACPY(&odaddr, pd.dst, pd.af);
     407           0 :         if (pd.sport)
     408           0 :                 osport = *pd.sport;
     409           0 :         if (pd.dport)
     410           0 :                 odport = *pd.dport;
     411             : 
     412           0 :         if (pd.virtual_proto != PF_VPROTO_FRAGMENT &&
     413           0 :             (pfloghdr->rewritten = pf_translate(&pd, &pfloghdr->saddr,
     414           0 :             pfloghdr->sport, &pfloghdr->daddr, pfloghdr->dport, 0,
     415           0 :             pfloghdr->dir))) {
     416           0 :                 m_copyback(pd.m, pd.off, min(pd.m->m_len - pd.off, pd.hdrlen),
     417           0 :                     &pd.hdr, M_NOWAIT);
     418             : #ifdef INET6
     419           0 :                 if (afto) {
     420           0 :                         PF_ACPY(&pd.nsaddr, &pfloghdr->saddr, pd.naf);
     421           0 :                         PF_ACPY(&pd.ndaddr, &pfloghdr->daddr, pd.naf);
     422           0 :                 }
     423             : #endif /* INET6 */
     424           0 :                 PF_ACPY(&pfloghdr->saddr, &osaddr, pd.af);
     425           0 :                 PF_ACPY(&pfloghdr->daddr, &odaddr, pd.af);
     426           0 :                 pfloghdr->sport = osport;
     427           0 :                 pfloghdr->dport = odport;
     428           0 :         }
     429             : 
     430           0 :         pd.tot_len = min(pd.tot_len, len);
     431           0 :         pd.tot_len -= pd.m->m_data - pd.m->m_pktdat;
     432             : 
     433             : #ifdef INET6
     434           0 :         if (afto && pfloghdr->rewritten)
     435           0 :                 pf_translate_af(&pd);
     436             : #endif /* INET6 */
     437             : 
     438           0 :         m = pd.m;
     439             :  copy:
     440           0 :         mlen = min(m->m_pkthdr.len, len);
     441           0 :         m_copydata(m, 0, mlen, dst);
     442           0 :         len -= mlen;
     443           0 :         if (len > 0)
     444           0 :                 bzero(dst + mlen, len);
     445           0 : }

Generated by: LCOV version 1.13