static int link_stat_show_cb(const struct nlmsghdr *nlh, void *data) { const char *name; const char *link = data; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); struct nlattr *info[TIPC_NLA_MAX + 1] = {}; struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1] = {}; struct nlattr *prop[TIPC_NLA_PROP_MAX + 1] = {}; struct nlattr *stats[TIPC_NLA_STATS_MAX + 1] = {}; mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); if (!info[TIPC_NLA_LINK]) return MNL_CB_ERROR; mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs); if (!attrs[TIPC_NLA_LINK_NAME] || !attrs[TIPC_NLA_LINK_PROP] || !attrs[TIPC_NLA_LINK_STATS]) return MNL_CB_ERROR; mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_PROP], parse_attrs, prop); mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_STATS], parse_attrs, stats); name = mnl_attr_get_str(attrs[TIPC_NLA_LINK_NAME]); /* If a link is passed, skip all but that link */ if (link && (strcmp(name, link) != 0)) return MNL_CB_OK; if (attrs[TIPC_NLA_LINK_BROADCAST]) { return _show_bc_link_stat(name, prop, stats); } return _show_link_stat(name, attrs, prop, stats); }
int nfct_nlmsg_parse(const struct nlmsghdr *nlh, struct nf_conntrack *ct) { struct nfgenmsg *nfhdr = mnl_nlmsg_get_payload(nlh); return nfct_payload_parse((uint8_t *)nfhdr + sizeof(struct nfgenmsg), nlh->nlmsg_len, nfhdr->nfgen_family, ct); }
static int data_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[CTA_MAX+1] = {}; struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); mnl_attr_parse(nlh, sizeof(*nfg), data_attr_cb, tb); if (tb[CTA_TUPLE_ORIG]) print_tuple(tb[CTA_TUPLE_ORIG]); if (tb[CTA_MARK]) printf("mark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_MARK]))); if (tb[CTA_SECMARK]) printf("secmark=%u ", ntohl(mnl_attr_get_u32(tb[CTA_SECMARK]))); if (tb[CTA_COUNTERS_ORIG]) { printf("original "); print_counters(tb[CTA_COUNTERS_ORIG]); } if (tb[CTA_COUNTERS_REPLY]) { printf("reply "); print_counters(tb[CTA_COUNTERS_REPLY]); } printf("\n"); return MNL_CB_OK; }
static int node_list_cb(const struct nlmsghdr *nlh, void *data) { uint32_t addr; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); struct nlattr *info[TIPC_NLA_MAX + 1] = {}; struct nlattr *attrs[TIPC_NLA_NODE_MAX + 1] = {}; mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); if (!info[TIPC_NLA_NODE]) return MNL_CB_ERROR; mnl_attr_parse_nested(info[TIPC_NLA_NODE], parse_attrs, attrs); if (!attrs[TIPC_NLA_NODE_ADDR]) return MNL_CB_ERROR; addr = mnl_attr_get_u32(attrs[TIPC_NLA_NODE_ADDR]); printf("<%u.%u.%u>: ", tipc_zone(addr), tipc_cluster(addr), tipc_node(addr)); if (attrs[TIPC_NLA_NODE_UP]) printf("up\n"); else printf("down\n"); return MNL_CB_OK; }
static int link_mon_summary_cb(const struct nlmsghdr *nlh, void *data) { struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); struct nlattr *info[TIPC_NLA_MAX + 1] = {}; struct nlattr *attrs[TIPC_NLA_MON_MAX + 1] = {}; mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); if (!info[TIPC_NLA_MON]) return MNL_CB_ERROR; mnl_attr_parse_nested(info[TIPC_NLA_MON], parse_attrs, attrs); open_json_object(NULL); print_string(PRINT_ANY, "bearer", "\nbearer %s\n", mnl_attr_get_str(attrs[TIPC_NLA_MON_BEARER_NAME])); print_uint(PRINT_ANY, "table_generation", " table_generation %u\n", mnl_attr_get_u32(attrs[TIPC_NLA_MON_LISTGEN])); print_uint(PRINT_ANY, "cluster_size", " cluster_size %u\n", mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEERCNT])); print_string(PRINT_ANY, "algorithm", " algorithm %s\n", attrs[TIPC_NLA_MON_ACTIVE] ? "overlapping-ring" : "full-mesh"); close_json_object(); return MNL_CB_OK; }
static int link_mon_list_cb(const struct nlmsghdr *nlh, void *data) { struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); struct nlattr *info[TIPC_NLA_MAX + 1] = {}; struct nlattr *attrs[TIPC_NLA_MON_MAX + 1] = {}; char *req_bearer = data; const char *bname; const char title[] = "node status monitored generation applied_node_status [non_applied_node:status]"; mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); if (!info[TIPC_NLA_MON]) return MNL_CB_ERROR; mnl_attr_parse_nested(info[TIPC_NLA_MON], parse_attrs, attrs); bname = mnl_attr_get_str(attrs[TIPC_NLA_MON_BEARER_NAME]); if (*req_bearer && (strcmp(req_bearer, bname) != 0)) return MNL_CB_OK; open_json_object(NULL); print_string(PRINT_ANY, "bearer", "\nbearer %s\n", bname); print_string(PRINT_FP, NULL, "%s\n", title); open_json_array(PRINT_JSON, bname); if (mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEERCNT])) link_mon_peer_list(mnl_attr_get_u32(attrs[TIPC_NLA_MON_REF])); close_json_array(PRINT_JSON, bname); close_json_object(); return MNL_CB_OK; }
//Function which parses the netlink message (*ADDR) we have received and extract //relevant information, which is parsed to OS-independent //neat_addr_update_src_list static void neat_linux_handle_addr(struct neat_ctx *nc, struct nlmsghdr *nl_hdr) { struct ifaddrmsg *ifm = (struct ifaddrmsg*) mnl_nlmsg_get_payload(nl_hdr); const struct nlattr *attr_table[IFA_MAX+1]; //IFA_MAX is the largest index I can store in my array. Since arrays are //zero-indexed, this is IFA_MAX and not IFA_MAX + 1. However, array has to //be of size IFA_MAX + 1. DOH! struct nlattr_storage tb_storage = {attr_table, IFA_MAX}; struct sockaddr_storage src_addr; struct sockaddr_in *src_addr4; struct sockaddr_in6 *src_addr6; struct ifa_cacheinfo *ci; uint32_t *addr6_ptr, ifa_pref = 0, ifa_valid = 0; uint8_t i; //On Linux, lo has a fixed index. We have no interest in that interface //TODO: Consider other filters - bridges, ifb, ... if (ifm->ifa_index == LO_DEV_IDX) return; if (ifm->ifa_scope == RT_SCOPE_LINK) return; memset(attr_table, 0, sizeof(attr_table)); memset(&src_addr, 0, sizeof(src_addr)); if (mnl_attr_parse(nl_hdr, sizeof(struct ifaddrmsg), neat_linux_parse_nlattr, &tb_storage) != MNL_CB_OK) { fprintf(stderr, "Failed to parse nlattr for msg of type %d\n", nl_hdr->nlmsg_type); return; } //v4 and v6 has to be handled differently, both due to address size and //available information if (ifm->ifa_family == AF_INET) { src_addr4 = (struct sockaddr_in*) &src_addr; src_addr4->sin_family = AF_INET; src_addr4->sin_addr.s_addr = mnl_attr_get_u32(attr_table[IFA_LOCAL]); } else { src_addr6 = (struct sockaddr_in6*) &src_addr; src_addr6->sin6_family = AF_INET6; addr6_ptr = (uint32_t*) mnl_attr_get_payload(attr_table[IFA_ADDRESS]); for (i=0; i<4; i++) src_addr6->sin6_addr.s6_addr32[i] = *(addr6_ptr + i); ci = (struct ifa_cacheinfo*) mnl_attr_get_payload(attr_table[IFA_CACHEINFO]); ifa_pref = ci->ifa_prefered; ifa_valid = ci->ifa_valid; } //TODO: Should this function be a callback instead? Will we have multiple //addresses handlers/types of context? neat_addr_update_src_list(nc, &src_addr, ifm->ifa_index, nl_hdr->nlmsg_type == RTM_NEWADDR, ifa_pref, ifa_valid); }
static int data_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr **tb = (struct nlattr **)data; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); mnl_attr_parse(nlh, sizeof(*genl), parse_attr_cb, tb); return MNL_CB_OK; }
static int link_mon_peer_list_cb(const struct nlmsghdr *nlh, void *data) { struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); struct nlattr *attrs[TIPC_NLA_MON_PEER_MAX + 1] = {}; struct nlattr *info[TIPC_NLA_MAX + 1] = {}; uint16_t member_cnt; uint32_t applied; uint32_t dom_gen; uint64_t up_map; char status[16]; char monitored[16]; mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); if (!info[TIPC_NLA_MON_PEER]) return MNL_CB_ERROR; open_json_object(NULL); mnl_attr_parse_nested(info[TIPC_NLA_MON_PEER], parse_attrs, attrs); (attrs[TIPC_NLA_MON_PEER_LOCAL] || attrs[TIPC_NLA_MON_PEER_HEAD]) ? strcpy(monitored, "direct") : strcpy(monitored, "indirect"); attrs[TIPC_NLA_MON_PEER_UP] ? strcpy(status, "up") : strcpy(status, "down"); dom_gen = attrs[TIPC_NLA_MON_PEER_DOMGEN] ? mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_DOMGEN]) : 0; link_mon_print_peer_state(mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_ADDR]), status, monitored, dom_gen); applied = mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_APPLIED]); if (!applied) goto exit; up_map = mnl_attr_get_u64(attrs[TIPC_NLA_MON_PEER_UPMAP]); member_cnt = mnl_attr_get_payload_len(attrs[TIPC_NLA_MON_PEER_MEMBERS]); /* each tipc address occupies 4 bytes of payload, hence compensate it */ member_cnt /= sizeof(uint32_t); link_mon_print_applied(applied, up_map); link_mon_print_non_applied(applied, member_cnt, up_map, mnl_attr_get_payload(attrs[TIPC_NLA_MON_PEER_MEMBERS])); exit: print_string(PRINT_FP, NULL, "\n", ""); close_json_object(); return MNL_CB_OK; }
int nfexp_nlmsg_parse(const struct nlmsghdr *nlh, struct nf_expect *exp) { struct nlattr *tb[CTA_EXPECT_MAX+1] = {}; struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); mnl_attr_parse(nlh, sizeof(struct nfgenmsg), nlmsg_parse_expection_attr_cb, tb); if (tb[CTA_EXPECT_MASTER]) { exp->expected.orig.l3protonum = nfg->nfgen_family; set_bit(ATTR_ORIG_L3PROTO, exp->expected.set); nfct_parse_tuple(tb[CTA_EXPECT_MASTER], &exp->master.orig, __DIR_ORIG, exp->master.set); set_bit(ATTR_EXP_MASTER, exp->set); } if (tb[CTA_EXPECT_TUPLE]) { exp->mask.orig.l3protonum = nfg->nfgen_family; set_bit(ATTR_ORIG_L3PROTO, exp->mask.set); nfct_parse_tuple(tb[CTA_EXPECT_TUPLE], &exp->expected.orig, __DIR_ORIG, exp->expected.set); set_bit(ATTR_EXP_EXPECTED, exp->set); } if (tb[CTA_EXPECT_MASK]) { exp->master.orig.l3protonum = nfg->nfgen_family; set_bit(ATTR_ORIG_L3PROTO, exp->master.set); nfct_parse_tuple(tb[CTA_EXPECT_MASK], &exp->mask.orig, __DIR_ORIG, exp->mask.set); set_bit(ATTR_EXP_MASK, exp->set); } if (tb[CTA_EXPECT_TIMEOUT]) { exp->timeout = ntohl(mnl_attr_get_u32(tb[CTA_EXPECT_TIMEOUT])); set_bit(ATTR_EXP_TIMEOUT, exp->set); } if (tb[CTA_EXPECT_ZONE]) { exp->zone = ntohs(mnl_attr_get_u16(tb[CTA_EXPECT_ZONE])); set_bit(ATTR_EXP_ZONE, exp->set); } if (tb[CTA_EXPECT_FLAGS]) { exp->flags = ntohl(mnl_attr_get_u32(tb[CTA_EXPECT_FLAGS])); set_bit(ATTR_EXP_FLAGS, exp->set); } if (tb[CTA_EXPECT_HELP_NAME]) { strncpy(exp->helper_name, mnl_attr_get_str(tb[CTA_EXPECT_HELP_NAME]), NFCT_HELPER_NAME_MAX); set_bit(ATTR_EXP_HELPER_NAME, exp->set); } return 0; }
static int cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[NLE_MAX]; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); mnl_attr_parse(nlh, sizeof(*genl), data_attr_cb, tb); if (tb[NLE_MYVAR]) printf("myvar=%d\n", mnl_attr_get_u32(tb[NLE_MYVAR])); return MNL_CB_OK; }
static int get_group_id_cb(const struct nlmsghdr *nlh, void *data) { struct group_info *group_info = data; struct nlattr *tb[CTRL_ATTR_MAX + 1] = {}; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); mnl_attr_parse(nlh, sizeof(*genl), get_group_id_attr_cb, tb); if (!tb[CTRL_ATTR_MCAST_GROUPS]) return MNL_CB_ERROR; parse_genl_mc_grps(tb[CTRL_ATTR_MCAST_GROUPS], group_info); return MNL_CB_OK; }
static int get_family_id_cb(const struct nlmsghdr *nlh, void *data) { uint32_t *p_id = data; struct nlattr *tb[CTRL_ATTR_MAX + 1] = {}; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); mnl_attr_parse(nlh, sizeof(*genl), get_family_id_attr_cb, tb); if (!tb[CTRL_ATTR_FAMILY_ID]) return MNL_CB_ERROR; *p_id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]); return MNL_CB_OK; }
int nftnl_gen_nlmsg_parse(const struct nlmsghdr *nlh, struct nftnl_gen *gen) { struct nlattr *tb[NFTA_GEN_MAX + 1] = {}; struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); if (mnl_attr_parse(nlh, sizeof(*nfg), nftnl_gen_parse_attr_cb, tb) < 0) return -1; if (tb[NFTA_GEN_ID]) { gen->id = ntohl(mnl_attr_get_u32(tb[NFTA_GEN_ID])); gen->flags |= (1 << NFTNL_GEN_ID); } return 0; }
static int genl_ctrl_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[CTRL_ATTR_MAX + 1] = {}; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); int32_t *genl_id = data; mnl_attr_parse(nlh, sizeof(*genl), genl_ctrl_validate_cb, tb); if (tb[CTRL_ATTR_FAMILY_ID]) *genl_id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]); else *genl_id = -1; return MNL_CB_OK; }
//Function which parses the netlink message (*ADDR) we have received and extract //relevant information, which is parsed to OS-independent //neat_addr_update_src_list static neat_error_code nt_linux_handle_addr(struct neat_ctx *ctx, struct nlmsghdr *nl_hdr) { struct ifaddrmsg *ifm = (struct ifaddrmsg*) mnl_nlmsg_get_payload(nl_hdr); const struct nlattr *attr_table[IFA_MAX+1]; //IFA_MAX is the largest index I can store in my array. Since arrays are //zero-indexed, this is IFA_MAX and not IFA_MAX + 1. However, array has to //be of size IFA_MAX + 1. DOH! struct nlattr_storage tb_storage = {attr_table, IFA_MAX}; struct sockaddr_storage src_addr; struct sockaddr_in *src_addr4; struct sockaddr_in6 *src_addr6; struct ifa_cacheinfo *ci; uint32_t ifa_pref = 0, ifa_valid = 0; if (ifm->ifa_scope == RT_SCOPE_LINK) return NEAT_ERROR_OK; memset(attr_table, 0, sizeof(attr_table)); memset(&src_addr, 0, sizeof(src_addr)); if (mnl_attr_parse(nl_hdr, sizeof(struct ifaddrmsg), neat_linux_parse_nlattr, &tb_storage) != MNL_CB_OK) { nt_log(ctx, NEAT_LOG_ERROR, "Failed to parse nlattr for msg of type %d", __func__, nl_hdr->nlmsg_type); return NEAT_ERROR_OK; } //v4 and v6 has to be handled differently, both due to address size and //available information if (ifm->ifa_family == AF_INET) { src_addr4 = (struct sockaddr_in*) &src_addr; src_addr4->sin_family = AF_INET; src_addr4->sin_addr.s_addr = mnl_attr_get_u32(attr_table[IFA_LOCAL]); } else { src_addr6 = (struct sockaddr_in6*) &src_addr; src_addr6->sin6_family = AF_INET6; memcpy(&src_addr6->sin6_addr, mnl_attr_get_payload(attr_table[IFA_ADDRESS]), sizeof(struct in6_addr)); ci = (struct ifa_cacheinfo*) mnl_attr_get_payload(attr_table[IFA_CACHEINFO]); ifa_pref = ci->ifa_prefered; ifa_valid = ci->ifa_valid; } //TODO: Should this function be a callback instead? Will we have multiple //addresses handlers/types of context? return nt_addr_update_src_list(ctx, (struct sockaddr*) &src_addr, ifm->ifa_index, nl_hdr->nlmsg_type == RTM_NEWADDR, ifm->ifa_prefixlen, ifa_pref, ifa_valid); }
static int mnlg_cb_error(const struct nlmsghdr *nlh, void *data) { const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); /* Netlink subsystems returns the errno value with different signess */ if (err->error < 0) errno = -err->error; else errno = err->error; if (nl_dump_ext_ack(nlh, NULL)) return MNL_CB_ERROR; return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR; }
static int mnl_cb_error(const struct nlmsghdr *nlh, void *data) { const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) { errno = EBADMSG; return MNL_CB_ERROR; } /* Netlink subsystems returns the errno value with different signess */ if (err->error < 0) errno = -err->error; else errno = err->error; return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR; }
static int data_cb(const struct nlmsghdr *nlh, void *data) { struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh); printf("index=%d type=%d flags=%d family=%d ", ifm->ifi_index, ifm->ifi_type, ifm->ifi_flags, ifm->ifi_family); if (ifm->ifi_flags & IFF_RUNNING) printf("[RUNNING] "); else printf("[NOT RUNNING] "); mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, NULL); printf("\n"); return MNL_CB_OK; }
static int nametable_show_cb(const struct nlmsghdr *nlh, void *data) { int *iteration = data; char port_id[PORTID_STR_LEN]; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); struct nlattr *info[TIPC_NLA_MAX + 1] = {}; struct nlattr *attrs[TIPC_NLA_NAME_TABLE_MAX + 1] = {}; struct nlattr *publ[TIPC_NLA_PUBL_MAX + 1] = {}; const char *scope[] = { "", "zone", "cluster", "node" }; mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); if (!info[TIPC_NLA_NAME_TABLE]) return MNL_CB_ERROR; mnl_attr_parse_nested(info[TIPC_NLA_NAME_TABLE], parse_attrs, attrs); if (!attrs[TIPC_NLA_NAME_TABLE_PUBL]) return MNL_CB_ERROR; mnl_attr_parse_nested(attrs[TIPC_NLA_NAME_TABLE_PUBL], parse_attrs, publ); if (!publ[TIPC_NLA_NAME_TABLE_PUBL]) return MNL_CB_ERROR; if (!*iteration) printf("%-10s %-10s %-10s %-26s %-10s\n", "Type", "Lower", "Upper", "Port Identity", "Publication Scope"); (*iteration)++; snprintf(port_id, sizeof(port_id), "<%u.%u.%u:%u>", tipc_zone(mnl_attr_get_u32(publ[TIPC_NLA_PUBL_NODE])), tipc_cluster(mnl_attr_get_u32(publ[TIPC_NLA_PUBL_NODE])), tipc_node(mnl_attr_get_u32(publ[TIPC_NLA_PUBL_NODE])), mnl_attr_get_u32(publ[TIPC_NLA_PUBL_REF])); printf("%-10u %-10u %-10u %-26s %-12u", mnl_attr_get_u32(publ[TIPC_NLA_PUBL_TYPE]), mnl_attr_get_u32(publ[TIPC_NLA_PUBL_LOWER]), mnl_attr_get_u32(publ[TIPC_NLA_PUBL_UPPER]), port_id, mnl_attr_get_u32(publ[TIPC_NLA_PUBL_KEY])); printf("%s\n", scope[mnl_attr_get_u32(publ[TIPC_NLA_PUBL_SCOPE])]); return MNL_CB_OK; }
static int netid_get_cb(const struct nlmsghdr *nlh, void *data) { struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); struct nlattr *info[TIPC_NLA_MAX + 1] = {}; struct nlattr *attrs[TIPC_NLA_NET_MAX + 1] = {}; mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); if (!info[TIPC_NLA_NET]) return MNL_CB_ERROR; mnl_attr_parse_nested(info[TIPC_NLA_NET], parse_attrs, attrs); if (!attrs[TIPC_NLA_NET_ID]) return MNL_CB_ERROR; printf("%u\n", mnl_attr_get_u32(attrs[TIPC_NLA_NET_ID])); return MNL_CB_OK; }
/** * nfacct_nlmsg_parse_payload - set accounting object attributes from message * \param nlh: netlink message that you want to use to add the payload. * \param nfacct: pointer to a accounting object * * This function returns -1 in case that some mandatory attributes are * missing. On sucess, it returns 0. */ int nfacct_nlmsg_parse_payload(const struct nlmsghdr *nlh, struct nfacct *nfacct) { struct nlattr *tb[NFACCT_MAX+1] = {}; struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh); mnl_attr_parse(nlh, sizeof(*nfg), nfacct_nlmsg_parse_attr_cb, tb); if (!tb[NFACCT_NAME] && !tb[NFACCT_PKTS] && !tb[NFACCT_BYTES]) return -1; nfacct_attr_set_str(nfacct, NFACCT_ATTR_NAME, mnl_attr_get_str(tb[NFACCT_NAME])); nfacct_attr_set_u64(nfacct, NFACCT_ATTR_PKTS, be64toh(mnl_attr_get_u64(tb[NFACCT_PKTS]))); nfacct_attr_set_u64(nfacct, NFACCT_ATTR_BYTES, be64toh(mnl_attr_get_u64(tb[NFACCT_BYTES]))); return 0; }
static int link_mon_get_cb(const struct nlmsghdr *nlh, void *data) { struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); struct nlattr *info[TIPC_NLA_MAX + 1] = {}; struct nlattr *attrs[TIPC_NLA_MON_MAX + 1] = {}; mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); if (!info[TIPC_NLA_MON]) return MNL_CB_ERROR; mnl_attr_parse_nested(info[TIPC_NLA_MON], parse_attrs, attrs); if (!attrs[TIPC_NLA_MON_ACTIVATION_THRESHOLD]) return MNL_CB_ERROR; new_json_obj(json); print_uint(PRINT_ANY, "threshold", "%u\n", mnl_attr_get_u32(attrs[TIPC_NLA_MON_ACTIVATION_THRESHOLD])); delete_json_obj(); return MNL_CB_OK; }
static int link_get_cb(const struct nlmsghdr *nlh, void *data) { int *prop = data; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); struct nlattr *info[TIPC_NLA_MAX + 1] = {}; struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1] = {}; struct nlattr *props[TIPC_NLA_PROP_MAX + 1] = {}; mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); if (!info[TIPC_NLA_LINK]) return MNL_CB_ERROR; mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs); if (!attrs[TIPC_NLA_LINK_PROP]) return MNL_CB_ERROR; mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_PROP], parse_attrs, props); if (!props[*prop]) return MNL_CB_ERROR; new_json_obj(json); open_json_object(NULL); switch (*prop) { case TIPC_NLA_PROP_PRIO: print_uint(PRINT_ANY, PRIORITY_STR, "%u\n", mnl_attr_get_u32(props[*prop])); break; case TIPC_NLA_PROP_TOL: print_uint(PRINT_ANY, TOLERANCE_STR, "%u\n", mnl_attr_get_u32(props[*prop])); break; case TIPC_NLA_PROP_WIN: print_uint(PRINT_ANY, WINDOW_STR, "%u\n", mnl_attr_get_u32(props[*prop])); break; default: break; } close_json_object(); delete_json_obj(); return MNL_CB_OK; }
static int data_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[CTRL_ATTR_MAX+1] = {}; struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); mnl_attr_parse(nlh, sizeof(*genl), data_attr_cb, tb); if (tb[CTRL_ATTR_FAMILY_NAME]) { printf("name=%s\t", mnl_attr_get_str(tb[CTRL_ATTR_FAMILY_NAME])); } if (tb[CTRL_ATTR_FAMILY_ID]) { printf("id=%u\t", mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID])); } if (tb[CTRL_ATTR_VERSION]) { printf("version=%u\t", mnl_attr_get_u32(tb[CTRL_ATTR_VERSION])); } if (tb[CTRL_ATTR_HDRSIZE]) { printf("hdrsize=%u\t", mnl_attr_get_u32(tb[CTRL_ATTR_HDRSIZE])); } if (tb[CTRL_ATTR_MAXATTR]) { printf("maxattr=%u\t", mnl_attr_get_u32(tb[CTRL_ATTR_MAXATTR])); } printf("\n"); if (tb[CTRL_ATTR_OPS]) { printf("ops:\n"); parse_genl_family_ops(tb[CTRL_ATTR_OPS]); } if (tb[CTRL_ATTR_MCAST_GROUPS]) { printf("grps:\n"); parse_genl_mc_grps(tb[CTRL_ATTR_MCAST_GROUPS]); } printf("\n"); return MNL_CB_OK; }
static int data_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[IFLA_MAX+1] = {}; struct ifinfomsg *ifm = mnl_nlmsg_get_payload(nlh); printf("index=%d type=%d flags=%d family=%d ", ifm->ifi_index, ifm->ifi_type, ifm->ifi_flags, ifm->ifi_family); if (ifm->ifi_flags & IFF_RUNNING) printf("[RUNNING] "); else printf("[NOT RUNNING] "); mnl_attr_parse(nlh, sizeof(*ifm), data_attr_cb, tb); if (tb[IFLA_MTU]) { printf("mtu=%d ", mnl_attr_get_u32(tb[IFLA_MTU])); } if (tb[IFLA_IFNAME]) { printf("name=%s", mnl_attr_get_str(tb[IFLA_IFNAME])); } printf("\n"); return MNL_CB_OK; }
static int link_list_cb(const struct nlmsghdr *nlh, void *data) { struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); struct nlattr *info[TIPC_NLA_MAX + 1] = {}; struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1] = {}; mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); if (!info[TIPC_NLA_LINK]) return MNL_CB_ERROR; mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs); if (!attrs[TIPC_NLA_LINK_NAME]) return MNL_CB_ERROR; print_string(PRINT_FP, NULL, "%s: ", mnl_attr_get_str(attrs[TIPC_NLA_LINK_NAME])); if (attrs[TIPC_NLA_LINK_UP]) print_string(PRINT_ANY, mnl_attr_get_str(attrs[TIPC_NLA_LINK_NAME]),"%s\n", "up"); else print_string(PRINT_ANY, mnl_attr_get_str(attrs[TIPC_NLA_LINK_NAME]), "%s\n", "down"); return MNL_CB_OK; }
static void multi_link_modify_link(const struct nlmsghdr *nlh, uint32_t probe_pipe, uint8_t unique){ struct ifinfomsg *ifi = mnl_nlmsg_get_payload(nlh); struct nlattr *tb[IFLA_MAX + 1] = {}; uint8_t iface_state = 0; struct multi_link_info *li = NULL; struct multi_link_info_static *li_static = NULL; pthread_attr_t detach_attr; uint8_t wireless_mode = 0; uint8_t *if_name; mnl_attr_parse(nlh, sizeof(*ifi), multi_link_fill_rtattr, tb); if (!tb[IFLA_IFNAME]) { MULTI_DEBUG_PRINT_SYSLOG(stderr, "Missing interface name\n"); return; } if_name = (uint8_t*) mnl_attr_get_str(tb[IFLA_IFNAME]); if (!strncmp(if_name, "veth", 4) || ifi->ifi_type == ARPHRD_VOID || (ifi->ifi_type == ARPHRD_NONE && strncmp(if_name,"wwan", 4)) || ifi->ifi_type == ARPHRD_TUNNEL || ifi->ifi_flags & IFF_LOOPBACK) return; if(tb[IFLA_OPERSTATE]){ iface_state = mnl_attr_get_u8(tb[IFLA_OPERSTATE]); /* Check linux/Documentation/networking/operstates.txt. IFF_RUNNING * wraps both UP and UNKNOWN*/ if (ifi->ifi_flags & IFF_RUNNING){ //IF_OPER_UP == 6, defined in linux/if.h, chaos with includes //if(iface_state == 6){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s (%u) is RUNNING, " "length %u\n", if_name, ifi->ifi_index, multi_link_num_links); if((wireless_mode = multi_link_check_wlan_mode(if_name))) if(wireless_mode == 6){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s is monitor, " "ignoring\n", if_name); return; } LIST_FIND_CUSTOM(li, &multi_link_links_2, next, &(ifi->ifi_index), multi_cmp_ifidx); if(li != NULL){ if(li->state == LINK_UP_STATIC_IFF){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s (idx %u) has " "gone from UP to RUNNING\n", if_name, ifi->ifi_index); li->state = GOT_IP_STATIC; } else MULTI_DEBUG_PRINT_SYSLOG(stderr,"Interface %s (idx %u) has " "already been seen. Ignoring event\n", if_name, ifi->ifi_index); return; } if(multi_link_num_links < MAX_NUM_LINKS){ TAILQ_FIND_CUSTOM(li_static, &multi_shared_static_links, list_ptr, if_name, multi_cmp_devname); if(li_static != NULL){ if(li_static->proto == PROTO_IGNORE){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Ignoring %s\n", if_name); return; } else li = multi_link_create_new_link(if_name, li_static->metric); } else { /* Allocate a new link, add to list and start DHCP */ li = multi_link_create_new_link(if_name, 0); } if (!li) { MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not create link\n"); return; } //Insert link into link list LIST_INSERT_HEAD(&multi_link_links_2, li, next); ++multi_link_num_links; /* Add as a case here! The check for point to point */ if(li_static != NULL && li_static->proto == PROTO_STATIC){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s found in static list\n", if_name); li->state = GOT_IP_STATIC; li->cfg = li_static->cfg_static; } else if (ifi->ifi_type == ARPHRD_PPP){ /* PPP will be dealt with separatley, since they get the IP * remotely by themself */ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s (%u) is PPP! state " "%u %u\n", if_name, ifi->ifi_index, iface_state, IFF_RUNNING); li->state = LINK_DOWN_PPP; multi_link_get_iface_info(li); if(li->state != GOT_IP_PPP){ //Need to treat this in a special way! Remove li, keep //li and have some sort of timeout? MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not get info for PPP " "link %u (first look)!\n", ifi->ifi_index); } else { //Clean the information that is automatically added to //routing table multi_link_remove_ppp(li); } } else if(wireless_mode){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s is wlan access point\n", if_name); li->state = LINK_DOWN_AP; multi_link_get_iface_info(li); //Remove the automatic route multi_link_remove_ap(li); } else { pthread_attr_init(&detach_attr); pthread_attr_setdetachstate(&detach_attr, PTHREAD_CREATE_DETACHED); pthread_create(&(li->dhcp_thread), &detach_attr, multi_dhcp_main, (void *) li); } } else MULTI_DEBUG_PRINT_SYSLOG(stderr, "Limit reached, cannot add more links\n"); } else if(ifi->ifi_flags & IFF_UP){ //Might replace with IF_OPER_DOWN //Check if interface has already been seen LIST_FIND_CUSTOM(li, &multi_link_links_2, next, &(ifi->ifi_index), multi_cmp_ifidx); //Interface is already seen as UP, so clean up, no matter if static //or not. Static is a special case: remove routes, li from list //and free li if(li != NULL){ //Need a generic cleanup, move the next "else" into a separate //function MULTI_DEBUG_PRINT_SYSLOG(stderr,"Interface %s (idx %u) has already " "been seen as UP, will clean\n", if_name, ifi->ifi_index); multi_link_delete_link(li, probe_pipe); return; } //Check if interface is in static list TAILQ_FIND_CUSTOM(li_static, &multi_shared_static_links, list_ptr, if_name, multi_cmp_devname); if(li_static != NULL && li_static->proto == PROTO_STATIC){ //Allocate a new link MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s is UP\n", if_name); li = multi_link_create_new_link(if_name, li_static->metric); if (li == NULL) { MULTI_DEBUG_PRINT_SYSLOG(stderr, "Failed to create new link\n"); return; } li->state = GOT_IP_STATIC_UP; li->cfg = li_static->cfg_static; LIST_INSERT_HEAD(&multi_link_links_2, li, next); ++multi_link_num_links; } } else { uint32_t dev_idx = ifi->ifi_index; LIST_FIND_CUSTOM(li, &multi_link_links_2, next, &dev_idx, multi_cmp_ifidx); MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s (index %u) is down, " "length %u\n", if_name, ifi->ifi_index, multi_link_num_links); if(li == NULL){ MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not find %s (index %u), " "length %u\n", if_name, ifi->ifi_index, multi_link_num_links); } else{ multi_link_delete_link(li, probe_pipe); } } } }
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; }
static int data_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[RTA_MAX+1] = {}; struct rtmsg *rm = mnl_nlmsg_get_payload(nlh); /* protocol family = AF_INET | AF_INET6 */ printf("family=%u ", rm->rtm_family); /* destination CIDR, eg. 24 or 32 for IPv4 */ printf("dst_len=%u ", rm->rtm_dst_len); /* source CIDR */ printf("src_len=%u ", rm->rtm_src_len); /* type of service (TOS), eg. 0 */ printf("tos=%u ", rm->rtm_tos); /* table id: * RT_TABLE_UNSPEC = 0 * * ... user defined values ... * * RT_TABLE_COMPAT = 252 * RT_TABLE_DEFAULT = 253 * RT_TABLE_MAIN = 254 * RT_TABLE_LOCAL = 255 * RT_TABLE_MAX = 0xFFFFFFFF * * Synonimous attribute: RTA_TABLE. */ printf("table=%u ", rm->rtm_table); /* type: * RTN_UNSPEC = 0 * RTN_UNICAST = 1 * RTN_LOCAL = 2 * RTN_BROADCAST = 3 * RTN_ANYCAST = 4 * RTN_MULTICAST = 5 * RTN_BLACKHOLE = 6 * RTN_UNREACHABLE = 7 * RTN_PROHIBIT = 8 * RTN_THROW = 9 * RTN_NAT = 10 * RTN_XRESOLVE = 11 * __RTN_MAX = 12 */ printf("type=%u ", rm->rtm_type); /* scope: * RT_SCOPE_UNIVERSE = 0 : everywhere in the universe * * ... user defined values ... * * RT_SCOPE_SITE = 200 * RT_SCOPE_LINK = 253 : destination attached to link * RT_SCOPE_HOST = 254 : local address * RT_SCOPE_NOWHERE = 255 : not existing destination */ printf("scope=%u ", rm->rtm_scope); /* protocol: * RTPROT_UNSPEC = 0 * RTPROT_REDIRECT = 1 * RTPROT_KERNEL = 2 : route installed by kernel * RTPROT_BOOT = 3 : route installed during boot * RTPROT_STATIC = 4 : route installed by administrator * * Values >= RTPROT_STATIC are not interpreted by kernel, they are * just user-defined. */ printf("proto=%u ", rm->rtm_protocol); /* flags: * RTM_F_NOTIFY = 0x100: notify user of route change * RTM_F_CLONED = 0x200: this route is cloned * RTM_F_EQUALIZE = 0x400: Multipath equalizer: NI * RTM_F_PREFIX = 0x800: Prefix addresses */ printf("flags=%x\n", rm->rtm_flags); switch(rm->rtm_family) { case AF_INET: mnl_attr_parse(nlh, sizeof(*rm), data_ipv4_attr_cb, tb); attributes_show_ipv4(tb); break; case AF_INET6: mnl_attr_parse(nlh, sizeof(*rm), data_ipv6_attr_cb, tb); attributes_show_ipv6(tb); break; } return MNL_CB_OK; }