diff options
Diffstat (limited to 'common/socket.c')
-rw-r--r-- | common/socket.c | 70 |
1 files changed, 64 insertions, 6 deletions
diff --git a/common/socket.c b/common/socket.c index 8879bc20..483eb9c3 100644 --- a/common/socket.c +++ b/common/socket.c @@ -65,6 +65,10 @@ static int no_global_v6_socket = 0; static unsigned int global_v6_socket_references = 0; static int global_v6_socket = -1; +#if defined(RELAY_PORT) +static unsigned int relay_port_v6_socket_references = 0; +static int relay_port_v6_socket = -1; +#endif static void if_register_multicast(struct interface_info *info); #endif @@ -157,6 +161,11 @@ if_register_socket(struct interface_info *info, int family, addr6 = (struct sockaddr_in6 *)&name; addr6->sin6_family = AF_INET6; addr6->sin6_port = local_port; +#if defined(RELAY_PORT) + if (relay_port && + ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM)) + addr6->sin6_port = relay_port; +#endif /* A server feature */ if (bind_local_address6) { memcpy(&addr6->sin6_addr, @@ -187,7 +196,7 @@ if_register_socket(struct interface_info *info, int family, default: addr = (struct sockaddr_in *)&name; addr->sin_family = AF_INET; - addr->sin_port = local_port; + addr->sin_port = relay_port ? relay_port : local_port; memcpy(&addr->sin_addr, &local_address, sizeof(addr->sin_addr)); @@ -496,6 +505,10 @@ if_register6(struct interface_info *info, int do_multicast) { log_fatal("Impossible condition at %s:%d", MDL); } +#if defined(RELAY_PORT) + if (!relay_port || + ((info->flags & INTERFACE_STREAMS) == INTERFACE_DOWNSTREAM)) { +#endif if (global_v6_socket_references == 0) { global_v6_socket = if_register_socket(info, AF_INET6, &req_multi, NULL); @@ -527,6 +540,30 @@ if_register6(struct interface_info *info, int do_multicast) { info->wfdesc = global_v6_socket; global_v6_socket_references++; +#if defined(RELAY_PORT) + } else { + /* + * If relay port is defined, we need to register one + * IPv6 UPD socket to handle upstream server or relay agent + * with a non-547 UDP local port. + */ + if ((relay_port_v6_socket_references == 0) && + ((info->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM)) { + relay_port_v6_socket = if_register_socket(info, AF_INET6, + &req_multi, NULL); + if (relay_port_v6_socket < 0) { + log_fatal("Impossible condition at %s:%d", MDL); + } else { + log_info("Bound to relay port *:%d", + (int) ntohs(relay_port)); + } + } + info->rfdesc = relay_port_v6_socket; + info->wfdesc = relay_port_v6_socket; + relay_port_v6_socket_references++; + } +#endif + if (req_multi) if_register_multicast(info); @@ -617,6 +654,16 @@ if_deregister6(struct interface_info *info) { global_v6_socket_references--; info->rfdesc = -1; info->wfdesc = -1; +#if defined(RELAY_PORT) + } else if (relay_port && + (info->rfdesc == relay_port_v6_socket) && + (info->wfdesc == relay_port_v6_socket) && + (relay_port_v6_socket_references > 0)) { + /* Dereference the relay port v6 socket. */ + relay_port_v6_socket_references--; + info->rfdesc = -1; + info->wfdesc = -1; +#endif } else { log_fatal("Impossible condition at %s:%d", MDL); } @@ -633,12 +680,23 @@ if_deregister6(struct interface_info *info) { } } - if (!no_global_v6_socket && - (global_v6_socket_references == 0)) { - close(global_v6_socket); - global_v6_socket = -1; + if (!no_global_v6_socket) { + if (global_v6_socket_references == 0) { + close(global_v6_socket); + global_v6_socket = -1; - log_info("Unbound from *:%d", ntohs(local_port)); + log_info("Unbound from *:%d", + (int) ntohs(local_port)); + } +#if defined(RELAY_PORT) + if (relay_port && (relay_port_v6_socket_references == 0)) { + close(relay_port_v6_socket); + relay_port_v6_socket = -1; + + log_info("Unbound from relay port *:%d", + (int) ntohs(relay_port)); + } +#endif } } #endif /* DHCPv6 */ |