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