diff --git a/src/Android.mk b/src/Android.mk new file mode 100644 index 0000000..8f7c729 --- /dev/null +++ b/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/src/android_dns.h b/src/android_dns.h new file mode 100644 index 0000000..dafd8ec --- /dev/null +++ b/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/src/client.c b/src/client.c index 0036b0e..9f5dfe7 100644 --- a/src/client.c +++ b/src/client.c @@ -31,6 +31,9 @@ #include "windows.h" #include #else +#ifdef ANDROID +#include "android_dns.h" +#endif #include #ifdef DARWIN #define BIND_8_COMPAT @@ -148,6 +151,32 @@ client_get_conn() void client_set_nameserver(const char *cp, int port) { +#ifdef ANDROID + struct addrinfo hints, *result, *p; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + + char sport[10]; + sprintf(sport, "%d", port); + + getaddrinfo(cp, sport, &hints, &result); + if (result == NULL) + errx(1, "Cannot resolve %s:%s (no network?)", cp, sport); + else { + for (p = result;p != NULL; p = p->ai_next) { + if (p->ai_family == AF_INET) { /* IPv4 */ + struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; + memset(&nameserv, 0, sizeof(nameserv)); + nameserv.sin_family = AF_INET; + nameserv.sin_port = htons(port); + nameserv.sin_addr = ipv4->sin_addr; + freeaddrinfo(result); + return; + } + } + freeaddrinfo(result); + } +#endif struct in_addr addr; if (inet_aton(cp, &addr) != 1) { diff --git a/src/common.c b/src/common.c index 4ab93d9..143fe34 100644 --- a/src/common.c +++ b/src/common.c @@ -54,7 +54,7 @@ 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__) +#if !defined(ANDROID) && !defined(WINDOWS32) && !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__) static int daemon(int nochdir, int noclose) { int fd, i; @@ -276,13 +276,15 @@ check_topdomain(char *str) return 0; } -#ifdef 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,11 +293,13 @@ 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()); } else { fprintf(stderr, ": %s\n", strerror(errno)); } +#endif va_end(list); } diff --git a/src/common.h b/src/common.h index 8dbbfbd..4ef25c5 100644 --- a/src/common.h +++ b/src/common.h @@ -119,8 +119,10 @@ void read_password(char*, size_t); int check_topdomain(char *); -#ifdef 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, ...); diff --git a/src/dns.c b/src/dns.c index fb2bcaf..eb29403 100644 --- a/src/dns.c +++ b/src/dns.c @@ -25,6 +25,9 @@ #ifdef WINDOWS32 #include "windows.h" #else +#ifdef ANDROID +#include "android_dns.h" +#endif #include #ifdef DARWIN #define BIND_8_COMPAT diff --git a/src/iodined.c b/src/iodined.c index b5265ac..3a15ba1 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -1655,7 +1655,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; @@ -1707,7 +1707,7 @@ tunnel(int tun_fd, int dns_fd, int bind_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 && diff --git a/src/tun.c b/src/tun.c index 02c85af..504451f 100644 --- a/src/tun.c +++ b/src/tun.c @@ -24,6 +24,10 @@ #include #include +#ifndef IFCONFIGPATH +#define IFCONFIGPATH "/sbin/" +#endif + #ifdef WINDOWS32 #include #include @@ -71,7 +75,11 @@ 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)); @@ -455,7 +463,7 @@ tun_setip(const char *ip, const char *other_ip, int netbits) } #ifndef WINDOWS32 snprintf(cmdline, sizeof(cmdline), - "/sbin/ifconfig %s %s %s netmask %s", + IFCONFIGPATH "ifconfig %s %s %s netmask %s", if_name, ip, #ifdef FREEBSD @@ -522,7 +530,7 @@ tun_setmtu(const unsigned mtu) if (mtu > 200 && mtu <= 1500) { snprintf(cmdline, sizeof(cmdline), - "/sbin/ifconfig %s mtu %u", + IFCONFIGPATH "ifconfig %s mtu %u", if_name, mtu); diff --git a/src/user.c b/src/user.c index cded79f..feeda3d 100644 --- a/src/user.c +++ b/src/user.c @@ -33,7 +33,8 @@ #include "encoding.h" #include "user.h" -struct user users[USERS]; +struct user *users; +unsigned usercount; int init_users(in_addr_t my_ip, int netbits) @@ -41,7 +42,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 +57,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 */ + usercount = MIN(maxusers, USERS); - memset(users, 0, USERS * sizeof(struct user)); - for (i = 0; i < USERS; i++) { + users = calloc(usercount, sizeof(struct 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 +73,12 @@ 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].active = 0; /* Rest is reset on login ('V' packet) */ } - return created_users; + return usercount; } const char* @@ -100,7 +96,7 @@ users_waiting_on_reply() int i; ret = 0; - for (i = 0; i < USERS; i++) { + 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) { @@ -118,7 +114,7 @@ find_user_by_ip(uint32_t ip) int i; ret = -1; - for (i = 0; i < USERS; i++) { + for (i = 0; i < usercount; i++) { if (users[i].active && !users[i].disabled && users[i].last_pkt + 60 > time(NULL) && ip == users[i].tun_ip) { @@ -143,7 +139,7 @@ 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) || @@ -167,7 +163,7 @@ 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; @@ -184,7 +180,7 @@ 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; @@ -193,7 +189,7 @@ user_switch_codec(int userid, struct 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) diff --git a/src/user.h b/src/user.h index 51a6092..34411cf 100644 --- a/src/user.h +++ b/src/user.h @@ -73,7 +73,7 @@ struct user { #endif }; -extern struct user users[USERS]; +extern struct user *users; int init_users(in_addr_t, int); const char* users_get_first_ip(); diff --git a/src/util.c b/src/util.c index 2515dd2..7a365ac 100644 --- a/src/util.c +++ b/src/util.c @@ -25,6 +25,16 @@ 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; @@ -41,6 +51,7 @@ get_resolvconf_addr() } fclose(fp); +#endif #else /* !WINDOWS32 */ FIXED_INFO *fixed_info; ULONG buflen; diff --git a/tests/user.c b/tests/user.c index afd61ca..58c3db8 100644 --- a/tests/user.c +++ b/tests/user.c @@ -32,10 +32,11 @@ START_TEST(test_init_users) in_addr_t ip; char givenip[16]; int i; + int count; ip = inet_addr("127.0.0.1"); - init_users(ip, 27); - for (i = 0; i < USERS; i++) { + count = init_users(ip, 27); + for (i = 0; i < count; i++) { fail_unless(users[i].id == i); fail_unless(users[i].q.id == 0); fail_unless(users[i].inpacket.len == 0);