| /* |
| * IFLA_AF_SPEC netlink attribute decoding check. |
| * |
| * Copyright (c) 2018 The strace developers. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "tests.h" |
| |
| #include <inttypes.h> |
| #include <stdio.h> |
| #include <stddef.h> |
| #include "test_nlattr.h" |
| |
| #include <linux/if.h> |
| #include <linux/if_arp.h> |
| #ifdef HAVE_LINUX_IF_LINK_H |
| # include <linux/if_link.h> |
| #endif |
| #include <linux/rtnetlink.h> |
| |
| #if !HAVE_DECL_IFLA_AF_SPEC |
| enum { IFLA_AF_SPEC = 26 }; |
| #endif |
| |
| #define XLAT_MACROS_ONLY |
| # include "xlat/rtnl_ifla_af_spec_inet_attrs.h" |
| # include "xlat/rtnl_ifla_af_spec_inet6_attrs.h" |
| #undef XLAT_MACROS_ONLY |
| |
| #ifndef HAVE_STRUCT_IFLA_CACHEINFO |
| struct ifla_cacheinfo { |
| uint32_t max_reasm_len; |
| uint32_t tstamp; |
| uint32_t reachable_time; |
| uint32_t retrans_time; |
| }; |
| #endif |
| |
| #define IFLA_ATTR IFLA_AF_SPEC |
| #include "nlattr_ifla.h" |
| |
| #define AF_SPEC_FUNCS(family_) \ |
| static void \ |
| init_##family_##_msg(struct nlmsghdr *const nlh, \ |
| const unsigned int msg_len) \ |
| { \ |
| init_ifinfomsg(nlh, msg_len); \ |
| \ |
| struct nlattr *nla = NLMSG_ATTR(nlh, hdrlen); \ |
| nla += 1; \ |
| SET_STRUCT(struct nlattr, nla, \ |
| .nla_len = msg_len - NLMSG_SPACE(hdrlen) \ |
| - NLA_HDRLEN, \ |
| .nla_type = family_, \ |
| ); \ |
| } \ |
| \ |
| static void \ |
| print_##family_##_msg(const unsigned int msg_len) \ |
| { \ |
| print_ifinfomsg(msg_len); \ |
| printf(", {{nla_len=%u, nla_type=" #family_ "}", \ |
| msg_len - NLMSG_SPACE(hdrlen) - NLA_HDRLEN); \ |
| } \ |
| /* end of AF_SPEC_FUNCS definition */ |
| |
| AF_SPEC_FUNCS(AF_INET) |
| AF_SPEC_FUNCS(AF_INET6) |
| |
| static void |
| print_arr_val(uint32_t *val, size_t idx, const char *idx_str) |
| { |
| if (idx_str) |
| printf("[%s] = ", idx_str); |
| else |
| printf("[%zu] = ", idx); |
| |
| printf("%d", *val); |
| } |
| |
| static void |
| print_arr_uval(uint64_t *val, size_t idx, const char *idx_str) |
| { |
| if (idx_str) |
| printf("[%s] = ", idx_str); |
| else |
| printf("[%zu] = ", idx); |
| |
| printf("%" PRIu64, *val); |
| } |
| |
| static void |
| print_inet_conf_val(uint32_t *val, size_t idx) |
| { |
| static const char * const strs[] = { |
| "IPV4_DEVCONF_FORWARDING-1", |
| "IPV4_DEVCONF_MC_FORWARDING-1", |
| }; |
| |
| print_arr_val(val, idx, idx < ARRAY_SIZE(strs) ? strs[idx] : NULL); |
| } |
| |
| |
| static void |
| print_inet6_conf_val(uint32_t *val, size_t idx) |
| { |
| static const char * const strs[] = { |
| "DEVCONF_FORWARDING", |
| "DEVCONF_HOPLIMIT", |
| }; |
| |
| print_arr_val(val, idx, idx < ARRAY_SIZE(strs) ? strs[idx] : NULL); |
| } |
| |
| static void |
| print_inet6_stats_val(uint64_t *val, size_t idx) |
| { |
| static const char * const strs[] = { |
| "IPSTATS_MIB_NUM", |
| "IPSTATS_MIB_INPKTS", |
| }; |
| |
| print_arr_uval(val, idx, idx < ARRAY_SIZE(strs) ? strs[idx] : NULL); |
| } |
| |
| static void |
| print_icmp6_stats_val(uint64_t *val, size_t idx) |
| { |
| static const char * const strs[] = { |
| "ICMP6_MIB_NUM", |
| "ICMP6_MIB_INMSGS", |
| "ICMP6_MIB_INERRORS", |
| "ICMP6_MIB_OUTMSGS", |
| "ICMP6_MIB_OUTERRORS", |
| "ICMP6_MIB_CSUMERRORS", |
| "6 /* ICMP6_MIB_??? */", |
| }; |
| |
| print_arr_uval(val, idx, idx < ARRAY_SIZE(strs) ? strs[idx] : NULL); |
| } |
| |
| 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 ifinfomsg); |
| void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), 3 * NLA_HDRLEN + 256); |
| |
| static char pattern[4096]; |
| fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1); |
| |
| |
| /* unknown AF_* */ |
| TEST_NESTED_NLATTR_OBJECT(fd, nlh0, hdrlen, |
| init_ifinfomsg, print_ifinfomsg, |
| AF_UNIX, pattern, unknown_msg, |
| printf("\"\\xab\\xac\\xdb\\xcd\"")); |
| |
| /* AF_INET */ |
| TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, |
| init_AF_INET_msg, print_AF_INET_msg, |
| 0, "IFLA_INET_UNSPEC", pattern, |
| unknown_msg, print_quoted_hex, 2, |
| printf("\"\\xab\\xac\\xdb\\xcd\"")); |
| TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, |
| init_AF_INET_msg, print_AF_INET_msg, |
| 2, "0x2 /* IFLA_INET_??? */", pattern, |
| unknown_msg, print_quoted_hex, 2, |
| printf("\"\\xab\\xac\\xdb\\xcd\"")); |
| |
| /* AF_INET: IFLA_INET_CONF */ |
| uint32_t inet_conf_vals[] = { 0xdeadc0de, 0xda7aface }; |
| TEST_NESTED_NLATTR_ARRAY_EX(fd, nlh0, hdrlen, |
| init_AF_INET_msg, print_AF_INET_msg, |
| IFLA_INET_CONF, pattern, |
| inet_conf_vals, 2, print_inet_conf_val); |
| |
| /* AF_INET6 */ |
| TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, |
| init_AF_INET6_msg, print_AF_INET6_msg, |
| 0, "IFLA_INET6_UNSPEC", pattern, |
| unknown_msg, print_quoted_hex, 2, |
| printf("\"\\xab\\xac\\xdb\\xcd\"")); |
| TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, |
| init_AF_INET6_msg, print_AF_INET6_msg, |
| 9, "0x9 /* IFLA_INET6_??? */", pattern, |
| unknown_msg, print_quoted_hex, 2, |
| printf("\"\\xab\\xac\\xdb\\xcd\"")); |
| |
| /* AF_INET6: IFLA_INET6_FLAGS */ |
| static const struct { |
| uint32_t flags; |
| const char *str; |
| } inet6_flags[] = { |
| { 0xf, "0xf /* IF_??? */" }, |
| { 0x10, "IF_RS_SENT" }, |
| { 0xc0, "IF_RA_MANAGED|IF_RA_OTHERCONF" }, |
| { 0xdeadc0de, "IF_RS_SENT|IF_RA_MANAGED|IF_RA_OTHERCONF" |
| "|IF_READY|0x5eadc00e" }, |
| }; |
| |
| for (size_t i = 0; i < ARRAY_SIZE(inet6_flags); i++) { |
| TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, |
| init_AF_INET6_msg, |
| print_AF_INET6_msg, |
| 1, "IFLA_INET6_FLAGS", pattern, |
| inet6_flags[i].flags, |
| print_quoted_hex, 2, |
| printf("%s", inet6_flags[i].str)); |
| } |
| |
| /* AF_INET6: IFLA_INET6_CONF */ |
| uint32_t inet6_conf_vals[] = { 0xdeadc0de, 0xda7aface }; |
| TEST_NESTED_NLATTR_ARRAY_EX(fd, nlh0, hdrlen, |
| init_AF_INET6_msg, print_AF_INET6_msg, |
| IFLA_INET6_CONF, pattern, |
| inet6_conf_vals, 2, print_inet6_conf_val); |
| |
| /* AF_INET6: IFLA_INET6_STATS */ |
| uint64_t inet6_stats_vals[] = { 0xdeadc0deda7aface, 0xdec0deedbadc0ded }; |
| TEST_NESTED_NLATTR_ARRAY_EX(fd, nlh0, hdrlen, |
| init_AF_INET6_msg, print_AF_INET6_msg, |
| IFLA_INET6_STATS, pattern, |
| inet6_stats_vals, 2, print_inet6_stats_val); |
| |
| /* AF_INET6: IFLA_INET6_MCAST */ |
| TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, |
| init_AF_INET6_msg, print_AF_INET6_msg, |
| 4, "IFLA_INET6_MCAST", pattern, |
| unknown_msg, print_quoted_hex, 2, |
| printf("\"\\xab\\xac\\xdb\\xcd\"")); |
| |
| /* AF_INET6: IFLA_INET6_CACHEINFO */ |
| static const struct ifla_cacheinfo ci = { |
| 0xbadc0ded, 0xfacebeef, 0xdecafeed, 0xdeadfeed, |
| }; |
| TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, |
| init_AF_INET6_msg, print_AF_INET6_msg, |
| 5, "IFLA_INET6_CACHEINFO", pattern, |
| ci, print_quoted_hex, 2, |
| PRINT_FIELD_U("{", ci, max_reasm_len); |
| PRINT_FIELD_U(", ", ci, tstamp); |
| PRINT_FIELD_U(", ", ci, reachable_time); |
| PRINT_FIELD_U(", ", ci, retrans_time); |
| printf("}")); |
| |
| /* AF_INET6: IFLA_INET6_ICMP6STATS */ |
| uint64_t icmp6_stats_vals[] = { |
| 0xdeadc0deda7aface, 0xdec0deedbadc0ded, 0xfacebeefdeadfeed, |
| 0xdeadc0deda7afacd, 0xdec0deedbadc0dee, 0xfacebeefdeadfeef, |
| 0xdeadc0deda7afacc |
| }; |
| TEST_NESTED_NLATTR_ARRAY_EX(fd, nlh0, hdrlen, |
| init_AF_INET6_msg, print_AF_INET6_msg, |
| IFLA_INET6_ICMP6STATS, pattern, |
| icmp6_stats_vals, 2, print_icmp6_stats_val); |
| |
| /* AF_INET6: IFLA_INET6_TOKEN */ |
| uint8_t inet6_addr[16] = { |
| 0xba, 0xdc, 0x0d, 0xed, 0xfa, 0xce, 0xbe, 0xef, |
| 0xde, 0xca, 0xfe, 0xed, 0xde, 0xad, 0xfe, 0xed, |
| }; |
| TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, |
| init_AF_INET6_msg, print_AF_INET6_msg, |
| 7, "IFLA_INET6_TOKEN", pattern, |
| inet6_addr, print_quoted_hex, 2, |
| printf("badc:ded:face:beef:deca:feed" |
| ":dead:feed")); |
| |
| /* AF_INET6: IFLA_INET6_ */ |
| static const struct { |
| uint8_t flags; |
| const char *str; |
| } agms[] = { |
| { 0x0, "IN6_ADDR_GEN_MODE_EUI64" }, |
| { 0x3, "IN6_ADDR_GEN_MODE_RANDOM" }, |
| { 0x4, "0x4 /* IN6_ADDR_GEN_MODE_??? */" }, |
| { 0xff, "0xff /* IN6_ADDR_GEN_MODE_??? */" }, |
| }; |
| |
| for (size_t i = 0; i < ARRAY_SIZE(agms); i++) { |
| TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, |
| init_AF_INET6_msg, |
| print_AF_INET6_msg, |
| 8, "IFLA_INET6_ADDR_GEN_MODE", |
| pattern, agms[i].flags, |
| print_quoted_hex, 2, |
| printf("%s", agms[i].str)); |
| } |
| |
| |
| puts("+++ exited with 0 +++"); |
| return 0; |
| } |