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