/* * Copyright (c) 2021 Eugene Syromyatnikov * All rights reserved. * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "tests.h" #include #include #include #include #include #include "test_netlink.h" #include "test_nlattr.h" #include #include #include #include #include "xlat.h" #include "xlat/addrfams.h" static uint8_t af; static char af_str[256]; /* uses global "af" variable */ static void init_rtgen(struct nlmsghdr *const nlh, const unsigned int msg_len) { SET_STRUCT(struct nlmsghdr, nlh, .nlmsg_len = msg_len, .nlmsg_type = RTM_NEWCACHEREPORT, .nlmsg_flags = NLM_F_EXCL|NLM_F_APPEND, ); struct rtgenmsg *const msg = NLMSG_DATA(nlh); SET_STRUCT(struct rtgenmsg, msg, .rtgen_family = af, ); } static void print_rtgen(const unsigned int msg_len) { printf("{nlmsg_len=%u, nlmsg_type=" XLAT_FMT ", nlmsg_flags=" XLAT_FMT ", nlmsg_seq=0, nlmsg_pid=0}, {rtgen_family=%s}", msg_len, XLAT_ARGS(RTM_NEWCACHEREPORT), XLAT_ARGS(NLM_F_EXCL|NLM_F_APPEND), af_str); } int main(void) { static const uint8_t unknown_msg[] = { 0xab, 0xac, 0xdb, 0xcd }; skip_if_unavailable("/proc/self/fd/"); const int fd = create_nl_socket(NETLINK_ROUTE); const unsigned int hdrlen = sizeof(struct rtgenmsg); void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), NLA_HDRLEN + 16); static char pattern[4096]; fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1); /* unknown AF_* */ static uint8_t skip_afs[] = { RTNL_FAMILY_IPMR, RTNL_FAMILY_IP6MR }; struct { struct rtgenmsg ATTRIBUTE_ALIGNED(NLMSG_ALIGNTO) hdr; struct { char str[sizeof(unknown_msg)]; } ATTRIBUTE_ALIGNED(NLMSG_ALIGNTO) payload; } buf; memcpy(buf.payload.str, unknown_msg, sizeof(unknown_msg)); size_t pos = 0; for (size_t i = 0; i < 256; i++) { if (pos < ARRAY_SIZE(skip_afs) && skip_afs[pos] == i) { pos += 1; continue; } buf.hdr.rtgen_family = i; TEST_NETLINK_(fd, nlh0, RTM_NEWCACHEREPORT, XLAT_KNOWN(0x60, "RTM_NEWCACHEREPORT"), NLM_F_REPLACE, XLAT_KNOWN(0x100, "NLM_F_REPLACE"), sizeof(buf), &buf, sizeof(buf), printf("{rtgen_family=%s}" ", \"\\xab\\xac\\xdb\\xcd\"", sprintxval(addrfams, i, "RTNL_FAMILY_???"))); } /* RTNL_FAMILY_IPMR */ af = RTNL_FAMILY_IPMR; snprintf(af_str, sizeof(af_str), XLAT_FMT, XLAT_ARGS(RTNL_FAMILY_IPMR)); /* RTNL_FAMILY_IPMR: unknown, undecoded */ static const struct strval16 unk_attrs[] = { { ENUM_KNOWN(0, IPMRA_CREPORT_UNSPEC) }, { ENUM_KNOWN(0x5, IPMRA_CREPORT_PKT) }, { ARG_XLAT_UNKNOWN(0x7, "IPMRA_CREPORT_???") }, { ARG_XLAT_UNKNOWN(0x1ead, "IPMRA_CREPORT_???") }, }; for (size_t i = 0; i < ARRAY_SIZE(unk_attrs); i++) { TEST_NLATTR_(fd, nlh0, hdrlen, init_rtgen, print_rtgen, unk_attrs[i].val, unk_attrs[i].str, 16, pattern, 16, print_quoted_hex(pattern, 16)); } /* RTNL_FAMILY_IPMR: IPMRA_CREPORT_MSGTYPE */ static const struct strval8 mr_msg_types[] = { { ARG_XLAT_UNKNOWN(0, "IGMPMSG_???") }, { ARG_XLAT_KNOWN(0x1, "IGMPMSG_NOCACHE") }, { ARG_XLAT_KNOWN(0x2, "IGMPMSG_WRONGVIF") }, { ARG_XLAT_KNOWN(0x3, "IGMPMSG_WHOLEPKT") }, { ARG_XLAT_KNOWN(0x4, "IGMPMSG_WRVIFWHOLE") }, { ARG_XLAT_UNKNOWN(0x5, "IGMPMSG_???") }, { ARG_XLAT_UNKNOWN(0xca, "IGMPMSG_???") }, }; for (size_t i = 0; i < ARRAY_SIZE(mr_msg_types); i++) { TEST_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_rtgen, print_rtgen, IPMRA_CREPORT_MSGTYPE, XLAT_KNOWN(0x1, "IPMRA_CREPORT_MSGTYPE"), pattern, mr_msg_types[i].val, 1, print_quoted_hex, printf("%s", mr_msg_types[i].str)); } /* RTNL_FAMILY_IPMR: u32 */ static const struct strval16 u32_mr_attrs[] = { { ENUM_KNOWN(0x2, IPMRA_CREPORT_VIF_ID) }, { ENUM_KNOWN(0x6, IPMRA_CREPORT_TABLE) }, }; void *nlh_u32 = midtail_alloc(NLMSG_SPACE(hdrlen), NLA_HDRLEN + sizeof(uint32_t)); for (size_t i = 0; i < ARRAY_SIZE(u32_mr_attrs); i++) { check_u32_nlattr(fd, nlh_u32, hdrlen, init_rtgen, print_rtgen, u32_mr_attrs[i].val, u32_mr_attrs[i].str, pattern, 0); } /* RTNL_FAMILY_IPMR: in_addr */ static const struct strval16 in_addr_attrs[] = { { ENUM_KNOWN(0x3, IPMRA_CREPORT_SRC_ADDR) }, { ENUM_KNOWN(0x4, IPMRA_CREPORT_DST_ADDR) }, }; static uint32_t ipv4_addr = BE32(0xdeadface); for (size_t i = 0; i < ARRAY_SIZE(in_addr_attrs); i++) { TEST_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_rtgen, print_rtgen, in_addr_attrs[i].val, in_addr_attrs[i].str, pattern, ipv4_addr, 4, print_quoted_hex, printf(XLAT_KNOWN_FMT( "\"\\xde\\xad\\xfa\\xce\"", "inet_addr(\"222.173.250.206\")")) ); } /* RTNL_FAMILY_IP6MR */ af = RTNL_FAMILY_IP6MR; snprintf(af_str, sizeof(af_str), XLAT_FMT, XLAT_ARGS(RTNL_FAMILY_IP6MR)); /* RTNL_FAMILY_IP6MR: unknown, undecoded */ static const struct strval16 unk6_attrs[] = { { ENUM_KNOWN(0, IP6MRA_CREPORT_UNSPEC) }, { ENUM_KNOWN(0x5, IP6MRA_CREPORT_PKT) }, { ARG_XLAT_UNKNOWN(0x6, "IP6MRA_CREPORT_???") }, { ARG_XLAT_UNKNOWN(0x1ead, "IP6MRA_CREPORT_???") }, }; for (size_t i = 0; i < ARRAY_SIZE(unk6_attrs); i++) { TEST_NLATTR_(fd, nlh0, hdrlen, init_rtgen, print_rtgen, unk6_attrs[i].val, unk6_attrs[i].str, 16, pattern, 16, print_quoted_hex(pattern, 16)); } /* RTNL_FAMILY_IP6MR: IP6MRA_CREPORT_MSGTYPE */ static const struct strval8 mr6_msg_types[] = { { ARG_XLAT_UNKNOWN(0, "MRT6MSG_???") }, { ARG_XLAT_KNOWN(0x1, "MRT6MSG_NOCACHE") }, { ARG_XLAT_KNOWN(0x2, "MRT6MSG_WRONGMIF") }, { ARG_XLAT_KNOWN(0x3, "MRT6MSG_WHOLEPKT") }, { ARG_XLAT_UNKNOWN(0x4, "MRT6MSG_???") }, { ARG_XLAT_UNKNOWN(0xca, "MRT6MSG_???") }, }; for (size_t i = 0; i < ARRAY_SIZE(mr6_msg_types); i++) { TEST_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_rtgen, print_rtgen, IP6MRA_CREPORT_MSGTYPE, XLAT_KNOWN(0x1, "IP6MRA_CREPORT_MSGTYPE"), pattern, mr6_msg_types[i].val, 1, print_quoted_hex, printf("%s", mr6_msg_types[i].str)); } /* RTNL_FAMILY_IP6MR: u32 */ static const struct strval16 u32_mr6_attrs[] = { { ENUM_KNOWN(0x2, IP6MRA_CREPORT_MIF_ID) }, }; for (size_t i = 0; i < ARRAY_SIZE(u32_mr6_attrs); i++) { check_u32_nlattr(fd, nlh_u32, hdrlen, init_rtgen, print_rtgen, u32_mr6_attrs[i].val, u32_mr6_attrs[i].str, pattern, 0); } /* RTNL_FAMILY_IPMR: in6_addr */ static const struct strval16 in6_addr_attrs[] = { { ENUM_KNOWN(0x3, IP6MRA_CREPORT_SRC_ADDR) }, { ENUM_KNOWN(0x4, IP6MRA_CREPORT_DST_ADDR) }, }; uint8_t ipv6_addr[16] = { 0xba, 0xdc, 0x0d, 0xed, 0xfa, 0xce, 0xbe, 0xef, 0xde, 0xca, 0xfe, 0xed, 0xde, 0xad, 0xfe, 0xed, }; for (size_t i = 0; i < ARRAY_SIZE(in6_addr_attrs); i++) { TEST_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_rtgen, print_rtgen, in6_addr_attrs[i].val, in6_addr_attrs[i].str, pattern, ipv6_addr, 16, print_quoted_hex, printf(XLAT_KNOWN_FMT( "\"\\xba\\xdc\\x0d\\xed" "\\xfa\\xce\\xbe\\xef" "\\xde\\xca\\xfe\\xed" "\\xde\\xad\\xfe\\xed\"", "inet_pton(AF_INET6" ", \"badc:ded:face:beef" ":deca:feed:dead:feed\")"))); } puts("+++ exited with 0 +++"); return 0; }