From 5d8801d4687035ae45143f0f3bc3eeaf75dc17ec Mon Sep 17 00:00:00 2001 From: Yves Fischer Date: Mon, 11 Aug 2014 23:26:36 +0200 Subject: Upgrade code to iodine 0.7.0 and improve logging --- jni/iodine/src/Android.mk | 22 ++ jni/iodine/src/Makefile | 5 +- jni/iodine/src/android_dns.h | 39 +++ jni/iodine/src/base128.c | 12 +- jni/iodine/src/base32.c | 21 +- jni/iodine/src/base32.h | 3 +- jni/iodine/src/base64.c | 15 +- jni/iodine/src/base64.h | 3 +- jni/iodine/src/client.c | 463 ++++++++++++++------------------ jni/iodine/src/client.h | 11 +- jni/iodine/src/common.c | 262 +++++++++++++----- jni/iodine/src/common.h | 53 ++-- jni/iodine/src/dns.c | 86 +++--- jni/iodine/src/dns.h | 7 +- jni/iodine/src/dns_android.h | 625 ------------------------------------------- jni/iodine/src/encoding.c | 22 +- jni/iodine/src/encoding.h | 3 +- jni/iodine/src/fw_query.c | 6 +- jni/iodine/src/fw_query.h | 4 +- jni/iodine/src/iodine.c | 106 +++++--- jni/iodine/src/iodined.c | 477 +++++++++++++++++++++------------ jni/iodine/src/login.c | 14 +- jni/iodine/src/login.h | 3 +- jni/iodine/src/md5.h | 2 +- jni/iodine/src/osflags | 13 +- jni/iodine/src/read.c | 25 +- jni/iodine/src/read.h | 5 +- jni/iodine/src/tun.c | 285 +++++++++++--------- jni/iodine/src/tun.h | 3 +- jni/iodine/src/user.c | 59 ++-- jni/iodine/src/user.h | 9 +- jni/iodine/src/util.c | 34 ++- jni/iodine/src/util.h | 1 + jni/iodine/src/version.h | 3 +- jni/iodine/src/windows.h | 8 +- 35 files changed, 1235 insertions(+), 1474 deletions(-) create mode 100644 jni/iodine/src/Android.mk create mode 100644 jni/iodine/src/android_dns.h delete mode 100644 jni/iodine/src/dns_android.h (limited to 'jni/iodine/src') diff --git a/jni/iodine/src/Android.mk b/jni/iodine/src/Android.mk new file mode 100644 index 0000000..8f7c729 --- /dev/null +++ b/jni/iodine/src/Android.mk @@ -0,0 +1,22 @@ +# +# iodine for Android +# +# by Marcel Bokhorst +# http://blog.bokhorst.biz/5123/computers-en-internet/iodine-for-android/ +# +# cd iodine-0.6.0-rc1/src +# make base64u.h base64u.c +# .../ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk +# + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := iodine +LOCAL_SRC_FILES := tun.c dns.c read.c encoding.c login.c base32.c base64.c base64u.c base128.c md5.c common.c iodine.c client.c util.c +LOCAL_CFLAGS := -c -DANDROID -DLINUX -DIFCONFIGPATH=\"/system/bin/\" -Wall +LOCAL_LDLIBS := -lz + +include $(BUILD_EXECUTABLE) + diff --git a/jni/iodine/src/Makefile b/jni/iodine/src/Makefile index a5b9838..80bd345 100644 --- a/jni/iodine/src/Makefile +++ b/jni/iodine/src/Makefile @@ -9,7 +9,7 @@ ARCH = `uname -m` LIBPATH = -L. LDFLAGS += -lz `sh osflags $(TARGETOS) link` $(LIBPATH) -CFLAGS += -c -g -Wall -D$(OS) -pedantic `sh osflags $(TARGETOS) cflags` +CFLAGS += -std=c99 -c -g -Wall -D$(OS) -pedantic `sh osflags $(TARGETOS) cflags` all: stateos $(CLIENT) $(SERVER) @@ -26,7 +26,7 @@ $(SERVER): $(COMMONOBJS) $(SERVEROBJS) @mkdir -p ../bin @$(CC) $(COMMONOBJS) $(SERVEROBJS) -o $(SERVER) $(LDFLAGS) -.c.o: +.c.o: @echo CC $< @$(CC) $(CFLAGS) $< -o $@ @@ -43,4 +43,5 @@ base64u.h: base64.h clean: @echo "Cleaning src/" @rm -f $(CLIENT){,.exe} $(SERVER){,.exe} *~ *.o *.core base64u.* + @rm -rf obj libs #android stuff diff --git a/jni/iodine/src/android_dns.h b/jni/iodine/src/android_dns.h new file mode 100644 index 0000000..dafd8ec --- /dev/null +++ b/jni/iodine/src/android_dns.h @@ -0,0 +1,39 @@ + +#ifndef __FIX_ANDROID_H__ +#define __FIX_ANDROID_H__ + +typedef struct { + unsigned id :16; + unsigned rd :1; + unsigned tc :1; + unsigned aa :1; + unsigned opcode :4; + unsigned qr :1; + unsigned rcode :4; + unsigned cd: 1; + unsigned ad: 1; + unsigned unused :1; + unsigned ra :1; + unsigned qdcount :16; + unsigned ancount :16; + unsigned nscount :16; + unsigned arcount :16; +} HEADER; + +#define NOERROR 0 +#define FORMERR 1 +#define SERVFAIL 2 +#define NXDOMAIN 3 +#define NOTIMP 4 +#define REFUSED 5 + +#define C_IN 1 + +#define T_A 1 +#define T_CNAME 5 +#define T_NULL 10 +#define T_MX 15 +#define T_TXT 16 +#define T_SRV 33 + +#endif diff --git a/jni/iodine/src/base128.c b/jni/iodine/src/base128.c index 32a29f8..7ddc38c 100644 --- a/jni/iodine/src/base128.c +++ b/jni/iodine/src/base128.c @@ -42,7 +42,7 @@ * accent chars since they might readily be entered in normal use, * don't use 254-255 because of possible function overloading in DNS systems. */ -static const unsigned char cb128[] = +static const unsigned char cb128[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" "\274\275\276\277" "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" @@ -75,19 +75,19 @@ struct encoder return &base128_encoder; } -static int +static int base128_handles_dots() { return 0; } -static int +static int base128_blksize_raw() { return BLKSIZE_RAW; } -static int +static int base128_blksize_enc() { return BLKSIZE_ENC; @@ -109,7 +109,7 @@ base128_reverse_init() } } -static int +static int base128_encode(char *buf, size_t *buflen, const void *data, size_t size) /* * Fills *buf with max. *buflen characters, encoding size bytes of *data. @@ -231,7 +231,7 @@ base128_decode(void *buf, size_t *buflen, const char *str, size_t slen) if (iout >= *buflen || iin + 1 >= slen || str[iin] == '\0' || str[iin + 1] == '\0') break; - ubuf[iout] = ((REV128(ustr[iin]) & 0x7f) << 1) | + ubuf[iout] = ((REV128(ustr[iin]) & 0x7f) << 1) | ((REV128(ustr[iin + 1]) & 0x40) >> 6); iin++; /* 0 used up, iin=1 */ iout++; diff --git a/jni/iodine/src/base32.c b/jni/iodine/src/base32.c index 8731a92..d971ce2 100644 --- a/jni/iodine/src/base32.c +++ b/jni/iodine/src/base32.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl * * Permission to use, copy, modify, and distribute this software for any @@ -25,9 +26,9 @@ #define BLKSIZE_RAW 5 #define BLKSIZE_ENC 8 -static const char cb32[] = +static const char cb32[] = "abcdefghijklmnopqrstuvwxyz012345"; -static const char cb32_ucase[] = +static const char cb32_ucase[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; static unsigned char rev32[256]; static int reverse_init = 0; @@ -55,19 +56,19 @@ struct encoder return &base32_encoder; } -static int +static int base32_handles_dots() { return 0; } -static int +static int base32_blksize_raw() { return BLKSIZE_RAW; } -static int +static int base32_blksize_enc() { return BLKSIZE_ENC; @@ -104,7 +105,7 @@ b32_8to5(int in) return rev32[in]; } -static int +static int base32_encode(char *buf, size_t *buflen, const void *data, size_t size) /* * Fills *buf with max. *buflen characters, encoding size bytes of *data. @@ -222,7 +223,7 @@ base32_decode(void *buf, size_t *buflen, const char *str, size_t slen) if (iout >= *buflen || iin + 1 >= slen || str[iin] == '\0' || str[iin + 1] == '\0') break; - ubuf[iout] = ((REV32(str[iin]) & 0x1f) << 3) | + ubuf[iout] = ((REV32(str[iin]) & 0x1f) << 3) | ((REV32(str[iin + 1]) & 0x1c) >> 2); iin++; /* 0 used up, iin=1 */ iout++; @@ -231,8 +232,8 @@ base32_decode(void *buf, size_t *buflen, const char *str, size_t slen) str[iin] == '\0' || str[iin + 1] == '\0' || str[iin + 2] == '\0') break; - ubuf[iout] = ((REV32(str[iin]) & 0x03) << 6) | - ((REV32(str[iin + 1]) & 0x1f) << 1) | + ubuf[iout] = ((REV32(str[iin]) & 0x03) << 6) | + ((REV32(str[iin + 1]) & 0x1f) << 1) | ((REV32(str[iin + 2]) & 0x10) >> 4); iin += 2; /* 1,2 used up, iin=3 */ iout++; diff --git a/jni/iodine/src/base32.h b/jni/iodine/src/base32.h index 497ca33..53975c5 100644 --- a/jni/iodine/src/base32.h +++ b/jni/iodine/src/base32.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/src/base64.c b/jni/iodine/src/base64.c index 5218c09..00a84fc 100644 --- a/jni/iodine/src/base64.c +++ b/jni/iodine/src/base64.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl * * Permission to use, copy, modify, and distribute this software for any @@ -27,7 +28,7 @@ /* Note: the "unofficial" char is last here, which means that the \377 pattern in DOWNCODECCHECK1 ('Y' request) will properly test it. */ -static const char cb64[] = +static const char cb64[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789+"; static unsigned char rev64[256]; static int reverse_init = 0; @@ -55,19 +56,19 @@ struct encoder return &base64_encoder; } -static int +static int base64_handles_dots() { return 0; } -static int +static int base64_blksize_raw() { return BLKSIZE_RAW; } -static int +static int base64_blksize_enc() { return BLKSIZE_ENC; @@ -177,7 +178,7 @@ base64_decode(void *buf, size_t *buflen, const char *str, size_t slen) if (iout >= *buflen || iin + 1 >= slen || str[iin] == '\0' || str[iin + 1] == '\0') break; - ubuf[iout] = ((REV64(str[iin]) & 0x3f) << 2) | + ubuf[iout] = ((REV64(str[iin]) & 0x3f) << 2) | ((REV64(str[iin + 1]) & 0x30) >> 4); iin++; /* 0 used up, iin=1 */ iout++; @@ -185,7 +186,7 @@ base64_decode(void *buf, size_t *buflen, const char *str, size_t slen) if (iout >= *buflen || iin + 1 >= slen || str[iin] == '\0' || str[iin + 1] == '\0') break; - ubuf[iout] = ((REV64(str[iin]) & 0x0f) << 4) | + ubuf[iout] = ((REV64(str[iin]) & 0x0f) << 4) | ((REV64(str[iin + 1]) & 0x3c) >> 2); iin++; /* 1 used up, iin=2 */ iout++; diff --git a/jni/iodine/src/base64.h b/jni/iodine/src/base64.h index d550cf3..662175e 100644 --- a/jni/iodine/src/base64.h +++ b/jni/iodine/src/base64.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/src/client.c b/jni/iodine/src/client.c index 552344b..979f668 100644 --- a/jni/iodine/src/client.c +++ b/jni/iodine/src/client.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +33,9 @@ #include "windows.h" #include #else +#ifdef ANDROID +#include "android_dns.h" +#endif #include #ifdef DARWIN #define BIND_8_COMPAT @@ -58,7 +63,8 @@ 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 int nameserv_len; static struct sockaddr_in raw_serv; static const char *topdomain; @@ -89,10 +95,10 @@ static struct encoder *b128; /* The encoder used for data packets * Defaults to Base32, can be changed after handshake */ static struct encoder *dataenc; - + /* The encoder to use for downstream data */ static char downenc = ' '; - + /* set query type to send */ static unsigned short do_qtype = T_UNSET; @@ -146,49 +152,10 @@ client_get_conn() } void -client_set_nameserver(const char *cp, int port) +client_set_nameserver(struct sockaddr_storage *addr, int addrlen) { - 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); + nameserv_len = addrlen; } void @@ -203,11 +170,13 @@ client_set_password(const char *cp) password = cp; } -void -set_qtype(char *qtype) +int +client_set_qtype(char *qtype) { if (!strcasecmp(qtype, "NULL")) do_qtype = T_NULL; + else if (!strcasecmp(qtype, "PRIVATE")) + do_qtype = T_PRIVATE; else if (!strcasecmp(qtype, "CNAME")) do_qtype = T_CNAME; else if (!strcasecmp(qtype, "A")) @@ -218,14 +187,16 @@ set_qtype(char *qtype) do_qtype = T_SRV; else if (!strcasecmp(qtype, "TXT")) do_qtype = T_TXT; + return (do_qtype == T_UNSET); } char * -get_qtype() +client_get_qtype() { char *c = "UNDEFINED"; if (do_qtype == T_NULL) c = "NULL"; + else if (do_qtype == T_PRIVATE) c = "PRIVATE"; else if (do_qtype == T_CNAME) c = "CNAME"; else if (do_qtype == T_A) c = "A"; else if (do_qtype == T_MX) c = "MX"; @@ -236,7 +207,7 @@ get_qtype() } void -set_downenc(char *encoding) +client_set_downenc(char *encoding) { if (!strcasecmp(encoding, "base32")) downenc = 'T'; @@ -250,7 +221,7 @@ set_downenc(char *encoding) downenc = 'R'; } -void +void client_set_selecttimeout(int select_timeout) { selecttimeout = select_timeout; @@ -302,7 +273,7 @@ send_query(int fd, char *hostname) fprintf(stderr, " Sendquery: id %5d name[0] '%c'\n", q.id, hostname[0]); #endif - sendto(fd, packet, len, 0, (struct sockaddr*)&nameserv, sizeof(nameserv)); + sendto(fd, packet, len, 0, (struct sockaddr*)&nameserv, nameserv_len); /* There are DNS relays that time out quickly but don't send anything back on timeout. @@ -369,7 +340,7 @@ send_packet(int fd, char cmd, const char *data, const size_t datalen) char buf[4096]; buf[0] = cmd; - + build_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain, b32, hostname_maxlen); send_query(fd, buf); @@ -402,7 +373,7 @@ send_chunk(int fd) /* Build upstream data header (see doc/proto_xxxxxxxx.txt) */ buf[0] = userid_char; /* First byte is hex userid */ - + code = ((outpkt.seqno & 7) << 2) | ((outpkt.fragment & 15) >> 2); buf[1] = b32_5to8(code); /* Second byte is 3 bits seqno, 2 upper bits fragment count */ @@ -416,7 +387,7 @@ send_chunk(int fd) datacmc++; if (datacmc >= 36) datacmc = 0; - + #if 0 fprintf(stderr, " Send: down %d/%d up %d/%d, %d bytes\n", inpkt.seqno, inpkt.fragment, outpkt.seqno, outpkt.fragment, @@ -431,12 +402,12 @@ send_ping(int fd) { if (conn == CONN_DNS_NULL) { char data[4]; - + data[0] = userid; data[1] = ((inpkt.seqno & 7) << 4) | (inpkt.fragment & 15); data[2] = (rand_seed >> 8) & 0xff; data[3] = (rand_seed >> 0) & 0xff; - + rand_seed++; #if 0 @@ -596,13 +567,13 @@ 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); - if ((r = recvfrom(dns_fd, data, sizeof(data), 0, + addrlen = sizeof(from); + if ((r = recvfrom(dns_fd, data, sizeof(data), 0, (struct sockaddr*)&from, &addrlen)) < 0) { warn("recvfrom"); return -1; @@ -624,9 +595,9 @@ read_dns_withq(int dns_fd, int tun_fd, char *buf, int buflen, struct query *q) /* * buf is a hostname or txt stream that we still need to * decode to binary - * + * * also update rv with the number of valid bytes - * + * * data is unused here, and will certainly hold the smaller binary */ @@ -1180,11 +1151,11 @@ client_tunnel_cb(int tun_fd, int dns_fd, int warnx("No downstream data received in 60 seconds, shutting down."); running = 0; } - + if (running == 0) break; - if (i < 0) + if (i < 0) err(1, "select"); if (i == 0) { @@ -1227,7 +1198,7 @@ client_tunnel_cb(int tun_fd, int dns_fd, int if (FD_ISSET(dns_fd, &fds)) { if (tunnel_dns(tun_fd, dns_fd) <= 0) continue; - } + } } } @@ -1245,7 +1216,7 @@ send_login(int fd, char *login, int len) data[17] = (rand_seed >> 8) & 0xff; data[18] = (rand_seed >> 0) & 0xff; - + rand_seed++; send_packet(fd, 'l', data, sizeof(data)); @@ -1284,23 +1255,23 @@ static void send_set_downstream_fragsize(int fd, int fragsize) { char data[5]; - + data[0] = userid; data[1] = (fragsize & 0xff00) >> 8; data[2] = (fragsize & 0x00ff); data[3] = (rand_seed >> 8) & 0xff; data[4] = (rand_seed >> 0) & 0xff; - + rand_seed++; send_packet(fd, 'n', data, sizeof(data)); } -static void +static void send_version(int fd, uint32_t version) { char data[6]; - + data[0] = (version >> 24) & 0xff; data[1] = (version >> 16) & 0xff; data[2] = (version >> 8) & 0xff; @@ -1308,7 +1279,7 @@ send_version(int fd, uint32_t version) data[4] = (rand_seed >> 8) & 0xff; data[5] = (rand_seed >> 0) & 0xff; - + rand_seed++; send_packet(fd, 'v', data, sizeof(data)); @@ -1319,7 +1290,7 @@ send_ip_request(int fd, int userid) { char buf[512] = "i____."; buf[1] = b32_5to8(userid); - + buf[2] = b32_5to8((rand_seed >> 10) & 0x1f); buf[3] = b32_5to8((rand_seed >> 5) & 0x1f); buf[4] = b32_5to8((rand_seed ) & 0x1f); @@ -1343,7 +1314,7 @@ send_upenctest(int fd, char *s) /* NOTE: String may be at most 63-4=59 chars to fit in 1 dns chunk. */ { char buf[512] = "z___"; - + buf[1] = b32_5to8((rand_seed >> 10) & 0x1f); buf[2] = b32_5to8((rand_seed >> 5) & 0x1f); buf[3] = b32_5to8((rand_seed ) & 0x1f); @@ -1379,7 +1350,7 @@ send_codec_switch(int fd, int userid, int bits) char buf[512] = "s_____."; buf[1] = b32_5to8(userid); buf[2] = b32_5to8(bits); - + buf[3] = b32_5to8((rand_seed >> 10) & 0x1f); buf[4] = b32_5to8((rand_seed >> 5) & 0x1f); buf[5] = b32_5to8((rand_seed ) & 0x1f); @@ -1442,33 +1413,31 @@ handshake_version(int dns_fd, int *seed) read = handshake_waitdns(dns_fd, in, sizeof(in), 'v', 'V', i+1); - /*XXX START adjust indent 1 tab back*/ - if (read >= 9) { - payload = (((in[4] & 0xff) << 24) | - ((in[5] & 0xff) << 16) | - ((in[6] & 0xff) << 8) | - ((in[7] & 0xff))); - - if (strncmp("VACK", in, 4) == 0) { - *seed = payload; - userid = in[8]; - userid_char = hex[userid & 15]; - userid_char2 = hex2[userid & 15]; + if (read >= 9) { + payload = (((in[4] & 0xff) << 24) | + ((in[5] & 0xff) << 16) | + ((in[6] & 0xff) << 8) | + ((in[7] & 0xff))); + + if (strncmp("VACK", in, 4) == 0) { + *seed = payload; + userid = in[8]; + userid_char = hex[userid & 15]; + userid_char2 = hex2[userid & 15]; + + fprintf(stderr, "Version ok, both using protocol v 0x%08x. You are user #%d\n", VERSION, userid); + return 0; + } else if (strncmp("VNAK", in, 4) == 0) { + warnx("You use protocol v 0x%08x, server uses v 0x%08x. Giving up", + VERSION, payload); + return 1; + } else if (strncmp("VFUL", in, 4) == 0) { + warnx("Server full, all %d slots are taken. Try again later", payload); + return 1; + } + } else if (read > 0) + warnx("did not receive proper login challenge"); - fprintf(stderr, "Version ok, both using protocol v 0x%08x. You are user #%d\n", VERSION, userid); - return 0; - } else if (strncmp("VNAK", in, 4) == 0) { - warnx("You use protocol v 0x%08x, server uses v 0x%08x. Giving up", - VERSION, payload); - return 1; - } else if (strncmp("VFUL", in, 4) == 0) { - warnx("Server full, all %d slots are taken. Try again later", payload); - return 1; - } - } else if (read > 0) - warnx("did not receive proper login challenge"); - /*XXX END adjust indent 1 tab back*/ - fprintf(stderr, "Retrying version check...\n"); } warnx("couldn't connect to server (maybe other -T options will work)"); @@ -1487,37 +1456,35 @@ handshake_login(int dns_fd, int seed) int read; login_calculate(login, 16, password, seed); - + for (i=0; running && i<5 ;i++) { send_login(dns_fd, login, 16); read = handshake_waitdns(dns_fd, in, sizeof(in), 'l', 'L', i+1); - /*XXX START adjust indent 1 tab back*/ - if (read > 0) { - int netmask; - if (strncmp("LNAK", in, 4) == 0) { - fprintf(stderr, "Bad password\n"); - return 1; - } else if (sscanf(in, "%64[^-]-%64[^-]-%d-%d", - server, client, &mtu, &netmask) == 4) { - - server[64] = 0; - client[64] = 0; - if (tun_setip(client, server, netmask) == 0 && - tun_setmtu(mtu) == 0) { - - fprintf(stderr, "Server tunnel IP is %s\n", server); - return 0; - } else { - errx(4, "Failed to set IP and MTU"); - } + if (read > 0) { + int netmask; + if (strncmp("LNAK", in, 4) == 0) { + fprintf(stderr, "Bad password\n"); + return 1; + } else if (sscanf(in, "%64[^-]-%64[^-]-%d-%d", + server, client, &mtu, &netmask) == 4) { + + server[64] = 0; + client[64] = 0; + if (tun_setip(client, server, netmask) == 0 && + tun_setmtu(mtu) == 0) { + + fprintf(stderr, "Server tunnel IP is %s\n", server); + return 0; } else { - fprintf(stderr, "Received bad handshake\n"); + errx(4, "Failed to set IP and MTU"); } + } else { + fprintf(stderr, "Received bad handshake\n"); } - /*XXX END adjust indent 1 tab back*/ + } fprintf(stderr, "Retrying login...\n"); } @@ -1544,20 +1511,18 @@ handshake_raw_udp(int dns_fd, int seed) len = handshake_waitdns(dns_fd, in, sizeof(in), 'i', 'I', i+1); - /*XXX START adjust indent 1 tab back*/ - if (len == 5 && in[0] == 'I') { - /* Received IP address */ - remoteaddr = (in[1] & 0xff); - remoteaddr <<= 8; - remoteaddr |= (in[2] & 0xff); - remoteaddr <<= 8; - remoteaddr |= (in[3] & 0xff); - remoteaddr <<= 8; - remoteaddr |= (in[4] & 0xff); - server.s_addr = ntohl(remoteaddr); - break; - } - /*XXX END adjust indent 1 tab back*/ + if (len == 5 && in[0] == 'I') { + /* Received IP address */ + remoteaddr = (in[1] & 0xff); + remoteaddr <<= 8; + remoteaddr |= (in[2] & 0xff); + remoteaddr <<= 8; + remoteaddr |= (in[3] & 0xff); + remoteaddr <<= 8; + remoteaddr |= (in[4] & 0xff); + server.s_addr = ntohl(remoteaddr); + break; + } fprintf(stderr, "."); fflush(stderr); @@ -1565,7 +1530,7 @@ handshake_raw_udp(int dns_fd, int seed) fprintf(stderr, "\n"); if (!running) return 0; - + if (!remoteaddr) { fprintf(stderr, "Failed to get raw server IP, will use DNS mode.\n"); return 0; @@ -1579,7 +1544,7 @@ handshake_raw_udp(int dns_fd, int seed) raw_serv.sin_port = htons(53); raw_serv.sin_addr = server; - /* do login against port 53 on remote server + /* do login against port 53 on remote server * based on the old seed. If reply received, * switch to raw udp mode */ for (i=0; running && i<4 ;i++) { @@ -1587,7 +1552,7 @@ handshake_raw_udp(int dns_fd, int seed) tv.tv_usec = 0; send_raw_udp_login(dns_fd, userid, seed); - + FD_ZERO(&fds); FD_SET(dns_fd, &fds); @@ -1600,7 +1565,7 @@ handshake_raw_udp(int dns_fd, int seed) char hash[16]; login_calculate(hash, 16, password, seed - 1); if (memcmp(in, raw_header, RAW_HDR_IDENT_LEN) == 0 - && RAW_HDR_GET_CMD(in) == RAW_HDR_CMD_LOGIN + && RAW_HDR_GET_CMD(in) == RAW_HDR_CMD_LOGIN && memcmp(&in[RAW_HDR_LEN], hash, sizeof(hash)) == 0) { fprintf(stderr, "OK\n"); @@ -1611,7 +1576,7 @@ handshake_raw_udp(int dns_fd, int seed) fprintf(stderr, "."); fflush(stderr); } - + fprintf(stderr, "failed\n"); return 0; } @@ -1840,7 +1805,7 @@ handshake_downenc_autodetect(int dns_fd) int base64uok = 0; int base128ok = 0; - if (do_qtype == T_NULL) { + if (do_qtype == T_NULL || do_qtype == T_PRIVATE) { /* no other choice than raw */ fprintf(stderr, "No alternative downstream codec available, using default (Raw)\n"); return ' '; @@ -1894,13 +1859,14 @@ handshake_qtypetest(int dns_fd, int timeout) int trycodec; int k; - if (do_qtype == T_NULL) + if (do_qtype == T_NULL || do_qtype == T_PRIVATE) trycodec = 'R'; else trycodec = 'T'; /* We could use 'Z' bouncing here, but 'Y' also tests that 0-255 - byte values can be returned, which is needed for NULL to work. */ + byte values can be returned, which is needed for NULL/PRIVATE + to work. */ send_downenctest(dns_fd, trycodec, 1, NULL, 0); @@ -1925,11 +1891,12 @@ handshake_qtype_numcvt(int num) { switch (num) { case 0: return T_NULL; - case 1: return T_TXT; - case 2: return T_SRV; - case 3: return T_MX; - case 4: return T_CNAME; - case 5: return T_A; + case 1: return T_PRIVATE; + case 2: return T_TXT; + case 3: return T_SRV; + case 4: return T_MX; + case 5: return T_CNAME; + case 6: return T_A; } return T_UNSET; } @@ -1972,7 +1939,7 @@ handshake_qtype_autodetect(int dns_fd) highestworking = qtypenum; #if 0 fprintf(stderr, " Type %s timeout %d works\n", - get_qtype(), timeout); + client_get_qtype(), timeout); #endif break; /* try others with longer timeout */ @@ -2079,27 +2046,25 @@ handshake_switch_codec(int dns_fd, int bits) for (i=0; running && i<5 ;i++) { send_codec_switch(dns_fd, userid, bits); - + read = handshake_waitdns(dns_fd, in, sizeof(in), 's', 'S', i+1); - /*XXX START adjust indent 1 tab back*/ - if (read > 0) { - if (strncmp("BADLEN", in, 6) == 0) { - fprintf(stderr, "Server got bad message length. "); - goto codec_revert; - } else if (strncmp("BADIP", in, 5) == 0) { - fprintf(stderr, "Server rejected sender IP address. "); - goto codec_revert; - } else if (strncmp("BADCODEC", in, 8) == 0) { - fprintf(stderr, "Server rejected the selected codec. "); - goto codec_revert; - } - in[read] = 0; /* zero terminate */ - fprintf(stderr, "Server switched upstream to codec %s\n", in); - dataenc = tempenc; - return; + if (read > 0) { + if (strncmp("BADLEN", in, 6) == 0) { + fprintf(stderr, "Server got bad message length. "); + goto codec_revert; + } else if (strncmp("BADIP", in, 5) == 0) { + fprintf(stderr, "Server rejected sender IP address. "); + goto codec_revert; + } else if (strncmp("BADCODEC", in, 8) == 0) { + fprintf(stderr, "Server rejected the selected codec. "); + goto codec_revert; } - /*XXX END adjust indent 1 tab back*/ + in[read] = 0; /* zero terminate */ + fprintf(stderr, "Server switched upstream to codec %s\n", in); + dataenc = tempenc; + return; + } fprintf(stderr, "Retrying codec switch...\n"); } @@ -2108,7 +2073,7 @@ handshake_switch_codec(int dns_fd, int bits) fprintf(stderr, "No reply from server on codec switch. "); -codec_revert: +codec_revert: fprintf(stderr, "Falling back to upstream codec %s\n", dataenc->name); } @@ -2137,23 +2102,21 @@ handshake_switch_downenc(int dns_fd) read = handshake_waitdns(dns_fd, in, sizeof(in), 'o', 'O', i+1); - /*XXX START adjust indent 1 tab back*/ - if (read > 0) { - if (strncmp("BADLEN", in, 6) == 0) { - fprintf(stderr, "Server got bad message length. "); - goto codec_revert; - } else if (strncmp("BADIP", in, 5) == 0) { - fprintf(stderr, "Server rejected sender IP address. "); - goto codec_revert; - } else if (strncmp("BADCODEC", in, 8) == 0) { - fprintf(stderr, "Server rejected the selected codec. "); - goto codec_revert; - } - in[read] = 0; /* zero terminate */ - fprintf(stderr, "Server switched downstream to codec %s\n", in); - return; + if (read > 0) { + if (strncmp("BADLEN", in, 6) == 0) { + fprintf(stderr, "Server got bad message length. "); + goto codec_revert; + } else if (strncmp("BADIP", in, 5) == 0) { + fprintf(stderr, "Server rejected sender IP address. "); + goto codec_revert; + } else if (strncmp("BADCODEC", in, 8) == 0) { + fprintf(stderr, "Server rejected the selected codec. "); + goto codec_revert; } - /*XXX END adjust indent 1 tab back*/ + in[read] = 0; /* zero terminate */ + fprintf(stderr, "Server switched downstream to codec %s\n", in); + return; + } fprintf(stderr, "Retrying codec switch...\n"); } @@ -2162,7 +2125,7 @@ handshake_switch_downenc(int dns_fd) fprintf(stderr, "No reply from server on codec switch. "); -codec_revert: +codec_revert: fprintf(stderr, "Falling back to downstream codec Base32\n"); } @@ -2180,24 +2143,22 @@ handshake_try_lazy(int dns_fd) read = handshake_waitdns(dns_fd, in, sizeof(in), 'o', 'O', i+1); - /*XXX START adjust indent 1 tab back*/ - if (read > 0) { - if (strncmp("BADLEN", in, 6) == 0) { - fprintf(stderr, "Server got bad message length. "); - goto codec_revert; - } else if (strncmp("BADIP", in, 5) == 0) { - fprintf(stderr, "Server rejected sender IP address. "); - goto codec_revert; - } else if (strncmp("BADCODEC", in, 8) == 0) { - fprintf(stderr, "Server rejected lazy mode. "); - goto codec_revert; - } else if (strncmp("Lazy", in, 4) == 0) { - fprintf(stderr, "Server switched to lazy mode\n"); - lazymode = 1; - return; - } + if (read > 0) { + if (strncmp("BADLEN", in, 6) == 0) { + fprintf(stderr, "Server got bad message length. "); + goto codec_revert; + } else if (strncmp("BADIP", in, 5) == 0) { + fprintf(stderr, "Server rejected sender IP address. "); + goto codec_revert; + } else if (strncmp("BADCODEC", in, 8) == 0) { + fprintf(stderr, "Server rejected lazy mode. "); + goto codec_revert; + } else if (strncmp("Lazy", in, 4) == 0) { + fprintf(stderr, "Server switched to lazy mode\n"); + lazymode = 1; + return; } - /*XXX END adjust indent 1 tab back*/ + } fprintf(stderr, "Retrying lazy mode switch...\n"); } @@ -2206,7 +2167,7 @@ handshake_try_lazy(int dns_fd) fprintf(stderr, "No reply from server on lazy switch. "); -codec_revert: +codec_revert: fprintf(stderr, "Falling back to legacy mode\n"); lazymode = 0; selecttimeout = 1; @@ -2226,14 +2187,12 @@ handshake_lazyoff(int dns_fd) read = handshake_waitdns(dns_fd, in, sizeof(in), 'o', 'O', 1); - /*XXX START adjust indent 2 tabs back*/ - if (read == 9 && strncmp("Immediate", in, 9) == 0) { - warnx("Server switched back to legacy mode.\n"); - lazymode = 0; - selecttimeout = 1; - return; - } - /*XXX END adjust indent 2 tabs back*/ + if (read == 9 && strncmp("Immediate", in, 9) == 0) { + warnx("Server switched back to legacy mode.\n"); + lazymode = 0; + selecttimeout = 1; + return; + } } if (!running) return; @@ -2288,28 +2247,26 @@ fragsize_check(char *in, int read, int proposed_fragsize, int *max_fragsize) okay = 1; v = in[3] & 0xff; - /*XXX START adjust indent 1 tab back*/ - for (i = 3; i < read; i++, v = (v + 107) & 0xff) - if ((in[i] & 0xff) != v) { - okay = 0; - break; - } + for (i = 3; i < read; i++, v = (v + 107) & 0xff) + if ((in[i] & 0xff) != v) { + okay = 0; + break; + } - if (okay) { - fprintf(stderr, "%d ok.. ", acked_fragsize); - fflush(stderr); - *max_fragsize = acked_fragsize; - return 1; + if (okay) { + fprintf(stderr, "%d ok.. ", acked_fragsize); + fflush(stderr); + *max_fragsize = acked_fragsize; + return 1; + } else { + if (downenc != ' ' && downenc != 'T') { + fprintf(stderr, "%d corrupted at %d.. (Try -O Base32)\n", acked_fragsize, i); } else { - if (downenc != ' ' && downenc != 'T') { - fprintf(stderr, "%d corrupted at %d.. (Try -O Base32)\n", acked_fragsize, i); - } else { - fprintf(stderr, "%d corrupted at %d.. ", acked_fragsize, i); - } - fflush(stderr); - return 1; + fprintf(stderr, "%d corrupted at %d.. ", acked_fragsize, i); } - /*XXX END adjust indent 1 tab back*/ + fflush(stderr); + return 1; + } /* notreached */ return 1; @@ -2327,7 +2284,7 @@ handshake_autoprobe_fragsize(int dns_fd) int max_fragsize; max_fragsize = 0; - fprintf(stderr, "Autoprobing max downstream fragment size... (skip with -m fragsize)\n"); + fprintf(stderr, "Autoprobing max downstream fragment size... (skip with -m fragsize)\n"); while (running && range > 0 && (range >= 8 || max_fragsize < 300)) { /* stop the slow probing early when we have enough bytes anyway */ for (i=0; running && i<3 ;i++) { @@ -2335,14 +2292,12 @@ handshake_autoprobe_fragsize(int dns_fd) send_fragsize_probe(dns_fd, proposed_fragsize); read = handshake_waitdns(dns_fd, in, sizeof(in), 'r', 'R', 1); - - /*XXX START adjust indent 1 tab back*/ - if (read > 0) { - /* We got a reply */ - if (fragsize_check(in, read, proposed_fragsize, &max_fragsize) == 1) - break; - } - /*XXX END adjust indent 1 tab back*/ + + if (read > 0) { + /* We got a reply */ + if (fragsize_check(in, read, proposed_fragsize, &max_fragsize) == 1) + break; + } fprintf(stderr, "."); fflush(stderr); @@ -2383,7 +2338,7 @@ handshake_autoprobe_fragsize(int dns_fd) fprintf(stderr, "Note: this probably won't work well.\n"); fprintf(stderr, "Try setting -M to 200 or lower, or try other DNS types (-T option).\n"); } else if (max_fragsize < 202 && - (do_qtype == T_NULL || do_qtype == T_TXT || + (do_qtype == T_NULL || do_qtype == T_PRIVATE || do_qtype == T_TXT || do_qtype == T_SRV || do_qtype == T_MX)) { fprintf(stderr, "Note: this isn't very much.\n"); fprintf(stderr, "Try setting -M to 200 or lower, or try other DNS types (-T option).\n"); @@ -2406,22 +2361,20 @@ handshake_set_fragsize(int dns_fd, int fragsize) read = handshake_waitdns(dns_fd, in, sizeof(in), 'n', 'N', i+1); - /*XXX START adjust indent 1 tab back*/ - if (read > 0) { - int accepted_fragsize; - - if (strncmp("BADFRAG", in, 7) == 0) { - fprintf(stderr, "Server rejected fragsize. Keeping default."); - return; - } else if (strncmp("BADIP", in, 5) == 0) { - fprintf(stderr, "Server rejected sender IP address.\n"); - return; - } + if (read > 0) { - accepted_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff); + if (strncmp("BADFRAG", in, 7) == 0) { + fprintf(stderr, "Server rejected fragsize. Keeping default."); + return; + } else if (strncmp("BADIP", in, 5) == 0) { + fprintf(stderr, "Server rejected sender IP address.\n"); return; } - /*XXX END adjust indent 1 tab back*/ + + /* The server returns the accepted fragsize: + accepted_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff) */ + return; + } fprintf(stderr, "Retrying set fragsize...\n"); } @@ -2448,7 +2401,7 @@ client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsiz } } - fprintf(stderr, "Using DNS type %s queries\n", get_qtype()); + fprintf(stderr, "Using DNS type %s queries\n", client_get_qtype()); r = handshake_version(dns_fd, &seed); if (r) { diff --git a/jni/iodine/src/client.h b/jni/iodine/src/client.h index e2d9501..79598fb 100644 --- a/jni/iodine/src/client.h +++ b/jni/iodine/src/client.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -23,12 +24,12 @@ 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); -char *get_qtype(); -void set_downenc(char *encoding); +int client_set_qtype(char *qtype); +char *client_get_qtype(); +void client_set_downenc(char *encoding); void client_set_selecttimeout(int select_timeout); void client_set_lazymode(int lazy_mode); void client_set_hostname_maxlen(int i); diff --git a/jni/iodine/src/common.c b/jni/iodine/src/common.c index 7a57a8a..6707a14 100644 --- a/jni/iodine/src/common.c +++ b/jni/iodine/src/common.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman +/* Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * Copyright (c) 2007 Albert Lee . * * Permission to use, copy, modify, and distribute this software for any @@ -39,9 +40,11 @@ #endif #include #include -#include #include +#include #include +#include +#include #endif #ifdef HAVE_SETCON @@ -54,11 +57,11 @@ const unsigned char raw_header[RAW_HDR_LEN] = { 0x10, 0xd1, 0x9e, 0x00 }; /* daemon(3) exists only in 4.4BSD or later, and in GNU libc */ -#if !defined(WINDOWS32) && !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__) && !defined(__ANDROID__) +#if !defined(ANDROID) && !defined(WINDOWS32) && !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__) static int daemon(int nochdir, int noclose) { int fd, i; - + switch (fork()) { case 0: break; @@ -67,15 +70,15 @@ static int daemon(int nochdir, int noclose) default: _exit(0); } - + if (!nochdir) { chdir("/"); } - + if (setsid() < 0) { return -1; } - + if (!noclose) { if ((fd = open("/dev/null", O_RDWR)) >= 0) { for (i = 0; i < 3; i++) { @@ -111,21 +114,69 @@ check_superuser(void (*usage_fn)(void)) #endif } -int -open_dns(int localport, in_addr_t listen_ip) +char * +format_addr(struct sockaddr_storage *sockaddr, int sockaddr_len) +{ + static char dst[INET6_ADDRSTRLEN + 1]; + + memset(dst, 0, sizeof(dst)); + if (sockaddr->ss_family == AF_INET && sockaddr_len >= sizeof(struct sockaddr_in)) { + getnameinfo((struct sockaddr *)sockaddr, sockaddr_len, dst, sizeof(dst) - 1, NULL, 0, NI_NUMERICHOST); + } else if (sockaddr->ss_family == AF_INET6 && sockaddr_len >= sizeof(struct sockaddr_in6)) { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *) sockaddr; + if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr)) { + struct in_addr ia; + /* Get mapped v4 addr from last 32bit field */ + memcpy(&ia.s_addr, &addr->sin6_addr.s6_addr[12], sizeof(ia)); + strcpy(dst, inet_ntoa(ia)); + } else { + getnameinfo((struct sockaddr *)sockaddr, sockaddr_len, dst, sizeof(dst) - 1, NULL, 0, NI_NUMERICHOST); + } + } else { + dst[0] = '?'; + } + return dst; +} + +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; +#if defined(WINDOWS32) || defined(OPENBSD) + /* AI_ADDRCONFIG misbehaves on windows, and does not exist in OpenBSD */ + hints.ai_flags = flags; +#else + hints.ai_flags = AI_ADDRCONFIG | flags; +#endif + 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"); } @@ -138,6 +189,8 @@ open_dns(int localport, in_addr_t listen_ip) #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)); + + fd_set_close_on_exec(fd); #endif #ifdef IP_OPT_DONT_FRAG @@ -146,14 +199,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) { @@ -167,8 +233,9 @@ do_chroot(char *newroot) if (chroot(newroot) != 0 || chdir("/") != 0) err(1, "%s", newroot); - seteuid(geteuid()); - setuid(getuid()); + if (seteuid(geteuid()) != 0 || setuid(getuid()) != 0) { + err(1, "set[e]uid()"); + } #else warnx("chroot not available"); #endif @@ -219,14 +286,14 @@ do_detach() void read_password(char *buf, size_t len) { - char pwd[80]; + char pwd[80] = {0}; #ifndef WINDOWS32 struct termios old; struct termios tp; tcgetattr(0, &tp); old = tp; - + tp.c_lflag &= (~ECHO); tcsetattr(0, TCSANOW, &tp); #else @@ -236,7 +303,7 @@ read_password(char *buf, size_t len) fprintf(stderr, "Enter password: "); fflush(stderr); #ifndef WINDOWS32 - scanf("%79s", pwd); + fscanf(stdin, "%79[^\n]", pwd); #else for (i = 0; i < sizeof(pwd); i++) { pwd[i] = getch(); @@ -252,7 +319,7 @@ read_password(char *buf, size_t len) fprintf(stderr, "\n"); #ifndef WINDOWS32 - tcsetattr(0, TCSANOW, &old); + tcsetattr(0, TCSANOW, &old); #endif strncpy(buf, pwd, len); @@ -260,29 +327,75 @@ read_password(char *buf, size_t len) } int -check_topdomain(char *str) +check_topdomain(char *str, char **errormsg) { - int i; - - if(str[0] == '.') /* special case */ - return 1; - - for( i = 0; i < strlen(str); i++) { - if( isalpha(str[i]) || isdigit(str[i]) || str[i] == '-' || str[i] == '.' ) - continue; - else - return 1; - } - return 0; + int i; + int dots = 0; + int chunklen = 0; + + if (strlen(str) < 3) { + if (errormsg) *errormsg = "Too short (< 3)"; + return 1; + } + if (strlen(str) > 128) { + if (errormsg) *errormsg = "Too long (> 128)"; + return 1; + } + + if (str[0] == '.') { + if (errormsg) *errormsg = "Starts with a dot"; + return 1; + } + + for( i = 0; i < strlen(str); i++) { + if(str[i] == '.') { + dots++; + if (chunklen == 0) { + if (errormsg) *errormsg = "Consecutive dots"; + return 1; + } + if (chunklen > 63) { + if (errormsg) *errormsg = "Too long domain part (> 63)"; + return 1; + } + chunklen = 0; + } else { + chunklen++; + } + if( (str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z') || + isdigit(str[i]) || str[i] == '-' || str[i] == '.' ) { + continue; + } else { + if (errormsg) *errormsg = "Contains illegal character (allowed: [a-zA-Z0-9-.])"; + return 1; + } + } + + if (dots == 0) { + if (errormsg) *errormsg = "No dots"; + return 1; + } + if (chunklen == 0) { + if (errormsg) *errormsg = "Ends with a dot"; + return 1; + } + if (chunklen > 63) { + if (errormsg) *errormsg = "Too long domain part (> 63)"; + return 1; + } + + return 0; } -#if defined(WINDOWS32) +#if defined(WINDOWS32) || defined(ANDROID) +#ifndef ANDROID int inet_aton(const char *cp, struct in_addr *inp) { inp->s_addr = inet_addr(cp); return inp->s_addr != INADDR_ANY; } +#endif void warn(const char *fmt, ...) @@ -291,45 +404,16 @@ warn(const char *fmt, ...) va_start(list, fmt); if (fmt) fprintf(stderr, fmt, list); +#ifndef ANDROID if (errno == 0) { - fprintf(stderr, ": WSA error %d\n", WSAGetLastError()); + fprintf(stderr, ": WSA error %d\n", WSAGetLastError()); } else { fprintf(stderr, ": %s\n", strerror(errno)); } - va_end(list); -} #endif - -#ifdef __ANDROID__ - -void android_printf(const char *fmt, ...) -{ - static char buf[1024]; - va_list list; - va_start(list, fmt); - - snprintf(buf,1024,fmt,list); - - android_log_callback(buf); - va_end(list); } - -void -warn(const char *fmt, ...) -{ - va_list list; - - va_start(list, fmt); - if (fmt) fprintf(stderr, fmt, list); - if (errno != 0) - fprintf(stderr, ": %s\n", strerror(errno)); - va_end(list); -} -#endif - -#if defined(WINDOWS32) || defined(__ANDROID__) void warnx(const char *fmt, ...) { @@ -364,6 +448,23 @@ errx(int eval, const char *fmt, ...) } #endif +#if defined(__ANDROID__) +void android_log_callback(const char *); +static char printf_buf[1024];; +void android_printf(const char *fmt, ...) +{ + va_list list; + va_start(list, fmt); + + vsnprintf(printf_buf,1024,fmt,list); + android_log_callback(printf_buf); + + __android_log_vprint(ANDROID_LOG_INFO, "Iodine", + fmt, list); + va_end(list); +} +#endif + int recent_seqno(int ourseqno, int gotseqno) /* Return 1 if we've seen gotseqno recently (current or up to 3 back). @@ -379,3 +480,22 @@ int recent_seqno(int ourseqno, int gotseqno) } return 0; } + +#ifndef WINDOWS32 +/* Set FD_CLOEXEC flag on file descriptor. + * This stops it from being inherited by system() calls. + */ +void +fd_set_close_on_exec(int fd) +{ + int flags; + + flags = fcntl(fd, F_GETFD); + if (flags == -1) + err(4, "Failed to get fd flags"); + flags |= FD_CLOEXEC; + if (fcntl(fd, F_SETFD, flags) == -1) + err(4, "Failed to set fd flags"); +} +#endif + diff --git a/jni/iodine/src/common.h b/jni/iodine/src/common.h index 0b0efb8..26800f6 100644 --- a/jni/iodine/src/common.h +++ b/jni/iodine/src/common.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,8 +38,8 @@ extern const unsigned char raw_header[RAW_HDR_LEN]; #include #include #include -#include #include +#include #endif #define DNS_PORT 53 @@ -52,12 +53,12 @@ extern const unsigned char raw_header[RAW_HDR_LEN]; #define QUERY_NAME_SIZE 256 -#if defined IP_RECVDSTADDR -# define DSTADDR_SOCKOPT IP_RECVDSTADDR -# define dstaddr(x) ((struct in_addr *) CMSG_DATA(x)) -#elif defined IP_PKTINFO -# define DSTADDR_SOCKOPT IP_PKTINFO -# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr)) +#if defined IP_RECVDSTADDR +# define DSTADDR_SOCKOPT IP_RECVDSTADDR +# define dstaddr(x) ((struct in_addr *) CMSG_DATA(x)) +#elif defined IP_PKTINFO +# define DSTADDR_SOCKOPT IP_PKTINFO +# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr)) #endif #if defined IP_MTU_DISCOVER @@ -74,10 +75,12 @@ extern const unsigned char raw_header[RAW_HDR_LEN]; # define DONT_FRAG_VALUE 1 #endif +#define T_PRIVATE 65399 +/* Undefined RR type; "private use" range, see http://www.bind9.net/dns-parameters */ #define T_UNSET 65432 -/* Unused RR type; "private use" range, see http://www.bind9.net/dns-parameters */ +/* Unused RR type, never actually sent */ -struct packet +struct packet { int len; /* Total packet length */ int sentlen; /* Length of chunk currently transmitted */ @@ -93,7 +96,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 +110,10 @@ enum connection { }; void check_superuser(void (*usage_fn)(void)); -int open_dns(int, in_addr_t); +char *format_addr(struct sockaddr_storage *sockaddr, int sockaddr_len); +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 *); @@ -117,24 +123,21 @@ void do_pidfile(char *); void read_password(char*, size_t); -int check_topdomain(char *); +int check_topdomain(char *, char **); #ifdef __ANDROID__ -//#define printf(...) __android_log_print(ANDROID_LOG_DEBUG, "iodine", __VA_ARGS__) +#include + #define printf(...) android_printf(__VA_ARGS__) +#define fprintf(egal,...) android_printf(__VA_ARGS__) void android_printf(const char *fmt, ...); +#endif - -#define fprintf(__fd_unused, ...) printf(__VA_ARGS__) - -#include -void err(int eval, const char *fmt, ...); -void warn(const char *fmt, ...); -void errx(int eval, const char *fmt, ...); -void warnx(const char *fmt, ...); -#elif WINDOWS32 +#if defined(WINDOWS32) || defined(ANDROID) +#ifndef ANDROID int inet_aton(const char *cp, struct in_addr *inp); +#endif void err(int eval, const char *fmt, ...); void warn(const char *fmt, ...); @@ -144,4 +147,8 @@ void warnx(const char *fmt, ...); int recent_seqno(int , int); +#ifndef WINDOWS32 +void fd_set_close_on_exec(int fd); +#endif + #endif diff --git a/jni/iodine/src/dns.c b/jni/iodine/src/dns.c index fb2bcaf..946fe83 100644 --- a/jni/iodine/src/dns.c +++ b/jni/iodine/src/dns.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,16 +21,21 @@ #include #include #include +#include #include #ifdef WINDOWS32 #include "windows.h" #else +#if defined(ANDROID) || defined(__ANDROID__) +#include "android_dns.h" +#endif #include #ifdef DARWIN #define BIND_8_COMPAT #include #endif +#include #include #include #endif @@ -41,7 +47,7 @@ int dnsc_use_edns0 = 1; -#define CHECKLEN(x) if (buflen - (p-buf) < (x)) return 0 +#define CHECKLEN(x) if (buflen < (x) + (unsigned)(p-buf)) return 0 int dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_t datalen) @@ -56,9 +62,9 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_ return 0; memset(buf, 0, buflen); - + header = (HEADER*)buf; - + header->id = htons(q->id); header->qr = (qr == QR_ANSWER); header->opcode = 0; @@ -72,7 +78,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_ switch (qr) { case QR_ANSWER: header->qdcount = htons(1); - + name = 0xc000 | ((p - buf) & 0x3fff); /* Question section */ @@ -91,7 +97,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_ int namelen; CHECKLEN(10); - putshort(&p, name); + putshort(&p, name); if (q->type == T_A) /* answer CNAME to A question */ putshort(&p, T_CNAME); @@ -121,7 +127,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_ ancnt = 1; while (1) { CHECKLEN(10); - putshort(&p, name); + putshort(&p, name); putshort(&p, q->type); putshort(&p, C_IN); putlong(&p, 0); /* TTL */ @@ -156,7 +162,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_ int txtlen; CHECKLEN(10); - putshort(&p, name); + putshort(&p, name); putshort(&p, q->type); putshort(&p, C_IN); putlong(&p, 0); /* TTL */ @@ -173,7 +179,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_ /* NULL has raw binary data */ CHECKLEN(10); - putshort(&p, name); + putshort(&p, name); putshort(&p, q->type); putshort(&p, C_IN); putlong(&p, 0); /* TTL */ @@ -192,7 +198,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_ /* Note that iodined also uses this for forward queries */ header->qdcount = htons(1); - + datalen = MIN(datalen, buflen - (p - buf)); putname(&p, datalen, data); @@ -204,20 +210,18 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_ (even CNAME/A/MX, 255+255+header would be >512) */ if (dnsc_use_edns0) { header->arcount = htons(1); - /*XXX START adjust indent 1 tab forward*/ - CHECKLEN(11); - putbyte(&p, 0x00); /* Root */ - putshort(&p, 0x0029); /* OPT */ - putshort(&p, 0x1000); /* Payload size: 4096 */ - putshort(&p, 0x0000); /* Higher bits/edns version */ - putshort(&p, 0x8000); /* Z */ - putshort(&p, 0x0000); /* Data length */ - /*XXX END adjust indent 1 tab forward*/ + CHECKLEN(11); + putbyte(&p, 0x00); /* Root */ + putshort(&p, 0x0029); /* OPT */ + putshort(&p, 0x1000); /* Payload size: 4096 */ + putshort(&p, 0x0000); /* Higher bits/edns version */ + putshort(&p, 0x8000); /* Z */ + putshort(&p, 0x0000); /* Data length */ } break; } - + len = p - buf; return len; @@ -241,9 +245,9 @@ dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomai return 0; memset(buf, 0, buflen); - + header = (HEADER*)buf; - + header->id = htons(q->id); header->qr = 1; header->opcode = 0; @@ -330,9 +334,9 @@ dns_encode_a_response(char *buf, size_t buflen, struct query *q) return 0; memset(buf, 0, buflen); - + header = (HEADER*)buf; - + header->id = htons(q->id); header->qr = 1; header->opcode = 0; @@ -389,7 +393,7 @@ dns_get_id(char *packet, size_t packetlen) return ntohs(header->id); } -#define CHECKLEN(x) if (packetlen - (data-packet) < (x)) return 0 +#define CHECKLEN(x) if (packetlen < (x) + (unsigned)(data-packet)) return 0 int dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen) @@ -400,11 +404,11 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz short qdcount; short ancount; uint32_t ttl; - short class; - short type; + unsigned short class; + unsigned short type; char *data; - short rlen; - int id; + unsigned short rlen; + int id; int rv; q->id2 = 0; @@ -412,9 +416,9 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz header = (HEADER*)packet; /* Reject short packets */ - if (packetlen < sizeof(HEADER)) + if (packetlen < sizeof(HEADER)) return 0; - + if (header->qr != qr) { warnx("header->qr does not match the requested qr"); return -1; @@ -423,13 +427,13 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz data = packet + sizeof(HEADER); qdcount = ntohs(header->qdcount); ancount = ntohs(header->ancount); - + id = ntohs(header->id); id = id & 0xFFFF; /* Kill any sign extension */ - + rlen = 0; - if (q != NULL) + if (q != NULL) q->rcode = header->rcode; switch (qr) { @@ -439,7 +443,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz return -1; } - if (q != NULL) + if (q != NULL) q->id = id; /* Read name even if no answer, to give better error message */ @@ -447,14 +451,14 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz CHECKLEN(4); readshort(packet, &data, &type); readshort(packet, &data, &class); - + /* if CHECKLEN okay, then we're sure to have a proper name */ if (q != NULL) { /* We only need the first char to check it */ q->name[0] = name[0]; q->name[1] = '\0'; - } - + } + if (ancount < 1) { /* DNS errors like NXDOMAIN have ancount=0 and stop here. CNAME may also have A; MX/SRV may have @@ -463,7 +467,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz } /* Here type is still the question type */ - if (type == T_NULL) { + if (type == T_NULL || type == T_PRIVATE) { /* Assume that first answer is what we wanted */ readname(packet, packetlen, &data, name, sizeof(name)); CHECKLEN(10); @@ -505,7 +509,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz */ char names[250][QUERY_NAME_SIZE]; char *rdatastart; - short pref; + unsigned short pref; int i; int offset; @@ -535,7 +539,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz names[pref / 10 - 1][QUERY_NAME_SIZE-1] = '\0'; } - /* always trust rlen, not name encoding */ + /* always trust rlen, not name encoding */ data = rdatastart + rlen; CHECKLEN(0); } diff --git a/jni/iodine/src/dns.h b/jni/iodine/src/dns.h index be8b940..7c1faff 100644 --- a/jni/iodine/src/dns.h +++ b/jni/iodine/src/dns.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -32,8 +33,4 @@ int dns_encode_a_response(char *buf, size_t buflen, struct query *q); unsigned short dns_get_id(char *packet, size_t packetlen); int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t); -#ifdef __ANDROID__ -#include "dns_android.h" -#endif - #endif /* _DNS_H_ */ diff --git a/jni/iodine/src/dns_android.h b/jni/iodine/src/dns_android.h deleted file mode 100644 index f8addf7..0000000 --- a/jni/iodine/src/dns_android.h +++ /dev/null @@ -1,625 +0,0 @@ -/* This file is modified to serve minimal requirements of iodine */ - - -/* - * Copyright (c) 1983, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1996-1999 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -/* - * $BINDId: nameser.h,v 8.37 2000/03/30 21:16:49 vixie Exp $ - */ - -#ifndef _ARPA_NAMESER_H_ -#define _ARPA_NAMESER_H_ - -/*% - * Revision information. This is the release date in YYYYMMDD format. - * It can change every day so the right thing to do with it is use it - * in preprocessor commands such as "#if (__NAMESER > 19931104)". Do not - * compare for equality; rather, use it to determine whether your libbind.a - * contains a new enough lib/nameser/ to support the feature you need. - */ - -#define __NAMESER 19991006 /*%< New interface version stamp. */ -/* - * Define constants based on RFC 883, RFC 1034, RFC 1035 - */ -#define NS_PACKETSZ 512 /*%< default UDP packet size */ -#define NS_MAXDNAME 1025 /*%< maximum domain name */ -#define NS_MAXMSG 65535 /*%< maximum message size */ -#define NS_MAXCDNAME 255 /*%< maximum compressed domain name */ -#define NS_MAXLABEL 63 /*%< maximum length of domain label */ -#define NS_HFIXEDSZ 12 /*%< #/bytes of fixed data in header */ -#define NS_QFIXEDSZ 4 /*%< #/bytes of fixed data in query */ -#define NS_RRFIXEDSZ 10 /*%< #/bytes of fixed data in r record */ -#define NS_INT32SZ 4 /*%< #/bytes of data in a u_int32_t */ -#define NS_INT16SZ 2 /*%< #/bytes of data in a u_int16_t */ -#define NS_INT8SZ 1 /*%< #/bytes of data in a u_int8_t */ -#define NS_INADDRSZ 4 /*%< IPv4 T_A */ -#define NS_IN6ADDRSZ 16 /*%< IPv6 T_AAAA */ -#define NS_CMPRSFLGS 0xc0 /*%< Flag bits indicating name compression. */ -#define NS_DEFAULTPORT 53 /*%< For both TCP and UDP. */ -/* - * These can be expanded with synonyms, just keep ns_parse.c:ns_parserecord() - * in synch with it. - */ -typedef enum __ns_sect { - ns_s_qd = 0, /*%< Query: Question. */ - ns_s_zn = 0, /*%< Update: Zone. */ - ns_s_an = 1, /*%< Query: Answer. */ - ns_s_pr = 1, /*%< Update: Prerequisites. */ - ns_s_ns = 2, /*%< Query: Name servers. */ - ns_s_ud = 2, /*%< Update: Update. */ - ns_s_ar = 3, /*%< Query|Update: Additional records. */ - ns_s_max = 4 -} ns_sect; - -/*% - * This is a message handle. It is caller allocated and has no dynamic data. - * This structure is intended to be opaque to all but ns_parse.c, thus the - * leading _'s on the member names. Use the accessor functions, not the _'s. - */ -typedef struct __ns_msg { - const u_char *_msg, *_eom; - u_int16_t _id, _flags, _counts[ns_s_max]; - const u_char *_sections[ns_s_max]; - ns_sect _sect; - int _rrnum; - const u_char *_msg_ptr; -} ns_msg; - -/* Private data structure - do not use from outside library. */ -struct _ns_flagdata { int mask, shift; }; -extern const struct _ns_flagdata _ns_flagdata[]; - -/* Accessor macros - this is part of the public interface. */ - -#define ns_msg_id(handle) ((handle)._id + 0) -#define ns_msg_base(handle) ((handle)._msg + 0) -#define ns_msg_end(handle) ((handle)._eom + 0) -#define ns_msg_size(handle) ((handle)._eom - (handle)._msg) -#define ns_msg_count(handle, section) ((handle)._counts[section] + 0) - -/*% - * This is a parsed record. It is caller allocated and has no dynamic data. - */ -typedef struct __ns_rr { - char name[NS_MAXDNAME]; - u_int16_t type; - u_int16_t rr_class; - u_int32_t ttl; - u_int16_t rdlength; - const u_char * rdata; -} ns_rr; - -/* Accessor macros - this is part of the public interface. */ -#define ns_rr_name(rr) (((rr).name[0] != '\0') ? (rr).name : ".") -#define ns_rr_type(rr) ((ns_type)((rr).type + 0)) -#define ns_rr_class(rr) ((ns_class)((rr).rr_class + 0)) -#define ns_rr_ttl(rr) ((rr).ttl + 0) -#define ns_rr_rdlen(rr) ((rr).rdlength + 0) -#define ns_rr_rdata(rr) ((rr).rdata + 0) - -/*% - * These don't have to be in the same order as in the packet flags word, - * and they can even overlap in some cases, but they will need to be kept - * in synch with ns_parse.c:ns_flagdata[]. - */ -typedef enum __ns_flag { - ns_f_qr, /*%< Question/Response. */ - ns_f_opcode, /*%< Operation code. */ - ns_f_aa, /*%< Authoritative Answer. */ - ns_f_tc, /*%< Truncation occurred. */ - ns_f_rd, /*%< Recursion Desired. */ - ns_f_ra, /*%< Recursion Available. */ - ns_f_z, /*%< MBZ. */ - ns_f_ad, /*%< Authentic Data (DNSSEC). */ - ns_f_cd, /*%< Checking Disabled (DNSSEC). */ - ns_f_rcode, /*%< Response code. */ - ns_f_max -} ns_flag; - -/*% - * Currently defined opcodes. - */ -typedef enum __ns_opcode { - ns_o_query = 0, /*%< Standard query. */ - ns_o_iquery = 1, /*%< Inverse query (deprecated/unsupported). */ - ns_o_status = 2, /*%< Name server status query (unsupported). */ - /* Opcode 3 is undefined/reserved. */ - ns_o_notify = 4, /*%< Zone change notification. */ - ns_o_update = 5, /*%< Zone update message. */ - ns_o_max = 6 -} ns_opcode; - -/*% - * Currently defined response codes. - */ -typedef enum __ns_rcode { - ns_r_noerror = 0, /*%< No error occurred. */ - ns_r_formerr = 1, /*%< Format error. */ - ns_r_servfail = 2, /*%< Server failure. */ - ns_r_nxdomain = 3, /*%< Name error. */ - ns_r_notimpl = 4, /*%< Unimplemented. */ - ns_r_refused = 5, /*%< Operation refused. */ - /* these are for BIND_UPDATE */ - ns_r_yxdomain = 6, /*%< Name exists */ - ns_r_yxrrset = 7, /*%< RRset exists */ - ns_r_nxrrset = 8, /*%< RRset does not exist */ - ns_r_notauth = 9, /*%< Not authoritative for zone */ - ns_r_notzone = 10, /*%< Zone of record different from zone section */ - ns_r_max = 11, - /* The following are EDNS extended rcodes */ - ns_r_badvers = 16, - /* The following are TSIG errors */ - ns_r_badsig = 16, - ns_r_badkey = 17, - ns_r_badtime = 18 -} ns_rcode; - -/* BIND_UPDATE */ -typedef enum __ns_update_operation { - ns_uop_delete = 0, - ns_uop_add = 1, - ns_uop_max = 2 -} ns_update_operation; - -/*% - * This structure is used for TSIG authenticated messages - */ -struct ns_tsig_key { - char name[NS_MAXDNAME], alg[NS_MAXDNAME]; - unsigned char *data; - int len; -}; -typedef struct ns_tsig_key ns_tsig_key; - -/*% - * This structure is used for TSIG authenticated TCP messages - */ -struct ns_tcp_tsig_state { - int counter; - struct dst_key *key; - void *ctx; - unsigned char sig[NS_PACKETSZ]; - int siglen; -}; -typedef struct ns_tcp_tsig_state ns_tcp_tsig_state; - -#define NS_TSIG_FUDGE 300 -#define NS_TSIG_TCP_COUNT 100 -#define NS_TSIG_ALG_HMAC_MD5 "HMAC-MD5.SIG-ALG.REG.INT" - -#define NS_TSIG_ERROR_NO_TSIG -10 -#define NS_TSIG_ERROR_NO_SPACE -11 -#define NS_TSIG_ERROR_FORMERR -12 - -/*% - * Currently defined type values for resources and queries. - */ -typedef enum __ns_type { - ns_t_invalid = 0, /*%< Cookie. */ - ns_t_a = 1, /*%< Host address. */ - ns_t_ns = 2, /*%< Authoritative server. */ - ns_t_md = 3, /*%< Mail destination. */ - ns_t_mf = 4, /*%< Mail forwarder. */ - ns_t_cname = 5, /*%< Canonical name. */ - ns_t_soa = 6, /*%< Start of authority zone. */ - ns_t_mb = 7, /*%< Mailbox domain name. */ - ns_t_mg = 8, /*%< Mail group member. */ - ns_t_mr = 9, /*%< Mail rename name. */ - ns_t_null = 10, /*%< Null resource record. */ - ns_t_wks = 11, /*%< Well known service. */ - ns_t_ptr = 12, /*%< Domain name pointer. */ - ns_t_hinfo = 13, /*%< Host information. */ - ns_t_minfo = 14, /*%< Mailbox information. */ - ns_t_mx = 15, /*%< Mail routing information. */ - ns_t_txt = 16, /*%< Text strings. */ - ns_t_rp = 17, /*%< Responsible person. */ - ns_t_afsdb = 18, /*%< AFS cell database. */ - ns_t_x25 = 19, /*%< X_25 calling address. */ - ns_t_isdn = 20, /*%< ISDN calling address. */ - ns_t_rt = 21, /*%< Router. */ - ns_t_nsap = 22, /*%< NSAP address. */ - ns_t_nsap_ptr = 23, /*%< Reverse NSAP lookup (deprecated). */ - ns_t_sig = 24, /*%< Security signature. */ - ns_t_key = 25, /*%< Security key. */ - ns_t_px = 26, /*%< X.400 mail mapping. */ - ns_t_gpos = 27, /*%< Geographical position (withdrawn). */ - ns_t_aaaa = 28, /*%< Ip6 Address. */ - ns_t_loc = 29, /*%< Location Information. */ - ns_t_nxt = 30, /*%< Next domain (security). */ - ns_t_eid = 31, /*%< Endpoint identifier. */ - ns_t_nimloc = 32, /*%< Nimrod Locator. */ - ns_t_srv = 33, /*%< Server Selection. */ - ns_t_atma = 34, /*%< ATM Address */ - ns_t_naptr = 35, /*%< Naming Authority PoinTeR */ - ns_t_kx = 36, /*%< Key Exchange */ - ns_t_cert = 37, /*%< Certification record */ - ns_t_a6 = 38, /*%< IPv6 address (deprecated, use ns_t_aaaa) */ - ns_t_dname = 39, /*%< Non-terminal DNAME (for IPv6) */ - ns_t_sink = 40, /*%< Kitchen sink (experimentatl) */ - ns_t_opt = 41, /*%< EDNS0 option (meta-RR) */ - ns_t_apl = 42, /*%< Address prefix list (RFC3123) */ - ns_t_tkey = 249, /*%< Transaction key */ - ns_t_tsig = 250, /*%< Transaction signature. */ - ns_t_ixfr = 251, /*%< Incremental zone transfer. */ - ns_t_axfr = 252, /*%< Transfer zone of authority. */ - ns_t_mailb = 253, /*%< Transfer mailbox records. */ - ns_t_maila = 254, /*%< Transfer mail agent records. */ - ns_t_any = 255, /*%< Wildcard match. */ - ns_t_zxfr = 256, /*%< BIND-specific, nonstandard. */ - ns_t_max = 65536 -} ns_type; - -/* Exclusively a QTYPE? (not also an RTYPE) */ -#define ns_t_qt_p(t) (ns_t_xfr_p(t) || (t) == ns_t_any || \ - (t) == ns_t_mailb || (t) == ns_t_maila) -/* Some kind of meta-RR? (not a QTYPE, but also not an RTYPE) */ -#define ns_t_mrr_p(t) ((t) == ns_t_tsig || (t) == ns_t_opt) -/* Exclusively an RTYPE? (not also a QTYPE or a meta-RR) */ -#define ns_t_rr_p(t) (!ns_t_qt_p(t) && !ns_t_mrr_p(t)) -#define ns_t_udp_p(t) ((t) != ns_t_axfr && (t) != ns_t_zxfr) -#define ns_t_xfr_p(t) ((t) == ns_t_axfr || (t) == ns_t_ixfr || \ - (t) == ns_t_zxfr) - -/*% - * Values for class field - */ -typedef enum __ns_class { - ns_c_invalid = 0, /*%< Cookie. */ - ns_c_in = 1, /*%< Internet. */ - ns_c_2 = 2, /*%< unallocated/unsupported. */ - ns_c_chaos = 3, /*%< MIT Chaos-net. */ - ns_c_hs = 4, /*%< MIT Hesiod. */ - /* Query class values which do not appear in resource records */ - ns_c_none = 254, /*%< for prereq. sections in update requests */ - ns_c_any = 255, /*%< Wildcard match. */ - ns_c_max = 65536 -} ns_class; - -/* DNSSEC constants. */ - -typedef enum __ns_key_types { - ns_kt_rsa = 1, /*%< key type RSA/MD5 */ - ns_kt_dh = 2, /*%< Diffie Hellman */ - ns_kt_dsa = 3, /*%< Digital Signature Standard (MANDATORY) */ - ns_kt_private = 254 /*%< Private key type starts with OID */ -} ns_key_types; - -typedef enum __ns_cert_types { - cert_t_pkix = 1, /*%< PKIX (X.509v3) */ - cert_t_spki = 2, /*%< SPKI */ - cert_t_pgp = 3, /*%< PGP */ - cert_t_url = 253, /*%< URL private type */ - cert_t_oid = 254 /*%< OID private type */ -} ns_cert_types; - -/* Flags field of the KEY RR rdata. */ -#define NS_KEY_TYPEMASK 0xC000 /*%< Mask for "type" bits */ -#define NS_KEY_TYPE_AUTH_CONF 0x0000 /*%< Key usable for both */ -#define NS_KEY_TYPE_CONF_ONLY 0x8000 /*%< Key usable for confidentiality */ -#define NS_KEY_TYPE_AUTH_ONLY 0x4000 /*%< Key usable for authentication */ -#define NS_KEY_TYPE_NO_KEY 0xC000 /*%< No key usable for either; no key */ -/* The type bits can also be interpreted independently, as single bits: */ -#define NS_KEY_NO_AUTH 0x8000 /*%< Key unusable for authentication */ -#define NS_KEY_NO_CONF 0x4000 /*%< Key unusable for confidentiality */ -#define NS_KEY_RESERVED2 0x2000 /* Security is *mandatory* if bit=0 */ -#define NS_KEY_EXTENDED_FLAGS 0x1000 /*%< reserved - must be zero */ -#define NS_KEY_RESERVED4 0x0800 /*%< reserved - must be zero */ -#define NS_KEY_RESERVED5 0x0400 /*%< reserved - must be zero */ -#define NS_KEY_NAME_TYPE 0x0300 /*%< these bits determine the type */ -#define NS_KEY_NAME_USER 0x0000 /*%< key is assoc. with user */ -#define NS_KEY_NAME_ENTITY 0x0200 /*%< key is assoc. with entity eg host */ -#define NS_KEY_NAME_ZONE 0x0100 /*%< key is zone key */ -#define NS_KEY_NAME_RESERVED 0x0300 /*%< reserved meaning */ -#define NS_KEY_RESERVED8 0x0080 /*%< reserved - must be zero */ -#define NS_KEY_RESERVED9 0x0040 /*%< reserved - must be zero */ -#define NS_KEY_RESERVED10 0x0020 /*%< reserved - must be zero */ -#define NS_KEY_RESERVED11 0x0010 /*%< reserved - must be zero */ -#define NS_KEY_SIGNATORYMASK 0x000F /*%< key can sign RR's of same name */ -#define NS_KEY_RESERVED_BITMASK ( NS_KEY_RESERVED2 | \ - NS_KEY_RESERVED4 | \ - NS_KEY_RESERVED5 | \ - NS_KEY_RESERVED8 | \ - NS_KEY_RESERVED9 | \ - NS_KEY_RESERVED10 | \ - NS_KEY_RESERVED11 ) -#define NS_KEY_RESERVED_BITMASK2 0xFFFF /*%< no bits defined here */ -/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */ -#define NS_ALG_MD5RSA 1 /*%< MD5 with RSA */ -#define NS_ALG_DH 2 /*%< Diffie Hellman KEY */ -#define NS_ALG_DSA 3 /*%< DSA KEY */ -#define NS_ALG_DSS NS_ALG_DSA -#define NS_ALG_EXPIRE_ONLY 253 /*%< No alg, no security */ -#define NS_ALG_PRIVATE_OID 254 /*%< Key begins with OID giving alg */ -/* Protocol values */ -/* value 0 is reserved */ -#define NS_KEY_PROT_TLS 1 -#define NS_KEY_PROT_EMAIL 2 -#define NS_KEY_PROT_DNSSEC 3 -#define NS_KEY_PROT_IPSEC 4 -#define NS_KEY_PROT_ANY 255 - -/* Signatures */ -#define NS_MD5RSA_MIN_BITS 512 /*%< Size of a mod or exp in bits */ -#define NS_MD5RSA_MAX_BITS 4096 - /* Total of binary mod and exp */ -#define NS_MD5RSA_MAX_BYTES ((NS_MD5RSA_MAX_BITS+7/8)*2+3) - /* Max length of text sig block */ -#define NS_MD5RSA_MAX_BASE64 (((NS_MD5RSA_MAX_BYTES+2)/3)*4) -#define NS_MD5RSA_MIN_SIZE ((NS_MD5RSA_MIN_BITS+7)/8) -#define NS_MD5RSA_MAX_SIZE ((NS_MD5RSA_MAX_BITS+7)/8) - -#define NS_DSA_SIG_SIZE 41 -#define NS_DSA_MIN_SIZE 213 -#define NS_DSA_MAX_BYTES 405 - -/* Offsets into SIG record rdata to find various values */ -#define NS_SIG_TYPE 0 /*%< Type flags */ -#define NS_SIG_ALG 2 /*%< Algorithm */ -#define NS_SIG_LABELS 3 /*%< How many labels in name */ -#define NS_SIG_OTTL 4 /*%< Original TTL */ -#define NS_SIG_EXPIR 8 /*%< Expiration time */ -#define NS_SIG_SIGNED 12 /*%< Signature time */ -#define NS_SIG_FOOT 16 /*%< Key footprint */ -#define NS_SIG_SIGNER 18 /*%< Domain name of who signed it */ -/* How RR types are represented as bit-flags in NXT records */ -#define NS_NXT_BITS 8 -#define NS_NXT_BIT_SET( n,p) (p[(n)/NS_NXT_BITS] |= (0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_BIT_CLEAR(n,p) (p[(n)/NS_NXT_BITS] &= ~(0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_BIT_ISSET(n,p) (p[(n)/NS_NXT_BITS] & (0x80>>((n)%NS_NXT_BITS))) -#define NS_NXT_MAX 127 - -/*% - * EDNS0 extended flags and option codes, host order. - */ -#define NS_OPT_DNSSEC_OK 0x8000U -#define NS_OPT_NSID 3 - -/*% - * Inline versions of get/put short/long. Pointer is advanced. - */ -#define NS_GET16(s, cp) do { \ - register const u_char *t_cp = (const u_char *)(cp); \ - (s) = ((u_int16_t)t_cp[0] << 8) \ - | ((u_int16_t)t_cp[1]) \ - ; \ - (cp) += NS_INT16SZ; \ -} while (0) - -#define NS_GET32(l, cp) do { \ - register const u_char *t_cp = (const u_char *)(cp); \ - (l) = ((u_int32_t)t_cp[0] << 24) \ - | ((u_int32_t)t_cp[1] << 16) \ - | ((u_int32_t)t_cp[2] << 8) \ - | ((u_int32_t)t_cp[3]) \ - ; \ - (cp) += NS_INT32SZ; \ -} while (0) - -#define NS_PUT16(s, cp) do { \ - register u_int16_t t_s = (u_int16_t)(s); \ - register u_char *t_cp = (u_char *)(cp); \ - *t_cp++ = t_s >> 8; \ - *t_cp = t_s; \ - (cp) += NS_INT16SZ; \ -} while (0) - -#define NS_PUT32(l, cp) do { \ - register u_int32_t t_l = (u_int32_t)(l); \ - register u_char *t_cp = (u_char *)(cp); \ - *t_cp++ = t_l >> 24; \ - *t_cp++ = t_l >> 16; \ - *t_cp++ = t_l >> 8; \ - *t_cp = t_l; \ - (cp) += NS_INT32SZ; \ -} while (0) - -#endif /* !_ARPA_NAMESER_H_ */ -/*! \file */ - - - -/*% - * from nameser.h 8.1 (Berkeley) 6/2/93 - * $BINDId: nameser_compat.h,v 8.11 1999/01/02 08:00:58 vixie Exp $ - */ - -#ifndef _ARPA_NAMESER_COMPAT_ -#define _ARPA_NAMESER_COMPAT_ - -#define __BIND 19950621 /*%< (DEAD) interface version stamp. */ - -#include - -/*% - * Structure for query header. The order of the fields is machine- and - * compiler-dependent, depending on the byte/bit order and the layout - * of bit fields. We use bit fields only in int variables, as this - * is all ANSI requires. This requires a somewhat confusing rearrangement. - */ - -typedef struct { - unsigned id :16; /*%< query identification number */ -#if BYTE_ORDER == BIG_ENDIAN - /* fields in third byte */ - unsigned qr: 1; /*%< response flag */ - unsigned opcode: 4; /*%< purpose of message */ - unsigned aa: 1; /*%< authoritive answer */ - unsigned tc: 1; /*%< truncated message */ - unsigned rd: 1; /*%< recursion desired */ - /* fields in fourth byte */ - unsigned ra: 1; /*%< recursion available */ - unsigned unused :1; /*%< unused bits (MBZ as of 4.9.3a3) */ - unsigned ad: 1; /*%< authentic data from named */ - unsigned cd: 1; /*%< checking disabled by resolver */ - unsigned rcode :4; /*%< response code */ -#endif -#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN - /* fields in third byte */ - unsigned rd :1; /*%< recursion desired */ - unsigned tc :1; /*%< truncated message */ - unsigned aa :1; /*%< authoritive answer */ - unsigned opcode :4; /*%< purpose of message */ - unsigned qr :1; /*%< response flag */ - /* fields in fourth byte */ - unsigned rcode :4; /*%< response code */ - unsigned cd: 1; /*%< checking disabled by resolver */ - unsigned ad: 1; /*%< authentic data from named */ - unsigned unused :1; /*%< unused bits (MBZ as of 4.9.3a3) */ - unsigned ra :1; /*%< recursion available */ -#endif - /* remaining bytes */ - unsigned qdcount :16; /*%< number of question entries */ - unsigned ancount :16; /*%< number of answer entries */ - unsigned nscount :16; /*%< number of authority entries */ - unsigned arcount :16; /*%< number of resource entries */ -} HEADER; - -#define PACKETSZ NS_PACKETSZ -#define MAXDNAME NS_MAXDNAME -#define MAXCDNAME NS_MAXCDNAME -#define MAXLABEL NS_MAXLABEL -#define HFIXEDSZ NS_HFIXEDSZ -#define QFIXEDSZ NS_QFIXEDSZ -#define RRFIXEDSZ NS_RRFIXEDSZ -#define INT32SZ NS_INT32SZ -#define INT16SZ NS_INT16SZ -#define INT8SZ NS_INT8SZ -#define INADDRSZ NS_INADDRSZ -#define IN6ADDRSZ NS_IN6ADDRSZ -#define INDIR_MASK NS_CMPRSFLGS -#define NAMESERVER_PORT NS_DEFAULTPORT - -#define S_ZONE ns_s_zn -#define S_PREREQ ns_s_pr -#define S_UPDATE ns_s_ud -#define S_ADDT ns_s_ar - -#define QUERY ns_o_query -#define IQUERY ns_o_iquery -#define STATUS ns_o_status -#define NS_NOTIFY_OP ns_o_notify -#define NS_UPDATE_OP ns_o_update - -#define NOERROR ns_r_noerror -#define FORMERR ns_r_formerr -#define SERVFAIL ns_r_servfail -#define NXDOMAIN ns_r_nxdomain -#define NOTIMP ns_r_notimpl -#define REFUSED ns_r_refused -#define YXDOMAIN ns_r_yxdomain -#define YXRRSET ns_r_yxrrset -#define NXRRSET ns_r_nxrrset -#define NOTAUTH ns_r_notauth -#define NOTZONE ns_r_notzone -/*#define BADSIG ns_r_badsig*/ -/*#define BADKEY ns_r_badkey*/ -/*#define BADTIME ns_r_badtime*/ - - -#define DELETE ns_uop_delete -#define ADD ns_uop_add - -#define T_A ns_t_a -#define T_NS ns_t_ns -#define T_MD ns_t_md -#define T_MF ns_t_mf -#define T_CNAME ns_t_cname -#define T_SOA ns_t_soa -#define T_MB ns_t_mb -#define T_MG ns_t_mg -#define T_MR ns_t_mr -#define T_NULL ns_t_null -#define T_WKS ns_t_wks -#define T_PTR ns_t_ptr -#define T_HINFO ns_t_hinfo -#define T_MINFO ns_t_minfo -#define T_MX ns_t_mx -#define T_TXT ns_t_txt -#define T_RP ns_t_rp -#define T_AFSDB ns_t_afsdb -#define T_X25 ns_t_x25 -#define T_ISDN ns_t_isdn -#define T_RT ns_t_rt -#define T_NSAP ns_t_nsap -#define T_NSAP_PTR ns_t_nsap_ptr -#define T_SIG ns_t_sig -#define T_KEY ns_t_key -#define T_PX ns_t_px -#define T_GPOS ns_t_gpos -#define T_AAAA ns_t_aaaa -#define T_LOC ns_t_loc -#define T_NXT ns_t_nxt -#define T_EID ns_t_eid -#define T_NIMLOC ns_t_nimloc -#define T_SRV ns_t_srv -#define T_ATMA ns_t_atma -#define T_NAPTR ns_t_naptr -#define T_A6 ns_t_a6 -#define T_DNAME ns_t_dname -#define T_TSIG ns_t_tsig -#define T_IXFR ns_t_ixfr -#define T_AXFR ns_t_axfr -#define T_MAILB ns_t_mailb -#define T_MAILA ns_t_maila -#define T_ANY ns_t_any - -#define C_IN ns_c_in -#define C_CHAOS ns_c_chaos -#define C_HS ns_c_hs -/* BIND_UPDATE */ -#define C_NONE ns_c_none -#define C_ANY ns_c_any - -#define GETSHORT NS_GET16 -#define GETLONG NS_GET32 -#define PUTSHORT NS_PUT16 -#define PUTLONG NS_PUT32 - -#endif /* _ARPA_NAMESER_COMPAT_ */ -/*! \file */ diff --git a/jni/iodine/src/encoding.c b/jni/iodine/src/encoding.c index 896d67d..af7620e 100644 --- a/jni/iodine/src/encoding.c +++ b/jni/iodine/src/encoding.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,23 +20,22 @@ #include "encoding.h" int -build_hostname(char *buf, size_t buflen, - const char *data, const size_t datalen, +build_hostname(char *buf, size_t buflen, + const char *data, const size_t datalen, const char *topdomain, struct encoder *encoder, int maxlen) { - int encsize; size_t space; char *b; - space = MIN(maxlen, buflen) - strlen(topdomain) - 8; + space = MIN((size_t)maxlen, buflen) - strlen(topdomain) - 8; /* 8 = 5 max header length + 1 dot before topdomain + 2 safety */ if (!encoder->places_dots()) space -= (space / 57); /* space for dots */ memset(buf, 0, buflen); - - encsize = encoder->encode(buf, &space, data, datalen); + + encoder->encode(buf, &space, data, datalen); if (!encoder->places_dots()) inline_dotify(buf, buflen); @@ -45,7 +45,7 @@ build_hostname(char *buf, size_t buflen, /* move b back one step to see if the dot is there */ b--; - if (*b != '.') + if (*b != '.') *++b = '.'; b++; /* move b ahead of the string so we can copy to it */ @@ -63,7 +63,7 @@ unpack_data(char *buf, size_t buflen, char *data, size_t datalen, struct encoder return enc->decode(buf, &buflen, data, datalen); } -int +int inline_dotify(char *buf, size_t buflen) { unsigned dots; @@ -101,7 +101,7 @@ inline_dotify(char *buf, size_t buflen) return total; } -int +int inline_undotify(char *buf, size_t len) { unsigned pos; @@ -124,7 +124,7 @@ inline_undotify(char *buf, size_t len) *writer++ = *reader++; pos++; } - + /* return new length of string */ return len - dots; } diff --git a/jni/iodine/src/encoding.h b/jni/iodine/src/encoding.h index 7ddf6e0..ab22279 100644 --- a/jni/iodine/src/encoding.h +++ b/jni/iodine/src/encoding.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/src/fw_query.c b/jni/iodine/src/fw_query.c index 3727f08..4f7d8c4 100644 --- a/jni/iodine/src/fw_query.c +++ b/jni/iodine/src/fw_query.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Erik Ekman + * Copyright (c) 2008-2014 Erik Ekman * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -29,9 +29,9 @@ void fw_query_init() void fw_query_put(struct fw_query *fw_query) { memcpy(&(fwq[fwq_ix]), fw_query, sizeof(struct fw_query)); - + ++fwq_ix; - if (fwq_ix >= FW_QUERY_CACHE_SIZE) + if (fwq_ix >= FW_QUERY_CACHE_SIZE) fwq_ix = 0; } diff --git a/jni/iodine/src/fw_query.h b/jni/iodine/src/fw_query.h index 7568a5f..f8f0de6 100644 --- a/jni/iodine/src/fw_query.h +++ b/jni/iodine/src/fw_query.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008 Erik Ekman + * Copyright (c) 2008-2014 Erik Ekman * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -28,7 +28,7 @@ #define FW_QUERY_CACHE_SIZE 16 struct fw_query { - struct sockaddr addr; + struct sockaddr_storage addr; int addrlen; unsigned short id; }; diff --git a/jni/iodine/src/iodine.c b/jni/iodine/src/iodine.c index 03efb18..5c19576 100644 --- a/jni/iodine/src/iodine.c +++ b/jni/iodine/src/iodine.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -32,6 +33,7 @@ #else #include #include +#include #endif #include "common.h" @@ -51,11 +53,17 @@ static char *__progname; #define PASSWORD_ENV_VAR "IODINE_PASS" static void -sighandler(int sig) +sighandler(int sig) { client_stop(); } +#if defined(__GNUC__) || defined(__clang__) +/* mark as no return to help some compilers to avoid warnings + * about use of uninitialized variables */ +static void usage() __attribute__((noreturn)); +#endif + static void usage() { extern char *__progname; @@ -75,7 +83,7 @@ help() { "[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec] " "[-z context] [-F pidfile] [nameserver] topdomain\n", __progname); fprintf(stderr, "Options to try if connection doesn't work:\n"); - fprintf(stderr, " -T force dns type: NULL, TXT, SRV, MX, CNAME, A (default: autodetect)\n"); + fprintf(stderr, " -T force dns type: NULL, PRIVATE, TXT, SRV, MX, CNAME, A (default: autodetect)\n"); fprintf(stderr, " -O force downstream encoding for -T other than NULL: Base32, Base64, Base64u,\n"); fprintf(stderr, " Base128, or (only for TXT:) Raw (default: autodetect)\n"); fprintf(stderr, " -I max interval between requests (default 4 sec) to prevent DNS timeouts\n"); @@ -101,8 +109,9 @@ help() { static void version() { + fprintf(stderr, "iodine IP over DNS tunneling client\n"); - fprintf(stderr, "version: 0.6.0-rc1 from 2010-02-13\n"); + fprintf(stderr, "version: 0.7.0 from 2014-06-16\n"); exit(0); } @@ -110,8 +119,9 @@ version() { int main(int argc, char **argv) { - char *nameserv_addr; + char *nameserv_host; char *topdomain; + char *errormsg; #ifndef WINDOWS32 struct passwd *pw; #endif @@ -132,9 +142,16 @@ main(int argc, char **argv) int lazymode; int selecttimeout; int hostname_maxlen; +#ifdef OPENBSD + int rtable = 0; +#endif + struct sockaddr_storage nameservaddr; + int nameservaddr_len; + int nameserv_family; - nameserv_addr = NULL; + nameserv_host = NULL; topdomain = NULL; + errormsg = NULL; #ifndef WINDOWS32 pw = NULL; #endif @@ -154,6 +171,7 @@ main(int argc, char **argv) lazymode = 1; selecttimeout = 4; hostname_maxlen = 0xFF; + nameserv_family = AF_UNSPEC; #ifdef WINDOWS32 WSAStartup(req_version, &wsa_data); @@ -161,7 +179,7 @@ main(int argc, char **argv) srand((unsigned) time(NULL)); client_init(); - + #if !defined(BSD) && !defined(__GLIBC__) __progname = strrchr(argv[0], '/'); if (__progname == NULL) @@ -170,8 +188,14 @@ main(int argc, char **argv) __progname++; #endif - while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:M:F:T:O:L:I:")) != -1) { + while ((choice = getopt(argc, argv, "46vfhru:t:d:R:P:m:M:F:T:O:L:I:")) != -1) { switch(choice) { + case '4': + nameserv_family = AF_INET; + break; + case '6': + nameserv_family = AF_INET6; + break; case 'v': version(); /* NOTREACHED */ @@ -185,6 +209,7 @@ main(int argc, char **argv) break; case 'r': raw_mode = 0; + break; case 'u': username = optarg; break; @@ -194,12 +219,17 @@ main(int argc, char **argv) case 'd': device = optarg; break; +#ifdef OPENBSD + case 'R': + rtable = atoi(optarg); + break; +#endif case 'P': strncpy(password, optarg, sizeof(password)); password[sizeof(password)-1] = 0; - + /* XXX: find better way of cleaning up ps(1) */ - memset(optarg, 0, strlen(optarg)); + memset(optarg, 0, strlen(optarg)); break; case 'm': autodetect_frag_size = 0; @@ -217,12 +247,13 @@ main(int argc, char **argv) break; case 'F': pidfile = optarg; - break; + break; case 'T': - set_qtype(optarg); + if (client_set_qtype(optarg)) + errx(5, "Invalid query type '%s'", optarg); break; case 'O': /* not -D, is Debug in server */ - set_downenc(optarg); + client_set_downenc(optarg); break; case 'L': lazymode = atoi(optarg); @@ -243,7 +274,7 @@ main(int argc, char **argv) /* NOTREACHED */ } } - + check_superuser(usage); argc -= optind; @@ -251,11 +282,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: @@ -269,22 +300,21 @@ 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, nameserv_family, 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(); /* NOTREACHED */ - } + } - if (strlen(topdomain) <= 128) { - if(check_topdomain(topdomain)) { - warnx("Topdomain contains invalid characters.\n"); - usage(); - /* NOTREACHED */ - } - } else { - warnx("Use a topdomain max 128 chars long.\n"); + if(check_topdomain(topdomain, &errormsg)) { + warnx("Invalid topdomain: %s", errormsg); usage(); /* NOTREACHED */ } @@ -293,7 +323,7 @@ main(int argc, char **argv) client_set_lazymode(lazymode); client_set_topdomain(topdomain); client_set_hostname_maxlen(hostname_maxlen); - + if (username != NULL) { #ifndef WINDOWS32 if ((pw = getpwnam(username)) == NULL) { @@ -303,51 +333,55 @@ main(int argc, char **argv) } #endif } - + if (strlen(password) == 0) { if (NULL != getenv(PASSWORD_ENV_VAR)) snprintf(password, sizeof(password), "%s", getenv(PASSWORD_ENV_VAR)); else read_password(password, sizeof(password)); } - + client_set_password(password); if ((tun_fd = open_tun(device)) == -1) { retval = 1; goto cleanup1; } - if ((dns_fd = open_dns(0, INADDR_ANY)) == -1) { + if ((dns_fd = open_dns_from_host(NULL, 0, nameservaddr.ss_family, AI_PASSIVE)) < 0) { retval = 1; goto cleanup2; } +#ifdef OPENBSD + if (rtable > 0) + socket_setrtable(dns_fd, rtable); +#endif signal(SIGINT, sighandler); signal(SIGTERM, sighandler); fprintf(stderr, "Sending DNS queries for %s to %s\n", - topdomain, nameserv_addr); + topdomain, format_addr(&nameservaddr, nameservaddr_len)); if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) { retval = 1; goto cleanup2; } - + if (client_get_conn() == CONN_RAW_UDP) { fprintf(stderr, "Sending raw traffic directly to %s\n", client_get_raw_addr()); } fprintf(stderr, "Connection setup complete, transmitting data.\n"); - if (foreground == 0) + if (foreground == 0) do_detach(); - + if (pidfile != NULL) do_pidfile(pidfile); if (newroot != NULL) do_chroot(newroot); - + if (username != NULL) { #ifndef WINDOWS32 gid_t gids[1]; diff --git a/jni/iodine/src/iodined.c b/jni/iodine/src/iodined.c index 3681084..1065c33 100644 --- a/jni/iodine/src/iodined.c +++ b/jni/iodine/src/iodined.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +61,10 @@ #include "fw_query.h" #include "version.h" +#ifdef HAVE_SYSTEMD +# include +#endif + #ifdef WINDOWS32 WORD req_version = MAKEWORD(2, 2); WSADATA wsa_data; @@ -93,8 +99,60 @@ static int read_dns(int, int, struct query *); static void write_dns(int, struct query *, char *, int, char); static void handle_full_packet(int, int, int); +/* Ask externalip.net webservice to get external ip */ +static int get_external_ip(struct in_addr *ip) +{ + int sock; + struct addrinfo *addr; + int res; + const char *getstr = "GET /ip/ HTTP/1.0\r\n" + /* HTTP 1.0 to avoid chunked transfer coding */ + "Host: api.externalip.net\r\n\r\n"; + char buf[512]; + char *b; + int len; + + res = getaddrinfo("api.externalip.net", "80", NULL, &addr); + if (res < 0) return 1; + + sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + if (sock < 0) { + freeaddrinfo(addr); + return 2; + } + + res = connect(sock, addr->ai_addr, addr->ai_addrlen); + freeaddrinfo(addr); + if (res < 0) return 3; + + res = write(sock, getstr, strlen(getstr)); + if (res != strlen(getstr)) return 4; + + /* Zero buf before receiving, leave at least one zero at the end */ + memset(buf, 0, sizeof(buf)); + res = read(sock, buf, sizeof(buf) - 1); + if (res < 0) return 5; + len = res; + + res = close(sock); + if (res < 0) return 6; + + b = buf; + while (len > 9) { + /* Look for split between headers and data */ + if (strncmp("\r\n\r\n", b, 4) == 0) break; + b++; + len--; + } + if (len < 10) return 7; + b += 4; + + res = inet_aton(b, ip); + return (res == 0); +} + static void -sigint(int sig) +sigint(int sig) { running = 0; } @@ -116,6 +174,7 @@ syslog(int a, const char *str, ...) } #endif +/* This will not check that user has passed login challenge */ static int check_user_and_ip(int userid, struct query *q) { @@ -124,7 +183,7 @@ check_user_and_ip(int userid, struct query *q) /* Note: duplicate in handle_raw_login() except IP-address check */ if (userid < 0 || userid >= created_users ) { - return 1; + return 1; } if (!users[userid].active || users[userid].disabled) { return 1; @@ -142,6 +201,20 @@ check_user_and_ip(int userid, struct query *q) return memcmp(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr)); } +/* This checks that user has passed normal (non-raw) login challenge */ +static int +check_authenticated_user_and_ip(int userid, struct query *q) +{ + int res = check_user_and_ip(userid, q); + if (res) + return res; + + if (!users[userid].authenticated) + return 1; + + return 0; +} + static void send_raw(int fd, char *buf, int buflen, int user, int cmd, struct query *q) { @@ -159,13 +232,11 @@ send_raw(int fd, char *buf, int buflen, int user, int cmd, struct query *q) packet[RAW_HDR_CMD] = cmd | (user & 0x0F); if (debug >= 2) { - struct sockaddr_in *tempin; - tempin = (struct sockaddr_in *) &(q->from); - fprintf(stderr, "TX-raw: client %s, cmd %d, %d bytes\n", - inet_ntoa(tempin->sin_addr), cmd, len); + fprintf(stderr, "TX-raw: client %s, cmd %d, %d bytes\n", + format_addr(&q->from, q->fromlen), cmd, len); } - sendto(fd, packet, len, 0, &q->from, q->fromlen); + sendto(fd, packet, len, 0, (struct sockaddr *) &q->from, q->fromlen); } @@ -496,12 +567,12 @@ send_chunk_or_dataless(int dns_fd, int userid, struct query *q) pkt[0] = (1<<7) | ((users[userid].inpacket.seqno & 7) << 4) | (users[userid].inpacket.fragment & 15); /* Second byte is 3 bits downstream seqno, 4 bits downstream fragment, 1 bit last flag */ - pkt[1] = ((users[userid].outpacket.seqno & 7) << 5) | + pkt[1] = ((users[userid].outpacket.seqno & 7) << 5) | ((users[userid].outpacket.fragment & 15) << 1) | (last & 1); if (debug >= 1) { fprintf(stderr, "OUT pkt seq# %d, frag %d (last=%d), offset %d, fragsize %d, total %d, to user %d\n", - users[userid].outpacket.seqno & 7, users[userid].outpacket.fragment & 15, + users[userid].outpacket.seqno & 7, users[userid].outpacket.fragment & 15, last, users[userid].outpacket.offset, datalen, users[userid].outpacket.len, userid); } write_dns(dns_fd, q, pkt, datalen + 2, users[userid].downenc); @@ -555,7 +626,7 @@ tunnel_tun(int tun_fd, int dns_fd) if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0) return 0; - + /* find target ip in packet, in is padded with 4 bytes TUN header */ header = (struct ip*) (in + 4); userid = find_user_by_ip(header->ip_dst.s_addr); @@ -601,7 +672,7 @@ static void send_version_response(int fd, version_ack_t ack, uint32_t payload, int userid, struct query *q) { char out[9]; - + switch (ack) { case VERSION_ACK: strncpy(out, "VACK", sizeof(out)); @@ -613,7 +684,7 @@ send_version_response(int fd, version_ack_t ack, uint32_t payload, int userid, s strncpy(out, "VFUL", sizeof(out)); break; } - + out[4] = ((payload >> 24) & 0xff); out[5] = ((payload >> 16) & 0xff); out[6] = ((payload >> 8) & 0xff); @@ -686,7 +757,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), domain_len - 1, b32); /* Version greeting, compare and send ack/nak */ - if (read > 4) { + if (read > 4) { /* Received V + 32bits version */ version = (((unpacked[0] & 0xff) << 24) | ((unpacked[1] & 0xff) << 16) | @@ -704,13 +775,13 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) /* Store remote IP number */ tempin = (struct sockaddr_in *) &(q->from); memcpy(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr)); - + memcpy(&(users[userid].q), q, sizeof(struct query)); users[userid].encoder = get_base32_encoder(); users[userid].downenc = 'T'; send_version_response(dns_fd, VERSION_ACK, users[userid].seed, userid, q); syslog(LOG_INFO, "accepted version for user #%d from %s", - userid, inet_ntoa(tempin->sin_addr)); + userid, format_addr(&q->from, q->fromlen)); users[userid].q.id = 0; users[userid].q.id2 = 0; users[userid].q_sendrealsoon.id = 0; @@ -751,13 +822,13 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) } else { /* No space for another user */ send_version_response(dns_fd, VERSION_FULL, created_users, 0, q); - syslog(LOG_INFO, "dropped user from %s, server full", - inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr)); + syslog(LOG_INFO, "dropped user from %s, server full", + format_addr(&q->from, q->fromlen)); } } else { send_version_response(dns_fd, VERSION_NACK, VERSION, 0, q); - syslog(LOG_INFO, "dropped user from %s, sent bad version %08X", - inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr), version); + syslog(LOG_INFO, "dropped user from %s, sent bad version %08X", + format_addr(&q->from, q->fromlen), version); } return; } else if(in[0] == 'L' || in[0] == 'l') { @@ -773,21 +844,23 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) if (check_user_and_ip(userid, q) != 0) { write_dns(dns_fd, q, "BADIP", 5, 'T'); syslog(LOG_WARNING, "dropped login request from user #%d from unexpected source %s", - userid, inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr)); + userid, format_addr(&q->from, q->fromlen)); return; } else { users[userid].last_pkt = time(NULL); login_calculate(logindata, 16, password, users[userid].seed); if (read >= 18 && (memcmp(logindata, unpacked+1, 16) == 0)) { - /* Login ok, send ip/mtu/netmask info */ + /* Store login ok */ + users[userid].authenticated = 1; + /* Send ip/mtu/netmask info */ tempip.s_addr = my_ip; tmp[0] = strdup(inet_ntoa(tempip)); tempip.s_addr = users[userid].tun_ip; tmp[1] = strdup(inet_ntoa(tempip)); - read = snprintf(out, sizeof(out), "%s-%s-%d-%d", + read = snprintf(out, sizeof(out), "%s-%s-%d-%d", tmp[0], tmp[1], my_mtu, netmask); write_dns(dns_fd, q, out, read, users[userid].downenc); @@ -799,7 +872,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) } else { write_dns(dns_fd, q, "LNAK", 4, 'T'); syslog(LOG_WARNING, "rejected login request from user #%d from %s, bad password", - userid, inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr)); + userid, format_addr(&q->from, q->fromlen)); } } return; @@ -808,9 +881,9 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) in_addr_t replyaddr; unsigned addr; char reply[5]; - + userid = b32_8to5(in[1]); - if (check_user_and_ip(userid, q) != 0) { + if (check_authenticated_user_and_ip(userid, q) != 0) { write_dns(dns_fd, q, "BADIP", 5, 'T'); return; /* illegal id */ } @@ -846,12 +919,12 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) } userid = b32_8to5(in[1]); - - if (check_user_and_ip(userid, q) != 0) { + + if (check_authenticated_user_and_ip(userid, q) != 0) { write_dns(dns_fd, q, "BADIP", 5, 'T'); return; /* illegal id */ } - + codec = b32_8to5(in[2]); switch (codec) { @@ -888,7 +961,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) userid = b32_8to5(in[1]); - if (check_user_and_ip(userid, q) != 0) { + if (check_authenticated_user_and_ip(userid, q) != 0) { write_dns(dns_fd, q, "BADIP", 5, 'T'); return; /* illegal id */ } @@ -1016,13 +1089,13 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) /* Downstream fragsize probe packet */ userid = (b32_8to5(in[1]) >> 1) & 15; - if (check_user_and_ip(userid, q) != 0) { + if (check_authenticated_user_and_ip(userid, q) != 0) { write_dns(dns_fd, q, "BADIP", 5, 'T'); return; /* illegal id */ } - + req_frag_size = ((b32_8to5(in[1]) & 1) << 10) | ((b32_8to5(in[2]) & 31) << 5) | (b32_8to5(in[3]) & 31); - if (req_frag_size < 2 || req_frag_size > 2047) { + if (req_frag_size < 2 || req_frag_size > 2047) { write_dns(dns_fd, q, "BADFRAG", 7, users[userid].downenc); } else { char buf[2048]; @@ -1051,13 +1124,13 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) /* Downstream fragsize packet */ userid = unpacked[0]; - if (check_user_and_ip(userid, q) != 0) { + if (check_authenticated_user_and_ip(userid, q) != 0) { write_dns(dns_fd, q, "BADIP", 5, 'T'); return; /* illegal id */ } - + max_frag_size = ((unpacked[1] & 0xff) << 8) | (unpacked[2] & 0xff); - if (max_frag_size < 2) { + if (max_frag_size < 2) { write_dns(dns_fd, q, "BADFRAG", 7, users[userid].downenc); } else { users[userid].fragsize = max_frag_size; @@ -1084,7 +1157,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) /* Ping packet, store userid */ userid = unpacked[0]; - if (check_user_and_ip(userid, q) != 0) { + if (check_authenticated_user_and_ip(userid, q) != 0) { write_dns(dns_fd, q, "BADIP", 5, 'T'); return; /* illegal id */ } @@ -1122,7 +1195,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) memcpy(&(users[userid].q.from2), &(q->from), q->fromlen); return; } - + if (users[userid].q_sendrealsoon.id != 0 && q->type == users[userid].q_sendrealsoon.type && !strcmp(q->name, users[userid].q_sendrealsoon.name)) { @@ -1138,7 +1211,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) &(q->from), q->fromlen); return; } - + dn_seq = unpacked[1] >> 4; dn_frag = unpacked[1] & 15; @@ -1214,7 +1287,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) userid = code; /* Check user and sending ip number */ - if (check_user_and_ip(userid, q) != 0) { + if (check_authenticated_user_and_ip(userid, q) != 0) { write_dns(dns_fd, q, "BADIP", 5, 'T'); return; /* illegal id */ } @@ -1233,7 +1306,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) like to re-try early and often (with _different_ .id!) */ if (users[userid].q.id != 0 && q->type == users[userid].q.type && - !strcmp(q->name, users[userid].q.name) && + !strcmp(q->name, users[userid].q.name) && users[userid].lazy) { /* We have this packet already, and it's waiting to be answered. Always keep the last duplicate, since the @@ -1250,7 +1323,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) memcpy(&(users[userid].q.from2), &(q->from), q->fromlen); return; } - + if (users[userid].q_sendrealsoon.id != 0 && q->type == users[userid].q_sendrealsoon.type && !strcmp(q->name, users[userid].q_sendrealsoon.name)) { @@ -1266,7 +1339,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) &(q->from), q->fromlen); return; } - + /* Decode data header */ up_seq = (b32_8to5(in[1]) >> 2) & 7; @@ -1277,7 +1350,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) process_downstream_ack(userid, dn_seq, dn_frag); - if (up_seq == users[userid].inpacket.seqno && + if (up_seq == users[userid].inpacket.seqno && up_frag <= users[userid].inpacket.fragment) { /* Got repeated old packet _with data_, probably because client didn't receive our ack. So re-send @@ -1435,12 +1508,10 @@ handle_ns_request(int dns_fd, struct query *q) warnx("dns_encode_ns_response doesn't fit"); return; } - + if (debug >= 2) { - struct sockaddr_in *tempin; - tempin = (struct sockaddr_in *) &(q->from); - fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes NS reply\n", - inet_ntoa(tempin->sin_addr), q->type, q->name, len); + fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes NS reply\n", + format_addr(&q->from, q->fromlen), q->type, q->name, len); } if (sendto(dns_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) { warn("ns reply send error"); @@ -1469,12 +1540,10 @@ handle_a_request(int dns_fd, struct query *q, int fakeip) warnx("dns_encode_a_response doesn't fit"); return; } - + if (debug >= 2) { - struct sockaddr_in *tempin; - tempin = (struct sockaddr_in *) &(q->from); fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes A reply\n", - inet_ntoa(tempin->sin_addr), q->type, q->name, len); + format_addr(&q->from, q->fromlen), q->type, q->name, len); } if (sendto(dns_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) { warn("a reply send error"); @@ -1506,7 +1575,7 @@ forward_query(int bind_fd, struct query *q) myaddr = (struct sockaddr_in *) &(q->from); memcpy(&(myaddr->sin_addr), &newaddr, sizeof(in_addr_t)); myaddr->sin_port = htons(bind_port); - + if (debug >= 2) { fprintf(stderr, "TX: NS reply \n"); } @@ -1515,45 +1584,45 @@ forward_query(int bind_fd, struct query *q) warn("forward query error"); } } - + static int tunnel_bind(int bind_fd, int dns_fd) { char packet[64*1024]; - struct sockaddr_in from; + struct sockaddr_storage from; socklen_t fromlen; struct fw_query *query; unsigned short id; int r; fromlen = sizeof(struct sockaddr); - r = recvfrom(bind_fd, packet, sizeof(packet), 0, + r = recvfrom(bind_fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &fromlen); if (r <= 0) return 0; id = dns_get_id(packet, r); - + if (debug >= 2) { fprintf(stderr, "RX: Got response on query %u from DNS\n", (id & 0xFFFF)); } /* Get sockaddr from id */ fw_query_get(id, &query); - if (!query && debug >= 2) { - fprintf(stderr, "Lost sender of id %u, dropping reply\n", (id & 0xFFFF)); + if (!query) { + if (debug >= 2) { + fprintf(stderr, "Lost sender of id %u, dropping reply\n", (id & 0xFFFF)); + } return 0; } if (debug >= 2) { - struct sockaddr_in *in; - in = (struct sockaddr_in *) &(query->addr); fprintf(stderr, "TX: client %s id %u, %d bytes\n", - inet_ntoa(in->sin_addr), (id & 0xffff), r); + format_addr(&query->addr, query->addrlen), (id & 0xffff), r); } - - if (sendto(dns_fd, packet, r, 0, (const struct sockaddr *) &(query->addr), + + if (sendto(dns_fd, packet, r, 0, (const struct sockaddr *) &(query->addr), query->addrlen) <= 0) { warn("forward reply error"); } @@ -1567,16 +1636,14 @@ tunnel_dns(int tun_fd, int dns_fd, int bind_fd) struct query q; int read; int domain_len; - int inside_topdomain; + int inside_topdomain = 0; if ((read = read_dns(dns_fd, tun_fd, &q)) <= 0) return 0; if (debug >= 2) { - struct sockaddr_in *tempin; - tempin = (struct sockaddr_in *) &(q.from); - fprintf(stderr, "RX: client %s, type %d, name %s\n", - inet_ntoa(tempin->sin_addr), q.type, q.name); + fprintf(stderr, "RX: client %s, type %d, name %s\n", + format_addr(&q.from, q.fromlen), q.type, q.name); } domain_len = strlen(q.name) - strlen(topdomain); @@ -1612,6 +1679,7 @@ tunnel_dns(int tun_fd, int dns_fd, int bind_fd) switch (q.type) { case T_NULL: + case T_PRIVATE: case T_CNAME: case T_A: case T_MX: @@ -1636,12 +1704,13 @@ tunnel_dns(int tun_fd, int dns_fd, int bind_fd) } static int -tunnel(int tun_fd, int dns_fd, int bind_fd) +tunnel(int tun_fd, int dns_fd, int bind_fd, int max_idle_time) { struct timeval tv; fd_set fds; int i; int userid; + time_t last_action = time(NULL); while (running) { int maxfd; @@ -1655,7 +1724,7 @@ tunnel(int tun_fd, int dns_fd, int bind_fd) requests during heavy upstream traffic. 20msec: ~8 packs every 1/50sec = ~400 DNSreq/sec, or ~1200bytes every 1/50sec = ~0.5 Mbit/sec upstream */ - for (userid = 0; userid < USERS; userid++) { + for (userid = 0; userid < created_users; userid++) { if (users[userid].active && !users[userid].disabled && users[userid].last_pkt + 60 > time(NULL)) { users[userid].q_sendrealsoon_new = 0; @@ -1685,29 +1754,41 @@ tunnel(int tun_fd, int dns_fd, int bind_fd) } i = select(maxfd + 1, &fds, NULL, NULL, &tv); - + if(i < 0) { - if (running) + if (running) warn("select"); return 1; } - if (i==0) { - /* timeout; whatever; doesn't matter anymore */ + if (i==0) { + if (max_idle_time) { + /* only trigger the check if that's worth ( ie, no need to loop over if there + is something to send */ + if (last_action + max_idle_time < time(NULL)) { + for (userid = 0; userid < created_users; userid++) { + last_action = ( users[userid].last_pkt > last_action ) ? users[userid].last_pkt : last_action; + } + if (last_action + max_idle_time < time(NULL)) { + fprintf(stderr, "Idling since too long, shutting down...\n"); + running = 0; + } + } + } } else { if (FD_ISSET(tun_fd, &fds)) { tunnel_tun(tun_fd, dns_fd); } if (FD_ISSET(dns_fd, &fds)) { tunnel_dns(tun_fd, dns_fd, bind_fd); - } + } if (FD_ISSET(bind_fd, &fds)) { tunnel_bind(bind_fd, dns_fd); } } /* Send realsoon's if tun or dns didn't already */ - for (userid = 0; userid < USERS; userid++) + for (userid = 0; userid < created_users; userid++) if (users[userid].active && !users[userid].disabled && users[userid].last_pkt + 60 > time(NULL) && users[userid].q_sendrealsoon.id != 0 && @@ -1728,7 +1809,7 @@ handle_full_packet(int tun_fd, int dns_fd, int userid) int ret; outlen = sizeof(out); - ret = uncompress((uint8_t*)out, &outlen, + ret = uncompress((uint8_t*)out, &outlen, (uint8_t*)users[userid].inpacket.data, users[userid].inpacket.len); if (ret == Z_OK) { @@ -1742,31 +1823,29 @@ handle_full_packet(int tun_fd, int dns_fd, int userid) write_tun(tun_fd, out, outlen); } else { /* send the compressed(!) packet to other client */ - /*XXX START adjust indent 1 tab forward*/ - if (users[touser].conn == CONN_DNS_NULL) { - if (users[touser].outpacket.len == 0) { - start_new_outpacket(touser, - users[userid].inpacket.data, - users[userid].inpacket.len); - - /* Start sending immediately if query is waiting */ - if (users[touser].q_sendrealsoon.id != 0) - send_chunk_or_dataless(dns_fd, touser, &users[touser].q_sendrealsoon); - else if (users[touser].q.id != 0) - send_chunk_or_dataless(dns_fd, touser, &users[touser].q); + if (users[touser].conn == CONN_DNS_NULL) { + if (users[touser].outpacket.len == 0) { + start_new_outpacket(touser, + users[userid].inpacket.data, + users[userid].inpacket.len); + + /* Start sending immediately if query is waiting */ + if (users[touser].q_sendrealsoon.id != 0) + send_chunk_or_dataless(dns_fd, touser, &users[touser].q_sendrealsoon); + else if (users[touser].q.id != 0) + send_chunk_or_dataless(dns_fd, touser, &users[touser].q); #ifdef OUTPACKETQ_LEN - } else { - save_to_outpacketq(touser, - users[userid].inpacket.data, - users[userid].inpacket.len); + } else { + save_to_outpacketq(touser, + users[userid].inpacket.data, + users[userid].inpacket.len); #endif + } + } else{ /* CONN_RAW_UDP */ + send_raw(dns_fd, users[userid].inpacket.data, + users[userid].inpacket.len, touser, + RAW_HDR_CMD_DATA, &users[touser].q); } - } else{ /* CONN_RAW_UDP */ - send_raw(dns_fd, users[userid].inpacket.data, - users[userid].inpacket.len, touser, - RAW_HDR_CMD_DATA, &users[touser].q); - } - /*XXX END adjust indent 1 tab forward*/ } } else { if (debug >= 1) @@ -1782,13 +1861,14 @@ static void handle_raw_login(char *packet, int len, struct query *q, int fd, int userid) { char myhash[16]; - + if (len < 16) return; - /* can't use check_user_and_ip() since IP address will be different, + /* can't use check_authenticated_user_and_ip() since IP address will be different, so duplicate here except IP address */ if (userid < 0 || userid >= created_users) return; if (!users[userid].active || users[userid].disabled) return; + if (!users[userid].authenticated) return; if (users[userid].last_pkt + 60 < time(NULL)) return; if (debug >= 1) { @@ -1808,20 +1888,23 @@ handle_raw_login(char *packet, int len, struct query *q, int fd, int userid) /* Store remote IP number */ tempin = (struct sockaddr_in *) &(q->from); memcpy(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr)); - + /* Correct hash, reply with hash of seed - 1 */ user_set_conn_type(userid, CONN_RAW_UDP); login_calculate(myhash, 16, password, users[userid].seed - 1); send_raw(fd, myhash, 16, userid, RAW_HDR_CMD_LOGIN, q); + + users[userid].authenticated_raw = 1; } } static void handle_raw_data(char *packet, int len, struct query *q, int dns_fd, int tun_fd, int userid) { - if (check_user_and_ip(userid, q) != 0) { + if (check_authenticated_user_and_ip(userid, q) != 0) { return; } + if (!users[userid].authenticated_raw) return; /* Update query and time info for user */ users[userid].last_pkt = time(NULL); @@ -1843,9 +1926,10 @@ handle_raw_data(char *packet, int len, struct query *q, int dns_fd, int tun_fd, static void handle_raw_ping(struct query *q, int dns_fd, int userid) { - if (check_user_and_ip(userid, q) != 0) { + if (check_authenticated_user_and_ip(userid, q) != 0) { return; } + if (!users[userid].authenticated_raw) return; /* Update query and time info for user */ users[userid].last_pkt = time(NULL); @@ -1914,7 +1998,7 @@ read_dns(int fd, int tun_fd, struct query *q) /* FIXME: tun_fd is because of raw msg.msg_control = address; msg.msg_controllen = sizeof(address); msg.msg_flags = 0; - + r = recvmsg(fd, &msg, 0); #else addrlen = sizeof(struct sockaddr); @@ -1932,22 +2016,22 @@ read_dns(int fd, int tun_fd, struct query *q) /* FIXME: tun_fd is because of raw if (dns_decode(NULL, 0, q, QR_QUERY, packet, r) < 0) { return 0; } - + #ifndef WINDOWS32 - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - - if (cmsg->cmsg_level == IPPROTO_IP && - cmsg->cmsg_type == DSTADDR_SOCKOPT) { - - q->destination = *dstaddr(cmsg); + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == DSTADDR_SOCKOPT) { + + q->destination = *dstaddr(cmsg); break; - } + } } #endif return strlen(q->name); - } else if (r < 0) { + } else if (r < 0) { /* Error */ warn("read dns"); } @@ -1977,7 +2061,7 @@ write_dns_nameenc(char *buf, size_t buflen, char *data, int datalen, char downen space = MIN(0xFF, buflen) - 4 - 2; /* -1 encoding type, -3 ".xy", -2 for safety */ - memset(buf, 0, sizeof(buf)); + memset(buf, 0, buflen); if (downenc == 'S') { buf[0] = 'i'; @@ -2012,7 +2096,7 @@ write_dns_nameenc(char *buf, size_t buflen, char *data, int datalen, char downen /* Add dot (if it wasn't there already) and topdomain */ b = buf; b += strlen(buf) - 1; - if (*b != '.') + if (*b != '.') *++b = '.'; b++; @@ -2104,12 +2188,10 @@ write_dns(int fd, struct query *q, char *data, int datalen, char downenc) warnx("dns_encode doesn't fit"); return; } - + if (debug >= 2) { - struct sockaddr_in *tempin; - tempin = (struct sockaddr_in *) &(q->from); - fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes data\n", - inet_ntoa(tempin->sin_addr), q->type, q->name, datalen); + fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes data\n", + format_addr(&q->from, q->fromlen), q->type, q->name, datalen); } sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen); @@ -2122,7 +2204,7 @@ usage() { fprintf(stderr, "Usage: %s [-v] [-h] [-c] [-s] [-f] [-D] [-u user] " "[-t chrootdir] [-d device] [-m mtu] [-z context] " "[-l ip address to listen on] [-p port] [-n external ip] " - "[-b dnsport] [-P password] [-F pidfile] " + "[-b dnsport] [-P password] [-F pidfile] [-i max idle time] " "tunnel_ip[/netmask] topdomain\n", __progname); exit(2); } @@ -2156,6 +2238,7 @@ help() { fprintf(stderr, " -b port to forward normal DNS queries to (on localhost)\n"); fprintf(stderr, " -P password used for authentication (max 32 chars will be used)\n"); fprintf(stderr, " -F pidfile to write pid to a file\n"); + fprintf(stderr, " -i maximum idle time before shutting down\n"); fprintf(stderr, "tunnel_ip is the IP number of the local tunnel interface.\n"); fprintf(stderr, " /netmask sets the size of the tunnel network.\n"); fprintf(stderr, "topdomain is the FQDN that is delegated to this server.\n"); @@ -2165,7 +2248,7 @@ help() { static void version() { fprintf(stderr, "iodine IP over DNS tunneling server\n"); - fprintf(stderr, "version: 0.6.0-rc1 from 2010-02-13\n"); + fprintf(stderr, "version: 0.7.0 from 2014-06-16\n"); exit(0); } @@ -2173,7 +2256,8 @@ int main(int argc, char **argv) { extern char *__progname; - in_addr_t listen_ip; + char *listen_ip; + char *errormsg; #ifndef WINDOWS32 struct passwd *pw; #endif @@ -2186,21 +2270,29 @@ main(int argc, char **argv) int dnsd_fd; int tun_fd; - /* settings for forwarding normal DNS to + /* settings for forwarding normal DNS to * local real DNS server */ int bind_fd; int bind_enable; - + int choice; int port; int mtu; int skipipconfig; char *netsize; + 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 #ifndef WINDOWS32 pw = NULL; #endif + errormsg = NULL; username = NULL; newroot = NULL; context = NULL; @@ -2210,9 +2302,10 @@ 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; check_ip = 1; skipipconfig = 0; debug = 0; @@ -2223,7 +2316,7 @@ main(int argc, char **argv) b64 = get_base64_encoder(); b64u = get_base64u_encoder(); b128 = get_base128_encoder(); - + retval = 0; #ifdef WINDOWS32 @@ -2241,8 +2334,8 @@ main(int argc, char **argv) memset(password, 0, sizeof(password)); srand(time(NULL)); fw_query_init(); - - while ((choice = getopt(argc, argv, "vcsfhDu:t:d:m:l:p:n:b:P:z:F:")) != -1) { + + while ((choice = getopt(argc, argv, "vcsfhDu:t:d:m:l:p:n:b:P:z:F:i:")) != -1) { switch(choice) { case 'v': version(); @@ -2275,13 +2368,17 @@ 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); break; case 'n': - ns_ip = inet_addr(optarg); + if (optarg && strcmp("auto", optarg) == 0) { + ns_get_externalip = 1; + } else { + ns_ip = inet_addr(optarg); + } break; case 'b': bind_enable = 1; @@ -2289,13 +2386,16 @@ main(int argc, char **argv) break; case 'F': pidfile = optarg; - break; + break; + case 'i': + max_idle_time = atoi(optarg); + break; case 'P': strncpy(password, optarg, sizeof(password)); password[sizeof(password)-1] = 0; - + /* XXX: find better way of cleaning up ps(1) */ - memset(optarg, 0, strlen(optarg)); + memset(optarg, 0, strlen(optarg)); break; case 'z': context = optarg; @@ -2311,9 +2411,9 @@ main(int argc, char **argv) check_superuser(usage); - if (argc != 2) + if (argc != 2) usage(); - + netsize = strchr(argv[0], '/'); if (netsize) { *netsize = 0; @@ -2322,21 +2422,17 @@ main(int argc, char **argv) } my_ip = inet_addr(argv[0]); - + if (my_ip == INADDR_NONE) { warnx("Bad IP address to use inside tunnel."); usage(); } topdomain = strdup(argv[1]); - if (strlen(topdomain) <= 128) { - if(check_topdomain(topdomain)) { - warnx("Topdomain contains invalid characters."); - usage(); - } - } else { - warnx("Use a topdomain max 128 chars long."); + if(check_topdomain(topdomain, &errormsg)) { + warnx("Invalid topdomain: %s", errormsg); usage(); + /* NOTREACHED */ } if (username != NULL) { @@ -2352,20 +2448,38 @@ main(int argc, char **argv) warnx("Bad MTU given."); usage(); } - + if(port < 1 || port > 65535) { warnx("Bad port number given."); usage(); } - + + 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); + } + + if (debug) { + fprintf(stderr, "Debug level %d enabled, will stay in foreground.\n", debug); + fprintf(stderr, "Add more -D switches to set higher debug level.\n"); + foreground = 1; + } + + 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 && (listen_ip == INADDR_ANY || listen_ip == htonl(0x7f000001L))) { + 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(); @@ -2374,23 +2488,18 @@ main(int argc, char **argv) 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); - } - if (debug) { - fprintf(stderr, "Debug level %d enabled, will stay in foreground.\n", debug); - fprintf(stderr, "Add more -D switches to set higher debug level.\n"); - foreground = 1; + if (ns_get_externalip) { + struct in_addr extip; + int res = get_external_ip(&extip); + if (res) { + fprintf(stderr, "Failed to get external IP via web service.\n"); + exit(3); + } + ns_ip = extip.s_addr; + fprintf(stderr, "Using %s as external IP.\n", inet_ntoa(extip)); } - if (listen_ip == INADDR_NONE) { - warnx("Bad IP address to listen on."); - usage(); - } - if (ns_ip == INADDR_NONE) { warnx("Bad IP address to return as nameserver."); usage(); @@ -2399,7 +2508,7 @@ main(int argc, char **argv) warnx("Bad netmask (%d bits). Use 8-30 bits.", netmask); usage(); } - + if (strlen(password) == 0) { if (NULL != getenv(PASSWORD_ENV_VAR)) snprintf(password, sizeof(password), "%s", getenv(PASSWORD_ENV_VAR)); @@ -2414,33 +2523,49 @@ main(int argc, char **argv) goto cleanup0; } if (!skipipconfig) { - if (tun_setip(argv[0], users_get_first_ip(), netmask) != 0 || tun_setmtu(mtu) != 0) { + const char *other_ip = users_get_first_ip(); + if (tun_setip(argv[0], other_ip, netmask) != 0 || tun_setmtu(mtu) != 0) { retval = 1; + free((void*) other_ip); goto cleanup1; } + free((void*) other_ip); } - if ((dnsd_fd = open_dns(port, listen_ip)) == -1) { +#ifdef HAVE_SYSTEMD + nb_fds = sd_listen_fds(0); + if (nb_fds > 1) { retval = 1; - goto cleanup2; + warnx("Too many file descriptors received!\n"); + goto cleanup1; + } else if (nb_fds == 1) { + dnsd_fd = SD_LISTEN_FDS_START; + } else { +#endif + if ((dnsd_fd = open_dns(&dnsaddr, dnsaddr_len)) < 0) { + retval = 1; + goto cleanup2; + } +#ifdef HAVE_SYSTEMD } +#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; } } my_mtu = mtu; - + if (created_users < USERS) { fprintf(stderr, "Limiting to %d simultaneous users because of netmask /%d\n", created_users, netmask); } fprintf(stderr, "Listening to dns for domain %s\n", topdomain); - if (foreground == 0) + if (foreground == 0) do_detach(); - + if (pidfile != NULL) do_pidfile(pidfile); @@ -2470,8 +2595,8 @@ main(int argc, char **argv) do_setcon(context); syslog(LOG_INFO, "started, listening on port %d", port); - - tunnel(tun_fd, dnsd_fd, bind_fd); + + tunnel(tun_fd, dnsd_fd, bind_fd, max_idle_time); syslog(LOG_INFO, "stopping"); cleanup3: @@ -2479,7 +2604,7 @@ cleanup3: cleanup2: close_dns(dnsd_fd); cleanup1: - close_tun(tun_fd); + close_tun(tun_fd); cleanup0: return retval; diff --git a/jni/iodine/src/login.c b/jni/iodine/src/login.c index c8827c3..a809998 100644 --- a/jni/iodine/src/login.c +++ b/jni/iodine/src/login.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,16 +21,17 @@ #ifdef WINDOWS32 #include "windows.h" #else +#include #include #endif #include "md5.h" -/* - * Needs a 16byte array for output, and 32 bytes password +/* + * Needs a 16byte array for output, and 32 bytes password */ -void -login_calculate(char *buf, int buflen, const char *pass, int seed) +void +login_calculate(char *buf, int buflen, const char *pass, int seed) { unsigned char temp[32]; md5_state_t ctx; @@ -37,7 +39,7 @@ login_calculate(char *buf, int buflen, const char *pass, int seed) int i; int k; - if (buflen < 16) + if (buflen < 16) return; memcpy(temp, pass, 32); diff --git a/jni/iodine/src/login.h b/jni/iodine/src/login.h index 840c920..ebea25c 100644 --- a/jni/iodine/src/login.h +++ b/jni/iodine/src/login.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/src/md5.h b/jni/iodine/src/md5.h index 698c995..3baa4dc 100644 --- a/jni/iodine/src/md5.h +++ b/jni/iodine/src/md5.h @@ -71,7 +71,7 @@ typedef struct md5_state_s { } md5_state_t; #ifdef __cplusplus -extern "C" +extern "C" { #endif diff --git a/jni/iodine/src/osflags b/jni/iodine/src/osflags index 787ffaa..9eda8f0 100755 --- a/jni/iodine/src/osflags +++ b/jni/iodine/src/osflags @@ -17,17 +17,26 @@ link) echo '-lws2_32 -liphlpapi'; ;; Linux) - [ -e /usr/include/selinux/selinux.h ] && echo '-lselinux'; + FLAGS=""; + [ -e /usr/include/selinux/selinux.h ] && FLAGS="$FLAGS -lselinux"; + [ -e /usr/include/systemd/sd-daemon.h ] && FLAGS="$FLAGS -lsystemd-daemon"; + echo $FLAGS; ;; esac ;; cflags) case $1 in + windows32) + echo '-DWINVER=0x0501'; + ;; BeOS) echo '-Dsocklen_t=int'; ;; Linux) - [ -e /usr/include/selinux/selinux.h ] && echo '-DHAVE_SETCON'; + FLAGS="-D_GNU_SOURCE" + [ -e /usr/include/selinux/selinux.h ] && FLAGS="$FLAGS -DHAVE_SETCON"; + [ -e /usr/include/systemd/sd-daemon.h ] && FLAGS="$FLAGS -DHAVE_SYSTEMD"; + echo $FLAGS; ;; esac ;; diff --git a/jni/iodine/src/read.c b/jni/iodine/src/read.c index ff40382..a2dcd96 100644 --- a/jni/iodine/src/read.c +++ b/jni/iodine/src/read.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -60,7 +61,7 @@ readname_loop(char *packet, int packetlen, char **src, char *dst, size_t length, c--; } - + if (len >= length - 1) { break; /* We used up all space */ } @@ -84,15 +85,15 @@ readname(char *packet, int packetlen, char **src, char *dst, size_t length) } int -readshort(char *packet, char **src, short *dst) +readshort(char *packet, char **src, unsigned short *dst) { unsigned char *p; p = (unsigned char *) *src; *dst = (p[0] << 8) | p[1]; - (*src) += sizeof(short); - return sizeof(short); + (*src) += sizeof(unsigned short); + return sizeof(unsigned short); } int @@ -103,8 +104,8 @@ readlong(char *packet, char **src, uint32_t *dst) p = (unsigned char *) *src; - *dst = ((uint32_t)p[0] << 24) - | ((uint32_t)p[1] << 16) + *dst = ((uint32_t)p[0] << 24) + | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | ((uint32_t)p[3]); @@ -115,9 +116,6 @@ readlong(char *packet, char **src, uint32_t *dst) int readdata(char *packet, char **src, char *dst, size_t len) { - if (len < 0) - return 0; - memcpy(dst, *src, len); (*src) += len; @@ -165,7 +163,7 @@ putname(char **buf, size_t buflen, const char *host) h = strdup(host); left = buflen; p = *buf; - + word = strtok(h, "."); while(word) { if (strlen(word) > 63 || strlen(word) > left) { @@ -232,11 +230,8 @@ putlong(char **dst, uint32_t value) int putdata(char **dst, char *data, size_t len) { - if (len < 0) - return 0; - memcpy(*dst, data, len); - + (*dst) += len; return len; } diff --git a/jni/iodine/src/read.h b/jni/iodine/src/read.h index b33f3bb..2aac355 100644 --- a/jni/iodine/src/read.h +++ b/jni/iodine/src/read.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,7 +19,7 @@ #define _READ_H_ int readname(char *, int, char **, char *, size_t); -int readshort(char *, char **, short *); +int readshort(char *, char **, unsigned short *); int readlong(char *, char **, uint32_t *); int readdata(char *, char **, char *, size_t); int readtxtbin(char *, char **, size_t, char *, size_t); diff --git a/jni/iodine/src/tun.c b/jni/iodine/src/tun.c index eb52959..f8a2fd4 100644 --- a/jni/iodine/src/tun.c +++ b/jni/iodine/src/tun.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,13 +25,16 @@ #include #include +#ifndef IFCONFIGPATH +#define IFCONFIGPATH "PATH=/sbin:/bin " +#endif + #ifdef WINDOWS32 -#include -#include #include "windows.h" +#include -HANDLE dev_handle; -struct tun_data data; +static HANDLE dev_handle; +static struct tun_data data; static void get_name(char *ifname, int namelen, char *dev_name); @@ -47,8 +51,8 @@ static void get_name(char *ifname, int namelen, char *dev_name); #define NET_CFG_INST_ID "NetCfgInstanceId" #else #include -#include #include +#include #define TUN_MAX_TRY 50 #endif @@ -56,22 +60,25 @@ static void get_name(char *ifname, int namelen, char *dev_name); #include "tun.h" #include "common.h" -char if_name[250]; +static char if_name[250]; -#ifndef WINDOWS32 #ifdef LINUX #include #include #include -int -open_tun(const char *tun_device) +int +open_tun(const char *tun_device) { int i; int tun_fd; struct ifreq ifreq; +#ifdef ANDROID + char *tunnel = "/dev/tun"; +#else char *tunnel = "/dev/net/tun"; +#endif if ((tun_fd = open(tunnel, O_RDWR)) < 0) { warn("open_tun: %s: %s", tunnel, strerror(errno)); @@ -80,7 +87,7 @@ open_tun(const char *tun_device) memset(&ifreq, 0, sizeof(ifreq)); - ifreq.ifr_flags = IFF_TUN; + ifreq.ifr_flags = IFF_TUN; if (tun_device != NULL) { strncpy(ifreq.ifr_name, tun_device, IFNAMSIZ); @@ -90,6 +97,7 @@ open_tun(const char *tun_device) if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) { fprintf(stderr, "Opened %s\n", ifreq.ifr_name); + fd_set_close_on_exec(tun_fd); return tun_fd; } @@ -104,6 +112,7 @@ open_tun(const char *tun_device) if (ioctl(tun_fd, TUNSETIFF, (void *) &ifreq) != -1) { fprintf(stderr, "Opened %s\n", ifreq.ifr_name); snprintf(if_name, sizeof(if_name), "dns%d", i); + fd_set_close_on_exec(tun_fd); return tun_fd; } @@ -119,49 +128,8 @@ open_tun(const char *tun_device) return -1; } -#else /* BSD */ - -int -open_tun(const char *tun_device) -{ - int i; - int tun_fd; - char tun_name[50]; - - if (tun_device != NULL) { - snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device); - strncpy(if_name, tun_device, sizeof(if_name)); - if_name[sizeof(if_name)-1] = '\0'; - - if ((tun_fd = open(tun_name, O_RDWR)) < 0) { - warn("open_tun: %s: %s", tun_name, strerror(errno)); - return -1; - } - - fprintf(stderr, "Opened %s\n", tun_name); - return tun_fd; - } else { - for (i = 0; i < TUN_MAX_TRY; i++) { - snprintf(tun_name, sizeof(tun_name), "/dev/tun%d", i); - - if ((tun_fd = open(tun_name, O_RDWR)) >= 0) { - fprintf(stderr, "Opened %s\n", tun_name); - snprintf(if_name, sizeof(if_name), "tun%d", i); - return tun_fd; - } - - if (errno == ENOENT) - break; - } - - warn("open_tun: Failed to open tunneling device"); - } - - return -1; -} +#elif WINDOWS32 -#endif /* !LINUX */ -#else /* WINDOWS32 */ static void get_device(char *device, int device_len, const char *wanted_dev) { @@ -176,7 +144,7 @@ get_device(char *device, int device_len, const char *wanted_dev) warnx("Error opening registry key " TAP_ADAPTER_KEY ); return; } - + while (TRUE) { char name[256]; char unit[256]; @@ -214,7 +182,7 @@ get_device(char *device, int device_len, const char *wanted_dev) strncmp(TAP_VERSION_ID_0901, component, strlen(TAP_VERSION_ID_0901)) == 0) { /* We found a TAP32 device, get its NetCfgInstanceId */ char iid_string[256] = NET_CFG_INST_ID; - + status = RegQueryValueEx(device_key, iid_string, NULL, &datatype, (LPBYTE) device, (DWORD *) &device_len); if (status != ERROR_SUCCESS || datatype != REG_SZ) { warnx("Error reading registry key %s\\%s on TAP device", unit, iid_string); @@ -280,7 +248,7 @@ DWORD WINAPI tun_reader(LPVOID arg) OVERLAPPED olpd; int sock; - sock = open_dns(0, INADDR_ANY); + sock = open_dns_from_host("127.0.0.1", 0, AF_INET, 0); olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -291,21 +259,22 @@ DWORD WINAPI tun_reader(LPVOID arg) if (!res) { 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)); + res = sendto(sock, buf, len, 0, (struct sockaddr*) &(tun->addr), + tun->addrlen); } } return 0; } -int -open_tun(const char *tun_device) +int +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)); @@ -319,7 +288,7 @@ open_tun(const char *tun_device) } return -1; } - + fprintf(stderr, "Opening device %s\n", if_name); snprintf(tapfile, sizeof(tapfile), "%s%s.tap", TAP_DEVICE_SPACE, adapter); dev_handle = CreateFile(tapfile, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, NULL); @@ -330,34 +299,115 @@ open_tun(const char *tun_device) /* Use a UDP connection to forward packets from tun, * so we can still use select() in main code. - * A thread does blocking reads on tun device and + * 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; } -#endif -void -close_tun(int tun_fd) +#else /* BSD and friends */ + +int +open_tun(const char *tun_device) +{ + int i; + int tun_fd; + char tun_name[50]; + + if (tun_device != NULL) { + snprintf(tun_name, sizeof(tun_name), "/dev/%s", tun_device); + strncpy(if_name, tun_device, sizeof(if_name)); + if_name[sizeof(if_name)-1] = '\0'; + + if ((tun_fd = open(tun_name, O_RDWR)) < 0) { + warn("open_tun: %s: %s", tun_name, strerror(errno)); + return -1; + } + + fprintf(stderr, "Opened %s\n", tun_name); + fd_set_close_on_exec(tun_fd); + return tun_fd; + } else { + for (i = 0; i < TUN_MAX_TRY; i++) { + snprintf(tun_name, sizeof(tun_name), "/dev/tun%d", i); + + if ((tun_fd = open(tun_name, O_RDWR)) >= 0) { + fprintf(stderr, "Opened %s\n", tun_name); + snprintf(if_name, sizeof(if_name), "tun%d", i); + fd_set_close_on_exec(tun_fd); + return tun_fd; + } + + if (errno == ENOENT) + break; + } + + warn("open_tun: Failed to open tunneling device"); + } + + return -1; +} + +#endif + +void +close_tun(int tun_fd) { if (tun_fd >= 0) close(tun_fd); } -int -write_tun(int tun_fd, char *data, size_t len) +#ifdef WINDOWS32 +int +write_tun(int tun_fd, char *data, size_t len) { -#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32) || defined(__ANDROID__) + DWORD written; + DWORD res; + OVERLAPPED olpd; + + data += 4; + len -= 4; + + olpd.Offset = 0; + olpd.OffsetHigh = 0; + olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + res = WriteFile(dev_handle, data, len, &written, &olpd); + if (!res && GetLastError() == ERROR_IO_PENDING) { + WaitForSingleObject(olpd.hEvent, INFINITE); + res = GetOverlappedResult(dev_handle, &olpd, &written, FALSE); + if (written != len) { + return -1; + } + } + return 0; +} + +ssize_t +read_tun(int tun_fd, char *buf, size_t len) +{ + int bytes; + memset(buf, 0, 4); + + bytes = recv(tun_fd, buf + 4, len - 4, 0); + if (bytes < 0) { + return bytes; + } else { + return bytes + 4; + } +} +#else +int +write_tun(int tun_fd, char *data, size_t len) +{ +#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(__ANDROID__) data += 4; len -= 4; #else /* !FREEBSD/DARWIN */ @@ -374,47 +424,22 @@ write_tun(int tun_fd, char *data, size_t len) #endif /* !LINUX */ #endif /* FREEBSD */ -#ifndef WINDOWS32 if (write(tun_fd, data, len) != len) { warn("write_tun"); return 1; } -#else /* WINDOWS32 */ - { - DWORD written; - DWORD res; - OVERLAPPED olpd; - - olpd.Offset = 0; - olpd.OffsetHigh = 0; - olpd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - res = WriteFile(dev_handle, data, len, &written, &olpd); - if (!res && GetLastError() == ERROR_IO_PENDING) { - WaitForSingleObject(olpd.hEvent, INFINITE); - res = GetOverlappedResult(dev_handle, &olpd, &written, FALSE); - if (written != len) { - return -1; - } - } - } -#endif return 0; } ssize_t -read_tun(int tun_fd, char *buf, size_t len) +read_tun(int tun_fd, char *buf, size_t len) { -#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(WINDOWS32) || defined(__ANDROID__) - /* FreeBSD/Darwin/NetBSD/Android-VPN has no header */ +#if defined (FREEBSD) || defined (DARWIN) || defined(NETBSD) || defined(__ANDROID__) + /* FreeBSD/Darwin/NetBSD/Android-SDK has no header */ int bytes; memset(buf, 0, 4); -#ifdef WINDOWS32 - /* Windows needs recv() since it is local UDP socket */ - bytes = recv(tun_fd, buf + 4, len - 4, 0); -#else - /* The other need read() because fd is not a socket */ + bytes = read(tun_fd, buf + 4, len - 4); -#endif /*WINDOWS32*/ if (bytes < 0) { return bytes; } else { @@ -424,9 +449,10 @@ read_tun(int tun_fd, char *buf, size_t len) return read(tun_fd, buf, len); #endif /* !FREEBSD */ } +#endif int -tun_setip(const char *ip, const char *remoteip, int netbits) +tun_setip(const char *ip, const char *other_ip, int netbits) { char cmdline[512]; int netmask; @@ -440,6 +466,11 @@ tun_setip(const char *ip, const char *remoteip, int netbits) DWORD ipdata[3]; struct in_addr addr; DWORD len; +#else + const char *display_ip; +#ifndef LINUX + struct in_addr netip; +#endif #endif netmask = 0; @@ -461,32 +492,36 @@ tun_setip(const char *ip, const char *remoteip, int netbits) free(tun_config_android.remoteip); } tun_config_android.ip = strdup(ip); - tun_config_android.remoteip = strdup(remoteip); + tun_config_android.remoteip = strdup(other_ip); tun_config_android.netbits = netbits; return 0; #elif !defined(WINDOWS32) - snprintf(cmdline, sizeof(cmdline), - "/sbin/ifconfig %s %s %s netmask %s", +# ifdef FREEBSD + display_ip = other_ip; /* FreeBSD wants other IP as second IP */ +# else + display_ip = ip; +# endif + snprintf(cmdline, sizeof(cmdline), + IFCONFIGPATH "ifconfig %s %s %s netmask %s", if_name, ip, -#ifdef FREEBSD - remoteip, /* FreeBSD wants other IP as second IP */ -#else - ip, -#endif + display_ip, inet_ntoa(net)); - + fprintf(stderr, "Setting IP of %s to %s\n", if_name, ip); #ifndef LINUX + netip.s_addr = inet_addr(ip); + netip.s_addr = netip.s_addr & net.s_addr; r = system(cmdline); if(r != 0) { return r; } else { + snprintf(cmdline, sizeof(cmdline), "/sbin/route add %s/%d %s", - ip, netbits, ip); + inet_ntoa(netip), netbits, ip); } - fprintf(stderr, "Adding route %s/%d to %s\n", ip, netbits, ip); + fprintf(stderr, "Adding route %s/%d to %s\n", inet_ntoa(netip), netbits, ip); #endif return system(cmdline); #else /* WINDOWS32 */ @@ -494,13 +529,13 @@ tun_setip(const char *ip, const char *remoteip, int netbits) /* Set device as connected */ fprintf(stderr, "Enabling interface '%s'\n", if_name); status = 1; - r = DeviceIoControl(dev_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, + r = DeviceIoControl(dev_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL); if (!r) { fprintf(stderr, "Failed to enable interface\n"); return -1; } - + if (inet_aton(ip, &addr)) { ipdata[0] = (DWORD) addr.s_addr; /* local ip addr */ ipdata[1] = net.s_addr & ipdata[0]; /* network addr */ @@ -510,7 +545,7 @@ tun_setip(const char *ip, const char *remoteip, int netbits) } /* Tell ip/networkaddr/netmask to device for arp use */ - r = DeviceIoControl(dev_handle, TAP_IOCTL_CONFIG_TUN, &ipdata, + r = DeviceIoControl(dev_handle, TAP_IOCTL_CONFIG_TUN, &ipdata, sizeof(ipdata), &ipdata, sizeof(ipdata), &len, NULL); if (!r) { fprintf(stderr, "Failed to set interface in TUN mode\n"); @@ -525,7 +560,7 @@ tun_setip(const char *ip, const char *remoteip, int netbits) #endif } -int +int tun_setmtu(const unsigned mtu) { #ifdef __ANDROID__ @@ -535,11 +570,11 @@ tun_setmtu(const unsigned mtu) char cmdline[512]; if (mtu > 200 && mtu <= 1500) { - snprintf(cmdline, sizeof(cmdline), - "/sbin/ifconfig %s mtu %u", + snprintf(cmdline, sizeof(cmdline), + IFCONFIGPATH "ifconfig %s mtu %u", if_name, mtu); - + fprintf(stderr, "Setting MTU of %s to %u\n", if_name, mtu); return system(cmdline); } else { diff --git a/jni/iodine/src/tun.h b/jni/iodine/src/tun.h index 397e7a9..83a6171 100644 --- a/jni/iodine/src/tun.h +++ b/jni/iodine/src/tun.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/src/user.c b/jni/iodine/src/user.c index dfe9c36..0dc95db 100644 --- a/jni/iodine/src/user.c +++ b/jni/iodine/src/user.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,7 +34,8 @@ #include "encoding.h" #include "user.h" -struct user users[USERS]; +struct tun_user *users; +unsigned usercount; int init_users(in_addr_t my_ip, int netbits) @@ -41,7 +43,6 @@ init_users(in_addr_t my_ip, int netbits) int i; int skip = 0; char newip[16]; - int created_users = 0; int maxusers; @@ -57,9 +58,10 @@ init_users(in_addr_t my_ip, int netbits) ipstart.s_addr = my_ip & net.s_addr; maxusers = (1 << (32-netbits)) - 3; /* 3: Net addr, broadcast addr, iodined addr */ - - memset(users, 0, USERS * sizeof(struct user)); - for (i = 0; i < USERS; i++) { + usercount = MIN(maxusers, USERS); + + users = calloc(usercount, sizeof(struct tun_user)); + for (i = 0; i < usercount; i++) { in_addr_t ip; users[i].id = i; snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1); @@ -72,17 +74,14 @@ init_users(in_addr_t my_ip, int netbits) } users[i].tun_ip = ip; net.s_addr = ip; - if (maxusers-- < 1) { - users[i].disabled = 1; - } else { - users[i].disabled = 0; - created_users++; - } + users[i].disabled = 0; + users[i].authenticated = 0; + users[i].authenticated_raw = 0; users[i].active = 0; /* Rest is reset on login ('V' packet) */ } - return created_users; + return usercount; } const char* @@ -90,7 +89,7 @@ users_get_first_ip() { struct in_addr ip; ip.s_addr = users[0].tun_ip; - return inet_ntoa(ip); + return strdup(inet_ntoa(ip)); } int @@ -100,14 +99,14 @@ users_waiting_on_reply() int i; ret = 0; - for (i = 0; i < USERS; i++) { - if (users[i].active && !users[i].disabled && + for (i = 0; i < usercount; i++) { + if (users[i].active && !users[i].disabled && users[i].last_pkt + 60 > time(NULL) && users[i].q.id != 0 && users[i].conn == CONN_DNS_NULL) { ret++; } } - + return ret; } @@ -118,8 +117,10 @@ find_user_by_ip(uint32_t ip) int i; ret = -1; - for (i = 0; i < USERS; i++) { - if (users[i].active && !users[i].disabled && + for (i = 0; i < usercount; i++) { + if (users[i].active && + users[i].authenticated && + !users[i].disabled && users[i].last_pkt + 60 > time(NULL) && ip == users[i].tun_ip) { ret = i; @@ -143,11 +144,11 @@ all_users_waiting_to_send() ret = 1; now = time(NULL); - for (i = 0; i < USERS; i++) { + for (i = 0; i < usercount; i++) { if (users[i].active && !users[i].disabled && users[i].last_pkt + 60 > now && - ((users[i].conn == CONN_RAW_UDP) || - ((users[i].conn == CONN_DNS_NULL) + ((users[i].conn == CONN_RAW_UDP) || + ((users[i].conn == CONN_DNS_NULL) #ifdef OUTPACKETQ_LEN && users[i].outpacketq_filled < 1 #else @@ -167,10 +168,12 @@ find_available_user() { int ret = -1; int i; - for (i = 0; i < USERS; i++) { + for (i = 0; i < usercount; i++) { /* Not used at all or not used in one minute */ if ((!users[i].active || users[i].last_pkt + 60 < time(NULL)) && !users[i].disabled) { users[i].active = 1; + users[i].authenticated = 0; + users[i].authenticated_raw = 0; users[i].last_pkt = time(NULL); users[i].fragsize = 4096; users[i].conn = CONN_DNS_NULL; @@ -184,21 +187,21 @@ find_available_user() void user_switch_codec(int userid, struct encoder *enc) { - if (userid < 0 || userid >= USERS) + if (userid < 0 || userid >= usercount) return; - + users[userid].encoder = enc; } void user_set_conn_type(int userid, enum connection c) { - if (userid < 0 || userid >= USERS) + if (userid < 0 || userid >= usercount) return; if (c < 0 || c >= CONN_MAX) return; - + users[userid].conn = c; } - + diff --git a/jni/iodine/src/user.h b/jni/iodine/src/user.h index 51a6092..76fc54b 100644 --- a/jni/iodine/src/user.h +++ b/jni/iodine/src/user.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -33,9 +34,11 @@ #define QMEMDATA_LEN 15 /* Max advisable: 36/2 = 18. Total mem usage: QMEMDATA_LEN * USERS * 6 bytes */ -struct user { +struct tun_user { char id; int active; + int authenticated; + int authenticated_raw; int disabled; time_t last_pkt; int seed; @@ -73,7 +76,7 @@ struct user { #endif }; -extern struct user users[USERS]; +extern struct tun_user *users; int init_users(in_addr_t, int); const char* users_get_first_ip(); diff --git a/jni/iodine/src/util.c b/jni/iodine/src/util.c index bc5fc8d..f4a538e 100644 --- a/jni/iodine/src/util.c +++ b/jni/iodine/src/util.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,12 +26,22 @@ get_resolvconf_addr() #ifndef WINDOWS32 char buf[80]; FILE *fp; - +#ifdef ANDROID + fp = popen("getprop net.dns1", "r"); + if (fp == NULL) + err(1, "getprop net.dns1 failed"); + if (fgets(buf, sizeof(buf), fp) == NULL) + err(1, "read getprop net.dns1 failed"); + if (sscanf(buf, "%15s", addr) == 1) + rv = addr; + pclose(fp); +#else + rv = NULL; - if ((fp = fopen("/etc/resolv.conf", "r")) == NULL) + if ((fp = fopen("/etc/resolv.conf", "r")) == NULL) err(1, "/etc/resolv.conf"); - + while (feof(fp) == 0) { fgets(buf, sizeof(buf), fp); @@ -39,8 +50,9 @@ get_resolvconf_addr() break; } } - + fclose(fp); +#endif #else /* !WINDOWS32 */ FIXED_INFO *fixed_info; ULONG buflen; @@ -67,3 +79,15 @@ get_resolvconf_addr() return rv; } +#ifdef OPENBSD +void +socket_setrtable(int fd, int rtable) +{ +#ifdef SO_RTABLE + if (setsockopt (fd, IPPROTO_IP, SO_RTABLE, &rtable, sizeof(rtable)) == -1) + err(1, "Failed to set routing table %d", rtable); +#else + fprintf(stderr, "Routing domain support was not available at compile time.\n"); +#endif +} +#endif diff --git a/jni/iodine/src/util.h b/jni/iodine/src/util.h index f514139..6872077 100644 --- a/jni/iodine/src/util.h +++ b/jni/iodine/src/util.h @@ -2,5 +2,6 @@ #define __UTIL_H__ char *get_resolvconf_addr(); +void socket_setrtable(int fd, int rtable); #endif diff --git a/jni/iodine/src/version.h b/jni/iodine/src/version.h index 1561b9e..2ab00ff 100644 --- a/jni/iodine/src/version.h +++ b/jni/iodine/src/version.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/jni/iodine/src/windows.h b/jni/iodine/src/windows.h index 7e0e16c..c665a60 100644 --- a/jni/iodine/src/windows.h +++ b/jni/iodine/src/windows.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2006-2009 Bjorn Andersson , Erik Ekman + * Copyright (c) 2006-2014 Erik Ekman , + * 2006-2009 Bjorn Andersson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,9 +20,9 @@ typedef unsigned int in_addr_t; +#include #include #include -#include #include #include @@ -94,7 +95,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 -- cgit v1.2.1