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