From e895e94d539d4e7184f4823177557af4e3a227dd Mon Sep 17 00:00:00 2001 From: Bill Yuan Date: Wed, 17 Jun 2015 09:35:05 +0800 Subject: [PATCH] ipfw3: support bpf filter in layer4 module syntax: bpf "" 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 | 2 ++ lib/libipfw3/layer4/Makefile | 8 +++-- lib/libipfw3/layer4/ipfw3_layer4.c | 53 ++++++++++++++++++++++++++++ sys/net/ipfw3/ip_fw3.h | 13 +++++++ sys/net/ipfw3_layer4/ip_fw3_layer4.c | 22 ++++++++++++ sys/net/ipfw3_layer4/ip_fw3_layer4.h | 1 + 6 files changed, 96 insertions(+), 3 deletions(-) diff --git a/Makefile.inc1 b/Makefile.inc1 index 19bb3fc67c..6b7f7e7305 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -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/libpcap + _generic_libs= gnu/lib _prebuild_libs+= lib/libcom_err lib/libcrypt lib/libmd \ diff --git a/lib/libipfw3/layer4/Makefile b/lib/libipfw3/layer4/Makefile index 8e0f0b6337..ff9ade7a0b 100644 --- a/lib/libipfw3/layer4/Makefile +++ b/lib/libipfw3/layer4/Makefile @@ -17,13 +17,15 @@ CFLAGS+=-DHAVE_STRUCT_ETHER_ADDR -DHAVE_NET_PFVAR_H CFLAGS+=-DINET6 .endif +LDADD=-lpcap +DPADD=${LIBPCAP} 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 diff --git a/lib/libipfw3/layer4/ipfw3_layer4.c b/lib/libipfw3/layer4/ipfw3_layer4.c index add3a7e137..a6af5c8253 100644 --- a/lib/libipfw3/layer4/ipfw3_layer4.c +++ b/lib/libipfw3/layer4/ipfw3_layer4.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,16 @@ #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[]) @@ -114,6 +125,37 @@ parse_established(ipfw_insn **cmd, int *ac, char **av[]) (*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) { @@ -150,6 +192,14 @@ show_established(ipfw_insn *cmd) 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) { @@ -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_BPF, "bpf", IPFW_KEYWORD_TYPE_FILTER); + function(MODULE_LAYER4_ID, O_LAYER4_BPF, + (parser_func)parse_bpf, (shower_func)show_bpf); } diff --git a/sys/net/ipfw3/ip_fw3.h b/sys/net/ipfw3/ip_fw3.h index c65d18ef1d..afa114a4bf 100644 --- a/sys/net/ipfw3/ip_fw3.h +++ b/sys/net/ipfw3/ip_fw3.h @@ -40,11 +40,15 @@ #define _IP_FW3_H_ #ifdef _KERNEL +#include #include int ip_fw3_sockopt(struct sockopt *); extern int ip_fw3_loaded; +#else +#include +#define PCAP_DONT_INCLUDE_PCAP_BPF_H #endif #define IPFW3_LOADED (ip_fw3_loaded) @@ -193,6 +197,15 @@ typedef struct _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. diff --git a/sys/net/ipfw3_layer4/ip_fw3_layer4.c b/sys/net/ipfw3_layer4/ip_fw3_layer4.c index 33c8260338..2ab94aed99 100644 --- a/sys/net/ipfw3_layer4/ip_fw3_layer4.c +++ b/sys/net/ipfw3_layer4/ip_fw3_layer4.c @@ -58,6 +58,7 @@ #include #include +#include #include #include #include @@ -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_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 @@ -181,6 +185,22 @@ void check_established(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, *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) { @@ -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); + register_ipfw_filter_funcs(MODULE_LAYER4_ID, O_LAYER4_BPF, + (filter_func)check_bpf); return 0; } diff --git a/sys/net/ipfw3_layer4/ip_fw3_layer4.h b/sys/net/ipfw3_layer4/ip_fw3_layer4.h index bf340871ef..0a8da4977f 100644 --- a/sys/net/ipfw3_layer4/ip_fw3_layer4.h +++ b/sys/net/ipfw3_layer4/ip_fw3_layer4.h @@ -47,6 +47,7 @@ enum ipfw_layer4_opcodes { O_LAYER4_UID, O_LAYER4_GID, O_LAYER4_ESTABLISHED, + O_LAYER4_BPF, /* bpf syntax filter */ }; #endif -- 2.41.0