]> granicus.if.org Git - strace/blob - tests/netlink_route.c
ff68579bbea67276b67c60707362676c5525ec32
[strace] / tests / netlink_route.c
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 "test_netlink.h"
35 #ifdef HAVE_LINUX_IF_ADDR_H
36 # include <linux/if_addr.h>
37 #endif
38 #include <linux/if_arp.h>
39 #include <linux/ip.h>
40 #include <linux/rtnetlink.h>
41
42 #ifdef HAVE_IF_INDEXTONAME
43 /* <linux/if.h> used to conflict with <net/if.h> */
44 extern unsigned int if_nametoindex(const char *);
45 # define IFINDEX_LO     (if_nametoindex("lo"))
46 #else
47 # define IFINDEX_LO     1
48 #endif
49
50 #define TEST_NL_ROUTE(fd_, nlh0_, type_, obj_, print_family_, ...)      \
51         do {                                                            \
52                 /* family and string */                                 \
53                 TEST_NETLINK((fd_), (nlh0_),                            \
54                              type_, NLM_F_REQUEST,                      \
55                              sizeof(obj_) - 1,                          \
56                              &(obj_), sizeof(obj_) - 1,                 \
57                              (print_family_);                           \
58                              printf(", ...}"));                         \
59                                                                         \
60                 /* sizeof(obj_) */                                      \
61                 TEST_NETLINK((fd_), (nlh0_),                            \
62                              type_, NLM_F_REQUEST,                      \
63                              sizeof(obj_), &(obj_), sizeof(obj_),       \
64                              (print_family_);                           \
65                               __VA_ARGS__);                             \
66                                                                         \
67                 /* short read of sizeof(obj_) */                        \
68                 TEST_NETLINK((fd_), (nlh0_),                            \
69                              type_, NLM_F_REQUEST,                      \
70                              sizeof(obj_), &(obj_), sizeof(obj_) - 1,   \
71                              (print_family_);                           \
72                              printf(", %p}",                            \
73                                     NLMSG_DATA(TEST_NETLINK_nlh) + 1)); \
74         } while (0)
75
76 static void
77 test_nlmsg_type(const int fd)
78 {
79         long rc;
80         struct nlmsghdr nlh = {
81                 .nlmsg_len = sizeof(nlh),
82                 .nlmsg_type = RTM_GETLINK,
83                 .nlmsg_flags = NLM_F_REQUEST,
84         };
85
86         rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
87         printf("sendto(%d, {len=%u, type=RTM_GETLINK"
88                ", flags=NLM_F_REQUEST, seq=0, pid=0}"
89                ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
90                fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
91 }
92
93 static void
94 test_nlmsg_flags(const int fd)
95 {
96         long rc;
97         struct nlmsghdr nlh = {
98                 .nlmsg_len = sizeof(nlh),
99         };
100
101         nlh.nlmsg_type = RTM_GETLINK;
102         nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
103         rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
104         printf("sendto(%d, {len=%u, type=RTM_GETLINK"
105                ", flags=NLM_F_REQUEST|NLM_F_DUMP, seq=0, pid=0}"
106                ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
107                fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
108
109         nlh.nlmsg_type = RTM_DELACTION;
110         nlh.nlmsg_flags = NLM_F_ROOT;
111         rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
112         printf("sendto(%d, {len=%u, type=RTM_DELACTION"
113                ", flags=NLM_F_ROOT, seq=0, pid=0}"
114                ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
115                fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
116
117         nlh.nlmsg_type = RTM_NEWLINK;
118         nlh.nlmsg_flags = NLM_F_ECHO | NLM_F_REPLACE;
119         rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
120         printf("sendto(%d, {len=%u, type=RTM_NEWLINK"
121                ", flags=NLM_F_ECHO|NLM_F_REPLACE, seq=0, pid=0}"
122                ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
123                fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
124
125         nlh.nlmsg_type = RTM_DELLINK;
126         nlh.nlmsg_flags = NLM_F_REPLACE;
127         rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
128         printf("sendto(%d, {len=%u, type=RTM_DELLINK"
129                ", flags=%#x /* NLM_F_??? */, seq=0, pid=0}"
130                ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
131                fd, nlh.nlmsg_len, NLM_F_REPLACE,
132                (unsigned) sizeof(nlh), sprintrc(rc));
133 }
134
135 static void
136 test_nlmsg_done(const int fd)
137 {
138         void *const nlh0 = tail_alloc(NLMSG_HDRLEN);
139         const int num = 0xabcdefad;
140
141         TEST_NETLINK(fd, nlh0, NLMSG_DONE, NLM_F_REQUEST,
142                      sizeof(num), &num, sizeof(num),
143                      printf("%d", num));
144 }
145
146 static void
147 test_rtnl_unspec(const int fd)
148 {
149         void *const nlh0 = tail_alloc(NLMSG_HDRLEN);
150
151         /* unspecified family only */
152         uint8_t family = 0;
153         TEST_NETLINK_(fd, nlh0,
154                       0xffff, "0xffff /* RTM_??? */",
155                       NLM_F_REQUEST, "NLM_F_REQUEST",
156                       sizeof(family), &family, sizeof(family),
157                       printf("{family=AF_UNSPEC}"));
158
159         /* unknown family only */
160         family = 0xff;
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=0xff /* AF_??? */}"));
166
167         /* short read of family */
168         TEST_NETLINK_(fd, nlh0,
169                       0xffff, "0xffff /* RTM_??? */",
170                       NLM_F_REQUEST, "NLM_F_REQUEST",
171                       sizeof(family), &family, sizeof(family) - 1,
172                       printf("%p", NLMSG_DATA(TEST_NETLINK_nlh)));
173
174         /* unspecified family and string */
175         char buf[sizeof(family) + 4];
176         family = 0;
177         memcpy(buf, &family, sizeof(family));
178         memcpy(buf + sizeof(family), "1234", 4);
179         TEST_NETLINK_(fd, nlh0,
180                       0xffff, "0xffff /* RTM_??? */",
181                       NLM_F_REQUEST, "NLM_F_REQUEST",
182                       sizeof(buf), buf, sizeof(buf),
183                       printf("{family=AF_UNSPEC, \"\\x31\\x32\\x33\\x34\"}"));
184
185         /* unknown family and string */
186         family = 0xfd;
187         memcpy(buf, &family, sizeof(family));
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=%#x /* AF_??? */"
193                              ", \"\\x31\\x32\\x33\\x34\"}", family));
194 }
195
196 static void
197 test_rtnl_link(const int fd)
198 {
199         void *const nlh0 = tail_alloc(NLMSG_HDRLEN);
200         const struct ifinfomsg ifinfo = {
201                 .ifi_family = AF_UNIX,
202                 .ifi_type = ARPHRD_LOOPBACK,
203                 .ifi_index = IFINDEX_LO,
204                 .ifi_flags = IFF_UP,
205                 .ifi_change = 0xfabcdeba
206         };
207
208         TEST_NL_ROUTE(fd, nlh0, RTM_GETLINK, ifinfo,
209                       printf("{ifi_family=AF_UNIX"),
210                       printf(", ifi_type=ARPHRD_LOOPBACK"
211                              ", ifi_index=if_nametoindex(\"lo\")"
212                              ", ifi_flags=IFF_UP");
213                       PRINT_FIELD_X(", ", ifinfo, ifi_change);
214                       printf("}"));
215 }
216
217 static void
218 test_rtnl_addr(const int fd)
219 {
220         void *const nlh0 = tail_alloc(NLMSG_HDRLEN);
221         const struct ifaddrmsg msg = {
222                 .ifa_family = AF_UNIX,
223                 .ifa_prefixlen = 0xde,
224                 .ifa_flags = IFA_F_SECONDARY,
225                 .ifa_scope = RT_SCOPE_UNIVERSE,
226                 .ifa_index = IFINDEX_LO
227         };
228
229         TEST_NL_ROUTE(fd, nlh0, RTM_GETADDR, msg,
230                       printf("{ifa_family=AF_UNIX"),
231                       PRINT_FIELD_U(", ", msg, ifa_prefixlen);
232                       printf(", ifa_flags=IFA_F_SECONDARY"
233                              ", ifa_scope=RT_SCOPE_UNIVERSE"
234                              ", ifa_index=if_nametoindex(\"lo\")");
235                       printf("}"));
236 }
237
238 static void
239 test_rtnl_route(const int fd)
240 {
241         void *const nlh0 = tail_alloc(NLMSG_HDRLEN);
242         static const struct rtmsg msg = {
243                 .rtm_family = AF_UNIX,
244                 .rtm_dst_len = 0xaf,
245                 .rtm_src_len = 0xda,
246                 .rtm_tos = IPTOS_LOWDELAY,
247                 .rtm_table = RT_TABLE_DEFAULT,
248                 .rtm_protocol = RTPROT_KERNEL,
249                 .rtm_scope = RT_SCOPE_UNIVERSE,
250                 .rtm_type = RTN_LOCAL,
251                 .rtm_flags = RTM_F_NOTIFY
252         };
253
254         TEST_NL_ROUTE(fd, nlh0, RTM_GETROUTE, msg,
255                       printf("{rtm_family=AF_UNIX"),
256                       PRINT_FIELD_U(", ", msg, rtm_dst_len);
257                       PRINT_FIELD_U(", ", msg, rtm_src_len);
258                       printf(", rtm_tos=IPTOS_LOWDELAY"
259                              ", rtm_table=RT_TABLE_DEFAULT"
260                              ", rtm_protocol=RTPROT_KERNEL"
261                              ", rtm_scope=RT_SCOPE_UNIVERSE"
262                              ", rtm_type=RTN_LOCAL"
263                              ", rtm_flags=RTM_F_NOTIFY}"));
264 }
265
266 int main(void)
267 {
268         skip_if_unavailable("/proc/self/fd/");
269
270         int fd = create_nl_socket(NETLINK_ROUTE);
271
272         test_nlmsg_type(fd);
273         test_nlmsg_flags(fd);
274         test_nlmsg_done(fd);
275         test_rtnl_unspec(fd);
276         test_rtnl_link(fd);
277         test_rtnl_addr(fd);
278         test_rtnl_route(fd);
279
280         printf("+++ exited with 0 +++\n");
281
282         return 0;
283 }