[dhcp6relay] Add retry mechanism for binding socket to interface ipv6 addresses (#10712)

This commit is contained in:
kellyyeh 2022-05-02 17:14:13 -07:00 committed by GitHub
parent a1e76d25b7
commit 243d0c73f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -378,44 +378,57 @@ void prepare_socket(int *local_sock, int *server_sock, relay_config *config, int
memset(&ll_addr, 0, sizeof(ll_addr)); memset(&ll_addr, 0, sizeof(ll_addr));
if ((*local_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { if ((*local_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) {
syslog(LOG_ERR, "socket: Failed to create socket\n"); syslog(LOG_ERR, "socket: Failed to create socket on interface %s\n", config->interface.c_str());
} }
if ((*server_sock= socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { if ((*server_sock= socket(AF_INET6, SOCK_DGRAM, 0)) == -1) {
syslog(LOG_ERR, "socket: Failed to create socket\n"); syslog(LOG_ERR, "socket: Failed to create socket on interface %s\n", config->interface.c_str());
} }
int retry = 0;
if (getifaddrs(&ifa) == -1) { bool bind_addr = false;
syslog(LOG_WARNING, "getifaddrs: Unable to get network interfaces\n"); bool bind_ll_addr = false;
exit(1); do {
} if (getifaddrs(&ifa) == -1) {
syslog(LOG_WARNING, "getifaddrs: Unable to get network interfaces with %s\n", strerror(errno));
ifa_tmp = ifa; }
while (ifa_tmp) { else {
if (ifa_tmp->ifa_addr->sa_family == AF_INET6) { ifa_tmp = ifa;
struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr; while (ifa_tmp) {
if((strcmp(ifa_tmp->ifa_name, config->interface.c_str()) == 0) && !IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { if ((ifa_tmp->ifa_addr->sa_family == AF_INET6) && (strcmp(ifa_tmp->ifa_name, config->interface.c_str()) == 0)) {
in6->sin6_family = AF_INET6; struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr;
in6->sin6_port = htons(RELAY_PORT); if(!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
addr = *in6; bind_addr = true;
} in6->sin6_family = AF_INET6;
if((strcmp(ifa_tmp->ifa_name, config->interface.c_str()) == 0) && IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) { in6->sin6_port = htons(RELAY_PORT);
in6->sin6_family = AF_INET6; addr = *in6;
in6->sin6_port = htons(RELAY_PORT); }
ll_addr = *in6; if(IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
} bind_ll_addr = true;
in6->sin6_family = AF_INET6;
in6->sin6_port = htons(RELAY_PORT);
ll_addr = *in6;
}
}
ifa_tmp = ifa_tmp->ifa_next;
}
freeifaddrs(ifa);
} }
ifa_tmp = ifa_tmp->ifa_next;
}
freeifaddrs(ifa);
if (bind(*local_sock, (sockaddr *)&addr, sizeof(addr)) == -1) { if (bind_addr && bind_ll_addr) {
syslog(LOG_ERR, "bind: Failed to bind to socket\n"); break;
}
syslog(LOG_WARNING, "Retry #%d to bind to sockets on interface %s\n", ++retry, config->interface.c_str());
sleep(5);
} while (retry < 6);
if ((!bind_addr) || (bind(*local_sock, (sockaddr *)&addr, sizeof(addr)) == -1)) {
syslog(LOG_ERR, "bind: Failed to bind socket to global ipv6 address on interface %s after %d retries with %s\n", config->interface.c_str(), retry, strerror(errno));
} }
if (bind(*server_sock, (sockaddr *)&ll_addr, sizeof(addr)) == -1) { if ((!bind_ll_addr) || (bind(*server_sock, (sockaddr *)&ll_addr, sizeof(addr)) == -1)) {
syslog(LOG_ERR, "bind: Failed to bind to socket\n"); syslog(LOG_ERR, "bind: Failed to bind socket to link local ipv6 address on interface %s after %d retries with %s\n", config->interface.c_str(), retry, strerror(errno));
} }
} }