ipfw3: support bpf filter in layer4 module
authorBill Yuan <bycn82@leaf.dragonflybsd.org>
Wed, 17 Jun 2015 01:35:05 +0000 (09:35 +0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Wed, 17 Jun 2015 03:50:28 +0000 (20:50 -0700)
syntax:
bpf "<bpf string>"
e.g.
ipfw3 add allow all bpf "icmp and src 8.8.8.8"

bpf can be used to filter the packet payload.

pcap_compile_nocap was used to compile the bpf string
and bpf_filter for the filtering.

Makefile.inc1
lib/libipfw3/layer4/Makefile
lib/libipfw3/layer4/ipfw3_layer4.c
sys/net/ipfw3/ip_fw3.h
sys/net/ipfw3_layer4/ip_fw3_layer4.c
sys/net/ipfw3_layer4/ip_fw3_layer4.h

index 19bb3fc..6b7f7e7 100644 (file)
@@ -1025,6 +1025,8 @@ _startup_libs=            lib/csu lib/libc lib/libc_rtld
 _prebuild_libs=                lib/libbz2 lib/liblzma lib/libz
 _prebuild_libs+=       lib/libutil
 
 _prebuild_libs=                lib/libbz2 lib/liblzma lib/libz
 _prebuild_libs+=       lib/libutil
 
+_prebuild_libs+=       lib/libpcap
+
 _generic_libs= gnu/lib
 
 _prebuild_libs+= lib/libcom_err lib/libcrypt lib/libmd \
 _generic_libs= gnu/lib
 
 _prebuild_libs+= lib/libcom_err lib/libcrypt lib/libmd \
index 8e0f0b6..ff9ade7 100644 (file)
@@ -17,13 +17,15 @@ CFLAGS+=-DHAVE_STRUCT_ETHER_ADDR -DHAVE_NET_PFVAR_H
 CFLAGS+=-DINET6
 .endif
 
 CFLAGS+=-DINET6
 .endif
 
+LDADD=-lpcap
+DPADD=${LIBPCAP}
 SHLIB_MAJOR=3
 
 #
 # Magic to grab sources out of src/contrib
 #
 SHLIB_MAJOR=3
 
 #
 # Magic to grab sources out of src/contrib
 #
-LAYER2_DISTDIR?=${SRCDIR}
-CFLAGS+=-I${LAYER2_DISTDIR}
-.PATH: ${LAYER2_DISTDIR}
+LAYER4_DISTDIR?=${SRCDIR}
+CFLAGS+=-I${LAYER4_DISTDIR}
+.PATH: ${LAYER4_DISTDIR}
 
 .include <bsd.lib.mk>
 
 .include <bsd.lib.mk>
index add3a7e..a6af5c8 100644 (file)
@@ -36,6 +36,7 @@
 #include <errno.h>
 #include <grp.h>
 #include <pwd.h>
 #include <errno.h>
 #include <grp.h>
 #include <pwd.h>
+#include <pcap.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "../../../sbin/ipfw3/ipfw.h"
 #include "ipfw3_layer4.h"
 
 #include "../../../sbin/ipfw3/ipfw.h"
 #include "ipfw3_layer4.h"
 
+int
+char_at(char *str, char c)
+{
+       int pos;
+       for (pos = 0; str[pos] != '\0'; pos++) {
+               if (str[pos] == c)
+                       return pos;
+       }
+       return -1;
+}
 
 void
 parse_tcpflag(ipfw_insn **cmd, int *ac, char **av[])
 
 void
 parse_tcpflag(ipfw_insn **cmd, int *ac, char **av[])
@@ -114,6 +125,37 @@ parse_established(ipfw_insn **cmd, int *ac, char **av[])
        (*cmd)->len |= LEN_OF_IPFWINSN;
 }
 
        (*cmd)->len |= LEN_OF_IPFWINSN;
 }
 
+void
+parse_bpf(ipfw_insn **cmd, int *ac, char **av[])
+{
+       struct bpf_program program;
+       ipfw_insn_bpf *bpf;
+       int avlen;
+
+       NEXT_ARG1;
+       (*cmd)->opcode = O_LAYER4_BPF;
+       (*cmd)->module = MODULE_LAYER4_ID;
+
+       avlen = strlen(**av);
+       if (avlen > 256)
+               errx(EX_DATAERR, "bpf \"%s\" too long (max 256)", **av);
+       bpf = (ipfw_insn_bpf *)(*cmd);
+       strcpy(bpf->bf_str, **av);
+       if (pcap_compile_nopcap(65535, DLT_RAW, &program, **av, 1,
+                       PCAP_NETMASK_UNKNOWN))
+               errx(EX_DATAERR, "bpf \"%s\" compilation error", **av);
+       bpf->bf_len = program.bf_len;
+
+       memcpy(&bpf->bf_insn, program.bf_insns,
+                       sizeof(struct bpf_insn) * program.bf_len);
+       (*cmd)->len |= (sizeof(ipfw_insn_bpf) +
+                       sizeof(struct bpf_insn) * (bpf->bf_len - 1)) /
+                       sizeof(uint32_t);
+
+       pcap_freecode(&program);
+       NEXT_ARG1;
+}
+
 void
 show_tcpflag(ipfw_insn *cmd)
 {
 void
 show_tcpflag(ipfw_insn *cmd)
 {
@@ -150,6 +192,14 @@ show_established(ipfw_insn *cmd)
        printf(" established");
 }
 
        printf(" established");
 }
 
+void
+show_bpf(ipfw_insn *cmd, int show_or)
+{
+       ipfw_insn_bpf *bpf;
+       bpf = (ipfw_insn_bpf *)cmd;
+       printf(" bpf \"%s\"", bpf->bf_str);
+}
+
 void
 load_module(register_func function, register_keyword keyword)
 {
 void
 load_module(register_func function, register_keyword keyword)
 {
@@ -165,4 +215,7 @@ load_module(register_func function, register_keyword keyword)
        keyword(MODULE_LAYER4_ID, O_LAYER4_ESTABLISHED, "established", IPFW_KEYWORD_TYPE_FILTER);
        function(MODULE_LAYER4_ID, O_LAYER4_ESTABLISHED,
                        (parser_func)parse_established, (shower_func)show_established);
        keyword(MODULE_LAYER4_ID, O_LAYER4_ESTABLISHED, "established", IPFW_KEYWORD_TYPE_FILTER);
        function(MODULE_LAYER4_ID, O_LAYER4_ESTABLISHED,
                        (parser_func)parse_established, (shower_func)show_established);
+       keyword(MODULE_LAYER4_ID, O_LAYER4_BPF, "bpf", IPFW_KEYWORD_TYPE_FILTER);
+       function(MODULE_LAYER4_ID, O_LAYER4_BPF,
+                       (parser_func)parse_bpf, (shower_func)show_bpf);
 }
 }
index c65d18e..afa114a 100644 (file)
 #define _IP_FW3_H_
 
 #ifdef _KERNEL
 #define _IP_FW3_H_
 
 #ifdef _KERNEL
+#include <net/bpf.h>
 #include <net/netisr2.h>
 
 int     ip_fw3_sockopt(struct sockopt *);
 extern int ip_fw3_loaded;
 
 #include <net/netisr2.h>
 
 int     ip_fw3_sockopt(struct sockopt *);
 extern int ip_fw3_loaded;
 
+#else
+#include <pcap/bpf.h>
+#define PCAP_DONT_INCLUDE_PCAP_BPF_H
 #endif
 
 #define        IPFW3_LOADED    (ip_fw3_loaded)
 #endif
 
 #define        IPFW3_LOADED    (ip_fw3_loaded)
@@ -193,6 +197,15 @@ typedef struct     _ipfw_insn_limit {
        uint16_t conn_limit;
 } ipfw_insn_limit;
 
        uint16_t conn_limit;
 } ipfw_insn_limit;
 
+/*
+ * This is used for bpf filtering.
+ */
+typedef struct _ipfw_insn_bpf {
+       ipfw_insn o;
+       char bf_str[128];
+       u_int bf_len;
+       struct bpf_insn bf_insn[1];
+} ipfw_insn_bpf;
 
 /*
  * Here we have the structure representing an ipfw rule.
 
 /*
  * Here we have the structure representing an ipfw rule.
index 33c8260..2ab94ae 100644 (file)
@@ -58,6 +58,7 @@
 #include <netinet/udp_var.h>
 #include <netinet/if_ether.h>
 
 #include <netinet/udp_var.h>
 #include <netinet/if_ether.h>
 
+#include <net/bpf.h>
 #include <net/ethernet.h>
 #include <net/netmsg2.h>
 #include <net/netisr2.h>
 #include <net/ethernet.h>
 #include <net/netmsg2.h>
 #include <net/netisr2.h>
@@ -79,6 +80,9 @@ check_gid(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
 void
 check_established(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
                struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
 void
 check_established(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
                struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
+void
+check_bpf(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
+               struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
 
 /*
  * ipfw_match_guid can match the gui and uid
 
 /*
  * ipfw_match_guid can match the gui and uid
@@ -181,6 +185,22 @@ void check_established(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
        *cmd_val = IP_FW_NOT_MATCH;
 }
 
        *cmd_val = IP_FW_NOT_MATCH;
 }
 
+void
+check_bpf(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
+               struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
+{
+       u_int slen = 0;
+       struct mbuf *m = (*args)->m;
+       ipfw_insn_bpf *bpf = (ipfw_insn_bpf *)cmd;
+       *cmd_ctl = IP_FW_CTL_NO;
+       slen = bpf_filter(bpf->bf_insn, (u_char *)m, m_lengthm(m, NULL), 0);
+       if (slen != 0)
+               *cmd_val = IP_FW_MATCH;
+       else
+               *cmd_val = IP_FW_NOT_MATCH;
+}
+
+
 static int
 ipfw3_layer4_init(void)
 {
 static int
 ipfw3_layer4_init(void)
 {
@@ -193,6 +213,8 @@ ipfw3_layer4_init(void)
                        (filter_func)check_gid);
        register_ipfw_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_ESTABLISHED,
                        (filter_func)check_established);
                        (filter_func)check_gid);
        register_ipfw_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_ESTABLISHED,
                        (filter_func)check_established);
+       register_ipfw_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_BPF,
+                       (filter_func)check_bpf);
        return 0;
 }
 
        return 0;
 }
 
index bf34087..0a8da49 100644 (file)
@@ -47,6 +47,7 @@ enum ipfw_layer4_opcodes {
        O_LAYER4_UID,
        O_LAYER4_GID,
        O_LAYER4_ESTABLISHED,
        O_LAYER4_UID,
        O_LAYER4_GID,
        O_LAYER4_ESTABLISHED,
+       O_LAYER4_BPF,                   /* bpf syntax filter */
 };
 
 #endif
 };
 
 #endif