diff options
author | Evan Hunt <each@isc.org> | 2008-06-13 00:55:53 +0000 |
---|---|---|
committer | Evan Hunt <each@isc.org> | 2008-06-13 00:55:53 +0000 |
commit | 7de20a9518b7f6073c83702b34fe9d7fcb2abfb6 (patch) | |
tree | b6d0a5042ebbe530bc5d733468f698ba4de247a4 /common/socket.c | |
parent | ffbaa8801ec3e4806ac70acbeaaa672b0024fe22 (diff) | |
download | isc-dhcp-7de20a9518b7f6073c83702b34fe9d7fcb2abfb6.tar.gz |
- Merge dhcrelay6 into dhcrelay
- Prep for 4.1.0a2 release
Diffstat (limited to 'common/socket.c')
-rw-r--r-- | common/socket.c | 64 |
1 files changed, 62 insertions, 2 deletions
diff --git a/common/socket.c b/common/socket.c index db9d8a3d..c748875f 100644 --- a/common/socket.c +++ b/common/socket.c @@ -95,6 +95,40 @@ void if_reinitialize_receive (info) #if defined (USE_SOCKET_SEND) || \ defined (USE_SOCKET_RECEIVE) || \ defined (USE_SOCKET_FALLBACK) +#ifdef DHCPv6 +/* Get the best (i.e., global or at least site-local) address + of the interface. */ +static isc_result_t +get_ifaddr6(struct interface_info *info, struct in6_addr *ifaddr6) { + int i; + struct in6_addr *a, *ba = NULL; + + for (i = 0; i < info->v6address_count; i++) { + a = &info->v6addresses[i]; + if (IN6_IS_ADDR_UNSPECIFIED(a) || + IN6_IS_ADDR_LOOPBACK(a) || + IN6_IS_ADDR_MULTICAST(a) || + IN6_IS_ADDR_LINKLOCAL(a) || + IN6_IS_ADDR_V4MAPPED(a)) + continue; + + if (ba == NULL) + ba = a; + + if (!IN6_IS_ADDR_SITELOCAL(a)) { + ba = a; + break; + } + } + + if (ba == NULL) + return ISC_R_NOTFOUND; + + *ifaddr6 = *ba; + return ISC_R_SUCCESS; +} +#endif /* DHCPv6 */ + /* Generic interface registration routine... */ int if_register_socket(struct interface_info *info, int family, int do_multicast) { @@ -128,8 +162,21 @@ if_register_socket(struct interface_info *info, int family, int do_multicast) { memcpy(&addr->sin6_addr, &local_address6, sizeof(addr->sin6_addr)); +#ifdef HAVE_SA_LEN + addr->sin6_len = sizeof(*addr); +#endif name_len = sizeof(*addr); domain = PF_INET6; + if ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM) { + struct in6_addr ifaddr6; + + do_multicast = 0; + if (get_ifaddr6(info, &ifaddr6) == ISC_R_SUCCESS) { + memcpy(&addr->sin6_addr, + &ifaddr6, + sizeof(addr->sin6_addr)); + } + } } else { #else { @@ -140,6 +187,9 @@ if_register_socket(struct interface_info *info, int family, int do_multicast) { memcpy(&addr->sin_addr, &local_address, sizeof(addr->sin_addr)); +#ifdef HAVE_SA_LEN + addr->sin_len = sizeof(*addr); +#endif name_len = sizeof(*addr); domain = PF_INET; } @@ -246,11 +296,21 @@ if_register_socket(struct interface_info *info, int family, int do_multicast) { All_DHCP_Servers); } mreq.ipv6mr_interface = if_nametoindex(info->name); - if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, - &mreq, sizeof(mreq)) < 0) { + if (((info->flags & INTERFACE_DOWNSTREAM) == 0) && + (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq, sizeof(mreq)) < 0)) { log_fatal("setsockopt: IPV6_JOIN_GROUP: %m"); } } + + if ((family == AF_INET6) && + ((info->flags & INTERFACE_UPSTREAM) != 0)) { + int hop_limit = 32; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &hop_limit, sizeof(int)) < 0) { + log_fatal("setsockopt: IPV6_MULTICAST_HOPS: %m"); + } + } #endif /* DHCPv6 */ if (strcmp(info->name, "fallback") != 0) |