1 /*
2 * Copyright (c) 2021 Eugene Syromyatnikov <evgsyr@gmail.com>
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #include "tests.h"
9
10 #include <inttypes.h>
11 #include <stdbool.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <unistd.h>
15
16 #include "test_netlink.h"
17 #include "test_nlattr.h"
18
19 #include <linux/ip.h>
20 #include <linux/rtnetlink.h>
21 #include <linux/mroute.h>
22 #include <linux/mroute6.h>
23
24 #include "xlat.h"
25 #include "xlat/addrfams.h"
26
27 static uint8_t af;
28 static char af_str[256];
29
30 /* uses global "af" variable */
31 static void
32 init_rtgen(struct nlmsghdr *const nlh, const unsigned int msg_len)
33 {
34 SET_STRUCT(struct nlmsghdr, nlh,
35 .nlmsg_len = msg_len,
36 .nlmsg_type = RTM_NEWCACHEREPORT,
37 .nlmsg_flags = NLM_F_EXCL|NLM_F_APPEND,
38 );
39
40 struct rtgenmsg *const msg = NLMSG_DATA(nlh);
41 SET_STRUCT(struct rtgenmsg, msg,
42 .rtgen_family = af,
43 );
44 }
45
46 static void
47 print_rtgen(const unsigned int msg_len)
48 {
49 printf("{nlmsg_len=%u, nlmsg_type=" XLAT_FMT ", nlmsg_flags=" XLAT_FMT
50 ", nlmsg_seq=0, nlmsg_pid=0}, {rtgen_family=%s}",
51 msg_len, XLAT_ARGS(RTM_NEWCACHEREPORT),
52 XLAT_ARGS(NLM_F_EXCL|NLM_F_APPEND), af_str);
53 }
54
55 int
56 main(void)
57 {
58 static const uint8_t unknown_msg[] = { 0xab, 0xac, 0xdb, 0xcd };
59
60 skip_if_unavailable("/proc/self/fd/");
61
62 const int fd = create_nl_socket(NETLINK_ROUTE);
63
64 const unsigned int hdrlen = sizeof(struct rtgenmsg);
65 void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), NLA_HDRLEN + 16);
66
67 static char pattern[4096];
68 fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
69
70
71 /* unknown AF_* */
72 static uint8_t skip_afs[] = { RTNL_FAMILY_IPMR, RTNL_FAMILY_IP6MR };
73 struct {
74 struct rtgenmsg ATTRIBUTE_ALIGNED(NLMSG_ALIGNTO) hdr;
75 struct {
76 char str[sizeof(unknown_msg)];
77 } ATTRIBUTE_ALIGNED(NLMSG_ALIGNTO) payload;
78 } buf;
79 memcpy(buf.payload.str, unknown_msg, sizeof(unknown_msg));
80 size_t pos = 0;
81 for (size_t i = 0; i < 256; i++) {
82 if (pos < ARRAY_SIZE(skip_afs) && skip_afs[pos] == i) {
83 pos += 1;
84 continue;
85 }
86
87 buf.hdr.rtgen_family = i;
88 TEST_NETLINK_(fd, nlh0, RTM_NEWCACHEREPORT,
89 XLAT_KNOWN(0x60, "RTM_NEWCACHEREPORT"),
90 NLM_F_REPLACE,
91 XLAT_KNOWN(0x100, "NLM_F_REPLACE"),
92 sizeof(buf), &buf, sizeof(buf),
93 printf("{rtgen_family=%s}"
94 ", \"\\xab\\xac\\xdb\\xcd\"",
95 sprintxval(addrfams, i,
96 "RTNL_FAMILY_???")));
97 }
98
99
100 /* RTNL_FAMILY_IPMR */
101 af = RTNL_FAMILY_IPMR;
102 snprintf(af_str, sizeof(af_str), XLAT_FMT, XLAT_ARGS(RTNL_FAMILY_IPMR));
103
104 /* RTNL_FAMILY_IPMR: unknown, undecoded */
105 static const struct strval16 unk_attrs[] = {
106 { ENUM_KNOWN(0, IPMRA_CREPORT_UNSPEC) },
107 { ENUM_KNOWN(0x5, IPMRA_CREPORT_PKT) },
108 { ARG_XLAT_UNKNOWN(0x7, "IPMRA_CREPORT_???") },
109 { ARG_XLAT_UNKNOWN(0x1ead, "IPMRA_CREPORT_???") },
110 };
111
112 for (size_t i = 0; i < ARRAY_SIZE(unk_attrs); i++) {
113 TEST_NLATTR_(fd, nlh0, hdrlen, init_rtgen, print_rtgen,
114 unk_attrs[i].val, unk_attrs[i].str,
115 16, pattern, 16,
116 print_quoted_hex(pattern, 16));
117 }
118
119 /* RTNL_FAMILY_IPMR: IPMRA_CREPORT_MSGTYPE */
120 static const struct strval8 mr_msg_types[] = {
121 { ARG_XLAT_UNKNOWN(0, "IGMPMSG_???") },
122 { ARG_XLAT_KNOWN(0x1, "IGMPMSG_NOCACHE") },
123 { ARG_XLAT_KNOWN(0x2, "IGMPMSG_WRONGVIF") },
124 { ARG_XLAT_KNOWN(0x3, "IGMPMSG_WHOLEPKT") },
125 { ARG_XLAT_KNOWN(0x4, "IGMPMSG_WRVIFWHOLE") },
126 { ARG_XLAT_UNKNOWN(0x5, "IGMPMSG_???") },
127 { ARG_XLAT_UNKNOWN(0xca, "IGMPMSG_???") },
128 };
129 for (size_t i = 0; i < ARRAY_SIZE(mr_msg_types); i++) {
130 TEST_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
131 init_rtgen, print_rtgen,
132 IPMRA_CREPORT_MSGTYPE,
133 XLAT_KNOWN(0x1, "IPMRA_CREPORT_MSGTYPE"),
134 pattern, mr_msg_types[i].val, 1,
135 print_quoted_hex,
136 printf("%s", mr_msg_types[i].str));
137 }
138
139 /* RTNL_FAMILY_IPMR: u32 */
140 static const struct strval16 u32_mr_attrs[] = {
141 { ENUM_KNOWN(0x2, IPMRA_CREPORT_VIF_ID) },
142 { ENUM_KNOWN(0x6, IPMRA_CREPORT_TABLE) },
143 };
144 void *nlh_u32 = midtail_alloc(NLMSG_SPACE(hdrlen),
145 NLA_HDRLEN + sizeof(uint32_t));
146 for (size_t i = 0; i < ARRAY_SIZE(u32_mr_attrs); i++) {
147 check_u32_nlattr(fd, nlh_u32, hdrlen, init_rtgen, print_rtgen,
148 u32_mr_attrs[i].val, u32_mr_attrs[i].str,
149 pattern, 0);
150 }
151
152 /* RTNL_FAMILY_IPMR: in_addr */
153 static const struct strval16 in_addr_attrs[] = {
154 { ENUM_KNOWN(0x3, IPMRA_CREPORT_SRC_ADDR) },
155 { ENUM_KNOWN(0x4, IPMRA_CREPORT_DST_ADDR) },
156 };
157 static uint32_t ipv4_addr = BE32(0xdeadface);
158 for (size_t i = 0; i < ARRAY_SIZE(in_addr_attrs); i++) {
159 TEST_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
160 init_rtgen, print_rtgen,
161 in_addr_attrs[i].val,
162 in_addr_attrs[i].str,
163 pattern, ipv4_addr, 4,
164 print_quoted_hex,
165 printf(XLAT_KNOWN_FMT(
166 "\"\\xde\\xad\\xfa\\xce\"",
167 "inet_addr(\"222.173.250.206\")"))
168 );
169 }
170
171
172 /* RTNL_FAMILY_IP6MR */
173 af = RTNL_FAMILY_IP6MR;
174 snprintf(af_str, sizeof(af_str), XLAT_FMT,
175 XLAT_ARGS(RTNL_FAMILY_IP6MR));
176
177 /* RTNL_FAMILY_IP6MR: unknown, undecoded */
178 static const struct strval16 unk6_attrs[] = {
179 { ENUM_KNOWN(0, IP6MRA_CREPORT_UNSPEC) },
180 { ENUM_KNOWN(0x5, IP6MRA_CREPORT_PKT) },
181 { ARG_XLAT_UNKNOWN(0x6, "IP6MRA_CREPORT_???") },
182 { ARG_XLAT_UNKNOWN(0x1ead, "IP6MRA_CREPORT_???") },
183 };
184
185 for (size_t i = 0; i < ARRAY_SIZE(unk6_attrs); i++) {
186 TEST_NLATTR_(fd, nlh0, hdrlen, init_rtgen, print_rtgen,
187 unk6_attrs[i].val, unk6_attrs[i].str,
188 16, pattern, 16,
189 print_quoted_hex(pattern, 16));
190 }
191
192 /* RTNL_FAMILY_IP6MR: IP6MRA_CREPORT_MSGTYPE */
193 static const struct strval8 mr6_msg_types[] = {
194 { ARG_XLAT_UNKNOWN(0, "MRT6MSG_???") },
195 { ARG_XLAT_KNOWN(0x1, "MRT6MSG_NOCACHE") },
196 { ARG_XLAT_KNOWN(0x2, "MRT6MSG_WRONGMIF") },
197 { ARG_XLAT_KNOWN(0x3, "MRT6MSG_WHOLEPKT") },
198 { ARG_XLAT_UNKNOWN(0x4, "MRT6MSG_???") },
199 { ARG_XLAT_UNKNOWN(0xca, "MRT6MSG_???") },
200 };
201 for (size_t i = 0; i < ARRAY_SIZE(mr6_msg_types); i++) {
202 TEST_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
203 init_rtgen, print_rtgen,
204 IP6MRA_CREPORT_MSGTYPE,
205 XLAT_KNOWN(0x1,
206 "IP6MRA_CREPORT_MSGTYPE"),
207 pattern, mr6_msg_types[i].val, 1,
208 print_quoted_hex,
209 printf("%s", mr6_msg_types[i].str));
210 }
211
212 /* RTNL_FAMILY_IP6MR: u32 */
213 static const struct strval16 u32_mr6_attrs[] = {
214 { ENUM_KNOWN(0x2, IP6MRA_CREPORT_MIF_ID) },
215 };
216 for (size_t i = 0; i < ARRAY_SIZE(u32_mr6_attrs); i++) {
217 check_u32_nlattr(fd, nlh_u32, hdrlen, init_rtgen, print_rtgen,
218 u32_mr6_attrs[i].val, u32_mr6_attrs[i].str,
219 pattern, 0);
220 }
221
222 /* RTNL_FAMILY_IPMR: in6_addr */
223 static const struct strval16 in6_addr_attrs[] = {
224 { ENUM_KNOWN(0x3, IP6MRA_CREPORT_SRC_ADDR) },
225 { ENUM_KNOWN(0x4, IP6MRA_CREPORT_DST_ADDR) },
226 };
227 uint8_t ipv6_addr[16] = {
228 0xba, 0xdc, 0x0d, 0xed, 0xfa, 0xce, 0xbe, 0xef,
229 0xde, 0xca, 0xfe, 0xed, 0xde, 0xad, 0xfe, 0xed,
230 };
231 for (size_t i = 0; i < ARRAY_SIZE(in6_addr_attrs); i++) {
232 TEST_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
233 init_rtgen, print_rtgen,
234 in6_addr_attrs[i].val,
235 in6_addr_attrs[i].str,
236 pattern, ipv6_addr, 16,
237 print_quoted_hex,
238 printf(XLAT_KNOWN_FMT(
239 "\"\\xba\\xdc\\x0d\\xed"
240 "\\xfa\\xce\\xbe\\xef"
241 "\\xde\\xca\\xfe\\xed"
242 "\\xde\\xad\\xfe\\xed\"",
243 "inet_pton(AF_INET6"
244 ", \"badc:ded:face:beef"
245 ":deca:feed:dead:feed\")")));
246 }
247
248 puts("+++ exited with 0 +++");
249 return 0;
250 }