IPv6 support for client (#107)
The iodine client now supports both IPv4 and IPv6 nameservers for sending DNS queries to an IPv4 iodined. The nameserver will transparently handle translation between IP protocols. Windows port needs Vista or later to support IPv6.
This commit is contained in:
parent
8baad91156
commit
a1d88c4f0a
77
src/client.c
77
src/client.c
|
@ -29,7 +29,6 @@
|
|||
|
||||
#ifdef WINDOWS32
|
||||
#include "windows.h"
|
||||
#include <winsock2.h>
|
||||
#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");
|
||||
|
|
|
@ -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);
|
||||
|
|
60
src/common.c
60
src/common.c
|
@ -42,6 +42,8 @@
|
|||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#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)
|
||||
{
|
||||
|
|
|
@ -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 *);
|
||||
|
|
24
src/iodine.c
24
src/iodine.c
|
@ -32,6 +32,7 @@
|
|||
#else
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <netdb.h>
|
||||
#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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
18
src/tun.c
18
src/tun.c
|
@ -29,9 +29,8 @@
|
|||
#endif
|
||||
|
||||
#ifdef WINDOWS32
|
||||
#include <winsock2.h>
|
||||
#include <winioctl.h>
|
||||
#include "windows.h"
|
||||
#include <winioctl.h>
|
||||
|
||||
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;
|
||||
|
|
|
@ -17,11 +17,20 @@
|
|||
#ifndef __FIX_WINDOWS_H__
|
||||
#define __FIX_WINDOWS_H__
|
||||
|
||||
#include <w32api.h>
|
||||
/* 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 <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <windns.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <iphlpapi.h>
|
||||
|
||||
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue