#11 basic support for multiple users. some work left

This commit is contained in:
Erik Ekman 2007-02-11 00:50:02 +00:00
parent 7994402806
commit 8d766e2857
4 changed files with 194 additions and 81 deletions

View file

@ -43,9 +43,16 @@ struct query {
}; };
struct user { struct user {
int id; char id;
int active;
time_t last_pkt;
int seed;
in_addr_t tun_ip;
struct sockaddr host; struct sockaddr host;
int addrlen; int addrlen;
struct query q;
struct packet inpacket;
struct packet outpacket;
}; };
int open_dns(int, in_addr_t); int open_dns(int, in_addr_t);

View file

@ -54,6 +54,7 @@ uint16_t rand_seed;
/* Current IP packet */ /* Current IP packet */
static char activepacket[4096]; static char activepacket[4096];
static char userid;
static int lastlen; static int lastlen;
static int packetpos; static int packetpos;
static int packetlen; static int packetlen;
@ -223,10 +224,12 @@ tunnel(int tun_fd, int dns_fd)
static void static void
send_chunk(int fd) send_chunk(int fd)
{ {
char hex[] = "0123456789ABCDEF";
char packet[4096]; char packet[4096];
struct query q; struct query q;
char buf[4096]; char buf[4096];
int avail; int avail;
int code;
char *p; char *p;
int len; int len;
@ -238,11 +241,14 @@ send_chunk(int fd)
avail = packetlen - packetpos; avail = packetlen - packetpos;
lastlen = dns_build_hostname(buf + 1, sizeof(buf) - 1, p, avail, topdomain); lastlen = dns_build_hostname(buf + 1, sizeof(buf) - 1, p, avail, topdomain);
if (lastlen == avail)
buf[0] = '1';
else
buf[0] = '0';
if (lastlen == avail)
code = 1;
else
code = 0;
code |= (userid << 1);
buf[0] = hex[code];
len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, buf, strlen(buf)); len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, buf, strlen(buf));
sendto(fd, packet, len, 0, (struct sockaddr*)&peer, sizeof(peer)); sendto(fd, packet, len, 0, (struct sockaddr*)&peer, sizeof(peer));
@ -251,13 +257,14 @@ send_chunk(int fd)
void void
send_login(int fd, char *login, int len) send_login(int fd, char *login, int len)
{ {
char data[18]; char data[19];
memset(data, 0, sizeof(data)); 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 >> 8) & 0xff;
data[17] = (rand_seed >> 0) & 0xff; data[18] = (rand_seed >> 0) & 0xff;
rand_seed++; rand_seed++;
@ -267,7 +274,7 @@ send_login(int fd, char *login, int len)
static void static void
send_ping(int fd) send_ping(int fd)
{ {
char data[2]; char data[3];
if (is_sending()) { if (is_sending()) {
lastlen = 0; lastlen = 0;
@ -275,8 +282,9 @@ send_ping(int fd)
packetlen = 0; packetlen = 0;
} }
data[0] = (rand_seed >> 8) & 0xff; data[0] = userid;
data[1] = (rand_seed >> 0) & 0xff; data[1] = (rand_seed >> 8) & 0xff;
data[2] = (rand_seed >> 0) & 0xff;
rand_seed++; rand_seed++;
@ -336,7 +344,7 @@ handshake(int dns_fd)
continue; continue;
} }
if (read >= 8) { if (read >= 9) {
payload = (((in[4] & 0xff) << 24) | payload = (((in[4] & 0xff) << 24) |
((in[5] & 0xff) << 16) | ((in[5] & 0xff) << 16) |
((in[6] & 0xff) << 8) | ((in[6] & 0xff) << 8) |
@ -344,13 +352,17 @@ handshake(int dns_fd)
if (strncmp("VACK", in, 4) == 0) { if (strncmp("VACK", in, 4) == 0) {
seed = payload; 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; goto perform_login;
} else { } else if (strncmp("VACK", in, 4) == 0) {
errx(1, "you run 0x%08x, server runs 0x%08x. giving up\n", errx(1, "you run 0x%08x, server runs 0x%08x. giving up\n",
VERSION, payload); VERSION, payload);
/* NOTREACHED */ /* NOTREACHED */
} else if (strncmp("VFUL", in, 4) == 0) {
errx(1, "server full, all %d slots are taken. try again later\n", payload);
/* NOTREACHED */
} }
} else } else
warnx("did not receive proper login challenge\n"); warnx("did not receive proper login challenge\n");

View file

@ -30,6 +30,7 @@
#include <pwd.h> #include <pwd.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <netinet/ip.h>
#include <zlib.h> #include <zlib.h>
#include "common.h" #include "common.h"
@ -41,15 +42,10 @@
int running = 1; int running = 1;
struct packet packetbuf;
struct packet outpacket;
int outid;
char *topdomain; char *topdomain;
struct query q; #define USERS 8
struct user users[USERS];
struct user u;
char password[33]; char password[33];
int my_mtu; int my_mtu;
@ -64,34 +60,96 @@ sigint(int sig)
running = 0; 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 static int
tunnel_tun(int tun_fd, int dns_fd) tunnel_tun(int tun_fd, int dns_fd)
{ {
unsigned long outlen; unsigned long outlen;
struct iphdr *header;
char out[64*1024]; char out[64*1024];
char in[64*1024]; char in[64*1024];
int userid;
int read; int read;
if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0) if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0)
return 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); outlen = sizeof(out);
compress2((uint8_t*)out, &outlen, (uint8_t*)in, read, 9); compress2((uint8_t*)out, &outlen, (uint8_t*)in, read, 9);
memcpy(outpacket.data, out, outlen); memcpy(users[userid].outpacket.data, out, outlen);
outpacket.len = outlen; users[userid].outpacket.len = outlen;
return outlen; return outlen;
} }
typedef enum { typedef enum {
VERSION_ACK, VERSION_ACK,
VERSION_NACK VERSION_NACK,
VERSION_FULL
} version_ack_t; } version_ack_t;
static void 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) { switch (ack) {
case VERSION_ACK: case VERSION_ACK:
@ -100,31 +158,37 @@ send_version_response(int fd, version_ack_t ack, uint32_t payload)
case VERSION_NACK: case VERSION_NACK:
strncpy(out, "VNAK", sizeof(out)); strncpy(out, "VNAK", sizeof(out));
break; break;
case VERSION_FULL:
strncpy(out, "VFUL", sizeof(out));
break;
} }
out[4] = ((payload >> 24) & 0xff); out[4] = ((payload >> 24) & 0xff);
out[5] = ((payload >> 16) & 0xff); out[5] = ((payload >> 16) & 0xff);
out[6] = ((payload >> 8) & 0xff); out[6] = ((payload >> 8) & 0xff);
out[7] = ((payload) & 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 static int
tunnel_dns(int tun_fd, int dns_fd) tunnel_dns(int tun_fd, int dns_fd)
{ {
struct in_addr clientip; struct in_addr tempip;
struct query q;
unsigned long outlen; unsigned long outlen;
struct in_addr myip;
char logindata[16]; char logindata[16];
char out[64*1024]; char out[64*1024];
char in[64*1024]; char in[64*1024];
static int seed;
char *tmp[2]; char *tmp[2];
int userid;
int version; int version;
int read; int read;
int code; int code;
userid = -1;
if ((read = read_dns(dns_fd, &q, in, sizeof(in))) <= 0) if ((read = read_dns(dns_fd, &q, in, sizeof(in))) <= 0)
return 0; return 0;
@ -139,34 +203,48 @@ tunnel_dns(int tun_fd, int dns_fd)
((in[4] & 0xff))); ((in[4] & 0xff)));
if (version == VERSION) { if (version == VERSION) {
seed = rand(); userid = find_available_user();
if (userid >= 0) {
send_version_response(dns_fd, VERSION_ACK, seed); 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 { } else {
send_version_response(dns_fd, VERSION_NACK, VERSION); /* No space for another user */
send_version_response(dns_fd, VERSION_FULL, USERS, NULL);
} }
} else { } 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, NULL);
} }
} else if(in[0] == 'L' || in[0] == 'l') { } else if(in[0] == 'L' || in[0] == 'l') {
/* Login phase, handle auth */ /* 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)) { if (q.fromlen != users[userid].addrlen ||
memcmp(&(users[userid].host), &(q.from), q.fromlen) != 0) {
write_dns(dns_fd, &q, "BADIP", 5);
} else {
if (read >= 18 && (memcmp(logindata, in+2, 16) == 0)) {
/* Login ok, send ip/mtu info */ /* 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)); tempip.s_addr = my_ip;
tmp[1] = strdup(inet_ntoa(clientip)); 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", read = snprintf(out, sizeof(out), "%s-%s-%d",
tmp[0], tmp[1], my_mtu); 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); write_dns(dns_fd, &q, out, read);
q.id = 0; q.id = 0;
@ -175,6 +253,14 @@ tunnel_dns(int tun_fd, int dns_fd)
} else { } else {
write_dns(dns_fd, &q, "LNAK", 4); 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') } else if((in[0] >= '0' && in[0] <= '9')
|| (in[0] >= 'a' && in[0] <= 'f') || (in[0] >= 'a' && in[0] <= 'f')
|| (in[0] >= 'A' && in[0] <= 'F')) { || (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')) if ((in[0] >= 'A' && in[0] <= 'F'))
code = in[0] - 'A' + 10; 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 */ /* Check sending ip number */
if (q.fromlen != u.addrlen || if (q.fromlen != users[userid].addrlen ||
memcmp(&(u.host), &(q.from), q.fromlen) != 0) { memcmp(&(users[userid].host), &(q.from), q.fromlen) != 0) {
write_dns(dns_fd, &q, "BADIP", 5); write_dns(dns_fd, &q, "BADIP", 5);
} else { } else {
memcpy(packetbuf.data + packetbuf.offset, in + 1, read - 1); memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, in + 1, read - 1);
packetbuf.len += read - 1; users[userid].inpacket.len += read - 1;
packetbuf.offset += read - 1; users[userid].inpacket.offset += read - 1;
if (code & 1) { if (code & 1) {
outlen = sizeof(out); outlen = sizeof(out);
uncompress((uint8_t*)out, &outlen, 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); 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 && /* userid must be set for a reply to be sent */
memcmp(&(u.host), &(q.from), q.fromlen) == 0 && if (userid >= 0 && userid < USERS && q.fromlen == users[userid].addrlen &&
outpacket.len > 0) { memcmp(&(users[userid].host), &(q.from), q.fromlen) == 0 &&
users[userid].outpacket.len > 0) {
write_dns(dns_fd, &q, outpacket.data, outpacket.len); write_dns(dns_fd, &q, users[userid].outpacket.data, users[userid].outpacket.len);
outpacket.len = 0; users[userid].outpacket.len = 0;
q.id = 0; q.id = 0;
} }
@ -223,18 +317,19 @@ tunnel(int tun_fd, int dns_fd)
struct timeval tv; struct timeval tv;
fd_set fds; fd_set fds;
int i; int i;
int j;
while (running) { while (running) {
if (q.id != 0) { //if (q.id != 0) {
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = 5000; tv.tv_usec = 5000;
} else { /*} else {
tv.tv_sec = 1; tv.tv_sec = 1;
tv.tv_usec = 0; tv.tv_usec = 0;
} }*/
FD_ZERO(&fds); FD_ZERO(&fds);
if(outpacket.len == 0) //if(outpacket.len == 0) TODO fix this
FD_SET(tun_fd, &fds); FD_SET(tun_fd, &fds);
FD_SET(dns_fd, &fds); FD_SET(dns_fd, &fds);
@ -247,10 +342,12 @@ tunnel(int tun_fd, int dns_fd)
} }
if (i==0) { if (i==0) {
if (q.id != 0) { for (j = 0; j < USERS; j++) {
write_dns(dns_fd, &q, outpacket.data, outpacket.len); if (users[j].q.id != 0) {
outpacket.len = 0; write_dns(dns_fd, &(users[j].q), users[j].outpacket.data, users[j].outpacket.len);
q.id = 0; users[j].outpacket.len = 0;
users[j].q.id = 0;
}
} }
} else { } else {
if(FD_ISSET(tun_fd, &fds)) { if(FD_ISSET(tun_fd, &fds)) {
@ -370,10 +467,6 @@ main(int argc, char **argv)
listen_ip = INADDR_ANY; listen_ip = INADDR_ANY;
port = 53; port = 53;
packetbuf.len = 0;
packetbuf.offset = 0;
outpacket.len = 0;
q.id = 0;
memset(password, 0, 33); memset(password, 0, 33);
srand(time(NULL)); srand(time(NULL));
@ -466,6 +559,7 @@ main(int argc, char **argv)
my_ip = inet_addr(argv[0]); my_ip = inet_addr(argv[0]);
my_mtu = mtu; my_mtu = mtu;
init_users();
printf("Listening to dns for domain %s\n", argv[1]); printf("Listening to dns for domain %s\n", argv[1]);

View file

@ -19,7 +19,7 @@
// This is the version of the network protocol // This is the version of the network protocol
// It is usually equal to the latest iodine version number // It is usually equal to the latest iodine version number
#define VERSION 0x00000305 #define VERSION 0x00000400
#endif /* _VERSION_H_ */ #endif /* _VERSION_H_ */