1 /* This example is placed in the public domain. */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <time.h>
7 #include <arpa/inet.h>
8
9 #include <libmnl/libmnl.h>
10 #include <linux/if.h>
11 #include <linux/if_link.h>
12 #include <linux/rtnetlink.h>
13
data_attr_cb2(const struct nlattr * attr,void * data)14 static int data_attr_cb2(const struct nlattr *attr, void *data)
15 {
16 const struct nlattr **tb = data;
17
18 /* skip unsupported attribute in user-space */
19 if (mnl_attr_type_valid(attr, RTAX_MAX) < 0)
20 return MNL_CB_OK;
21
22 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
23 perror("mnl_attr_validate");
24 return MNL_CB_ERROR;
25 }
26
27 tb[mnl_attr_get_type(attr)] = attr;
28 return MNL_CB_OK;
29 }
30
attributes_show_ipv4(struct nlattr * tb[])31 static void attributes_show_ipv4(struct nlattr *tb[])
32 {
33 if (tb[RTA_TABLE]) {
34 printf("table=%u ", mnl_attr_get_u32(tb[RTA_TABLE]));
35 }
36 if (tb[RTA_DST]) {
37 struct in_addr *addr = mnl_attr_get_payload(tb[RTA_DST]);
38 printf("dst=%s ", inet_ntoa(*addr));
39 }
40 if (tb[RTA_SRC]) {
41 struct in_addr *addr = mnl_attr_get_payload(tb[RTA_SRC]);
42 printf("src=%s ", inet_ntoa(*addr));
43 }
44 if (tb[RTA_OIF]) {
45 printf("oif=%u ", mnl_attr_get_u32(tb[RTA_OIF]));
46 }
47 if (tb[RTA_FLOW]) {
48 printf("flow=%u ", mnl_attr_get_u32(tb[RTA_FLOW]));
49 }
50 if (tb[RTA_PREFSRC]) {
51 struct in_addr *addr = mnl_attr_get_payload(tb[RTA_PREFSRC]);
52 printf("prefsrc=%s ", inet_ntoa(*addr));
53 }
54 if (tb[RTA_GATEWAY]) {
55 struct in_addr *addr = mnl_attr_get_payload(tb[RTA_GATEWAY]);
56 printf("gw=%s ", inet_ntoa(*addr));
57 }
58 if (tb[RTA_PRIORITY]) {
59 printf("prio=%u ", mnl_attr_get_u32(tb[RTA_PRIORITY]));
60 }
61 if (tb[RTA_METRICS]) {
62 int i;
63 struct nlattr *tbx[RTAX_MAX+1] = {};
64
65 mnl_attr_parse_nested(tb[RTA_METRICS], data_attr_cb2, tbx);
66
67 for (i=0; i<RTAX_MAX; i++) {
68 if (tbx[i]) {
69 printf("metrics[%d]=%u ",
70 i, mnl_attr_get_u32(tbx[i]));
71 }
72 }
73 }
74 }
75
76 /* like inet_ntoa(), not reentrant */
inet6_ntoa(struct in6_addr in6)77 static const char *inet6_ntoa(struct in6_addr in6)
78 {
79 static char buf[INET6_ADDRSTRLEN];
80
81 return inet_ntop(AF_INET6, &in6.s6_addr, buf, sizeof(buf));
82 }
83
attributes_show_ipv6(struct nlattr * tb[])84 static void attributes_show_ipv6(struct nlattr *tb[])
85 {
86 if (tb[RTA_TABLE]) {
87 printf("table=%u ", mnl_attr_get_u32(tb[RTA_TABLE]));
88 }
89 if (tb[RTA_DST]) {
90 struct in6_addr *addr = mnl_attr_get_payload(tb[RTA_DST]);
91 printf("dst=%s ", inet6_ntoa(*addr));
92 }
93 if (tb[RTA_SRC]) {
94 struct in6_addr *addr = mnl_attr_get_payload(tb[RTA_SRC]);
95 printf("src=%s ", inet6_ntoa(*addr));
96 }
97 if (tb[RTA_OIF]) {
98 printf("oif=%u ", mnl_attr_get_u32(tb[RTA_OIF]));
99 }
100 if (tb[RTA_FLOW]) {
101 printf("flow=%u ", mnl_attr_get_u32(tb[RTA_FLOW]));
102 }
103 if (tb[RTA_PREFSRC]) {
104 struct in6_addr *addr = mnl_attr_get_payload(tb[RTA_PREFSRC]);
105 printf("prefsrc=%s ", inet6_ntoa(*addr));
106 }
107 if (tb[RTA_GATEWAY]) {
108 struct in6_addr *addr = mnl_attr_get_payload(tb[RTA_GATEWAY]);
109 printf("gw=%s ", inet6_ntoa(*addr));
110 }
111 if (tb[RTA_PRIORITY]) {
112 printf("prio=%u ", mnl_attr_get_u32(tb[RTA_PRIORITY]));
113 }
114 if (tb[RTA_METRICS]) {
115 int i;
116 struct nlattr *tbx[RTAX_MAX+1] = {};
117
118 mnl_attr_parse_nested(tb[RTA_METRICS], data_attr_cb2, tbx);
119
120 for (i=0; i<RTAX_MAX; i++) {
121 if (tbx[i]) {
122 printf("metrics[%d]=%u ",
123 i, mnl_attr_get_u32(tbx[i]));
124 }
125 }
126 }
127 }
128
data_ipv4_attr_cb(const struct nlattr * attr,void * data)129 static int data_ipv4_attr_cb(const struct nlattr *attr, void *data)
130 {
131 const struct nlattr **tb = data;
132 int type = mnl_attr_get_type(attr);
133
134 /* skip unsupported attribute in user-space */
135 if (mnl_attr_type_valid(attr, RTA_MAX) < 0)
136 return MNL_CB_OK;
137
138 switch(type) {
139 case RTA_TABLE:
140 case RTA_DST:
141 case RTA_SRC:
142 case RTA_OIF:
143 case RTA_FLOW:
144 case RTA_PREFSRC:
145 case RTA_GATEWAY:
146 case RTA_PRIORITY:
147 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
148 perror("mnl_attr_validate");
149 return MNL_CB_ERROR;
150 }
151 break;
152 case RTA_METRICS:
153 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
154 perror("mnl_attr_validate");
155 return MNL_CB_ERROR;
156 }
157 break;
158 }
159 tb[type] = attr;
160 return MNL_CB_OK;
161 }
162
data_ipv6_attr_cb(const struct nlattr * attr,void * data)163 static int data_ipv6_attr_cb(const struct nlattr *attr, void *data)
164 {
165 const struct nlattr **tb = data;
166 int type = mnl_attr_get_type(attr);
167
168 /* skip unsupported attribute in user-space */
169 if (mnl_attr_type_valid(attr, RTA_MAX) < 0)
170 return MNL_CB_OK;
171
172 switch(type) {
173 case RTA_TABLE:
174 case RTA_OIF:
175 case RTA_FLOW:
176 case RTA_PRIORITY:
177 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
178 perror("mnl_attr_validate");
179 return MNL_CB_ERROR;
180 }
181 break;
182 case RTA_DST:
183 case RTA_SRC:
184 case RTA_PREFSRC:
185 case RTA_GATEWAY:
186 if (mnl_attr_validate2(attr, MNL_TYPE_BINARY,
187 sizeof(struct in6_addr)) < 0) {
188 perror("mnl_attr_validate2");
189 return MNL_CB_ERROR;
190 }
191 break;
192 case RTA_METRICS:
193 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
194 perror("mnl_attr_validate");
195 return MNL_CB_ERROR;
196 }
197 break;
198 }
199 tb[type] = attr;
200 return MNL_CB_OK;
201 }
202
data_cb(const struct nlmsghdr * nlh,void * data)203 static int data_cb(const struct nlmsghdr *nlh, void *data)
204 {
205 struct nlattr *tb[RTA_MAX+1] = {};
206 struct rtmsg *rm = mnl_nlmsg_get_payload(nlh);
207
208 /* protocol family = AF_INET | AF_INET6 */
209 printf("family=%u ", rm->rtm_family);
210
211 /* destination CIDR, eg. 24 or 32 for IPv4 */
212 printf("dst_len=%u ", rm->rtm_dst_len);
213
214 /* source CIDR */
215 printf("src_len=%u ", rm->rtm_src_len);
216
217 /* type of service (TOS), eg. 0 */
218 printf("tos=%u ", rm->rtm_tos);
219
220 /* table id:
221 * RT_TABLE_UNSPEC = 0
222 *
223 * ... user defined values ...
224 *
225 * RT_TABLE_COMPAT = 252
226 * RT_TABLE_DEFAULT = 253
227 * RT_TABLE_MAIN = 254
228 * RT_TABLE_LOCAL = 255
229 * RT_TABLE_MAX = 0xFFFFFFFF
230 *
231 * Synonimous attribute: RTA_TABLE.
232 */
233 printf("table=%u ", rm->rtm_table);
234
235 /* type:
236 * RTN_UNSPEC = 0
237 * RTN_UNICAST = 1
238 * RTN_LOCAL = 2
239 * RTN_BROADCAST = 3
240 * RTN_ANYCAST = 4
241 * RTN_MULTICAST = 5
242 * RTN_BLACKHOLE = 6
243 * RTN_UNREACHABLE = 7
244 * RTN_PROHIBIT = 8
245 * RTN_THROW = 9
246 * RTN_NAT = 10
247 * RTN_XRESOLVE = 11
248 * __RTN_MAX = 12
249 */
250 printf("type=%u ", rm->rtm_type);
251
252 /* scope:
253 * RT_SCOPE_UNIVERSE = 0 : everywhere in the universe
254 *
255 * ... user defined values ...
256 *
257 * RT_SCOPE_SITE = 200
258 * RT_SCOPE_LINK = 253 : destination attached to link
259 * RT_SCOPE_HOST = 254 : local address
260 * RT_SCOPE_NOWHERE = 255 : not existing destination
261 */
262 printf("scope=%u ", rm->rtm_scope);
263
264 /* protocol:
265 * RTPROT_UNSPEC = 0
266 * RTPROT_REDIRECT = 1
267 * RTPROT_KERNEL = 2 : route installed by kernel
268 * RTPROT_BOOT = 3 : route installed during boot
269 * RTPROT_STATIC = 4 : route installed by administrator
270 *
271 * Values >= RTPROT_STATIC are not interpreted by kernel, they are
272 * just user-defined.
273 */
274 printf("proto=%u ", rm->rtm_protocol);
275
276 /* flags:
277 * RTM_F_NOTIFY = 0x100: notify user of route change
278 * RTM_F_CLONED = 0x200: this route is cloned
279 * RTM_F_EQUALIZE = 0x400: Multipath equalizer: NI
280 * RTM_F_PREFIX = 0x800: Prefix addresses
281 */
282 printf("flags=%x ", rm->rtm_flags);
283
284 switch(rm->rtm_family) {
285 case AF_INET:
286 mnl_attr_parse(nlh, sizeof(*rm), data_ipv4_attr_cb, tb);
287 attributes_show_ipv4(tb);
288 break;
289 case AF_INET6:
290 mnl_attr_parse(nlh, sizeof(*rm), data_ipv6_attr_cb, tb);
291 attributes_show_ipv6(tb);
292 break;
293 }
294
295 printf("\n");
296 return MNL_CB_OK;
297 }
298
main(int argc,char * argv[])299 int main(int argc, char *argv[])
300 {
301 char buf[MNL_SOCKET_DUMP_SIZE];
302 unsigned int seq, portid;
303 struct mnl_socket *nl;
304 struct nlmsghdr *nlh;
305 struct rtmsg *rtm;
306 int ret;
307
308 if (argc != 2) {
309 fprintf(stderr, "Usage: %s <inet|inet6>\n", argv[0]);
310 exit(EXIT_FAILURE);
311 }
312
313 nlh = mnl_nlmsg_put_header(buf);
314 nlh->nlmsg_type = RTM_GETROUTE;
315 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
316 nlh->nlmsg_seq = seq = time(NULL);
317 rtm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtmsg));
318
319 if (strcmp(argv[1], "inet") == 0)
320 rtm->rtm_family = AF_INET;
321 else if (strcmp(argv[1], "inet6") == 0)
322 rtm->rtm_family = AF_INET6;
323
324 nl = mnl_socket_open(NETLINK_ROUTE);
325 if (nl == NULL) {
326 perror("mnl_socket_open");
327 exit(EXIT_FAILURE);
328 }
329
330 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
331 perror("mnl_socket_bind");
332 exit(EXIT_FAILURE);
333 }
334 portid = mnl_socket_get_portid(nl);
335
336 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
337 perror("mnl_socket_sendto");
338 exit(EXIT_FAILURE);
339 }
340
341 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
342 while (ret > 0) {
343 ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL);
344 if (ret <= MNL_CB_STOP)
345 break;
346 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
347 }
348 if (ret == -1) {
349 perror("error");
350 exit(EXIT_FAILURE);
351 }
352
353 mnl_socket_close(nl);
354
355 return 0;
356 }
357