1 /*
2  * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
3  * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
4  * Copyright (c) 2017-2018 The strace developers.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "tests.h"
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdint.h>
34 #include <unistd.h>
35 #include <sys/socket.h>
36 #include <arpa/inet.h>
37 #include <netinet/tcp.h>
38 #include "test_netlink.h"
39 #include <linux/if_ether.h>
40 #include <linux/inet_diag.h>
41 #include <linux/netlink_diag.h>
42 #include <linux/packet_diag.h>
43 #ifdef AF_SMC
44 # include <linux/smc_diag.h>
45 #endif
46 #include <linux/sock_diag.h>
47 #include <linux/unix_diag.h>
48 
49 #define SMC_ACTIVE 1
50 
51 #define TEST_SOCK_DIAG(fd_, nlh0_,					\
52 		       family_, type_, flags_,				\
53 		       obj_, print_family_, ...)			\
54 									\
55 	do {								\
56 		/* family only */					\
57 		uint8_t family = (family_);				\
58 		TEST_NETLINK_((fd_), (nlh0_),				\
59 			      type_, #type_,				\
60 			      flags_, #flags_,				\
61 			      sizeof(family), &family, sizeof(family),	\
62 			      printf("{family=%s}", #family_));		\
63 									\
64 		/* family and string */					\
65 		char buf[sizeof(family) + 4];				\
66 		memcpy(buf, &family, sizeof(family));			\
67 		memcpy(buf + sizeof(family), "1234", 4);		\
68 		TEST_NETLINK_((fd_), (nlh0_),				\
69 			      type_, #type_,				\
70 			      flags_, #flags_,				\
71 			      sizeof(buf), buf, sizeof(buf),		\
72 			      (print_family_);				\
73 			      printf(", ...}"));			\
74 									\
75 		/* sizeof(obj_) */					\
76 		TEST_NETLINK_((fd_), (nlh0_),				\
77 			      type_, #type_,				\
78 			      flags_, #flags_,				\
79 			      sizeof(obj_), &(obj_), sizeof(obj_),	\
80 			      (print_family_);				\
81 			      __VA_ARGS__);				\
82 									\
83 		/* short read of sizeof(obj_) */			\
84 		TEST_NETLINK_((fd_), (nlh0_),				\
85 			      type_, #type_,				\
86 			      flags_, #flags_,				\
87 			      sizeof(obj_), &(obj_), sizeof(obj_) - 1,	\
88 			      (print_family_);				\
89 			      printf(", %p}",				\
90 				     NLMSG_DATA(TEST_NETLINK_nlh) + 1));\
91 	} while (0)
92 
93 static void
test_nlmsg_type(const int fd)94 test_nlmsg_type(const int fd)
95 {
96 	long rc;
97 	struct nlmsghdr nlh = {
98 		.nlmsg_len = sizeof(nlh),
99 		.nlmsg_type = SOCK_DIAG_BY_FAMILY,
100 		.nlmsg_flags = NLM_F_REQUEST,
101 	};
102 
103 	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
104 	printf("sendto(%d, {len=%u, type=SOCK_DIAG_BY_FAMILY"
105 	       ", flags=NLM_F_REQUEST, seq=0, pid=0}"
106 	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
107 	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
108 }
109 
110 static void
test_nlmsg_flags(const int fd)111 test_nlmsg_flags(const int fd)
112 {
113 	long rc;
114 	struct nlmsghdr nlh = {
115 		.nlmsg_len = sizeof(nlh),
116 		.nlmsg_type = SOCK_DIAG_BY_FAMILY,
117 		.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
118 	};
119 
120 	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
121 	printf("sendto(%d, {len=%u, type=SOCK_DIAG_BY_FAMILY"
122 	       ", flags=NLM_F_REQUEST|NLM_F_DUMP, seq=0, pid=0}"
123 	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
124 	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
125 }
126 
127 static void
test_odd_family_req(const int fd)128 test_odd_family_req(const int fd)
129 {
130 	uint8_t family = 0;
131 	char buf[sizeof(family) + 4];
132 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(buf));
133 
134 	/* unspecified family only */
135 	TEST_NETLINK(fd, nlh0,
136 		     SOCK_DIAG_BY_FAMILY,
137 		     NLM_F_REQUEST,
138 		     sizeof(family), &family, sizeof(family),
139 		     printf("{family=AF_UNSPEC}"));
140 
141 	/* unknown family only */
142 	family = 0xff;
143 	TEST_NETLINK(fd, nlh0,
144 		     SOCK_DIAG_BY_FAMILY,
145 		     NLM_F_REQUEST,
146 		     sizeof(family), &family, sizeof(family),
147 		     printf("{family=%#x /* AF_??? */}", family));
148 
149 	/* short read of family */
150 	TEST_NETLINK(fd, nlh0,
151 		     SOCK_DIAG_BY_FAMILY,
152 		     NLM_F_REQUEST,
153 		     sizeof(family), &family, sizeof(family) - 1,
154 		     printf("%p", NLMSG_DATA(TEST_NETLINK_nlh)));
155 
156 	/* unspecified family and string */
157 	family = 0;
158 	memcpy(buf, &family, sizeof(family));
159 	memcpy(buf + sizeof(family), "1234", 4);
160 	TEST_NETLINK(fd, nlh0,
161 		     SOCK_DIAG_BY_FAMILY,
162 		     NLM_F_REQUEST,
163 		     sizeof(buf), buf, sizeof(buf),
164 		     printf("{family=AF_UNSPEC, \"\\x31\\x32\\x33\\x34\"}"));
165 
166 	/* unknown family and string */
167 	family = 0xfd;
168 	memcpy(buf, &family, sizeof(family));
169 	TEST_NETLINK(fd, nlh0,
170 		     SOCK_DIAG_BY_FAMILY,
171 		     NLM_F_REQUEST,
172 		     sizeof(buf), buf, sizeof(buf),
173 		     printf("{family=%#x /* AF_??? */"
174 			    ", \"\\x31\\x32\\x33\\x34\"}", family));
175 }
176 
177 static void
test_odd_family_msg(const int fd)178 test_odd_family_msg(const int fd)
179 {
180 	uint8_t family = 0;
181 	char buf[sizeof(family) + 4];
182 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(buf));
183 
184 	/* unspecified family only */
185 	TEST_NETLINK(fd, nlh0,
186 		     SOCK_DIAG_BY_FAMILY, NLM_F_DUMP,
187 		     sizeof(family), &family, sizeof(family),
188 		     printf("{family=AF_UNSPEC}"));
189 
190 	/* unknown family only */
191 	family = 0xff;
192 	TEST_NETLINK(fd, nlh0,
193 		     SOCK_DIAG_BY_FAMILY, NLM_F_DUMP,
194 		     sizeof(family), &family, sizeof(family),
195 		     printf("{family=%#x /* AF_??? */}", family));
196 
197 	/* short read of family */
198 	TEST_NETLINK(fd, nlh0,
199 		     SOCK_DIAG_BY_FAMILY, NLM_F_DUMP,
200 		     sizeof(family), &family, sizeof(family) - 1,
201 		     printf("%p", NLMSG_DATA(TEST_NETLINK_nlh)));
202 
203 	/* unspecified family and string */
204 	family = 0;
205 	memcpy(buf, &family, sizeof(family));
206 	memcpy(buf + sizeof(family), "1234", 4);
207 	TEST_NETLINK(fd, nlh0,
208 		     SOCK_DIAG_BY_FAMILY, NLM_F_DUMP,
209 		     sizeof(buf), buf, sizeof(buf),
210 		     printf("{family=AF_UNSPEC, \"\\x31\\x32\\x33\\x34\"}"));
211 
212 	/* unknown family and string */
213 	family = 0xfd;
214 	memcpy(buf, &family, sizeof(family));
215 	TEST_NETLINK(fd, nlh0,
216 		     SOCK_DIAG_BY_FAMILY, NLM_F_DUMP,
217 		     sizeof(buf), buf, sizeof(buf),
218 		     printf("{family=%#x /* AF_??? */"
219 			    ", \"\\x31\\x32\\x33\\x34\"}", family));
220 }
221 
222 static void
test_unix_diag_req(const int fd)223 test_unix_diag_req(const int fd)
224 {
225 	static const struct unix_diag_req req = {
226 		.sdiag_family = AF_UNIX,
227 		.sdiag_protocol = 253,
228 		.udiag_states = 1 << TCP_ESTABLISHED | 1 << TCP_LISTEN,
229 		.udiag_ino = 0xfacefeed,
230 		.udiag_show = UDIAG_SHOW_NAME,
231 		.udiag_cookie = { 0xdeadbeef, 0xbadc0ded }
232 	};
233 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(req));
234 	TEST_SOCK_DIAG(fd, nlh0, AF_UNIX,
235 		       SOCK_DIAG_BY_FAMILY, NLM_F_REQUEST, req,
236 		       printf("{sdiag_family=AF_UNIX"),
237 		       PRINT_FIELD_U(", ", req, sdiag_protocol);
238 		       printf(", udiag_states=1<<TCP_ESTABLISHED|1<<TCP_LISTEN");
239 		       PRINT_FIELD_U(", ", req, udiag_ino);
240 		       printf(", udiag_show=UDIAG_SHOW_NAME");
241 		       PRINT_FIELD_COOKIE(", ", req, udiag_cookie);
242 		       printf("}"));
243 }
244 
245 static void
test_unix_diag_msg(const int fd)246 test_unix_diag_msg(const int fd)
247 {
248 	static const struct unix_diag_msg msg = {
249 		.udiag_family = AF_UNIX,
250 		.udiag_type = SOCK_STREAM,
251 		.udiag_state = TCP_FIN_WAIT1,
252 		.udiag_ino = 0xfacefeed,
253 		.udiag_cookie = { 0xdeadbeef, 0xbadc0ded }
254 	};
255 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
256 	TEST_SOCK_DIAG(fd, nlh0, AF_UNIX,
257 		       SOCK_DIAG_BY_FAMILY, NLM_F_DUMP, msg,
258 		       printf("{udiag_family=AF_UNIX"),
259 		       printf(", udiag_type=SOCK_STREAM"
260 			      ", udiag_state=TCP_FIN_WAIT1");
261 		       PRINT_FIELD_U(", ", msg, udiag_ino);
262 		       PRINT_FIELD_COOKIE(", ", msg, udiag_cookie);
263 		       printf("}"));
264 }
265 
266 static void
test_netlink_diag_req(const int fd)267 test_netlink_diag_req(const int fd)
268 {
269 	struct netlink_diag_req req = {
270 		.sdiag_family = AF_NETLINK,
271 		.sdiag_protocol = NDIAG_PROTO_ALL,
272 		.ndiag_ino = 0xfacefeed,
273 		.ndiag_show = NDIAG_SHOW_MEMINFO,
274 		.ndiag_cookie = { 0xdeadbeef, 0xbadc0ded }
275 	};
276 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(req));
277 	TEST_SOCK_DIAG(fd, nlh0, AF_NETLINK,
278 		       SOCK_DIAG_BY_FAMILY, NLM_F_REQUEST, req,
279 		       printf("{sdiag_family=AF_NETLINK"),
280 		       printf(", sdiag_protocol=NDIAG_PROTO_ALL");
281 		       PRINT_FIELD_U(", ", req, ndiag_ino);
282 		       printf(", ndiag_show=NDIAG_SHOW_MEMINFO");
283 		       PRINT_FIELD_COOKIE(", ", req, ndiag_cookie);
284 		       printf("}"));
285 
286 	req.sdiag_protocol = NETLINK_ROUTE;
287 	req.ndiag_show = NDIAG_SHOW_GROUPS;
288 	TEST_SOCK_DIAG(fd, nlh0, AF_NETLINK,
289 		       SOCK_DIAG_BY_FAMILY, NLM_F_REQUEST, req,
290 		       printf("{sdiag_family=AF_NETLINK"),
291 		       printf(", sdiag_protocol=NETLINK_ROUTE");
292 		       PRINT_FIELD_U(", ", req, ndiag_ino);
293 		       printf(", ndiag_show=NDIAG_SHOW_GROUPS");
294 		       PRINT_FIELD_COOKIE(", ", req, ndiag_cookie);
295 		       printf("}"));
296 }
297 
298 static void
test_netlink_diag_msg(const int fd)299 test_netlink_diag_msg(const int fd)
300 {
301 	static const struct netlink_diag_msg msg = {
302 		.ndiag_family = AF_NETLINK,
303 		.ndiag_type = SOCK_RAW,
304 		.ndiag_protocol = NETLINK_ROUTE,
305 		.ndiag_state = NETLINK_CONNECTED,
306 		.ndiag_portid = 0xbadc0ded,
307 		.ndiag_dst_portid = 0xdeadbeef,
308 		.ndiag_dst_group = 0xfacefeed,
309 		.ndiag_ino = 0xdaeefacd,
310 		.ndiag_cookie = { 0xbadc0ded, 0xdeadbeef }
311 	};
312 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
313 	TEST_SOCK_DIAG(fd, nlh0, AF_NETLINK,
314 		       SOCK_DIAG_BY_FAMILY, NLM_F_DUMP, msg,
315 		       printf("{ndiag_family=AF_NETLINK"),
316 		       printf(", ndiag_type=SOCK_RAW"
317 			      ", ndiag_protocol=NETLINK_ROUTE"
318 			      ", ndiag_state=NETLINK_CONNECTED");
319 		       PRINT_FIELD_U(", ", msg, ndiag_portid);
320 		       PRINT_FIELD_U(", ", msg, ndiag_dst_portid);
321 		       PRINT_FIELD_U(", ", msg, ndiag_dst_group);
322 		       PRINT_FIELD_U(", ", msg, ndiag_ino);
323 		       PRINT_FIELD_COOKIE(", ", msg, ndiag_cookie);
324 		       printf("}"));
325 }
326 
327 static void
test_packet_diag_req(const int fd)328 test_packet_diag_req(const int fd)
329 {
330 	static const struct packet_diag_req req = {
331 		.sdiag_family = AF_PACKET,
332 		.sdiag_protocol = ETH_P_LOOP,
333 		.pdiag_ino = 0xfacefeed,
334 		.pdiag_show = PACKET_SHOW_INFO,
335 		.pdiag_cookie = { 0xdeadbeef, 0xbadc0ded }
336 	};
337 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(req));
338 	TEST_SOCK_DIAG(fd, nlh0, AF_PACKET,
339 		       SOCK_DIAG_BY_FAMILY, NLM_F_REQUEST, req,
340 		       printf("{sdiag_family=AF_PACKET"),
341 		       printf(", sdiag_protocol=%#x", req.sdiag_protocol);
342 		       PRINT_FIELD_U(", ", req, pdiag_ino);
343 		       printf(", pdiag_show=PACKET_SHOW_INFO");
344 		       PRINT_FIELD_COOKIE(", ", req, pdiag_cookie);
345 		       printf("}"));
346 }
347 
348 static void
test_packet_diag_msg(const int fd)349 test_packet_diag_msg(const int fd)
350 {
351 	static const struct packet_diag_msg msg = {
352 		.pdiag_family = AF_PACKET,
353 		.pdiag_type = SOCK_STREAM,
354 		.pdiag_num = 0x9100,
355 		.pdiag_ino = 0xfacefeed,
356 		.pdiag_cookie = { 0xdeadbeef, 0xbadc0ded }
357 	};
358 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
359 	TEST_SOCK_DIAG(fd, nlh0, AF_PACKET,
360 		       SOCK_DIAG_BY_FAMILY, NLM_F_DUMP, msg,
361 		       printf("{pdiag_family=AF_PACKET"),
362 		       printf(", pdiag_type=SOCK_STREAM");
363 		       printf(", pdiag_num=ETH_P_QINQ1");
364 		       PRINT_FIELD_U(", ", msg, pdiag_ino);
365 		       PRINT_FIELD_COOKIE(", ", msg, pdiag_cookie);
366 		       printf("}"));
367 }
368 
369 static void
test_inet_diag_sockid(const int fd)370 test_inet_diag_sockid(const int fd)
371 {
372 	const char address[] = "12.34.56.78";
373 	const char address6[] = "12:34:56:78:90:ab:cd:ef";
374 	struct inet_diag_req_v2 req = {
375 		.sdiag_family = AF_INET,
376 		.idiag_ext = 1 << (INET_DIAG_CONG - 1),
377 		.sdiag_protocol = IPPROTO_TCP,
378 		.idiag_states = 1 << TCP_CLOSE,
379 		.id = {
380 			.idiag_sport = 0xfacd,
381 			.idiag_dport = 0xdead,
382 			.idiag_if = ifindex_lo(),
383 			.idiag_cookie = { 0xdeadbeef, 0xbadc0ded }
384 		},
385 	};
386 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(req));
387 
388 	if (!inet_pton(AF_INET, address, &req.id.idiag_src) ||
389 	    !inet_pton(AF_INET, address, &req.id.idiag_dst))
390 		perror_msg_and_skip("inet_pton");
391 
392 	TEST_NETLINK(fd, nlh0,
393 		     SOCK_DIAG_BY_FAMILY, NLM_F_REQUEST,
394 		     sizeof(req), &req, sizeof(req),
395 		     printf("{sdiag_family=AF_INET"),
396 		     printf(", sdiag_protocol=IPPROTO_TCP"
397 			    ", idiag_ext=1<<(INET_DIAG_CONG-1)"
398 			    ", idiag_states=1<<TCP_CLOSE"
399 			    ", id={idiag_sport=htons(%u)"
400 			    ", idiag_dport=htons(%u)"
401 			    ", idiag_src=inet_addr(\"%s\")"
402 			    ", idiag_dst=inet_addr(\"%s\")",
403 			    ntohs(req.id.idiag_sport),
404 			    ntohs(req.id.idiag_dport),
405 			    address, address);
406 		     printf(", idiag_if=" IFINDEX_LO_STR);
407 		     PRINT_FIELD_COOKIE(", ", req.id, idiag_cookie);
408 		     printf("}}"));
409 
410 	req.sdiag_family = AF_INET6;
411 	if (!inet_pton(AF_INET6, address6, &req.id.idiag_src) ||
412 	    !inet_pton(AF_INET6, address6, &req.id.idiag_dst))
413 		perror_msg_and_skip("inet_pton");
414 
415 	TEST_NETLINK(fd, nlh0,
416 		     SOCK_DIAG_BY_FAMILY, NLM_F_REQUEST,
417 		     sizeof(req), &req, sizeof(req),
418 		     printf("{sdiag_family=AF_INET6"),
419 		     printf(", sdiag_protocol=IPPROTO_TCP"
420 			    ", idiag_ext=1<<(INET_DIAG_CONG-1)"
421 			    ", idiag_states=1<<TCP_CLOSE"
422 			    ", id={idiag_sport=htons(%u)"
423 			    ", idiag_dport=htons(%u)"
424 			    ", inet_pton(AF_INET6, \"%s\", &idiag_src)"
425 			    ", inet_pton(AF_INET6, \"%s\", &idiag_dst)",
426 			    ntohs(req.id.idiag_sport),
427 			    ntohs(req.id.idiag_dport),
428 			    address6, address6);
429 		     printf(", idiag_if=" IFINDEX_LO_STR);
430 		     PRINT_FIELD_COOKIE(", ", req.id, idiag_cookie);
431 		     printf("}}"));
432 }
433 
434 static void
test_inet_diag_req(const int fd)435 test_inet_diag_req(const int fd)
436 {
437 	const char address[] = "12.34.56.78";
438 	struct inet_diag_req req = {
439 		.idiag_family = AF_INET,
440 		.idiag_src_len = 0xde,
441 		.idiag_dst_len = 0xba,
442 		.idiag_ext = 1 << (INET_DIAG_TOS - 1),
443 		.id = {
444 			.idiag_sport = 0xdead,
445 			.idiag_dport = 0xadcd,
446 			.idiag_if = ifindex_lo(),
447 			.idiag_cookie = { 0xdeadbeef, 0xbadc0ded }
448 		},
449 		.idiag_states = 1 << TCP_LAST_ACK,
450 		.idiag_dbs = 0xfacefeed,
451 	};
452 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(req));
453 
454 	if (!inet_pton(AF_INET, address, &req.id.idiag_src) ||
455 	    !inet_pton(AF_INET, address, &req.id.idiag_dst))
456 		perror_msg_and_skip("inet_pton");
457 
458 	TEST_SOCK_DIAG(fd, nlh0, AF_INET,
459 		       TCPDIAG_GETSOCK, NLM_F_REQUEST, req,
460 		       printf("{idiag_family=AF_INET"),
461 		       PRINT_FIELD_U(", ", req, idiag_src_len);
462 		       PRINT_FIELD_U(", ", req, idiag_dst_len);
463 		       printf(", idiag_ext=1<<(INET_DIAG_TOS-1)");
464 		       printf(", id={idiag_sport=htons(%u)"
465 			      ", idiag_dport=htons(%u)"
466 			      ", idiag_src=inet_addr(\"%s\")"
467 			      ", idiag_dst=inet_addr(\"%s\")",
468 			      ntohs(req.id.idiag_sport),
469 			      ntohs(req.id.idiag_dport),
470 			      address, address);
471 		       printf(", idiag_if=" IFINDEX_LO_STR);
472 		       PRINT_FIELD_COOKIE(", ", req.id, idiag_cookie);
473 		       printf("}, idiag_states=1<<TCP_LAST_ACK");
474 		       PRINT_FIELD_U(", ", req, idiag_dbs);
475 		       printf("}"));
476 }
477 
478 static void
test_inet_diag_req_v2(const int fd)479 test_inet_diag_req_v2(const int fd)
480 {
481 	const char address[] = "87.65.43.21";
482 	struct inet_diag_req_v2 req = {
483 		.sdiag_family = AF_INET,
484 		.idiag_ext = 1 << (INET_DIAG_CONG - 1),
485 		.sdiag_protocol = IPPROTO_TCP,
486 		.idiag_states = 1 << TCP_CLOSE,
487 		.id = {
488 			.idiag_sport = 0xfacd,
489 			.idiag_dport = 0xdead,
490 			.idiag_if = ifindex_lo(),
491 			.idiag_cookie = { 0xdeadbeef, 0xbadc0ded }
492 		},
493 	};
494 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(req));
495 
496 	if (!inet_pton(AF_INET, address, &req.id.idiag_src) ||
497 	    !inet_pton(AF_INET, address, &req.id.idiag_dst))
498 		perror_msg_and_skip("inet_pton");
499 
500 	TEST_SOCK_DIAG(fd, nlh0, AF_INET,
501 		       SOCK_DIAG_BY_FAMILY, NLM_F_REQUEST, req,
502 		       printf("{sdiag_family=AF_INET"),
503 		       printf(", sdiag_protocol=IPPROTO_TCP"
504 			      ", idiag_ext=1<<(INET_DIAG_CONG-1)"
505 			      ", idiag_states=1<<TCP_CLOSE"
506 			      ", id={idiag_sport=htons(%u)"
507 			      ", idiag_dport=htons(%u)"
508 			      ", idiag_src=inet_addr(\"%s\")"
509 			      ", idiag_dst=inet_addr(\"%s\")",
510 			      ntohs(req.id.idiag_sport),
511 			      ntohs(req.id.idiag_dport),
512 			      address, address);
513 		       printf(", idiag_if=" IFINDEX_LO_STR);
514 		       PRINT_FIELD_COOKIE(", ", req.id, idiag_cookie);
515 		       printf("}}"));
516 }
517 
518 static void
test_inet_diag_msg(const int fd)519 test_inet_diag_msg(const int fd)
520 {
521 	const char address[] = "11.22.33.44";
522 	struct inet_diag_msg msg = {
523 		.idiag_family = AF_INET,
524 		.idiag_state = TCP_LISTEN,
525 		.idiag_timer = 0xfa,
526 		.idiag_retrans = 0xde,
527 		.id = {
528 			.idiag_sport = 0xfacf,
529 			.idiag_dport = 0xdead,
530 			.idiag_if = ifindex_lo(),
531 			.idiag_cookie = { 0xdeadbeef, 0xbadc0ded }
532 		},
533 		.idiag_expires = 0xfacefeed,
534 		.idiag_rqueue = 0xdeadbeef,
535 		.idiag_wqueue = 0xadcdfafc,
536 		.idiag_uid = 0xdecefaeb,
537 		.idiag_inode = 0xbadc0ded,
538 	};
539 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
540 
541 	if (!inet_pton(AF_INET, address, &msg.id.idiag_src) ||
542 	    !inet_pton(AF_INET, address, &msg.id.idiag_dst))
543 		perror_msg_and_skip("inet_pton");
544 
545 	TEST_SOCK_DIAG(fd, nlh0, AF_INET,
546 		       SOCK_DIAG_BY_FAMILY, NLM_F_DUMP, msg,
547 		       printf("{idiag_family=AF_INET"),
548 		       printf(", idiag_state=TCP_LISTEN");
549 		       PRINT_FIELD_U(", ", msg, idiag_timer);
550 		       PRINT_FIELD_U(", ", msg, idiag_retrans);
551 		       printf(", id={idiag_sport=htons(%u)"
552 			      ", idiag_dport=htons(%u)"
553 			      ", idiag_src=inet_addr(\"%s\")"
554 			      ", idiag_dst=inet_addr(\"%s\")",
555 			      ntohs(msg.id.idiag_sport),
556 			      ntohs(msg.id.idiag_dport),
557 			      address, address);
558 		       printf(", idiag_if=" IFINDEX_LO_STR);
559 		       PRINT_FIELD_COOKIE(", ", msg.id, idiag_cookie);
560 		       PRINT_FIELD_U("}, ", msg, idiag_expires);
561 		       PRINT_FIELD_U(", ", msg, idiag_rqueue);
562 		       PRINT_FIELD_U(", ", msg, idiag_wqueue);
563 		       PRINT_FIELD_U(", ", msg, idiag_uid);
564 		       PRINT_FIELD_U(", ", msg, idiag_inode);
565 		       printf("}"));
566 }
567 
568 #ifdef AF_SMC
569 static void
test_smc_diag_req(const int fd)570 test_smc_diag_req(const int fd)
571 {
572 	const char address[] = "43.21.56.78";
573 	struct smc_diag_req req = {
574 		.diag_family = AF_SMC,
575 		.diag_ext = 1 << (SMC_DIAG_CONNINFO - 1),
576 		.id = {
577 			.idiag_sport = 0xdead,
578 			.idiag_dport = 0xadcd,
579 			.idiag_if = ifindex_lo(),
580 			.idiag_cookie = { 0xdeadbeef, 0xbadc0ded },
581 		},
582 	};
583 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(req));
584 
585 	if (!inet_pton(AF_INET, address, &req.id.idiag_src) ||
586 	    !inet_pton(AF_INET, address, &req.id.idiag_dst))
587 		perror_msg_and_skip("inet_pton");
588 
589 	TEST_SOCK_DIAG(fd, nlh0, AF_SMC,
590 		       SOCK_DIAG_BY_FAMILY, NLM_F_REQUEST, req,
591 		       printf("{diag_family=AF_SMC"),
592 		       printf(", diag_ext=1<<(SMC_DIAG_CONNINFO-1)");
593 		       printf(", id={idiag_sport=htons(%u)"
594 			      ", idiag_dport=htons(%u)"
595 			      ", idiag_src=inet_addr(\"%s\")"
596 			      ", idiag_dst=inet_addr(\"%s\")",
597 			      ntohs(req.id.idiag_sport),
598 			      ntohs(req.id.idiag_dport),
599 			      address, address);
600 		       printf(", idiag_if=" IFINDEX_LO_STR);
601 		       PRINT_FIELD_COOKIE(", ", req.id, idiag_cookie);
602 		       printf("}}"));
603 }
604 
605 static void
test_smc_diag_msg(const int fd)606 test_smc_diag_msg(const int fd)
607 {
608 	const char address[] = "34.87.12.90";
609 	struct smc_diag_msg msg = {
610 		.diag_family = AF_SMC,
611 		.diag_state = SMC_ACTIVE,
612 		.diag_fallback = 0x1,
613 		.diag_shutdown = 0xba,
614 		.id = {
615 			.idiag_sport = 0xdead,
616 			.idiag_dport = 0xadcd,
617 			.idiag_if = ifindex_lo(),
618 			.idiag_cookie = { 0xdeadbeef, 0xbadc0ded },
619 		},
620 		.diag_uid = 0xadcdfafc,
621 		.diag_inode = 0xbadc0ded,
622 	};
623 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
624 
625 	if (!inet_pton(AF_INET, address, &msg.id.idiag_src) ||
626 	    !inet_pton(AF_INET, address, &msg.id.idiag_dst))
627 		perror_msg_and_skip("inet_pton");
628 
629 	TEST_SOCK_DIAG(fd, nlh0, AF_SMC,
630 		       SOCK_DIAG_BY_FAMILY, NLM_F_DUMP, msg,
631 		       printf("{diag_family=AF_SMC"),
632 		       printf(", diag_state=SMC_ACTIVE");
633 		       printf(", diag_fallback=SMC_DIAG_MODE_FALLBACK_TCP");
634 		       PRINT_FIELD_U(", ", msg, diag_shutdown);
635 		       printf(", id={idiag_sport=htons(%u)"
636 			      ", idiag_dport=htons(%u)"
637 			      ", idiag_src=inet_addr(\"%s\")"
638 			      ", idiag_dst=inet_addr(\"%s\")",
639 			      ntohs(msg.id.idiag_sport),
640 			      ntohs(msg.id.idiag_dport),
641 			      address, address);
642 		       printf(", idiag_if=" IFINDEX_LO_STR);
643 		       PRINT_FIELD_COOKIE(", ", msg.id, idiag_cookie);
644 		       PRINT_FIELD_U("}, ", msg, diag_uid);
645 		       PRINT_FIELD_U(", ", msg, diag_inode);
646 		       printf("}"));
647 }
648 #endif
649 
650 int
main(void)651 main(void)
652 {
653 	skip_if_unavailable("/proc/self/fd/");
654 
655 	int fd = create_nl_socket(NETLINK_SOCK_DIAG);
656 
657 	test_nlmsg_type(fd);
658 	test_nlmsg_flags(fd);
659 	test_odd_family_req(fd);
660 	test_odd_family_msg(fd);
661 	test_unix_diag_req(fd);
662 	test_unix_diag_msg(fd);
663 	test_netlink_diag_req(fd);
664 	test_netlink_diag_msg(fd);
665 	test_packet_diag_req(fd);
666 	test_packet_diag_msg(fd);
667 	test_inet_diag_sockid(fd);
668 	test_inet_diag_req(fd);
669 	test_inet_diag_req_v2(fd);
670 	test_inet_diag_msg(fd);
671 #ifdef AF_SMC
672 	test_smc_diag_req(fd);
673 	test_smc_diag_msg(fd);
674 #endif
675 
676 	printf("+++ exited with 0 +++\n");
677 
678 	return 0;
679 }
680