diff --git a/CHANGELOG b/CHANGELOG index 6bb566d..0f01ad3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,10 @@ version 2.79 Fix parsing of CNAME arguments, which are confused by extra spaces. Thanks to Diego Aguirre for spotting the bug. + Where available, use IP_UNICAST_IF or IPV6_UNICAST_IF to bind + upstream servers to an interface, rather than SO_BINDTODEVICE. + Thanks to Beniamino Galvani for the patch. + version 2.78 Fix logic of appending "." to PXE basename. Thanks to Chris diff --git a/src/dnsmasq.h b/src/dnsmasq.h index c30a2f1..563443e 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1254,7 +1254,7 @@ void free_rfd(struct randfd *rfd); /* network.c */ int indextoname(int fd, int index, char *name); -int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp); +int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp); int random_sock(int family); void pre_allocate_sfds(void); int reload_servers(char *fname); diff --git a/src/forward.c b/src/forward.c index 942b02d..c2c50ec 100644 --- a/src/forward.c +++ b/src/forward.c @@ -1551,7 +1551,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si setsockopt(server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); #endif - if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 1) || + if (!local_bind(server->tcpfd, &server->source_addr, server->interface, 0, 1) || connect(server->tcpfd, &server->addr.sa, sa_len(&server->addr)) == -1) { close(server->tcpfd); @@ -1847,7 +1847,7 @@ unsigned char *tcp_request(int confd, time_t now, setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int)); #endif - if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) || + if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 0, 1) || connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)) { close(last_server->tcpfd); diff --git a/src/network.c b/src/network.c index 622c787..7395cfd 100644 --- a/src/network.c +++ b/src/network.c @@ -1187,7 +1187,7 @@ int random_sock(int family) } -int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp) +int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifindex, int is_tcp) { union mysockaddr addr_copy = *addr; @@ -1204,7 +1204,25 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, int is_tcp) if (bind(fd, (struct sockaddr *)&addr_copy, sa_len(&addr_copy)) == -1) return 0; - + + if (!is_tcp && ifindex > 0) + { +#if defined(IP_UNICAST_IF) + if (addr_copy.sa.sa_family == AF_INET) + { + uint32_t ifindex_opt = htonl(ifindex); + return setsockopt(fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex_opt, sizeof(ifindex_opt)) == 0; + } +#endif +#if defined(HAVE_IPV6) && defined (IPV6_UNICAST_IF) + if (addr_copy.sa.sa_family == AF_INET6) + { + uint32_t ifindex_opt = htonl(ifindex); + return setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_IF, &ifindex_opt, sizeof(ifindex_opt)) == 0; + } +#endif + } + #if defined(SO_BINDTODEVICE) if (intname[0] != 0 && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intname, IF_NAMESIZE) == -1) @@ -1260,7 +1278,7 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname) return NULL; } - if (!local_bind(sfd->fd, addr, intname, 0) || !fix_fd(sfd->fd)) + if (!local_bind(sfd->fd, addr, intname, ifindex, 0) || !fix_fd(sfd->fd)) { errsave = errno; /* save error from bind. */ close(sfd->fd);