/* * * Authors: * Lars Fenneberg * * This software is Copyright 1996,1997 by the above mentioned author(s), * All Rights Reserved. * * The license which is distributed with this software in the file COPYRIGHT * applies to this software. If your distribution is missing this file, you * may request it from . * */ #include "config.h" #include "defaults.h" #include "includes.h" #include "radvd.h" #define IFACE_SETUP_DELAY 1 void iface_init_defaults(struct Interface *iface) { memset(iface, 0, sizeof(struct Interface)); iface->state_info.changed = 1; iface->IgnoreIfMissing = DFLT_IgnoreIfMissing; iface->AdvSendAdvert = DFLT_AdvSendAdv; iface->MaxRtrAdvInterval = DFLT_MaxRtrAdvInterval; iface->AdvSourceLLAddress = DFLT_AdvSourceLLAddress; iface->RemoveAdvOnExit = DFLT_RemoveAdvOnExit; iface->MinDelayBetweenRAs = DFLT_MinDelayBetweenRAs; iface->MinRtrAdvInterval = -1; iface->UnicastOnly = DFLT_UnicastOnly; iface->UnrestrictedUnicast = DFLT_UnrestrictedUnicast; iface->AdvRASolicitedUnicast = DFLT_AdvRASolicitedUnicast; iface->ra_header_info.AdvDefaultPreference = DFLT_AdvDefaultPreference; iface->ra_header_info.AdvDefaultLifetime = -1; iface->ra_header_info.AdvReachableTime = DFLT_AdvReachableTime; iface->ra_header_info.AdvRetransTimer = DFLT_AdvRetransTimer; iface->ra_header_info.AdvCurHopLimit = DFLT_AdvCurHopLimit; iface->ra_header_info.AdvHomeAgentFlag = DFLT_AdvHomeAgentFlag; iface->mipv6.AdvIntervalOpt = DFLT_AdvIntervalOpt; iface->mipv6.AdvHomeAgentInfo = DFLT_AdvHomeAgentInfo; iface->mipv6.HomeAgentPreference = DFLT_HomeAgentPreference; iface->mipv6.AdvMobRtrSupportFlag = DFLT_AdvMobRtrSupportFlag; iface->mipv6.HomeAgentLifetime = -1; iface->AdvLinkMTU = DFLT_AdvLinkMTU; iface->AdvRAMTU = DFLT_AdvRAMTU; } void touch_iface(struct Interface *iface) { iface->state_info.changed = 1; iface->state_info.ready = 0; iface->state_info.racount = 0; reschedule_iface(iface, 0); } int setup_iface(int sock, struct Interface *iface) { iface->state_info.changed = 0; iface->state_info.ready = 0; /* The device index must be setup first so we can search it later */ if (update_device_index(iface) < 0) { return -1; } /* Check IFF_UP, IFF_RUNNING and IFF_MULTICAST */ if (check_device(sock, iface) < 0) { return -2; } /* Set iface->max_mtu and iface hardware address */ if (update_device_info(sock, iface) < 0) { return -3; } /* Make sure the settings in the config file for this interface are ok (this depends * on iface->max_mtu already being set). */ if (check_iface(iface) < 0) { return -4; } /* Save the first link local address seen on the specified interface to * iface->props.if_addr and keep a list off all addrs in iface->props.if_addrs */ if (setup_iface_addrs(iface) < 0) { return -5; } /* Check if we a usable RA source address */ if (iface->props.if_addr_rasrc == NULL) { dlog(LOG_DEBUG, 5, "no configured AdvRASrcAddress present, skipping send"); return -6; } /* join the allrouters multicast group so we get the solicitations */ if (setup_allrouters_membership(sock, iface) < 0) { return -7; } iface->state_info.ready = 1; dlog(LOG_DEBUG, 4, "%s is ready", iface->props.name); return 0; } int cleanup_iface(int sock, struct Interface *iface) { /* leave the allrouters multicast group */ cleanup_allrouters_membership(sock, iface); return 0; } void prefix_init_defaults(struct AdvPrefix *prefix) { memset(prefix, 0, sizeof(struct AdvPrefix)); prefix->AdvOnLinkFlag = DFLT_AdvOnLinkFlag; prefix->AdvAutonomousFlag = DFLT_AdvAutonomousFlag; prefix->AdvRouterAddr = DFLT_AdvRouterAddr; prefix->AdvValidLifetime = DFLT_AdvValidLifetime; prefix->AdvPreferredLifetime = DFLT_AdvPreferredLifetime; prefix->DeprecatePrefixFlag = DFLT_DeprecatePrefixFlag; prefix->DecrementLifetimesFlag = DFLT_DecrementLifetimesFlag; prefix->curr_validlft = prefix->AdvValidLifetime; prefix->curr_preferredlft = prefix->AdvPreferredLifetime; } void nat64prefix_init_defaults(struct NAT64Prefix *prefix, struct Interface *iface) { memset(prefix, 0, sizeof(struct NAT64Prefix)); prefix->AdvValidLifetime = min(DFLT_NAT64MaxValidLifetime, 3*(iface->MaxRtrAdvInterval)); prefix->curr_validlft = prefix->AdvValidLifetime; } void route_init_defaults(struct AdvRoute *route, struct Interface *iface) { memset(route, 0, sizeof(struct AdvRoute)); route->AdvRouteLifetime = DFLT_AdvRouteLifetime(iface); route->AdvRoutePreference = DFLT_AdvRoutePreference; route->RemoveRouteFlag = DFLT_RemoveRouteFlag; } void rdnss_init_defaults(struct AdvRDNSS *rdnss, struct Interface *iface) { memset(rdnss, 0, sizeof(struct AdvRDNSS)); rdnss->AdvRDNSSLifetime = DFLT_AdvRDNSSLifetime(iface); rdnss->AdvRDNSSNumber = 0; rdnss->FlushRDNSSFlag = DFLT_FlushRDNSSFlag; } void dnssl_init_defaults(struct AdvDNSSL *dnssl, struct Interface *iface) { memset(dnssl, 0, sizeof(struct AdvDNSSL)); dnssl->AdvDNSSLLifetime = DFLT_AdvDNSSLLifetime(iface); dnssl->FlushDNSSLFlag = DFLT_FlushDNSSLFlag; } int check_iface(struct Interface *iface) { int res = 0; int MIPv6 = 0; struct in6_addr zeroaddr; memset(&zeroaddr, 0, sizeof(zeroaddr)); /* Check if we use Mobile IPv6 extensions */ if (iface->ra_header_info.AdvHomeAgentFlag || iface->mipv6.AdvHomeAgentInfo || iface->mipv6.AdvIntervalOpt) { MIPv6 = 1; flog(LOG_INFO, "using Mobile IPv6 extensions"); } /* Check forwarding on interface */ if (check_ip6_iface_forwarding(iface->props.name) < 1) { flog(LOG_WARNING, "IPv6 forwarding on interface seems to be disabled, but continuing anyway"); } struct AdvPrefix *prefix = iface->AdvPrefixList; while (!MIPv6 && prefix) { if (prefix->AdvRouterAddr) { MIPv6 = 1; } prefix = prefix->next; } if (iface->MinRtrAdvInterval < 0) iface->MinRtrAdvInterval = DFLT_MinRtrAdvInterval(iface); if ((iface->MinRtrAdvInterval < (MIPv6 ? MIN_MinRtrAdvInterval_MIPv6 : MIN_MinRtrAdvInterval)) || (iface->MinRtrAdvInterval > MAX_MinRtrAdvInterval(iface))) { flog(LOG_ERR, "MinRtrAdvInterval for %s (%.2f) must be at least %.2f but no more than 3/4 of MaxRtrAdvInterval (%.2f)", iface->props.name, iface->MinRtrAdvInterval, MIPv6 ? MIN_MinRtrAdvInterval_MIPv6 : (int)MIN_MinRtrAdvInterval, MAX_MinRtrAdvInterval(iface)); res = -1; } if ((iface->MaxRtrAdvInterval < (MIPv6 ? MIN_MaxRtrAdvInterval_MIPv6 : MIN_MaxRtrAdvInterval)) || (iface->MaxRtrAdvInterval > MAX_MaxRtrAdvInterval)) { flog(LOG_ERR, "MaxRtrAdvInterval for %s (%.2f) must be between %.2f and %d", iface->props.name, iface->MaxRtrAdvInterval, MIPv6 ? MIN_MaxRtrAdvInterval_MIPv6 : (int)MIN_MaxRtrAdvInterval, MAX_MaxRtrAdvInterval); res = -1; } if (iface->MinDelayBetweenRAs < (MIPv6 ? MIN_DELAY_BETWEEN_RAS_MIPv6 : MIN_DELAY_BETWEEN_RAS)) { flog(LOG_ERR, "MinDelayBetweenRAs for %s (%.2f) must be at least %.2f", iface->props.name, iface->MinDelayBetweenRAs, MIPv6 ? MIN_DELAY_BETWEEN_RAS_MIPv6 : MIN_DELAY_BETWEEN_RAS); res = -1; } if ((iface->AdvLinkMTU != 0) && ((iface->AdvLinkMTU < MIN_AdvLinkMTU) || (iface->sllao.if_maxmtu != -1 && (iface->AdvLinkMTU > iface->sllao.if_maxmtu)))) { flog(LOG_ERR, "AdvLinkMTU for %s (%u) must be zero or between %u and %u", iface->props.name, iface->AdvLinkMTU, MIN_AdvLinkMTU, iface->sllao.if_maxmtu); res = -1; } if (iface->ra_header_info.AdvReachableTime > MAX_AdvReachableTime) { flog(LOG_ERR, "AdvReachableTime for %s (%u) must not be greater than %u", iface->props.name, iface->ra_header_info.AdvReachableTime, MAX_AdvReachableTime); res = -1; } if (iface->ra_header_info.AdvDefaultLifetime < 0) iface->ra_header_info.AdvDefaultLifetime = DFLT_AdvDefaultLifetime(iface); if ((iface->ra_header_info.AdvDefaultLifetime != 0) && ((iface->ra_header_info.AdvDefaultLifetime > MAX_AdvDefaultLifetime) || (iface->ra_header_info.AdvDefaultLifetime < MIN_AdvDefaultLifetime(iface)))) { flog(LOG_ERR, "AdvDefaultLifetime for %s (%u) must be zero or between %u and %u", iface->props.name, iface->ra_header_info.AdvDefaultLifetime, (int)MIN_AdvDefaultLifetime(iface), MAX_AdvDefaultLifetime); res = -1; } /* Mobile IPv6 ext */ if (iface->mipv6.HomeAgentLifetime < 0) iface->mipv6.HomeAgentLifetime = DFLT_HomeAgentLifetime(iface); /* Mobile IPv6 ext */ if (iface->mipv6.AdvHomeAgentInfo) { if ((iface->mipv6.HomeAgentLifetime > MAX_HomeAgentLifetime) || (iface->mipv6.HomeAgentLifetime < MIN_HomeAgentLifetime)) { flog(LOG_ERR, "HomeAgentLifetime for %s (%u) must be between %u and %u", iface->props.name, iface->mipv6.HomeAgentLifetime, MIN_HomeAgentLifetime, MAX_HomeAgentLifetime); res = -1; } } /* Mobile IPv6 ext */ if (iface->mipv6.AdvHomeAgentInfo && !(iface->ra_header_info.AdvHomeAgentFlag)) { flog(LOG_ERR, "AdvHomeAgentFlag for %s must be set with HomeAgentInfo", iface->props.name); res = -1; } if (iface->mipv6.AdvMobRtrSupportFlag && !(iface->mipv6.AdvHomeAgentInfo)) { flog(LOG_ERR, "AdvHomeAgentInfo for %s must be set with AdvMobRtrSupportFlag", iface->props.name); res = -1; } /* XXX: need this? prefix = iface->AdvPrefixList; */ while (prefix) { if (prefix->PrefixLen > MAX_PrefixLen) { flog(LOG_ERR, "invalid prefix length (%u) for %s", prefix->PrefixLen, iface->props.name); res = -1; } if (prefix->AdvPreferredLifetime > prefix->AdvValidLifetime) { flog(LOG_ERR, "AdvValidLifetime for %s (%u) must be " "greater than or equal to AdvPreferredLifetime for", iface->props.name, prefix->AdvValidLifetime); res = -1; } prefix = prefix->next; } struct AdvRoute *route = iface->AdvRouteList; while (route) { if (route->PrefixLen > MAX_PrefixLen) { flog(LOG_ERR, "invalid route prefix length (%u) for %s", route->PrefixLen, iface->props.name); res = -1; } /* For the default route 0::/0, we need to explicitly check the * lifetime against the AdvDefaultLifetime value. * * If exactly one of the two has a zero value, then nodes processing * the RA may have a flap in their default route. * * AdvDefaultLifetime == 0 && route.AdvRouteLifetime > 0: * - default route is deleted and then re-added. * AdvDefaultLifetime > 0 && route.AdvRouteLifetime == 0: * - default route is added and then deleted. */ if (IN6_IS_ADDR_UNSPECIFIED(&(route->Prefix))) { int route_zerolife = (route->AdvRouteLifetime == 0); int defaultroute_zerolife = (iface->ra_header_info.AdvDefaultLifetime == 0); if (route_zerolife ^ defaultroute_zerolife) { flog( LOG_ERR, "route 0::/0 lifetime (%u) conflicts with AdvDefaultLifetime (%u), default routes will flap!", route->AdvRouteLifetime, iface->ra_header_info.AdvDefaultLifetime); // res = -1; // In some future version, abort on this configuration error. } } route = route->next; } return res; } struct Interface *find_iface_by_index(struct Interface *iface, int index) { for (; iface; iface = iface->next) { if (iface->props.if_index == index) { return iface; } } return 0; } struct Interface *find_iface_by_name(struct Interface *iface, const char *name) { if (!name) { return 0; } for (; iface; iface = iface->next) { if (strcmp(iface->props.name, name) == 0) { return iface; } } return 0; } struct Interface *find_iface_by_time(struct Interface *iface) { if (!iface) { return 0; } int timeout = next_time_msec(iface); struct Interface *next = iface; for (iface = iface->next; iface; iface = iface->next) { int t = next_time_msec(iface); if (timeout > t) { timeout = t; next = iface; } } return next; } void reschedule_iface(struct Interface *iface, double next) { #ifdef HAVE_NETLINK if (!iface->state_info.changed && !iface->state_info.ready) { next = 10 * iface->MaxRtrAdvInterval; } else if (next == 0) { next = IFACE_SETUP_DELAY; } else #endif if (iface->state_info.racount < MAX_INITIAL_RTR_ADVERTISEMENTS) { next = min(MAX_INITIAL_RTR_ADVERT_INTERVAL, iface->MaxRtrAdvInterval); } dlog(LOG_DEBUG, 5, "%s next scheduled RA in %g second(s)", iface->props.name, next); iface->times.next_multicast = next_timespec(next); } void for_each_iface(struct Interface *ifaces, void (*foo)(struct Interface *, void *), void *data) { for (; ifaces; ifaces = ifaces->next) { foo(ifaces, data); } } static void free_iface_list(struct Interface *iface) { while (iface) { struct Interface *next_iface = iface->next; dlog(LOG_DEBUG, 4, "freeing interface %s", iface->props.name); struct AdvPrefix *prefix = iface->AdvPrefixList; while (prefix) { struct AdvPrefix *next_prefix = prefix->next; free(prefix); prefix = next_prefix; } struct AdvRoute *route = iface->AdvRouteList; while (route) { struct AdvRoute *next_route = route->next; free(route); route = next_route; } struct AdvRDNSS *rdnss = iface->AdvRDNSSList; while (rdnss) { struct AdvRDNSS *next_rdnss = rdnss->next; free(rdnss->AdvRDNSSAddr); free(rdnss); rdnss = next_rdnss; } struct AdvDNSSL *dnssl = iface->AdvDNSSLList; while (dnssl) { struct AdvDNSSL *next_dnssl = dnssl->next; for (int i = 0; i < dnssl->AdvDNSSLNumber; i++) free(dnssl->AdvDNSSLSuffixes[i]); free(dnssl->AdvDNSSLSuffixes); free(dnssl); dnssl = next_dnssl; } struct AutogenIgnorePrefix *ignore_prefixes = iface->IgnorePrefixList; while (ignore_prefixes) { struct AutogenIgnorePrefix *next_ignore_prefix = ignore_prefixes->next; free(ignore_prefixes); ignore_prefixes = next_ignore_prefix; } struct Clients *clients = iface->ClientList; while (clients) { struct Clients *next_client = clients->next; free(clients); clients = next_client; } free(iface->props.if_addrs); free(iface->AdvCaptivePortalAPI); free(iface); iface = next_iface; } } void free_ifaces(struct Interface *ifaces) { dlog(LOG_DEBUG, 3, "Freeing Interfaces"); free_iface_list(ifaces); }