static int nfct_parse_helper(const struct nlattr *attr, struct nf_conntrack *ct) { struct nlattr *tb[CTA_HELP_MAX+1] = {}; if (mnl_attr_parse_nested(attr, nfct_parse_helper_attr_cb, tb) < 0) return -1; if (!tb[CTA_HELP_NAME]) return 0; strncpy(ct->helper_name, mnl_attr_get_str(tb[CTA_HELP_NAME]), NFCT_HELPER_NAME_MAX); ct->helper_name[NFCT_HELPER_NAME_MAX-1] = '\0'; set_bit(ATTR_HELPER_NAME, ct->head.set); if (!tb[CTA_HELP_INFO]) return 0; ct->helper_info_len = mnl_attr_get_payload_len(tb[CTA_HELP_INFO]); ct->helper_info = calloc(1, ct->helper_info_len); if (ct->helper_info == NULL) return -1; memcpy(ct->helper_info, mnl_attr_get_payload(tb[CTA_HELP_INFO]), ct->helper_info_len); set_bit(ATTR_HELPER_INFO, ct->head.set); return 0; }
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; }
static int __mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type, size_t exp_len) { uint16_t attr_len = mnl_attr_get_payload_len(attr); const char *attr_data = mnl_attr_get_payload(attr); if (attr_len < exp_len) { errno = ERANGE; return -1; } switch(type) { case MNL_TYPE_FLAG: if (attr_len > 0) { errno = ERANGE; return -1; } break; case MNL_TYPE_NUL_STRING: if (attr_len == 0) { errno = ERANGE; return -1; } if (attr_data[attr_len-1] != '\0') { errno = EINVAL; return -1; } break; case MNL_TYPE_STRING: if (attr_len == 0) { errno = ERANGE; return -1; } break; case MNL_TYPE_NESTED: /* empty nested attributes are OK. */ if (attr_len == 0) break; /* if not empty, they must contain one header, eg. flag */ if (attr_len < MNL_ATTR_HDRLEN) { errno = ERANGE; return -1; } break; default: /* make gcc happy. */ break; } if (exp_len && attr_len > exp_len) { errno = ERANGE; return -1; } return 0; }
static int nfct_parse_labels(const struct nlattr *attr, struct nf_conntrack *ct) { uint16_t len = mnl_attr_get_payload_len(attr); struct nfct_bitmask *mask; uint32_t *bits; if (len == 0) return 0; mask = nfct_bitmask_new((len * CHAR_BIT) - 1); if (!mask) return -1; bits = mnl_attr_get_payload(attr); memcpy(mask->bits, bits, len); nfct_set_attr(ct, ATTR_CONNLABELS, mask); return 0; }
static int nftnl_expr_target_parse(struct nftnl_expr *e, struct nlattr *attr) { struct nftnl_expr_target *target = nftnl_expr_data(e); struct nlattr *tb[NFTA_TARGET_MAX+1] = {}; if (mnl_attr_parse_nested(attr, nftnl_expr_target_cb, tb) < 0) return -1; if (tb[NFTA_TARGET_NAME]) { snprintf(target->name, XT_EXTENSION_MAXNAMELEN, "%s", mnl_attr_get_str(tb[NFTA_TARGET_NAME])); target->name[XT_EXTENSION_MAXNAMELEN-1] = '\0'; e->flags |= (1 << NFTNL_EXPR_TG_NAME); } if (tb[NFTA_TARGET_REV]) { target->rev = ntohl(mnl_attr_get_u32(tb[NFTA_TARGET_REV])); e->flags |= (1 << NFTNL_EXPR_TG_REV); } if (tb[NFTA_TARGET_INFO]) { uint32_t len = mnl_attr_get_payload_len(tb[NFTA_TARGET_INFO]); void *target_data; if (target->data) xfree(target->data); target_data = calloc(1, len); if (target_data == NULL) return -1; memcpy(target_data, mnl_attr_get_payload(tb[NFTA_TARGET_INFO]), len); target->data = target_data; target->data_len = len; e->flags |= (1 << NFTNL_EXPR_TG_INFO); } return 0; }
static int nft_rule_expr_match_parse(struct nft_rule_expr *e, struct nlattr *attr) { struct nft_expr_match *match = nft_expr_data(e); struct nlattr *tb[NFTA_MATCH_MAX+1] = {}; if (mnl_attr_parse_nested(attr, nft_rule_expr_match_cb, tb) < 0) return -1; if (tb[NFTA_MATCH_NAME]) { snprintf(match->name, XT_EXTENSION_MAXNAMELEN, "%s", mnl_attr_get_str(tb[NFTA_MATCH_NAME])); match->name[XT_EXTENSION_MAXNAMELEN-1] = '\0'; e->flags |= (1 << NFT_EXPR_MT_NAME); } if (tb[NFTA_MATCH_REV]) { match->rev = ntohl(mnl_attr_get_u32(tb[NFTA_MATCH_REV])); e->flags |= (1 << NFT_EXPR_MT_REV); } if (tb[NFTA_MATCH_INFO]) { uint32_t len = mnl_attr_get_payload_len(tb[NFTA_MATCH_INFO]); void *match_data; if (match->data) xfree(match->data); match_data = calloc(1, len); if (match_data == NULL) return -1; memcpy(match_data, mnl_attr_get_payload(tb[NFTA_MATCH_INFO]), len); match->data = match_data; match->data_len = len; e->flags |= (1 << NFT_EXPR_MT_INFO); } return 0; }
/* returns negative on error * or returns remainded nlmsghdr length */ static int _unpack_nlmsg(const struct nlmsghdr *nlh, const char *format, va_list ap) { struct nlattr *attr = mnl_nlmsg_get_payload(nlh); int remains = (int)mnl_nlmsg_get_payload_len(nlh); size_t len; uint16_t atype, alen; void *p; while (*format != '\0' ) { if (!mnl_attr_ok(attr, remains)) { errno = EOVERFLOW; return -1; } remains -= MY_NLATTR_HDRLEN; atype = mnl_attr_get_type(attr); alen = mnl_attr_get_payload_len(attr); switch (*format) { case 'B': /* byte */ if (atype != MNL_TYPE_U8 || alen != sizeof(uint8_t)) { errno =EINVAL; return -1; } *(va_arg(ap, uint8_t *)) = mnl_attr_get_u8(attr); break; case 'H': /* 2byte */ if (atype != MNL_TYPE_U16 || alen != sizeof(uint16_t)) { errno = EINVAL; return -1; } *(va_arg(ap, uint16_t *)) = mnl_attr_get_u16(attr); break; case 'I': /* 4byte */ if (atype != MNL_TYPE_U32 || alen != sizeof(uint32_t)) { errno = EINVAL; return -1; } *(va_arg(ap, uint32_t *)) = mnl_attr_get_u32(attr); break; case 'K': /* 8byte */ if (atype != MNL_TYPE_U64 || alen != sizeof(uint64_t)) { errno = EINVAL; return -1; } *(va_arg(ap, uint64_t *)) = mnl_attr_get_u64(attr); break; case 'p': /* pointer */ if (atype != MNL_TYPE_BINARY || alen != sizeof(void *)) { errno = EINVAL; return -1; } *(va_arg(ap, void **)) = *((void **)mnl_attr_get_payload(attr)); break; case 'z': /* null string */ if (atype != MNL_TYPE_NUL_STRING) { errno = EINVAL; return -1; } p = va_arg(ap, void *); if (*(format + 1) == '#') { format++; len = va_arg(ap, size_t); if (alen > len) { errno = EINVAL; return -1; } } strncpy(p, mnl_attr_get_payload(attr), alen); break; case 'y': /* bytes with size */ format++; if (*format != '#') { errno = EINVAL; return -1; } p = va_arg(ap, void *); len = va_arg(ap, size_t); if (alen > len) return -EINVAL; memcpy(p, mnl_attr_get_payload(attr), alen); break; default: errno =EINVAL; return -1; } remains -= MY_ATTR_ALIGN(alen); format++; attr = mnl_attr_next(attr); } if (remains) { errno = EMSGSIZE; nurs_log(NURS_NOTICE, "unpack remains: %d\n", remains); } return remains; }