diff --git a/src/client.c b/src/client.c index 31f594f..efb0f51 100644 --- a/src/client.c +++ b/src/client.c @@ -29,7 +29,6 @@ #ifdef WINDOWS32 #include "windows.h" -#include #else #ifdef ANDROID #include "android_dns.h" @@ -61,7 +60,7 @@ static void handshake_lazyoff(int dns_fd); static int running; static const char *password; -static struct sockaddr_in nameserv; +static struct sockaddr_storage nameserv; static struct sockaddr_in raw_serv; static const char *topdomain; @@ -149,75 +148,9 @@ client_get_conn() } void -client_set_nameserver(const char *cp, int port) +client_set_nameserver(struct sockaddr_storage *addr, int addrlen) { -#ifdef ANDROID - struct addrinfo hints, *result, *p; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - - char sport[10]; - sprintf(sport, "%d", port); - - getaddrinfo(cp, sport, &hints, &result); - if (result == NULL) - errx(1, "Cannot resolve %s:%s (no network?)", cp, sport); - else { - for (p = result;p != NULL; p = p->ai_next) { - if (p->ai_family == AF_INET) { /* IPv4 */ - struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; - memset(&nameserv, 0, sizeof(nameserv)); - nameserv.sin_family = AF_INET; - nameserv.sin_port = htons(port); - nameserv.sin_addr = ipv4->sin_addr; - freeaddrinfo(result); - return; - } - } - freeaddrinfo(result); - } -#endif - struct in_addr addr; - - if (inet_aton(cp, &addr) != 1) { - /* try resolving if a domain is given */ - struct hostent *host; - const char *err; - host = gethostbyname(cp); - if (host != NULL && h_errno > 0) { - int i = 0; - while (host->h_addr_list[i] != 0) { - addr = *(struct in_addr *) host->h_addr_list[i++]; - fprintf(stderr, "Resolved %s to %s\n", cp, inet_ntoa(addr)); - goto setaddr; - } - } -#ifndef WINDOWS32 - err = hstrerror(h_errno); -#else - { - DWORD wserr = WSAGetLastError(); - switch (wserr) { - case WSAHOST_NOT_FOUND: - err = "Host not found"; - break; - case WSANO_DATA: - err = "No data record found"; - break; - default: - err = "Unknown error"; - break; - } - } -#endif /* !WINDOWS32 */ - errx(1, "error resolving nameserver '%s': %s", cp, err); - } - -setaddr: - memset(&nameserv, 0, sizeof(nameserv)); - nameserv.sin_family = AF_INET; - nameserv.sin_port = htons(port); - nameserv.sin_addr = addr; + memcpy(&nameserv, addr, addrlen); } void @@ -625,12 +558,12 @@ read_dns_withq(int dns_fd, int tun_fd, char *buf, int buflen, struct query *q) Returns >0 on correct replies; value is #valid bytes in *buf. */ { - struct sockaddr_in from; + struct sockaddr_storage from; char data[64*1024]; socklen_t addrlen; int r; - addrlen = sizeof(struct sockaddr); + addrlen = sizeof(from); if ((r = recvfrom(dns_fd, data, sizeof(data), 0, (struct sockaddr*)&from, &addrlen)) < 0) { warn("recvfrom"); diff --git a/src/client.h b/src/client.h index 16ab0e4..fc5625d 100644 --- a/src/client.h +++ b/src/client.h @@ -23,7 +23,7 @@ void client_stop(); enum connection client_get_conn(); const char *client_get_raw_addr(); -void client_set_nameserver(const char *cp, int port); +void client_set_nameserver(struct sockaddr_storage *, int); void client_set_topdomain(const char *cp); void client_set_password(const char *cp); void set_qtype(char *qtype); diff --git a/src/common.c b/src/common.c index fe88112..19fdb95 100644 --- a/src/common.c +++ b/src/common.c @@ -42,6 +42,8 @@ #include #include #include +#include +#include #endif #ifdef HAVE_SETCON @@ -111,21 +113,40 @@ check_superuser(void (*usage_fn)(void)) #endif } -int -open_dns(int localport, in_addr_t listen_ip) +int +get_addr(char *host, int port, int addr_family, int flags, struct sockaddr_storage *out) +{ + struct addrinfo hints, *addr; + int res; + char portnum[8]; + + memset(portnum, 0, sizeof(portnum)); + snprintf(portnum, sizeof(portnum) - 1, "%d", port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = addr_family; + hints.ai_flags = AI_ADDRCONFIG | flags; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + + res = getaddrinfo(host, portnum, &hints, &addr); + if (res == 0) { + int addrlen = addr->ai_addrlen; + /* Grab first result */ + memcpy(out, addr->ai_addr, addr->ai_addrlen); + freeaddrinfo(addr); + return addrlen; + } + return res; +} + +int +open_dns(struct sockaddr_storage *sockaddr, size_t sockaddr_len) { - struct sockaddr_in addr; int flag = 1; int fd; - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(localport); - /* listen_ip already in network byte order from inet_addr, or 0 */ - addr.sin_addr.s_addr = listen_ip; - - if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - fprintf(stderr, "got fd %d\n", fd); + if ((fd = socket(sockaddr->ss_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) { err(1, "socket"); } @@ -146,14 +167,27 @@ open_dns(int localport, in_addr_t listen_ip) setsockopt(fd, IPPROTO_IP, IP_OPT_DONT_FRAG, (const void*) &flag, sizeof(flag)); #endif - if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) + if(bind(fd, (struct sockaddr*) sockaddr, sockaddr_len) < 0) err(1, "bind"); - fprintf(stderr, "Opened UDP socket\n"); + fprintf(stderr, "Opened IPv%d UDP socket\n", sockaddr->ss_family == AF_INET6 ? 6 : 4); return fd; } +int +open_dns_from_host(char *host, int port, int addr_family, int flags) +{ + struct sockaddr_storage addr; + int addrlen; + + addrlen = get_addr(host, port, addr_family, flags, &addr); + if (addrlen < 0) + return addrlen; + + return open_dns(&addr, addrlen); +} + void close_dns(int fd) { diff --git a/src/common.h b/src/common.h index 4f8a6fc..9163834 100644 --- a/src/common.h +++ b/src/common.h @@ -93,7 +93,7 @@ struct query { unsigned short rcode; unsigned short id; struct in_addr destination; - struct sockaddr from; + struct sockaddr_storage from; int fromlen; unsigned short id2; struct sockaddr from2; @@ -107,7 +107,9 @@ enum connection { }; void check_superuser(void (*usage_fn)(void)); -int open_dns(int, in_addr_t); +int get_addr(char *, int, int, int, struct sockaddr_storage *); +int open_dns(struct sockaddr_storage *, size_t); +int open_dns_from_host(char *host, int port, int addr_family, int flags); void close_dns(int); void do_chroot(char *); diff --git a/src/iodine.c b/src/iodine.c index 93d55f0..eb4185e 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -32,6 +32,7 @@ #else #include #include +#include #endif #include "common.h" @@ -111,7 +112,7 @@ version() { int main(int argc, char **argv) { - char *nameserv_addr; + char *nameserv_host; char *topdomain; #ifndef WINDOWS32 struct passwd *pw; @@ -134,8 +135,10 @@ main(int argc, char **argv) int selecttimeout; int hostname_maxlen; int rtable = 0; + struct sockaddr_storage nameservaddr; + int nameservaddr_len; - nameserv_addr = NULL; + nameserv_host = NULL; topdomain = NULL; #ifndef WINDOWS32 pw = NULL; @@ -257,11 +260,11 @@ main(int argc, char **argv) switch (argc) { case 1: - nameserv_addr = get_resolvconf_addr(); + nameserv_host = get_resolvconf_addr(); topdomain = strdup(argv[0]); break; case 2: - nameserv_addr = argv[0]; + nameserv_host = argv[0]; topdomain = strdup(argv[1]); break; default: @@ -275,8 +278,13 @@ main(int argc, char **argv) /* NOTREACHED */ } - if (nameserv_addr) { - client_set_nameserver(nameserv_addr, DNS_PORT); + if (nameserv_host) { + nameservaddr_len = get_addr(nameserv_host, DNS_PORT, AF_UNSPEC, 0, &nameservaddr); + if (nameservaddr_len < 0) { + errx(1, "Cannot lookup nameserver '%s': %s ", + nameserv_host, gai_strerror(nameservaddr_len)); + } + client_set_nameserver(&nameservaddr, nameservaddr_len); } else { warnx("No nameserver found - not connected to any network?\n"); usage(); @@ -323,7 +331,7 @@ main(int argc, char **argv) retval = 1; goto cleanup1; } - if ((dns_fd = open_dns(0, INADDR_ANY)) == -1) { + if ((dns_fd = open_dns_from_host(NULL, 53, nameservaddr.ss_family, AI_PASSIVE)) < 0) { retval = 1; goto cleanup2; } @@ -338,7 +346,7 @@ main(int argc, char **argv) signal(SIGTERM, sighandler); fprintf(stderr, "Sending DNS queries for %s to %s\n", - topdomain, nameserv_addr); + topdomain, nameserv_host); if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) { retval = 1; diff --git a/src/iodined.c b/src/iodined.c index b39c896..d83893c 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -221,7 +221,7 @@ send_raw(int fd, char *buf, int buflen, int user, int cmd, struct query *q) inet_ntoa(tempin->sin_addr), cmd, len); } - sendto(fd, packet, len, 0, &q->from, q->fromlen); + sendto(fd, packet, len, 0, (struct sockaddr *) &q->from, q->fromlen); } @@ -2241,7 +2241,7 @@ int main(int argc, char **argv) { extern char *__progname; - in_addr_t listen_ip; + char *listen_ip; #ifndef WINDOWS32 struct passwd *pw; #endif @@ -2267,6 +2267,8 @@ main(int argc, char **argv) int ns_get_externalip; int retval; int max_idle_time = 0; + struct sockaddr_storage dnsaddr; + int dnsaddr_len; #ifdef HAVE_SYSTEMD int nb_fds; #endif @@ -2283,7 +2285,7 @@ main(int argc, char **argv) bind_fd = 0; mtu = 1130; /* Very many relays give fragsize 1150 or slightly higher for NULL; tun/zlib adds ~17 bytes. */ - listen_ip = INADDR_ANY; + listen_ip = NULL; port = 53; ns_ip = INADDR_ANY; ns_get_externalip = 0; @@ -2349,7 +2351,7 @@ main(int argc, char **argv) mtu = atoi(optarg); break; case 'l': - listen_ip = inet_addr(optarg); + listen_ip = optarg; break; case 'p': port = atoi(optarg); @@ -2439,23 +2441,6 @@ main(int argc, char **argv) usage(); } - if(bind_enable) { - if (bind_port < 1 || bind_port > 65535) { - warnx("Bad DNS server port number given."); - usage(); - /* NOTREACHED */ - } - /* Avoid forwarding loops */ - if (bind_port == port && (listen_ip == INADDR_ANY || listen_ip == htonl(0x7f000001L))) { - warnx("Forward port is same as listen port (%d), will create a loop!", bind_port); - fprintf(stderr, "Use -l to set listen ip to avoid this.\n"); - usage(); - /* NOTREACHED */ - } - fprintf(stderr, "Requests for domains outside of %s will be forwarded to port %d\n", - topdomain, bind_port); - } - if (port != 53) { fprintf(stderr, "ALERT! Other dns servers expect you to run on port 53.\n"); fprintf(stderr, "You must manually forward port 53 to port %d for things to work.\n", port); @@ -2467,11 +2452,30 @@ main(int argc, char **argv) foreground = 1; } - if (listen_ip == INADDR_NONE) { + dnsaddr_len = get_addr(listen_ip, port, AF_INET, AI_PASSIVE | AI_NUMERICHOST, &dnsaddr); + if (dnsaddr_len < 0) { warnx("Bad IP address to listen on."); usage(); } - + + if(bind_enable) { + in_addr_t dns_ip = ((struct sockaddr_in *) &dnsaddr)->sin_addr.s_addr; + if (bind_port < 1 || bind_port > 65535) { + warnx("Bad DNS server port number given."); + usage(); + /* NOTREACHED */ + } + /* Avoid forwarding loops */ + if (bind_port == port && (dns_ip == INADDR_ANY || dns_ip == htonl(0x7f000001L))) { + warnx("Forward port is same as listen port (%d), will create a loop!", bind_port); + fprintf(stderr, "Use -l to set listen ip to avoid this.\n"); + usage(); + /* NOTREACHED */ + } + fprintf(stderr, "Requests for domains outside of %s will be forwarded to port %d\n", + topdomain, bind_port); + } + if (ns_get_externalip) { struct in_addr extip; int res = get_external_ip(&extip); @@ -2524,7 +2528,7 @@ main(int argc, char **argv) dnsd_fd = SD_LISTEN_FDS_START; } else { #endif - if ((dnsd_fd = open_dns(port, listen_ip)) == -1) { + if ((dnsd_fd = open_dns(&dnsaddr, dnsaddr_len)) < 0) { retval = 1; goto cleanup2; } @@ -2532,7 +2536,7 @@ main(int argc, char **argv) } #endif if (bind_enable) { - if ((bind_fd = open_dns(0, INADDR_ANY)) == -1) { + if ((bind_fd = open_dns_from_host(NULL, 0, AF_INET, 0)) < 0) { retval = 1; goto cleanup3; } diff --git a/src/tun.c b/src/tun.c index 734557b..301e08d 100644 --- a/src/tun.c +++ b/src/tun.c @@ -29,9 +29,8 @@ #endif #ifdef WINDOWS32 -#include -#include #include "windows.h" +#include HANDLE dev_handle; struct tun_data data; @@ -300,7 +299,7 @@ DWORD WINAPI tun_reader(LPVOID arg) WaitForSingleObject(olpd.hEvent, INFINITE); res = GetOverlappedResult(dev_handle, &olpd, (LPDWORD) &len, FALSE); res = sendto(sock, buf, len, 0, (struct sockaddr*) &(tun->addr), - sizeof(struct sockaddr_in)); + tun->addrlen); } } @@ -313,7 +312,8 @@ open_tun(const char *tun_device) char adapter[256]; char tapfile[512]; int tunfd; - in_addr_t local; + struct sockaddr_storage localsock; + int localsock_len; memset(adapter, 0, sizeof(adapter)); memset(if_name, 0, sizeof(if_name)); @@ -341,14 +341,12 @@ open_tun(const char *tun_device) * A thread does blocking reads on tun device and * sends data as udp to this socket */ - local = htonl(0x7f000001); /* 127.0.0.1 */ - tunfd = open_dns(55353, local); + localsock_len = get_addr("127.0.0.1", 55353, AF_INET, 0, &localsock); + tunfd = open_dns(&localsock, localsock_len); data.tun = dev_handle; - memset(&(data.addr), 0, sizeof(data.addr)); - data.addr.sin_family = AF_INET; - data.addr.sin_port = htons(55353); - data.addr.sin_addr.s_addr = local; + memcpy(&(data.addr), &localsock, localsock_len); + data.addrlen = localsock_len; CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tun_reader, &data, 0, NULL); return tunfd; diff --git a/src/windows.h b/src/windows.h index 7e0e16c..a002b55 100644 --- a/src/windows.h +++ b/src/windows.h @@ -17,11 +17,20 @@ #ifndef __FIX_WINDOWS_H__ #define __FIX_WINDOWS_H__ +#include +/* Need Vista or Later to get IPv6 support */ +#undef WINVER +#undef _WIN32_WINDOWS +#undef _WIN32_WINNT +#define WINVER WindowsVista +#define _WIN32_WINDOWS WindowsVista +#define _WIN32_WINNT WindowsVista + typedef unsigned int in_addr_t; +#include #include #include -#include #include #include @@ -94,7 +103,8 @@ DWORD WINAPI tun_reader(LPVOID arg); struct tun_data { HANDLE tun; int sock; - struct sockaddr_in addr; + struct sockaddr_storage addr; + int addrlen; }; #endif