1 /*
2  * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
3  * Copyright (c) 2017-2018 The strace developers.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "tests.h"
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include "test_netlink.h"
37 #ifdef HAVE_STRUCT_DCBMSG
38 # include <linux/dcbnl.h>
39 #endif
40 #ifdef HAVE_LINUX_FIB_RULES_H
41 # include <linux/fib_rules.h>
42 #endif
43 #ifdef HAVE_LINUX_IF_ADDR_H
44 # include <linux/if_addr.h>
45 #endif
46 #ifdef HAVE_STRUCT_IFADDRLBLMSG
47 # include <linux/if_addrlabel.h>
48 #endif
49 #include <linux/if_arp.h>
50 #include <linux/if_bridge.h>
51 #include <linux/ip.h>
52 #ifdef HAVE_LINUX_NEIGHBOUR_H
53 # include <linux/neighbour.h>
54 #endif
55 #ifdef HAVE_STRUCT_NETCONFMSG
56 # include <linux/netconf.h>
57 #endif
58 #include <linux/rtnetlink.h>
59 
60 #define TEST_NL_ROUTE(fd_, nlh0_, type_, obj_, print_family_, ...)	\
61 	do {								\
62 		/* family and string */					\
63 		TEST_NETLINK((fd_), (nlh0_),				\
64 			     type_, NLM_F_REQUEST,			\
65 			     sizeof(obj_) - 1,				\
66 			     &(obj_), sizeof(obj_) - 1,			\
67 			     (print_family_);				\
68 			     printf(", ...}"));				\
69 									\
70 		/* sizeof(obj_) */					\
71 		TEST_NETLINK((fd_), (nlh0_),				\
72 			     type_, NLM_F_REQUEST,			\
73 			     sizeof(obj_), &(obj_), sizeof(obj_),	\
74 			     (print_family_);				\
75 			      __VA_ARGS__);				\
76 									\
77 		/* short read of sizeof(obj_) */			\
78 		TEST_NETLINK((fd_), (nlh0_),				\
79 			     type_, NLM_F_REQUEST,			\
80 			     sizeof(obj_), &(obj_), sizeof(obj_) - 1,	\
81 			     (print_family_);				\
82 			     printf(", %p}",				\
83 				    NLMSG_DATA(TEST_NETLINK_nlh) + 1));	\
84 	} while (0)
85 
86 static void
test_nlmsg_type(const int fd)87 test_nlmsg_type(const int fd)
88 {
89 	long rc;
90 	struct nlmsghdr nlh = {
91 		.nlmsg_len = sizeof(nlh),
92 		.nlmsg_type = RTM_GETLINK,
93 		.nlmsg_flags = NLM_F_REQUEST,
94 	};
95 
96 	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
97 	printf("sendto(%d, {len=%u, type=RTM_GETLINK"
98 	       ", flags=NLM_F_REQUEST, seq=0, pid=0}"
99 	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
100 	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
101 }
102 
103 static void
test_nlmsg_flags(const int fd)104 test_nlmsg_flags(const int fd)
105 {
106 	long rc;
107 	struct nlmsghdr nlh = {
108 		.nlmsg_len = sizeof(nlh),
109 	};
110 
111 	nlh.nlmsg_type = RTM_GETLINK;
112 	nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
113 	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
114 	printf("sendto(%d, {len=%u, type=RTM_GETLINK"
115 	       ", flags=NLM_F_REQUEST|NLM_F_DUMP, seq=0, pid=0}"
116 	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
117 	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
118 
119 	nlh.nlmsg_type = RTM_DELACTION;
120 	nlh.nlmsg_flags = NLM_F_ROOT;
121 	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
122 	printf("sendto(%d, {len=%u, type=RTM_DELACTION"
123 	       ", flags=NLM_F_ROOT, seq=0, pid=0}"
124 	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
125 	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
126 
127 	nlh.nlmsg_type = RTM_NEWLINK;
128 	nlh.nlmsg_flags = NLM_F_ECHO | NLM_F_REPLACE;
129 	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
130 	printf("sendto(%d, {len=%u, type=RTM_NEWLINK"
131 	       ", flags=NLM_F_ECHO|NLM_F_REPLACE, seq=0, pid=0}"
132 	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
133 	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
134 
135 	nlh.nlmsg_type = RTM_DELLINK;
136 	nlh.nlmsg_flags = NLM_F_NONREC;
137 	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
138 	printf("sendto(%d, {len=%u, type=RTM_DELLINK"
139 	       ", flags=NLM_F_NONREC, seq=0, pid=0}"
140 	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
141 	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
142 }
143 
144 static void
test_nlmsg_done(const int fd)145 test_nlmsg_done(const int fd)
146 {
147 	const int num = 0xabcdefad;
148 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(num));
149 
150 	TEST_NETLINK(fd, nlh0, NLMSG_DONE, NLM_F_REQUEST,
151 		     sizeof(num), &num, sizeof(num),
152 		     printf("%d", num));
153 }
154 
155 static void
test_rtnl_unspec(const int fd)156 test_rtnl_unspec(const int fd)
157 {
158 	uint8_t family = 0;
159 	char buf[sizeof(family) + 4];
160 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(buf));
161 
162 	/* unspecified family only */
163 	TEST_NETLINK_(fd, nlh0,
164 		      0xffff, "0xffff /* RTM_??? */",
165 		      NLM_F_REQUEST, "NLM_F_REQUEST",
166 		      sizeof(family), &family, sizeof(family),
167 		      printf("{family=AF_UNSPEC}"));
168 
169 	/* unknown family only */
170 	family = 0xff;
171 	TEST_NETLINK_(fd, nlh0,
172 		      0xffff, "0xffff /* RTM_??? */",
173 		      NLM_F_REQUEST, "NLM_F_REQUEST",
174 		      sizeof(family), &family, sizeof(family),
175 		      printf("{family=0xff /* AF_??? */}"));
176 
177 	/* short read of family */
178 	TEST_NETLINK_(fd, nlh0,
179 		      0xffff, "0xffff /* RTM_??? */",
180 		      NLM_F_REQUEST, "NLM_F_REQUEST",
181 		      sizeof(family), &family, sizeof(family) - 1,
182 		      printf("%p", NLMSG_DATA(TEST_NETLINK_nlh)));
183 
184 	/* unspecified family and string */
185 	family = 0;
186 	memcpy(buf, &family, sizeof(family));
187 	memcpy(buf + sizeof(family), "1234", 4);
188 	TEST_NETLINK_(fd, nlh0,
189 		      0xffff, "0xffff /* RTM_??? */",
190 		      NLM_F_REQUEST, "NLM_F_REQUEST",
191 		      sizeof(buf), buf, sizeof(buf),
192 		      printf("{family=AF_UNSPEC, \"\\x31\\x32\\x33\\x34\"}"));
193 
194 	/* unknown family and string */
195 	family = 0xfd;
196 	memcpy(buf, &family, sizeof(family));
197 	TEST_NETLINK_(fd, nlh0,
198 		      0xffff, "0xffff /* RTM_??? */",
199 		      NLM_F_REQUEST, "NLM_F_REQUEST",
200 		      sizeof(buf), buf, sizeof(buf),
201 		      printf("{family=%#x /* AF_??? */"
202 			     ", \"\\x31\\x32\\x33\\x34\"}", family));
203 }
204 
205 static void
test_rtnl_link(const int fd)206 test_rtnl_link(const int fd)
207 {
208 	const struct ifinfomsg ifinfo = {
209 		.ifi_family = AF_UNIX,
210 		.ifi_type = ARPHRD_LOOPBACK,
211 		.ifi_index = ifindex_lo(),
212 		.ifi_flags = IFF_UP,
213 		.ifi_change = 0xfabcdeba
214 	};
215 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(ifinfo));
216 
217 	TEST_NL_ROUTE(fd, nlh0, RTM_GETLINK, ifinfo,
218 		      printf("{ifi_family=AF_UNIX"),
219 		      printf(", ifi_type=ARPHRD_LOOPBACK"
220 			     ", ifi_index=" IFINDEX_LO_STR
221 			     ", ifi_flags=IFF_UP");
222 		      PRINT_FIELD_X(", ", ifinfo, ifi_change);
223 		      printf("}"));
224 }
225 
226 static void
test_rtnl_addr(const int fd)227 test_rtnl_addr(const int fd)
228 {
229 	const struct ifaddrmsg msg = {
230 		.ifa_family = AF_UNIX,
231 		.ifa_prefixlen = 0xde,
232 		.ifa_flags = IFA_F_SECONDARY,
233 		.ifa_scope = RT_SCOPE_UNIVERSE,
234 		.ifa_index = ifindex_lo()
235 	};
236 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
237 
238 	TEST_NL_ROUTE(fd, nlh0, RTM_GETADDR, msg,
239 		      printf("{ifa_family=AF_UNIX"),
240 		      PRINT_FIELD_U(", ", msg, ifa_prefixlen);
241 		      printf(", ifa_flags=IFA_F_SECONDARY"
242 			     ", ifa_scope=RT_SCOPE_UNIVERSE"
243 			     ", ifa_index=" IFINDEX_LO_STR);
244 		      printf("}"));
245 }
246 
247 static void
test_rtnl_route(const int fd)248 test_rtnl_route(const int fd)
249 {
250 	static const struct rtmsg msg = {
251 		.rtm_family = AF_UNIX,
252 		.rtm_dst_len = 0xaf,
253 		.rtm_src_len = 0xda,
254 		.rtm_tos = IPTOS_LOWDELAY,
255 		.rtm_table = RT_TABLE_DEFAULT,
256 		.rtm_protocol = RTPROT_KERNEL,
257 		.rtm_scope = RT_SCOPE_UNIVERSE,
258 		.rtm_type = RTN_LOCAL,
259 		.rtm_flags = RTM_F_NOTIFY
260 	};
261 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
262 
263 	TEST_NL_ROUTE(fd, nlh0, RTM_GETROUTE, msg,
264 		      printf("{rtm_family=AF_UNIX"),
265 		      PRINT_FIELD_U(", ", msg, rtm_dst_len);
266 		      PRINT_FIELD_U(", ", msg, rtm_src_len);
267 		      printf(", rtm_tos=IPTOS_LOWDELAY"
268 			     ", rtm_table=RT_TABLE_DEFAULT"
269 			     ", rtm_protocol=RTPROT_KERNEL"
270 			     ", rtm_scope=RT_SCOPE_UNIVERSE"
271 			     ", rtm_type=RTN_LOCAL"
272 			     ", rtm_flags=RTM_F_NOTIFY}"));
273 }
274 
275 #ifdef HAVE_LINUX_FIB_RULES_H
276 static void
test_rtnl_rule(const int fd)277 test_rtnl_rule(const int fd)
278 {
279 	struct rtmsg msg = {
280 		.rtm_family = AF_UNIX,
281 		.rtm_dst_len = 0xaf,
282 		.rtm_src_len = 0xda,
283 		.rtm_tos = IPTOS_LOWDELAY,
284 		.rtm_table = RT_TABLE_UNSPEC,
285 		.rtm_type = FR_ACT_TO_TBL,
286 		.rtm_flags = FIB_RULE_INVERT
287 	};
288 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
289 
290 	TEST_NL_ROUTE(fd, nlh0, RTM_GETRULE, msg,
291 		      printf("{family=AF_UNIX"),
292 		      printf(", dst_len=%u, src_len=%u"
293 			     ", tos=IPTOS_LOWDELAY"
294 			     ", table=RT_TABLE_UNSPEC"
295 			     ", action=FR_ACT_TO_TBL"
296 			     ", flags=FIB_RULE_INVERT}",
297 			     msg.rtm_dst_len,
298 			     msg.rtm_src_len));
299 }
300 #endif
301 
302 static void
test_rtnl_neigh(const int fd)303 test_rtnl_neigh(const int fd)
304 {
305 	const struct ndmsg msg = {
306 		.ndm_family = AF_UNIX,
307 		.ndm_ifindex = ifindex_lo(),
308 		.ndm_state = NUD_PERMANENT,
309 		.ndm_flags = NTF_PROXY,
310 		.ndm_type = RTN_UNSPEC
311 	};
312 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
313 
314 	TEST_NL_ROUTE(fd, nlh0, RTM_GETNEIGH, msg,
315 		      printf("{ndm_family=AF_UNIX"),
316 		      printf(", ndm_ifindex=" IFINDEX_LO_STR
317 			     ", ndm_state=NUD_PERMANENT"
318 			     ", ndm_flags=NTF_PROXY"
319 			     ", ndm_type=RTN_UNSPEC}"));
320 }
321 
322 static void
test_rtnl_neightbl(const int fd)323 test_rtnl_neightbl(const int fd)
324 {
325 	static const struct ndtmsg msg = {
326 		.ndtm_family = AF_NETLINK
327 	};
328 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
329 
330 	TEST_NETLINK(fd, nlh0,
331 		     RTM_GETNEIGHTBL, NLM_F_REQUEST,
332 		     sizeof(msg), &msg, sizeof(msg),
333 		     printf("{ndtm_family=AF_NETLINK}"));
334 }
335 
336 static void
test_rtnl_tc(const int fd)337 test_rtnl_tc(const int fd)
338 {
339 	const struct tcmsg msg = {
340 		.tcm_family = AF_UNIX,
341 		.tcm_ifindex = ifindex_lo(),
342 		.tcm_handle = 0xfadcdafb,
343 		.tcm_parent = 0xafbcadab,
344 		.tcm_info = 0xbcaedafa
345 	};
346 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
347 
348 	TEST_NL_ROUTE(fd, nlh0, RTM_GETQDISC, msg,
349 		      printf("{tcm_family=AF_UNIX"),
350 		      printf(", tcm_ifindex=" IFINDEX_LO_STR);
351 		      PRINT_FIELD_U(", ", msg, tcm_handle);
352 		      PRINT_FIELD_U(", ", msg, tcm_parent);
353 		      PRINT_FIELD_U(", ", msg, tcm_info);
354 		      printf("}"));
355 }
356 
357 static void
test_rtnl_tca(const int fd)358 test_rtnl_tca(const int fd)
359 {
360 	struct tcamsg msg = {
361 		.tca_family = AF_INET
362 	};
363 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
364 
365 	TEST_NETLINK(fd, nlh0,
366 		     RTM_GETACTION, NLM_F_REQUEST,
367 		     sizeof(msg), &msg, sizeof(msg),
368 		     printf("{tca_family=AF_INET}"));
369 }
370 
371 #ifdef HAVE_STRUCT_IFADDRLBLMSG
372 static void
test_rtnl_addrlabel(const int fd)373 test_rtnl_addrlabel(const int fd)
374 {
375 	const struct ifaddrlblmsg msg = {
376 		.ifal_family = AF_UNIX,
377 		.ifal_prefixlen = 0xaf,
378 		.ifal_flags = 0xbd,
379 		.ifal_index = ifindex_lo(),
380 		.ifal_seq = 0xfadcdafb
381 	};
382 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
383 
384 	TEST_NL_ROUTE(fd, nlh0, RTM_GETADDRLABEL, msg,
385 		      printf("{ifal_family=AF_UNIX"),
386 		      PRINT_FIELD_U(", ", msg, ifal_prefixlen);
387 		      PRINT_FIELD_U(", ", msg, ifal_flags);
388 		      printf(", ifal_index=" IFINDEX_LO_STR);
389 		      PRINT_FIELD_U(", ", msg, ifal_seq);
390 		      printf("}"));
391 }
392 #endif
393 
394 #ifdef HAVE_STRUCT_DCBMSG
395 static void
test_rtnl_dcb(const int fd)396 test_rtnl_dcb(const int fd)
397 {
398 	static const struct dcbmsg msg = {
399 		.dcb_family = AF_UNIX,
400 		.cmd = DCB_CMD_UNDEFINED
401 	};
402 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
403 
404 	TEST_NL_ROUTE(fd, nlh0, RTM_GETDCB, msg,
405 		      printf("{dcb_family=AF_UNIX"),
406 		      printf(", cmd=DCB_CMD_UNDEFINED}"));
407 }
408 #endif
409 
410 #ifdef HAVE_STRUCT_NETCONFMSG
411 static void
test_rtnl_netconf(const int fd)412 test_rtnl_netconf(const int fd)
413 {
414 	static const struct netconfmsg msg = {
415 		.ncm_family = AF_INET
416 	};
417 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
418 
419 	TEST_NETLINK(fd, nlh0,
420 		     RTM_GETNETCONF, NLM_F_REQUEST,
421 		     sizeof(msg), &msg, sizeof(msg),
422 		     printf("{ncm_family=AF_INET}"));
423 }
424 #endif
425 
426 #ifdef HAVE_STRUCT_BR_PORT_MSG
427 static void
test_rtnl_mdb(const int fd)428 test_rtnl_mdb(const int fd)
429 {
430 	const struct br_port_msg msg = {
431 		.family = AF_UNIX,
432 		.ifindex = ifindex_lo()
433 	};
434 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
435 
436 	TEST_NL_ROUTE(fd, nlh0, RTM_GETMDB, msg,
437 		      printf("{family=AF_UNIX"),
438 		      printf(", ifindex=" IFINDEX_LO_STR "}"));
439 }
440 #endif
441 
442 #ifdef RTM_NEWNSID
443 static void
test_rtnl_nsid(const int fd)444 test_rtnl_nsid(const int fd)
445 {
446 	static const struct rtgenmsg msg = {
447 		.rtgen_family = AF_UNIX
448 	};
449 	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(msg));
450 
451 	TEST_NETLINK(fd, nlh0,
452 		     RTM_GETNSID, NLM_F_REQUEST,
453 		     sizeof(msg), &msg, sizeof(msg),
454 		     printf("{rtgen_family=AF_UNIX}"));
455 }
456 #endif
457 
main(void)458 int main(void)
459 {
460 	skip_if_unavailable("/proc/self/fd/");
461 
462 	int fd = create_nl_socket(NETLINK_ROUTE);
463 
464 	test_nlmsg_type(fd);
465 	test_nlmsg_flags(fd);
466 	test_nlmsg_done(fd);
467 	test_rtnl_unspec(fd);
468 	test_rtnl_link(fd);
469 	test_rtnl_addr(fd);
470 	test_rtnl_route(fd);
471 #ifdef HAVE_LINUX_FIB_RULES_H
472 	test_rtnl_rule(fd);
473 #endif
474 	test_rtnl_neigh(fd);
475 	test_rtnl_neightbl(fd);
476 	test_rtnl_tc(fd);
477 	test_rtnl_tca(fd);
478 #ifdef HAVE_STRUCT_IFADDRLBLMSG
479 	test_rtnl_addrlabel(fd);
480 #endif
481 #ifdef HAVE_STRUCT_DCBMSG
482 	test_rtnl_dcb(fd);
483 #endif
484 #ifdef HAVE_STRUCT_NETCONFMSG
485 	test_rtnl_netconf(fd);
486 #endif
487 #ifdef HAVE_STRUCT_BR_PORT_MSG
488 	test_rtnl_mdb(fd);
489 #endif
490 #ifdef RTM_NEWNSID
491 	test_rtnl_nsid(fd);
492 #endif
493 
494 	printf("+++ exited with 0 +++\n");
495 
496 	return 0;
497 }
498