1 /*
2 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
3 * Copyright (c) 2017-2022 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "tests.h"
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <sys/socket.h>
14 #include <arpa/inet.h>
15 #include <net/if.h>
16 #include <netinet/tcp.h>
17 #include "test_nlattr.h"
18 #include <linux/inet_diag.h>
19 #include <linux/rtnetlink.h>
20 #include <linux/sock_diag.h>
21
22 static const char address[] = "10.11.12.13";
23 static const unsigned int hdrlen = sizeof(struct inet_diag_req_v2);
24 static void *nlh0;
25 static char pattern[4096];
26
27 static void
28 init_inet_diag_req_v2(struct nlmsghdr *const nlh, const unsigned int msg_len)
29 {
30 SET_STRUCT(struct nlmsghdr, nlh,
31 .nlmsg_len = msg_len,
32 .nlmsg_type = SOCK_DIAG_BY_FAMILY,
33 .nlmsg_flags = NLM_F_REQUEST
34 );
35
36 struct inet_diag_req_v2 *const req = NLMSG_DATA(nlh);
37 SET_STRUCT(struct inet_diag_req_v2, req,
38 .sdiag_family = AF_INET,
39 .idiag_ext = 1 << (INET_DIAG_CONG - 1),
40 .sdiag_protocol = IPPROTO_TCP,
41 .idiag_states = 1 << TCP_CLOSE,
42 .id.idiag_if = ifindex_lo()
43 );
44
45 if (!inet_pton(AF_INET, address, req->id.idiag_src) ||
46 !inet_pton(AF_INET, address, req->id.idiag_dst))
47 perror_msg_and_skip("inet_pton");
48 }
49
50 static void
51 print_inet_diag_req_v2(const unsigned int msg_len)
52 {
53 printf("{nlmsg_len=%u, nlmsg_type=SOCK_DIAG_BY_FAMILY"
54 ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}"
55 ", {sdiag_family=AF_INET, sdiag_protocol=IPPROTO_TCP"
56 ", idiag_ext=1<<(INET_DIAG_CONG-1)"
57 ", idiag_states=1<<TCP_CLOSE"
58 ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
59 ", idiag_src=inet_addr(\"%s\")"
60 ", idiag_dst=inet_addr(\"%s\")"
61 ", idiag_if=" IFINDEX_LO_STR
62 ", idiag_cookie=[0, 0]}}",
63 msg_len, address, address);
64 }
65
66 static void
67 test_unk_attrs(const int fd)
68 {
69 static const struct strval16 unk_attrs[] = {
70 { ENUM_KNOWN(0, INET_DIAG_REQ_NONE) },
71 { ENUM_KNOWN(0x2, INET_DIAG_REQ_SK_BPF_STORAGES) },
72 { ARG_XLAT_UNKNOWN(0x4, "INET_DIAG_REQ_???") },
73 { ARG_XLAT_UNKNOWN(0x1ace, "INET_DIAG_REQ_???") },
74 };
75 static const char buf[4] = { 0xde, 0xad, 0xfa, 0xce };
76
77 for (size_t i = 0; i < ARRAY_SIZE(unk_attrs); i++) {
78 TEST_NLATTR_(fd, nlh0, hdrlen,
79 init_inet_diag_req_v2, print_inet_diag_req_v2,
80 unk_attrs[i].val, unk_attrs[i].str,
81 sizeof(buf), buf, sizeof(buf),
82 print_quoted_hex(buf, sizeof(buf)));
83 }
84 }
85
86 static void
87 test_inet_diag_bc_op(const int fd)
88 {
89 static const struct inet_diag_bc_op op = {
90 .code = INET_DIAG_BC_S_COND,
91 .yes = 0xaf,
92 .no = 0xafcd
93 };
94 TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
95 init_inet_diag_req_v2, print_inet_diag_req_v2,
96 INET_DIAG_REQ_BYTECODE, pattern, op,
97 printf("{code=INET_DIAG_BC_S_COND");
98 printf(", ");
99 PRINT_FIELD_U(op, yes);
100 printf(", ");
101 PRINT_FIELD_U(op, no);
102 printf("}"));
103 }
104
105 static void
106 print_inet_diag_bc_op(const char *const code)
107 {
108 printf("{code=%s, yes=0, no=0}, ", code);
109 }
110
111 static void
112 test_inet_diag_bc_s_cond(const int fd)
113 {
114 static const struct inet_diag_bc_op op = {
115 .code = INET_DIAG_BC_S_COND,
116 };
117 static const struct inet_diag_hostcond cond = {
118 .family = AF_UNSPEC,
119 .prefix_len = 0xad,
120 .port = 0xadfa
121 };
122 char buf[sizeof(op) + sizeof(cond)];
123 memcpy(buf, &op, sizeof(op));
124
125 const unsigned int plen = sizeof(cond) - 1 > DEFAULT_STRLEN ?
126 sizeof(op) + DEFAULT_STRLEN : sizeof(buf) - 1;
127 memcpy(buf + sizeof(op), &pattern, sizeof(cond));
128 TEST_NLATTR(fd, nlh0, hdrlen,
129 init_inet_diag_req_v2, print_inet_diag_req_v2,
130 INET_DIAG_REQ_BYTECODE,
131 plen, buf, plen,
132 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
133 print_quoted_hex(buf + sizeof(op), plen - sizeof(op)));
134
135 TEST_NLATTR(fd, nlh0, hdrlen,
136 init_inet_diag_req_v2, print_inet_diag_req_v2,
137 INET_DIAG_REQ_BYTECODE,
138 sizeof(buf), buf, sizeof(buf) - 1,
139 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
140 printf("%p", RTA_DATA(TEST_NLATTR_nla) + sizeof(op)));
141
142 memcpy(buf + sizeof(op), &cond, sizeof(cond));
143 TEST_NLATTR(fd, nlh0, hdrlen,
144 init_inet_diag_req_v2, print_inet_diag_req_v2,
145 INET_DIAG_REQ_BYTECODE,
146 sizeof(buf), buf, sizeof(buf),
147 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
148 printf("{family=AF_UNSPEC");
149 printf(", ");
150 PRINT_FIELD_U(cond, prefix_len);
151 printf(", ");
152 PRINT_FIELD_U(cond, port);
153 printf("}"));
154 }
155
156 static void
157 print_inet_diag_hostcond(const char *const family)
158 {
159 printf("{family=%s, prefix_len=0, port=0, ", family);
160 }
161
162 static void
163 test_in_addr(const int fd)
164 {
165 static const struct inet_diag_bc_op op = {
166 .code = INET_DIAG_BC_S_COND,
167 };
168 static const struct inet_diag_hostcond cond = {
169 .family = AF_INET,
170 };
171 struct in_addr addr;
172 if (!inet_pton(AF_INET, address, &addr))
173 perror_msg_and_skip("inet_pton");
174
175 char buf[sizeof(op) + sizeof(cond) + sizeof(addr)];
176 memcpy(buf, &op, sizeof(op));
177 memcpy(buf + sizeof(op), &cond, sizeof(cond));
178
179 const unsigned int plen = sizeof(addr) - 1 > DEFAULT_STRLEN ?
180 sizeof(cond) + sizeof(cond) + DEFAULT_STRLEN : sizeof(buf) - 1;
181 memcpy(buf + sizeof(op) + sizeof(cond), &pattern, sizeof(addr));
182 TEST_NLATTR(fd, nlh0, hdrlen,
183 init_inet_diag_req_v2, print_inet_diag_req_v2,
184 INET_DIAG_REQ_BYTECODE,
185 plen, buf, plen,
186 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
187 print_inet_diag_hostcond("AF_INET");
188 printf("addr=");
189 print_quoted_hex(pattern, plen - sizeof(op) - sizeof(cond));
190 printf("}"));
191
192 TEST_NLATTR(fd, nlh0, hdrlen,
193 init_inet_diag_req_v2, print_inet_diag_req_v2,
194 INET_DIAG_REQ_BYTECODE,
195 sizeof(buf), buf, sizeof(buf) - 1,
196 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
197 print_inet_diag_hostcond("AF_INET");
198 printf("addr=%p}",
199 RTA_DATA(TEST_NLATTR_nla)
200 + sizeof(op) + sizeof(cond)));
201
202 memcpy(buf + sizeof(op) + sizeof(cond), &addr, sizeof(addr));
203 TEST_NLATTR(fd, nlh0, hdrlen,
204 init_inet_diag_req_v2, print_inet_diag_req_v2,
205 INET_DIAG_REQ_BYTECODE,
206 sizeof(buf), buf, sizeof(buf),
207 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
208 print_inet_diag_hostcond("AF_INET");
209 printf("addr=inet_addr(\"%s\")}", address));
210 }
211
212 static void
213 test_in6_addr(const int fd)
214 {
215 const char address6[] = "12:34:56:78:90:ab:cd:ef";
216 static const struct inet_diag_bc_op op = {
217 .code = INET_DIAG_BC_S_COND,
218 };
219 static const struct inet_diag_hostcond cond = {
220 .family = AF_INET6,
221 };
222 struct in6_addr addr;
223 if (!inet_pton(AF_INET6, address6, &addr))
224 perror_msg_and_skip("inet_pton");
225
226 char buf[sizeof(op) + sizeof(cond) + sizeof(addr)];
227 memcpy(buf, &op, sizeof(op));
228 memcpy(buf + sizeof(op), &cond, sizeof(cond));
229
230 const unsigned int plen = sizeof(addr) - 1 > DEFAULT_STRLEN ?
231 sizeof(cond) + sizeof(cond) + DEFAULT_STRLEN : sizeof(buf) - 1;
232 memcpy(buf + sizeof(op) + sizeof(cond), &pattern, sizeof(addr));
233 TEST_NLATTR(fd, nlh0, hdrlen,
234 init_inet_diag_req_v2, print_inet_diag_req_v2,
235 INET_DIAG_REQ_BYTECODE,
236 plen, buf, plen,
237 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
238 print_inet_diag_hostcond("AF_INET6");
239 printf("addr=");
240 print_quoted_hex(pattern, plen - sizeof(op) - sizeof(cond));
241 printf("}"));
242
243 TEST_NLATTR(fd, nlh0, hdrlen,
244 init_inet_diag_req_v2, print_inet_diag_req_v2,
245 INET_DIAG_REQ_BYTECODE,
246 sizeof(buf), buf, sizeof(buf) - 1,
247 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
248 print_inet_diag_hostcond("AF_INET6");
249 printf("addr=%p}",
250 RTA_DATA(TEST_NLATTR_nla)
251 + sizeof(op) + sizeof(cond)));
252
253 memcpy(buf + sizeof(op) + sizeof(cond), &addr, sizeof(addr));
254 TEST_NLATTR(fd, nlh0, hdrlen,
255 init_inet_diag_req_v2, print_inet_diag_req_v2,
256 INET_DIAG_REQ_BYTECODE,
257 sizeof(buf), buf, sizeof(buf),
258 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
259 print_inet_diag_hostcond("AF_INET6");
260 printf("inet_pton(AF_INET6, \"%s\", &addr)}", address6));
261 }
262
263 static void
264 test_inet_diag_bc_dev_cond(const int fd)
265 {
266 static const struct inet_diag_bc_op op = {
267 .code = INET_DIAG_BC_DEV_COND,
268 };
269 const uint32_t ifindex = ifindex_lo();
270 char buf[sizeof(op) + sizeof(ifindex)];
271 memcpy(buf, &op, sizeof(op));
272 memcpy(buf + sizeof(op), pattern, sizeof(ifindex));
273
274 TEST_NLATTR(fd, nlh0, hdrlen,
275 init_inet_diag_req_v2, print_inet_diag_req_v2,
276 INET_DIAG_REQ_BYTECODE,
277 sizeof(buf) - 1, buf, sizeof(buf) - 1,
278 print_inet_diag_bc_op("INET_DIAG_BC_DEV_COND");
279 print_quoted_hex(pattern, sizeof(ifindex) - 1));
280
281 TEST_NLATTR(fd, nlh0, hdrlen,
282 init_inet_diag_req_v2, print_inet_diag_req_v2,
283 INET_DIAG_REQ_BYTECODE,
284 sizeof(buf), buf, sizeof(buf) - 1,
285 print_inet_diag_bc_op("INET_DIAG_BC_DEV_COND");
286 printf("%p", RTA_DATA(TEST_NLATTR_nla) + sizeof(op)));
287
288 memcpy(buf + sizeof(op), &ifindex, sizeof(ifindex));
289 TEST_NLATTR(fd, nlh0, hdrlen,
290 init_inet_diag_req_v2, print_inet_diag_req_v2,
291 INET_DIAG_REQ_BYTECODE,
292 sizeof(buf), buf, sizeof(buf),
293 print_inet_diag_bc_op("INET_DIAG_BC_DEV_COND");
294 printf(IFINDEX_LO_STR));
295 }
296
297 static void
298 test_inet_diag_bc_s_le(const int fd)
299 {
300 static const struct inet_diag_bc_op op[] = {
301 {
302 .code = INET_DIAG_BC_S_LE,
303 },
304 {
305 .code = INET_DIAG_BC_DEV_COND,
306 .yes = 0xaf,
307 .no = 0xafcd
308 }
309 };
310
311 char buf[sizeof(op)];
312 memcpy(buf, op, sizeof(op[0]));
313 memcpy(buf + sizeof(op[0]), pattern, sizeof(op[1]));
314
315 const unsigned int plen = sizeof(op[1]) - 1 > DEFAULT_STRLEN ?
316 sizeof(op[0]) + DEFAULT_STRLEN : sizeof(buf) - 1;
317 TEST_NLATTR(fd, nlh0, hdrlen,
318 init_inet_diag_req_v2, print_inet_diag_req_v2,
319 INET_DIAG_REQ_BYTECODE,
320 plen, buf, plen,
321 print_inet_diag_bc_op("INET_DIAG_BC_S_LE");
322 print_quoted_hex(buf + sizeof(op[0]), plen - sizeof(op[0])));
323
324 TEST_NLATTR(fd, nlh0, hdrlen,
325 init_inet_diag_req_v2, print_inet_diag_req_v2,
326 INET_DIAG_REQ_BYTECODE,
327 sizeof(buf), buf, sizeof(buf) - 1,
328 print_inet_diag_bc_op("INET_DIAG_BC_S_LE");
329 printf("%p", RTA_DATA(TEST_NLATTR_nla) + sizeof(op[0])));
330
331 memcpy(buf + sizeof(op[0]), &op[1], sizeof(op[1]));
332 TEST_NLATTR(fd, nlh0, hdrlen,
333 init_inet_diag_req_v2, print_inet_diag_req_v2,
334 INET_DIAG_REQ_BYTECODE,
335 sizeof(buf), buf, sizeof(buf),
336 print_inet_diag_bc_op("INET_DIAG_BC_S_LE");
337 printf("{code=INET_DIAG_BC_DEV_COND");
338 printf(", ");
339 PRINT_FIELD_U(op[1], yes);
340 printf(", ");
341 PRINT_FIELD_U(op[1], no);
342 printf("}"));
343 };
344
345 static void
346 test_inet_diag_bc_mark_cond(const int fd)
347 {
348 static const struct inet_diag_bc_op op = {
349 .code = INET_DIAG_BC_MARK_COND,
350 };
351 static const struct inet_diag_markcond markcond = {
352 .mark = 0xafbcafcd,
353 .mask = 0xbafaacda
354 };
355 char buf[sizeof(op) + sizeof(markcond)];
356 memcpy(buf, &op, sizeof(op));
357 memcpy(buf + sizeof(op), pattern, sizeof(markcond));
358
359 const unsigned int plen = sizeof(markcond) - 1 > DEFAULT_STRLEN ?
360 sizeof(markcond) + DEFAULT_STRLEN : sizeof(buf) - 1;
361 TEST_NLATTR(fd, nlh0, hdrlen,
362 init_inet_diag_req_v2, print_inet_diag_req_v2,
363 INET_DIAG_REQ_BYTECODE,
364 plen, buf, plen,
365 print_inet_diag_bc_op("INET_DIAG_BC_MARK_COND");
366 print_quoted_hex(buf + sizeof(op), plen - sizeof(op)));
367
368 TEST_NLATTR(fd, nlh0, hdrlen,
369 init_inet_diag_req_v2, print_inet_diag_req_v2,
370 INET_DIAG_REQ_BYTECODE,
371 sizeof(buf), buf, sizeof(buf) - 1,
372 print_inet_diag_bc_op("INET_DIAG_BC_MARK_COND");
373 printf("%p", RTA_DATA(TEST_NLATTR_nla) + sizeof(op)));
374
375 memcpy(buf + sizeof(op), &markcond, sizeof(markcond));
376 TEST_NLATTR(fd, nlh0, hdrlen,
377 init_inet_diag_req_v2, print_inet_diag_req_v2,
378 INET_DIAG_REQ_BYTECODE,
379 sizeof(buf), buf, sizeof(buf),
380 print_inet_diag_bc_op("INET_DIAG_BC_MARK_COND");
381 printf("{");
382 PRINT_FIELD_U(markcond, mark);
383 printf(", ");
384 PRINT_FIELD_U(markcond, mask);
385 printf("}"));
386 }
387
388 static void
389 test_inet_diag_bc_nop(const int fd)
390 {
391 static const struct inet_diag_bc_op op = {
392 .code = INET_DIAG_BC_AUTO,
393 };
394 char buf[sizeof(op) + 4];
395 memcpy(buf, &op, sizeof(op));
396 memcpy(buf + sizeof(op), pattern, 4);
397
398 TEST_NLATTR(fd, nlh0, hdrlen,
399 init_inet_diag_req_v2, print_inet_diag_req_v2,
400 INET_DIAG_REQ_BYTECODE,
401 sizeof(buf), buf, sizeof(buf),
402 print_inet_diag_bc_op("INET_DIAG_BC_AUTO");
403 print_quoted_hex(buf + sizeof(op),
404 sizeof(buf) - sizeof(op)));
405 }
406
407 static void
408 test_inet_diag_proto(const int fd)
409 {
410 static const struct strval32 protos[] = {
411 { 0, "IPPROTO_IP" },
412 { 3, "0x3 /* IPPROTO_??? */" },
413 { 6, "IPPROTO_TCP" },
414 { 255, "IPPROTO_RAW" },
415 { 256, "0x100 /* IPPROTO_??? */" },
416 { 262, "IPPROTO_MPTCP" },
417 { 0xcafeface, "0xcafeface /* IPPROTO_??? */" },
418 };
419
420 for (size_t i = 0; i < ARRAY_SIZE(protos); i++) {
421 TEST_NLATTR(fd, nlh0, hdrlen,
422 init_inet_diag_req_v2, print_inet_diag_req_v2,
423 INET_DIAG_REQ_PROTOCOL,
424 sizeof(uint32_t), &protos[i].val, sizeof(uint32_t),
425 printf("%s", protos[i].str));
426 }
427 }
428
429 int
430 main(void)
431 {
432 skip_if_unavailable("/proc/self/fd/");
433
434 int fd = create_nl_socket(NETLINK_SOCK_DIAG);
435 nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), NLA_HDRLEN +
436 sizeof(struct inet_diag_bc_op) +
437 sizeof(struct inet_diag_hostcond) +
438 sizeof(struct in6_addr) + DEFAULT_STRLEN);
439 fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
440
441 test_unk_attrs(fd);
442 test_inet_diag_bc_op(fd);
443 test_inet_diag_bc_s_cond(fd);
444 test_in_addr(fd);
445 test_in6_addr(fd);
446 test_inet_diag_bc_dev_cond(fd);
447 test_inet_diag_bc_s_le(fd);
448 test_inet_diag_bc_mark_cond(fd);
449 test_inet_diag_bc_nop(fd);
450 test_inet_diag_proto(fd);
451
452 printf("+++ exited with 0 +++\n");
453 return 0;
454 }