From 8d766e28574aff36f58439cff75a22722058c33d Mon Sep 17 00:00:00 2001 From: Erik Ekman Date: Sun, 11 Feb 2007 00:50:02 +0000 Subject: [PATCH] #11 basic support for multiple users. some work left --- src/common.h | 9 +- src/iodine.c | 36 +++++--- src/iodined.c | 228 +++++++++++++++++++++++++++++++++++--------------- src/version.h | 2 +- 4 files changed, 194 insertions(+), 81 deletions(-) diff --git a/src/common.h b/src/common.h index b58e7d2..8c95767 100644 --- a/src/common.h +++ b/src/common.h @@ -43,9 +43,16 @@ struct query { }; struct user { - int id; + char id; + int active; + time_t last_pkt; + int seed; + in_addr_t tun_ip; struct sockaddr host; int addrlen; + struct query q; + struct packet inpacket; + struct packet outpacket; }; int open_dns(int, in_addr_t); diff --git a/src/iodine.c b/src/iodine.c index 6d4a99d..7437a15 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -54,6 +54,7 @@ uint16_t rand_seed; /* Current IP packet */ static char activepacket[4096]; +static char userid; static int lastlen; static int packetpos; static int packetlen; @@ -223,10 +224,12 @@ tunnel(int tun_fd, int dns_fd) static void send_chunk(int fd) { + char hex[] = "0123456789ABCDEF"; char packet[4096]; struct query q; char buf[4096]; int avail; + int code; char *p; int len; @@ -238,11 +241,14 @@ send_chunk(int fd) avail = packetlen - packetpos; lastlen = dns_build_hostname(buf + 1, sizeof(buf) - 1, p, avail, topdomain); + if (lastlen == avail) - buf[0] = '1'; + code = 1; else - buf[0] = '0'; + code = 0; + code |= (userid << 1); + buf[0] = hex[code]; len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, buf, strlen(buf)); sendto(fd, packet, len, 0, (struct sockaddr*)&peer, sizeof(peer)); @@ -251,13 +257,14 @@ send_chunk(int fd) void send_login(int fd, char *login, int len) { - char data[18]; + char data[19]; memset(data, 0, sizeof(data)); - memcpy(data, login, MIN(len, 16)); + data[0] = userid; + memcpy(&data[1], login, MIN(len, 16)); - data[16] = (rand_seed >> 8) & 0xff; - data[17] = (rand_seed >> 0) & 0xff; + data[17] = (rand_seed >> 8) & 0xff; + data[18] = (rand_seed >> 0) & 0xff; rand_seed++; @@ -267,7 +274,7 @@ send_login(int fd, char *login, int len) static void send_ping(int fd) { - char data[2]; + char data[3]; if (is_sending()) { lastlen = 0; @@ -275,8 +282,9 @@ send_ping(int fd) packetlen = 0; } - data[0] = (rand_seed >> 8) & 0xff; - data[1] = (rand_seed >> 0) & 0xff; + data[0] = userid; + data[1] = (rand_seed >> 8) & 0xff; + data[2] = (rand_seed >> 0) & 0xff; rand_seed++; @@ -336,7 +344,7 @@ handshake(int dns_fd) continue; } - if (read >= 8) { + if (read >= 9) { payload = (((in[4] & 0xff) << 24) | ((in[5] & 0xff) << 16) | ((in[6] & 0xff) << 8) | @@ -344,13 +352,17 @@ handshake(int dns_fd) if (strncmp("VACK", in, 4) == 0) { seed = payload; + userid = in[8]; - printf("Version ok, both running 0x%08x\n", VERSION); + printf("Version ok, both running 0x%08x. You are user #%d\n", VERSION, userid); goto perform_login; - } else { + } else if (strncmp("VACK", in, 4) == 0) { errx(1, "you run 0x%08x, server runs 0x%08x. giving up\n", VERSION, payload); /* NOTREACHED */ + } else if (strncmp("VFUL", in, 4) == 0) { + errx(1, "server full, all %d slots are taken. try again later\n", payload); + /* NOTREACHED */ } } else warnx("did not receive proper login challenge\n"); diff --git a/src/iodined.c b/src/iodined.c index e1ef88b..61419cb 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "common.h" @@ -41,15 +42,10 @@ int running = 1; -struct packet packetbuf; -struct packet outpacket; -int outid; - char *topdomain; -struct query q; - -struct user u; +#define USERS 8 +struct user users[USERS]; char password[33]; int my_mtu; @@ -64,34 +60,96 @@ sigint(int sig) running = 0; } +static void +init_users() +{ + int i; + char newip[16]; + + memset(users, 0, USERS * sizeof(struct user)); + for (i = 0; i < USERS; i++) { + users[i].id = i; + snprintf(newip, sizeof(newip), "0.0.0.%d", i + 1); + users[i].tun_ip = my_ip + inet_addr(newip);; + users[i].inpacket.len = 0; + users[i].inpacket.offset = 0; + users[i].outpacket.len = 0; + users[i].q.id = 0; + } +} + +static int +find_user_by_ip(uint32_t ip) +{ + int ret = -1; + int i; + + for (i = 0; i < USERS; i++) { + /* Not used at all or not used in one minute */ + if (users[i].active && users[i].last_pkt + 60 > time(NULL) && + ip == users[i].tun_ip) { + ret = i; + break; + } + } + return ret; +} + +static int +find_available_user() +{ + int ret = -1; + int i; + + for (i = 0; i < USERS; i++) { + /* Not used at all or not used in one minute */ + if (!users[i].active || users[i].last_pkt + 60 < time(NULL)) { + users[i].active = 1; + users[i].last_pkt = time(NULL); + ret = i; + break; + } + } + return ret; +} + static int tunnel_tun(int tun_fd, int dns_fd) { unsigned long outlen; + struct iphdr *header; char out[64*1024]; char in[64*1024]; + int userid; int read; 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 iphdr*) (in + 4); + userid = find_user_by_ip(header->daddr); + if (userid < 0) + return 0; outlen = sizeof(out); compress2((uint8_t*)out, &outlen, (uint8_t*)in, read, 9); - memcpy(outpacket.data, out, outlen); - outpacket.len = outlen; + memcpy(users[userid].outpacket.data, out, outlen); + users[userid].outpacket.len = outlen; return outlen; } typedef enum { VERSION_ACK, - VERSION_NACK + VERSION_NACK, + VERSION_FULL } version_ack_t; static void -send_version_response(int fd, version_ack_t ack, uint32_t payload) +send_version_response(int fd, version_ack_t ack, uint32_t payload, struct user *u) { - char out[8]; + char out[9]; switch (ack) { case VERSION_ACK: @@ -100,31 +158,37 @@ send_version_response(int fd, version_ack_t ack, uint32_t payload) case VERSION_NACK: strncpy(out, "VNAK", sizeof(out)); break; + case VERSION_FULL: + strncpy(out, "VFUL", sizeof(out)); + break; } out[4] = ((payload >> 24) & 0xff); out[5] = ((payload >> 16) & 0xff); out[6] = ((payload >> 8) & 0xff); out[7] = ((payload) & 0xff); + out[8] = u->id; - write_dns(fd, &q, out, 8); + + write_dns(fd, &u->q, out, sizeof(out)); } static int tunnel_dns(int tun_fd, int dns_fd) { - struct in_addr clientip; + struct in_addr tempip; + struct query q; unsigned long outlen; - struct in_addr myip; char logindata[16]; char out[64*1024]; char in[64*1024]; - static int seed; char *tmp[2]; + int userid; int version; int read; int code; + userid = -1; if ((read = read_dns(dns_fd, &q, in, sizeof(in))) <= 0) return 0; @@ -139,41 +203,63 @@ tunnel_dns(int tun_fd, int dns_fd) ((in[4] & 0xff))); if (version == VERSION) { - seed = rand(); - - send_version_response(dns_fd, VERSION_ACK, seed); + userid = find_available_user(); + if (userid >= 0) { + users[userid].seed = rand(); + memcpy(&(users[userid].host), &(q.from), q.fromlen); + memcpy(&(users[userid].q), &q, sizeof(struct query)); + users[userid].addrlen = q.fromlen; + send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]); + } else { + /* No space for another user */ + send_version_response(dns_fd, VERSION_FULL, USERS, NULL); + } } else { - send_version_response(dns_fd, VERSION_NACK, VERSION); + send_version_response(dns_fd, VERSION_NACK, VERSION, NULL); } } else { - send_version_response(dns_fd, VERSION_NACK, VERSION); + send_version_response(dns_fd, VERSION_NACK, VERSION, NULL); } } else if(in[0] == 'L' || in[0] == 'l') { /* Login phase, handle auth */ - login_calculate(logindata, 16, password, seed); + userid = in[1]; + if (userid < 0 || userid >= USERS) { + write_dns(dns_fd, &q, "BADIP", 5); + return 0; /* illegal id */ + } + users[userid].last_pkt = time(NULL); + login_calculate(logindata, 16, password, users[userid].seed); - if (read >= 17 && (memcmp(logindata, in+1, 16) == 0)) { - /* Login ok, send ip/mtu info */ - myip.s_addr = my_ip; - clientip.s_addr = my_ip + inet_addr("0.0.0.1"); - - tmp[0] = strdup(inet_ntoa(myip)); - tmp[1] = strdup(inet_ntoa(clientip)); - - read = snprintf(out, sizeof(out), "%s-%s-%d", - tmp[0], tmp[1], my_mtu); - - /* Store user ip */ - memcpy(&(u.host), &(q.from), q.fromlen); - u.addrlen = q.fromlen; - - write_dns(dns_fd, &q, out, read); - q.id = 0; - - free(tmp[1]); - free(tmp[0]); + if (q.fromlen != users[userid].addrlen || + memcmp(&(users[userid].host), &(q.from), q.fromlen) != 0) { + write_dns(dns_fd, &q, "BADIP", 5); } else { - write_dns(dns_fd, &q, "LNAK", 4); + if (read >= 18 && (memcmp(logindata, in+2, 16) == 0)) { + /* Login ok, send ip/mtu 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", + tmp[0], tmp[1], my_mtu); + + write_dns(dns_fd, &q, out, read); + q.id = 0; + + free(tmp[1]); + free(tmp[0]); + } else { + write_dns(dns_fd, &q, "LNAK", 4); + } + } + } else if(in[0] == 'P' || in[0] == 'p') { + /* Ping packet, store userid */ + userid = in[1]; + if (userid < 0 || userid >= USERS) { + write_dns(dns_fd, &q, "BADIP", 5); + return 0; /* illegal id */ } } else if((in[0] >= '0' && in[0] <= '9') || (in[0] >= 'a' && in[0] <= 'f') @@ -185,32 +271,40 @@ tunnel_dns(int tun_fd, int dns_fd) if ((in[0] >= 'A' && in[0] <= 'F')) code = in[0] - 'A' + 10; + userid = code >> 1; + if (userid < 0 || userid >= USERS) { + write_dns(dns_fd, &q, "BADIP", 5); + return 0; /* illegal id */ + } + users[userid].last_pkt = time(NULL); + /* Check sending ip number */ - if (q.fromlen != u.addrlen || - memcmp(&(u.host), &(q.from), q.fromlen) != 0) { + if (q.fromlen != users[userid].addrlen || + memcmp(&(users[userid].host), &(q.from), q.fromlen) != 0) { write_dns(dns_fd, &q, "BADIP", 5); } else { - memcpy(packetbuf.data + packetbuf.offset, in + 1, read - 1); - packetbuf.len += read - 1; - packetbuf.offset += read - 1; + memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, in + 1, read - 1); + users[userid].inpacket.len += read - 1; + users[userid].inpacket.offset += read - 1; if (code & 1) { outlen = sizeof(out); uncompress((uint8_t*)out, &outlen, - (uint8_t*)packetbuf.data, packetbuf.len); + (uint8_t*)users[userid].inpacket.data, users[userid].inpacket.len); write_tun(tun_fd, out, outlen); - packetbuf.len = packetbuf.offset = 0; + users[userid].inpacket.len = users[userid].inpacket.offset = 0; } } } - if (q.fromlen == u.addrlen && - memcmp(&(u.host), &(q.from), q.fromlen) == 0 && - outpacket.len > 0) { + /* userid must be set for a reply to be sent */ + if (userid >= 0 && userid < USERS && q.fromlen == users[userid].addrlen && + memcmp(&(users[userid].host), &(q.from), q.fromlen) == 0 && + users[userid].outpacket.len > 0) { - write_dns(dns_fd, &q, outpacket.data, outpacket.len); - outpacket.len = 0; + write_dns(dns_fd, &q, users[userid].outpacket.data, users[userid].outpacket.len); + users[userid].outpacket.len = 0; q.id = 0; } @@ -223,18 +317,19 @@ tunnel(int tun_fd, int dns_fd) struct timeval tv; fd_set fds; int i; + int j; while (running) { - if (q.id != 0) { + //if (q.id != 0) { tv.tv_sec = 0; tv.tv_usec = 5000; - } else { + /*} else { tv.tv_sec = 1; tv.tv_usec = 0; - } + }*/ FD_ZERO(&fds); - if(outpacket.len == 0) + //if(outpacket.len == 0) TODO fix this FD_SET(tun_fd, &fds); FD_SET(dns_fd, &fds); @@ -247,10 +342,12 @@ tunnel(int tun_fd, int dns_fd) } if (i==0) { - if (q.id != 0) { - write_dns(dns_fd, &q, outpacket.data, outpacket.len); - outpacket.len = 0; - q.id = 0; + for (j = 0; j < USERS; j++) { + if (users[j].q.id != 0) { + write_dns(dns_fd, &(users[j].q), users[j].outpacket.data, users[j].outpacket.len); + users[j].outpacket.len = 0; + users[j].q.id = 0; + } } } else { if(FD_ISSET(tun_fd, &fds)) { @@ -370,10 +467,6 @@ main(int argc, char **argv) listen_ip = INADDR_ANY; port = 53; - packetbuf.len = 0; - packetbuf.offset = 0; - outpacket.len = 0; - q.id = 0; memset(password, 0, 33); srand(time(NULL)); @@ -466,6 +559,7 @@ main(int argc, char **argv) my_ip = inet_addr(argv[0]); my_mtu = mtu; + init_users(); printf("Listening to dns for domain %s\n", argv[1]); diff --git a/src/version.h b/src/version.h index 2b9e2e8..9ce306e 100644 --- a/src/version.h +++ b/src/version.h @@ -19,7 +19,7 @@ // This is the version of the network protocol // It is usually equal to the latest iodine version number -#define VERSION 0x00000305 +#define VERSION 0x00000400 #endif /* _VERSION_H_ */