static void put_msg(char *buf, uint16_t i, int seq) { struct nlmsghdr *nlh; struct nfgenmsg *nfh; struct nlattr *nest1, *nest2; nlh = mnl_nlmsg_put_header(buf); nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW; nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; nlh->nlmsg_seq = seq; nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); nfh->nfgen_family = AF_INET; nfh->version = NFNETLINK_V0; nfh->res_id = 0; nest1 = mnl_attr_nest_start(nlh, CTA_TUPLE_ORIG); nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_IP); mnl_attr_put_u32(nlh, CTA_IP_V4_SRC, inet_addr("1.1.1.1")); mnl_attr_put_u32(nlh, CTA_IP_V4_DST, inet_addr("2.2.2.2")); mnl_attr_nest_end(nlh, nest2); nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_PROTO); mnl_attr_put_u8(nlh, CTA_PROTO_NUM, IPPROTO_TCP); mnl_attr_put_u16(nlh, CTA_PROTO_SRC_PORT, htons(i)); mnl_attr_put_u16(nlh, CTA_PROTO_DST_PORT, htons(1025)); mnl_attr_nest_end(nlh, nest2); mnl_attr_nest_end(nlh, nest1); nest1 = mnl_attr_nest_start(nlh, CTA_TUPLE_REPLY); nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_IP); mnl_attr_put_u32(nlh, CTA_IP_V4_SRC, inet_addr("2.2.2.2")); mnl_attr_put_u32(nlh, CTA_IP_V4_DST, inet_addr("1.1.1.1")); mnl_attr_nest_end(nlh, nest2); nest2 = mnl_attr_nest_start(nlh, CTA_TUPLE_PROTO); mnl_attr_put_u8(nlh, CTA_PROTO_NUM, IPPROTO_TCP); mnl_attr_put_u16(nlh, CTA_PROTO_SRC_PORT, htons(1025)); mnl_attr_put_u16(nlh, CTA_PROTO_DST_PORT, htons(i)); mnl_attr_nest_end(nlh, nest2); mnl_attr_nest_end(nlh, nest1); nest1 = mnl_attr_nest_start(nlh, CTA_PROTOINFO); nest2 = mnl_attr_nest_start(nlh, CTA_PROTOINFO_TCP); mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_STATE, TCP_CONNTRACK_SYN_SENT); mnl_attr_nest_end(nlh, nest2); mnl_attr_nest_end(nlh, nest1); mnl_attr_put_u32(nlh, CTA_STATUS, htonl(IPS_CONFIRMED)); mnl_attr_put_u32(nlh, CTA_TIMEOUT, htonl(1000)); }
static int nfct_build_tuple_proto(struct nlmsghdr *nlh, const struct __nfct_tuple *t) { struct nlattr *nest; nest = mnl_attr_nest_start(nlh, CTA_TUPLE_PROTO); if (nest == NULL) return -1; mnl_attr_put_u8(nlh, CTA_PROTO_NUM, t->protonum); switch(t->protonum) { case IPPROTO_UDP: case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: case IPPROTO_GRE: case IPPROTO_UDPLITE: mnl_attr_put_u16(nlh, CTA_PROTO_SRC_PORT, t->l4src.tcp.port); mnl_attr_put_u16(nlh, CTA_PROTO_DST_PORT, t->l4dst.tcp.port); break; case IPPROTO_ICMP: mnl_attr_put_u8(nlh, CTA_PROTO_ICMP_CODE, t->l4dst.icmp.code); mnl_attr_put_u8(nlh, CTA_PROTO_ICMP_TYPE, t->l4dst.icmp.type); mnl_attr_put_u16(nlh, CTA_PROTO_ICMP_ID, t->l4src.icmp.id); break; case IPPROTO_ICMPV6: mnl_attr_put_u8(nlh, CTA_PROTO_ICMPV6_CODE, t->l4dst.icmp.code); mnl_attr_put_u8(nlh, CTA_PROTO_ICMPV6_TYPE, t->l4dst.icmp.type); mnl_attr_put_u16(nlh, CTA_PROTO_ICMPV6_ID, t->l4src.icmp.id); break; default: mnl_attr_nest_cancel(nlh, nest); return -1; } mnl_attr_nest_end(nlh, nest); return 0; }
static void nft_rule_expr_ct_build(struct nlmsghdr *nlh, struct nft_rule_expr *e) { struct nft_expr_ct *ct = nft_expr_data(e); if (e->flags & (1 << NFT_EXPR_CT_KEY)) mnl_attr_put_u32(nlh, NFTA_CT_KEY, htonl(ct->key)); if (e->flags & (1 << NFT_EXPR_CT_DREG)) mnl_attr_put_u32(nlh, NFTA_CT_DREG, htonl(ct->dreg)); if (e->flags & (1 << NFT_EXPR_CT_DIR)) mnl_attr_put_u8(nlh, NFTA_CT_DIRECTION, ct->dir); if (e->flags & (1 << NFT_EXPR_CT_SREG)) mnl_attr_put_u32(nlh, NFTA_CT_SREG, htonl(ct->sreg)); }
static int nfct_build_protoinfo(struct nlmsghdr *nlh, const struct nf_conntrack *ct) { struct nlattr *nest, *nest_proto; switch(ct->head.orig.protonum) { case IPPROTO_TCP: /* Preliminary attribute check to avoid sending an empty * CTA_PROTOINFO_TCP nest, which results in EINVAL in * Linux kernel <= 2.6.25. */ if (!(test_bit(ATTR_TCP_STATE, ct->head.set) || test_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set) || test_bit(ATTR_TCP_FLAGS_REPL, ct->head.set) || test_bit(ATTR_TCP_MASK_ORIG, ct->head.set) || test_bit(ATTR_TCP_MASK_REPL, ct->head.set) || test_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set) || test_bit(ATTR_TCP_WSCALE_REPL, ct->head.set))) { break; } nest = mnl_attr_nest_start(nlh, CTA_PROTOINFO); nest_proto = mnl_attr_nest_start(nlh, CTA_PROTOINFO_TCP); if (test_bit(ATTR_TCP_STATE, ct->head.set)) { mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_STATE, ct->protoinfo.tcp.state); } if (test_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set) && test_bit(ATTR_TCP_MASK_ORIG, ct->head.set)) { mnl_attr_put(nlh, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL, sizeof(struct nf_ct_tcp_flags), &ct->protoinfo.tcp.flags[0]); } if (test_bit(ATTR_TCP_FLAGS_REPL, ct->head.set) && test_bit(ATTR_TCP_MASK_REPL, ct->head.set)) { mnl_attr_put(nlh, CTA_PROTOINFO_TCP_FLAGS_REPLY, sizeof(struct nf_ct_tcp_flags), &ct->protoinfo.tcp.flags[1]); } if (test_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set)) { mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL, ct->protoinfo.tcp.wscale[__DIR_ORIG]); } if (test_bit(ATTR_TCP_WSCALE_REPL, ct->head.set)) { mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_WSCALE_REPLY, ct->protoinfo.tcp.wscale[__DIR_REPL]); } mnl_attr_nest_end(nlh, nest_proto); mnl_attr_nest_end(nlh, nest); break; case IPPROTO_SCTP: /* See comment above on TCP. */ if (!(test_bit(ATTR_SCTP_STATE, ct->head.set) || test_bit(ATTR_SCTP_VTAG_ORIG, ct->head.set) || test_bit(ATTR_SCTP_VTAG_REPL, ct->head.set))) { break; } nest = mnl_attr_nest_start(nlh, CTA_PROTOINFO); nest_proto = mnl_attr_nest_start(nlh, CTA_PROTOINFO_SCTP); if (test_bit(ATTR_SCTP_STATE, ct->head.set)) { mnl_attr_put_u8(nlh, CTA_PROTOINFO_SCTP_STATE, ct->protoinfo.sctp.state); } if (test_bit(ATTR_SCTP_VTAG_ORIG, ct->head.set)) { mnl_attr_put_u32(nlh, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL, htonl(ct->protoinfo.sctp.vtag[__DIR_ORIG])); } if (test_bit(ATTR_SCTP_VTAG_REPL, ct->head.set)) { mnl_attr_put_u32(nlh, CTA_PROTOINFO_SCTP_VTAG_REPLY, htonl(ct->protoinfo.sctp.vtag[__DIR_REPL])); } mnl_attr_nest_end(nlh, nest_proto); mnl_attr_nest_end(nlh, nest); break; case IPPROTO_DCCP: /* See comment above on TCP. */ if (!(test_bit(ATTR_DCCP_STATE, ct->head.set) || test_bit(ATTR_DCCP_ROLE, ct->head.set) || test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set))) { break; } nest = mnl_attr_nest_start(nlh, CTA_PROTOINFO); nest_proto = mnl_attr_nest_start(nlh, CTA_PROTOINFO_DCCP); if (test_bit(ATTR_DCCP_STATE, ct->head.set)) { mnl_attr_put_u8(nlh, CTA_PROTOINFO_DCCP_STATE, ct->protoinfo.dccp.state); } if (test_bit(ATTR_DCCP_ROLE, ct->head.set)) { mnl_attr_put_u8(nlh, CTA_PROTOINFO_DCCP_ROLE, ct->protoinfo.dccp.role); } if (test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set)) { uint64_t handshake_seq = be64toh(ct->protoinfo.dccp.handshake_seq); mnl_attr_put_u64(nlh, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ, handshake_seq); } mnl_attr_nest_end(nlh, nest_proto); mnl_attr_nest_end(nlh, nest); default: break; } return 0; }