#include #include #include #include #include #include #include #include #define SKF_AD_NLATTR 12 #define FILTER_REJECT 0x0000 #define FILTER_ACCEPT 0xFFFF static int sk_set_filter(int fd) { struct sock_filter filt[] = { { /* A=sizeof(struct nlmsghdr)+sizeof(struct nfgenmsg) */ .code = BPF_LD|BPF_IMM, .k = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg), }, { /* X = CTA_PROTOINFO */ .code = BPF_LDX|BPF_IMM, .k = CTA_PROTOINFO, }, { /* A = netlink attribute offset */ .code = BPF_LD|BPF_B|BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR, }, { /* Reject if not found (A == 0) */ .code = BPF_JMP|BPF_JEQ|BPF_K, .k = 0, .jt = 20 - 3 - 1, }, { /* A += sizeof(struct nlattr) */ .code = BPF_ALU|BPF_ADD|BPF_K, .k = sizeof(struct nlattr), }, { /* X = CTA_PROTOINFO_TCP */ .code = BPF_LDX|BPF_IMM, .k = CTA_PROTOINFO_TCP, }, { /* A = netlink attribute offset */ .code = BPF_LD|BPF_B|BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR, }, { /* Reject if not found (A == 0) */ .code = BPF_JMP|BPF_JEQ|BPF_K, .k = 0, .jt = 20 - 7 - 1, }, { /* A += sizeof(struct nlattr) */ .code = BPF_ALU|BPF_ADD|BPF_K, .k = sizeof(struct nlattr), }, { /* X = CTA_PROTOINFO_TCP_STATE */ .code = BPF_LDX|BPF_IMM, .k = CTA_PROTOINFO_TCP_STATE, }, { /* A = netlink attribute offset */ .code = BPF_LD|BPF_B|BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR, }, { /* Reject if not found (A == 0) */ .code = BPF_JMP|BPF_JEQ|BPF_K, .k = 0, .jt = 20 - 11 - 1, }, { /* X = A */ .code = BPF_MISC|BPF_TAX, }, { /* A = skb->data[X + k] */ .code = BPF_LD|BPF_B|BPF_IND, .k = sizeof(struct nlattr), }, { /* Reject if A != TCA_CONNTRACK_ESTABLISHED */ .code = BPF_JMP|BPF_JEQ|BPF_K, .k = TCP_CONNTRACK_ESTABLISHED, .jt = 20 - 14 - 1, }, { /* Reject */ .code = BPF_RET|BPF_K, .k = 0, }, [20] = { /* Accept */ .code = BPF_RET|BPF_K, .k = 0xFFFF, }, }; struct sock_fprog fprog = { .len = sizeof(filt) / sizeof(filt[0]), .filter = filt, }; return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); } #define LABEL_REJECT 29 #define LABEL_ACCEPT 30 struct sock_filter filter[] = { [0] = { /* A = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg) */ .code = BPF_LD|BPF_IMM, .k = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg), }, [1] = { /* X = CTA_PROTOINFO */ .code = BPF_LDX|BPF_IMM, .k = CTA_PROTOINFO, }, [2] = { /* A = netlink attribute offset */ .code = BPF_LD|BPF_B|BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR, }, [3] = { /* Reject if not found (A == 0) */ .code = BPF_JMP|BPF_JEQ|BPF_K, .k = 0, .jt = LABEL_REJECT - 3 - 1, }, [4] = { /* A += sizeof(struct nlattr) */ .code = BPF_ALU|BPF_ADD|BPF_K, .k = sizeof(struct nlattr), }, [5] = { /* X = CTA_PROTOINFO_TCP */ .code = BPF_LDX|BPF_IMM, .k = CTA_PROTOINFO_TCP, }, [6] = { /* A = netlink attribute offset */ .code = BPF_LD|BPF_B|BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR, }, [7] = { /* Reject if not found (A == 0) */ .code = BPF_JMP|BPF_JEQ|BPF_K, .k = 0, .jt = LABEL_REJECT - 7 - 1, }, [8] = { /* A += sizeof(struct nlattr) */ .code = BPF_ALU|BPF_ADD|BPF_K, .k = sizeof(struct nlattr), }, [9] = { /* X = CTA_PROTOINFO_TCP_STATE */ .code = BPF_LDX|BPF_IMM, .k = CTA_PROTOINFO_TCP_STATE, }, [10] = { /* A = netlink attribute offset */ .code = BPF_LD|BPF_B|BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR, }, [11] = { /* Reject if not found (A == 0) */ .code = BPF_JMP|BPF_JEQ|BPF_K, .k = 0, .jt = LABEL_REJECT - 11 - 1, }, [12] = { /* X = A */ .code = BPF_MISC|BPF_TAX, }, [13] = { /* A = skb->data[X + k] */ .code = BPF_LD|BPF_B|BPF_IND, .k = sizeof(struct nlattr), }, #define FILTER_LINE 14 /* * * We add TCP states matching code here * */ [LABEL_REJECT] = { /* Reject */ .code = BPF_RET|BPF_K, .k = FILTER_REJECT, }, [LABEL_ACCEPT] = { /* Accept */ .code = BPF_RET|BPF_K, .k = FILTER_ACCEPT, }, }; static void build_bsf_netlink(int *tcp_state_array, int len) { struct sock_filter reject = { /* Reject */ .code = BPF_RET|BPF_K, .k = 0, }; int i; for (i=0; i