Merge branch 'tomato-ND-USBmod' into tomato-RT
[tomato.git] / release / src / router / radvd / radvdump.c
blob46ad609883f522429c295481272fb501118a08b2
1 /*
2 * $Id: radvdump.c,v 1.25 2011/02/28 10:53:07 reubenhwk Exp $
4 * Authors:
5 * Lars Fenneberg <lf@elemental.net>
6 * Marko Myllynen <myllynen@lut.fi>
8 * This software is Copyright 1996-2000 by the above mentioned author(s),
9 * All Rights Reserved.
11 * The license which is distributed with this software in the file COPYRIGHT
12 * applies to this software. If your distribution is missing this file, you
13 * may request it from <pekkas@netcore.fi>.
17 #include "config.h"
18 #include "includes.h"
19 #include "radvd.h"
21 char usage_str[] = "[-vhfe] [-d level]";
23 #ifdef HAVE_GETOPT_LONG
24 struct option prog_opt[] = {
25 {"debug", 1, 0, 'd'},
26 {"file-format", 0, 0, 'f'},
27 {"exclude-defaults", 0, 0, 'e'},
28 {"version", 0, 0, 'v'},
29 {"help", 0, 0, 'h'},
30 {NULL, 0, 0, 0}
32 #endif
34 char *pname;
35 int sock = -1;
37 void version(void);
38 void usage(void);
39 void print_ff(unsigned char *, int, struct sockaddr_in6 *, int, unsigned int, int);
40 void print_preferences(int);
42 int
43 main(int argc, char *argv[])
45 unsigned char msg[MSG_SIZE_RECV];
46 int c, len, hoplimit;
47 int edefs = 0;
48 struct sockaddr_in6 rcv_addr;
49 struct in6_pktinfo *pkt_info = NULL;
50 #ifdef HAVE_GETOPT_LONG
51 int opt_idx;
52 #endif
54 pname = ((pname=strrchr(argv[0],'/')) != NULL)?pname+1:argv[0];
56 /* parse args */
57 #ifdef HAVE_GETOPT_LONG
58 while ((c = getopt_long(argc, argv, "d:fehv", prog_opt, &opt_idx)) > 0)
59 #else
60 while ((c = getopt(argc, argv, "d:fehv")) > 0)
61 #endif
63 switch (c) {
64 case 'd':
65 set_debuglevel(atoi(optarg));
66 break;
67 case 'f':
68 break;
69 case 'e':
70 edefs = 1;
71 break;
72 case 'v':
73 version();
74 break;
75 case 'h':
76 usage();
77 #ifdef HAVE_GETOPT_LONG
78 case ':':
79 fprintf(stderr, "%s: option %s: parameter expected\n", pname,
80 prog_opt[opt_idx].name);
81 exit(1);
82 #endif
83 case '?':
84 exit(1);
88 if (log_open(L_STDERR, pname, NULL, 0) < 0) {
89 perror("log_open");
90 exit(1);
93 /* get a raw socket for sending and receiving ICMPv6 messages */
94 sock = open_icmpv6_socket();
95 if (sock < 0) {
96 perror("open_icmpv6_socket");
97 exit(1);
100 for(;;)
102 len = recv_rs_ra(msg, &rcv_addr, &pkt_info, &hoplimit);
103 if (len > 0)
105 struct icmp6_hdr *icmph;
108 * can this happen?
111 if (len < sizeof(struct icmp6_hdr))
113 flog(LOG_WARNING, "received icmpv6 packet with invalid length: %d",
114 len);
115 exit(1);
118 icmph = (struct icmp6_hdr *) msg;
120 if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
121 icmph->icmp6_type != ND_ROUTER_ADVERT)
124 * We just want to listen to RSs and RAs
127 flog(LOG_ERR, "icmpv6 filter failed");
128 exit(1);
131 dlog(LOG_DEBUG, 4, "receiver if_index: %u", pkt_info->ipi6_ifindex);
133 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
135 /* not yet */
137 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
138 print_ff(msg, len, &rcv_addr, hoplimit, (unsigned int)pkt_info->ipi6_ifindex, edefs);
140 else if (len == 0)
142 flog(LOG_ERR, "received zero lenght packet");
143 exit(1);
145 else
147 flog(LOG_ERR, "recv_rs_ra: %s", strerror(errno));
148 exit(1);
152 exit(0);
155 void
156 print_ff(unsigned char *msg, int len, struct sockaddr_in6 *addr, int hoplimit, unsigned int if_index, int edefs)
158 /* XXX: hoplimit not being used for anything here.. */
159 struct nd_router_advert *radvert;
160 char addr_str[INET6_ADDRSTRLEN];
161 uint8_t *opt_str;
162 int orig_len = len;
163 char if_name[IFNAMSIZ] = "";
165 print_addr(&addr->sin6_addr, addr_str);
166 printf("#\n# radvd configuration generated by radvdump %s\n", VERSION);
167 printf("# based on Router Advertisement from %s\n", addr_str);
168 if_indextoname(if_index, if_name);
169 printf("# received by interface %s\n", if_name);
170 printf("#\n\ninterface %s\n{\n\tAdvSendAdvert on;\n", if_name);
172 printf("\t# Note: {Min,Max}RtrAdvInterval cannot be obtained with radvdump\n");
174 radvert = (struct nd_router_advert *) msg;
176 if (!edefs || DFLT_AdvManagedFlag != (ND_RA_FLAG_MANAGED == (radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)))
177 printf("\tAdvManagedFlag %s;\n",
178 (radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)?"on":"off");
180 if (!edefs || DFLT_AdvOtherConfigFlag != (ND_RA_FLAG_OTHER == (radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)))
181 printf("\tAdvOtherConfigFlag %s;\n",
182 (radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)?"on":"off");
184 if (!edefs || DFLT_AdvReachableTime != ntohl(radvert->nd_ra_reachable))
185 printf("\tAdvReachableTime %u;\n", ntohl(radvert->nd_ra_reachable));
187 if (!edefs || DFLT_AdvRetransTimer != ntohl(radvert->nd_ra_retransmit))
188 printf("\tAdvRetransTimer %u;\n", ntohl(radvert->nd_ra_retransmit));
190 if (!edefs || DFLT_AdvCurHopLimit != radvert->nd_ra_curhoplimit)
191 printf("\tAdvCurHopLimit %u;\n", radvert->nd_ra_curhoplimit);
193 if (!edefs || (3*DFLT_MaxRtrAdvInterval) != ntohs(radvert->nd_ra_router_lifetime))
194 printf("\tAdvDefaultLifetime %hu;\n", ntohs(radvert->nd_ra_router_lifetime));
196 /* Mobile IPv6 ext */
197 if (!edefs || DFLT_AdvHomeAgentFlag != (ND_RA_FLAG_HOME_AGENT == (radvert->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT)))
198 printf("\tAdvHomeAgentFlag %s;\n",
199 (radvert->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT)?"on":"off");
201 /* Route Preferences and more specific routes */
202 /* XXX two middlemost bits from 8 bit field */
203 if (!edefs || (((radvert->nd_ra_flags_reserved & 0x18) >> 3) & 0xff) != DFLT_AdvDefaultPreference) {
204 printf("\tAdvDefaultPreference ");
205 print_preferences(((radvert->nd_ra_flags_reserved & 0x18) >> 3) & 0xff);
206 printf(";\n");
209 len -= sizeof(struct nd_router_advert);
211 if (len == 0)
212 return;
214 opt_str = (uint8_t *)(msg + sizeof(struct nd_router_advert));
216 while (len > 0)
218 int optlen;
219 struct nd_opt_mtu *mtu;
220 struct HomeAgentInfo *ha_info;
222 if (len < 2)
224 flog(LOG_ERR, "trailing garbage in RA from %s",
225 addr_str);
226 break;
229 optlen = (opt_str[1] << 3);
231 if (optlen == 0)
233 flog(LOG_ERR, "zero length option in RA");
234 break;
236 else if (optlen > len)
238 flog(LOG_ERR, "option length greater than total"
239 " length in RA (type %d, optlen %d, len %d)",
240 (int)*opt_str, optlen, len);
241 break;
244 switch (*opt_str)
246 case ND_OPT_MTU:
247 mtu = (struct nd_opt_mtu *)opt_str;
249 if (!edefs || DFLT_AdvLinkMTU != ntohl(mtu->nd_opt_mtu_mtu))
250 printf("\tAdvLinkMTU %u;\n", ntohl(mtu->nd_opt_mtu_mtu));
251 break;
252 case ND_OPT_SOURCE_LINKADDR:
253 /* XXX: !DFLT depends on current DFLT_ value */
254 if (!edefs || !DFLT_AdvSourceLLAddress)
255 printf("\tAdvSourceLLAddress on;\n");
256 break;
257 /* Mobile IPv6 ext */
258 case ND_OPT_RTR_ADV_INTERVAL:
259 /* XXX: !DFLT depends on current DFLT_ value */
260 if (!edefs || !DFLT_AdvIntervalOpt)
261 printf("\tAdvIntervalOpt on;\n");
262 break;
263 /* Mobile IPv6 ext */
264 case ND_OPT_HOME_AGENT_INFO:
265 ha_info = (struct HomeAgentInfo *)opt_str;
267 /* XXX: we check DFLT_HomeAgentInfo by interface, and it's outside
268 of context here, so we always need to print it out.. */
269 printf("\tAdvHomeAgentInfo on;\n");
271 /* NEMO ext */
272 if (!edefs || DFLT_AdvMobRtrSupportFlag != (ha_info->flags_reserved & ND_OPT_HAI_FLAG_SUPPORT_MR))
273 printf("\tAdvMobRtrSupportFlag %s;\n", (ha_info->flags_reserved & ND_OPT_HAI_FLAG_SUPPORT_MR)?"on":"off");
275 if (!edefs || DFLT_HomeAgentPreference != ntohs(ha_info->preference))
276 printf("\tHomeAgentPreference %hu;\n", ntohs(ha_info->preference));
277 /* Hum.. */
278 if (!edefs || (3*DFLT_MaxRtrAdvInterval) != ntohs(ha_info->lifetime))
279 printf("\tHomeAgentLifetime %hu;\n", ntohs(ha_info->lifetime));
280 break;
281 case ND_OPT_TARGET_LINKADDR:
282 case ND_OPT_REDIRECTED_HEADER:
283 flog(LOG_ERR, "invalid option %d in RA", (int)*opt_str);
284 break;
285 case ND_OPT_PREFIX_INFORMATION:
286 break;
287 case ND_OPT_ROUTE_INFORMATION:
288 break;
289 case ND_OPT_RDNSS_INFORMATION:
290 break;
291 case ND_OPT_DNSSL_INFORMATION:
292 break;
293 default:
294 dlog(LOG_DEBUG, 1, "unknown option %d in RA",
295 (int)*opt_str);
296 break;
299 len -= optlen;
300 opt_str += optlen;
303 orig_len -= sizeof(struct nd_router_advert);
305 if (orig_len == 0)
306 return;
308 opt_str = (uint8_t *)(msg + sizeof(struct nd_router_advert));
310 while (orig_len > 0)
312 int optlen;
313 struct nd_opt_prefix_info *pinfo;
314 struct nd_opt_route_info_local *rinfo;
315 struct nd_opt_rdnss_info_local *rdnss_info;
316 struct nd_opt_dnssl_info_local *dnssl_info;
317 char prefix_str[INET6_ADDRSTRLEN];
318 char suffix[256];
319 int offset, label_len;
321 if (orig_len < 2)
323 flog(LOG_ERR, "trailing garbage in RA from %s",
324 addr_str);
325 break;
328 optlen = (opt_str[1] << 3);
330 if (optlen == 0)
332 flog(LOG_ERR, "zero length option in RA");
333 break;
335 else if (optlen > orig_len)
337 flog(LOG_ERR, "option length greater than total"
338 " length in RA (type %d, optlen %d, len %d)",
339 (int)*opt_str, optlen, orig_len);
340 break;
343 switch (*opt_str)
345 case ND_OPT_PREFIX_INFORMATION:
346 pinfo = (struct nd_opt_prefix_info *) opt_str;
348 print_addr(&pinfo->nd_opt_pi_prefix, prefix_str);
350 printf("\n\tprefix %s/%d\n\t{\n", prefix_str, pinfo->nd_opt_pi_prefix_len);
352 if (ntohl(pinfo->nd_opt_pi_valid_time) == 0xffffffff)
354 if (!edefs || DFLT_AdvValidLifetime != 0xffffffff)
355 printf("\t\tAdvValidLifetime infinity; # (0xffffffff)\n");
357 else
359 if (!edefs || DFLT_AdvValidLifetime != ntohl(pinfo->nd_opt_pi_valid_time))
360 printf("\t\tAdvValidLifetime %u;\n", ntohl(pinfo->nd_opt_pi_valid_time));
362 if (ntohl(pinfo->nd_opt_pi_preferred_time) == 0xffffffff)
364 if (!edefs || DFLT_AdvPreferredLifetime != 0xffffffff)
365 printf("\t\tAdvPreferredLifetime infinity; # (0xffffffff)\n");
367 else
369 if (!edefs || DFLT_AdvPreferredLifetime != ntohl(pinfo->nd_opt_pi_preferred_time))
370 printf("\t\tAdvPreferredLifetime %u;\n", ntohl(pinfo->nd_opt_pi_preferred_time));
373 if (!edefs || DFLT_AdvOnLinkFlag != (ND_OPT_PI_FLAG_ONLINK == (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)))
374 printf("\t\tAdvOnLink %s;\n",
375 (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)?"on":"off");
377 if (!edefs || DFLT_AdvAutonomousFlag != (ND_OPT_PI_FLAG_AUTO == (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)))
378 printf("\t\tAdvAutonomous %s;\n",
379 (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO)?"on":"off");
381 /* Mobile IPv6 ext */
382 if (!edefs || DFLT_AdvRouterAddr != (ND_OPT_PI_FLAG_RADDR == (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_RADDR)))
383 printf("\t\tAdvRouterAddr %s;\n",
384 (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_RADDR)?"on":"off");
386 printf("\t}; # End of prefix definition\n\n");
387 break;
388 case ND_OPT_ROUTE_INFORMATION:
389 rinfo = (struct nd_opt_route_info_local *) opt_str;
391 print_addr(&rinfo->nd_opt_ri_prefix, prefix_str);
393 printf("\n\troute %s/%d\n\t{\n", prefix_str, rinfo->nd_opt_ri_prefix_len);
395 if (!edefs || (((radvert->nd_ra_flags_reserved & 0x18) >> 3) & 0xff) != DFLT_AdvRoutePreference) {
396 printf("\t\tAdvRoutePreference ");
397 print_preferences(((rinfo->nd_opt_ri_flags_reserved & 0x18) >> 3) & 0xff);
398 printf(";\n");
401 /* XXX: we check DFLT_AdvRouteLifetime by interface, and it's outside of context here */
402 if (ntohl(rinfo->nd_opt_ri_lifetime) == 0xffffffff)
403 printf("\t\tAdvRouteLifetime infinity; # (0xffffffff)\n");
404 else
405 printf("\t\tAdvRouteLifetime %u;\n", ntohl(rinfo->nd_opt_ri_lifetime));
407 printf("\t}; # End of route definition\n\n");
408 break;
409 case ND_OPT_RDNSS_INFORMATION:
410 rdnss_info = (struct nd_opt_rdnss_info_local *) opt_str;
412 printf("\n\tRDNSS");
414 print_addr(&rdnss_info->nd_opt_rdnssi_addr1, prefix_str);
415 printf(" %s", prefix_str);
417 if (rdnss_info->nd_opt_rdnssi_len >= 5) {
418 print_addr(&rdnss_info->nd_opt_rdnssi_addr2, prefix_str);
419 printf(" %s", prefix_str);
421 if (rdnss_info->nd_opt_rdnssi_len >= 7) {
422 print_addr(&rdnss_info->nd_opt_rdnssi_addr3, prefix_str);
423 printf(" %s", prefix_str);
426 printf("\n\t{\n");
427 /* as AdvRDNSSLifetime may depend on MaxRtrAdvInterval, it could change */
428 if (ntohl(rdnss_info->nd_opt_rdnssi_lifetime) == 0xffffffff)
429 printf("\t\tAdvRDNSSLifetime infinity; # (0xffffffff)\n");
430 else
431 printf("\t\tAdvRDNSSLifetime %u;\n", ntohl(rdnss_info->nd_opt_rdnssi_lifetime));
433 printf("\t}; # End of RDNSS definition\n\n");
434 break;
435 case ND_OPT_DNSSL_INFORMATION:
436 dnssl_info = (struct nd_opt_dnssl_info_local *) opt_str;
438 printf("\n\tDNSSL");
439 suffix[0] = '\0';
441 for (offset = 0;offset < (dnssl_info->nd_opt_dnssli_len-1)*8;) {
442 label_len = dnssl_info->nd_opt_dnssli_suffixes[offset++];
444 if (label_len == 0) {
446 * Ignore empty suffixes. They're
447 * probably just padding...
449 if (suffix[0] == '\0')
450 continue;
452 printf(" %s", suffix);
454 suffix[0] = '\0';
455 continue;
458 if ((sizeof(suffix) - strlen(suffix)) < (label_len + 2)) {
459 flog(LOG_ERR, "oversized suffix in DNSSL option from %s",
460 addr_str);
461 break;
464 if (suffix[0] != '\0')
465 strcat(suffix, ".");
466 strncat(suffix, &dnssl_info->nd_opt_dnssli_suffixes[offset], label_len);
467 offset += label_len;
470 printf("\n\t{\n");
471 /* as AdvDNSSLLifetime may depend on MaxRtrAdvInterval, it could change */
472 if (ntohl(dnssl_info->nd_opt_dnssli_lifetime) == 0xffffffff)
473 printf("\t\tAdvDNSSLLifetime infinity; # (0xffffffff)\n");
474 else
475 printf("\t\tAdvDNSSLLifetime %u;\n", ntohl(dnssl_info->nd_opt_dnssli_lifetime));
477 printf("\t}; # End of DNSSL definition\n\n");
478 break;
479 default:
480 break;
482 orig_len -= optlen;
483 opt_str += optlen;
486 printf("}; # End of interface definition\n");
488 fflush(stdout);
491 void
492 print_preferences(int p)
494 switch (p) {
495 case 0:
496 printf("medium");
497 break;
498 case 1:
499 printf("high");
500 break;
501 case 2:
502 /* reserved, ignore */
503 break;
504 case 3:
505 printf("low");
506 break;
510 void
511 version(void)
513 fprintf(stderr,"Version: %s\n\n", VERSION);
514 fprintf(stderr,"Please send bug reports and suggestions to %s\n",
515 CONTACT_EMAIL);
516 exit(1);
519 void
520 usage(void)
522 fprintf(stderr,"usage: %s %s\n", pname, usage_str);
523 exit(1);