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 int cmd_link_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { int val; int prop; char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *props; struct nlattr *attrs; struct opt *opt; struct opt opts[] = { { "link", OPT_KEYVAL, NULL }, { NULL } }; if (strcmp(cmd->cmd, PRIORITY_STR) == 0) prop = TIPC_NLA_PROP_PRIO; else if ((strcmp(cmd->cmd, TOLERANCE_STR) == 0)) prop = TIPC_NLA_PROP_TOL; else if ((strcmp(cmd->cmd, WINDOW_STR) == 0)) prop = TIPC_NLA_PROP_WIN; else return -EINVAL; if (help_flag) { (cmd->help)(cmdl); return -EINVAL; } if (cmdl->optind >= cmdl->argc) { fprintf(stderr, "error, missing value\n"); return -EINVAL; } val = atoi(shift_cmdl(cmdl)); if (parse_opts(opts, cmdl) < 0) return -EINVAL; nlh = msg_init(buf, TIPC_NL_LINK_SET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } attrs = mnl_attr_nest_start(nlh, TIPC_NLA_LINK); opt = get_opt(opts, "link"); if (!opt) { fprintf(stderr, "error, missing link\n"); return -EINVAL; } mnl_attr_put_strz(nlh, TIPC_NLA_LINK_NAME, opt->val); props = mnl_attr_nest_start(nlh, TIPC_NLA_LINK_PROP); mnl_attr_put_u32(nlh, prop, val); mnl_attr_nest_end(nlh, props); mnl_attr_nest_end(nlh, attrs); return msg_doit(nlh, link_get_cb, &prop); }
static int cmd_link_mon_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { int size; char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *attrs; if (cmdl->argc != cmdl->optind + 1) { fprintf(stderr, "error, missing value\n"); return -EINVAL; } size = atoi(shift_cmdl(cmdl)); nlh = msg_init(buf, TIPC_NL_MON_SET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } attrs = mnl_attr_nest_start(nlh, TIPC_NLA_MON); mnl_attr_put_u32(nlh, TIPC_NLA_MON_ACTIVATION_THRESHOLD, size); mnl_attr_nest_end(nlh, attrs); return msg_doit(nlh, NULL, NULL); }
static int cmd_node_set_netid(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { int netid; char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *nest; if (help_flag) { (cmd->help)(cmdl); return -EINVAL; } if (!(nlh = msg_init(buf, TIPC_NL_NET_SET))) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } if (cmdl->argc != cmdl->optind + 1) { fprintf(stderr, "Usage: %s node set netid NETID\n", cmdl->argv[0]); return -EINVAL; } netid = atoi(shift_cmdl(cmdl)); nest = mnl_attr_nest_start(nlh, TIPC_NLA_NET); mnl_attr_put_u32(nlh, TIPC_NLA_NET_ID, netid); mnl_attr_nest_end(nlh, nest); return msg_doit(nlh, NULL, NULL); }
static int cmd_node_set_addr(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { char *str; uint32_t addr; struct nlattr *nest; char buf[MNL_SOCKET_BUFFER_SIZE]; if (cmdl->argc != cmdl->optind + 1) { fprintf(stderr, "Usage: %s node set address ADDRESS\n", cmdl->argv[0]); return -EINVAL; } str = shift_cmdl(cmdl); addr = str2addr(str); if (!addr) return -1; if (!(nlh = msg_init(buf, TIPC_NL_NET_SET))) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } nest = mnl_attr_nest_start(nlh, TIPC_NLA_NET); mnl_attr_put_u32(nlh, TIPC_NLA_NET_ADDR, addr); mnl_attr_nest_end(nlh, nest); return msg_doit(nlh, NULL, NULL); }
/** * mnl_attr_nest_start_check - start an attribute nest * \param buflen size of buffer which stores the message * \param nlh pointer to the netlink message * \param type netlink attribute type * * This function adds the attribute header that identifies the beginning of * an attribute nest. If the nested attribute cannot be added then NULL, * otherwise valid pointer to the beginning of the nest is returned. */ struct nlattr * mnl_attr_nest_start_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type) { if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen) return NULL; return mnl_attr_nest_start(nlh, type); }
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 int nfct_build_dnat_port(struct nlmsghdr *nlh, const struct nf_conntrack *ct) { struct nlattr *nest; nest = mnl_attr_nest_start(nlh, CTA_NAT_DST); nfct_build_protonat(nlh, ct, &ct->dnat); mnl_attr_nest_end(nlh, nest); return 0; }
static int nfct_build_snat_ipv4(struct nlmsghdr *nlh, const struct nf_conntrack *ct) { struct nlattr *nest; nest = mnl_attr_nest_start(nlh, CTA_NAT_SRC); nfct_build_nat(nlh, &ct->snat); mnl_attr_nest_end(nlh, nest); return 0; }
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_nat_seq_adj(struct nlmsghdr *nlh, const struct nf_conntrack *ct, int dir) { int type = (dir == __DIR_ORIG) ? CTA_NAT_SEQ_ADJ_ORIG : CTA_NAT_SEQ_ADJ_REPLY; struct nlattr *nest; nest = mnl_attr_nest_start(nlh, type); nfct_nat_seq_adj(nlh, ct, dir); mnl_attr_nest_end(nlh, nest); return 0; }
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 int nfct_build_protonat(struct nlmsghdr *nlh, const struct nf_conntrack *ct, const struct __nfct_nat *nat) { struct nlattr *nest; nest = mnl_attr_nest_start(nlh, CTA_NAT_PROTO); switch (ct->head.orig.protonum) { case IPPROTO_TCP: case IPPROTO_UDP: mnl_attr_put_u16(nlh, CTA_PROTONAT_PORT_MIN, nat->l4min.tcp.port); mnl_attr_put_u16(nlh, CTA_PROTONAT_PORT_MAX, nat->l4max.tcp.port); break; } mnl_attr_nest_end(nlh, nest); return 0; }
static int link_mon_peer_list(uint32_t mon_ref) { struct nlmsghdr *nlh; char buf[MNL_SOCKET_BUFFER_SIZE]; struct nlattr *nest; int err = 0; nlh = msg_init(buf, TIPC_NL_MON_PEER_GET); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } nest = mnl_attr_nest_start(nlh, TIPC_NLA_MON); mnl_attr_put_u32(nlh, TIPC_NLA_MON_REF, mon_ref); mnl_attr_nest_end(nlh, nest); err = msg_dumpit(nlh, link_mon_peer_list_cb, NULL); return err; }
int nfct_build_tuple(struct nlmsghdr *nlh, const struct __nfct_tuple *t, int type) { struct nlattr *nest; nest = mnl_attr_nest_start(nlh, type); if (nest == NULL) return -1; if (nfct_build_tuple_ip(nlh, t) < 0) goto err; if (nfct_build_tuple_proto(nlh, t) < 0) goto err; mnl_attr_nest_end(nlh, nest); return 0; err: mnl_attr_nest_cancel(nlh, nest); return -1; }
static int cmd_link_stat_reset(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, void *data) { char *link; char buf[MNL_SOCKET_BUFFER_SIZE]; struct opt *opt; struct nlattr *nest; struct opt opts[] = { { "link", OPT_KEYVAL, NULL }, { NULL } }; if (help_flag) { (cmd->help)(cmdl); return -EINVAL; } if (parse_opts(opts, cmdl) != 1) { (cmd->help)(cmdl); return -EINVAL; } nlh = msg_init(buf, TIPC_NL_LINK_RESET_STATS); if (!nlh) { fprintf(stderr, "error, message initialisation failed\n"); return -1; } opt = get_opt(opts, "link"); if (!opt) { fprintf(stderr, "error, missing link\n"); return -EINVAL; } link = opt->val; nest = mnl_attr_nest_start(nlh, TIPC_NLA_LINK); mnl_attr_put_strz(nlh, TIPC_NLA_LINK_NAME, link); mnl_attr_nest_end(nlh, nest); return msg_doit(nlh, NULL, NULL); }
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 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; }
int main(int argc, char *argv[]){ struct mnl_socket *nl_sock = NULL; struct nlmsghdr *nlh = NULL; struct nlmsgerr *nlerr = NULL; struct nlattr *linkinfo = NULL, *tunnelinfo = NULL; struct ifinfomsg *ifinfo = NULL; uint8_t buf[MNL_SOCKET_BUFFER_SIZE]; size_t numbytes = 0; struct in_addr addr; memset(buf, 0, sizeof(buf)); if((nl_sock = mnl_socket_open(NETLINK_ROUTE)) == NULL){ perror("mnl_socket_open: "); exit(EXIT_FAILURE); } //Add and configure header nlh = mnl_nlmsg_put_header(buf); //Create only if interface does not exists from before (EXCL) nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK; nlh->nlmsg_type = RTM_NEWLINK; //see rtnl_newlink in net/core/rtnetlink.c for observing how this function //works ifinfo = mnl_nlmsg_put_extra_header(nlh, sizeof(struct ifinfomsg)); ifinfo->ifi_family = AF_UNSPEC; //Add a name and mtu, for testing mnl_attr_put_str(nlh, IFLA_IFNAME, "kre2"); mnl_attr_put_u32(nlh, IFLA_MTU, 1234); //Type is required, set to IPIP linkinfo = mnl_attr_nest_start(nlh, IFLA_LINKINFO); mnl_attr_put_str(nlh, IFLA_INFO_KIND, "ipip"); //Add information about the tunnel tunnelinfo = mnl_attr_nest_start(nlh, IFLA_INFO_DATA); inet_pton(AF_INET, "192.168.203.19", &addr); mnl_attr_put_u32(nlh, IFLA_IPTUN_LOCAL, addr.s_addr); inet_pton(AF_INET, "10.0.0.2", &addr); mnl_attr_put_u32(nlh, IFLA_IPTUN_REMOTE, addr.s_addr); mnl_attr_nest_end(nlh, tunnelinfo); mnl_attr_nest_end(nlh, linkinfo); numbytes = mnl_socket_sendto(nl_sock, nlh, nlh->nlmsg_len); numbytes = mnl_socket_recvfrom(nl_sock, buf, sizeof(buf)); nlh = (struct nlmsghdr*) buf; if(nlh->nlmsg_type == NLMSG_ERROR){ nlerr = mnl_nlmsg_get_payload(nlh); //error==0 for ack if(nlerr->error) printf("Error: %s\n", strerror(-nlerr->error)); } else { printf("Link added\n"); } return EXIT_FAILURE; }