diff --git a/src/common.c b/src/common.c index 5af566e..d9f7ba0 100644 --- a/src/common.c +++ b/src/common.c @@ -155,6 +155,49 @@ open_dns(int localport, in_addr_t listen_ip) return fd; } +int +open_dns_ipv6(int localport, struct in6_addr listen_ip6) +{ + struct sockaddr_in6 addr; + int flag = 1; + int fd; + + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(localport); + /* listen_ip already in network byte order from inet_addr, or 0 */ + addr.sin6_addr = listen_ip6; + + if ((fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + fprintf(stderr, "got fd %d\n", fd); + err(1, "socket"); + } + + flag = 1; +#ifdef SO_REUSEPORT + setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &flag, sizeof(flag)); +#endif + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &flag, sizeof(flag)); + +#ifndef WINDOWS32 + /* To get destination address from each UDP datagram, see iodined.c:read_dns() */ + setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, (const void*) &flag, sizeof(flag)); +#endif + +#ifdef IP_OPT_DONT_FRAG + /* Set dont-fragment ip header flag */ + flag = DONT_FRAG_VALUE; + setsockopt(fd, IPPROTO_IP, IP_OPT_DONT_FRAG, (const void*) &flag, sizeof(flag)); +#endif + + if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) + err(1, "bind"); + + fprintf(stderr, "Opened IPv6 UDP socket\n"); + + return fd; +} + void close_dns(int fd) { diff --git a/src/common.h b/src/common.h index 022a9b1..662b06a 100644 --- a/src/common.h +++ b/src/common.h @@ -110,6 +110,7 @@ enum connection { void check_superuser(void (*usage_fn)(void)); int open_dns(int, in_addr_t); +int open_dns_ipv6(int localport, struct in6_addr listen_ip6); void close_dns(int); void do_chroot(char *); diff --git a/src/iodined.c b/src/iodined.c index 59b373c..3816f40 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -2289,6 +2289,9 @@ main(int argc, char **argv) int dnsd_fd; int tun_fd; + int v6_listen; + + /* settings for forwarding normal DNS to * local real DNS server */ int bind_fd; @@ -2324,6 +2327,7 @@ main(int argc, char **argv) pidfile = NULL; #ifdef LINUX v6 = 0; + v6_listen = 1; #endif b32 = get_base32_encoder(); @@ -2592,10 +2596,13 @@ main(int argc, char **argv) #endif free((void*) other_ip); } - if ((dnsd_fd = open_dns(port, listen_ip)) == -1) { + if ((dnsd_fd = v6_listen ? open_dns_ipv6(port, in6addr_any) : open_dns(port, listen_ip)) == -1) { retval = 1; goto cleanup2; } + /** + * Todo: IPv6? + */ if (bind_enable) { if ((bind_fd = open_dns(0, INADDR_ANY)) == -1) { retval = 1;