static int nfct_build_tuple_ip(struct nlmsghdr *nlh, const struct __nfct_tuple *t) { struct nlattr *nest; nest = mnl_attr_nest_start(nlh, CTA_TUPLE_IP); if (nest == NULL) return -1; switch(t->l3protonum) { case AF_INET: mnl_attr_put_u32(nlh, CTA_IP_V4_SRC, t->src.v4); mnl_attr_put_u32(nlh, CTA_IP_V4_DST, t->dst.v4); break; case AF_INET6: mnl_attr_put(nlh, CTA_IP_V6_SRC, sizeof(struct in6_addr), &t->src.v6); mnl_attr_put(nlh, CTA_IP_V6_DST, sizeof(struct in6_addr), &t->dst.v6); break; default: mnl_attr_nest_cancel(nlh, nest); return -1; } mnl_attr_nest_end(nlh, nest); return 0; }
static void nft_rule_expr_bitwise_build(struct nlmsghdr *nlh, struct nft_rule_expr *e) { struct nft_expr_bitwise *bitwise = nft_expr_data(e); if (e->flags & (1 << NFT_EXPR_BITWISE_SREG)) mnl_attr_put_u32(nlh, NFTA_BITWISE_SREG, htonl(bitwise->sreg)); if (e->flags & (1 << NFT_EXPR_BITWISE_DREG)) mnl_attr_put_u32(nlh, NFTA_BITWISE_DREG, htonl(bitwise->dreg)); if (e->flags & (1 << NFT_EXPR_BITWISE_LEN)) mnl_attr_put_u32(nlh, NFTA_BITWISE_LEN, htonl(bitwise->len)); if (e->flags & (1 << NFT_EXPR_BITWISE_MASK)) { struct nlattr *nest; nest = mnl_attr_nest_start(nlh, NFTA_BITWISE_MASK); mnl_attr_put(nlh, NFTA_DATA_VALUE, bitwise->mask.len, bitwise->mask.val); mnl_attr_nest_end(nlh, nest); } if (e->flags & (1 << NFT_EXPR_BITWISE_XOR)) { struct nlattr *nest; nest = mnl_attr_nest_start(nlh, NFTA_BITWISE_XOR); mnl_attr_put(nlh, NFTA_DATA_VALUE, bitwise->xor.len, bitwise->xor.val); mnl_attr_nest_end(nlh, nest); } }
static void nfct_build_labels(struct nlmsghdr *nlh, const struct nf_conntrack *ct) { struct nfct_bitmask *b = ct->connlabels; unsigned int size = b->words * sizeof(b->bits[0]); mnl_attr_put(nlh, CTA_LABELS, size, b->bits); if (test_bit(ATTR_CONNLABELS_MASK, ct->head.set)) { b = ct->connlabels_mask; if (size == (b->words * sizeof(b->bits[0]))) mnl_attr_put(nlh, CTA_LABELS_MASK, size, b->bits); } }
void nfq_nlmsg_cfg_put_params(struct nlmsghdr *nlh, uint8_t mode, int range) { struct nfqnl_msg_config_params params = { .copy_range = htonl(range), .copy_mode = mode, }; mnl_attr_put(nlh, NFQA_CFG_PARAMS, sizeof(params), ¶ms); }
/** * nfq_nlmsg_cfg_build_request- build netlink config message * \param buf Buffer where netlink message is going to be written. * \param cfg Structure that contains the config parameters. * \param command nfqueue nfnetlink command. * * This function returns a pointer to the netlink message. If something goes * wrong it returns NULL. * * Possible commands are: * * - NFQNL_CFG_CMD_NONE: Do nothing. It can be useful to know if the queue * subsystem is working. * - NFQNL_CFG_CMD_BIND: Binds the program to a specific queue. * - NFQNL_CFG_CMD_UNBIND: Unbinds the program to a specifiq queue. * - NFQNL_CFG_CMD_PF_BIND: Binds to process packets belonging to the given * protocol family (ie. PF_INET, PF_INET6, etc). * - NFQNL_CFG_CMD_PF_UNBIND: Unbinds from processing packets belonging to the * given protocol family. */ void nfq_nlmsg_cfg_put_cmd(struct nlmsghdr *nlh, uint16_t pf, uint8_t cmd) { struct nfqnl_msg_config_cmd command = { .command = cmd, .pf = htons(pf), }; mnl_attr_put(nlh, NFQA_CFG_CMD, sizeof(command), &command); }
void nfq_nlmsg_verdict_put(struct nlmsghdr *nlh, int id, int verdict) { struct nfqnl_msg_verdict_hdr vh = { .verdict = htonl(verdict), .id = htonl(id), }; mnl_attr_put(nlh, NFQA_VERDICT_HDR, sizeof(vh), &vh); }
/** * mnl_attr_put_check - add an attribute to netlink message * \param nlh pointer to the netlink message * \param buflen size of buffer which stores the message * \param type netlink attribute type that you want to add * \param len netlink attribute payload length * \param data pointer to the data that will be stored by the new attribute * * This function first checks that the data can be added to the message * (fits into the buffer) and then updates the length field of the Netlink * message (nlmsg_len) by adding the size (header + payload) of the new * attribute. The function returns true if the attribute could be added * to the message, otherwise false is returned. */ bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, size_t len, const void *data) { if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen) return false; mnl_attr_put(nlh, type, len, data); return true; }
/** * nflog_attr_put_cfg_cmd - add a cmd attribute to nflog netlink message * \param nlh pointer to the netlink message * \param cmd command one of the enum nfulnl_msg_config_cmds * * this function returns -1 and errno is explicitly set on error. * On success, this function returns 1. */ int nflog_attr_put_cfg_cmd(struct nlmsghdr *nlh, uint8_t cmd) { struct nfulnl_msg_config_cmd nfcmd = { .command = cmd }; mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(nfcmd), &nfcmd); /* it may returns -1 in future */ return 0; }
/** * nflog_attr_put_cfg_mode - add a mode attribute to nflog netlink message * \param nlh pointer to the netlink message * \param mode copy mode defined in linux/netfilter/nfnetlink_log.h * \param range copy range * * this function returns -1 and errno is explicitly set on error. * On success, this function returns 1. */ int nflog_attr_put_cfg_mode(struct nlmsghdr *nlh, uint8_t mode, uint32_t range) { struct nfulnl_msg_config_mode nfmode = { .copy_mode = mode, .copy_range = htonl(range) }; mnl_attr_put(nlh, NFULA_CFG_MODE, sizeof(nfmode), &nfmode); /* it may returns -1 in future */ return 0; }
static void nftnl_expr_target_build(struct nlmsghdr *nlh, const struct nftnl_expr *e) { struct nftnl_expr_target *tg = nftnl_expr_data(e); if (e->flags & (1 << NFTNL_EXPR_TG_NAME)) mnl_attr_put_strz(nlh, NFTA_TARGET_NAME, tg->name); if (e->flags & (1 << NFTNL_EXPR_TG_REV)) mnl_attr_put_u32(nlh, NFTA_TARGET_REV, htonl(tg->rev)); if (e->flags & (1 << NFTNL_EXPR_TG_INFO)) mnl_attr_put(nlh, NFTA_TARGET_INFO, tg->data_len, tg->data); }
static void nft_rule_expr_match_build(struct nlmsghdr *nlh, struct nft_rule_expr *e) { struct nft_expr_match *mt = nft_expr_data(e); if (e->flags & (1 << NFT_EXPR_MT_NAME)) mnl_attr_put_strz(nlh, NFTA_MATCH_NAME, mt->name); if (e->flags & (1 << NFT_EXPR_MT_REV)) mnl_attr_put_u32(nlh, NFTA_MATCH_REV, htonl(mt->rev)); if (e->flags & (1 << NFT_EXPR_MT_INFO)) mnl_attr_put(nlh, NFTA_MATCH_INFO, mt->data_len, mt->data); }
static int nfct_build_helper_name(struct nlmsghdr *nlh, const struct nf_conntrack *ct) { struct nlattr *nest; nest = mnl_attr_nest_start(nlh, CTA_HELP); mnl_attr_put_strz(nlh, CTA_HELP_NAME, ct->helper_name); if (ct->helper_info != NULL) { mnl_attr_put(nlh, CTA_HELP_INFO, ct->helper_info_len, ct->helper_info); } mnl_attr_nest_end(nlh, nest); return 0; }
static struct nlmsghdr * nflog_build_cfg_pf_request(char *buf, uint8_t command) { struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); nlh->nlmsg_type = (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG; nlh->nlmsg_flags = NLM_F_REQUEST; struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); nfg->nfgen_family = AF_INET; nfg->version = NFNETLINK_V0; struct nfulnl_msg_config_cmd cmd = { .command = command, }; mnl_attr_put(nlh, NFULA_CFG_CMD, sizeof(cmd), &cmd); return nlh; }
static struct nlmsghdr * nfq_build_cfg_request(char *buf, uint8_t command, int queue_num) { struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG; nlh->nlmsg_flags = NLM_F_REQUEST; struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); nfg->nfgen_family = AF_UNSPEC; nfg->version = NFNETLINK_V0; nfg->res_id = htons(queue_num); struct nfqnl_msg_config_cmd cmd = { .command = command, .pf = htons(AF_INET), }; mnl_attr_put(nlh, NFQA_CFG_CMD, sizeof(cmd), &cmd); return nlh; }
static struct nlmsghdr * nfq_build_cfg_params(char *buf, uint8_t mode, int range, int queue_num) { struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG; nlh->nlmsg_flags = NLM_F_REQUEST; struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); nfg->nfgen_family = AF_UNSPEC; nfg->version = NFNETLINK_V0; nfg->res_id = htons(queue_num); struct nfqnl_msg_config_params params = { .copy_range = htonl(range), .copy_mode = mode, }; mnl_attr_put(nlh, NFQA_CFG_PARAMS, sizeof(params), ¶ms); return nlh; }
static struct nlmsghdr * nfq_build_verdict(char *buf, int id, int queue_num, int verd) { struct nlmsghdr *nlh; struct nfgenmsg *nfg; nlh = mnl_nlmsg_put_header(buf); nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_VERDICT; nlh->nlmsg_flags = NLM_F_REQUEST; nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg)); nfg->nfgen_family = AF_UNSPEC; nfg->version = NFNETLINK_V0; nfg->res_id = htons(queue_num); struct nfqnl_msg_verdict_hdr vh = { .verdict = htonl(verd), .id = htonl(id), }; mnl_attr_put(nlh, NFQA_VERDICT_HDR, sizeof(vh), &vh); return nlh; }
/** * mnl_attr_put_u32 - add 32-bit unsigned integer attribute to netlink message * \param nlh pointer to the netlink message * \param type netlink attribute type * \param data 32-bit unsigned integer data that is stored by the new attribute * * This function updates the length field of the Netlink message (nlmsg_len) * by adding the size (header + payload) of the new attribute. */ EXPORT_SYMBOL void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32_t data) { mnl_attr_put(nlh, type, sizeof(uint32_t), &data); }
static struct nlmsghdr *pack_nlmsg(void *buf, int len, const char *format, va_list ap) { struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); void *p; char *s; size_t slen; int remains; while (*format != '\0') { remains = len - (int)nlh->nlmsg_len - MY_ATTR_ALIGN(sizeof(struct nlattr)); switch (*format) { case 'B': /* byte */ if (MY_ATTR_ALIGN(sizeof(uint8_t)) > remains) { errno = EOVERFLOW; return NULL; } /* gcc warning: 'uint8_t' is promoted * to 'int' when passed through '...' */ mnl_attr_put_u8(nlh, MNL_TYPE_U8, (uint8_t)va_arg(ap, int)); break; case 'H': /* 2byte */ if (MY_ATTR_ALIGN(sizeof(uint16_t)) > remains) { errno = EOVERFLOW; return NULL; } /* gcc warning: 'uint16_t' is promoted * to 'int' when passed through '...' */ mnl_attr_put_u16(nlh, MNL_TYPE_U16, (uint16_t)va_arg(ap, int)); break; case 'I': /* 4byte */ if (MY_ATTR_ALIGN(sizeof(uint32_t)) > remains) { errno = EOVERFLOW; return NULL; } mnl_attr_put_u32(nlh, MNL_TYPE_U32, va_arg(ap, uint32_t)); break; case 'K': /* 8byte */ if (MY_ATTR_ALIGN(sizeof(uint64_t)) > remains) { errno = EOVERFLOW; return NULL; } mnl_attr_put_u64(nlh, MNL_TYPE_U64, va_arg(ap, uint64_t)); break; case 'p': /* pointer */ if (MY_ATTR_ALIGN(sizeof(void *)) > remains) { errno = EOVERFLOW; return NULL; } p = va_arg(ap, void *); mnl_attr_put(nlh, MNL_TYPE_BINARY, sizeof(void *), &p); break; case 'z': /* null string */ s = va_arg(ap, char *); slen = strlen(s); if (MY_ATTR_ALIGN(slen + 1) > remains) { errno = EOVERFLOW; return NULL; } mnl_attr_put(nlh, MNL_TYPE_NUL_STRING, slen + 1, s); break; case 'y': /* bytes with size */ format++; if (*format != '#') { errno = EINVAL; return NULL; } p = va_arg(ap, void *); slen = va_arg(ap, size_t); if (MY_ATTR_ALIGN(slen) > remains) { errno = EOVERFLOW; return NULL; } mnl_attr_put(nlh, MNL_TYPE_STRING, slen, p); break; default: errno = EINVAL; return NULL; } format++; } return nlh; }
/** * mnl_attr_put_str - add string attribute to netlink message * \param nlh pointer to the netlink message * \param type netlink attribute type * \param data pointer to string data that is stored by the new attribute * * This function updates the length field of the Netlink message (nlmsg_len) * by adding the size (header + payload) of the new attribute. */ EXPORT_SYMBOL void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type, const char *data) { mnl_attr_put(nlh, type, strlen(data), data); }
void nfq_nlmsg_verdict_put_pkt(struct nlmsghdr *nlh, const void *pkt, uint32_t plen) { mnl_attr_put(nlh, NFQA_PAYLOAD, plen, pkt); }
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; }
/** * mnl_attr_put_u64 - add 64-bit unsigned integer attribute to netlink message * \param nlh pointer to the netlink message * \param type netlink attribute type * \param data 64-bit unsigned integer data that is stored by the new attribute * * This function updates the length field of the Netlink message (nlmsg_len) * by adding the size (header + payload) of the new attribute. */ void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type, uint64_t data) { mnl_attr_put(nlh, type, sizeof(uint64_t), &data); }
/** * mnl_attr_put_strz - add string attribute to netlink message * \param nlh pointer to the netlink message * \param type netlink attribute type * \param data pointer to string data that is stored by the new attribute * * This function is similar to mnl_attr_put_str, but it includes the * NUL/zero ('\0') terminator at the end of the string. * * This function updates the length field of the Netlink message (nlmsg_len) * by adding the size (header + payload) of the new attribute. */ void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, const char *data) { mnl_attr_put(nlh, type, strlen(data)+1, data); }