/* gcc -o test test.c -lmnl -lnftnl */ #include #include #include #include #include #include #include #include #define __kernel_sa_family_t unsigned short /* old kernel headers */ #include #include #include #include #include #include #include #include #include #include #define SO_ATTACH_NFT_FILTER 49 static void add_meta(struct nft_rule *r) { struct nft_rule_expr *e; e = nft_rule_expr_alloc("meta"); if (e == NULL) { perror("expr payload oom"); exit(EXIT_FAILURE); } nft_rule_expr_set_u32(e, NFT_EXPR_META_DREG, NFT_REG_1); nft_rule_expr_set_u32(e, NFT_EXPR_META_KEY, NFT_META_PROTOCOL); nft_rule_add_expr(r, e); } static void add_cmp_meta(struct nft_rule *r) { struct nft_rule_expr *e; uint16_t data = htons(ETH_P_IP); e = nft_rule_expr_alloc("cmp"); if (e == NULL) { perror("expr cmp oom"); exit(EXIT_FAILURE); } nft_rule_expr_set_u32(e, NFT_EXPR_CMP_SREG, NFT_REG_1); nft_rule_expr_set_u32(e, NFT_EXPR_CMP_OP, NFT_CMP_EQ); nft_rule_expr_set(e, NFT_EXPR_CMP_DATA, &data, sizeof(data)); nft_rule_add_expr(r, e); } static void add_payload(struct nft_rule *r) { struct nft_rule_expr *e; e = nft_rule_expr_alloc("payload"); if (e == NULL) { perror("expr payload oom"); exit(EXIT_FAILURE); } nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_BASE, NFT_PAYLOAD_NETWORK_HEADER); nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_DREG, NFT_REG_1); nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_OFFSET, offsetof(struct iphdr, protocol)); nft_rule_expr_set_u32(e, NFT_EXPR_PAYLOAD_LEN, sizeof(uint8_t)); nft_rule_add_expr(r, e); } static void add_cmp(struct nft_rule *r) { struct nft_rule_expr *e; uint8_t data = IPPROTO_TCP; e = nft_rule_expr_alloc("cmp"); if (e == NULL) { perror("expr cmp oom"); exit(EXIT_FAILURE); } nft_rule_expr_set_u32(e, NFT_EXPR_CMP_SREG, NFT_REG_1); nft_rule_expr_set_u32(e, NFT_EXPR_CMP_OP, NFT_CMP_EQ); nft_rule_expr_set(e, NFT_EXPR_CMP_DATA, &data, sizeof(data)); nft_rule_add_expr(r, e); } static void add_immediate(struct nft_rule *r) { struct nft_rule_expr *e; uint32_t verdict = 0xffffffff; e = nft_rule_expr_alloc("immediate"); if (e == NULL) { perror("expr cmp oom"); exit(EXIT_FAILURE); } nft_rule_expr_set_u32(e, NFT_EXPR_IMM_DREG, NFT_REG_VERDICT); nft_rule_expr_set_u32(e, NFT_EXPR_IMM_VERDICT, verdict); nft_rule_add_expr(r, e); } int main() { int sock; char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlmsghdr *nlh; struct nft_rule *r; struct nft_rule_expr *e; int ret; r = nft_rule_alloc(); if (r == NULL) { perror("nft_rule_alloc"); exit(EXIT_FAILURE); } add_payload(r); add_cmp(r); add_meta(r); add_cmp_meta(r); add_immediate(r); nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE, AF_INET, 0, 1234); nft_rule_nlmsg_build_payload(nlh, r); nft_rule_free(r); mnl_nlmsg_fprintf(stdout, nlh, nlh->nlmsg_len, sizeof(struct nfgenmsg)); sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (sock < 0) { perror("socket"); exit(EXIT_FAILURE); } ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_NFT_FILTER, (char *)nlh + sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg), nlh->nlmsg_len - sizeof(struct nlmsghdr) - sizeof(struct nfgenmsg)); if (ret < 0) { perror("setsockopt"); exit(EXIT_FAILURE); } while (1) { ret = recv(sock, buf, sizeof(buf), 0); if (ret < 0) { perror("recv"); exit(EXIT_FAILURE); } printf("received packet %d bytes\n", ret); } close(sock); }