summaryrefslogtreecommitdiff
path: root/jni/iodine/src/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'jni/iodine/src/common.c')
-rw-r--r--jni/iodine/src/common.c262
1 files changed, 191 insertions, 71 deletions
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 <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+/* Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@kryo.se>
* Copyright (c) 2007 Albert Lee <trisk@acm.jhu.edu>.
*
* Permission to use, copy, modify, and distribute this software for any
@@ -39,9 +40,11 @@
#endif
#include <termios.h>
#include <err.h>
-#include <arpa/inet.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include <syslog.h>
+#include <sys/socket.h>
+#include <netdb.h>
#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
+