2 * $Id: radvdump.c,v 1.25 2011/02/28 10:53:07 reubenhwk Exp $
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),
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>.
21 char usage_str
[] = "[-vhfe] [-d level]";
23 #ifdef HAVE_GETOPT_LONG
24 struct option prog_opt
[] = {
26 {"file-format", 0, 0, 'f'},
27 {"exclude-defaults", 0, 0, 'e'},
28 {"version", 0, 0, 'v'},
39 void print_ff(unsigned char *, int, struct sockaddr_in6
*, int, unsigned int, int);
40 void print_preferences(int);
43 main(int argc
, char *argv
[])
45 unsigned char msg
[MSG_SIZE_RECV
];
48 struct sockaddr_in6 rcv_addr
;
49 struct in6_pktinfo
*pkt_info
= NULL
;
50 #ifdef HAVE_GETOPT_LONG
54 pname
= ((pname
=strrchr(argv
[0],'/')) != NULL
)?pname
+1:argv
[0];
57 #ifdef HAVE_GETOPT_LONG
58 while ((c
= getopt_long(argc
, argv
, "d:fehv", prog_opt
, &opt_idx
)) > 0)
60 while ((c
= getopt(argc
, argv
, "d:fehv")) > 0)
65 set_debuglevel(atoi(optarg
));
77 #ifdef HAVE_GETOPT_LONG
79 fprintf(stderr
, "%s: option %s: parameter expected\n", pname
,
80 prog_opt
[opt_idx
].name
);
88 if (log_open(L_STDERR
, pname
, NULL
, 0) < 0) {
93 /* get a raw socket for sending and receiving ICMPv6 messages */
94 sock
= open_icmpv6_socket();
96 perror("open_icmpv6_socket");
102 len
= recv_rs_ra(msg
, &rcv_addr
, &pkt_info
, &hoplimit
);
105 struct icmp6_hdr
*icmph
;
111 if (len
< sizeof(struct icmp6_hdr
))
113 flog(LOG_WARNING
, "received icmpv6 packet with invalid length: %d",
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");
131 dlog(LOG_DEBUG
, 4, "receiver if_index: %u", pkt_info
->ipi6_ifindex
);
133 if (icmph
->icmp6_type
== ND_ROUTER_SOLICIT
)
137 else if (icmph
->icmp6_type
== ND_ROUTER_ADVERT
)
138 print_ff(msg
, len
, &rcv_addr
, hoplimit
, (unsigned int)pkt_info
->ipi6_ifindex
, edefs
);
142 flog(LOG_ERR
, "received zero lenght packet");
147 flog(LOG_ERR
, "recv_rs_ra: %s", strerror(errno
));
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
];
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);
209 len
-= sizeof(struct nd_router_advert
);
214 opt_str
= (uint8_t *)(msg
+ sizeof(struct nd_router_advert
));
219 struct nd_opt_mtu
*mtu
;
220 struct HomeAgentInfo
*ha_info
;
224 flog(LOG_ERR
, "trailing garbage in RA from %s",
229 optlen
= (opt_str
[1] << 3);
233 flog(LOG_ERR
, "zero length option in RA");
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
);
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
));
252 case ND_OPT_SOURCE_LINKADDR
:
253 /* XXX: !DFLT depends on current DFLT_ value */
254 if (!edefs
|| !DFLT_AdvSourceLLAddress
)
255 printf("\tAdvSourceLLAddress on;\n");
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");
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");
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
));
278 if (!edefs
|| (3*DFLT_MaxRtrAdvInterval
) != ntohs(ha_info
->lifetime
))
279 printf("\tHomeAgentLifetime %hu;\n", ntohs(ha_info
->lifetime
));
281 case ND_OPT_TARGET_LINKADDR
:
282 case ND_OPT_REDIRECTED_HEADER
:
283 flog(LOG_ERR
, "invalid option %d in RA", (int)*opt_str
);
285 case ND_OPT_PREFIX_INFORMATION
:
287 case ND_OPT_ROUTE_INFORMATION
:
289 case ND_OPT_RDNSS_INFORMATION
:
291 case ND_OPT_DNSSL_INFORMATION
:
294 dlog(LOG_DEBUG
, 1, "unknown option %d in RA",
303 orig_len
-= sizeof(struct nd_router_advert
);
308 opt_str
= (uint8_t *)(msg
+ sizeof(struct nd_router_advert
));
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
];
319 int offset
, label_len
;
323 flog(LOG_ERR
, "trailing garbage in RA from %s",
328 optlen
= (opt_str
[1] << 3);
332 flog(LOG_ERR
, "zero length option in RA");
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
);
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");
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");
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");
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);
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");
405 printf("\t\tAdvRouteLifetime %u;\n", ntohl(rinfo
->nd_opt_ri_lifetime
));
407 printf("\t}; # End of route definition\n\n");
409 case ND_OPT_RDNSS_INFORMATION
:
410 rdnss_info
= (struct nd_opt_rdnss_info_local
*) opt_str
;
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
);
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");
431 printf("\t\tAdvRDNSSLifetime %u;\n", ntohl(rdnss_info
->nd_opt_rdnssi_lifetime
));
433 printf("\t}; # End of RDNSS definition\n\n");
435 case ND_OPT_DNSSL_INFORMATION
:
436 dnssl_info
= (struct nd_opt_dnssl_info_local
*) opt_str
;
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')
452 printf(" %s", suffix
);
458 if ((sizeof(suffix
) - strlen(suffix
)) < (label_len
+ 2)) {
459 flog(LOG_ERR
, "oversized suffix in DNSSL option from %s",
464 if (suffix
[0] != '\0')
466 strncat(suffix
, &dnssl_info
->nd_opt_dnssli_suffixes
[offset
], label_len
);
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");
475 printf("\t\tAdvDNSSLLifetime %u;\n", ntohl(dnssl_info
->nd_opt_dnssli_lifetime
));
477 printf("\t}; # End of DNSSL definition\n\n");
486 printf("}; # End of interface definition\n");
492 print_preferences(int p
)
502 /* reserved, ignore */
513 fprintf(stderr
,"Version: %s\n\n", VERSION
);
514 fprintf(stderr
,"Please send bug reports and suggestions to %s\n",
522 fprintf(stderr
,"usage: %s %s\n", pname
, usage_str
);