156132dccSAndrey V. Elsukov /*-
256132dccSAndrey V. Elsukov * Copyright (c) 2016 Yandex LLC
356132dccSAndrey V. Elsukov * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
456132dccSAndrey V. Elsukov *
556132dccSAndrey V. Elsukov * Redistribution and use in source and binary forms, with or without
656132dccSAndrey V. Elsukov * modification, are permitted provided that the following conditions
756132dccSAndrey V. Elsukov * are met:
856132dccSAndrey V. Elsukov * 1. Redistributions of source code must retain the above copyright
956132dccSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer.
1056132dccSAndrey V. Elsukov * 2. Redistributions in binary form must reproduce the above copyright
1156132dccSAndrey V. Elsukov * notice, this list of conditions and the following disclaimer in the
1256132dccSAndrey V. Elsukov * documentation and/or other materials provided with the distribution.
1356132dccSAndrey V. Elsukov *
1456132dccSAndrey V. Elsukov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1556132dccSAndrey V. Elsukov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1656132dccSAndrey V. Elsukov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1756132dccSAndrey V. Elsukov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1856132dccSAndrey V. Elsukov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1956132dccSAndrey V. Elsukov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2056132dccSAndrey V. Elsukov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2156132dccSAndrey V. Elsukov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2256132dccSAndrey V. Elsukov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2356132dccSAndrey V. Elsukov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2456132dccSAndrey V. Elsukov * SUCH DAMAGE.
2556132dccSAndrey V. Elsukov */
2656132dccSAndrey V. Elsukov
2756132dccSAndrey V. Elsukov #include <sys/param.h>
2856132dccSAndrey V. Elsukov #include <sys/systm.h>
2956132dccSAndrey V. Elsukov #include <sys/mbuf.h>
3056132dccSAndrey V. Elsukov #include <sys/kernel.h>
3156132dccSAndrey V. Elsukov #include <sys/lock.h>
3256132dccSAndrey V. Elsukov #include <sys/socket.h>
3356132dccSAndrey V. Elsukov #include <net/ethernet.h>
3456132dccSAndrey V. Elsukov #include <net/if.h>
3556132dccSAndrey V. Elsukov #include <net/if_pflog.h>
3656132dccSAndrey V. Elsukov #include <net/if_var.h>
3756132dccSAndrey V. Elsukov #include <net/if_clone.h>
38*3d0d5b21SJustin Hibbits #include <net/if_private.h>
3956132dccSAndrey V. Elsukov #include <net/if_types.h>
4056132dccSAndrey V. Elsukov #include <net/vnet.h>
4156132dccSAndrey V. Elsukov #include <net/bpf.h>
4256132dccSAndrey V. Elsukov
4356132dccSAndrey V. Elsukov #include <netinet/in.h>
4456132dccSAndrey V. Elsukov #include <netinet/ip_fw.h>
4556132dccSAndrey V. Elsukov #include <netinet/ip_var.h>
4656132dccSAndrey V. Elsukov #include <netpfil/ipfw/ip_fw_private.h>
4756132dccSAndrey V. Elsukov
485f901c92SAndrew Turner VNET_DEFINE_STATIC(struct ifnet *, log_if);
495f901c92SAndrew Turner VNET_DEFINE_STATIC(struct ifnet *, pflog_if);
505f901c92SAndrew Turner VNET_DEFINE_STATIC(struct if_clone *, ipfw_cloner);
515f901c92SAndrew Turner VNET_DEFINE_STATIC(struct if_clone *, ipfwlog_cloner);
5256132dccSAndrey V. Elsukov #define V_ipfw_cloner VNET(ipfw_cloner)
5356132dccSAndrey V. Elsukov #define V_ipfwlog_cloner VNET(ipfwlog_cloner)
5456132dccSAndrey V. Elsukov #define V_log_if VNET(log_if)
5556132dccSAndrey V. Elsukov #define V_pflog_if VNET(pflog_if)
5656132dccSAndrey V. Elsukov
5756132dccSAndrey V. Elsukov static const char ipfwname[] = "ipfw";
5856132dccSAndrey V. Elsukov static const char ipfwlogname[] = "ipfwlog";
5956132dccSAndrey V. Elsukov
6056132dccSAndrey V. Elsukov static int
ipfw_bpf_ioctl(struct ifnet * ifp,u_long cmd,caddr_t addr)6156132dccSAndrey V. Elsukov ipfw_bpf_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
6256132dccSAndrey V. Elsukov {
6356132dccSAndrey V. Elsukov
6456132dccSAndrey V. Elsukov return (EINVAL);
6556132dccSAndrey V. Elsukov }
6656132dccSAndrey V. Elsukov
6756132dccSAndrey V. Elsukov static int
ipfw_bpf_output(struct ifnet * ifp,struct mbuf * m,const struct sockaddr * dst,struct route * ro)6856132dccSAndrey V. Elsukov ipfw_bpf_output(struct ifnet *ifp, struct mbuf *m,
6956132dccSAndrey V. Elsukov const struct sockaddr *dst, struct route *ro)
7056132dccSAndrey V. Elsukov {
7156132dccSAndrey V. Elsukov
7256132dccSAndrey V. Elsukov if (m != NULL)
7356132dccSAndrey V. Elsukov FREE_PKT(m);
7456132dccSAndrey V. Elsukov return (0);
7556132dccSAndrey V. Elsukov }
7656132dccSAndrey V. Elsukov
7756132dccSAndrey V. Elsukov static void
ipfw_clone_destroy(struct ifnet * ifp)7856132dccSAndrey V. Elsukov ipfw_clone_destroy(struct ifnet *ifp)
7956132dccSAndrey V. Elsukov {
8056132dccSAndrey V. Elsukov
8156132dccSAndrey V. Elsukov if (ifp->if_hdrlen == ETHER_HDR_LEN)
8256132dccSAndrey V. Elsukov V_log_if = NULL;
8356132dccSAndrey V. Elsukov else
8456132dccSAndrey V. Elsukov V_pflog_if = NULL;
8556132dccSAndrey V. Elsukov
86455d2ecbSAndrey V. Elsukov NET_EPOCH_WAIT();
8756132dccSAndrey V. Elsukov bpfdetach(ifp);
8856132dccSAndrey V. Elsukov if_detach(ifp);
8956132dccSAndrey V. Elsukov if_free(ifp);
9056132dccSAndrey V. Elsukov }
9156132dccSAndrey V. Elsukov
9256132dccSAndrey V. Elsukov static int
ipfw_clone_create(struct if_clone * ifc,int unit,caddr_t params)9356132dccSAndrey V. Elsukov ipfw_clone_create(struct if_clone *ifc, int unit, caddr_t params)
9456132dccSAndrey V. Elsukov {
9556132dccSAndrey V. Elsukov struct ifnet *ifp;
9656132dccSAndrey V. Elsukov
9756132dccSAndrey V. Elsukov ifp = if_alloc(IFT_PFLOG);
9856132dccSAndrey V. Elsukov if_initname(ifp, ipfwname, unit);
9956132dccSAndrey V. Elsukov ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
10056132dccSAndrey V. Elsukov ifp->if_mtu = 65536;
10156132dccSAndrey V. Elsukov ifp->if_ioctl = ipfw_bpf_ioctl;
10256132dccSAndrey V. Elsukov ifp->if_output = ipfw_bpf_output;
10356132dccSAndrey V. Elsukov ifp->if_hdrlen = ETHER_HDR_LEN;
10456132dccSAndrey V. Elsukov if_attach(ifp);
10556132dccSAndrey V. Elsukov bpfattach(ifp, DLT_EN10MB, ETHER_HDR_LEN);
10656132dccSAndrey V. Elsukov if (V_log_if != NULL) {
10756132dccSAndrey V. Elsukov bpfdetach(ifp);
10856132dccSAndrey V. Elsukov if_detach(ifp);
10956132dccSAndrey V. Elsukov if_free(ifp);
11056132dccSAndrey V. Elsukov return (EEXIST);
11156132dccSAndrey V. Elsukov }
11256132dccSAndrey V. Elsukov V_log_if = ifp;
11356132dccSAndrey V. Elsukov return (0);
11456132dccSAndrey V. Elsukov }
11556132dccSAndrey V. Elsukov
11656132dccSAndrey V. Elsukov static int
ipfwlog_clone_create(struct if_clone * ifc,int unit,caddr_t params)11756132dccSAndrey V. Elsukov ipfwlog_clone_create(struct if_clone *ifc, int unit, caddr_t params)
11856132dccSAndrey V. Elsukov {
11956132dccSAndrey V. Elsukov struct ifnet *ifp;
12056132dccSAndrey V. Elsukov
12156132dccSAndrey V. Elsukov ifp = if_alloc(IFT_PFLOG);
12256132dccSAndrey V. Elsukov if_initname(ifp, ipfwlogname, unit);
12356132dccSAndrey V. Elsukov ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
12456132dccSAndrey V. Elsukov ifp->if_mtu = 65536;
12556132dccSAndrey V. Elsukov ifp->if_ioctl = ipfw_bpf_ioctl;
12656132dccSAndrey V. Elsukov ifp->if_output = ipfw_bpf_output;
12756132dccSAndrey V. Elsukov ifp->if_hdrlen = PFLOG_HDRLEN;
12856132dccSAndrey V. Elsukov if_attach(ifp);
12956132dccSAndrey V. Elsukov bpfattach(ifp, DLT_PFLOG, PFLOG_HDRLEN);
13056132dccSAndrey V. Elsukov if (V_pflog_if != NULL) {
13156132dccSAndrey V. Elsukov bpfdetach(ifp);
13256132dccSAndrey V. Elsukov if_detach(ifp);
13356132dccSAndrey V. Elsukov if_free(ifp);
13456132dccSAndrey V. Elsukov return (EEXIST);
13556132dccSAndrey V. Elsukov }
13656132dccSAndrey V. Elsukov V_pflog_if = ifp;
13756132dccSAndrey V. Elsukov return (0);
13856132dccSAndrey V. Elsukov }
13956132dccSAndrey V. Elsukov
14056132dccSAndrey V. Elsukov void
ipfw_bpf_tap(u_char * pkt,u_int pktlen)141f355cb3eSGleb Smirnoff ipfw_bpf_tap(u_char *pkt, u_int pktlen)
142f355cb3eSGleb Smirnoff {
143455d2ecbSAndrey V. Elsukov struct ifnet *ifp = V_log_if;
144f355cb3eSGleb Smirnoff
145455d2ecbSAndrey V. Elsukov NET_EPOCH_ASSERT();
146455d2ecbSAndrey V. Elsukov if (ifp != NULL)
147455d2ecbSAndrey V. Elsukov BPF_TAP(ifp, pkt, pktlen);
148f355cb3eSGleb Smirnoff }
149f355cb3eSGleb Smirnoff
150f355cb3eSGleb Smirnoff void
ipfw_bpf_mtap(struct mbuf * m)151f355cb3eSGleb Smirnoff ipfw_bpf_mtap(struct mbuf *m)
152f355cb3eSGleb Smirnoff {
153455d2ecbSAndrey V. Elsukov struct ifnet *ifp = V_log_if;
154f355cb3eSGleb Smirnoff
155455d2ecbSAndrey V. Elsukov NET_EPOCH_ASSERT();
156455d2ecbSAndrey V. Elsukov if (ifp != NULL)
157455d2ecbSAndrey V. Elsukov BPF_MTAP(ifp, m);
158f355cb3eSGleb Smirnoff }
159f355cb3eSGleb Smirnoff
160f355cb3eSGleb Smirnoff void
ipfw_bpf_mtap2(void * data,u_int dlen,struct mbuf * m)16156132dccSAndrey V. Elsukov ipfw_bpf_mtap2(void *data, u_int dlen, struct mbuf *m)
16256132dccSAndrey V. Elsukov {
1632d023278SGleb Smirnoff struct ifnet *logif;
16456132dccSAndrey V. Elsukov
165455d2ecbSAndrey V. Elsukov NET_EPOCH_ASSERT();
1662d023278SGleb Smirnoff switch (dlen) {
1672d023278SGleb Smirnoff case (ETHER_HDR_LEN):
1682d023278SGleb Smirnoff logif = V_log_if;
1692d023278SGleb Smirnoff break;
1702d023278SGleb Smirnoff case (PFLOG_HDRLEN):
1712d023278SGleb Smirnoff logif = V_pflog_if;
1722d023278SGleb Smirnoff break;
1732d023278SGleb Smirnoff default:
1742d023278SGleb Smirnoff #ifdef INVARIANTS
1752d023278SGleb Smirnoff panic("%s: unsupported len %d", __func__, dlen);
1762d023278SGleb Smirnoff #endif
1772d023278SGleb Smirnoff logif = NULL;
17856132dccSAndrey V. Elsukov }
1792d023278SGleb Smirnoff
1802d023278SGleb Smirnoff if (logif != NULL)
1812d023278SGleb Smirnoff BPF_MTAP2(logif, data, dlen, m);
18256132dccSAndrey V. Elsukov }
18356132dccSAndrey V. Elsukov
18456132dccSAndrey V. Elsukov void
ipfw_bpf_init(int first __unused)185455d2ecbSAndrey V. Elsukov ipfw_bpf_init(int first __unused)
18656132dccSAndrey V. Elsukov {
18756132dccSAndrey V. Elsukov
18856132dccSAndrey V. Elsukov V_log_if = NULL;
18956132dccSAndrey V. Elsukov V_pflog_if = NULL;
19056132dccSAndrey V. Elsukov V_ipfw_cloner = if_clone_simple(ipfwname, ipfw_clone_create,
19156132dccSAndrey V. Elsukov ipfw_clone_destroy, 0);
19256132dccSAndrey V. Elsukov V_ipfwlog_cloner = if_clone_simple(ipfwlogname, ipfwlog_clone_create,
19356132dccSAndrey V. Elsukov ipfw_clone_destroy, 0);
19456132dccSAndrey V. Elsukov }
19556132dccSAndrey V. Elsukov
19656132dccSAndrey V. Elsukov void
ipfw_bpf_uninit(int last __unused)197455d2ecbSAndrey V. Elsukov ipfw_bpf_uninit(int last __unused)
19856132dccSAndrey V. Elsukov {
19956132dccSAndrey V. Elsukov
20056132dccSAndrey V. Elsukov if_clone_detach(V_ipfw_cloner);
20156132dccSAndrey V. Elsukov if_clone_detach(V_ipfwlog_cloner);
20256132dccSAndrey V. Elsukov }
203