static void print_ip(const struct nlattr *nest) { struct nlattr *tb[CTA_IP_MAX+1] = {}; mnl_attr_parse_nested(nest, parse_ip_cb, tb); if (tb[CTA_IP_V4_SRC]) { struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_SRC]); printf("src=%s ", inet_ntoa(*in)); } if (tb[CTA_IP_V4_DST]) { struct in_addr *in = mnl_attr_get_payload(tb[CTA_IP_V4_DST]); printf("dst=%s ", inet_ntoa(*in)); } if (tb[CTA_IP_V6_SRC]) { struct in6_addr *in = mnl_attr_get_payload(tb[CTA_IP_V6_SRC]); char out[INET6_ADDRSTRLEN]; if (!inet_ntop(AF_INET6, in, out, sizeof(out))) printf("src=%s ", out); } if (tb[CTA_IP_V6_DST]) { struct in6_addr *in = mnl_attr_get_payload(tb[CTA_IP_V6_DST]); char out[INET6_ADDRSTRLEN]; if (!inet_ntop(AF_INET6, in, out, sizeof(out))) printf("dst=%s ", out); } }
//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); }
//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 ss_ntop(struct nlattr *nla_line, char *addr_str, uint16_t *port) { struct __kernel_sockaddr_storage *addr; addr = (struct __kernel_sockaddr_storage *) mnl_attr_get_payload(nla_line); switch (addr->ss_family) { case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *)addr; if (!inet_ntop(AF_INET, (const void *)&sin->sin_addr, addr_str, INET6_ADDRSTRLEN)) return -EINVAL; *port = ntohs(sin->sin_port); break; } case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; if (!inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr, addr_str, INET6_ADDRSTRLEN)) return -EINVAL; *port = ntohs(sin6->sin6_port); break; } default: return -EINVAL; } return 0; }
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 nfct_parse_protoinfo_tcp(const struct nlattr *attr, struct nf_conntrack *ct) { struct nlattr *tb[CTA_PROTOINFO_TCP_MAX+1] = {}; if (mnl_attr_parse_nested(attr, nfct_parse_pinfo_tcp_attr_cb, tb) < 0) return -1; if (tb[CTA_PROTOINFO_TCP_STATE]) { ct->protoinfo.tcp.state = mnl_attr_get_u8(tb[CTA_PROTOINFO_TCP_STATE]); set_bit(ATTR_TCP_STATE, ct->head.set); } if (tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]) { memcpy(&ct->protoinfo.tcp.wscale[__DIR_ORIG], mnl_attr_get_payload(tb[CTA_PROTOINFO_TCP_WSCALE_ORIGINAL]), sizeof(uint8_t)); set_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set); } if (tb[CTA_PROTOINFO_TCP_WSCALE_REPLY]) { memcpy(&ct->protoinfo.tcp.wscale[__DIR_REPL], mnl_attr_get_payload(tb[CTA_PROTOINFO_TCP_WSCALE_REPLY]), sizeof(uint8_t)); set_bit(ATTR_TCP_WSCALE_REPL, ct->head.set); } if (tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]) { memcpy(&ct->protoinfo.tcp.flags[0], mnl_attr_get_payload(tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]), sizeof(struct nf_ct_tcp_flags)); set_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set); set_bit(ATTR_TCP_MASK_ORIG, ct->head.set); } if (tb[CTA_PROTOINFO_TCP_FLAGS_REPLY]) { memcpy(&ct->protoinfo.tcp.flags[1], mnl_attr_get_payload(tb[CTA_PROTOINFO_TCP_FLAGS_REPLY]), sizeof(struct nf_ct_tcp_flags)); set_bit(ATTR_TCP_FLAGS_REPL, ct->head.set); set_bit(ATTR_TCP_MASK_REPL, ct->head.set); } return 0; }
static void attributes_show_ipv4(struct nlattr *tb[]) { if (tb[RTA_TABLE]) { printf("table=%u ", mnl_attr_get_u32(tb[RTA_TABLE])); } if (tb[RTA_DST]) { struct in_addr *addr = mnl_attr_get_payload(tb[RTA_DST]); printf("dst=%s ", inet_ntoa(*addr)); } if (tb[RTA_SRC]) { struct in_addr *addr = mnl_attr_get_payload(tb[RTA_SRC]); printf("src=%s ", inet_ntoa(*addr)); } if (tb[RTA_OIF]) { printf("oif=%u ", mnl_attr_get_u32(tb[RTA_OIF])); } if (tb[RTA_FLOW]) { printf("flow=%u ", mnl_attr_get_u32(tb[RTA_FLOW])); } if (tb[RTA_PREFSRC]) { struct in_addr *addr = mnl_attr_get_payload(tb[RTA_PREFSRC]); printf("prefsrc=%s ", inet_ntoa(*addr)); } if (tb[RTA_GATEWAY]) { struct in_addr *addr = mnl_attr_get_payload(tb[RTA_GATEWAY]); printf("gw=%s ", inet_ntoa(*addr)); } if (tb[RTA_PRIORITY]) { printf("prio=%u ", mnl_attr_get_u32(tb[RTA_PRIORITY])); } if (tb[RTA_METRICS]) { int i; struct nlattr *tbx[RTAX_MAX+1] = {}; mnl_attr_parse_nested(tb[RTA_METRICS], data_attr_cb2, tbx); for (i=0; i<RTAX_MAX; i++) { if (tbx[i]) { printf("metrics[%d]=%u ", i, mnl_attr_get_u32(tbx[i])); } } } printf("\n"); }
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; }
/** * mnl_attr_put - add an attribute to netlink message * \param nlh pointer to the netlink 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 updates the length field of the Netlink message (nlmsg_len) * by adding the size (header + payload) of the new attribute. */ void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data) { struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh); uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len; attr->nla_type = type; attr->nla_len = payload_len; memcpy(mnl_attr_get_payload(attr), data, len); nlh->nlmsg_len += MNL_ALIGN(payload_len); }
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 queue_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[NFQA_MAX+1] = {}; struct nfqnl_msg_packet_hdr *ph = NULL; uint32_t id = 0; mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb); if (tb[NFQA_PACKET_HDR]) { ph = mnl_attr_get_payload(tb[NFQA_PACKET_HDR]); id = ntohl(ph->packet_id); } printf("packet received (id=%u hw=0x%04x hook=%u)\n", id, ntohs(ph->hw_protocol), ph->hook); return MNL_CB_OK + id; }
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 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; }
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 log_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[NFULA_MAX+1] = {}; struct nfulnl_msg_packet_hdr *ph = NULL; const char *prefix = NULL; uint32_t mark = 0; mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb); if (tb[NFULA_PACKET_HDR]) ph = mnl_attr_get_payload(tb[NFULA_PACKET_HDR]); if (tb[NFULA_PREFIX]) prefix = mnl_attr_get_str(tb[NFULA_PREFIX]); if (tb[NFULA_MARK]) mark = ntohl(mnl_attr_get_u32(tb[NFULA_MARK])); printf("log received (prefix=\"%s\" hw=0x%04x hook=%u mark=%u)\n", prefix ? prefix : "", ntohs(ph->hw_protocol), ph->hook, mark); return MNL_CB_OK; }
/* 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; }
static int log_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[NFULA_MAX+1] = {}; mnl_attr_parse(nlh, sizeof(struct nfgenmsg), parse_attr_cb, tb); if (tb[NFULA_PREFIX]) { const char *prefix = mnl_attr_get_str(tb[NFULA_PREFIX]); printf("%s ", prefix); } if (tb[NFULA_IFINDEX_INDEV]) { uint32_t indev = ntohl(mnl_attr_get_u32(tb[NFULA_IFINDEX_INDEV])); char *instr = get_net_device_name_by_index(indev); printf("IN=%s ", instr ? instr : ""); } else { printf("IN= "); } if (tb[NFULA_IFINDEX_OUTDEV]) { uint32_t outdev = ntohl(mnl_attr_get_u32(tb[NFULA_IFINDEX_OUTDEV])); char *outstr = get_net_device_name_by_index(outdev); printf("OUT=%s ", outstr ? outstr : ""); } else { printf("OUT= "); } if (tb[NFULA_PAYLOAD]) { struct iphdr *iph = (struct iphdr *) mnl_attr_get_payload(tb[NFULA_PAYLOAD]); printf("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ", ((unsigned char *)&iph->saddr)[0], ((unsigned char *)&iph->saddr)[1], ((unsigned char *)&iph->saddr)[2], ((unsigned char *)&iph->saddr)[3], ((unsigned char *)&iph->daddr)[0], ((unsigned char *)&iph->daddr)[1], ((unsigned char *)&iph->daddr)[2], ((unsigned char *)&iph->daddr)[3]); printf("LEN=%u ", ntohs(iph->tot_len)); switch(iph->protocol) { case IPPROTO_TCP: { struct tcphdr *th = (struct tcphdr *) ((__u32 *) iph + iph->ihl); printf("PROTO=TCP SPT=%u DPT=%u ", ntohs(th->source), ntohs(th->dest)); break; } case IPPROTO_UDP: { struct udphdr *uh = (struct udphdr *) ((__u32 *) iph + iph->ihl); printf("PROTO=UDP SPT=%u DPT=%u LEN=%u ", ntohs(uh->source), ntohs(uh->dest), ntohs(uh->len)); break; } case IPPROTO_ICMP: { struct icmphdr *ich = (struct icmphdr *) ((__u32 *) iph + iph->ihl); printf("PROTO=ICMP TYPE=%u CODE=%u ", ich->type, ich->code); break; } default: { printf("PROTO=%u ", iph->protocol); } } } if (tb[NFULA_UID]) { uint32_t uid = ntohl(mnl_attr_get_u32(tb[NFULA_UID])); printf("UID=%u ", uid); } puts(""); return MNL_CB_OK; }
/** * mnl_attr_get_u8 - returns 8-bit unsigned integer attribute payload * \param attr pointer to netlink attribute * * This function returns the 8-bit value of the attribute payload. */ EXPORT_SYMBOL uint8_t mnl_attr_get_u8(const struct nlattr *attr) { return *((uint8_t *)mnl_attr_get_payload(attr)); }
/** * mnl_attr_get_str - returns pointer to string attribute. * \param attr pointer to netlink attribute * * This function returns the payload of string attribute value. */ const char *mnl_attr_get_str(const struct nlattr *attr) { return mnl_attr_get_payload(attr); }
/** * mnl_attr_get_u64 - returns 64-bit unsigned integer attribute. * \param attr pointer to netlink attribute * * This function returns the 64-bit value of the attribute payload. This * function is align-safe, since accessing 64-bit Netlink attributes is a * common source of alignment issues. */ uint64_t mnl_attr_get_u64(const struct nlattr *attr) { uint64_t tmp; memcpy(&tmp, mnl_attr_get_payload(attr), sizeof(tmp)); return tmp; }
/** * mnl_attr_get_u32 - returns 32-bit unsigned integer attribute payload * \param attr pointer to netlink attribute * * This function returns the 32-bit value of the attribute payload. */ uint32_t mnl_attr_get_u32(const struct nlattr *attr) { return *((uint32_t *)mnl_attr_get_payload(attr)); }
/** * mnl_attr_get_u16 - returns 16-bit unsigned integer attribute payload * \param attr pointer to netlink attribute * * This function returns the 16-bit value of the attribute payload. */ uint16_t mnl_attr_get_u16(const struct nlattr *attr) { return *((uint16_t *)mnl_attr_get_payload(attr)); }
static int nfct_parse_ip(const struct nlattr *attr, struct __nfct_tuple *tuple, const int dir, u_int32_t *set) { struct nlattr *tb[CTA_IP_MAX+1] = {}; if (mnl_attr_parse_nested(attr, nfct_parse_ip_attr_cb, tb) < 0) return -1; if (tb[CTA_IP_V4_SRC]) { tuple->src.v4 = mnl_attr_get_u32(tb[CTA_IP_V4_SRC]); switch(dir) { case __DIR_ORIG: set_bit(ATTR_ORIG_IPV4_SRC, set); break; case __DIR_REPL: set_bit(ATTR_REPL_IPV4_SRC, set); break; case __DIR_MASTER: set_bit(ATTR_MASTER_IPV4_SRC, set); break; } } if (tb[CTA_IP_V4_DST]) { tuple->dst.v4 = mnl_attr_get_u32(tb[CTA_IP_V4_DST]); switch(dir) { case __DIR_ORIG: set_bit(ATTR_ORIG_IPV4_DST, set); break; case __DIR_REPL: set_bit(ATTR_REPL_IPV4_DST, set); break; case __DIR_MASTER: set_bit(ATTR_MASTER_IPV4_DST, set); break; } } if (tb[CTA_IP_V6_SRC]) { memcpy(&tuple->src.v6, mnl_attr_get_payload(tb[CTA_IP_V6_SRC]), sizeof(struct in6_addr)); switch(dir) { case __DIR_ORIG: set_bit(ATTR_ORIG_IPV6_SRC, set); break; case __DIR_REPL: set_bit(ATTR_REPL_IPV6_SRC, set); break; case __DIR_MASTER: set_bit(ATTR_MASTER_IPV6_SRC, set); break; } } if (tb[CTA_IP_V6_DST]) { memcpy(&tuple->dst.v6, mnl_attr_get_payload(tb[CTA_IP_V6_DST]), sizeof(struct in6_addr)); switch(dir) { case __DIR_ORIG: set_bit(ATTR_ORIG_IPV6_DST, set); break; case __DIR_REPL: set_bit(ATTR_REPL_IPV6_DST, set); break; case __DIR_MASTER: set_bit(ATTR_MASTER_IPV6_DST, set); break; } } return 0; }