libmnl  1.0.4
rtnl-route-dump.c
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 
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 
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 */
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 
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 
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 
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 
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 
299 int main(int argc, char *argv[])
300 {
301  struct mnl_socket *nl;
302  char buf[MNL_SOCKET_BUFFER_SIZE];
303  struct nlmsghdr *nlh;
304  struct rtmsg *rtm;
305  int ret;
306  unsigned int seq, portid;
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 }