#36, upstream traffic now sent in raw mode

This commit is contained in:
Erik Ekman 2009-08-06 19:48:55 +00:00
parent e2c8ac3985
commit 5d3b502ec6
5 changed files with 183 additions and 80 deletions

View File

@ -21,8 +21,13 @@
#define RAW_HDR_LEN 4 #define RAW_HDR_LEN 4
#define RAW_HDR_IDENT_LEN 3 #define RAW_HDR_IDENT_LEN 3
#define RAW_HDR_CMD 3 #define RAW_HDR_CMD 3
#define RAW_HDR_CMD_LOGIN 0x01 #define RAW_HDR_CMD_LOGIN 0x10
#define RAW_HDR_CMD_DATA 0x02 #define RAW_HDR_CMD_DATA 0x20
#define RAW_HDR_CMD_MASK 0xF0
#define RAW_HDR_USR_MASK 0x0F
#define RAW_HDR_GET_CMD(x) ((x)[RAW_HDR_CMD] & RAW_HDR_CMD_MASK)
#define RAW_HDR_GET_USR(x) ((x)[RAW_HDR_CMD] & RAW_HDR_USR_MASK)
extern const unsigned char raw_header[RAW_HDR_LEN]; extern const unsigned char raw_header[RAW_HDR_LEN];
#ifdef WINDOWS32 #ifdef WINDOWS32
@ -85,6 +90,12 @@ struct query {
int fromlen; int fromlen;
}; };
enum connection {
CONN_RAW_UDP,
CONN_DNS_NULL,
CONN_MAX
};
void check_superuser(void (*usage_fn)(void)); void check_superuser(void (*usage_fn)(void));
int open_dns(int, in_addr_t); int open_dns(int, in_addr_t);
void close_dns(int); void close_dns(int);

View File

@ -60,6 +60,7 @@ WSADATA wsa_data;
static void send_ping(int fd); static void send_ping(int fd);
static void send_chunk(int fd); static void send_chunk(int fd);
static void send_raw_data(int fd);
static int build_hostname(char *buf, size_t buflen, static int build_hostname(char *buf, size_t buflen,
const char *data, const size_t datalen, const char *data, const size_t datalen,
const char *topdomain, struct encoder *encoder); const char *topdomain, struct encoder *encoder);
@ -94,6 +95,9 @@ static struct encoder *b32;
* Defaults to Base32, can be changed after handshake */ * Defaults to Base32, can be changed after handshake */
static struct encoder *dataenc; static struct encoder *dataenc;
/* My connection mode */
static enum connection conn;
#if !defined(BSD) && !defined(__GLIBC__) #if !defined(BSD) && !defined(__GLIBC__)
static char *__progname; static char *__progname;
#endif #endif
@ -120,7 +124,7 @@ send_query(int fd, char *hostname)
} }
static void static void
send_raw(int fd, char *buf, int buflen, int cmd) send_raw(int fd, char *buf, int buflen, int user, int cmd)
{ {
char packet[4096]; char packet[4096];
int len; int len;
@ -131,7 +135,7 @@ send_raw(int fd, char *buf, int buflen, int cmd)
memcpy(&packet[RAW_HDR_LEN], buf, len); memcpy(&packet[RAW_HDR_LEN], buf, len);
len += RAW_HDR_LEN; len += RAW_HDR_LEN;
packet[RAW_HDR_CMD] = cmd; packet[RAW_HDR_CMD] = cmd | (user & 0x0F);
sendto(fd, packet, len, 0, (struct sockaddr*)&raw_serv, sizeof(raw_serv)); sendto(fd, packet, len, 0, (struct sockaddr*)&raw_serv, sizeof(raw_serv));
} }
@ -263,7 +267,11 @@ tunnel_tun(int tun_fd, int dns_fd)
outpkt.seqno++; outpkt.seqno++;
outpkt.fragment = 0; outpkt.fragment = 0;
send_chunk(dns_fd); if (conn == CONN_DNS_NULL) {
send_chunk(dns_fd);
} else {
send_raw_data(dns_fd);
}
return read; return read;
} }
@ -327,7 +335,7 @@ tunnel(int tun_fd, int dns_fd)
FD_ZERO(&fds); FD_ZERO(&fds);
if (!is_sending()) { if ((!is_sending()) || conn == CONN_RAW_UDP) {
FD_SET(tun_fd, &fds); FD_SET(tun_fd, &fds);
} }
FD_SET(dns_fd, &fds); FD_SET(dns_fd, &fds);
@ -340,7 +348,7 @@ tunnel(int tun_fd, int dns_fd)
if (i < 0) if (i < 0)
err(1, "select"); err(1, "select");
if (i == 0) /* timeout */ if (i == 0 && conn == CONN_DNS_NULL) /* timeout */
send_ping(dns_fd); send_ping(dns_fd);
else { else {
if (FD_ISSET(tun_fd, &fds)) { if (FD_ISSET(tun_fd, &fds)) {
@ -357,6 +365,12 @@ tunnel(int tun_fd, int dns_fd)
return rv; return rv;
} }
static void
send_raw_data(int dns_fd)
{
send_raw(dns_fd, outpkt.data, outpkt.len, userid, RAW_HDR_CMD_DATA);
}
static void static void
send_chunk(int fd) send_chunk(int fd)
{ {
@ -507,11 +521,10 @@ send_ip_request(int fd, int userid)
static void static void
send_raw_udp_login(int dns_fd, int userid, int seed) send_raw_udp_login(int dns_fd, int userid, int seed)
{ {
char buf[17]; char buf[16];
login_calculate(buf, 16, password, seed + 1); login_calculate(buf, 16, password, seed + 1);
buf[16] = userid;
send_raw(dns_fd, buf, sizeof(buf), RAW_HDR_CMD_LOGIN); send_raw(dns_fd, buf, sizeof(buf), userid, RAW_HDR_CMD_LOGIN);
} }
static void static void
@ -715,7 +728,7 @@ handshake_raw_udp(int dns_fd, int seed)
if (!remoteaddr) { if (!remoteaddr) {
fprintf(stderr, " failed to get IP.\n"); fprintf(stderr, " failed to get IP.\n");
return 1; return 0;
} }
fprintf(stderr, " at %s: ", inet_ntoa(server)); fprintf(stderr, " at %s: ", inet_ntoa(server));
fflush(stderr); fflush(stderr);
@ -743,16 +756,15 @@ handshake_raw_udp(int dns_fd, int seed)
if(r > 0) { if(r > 0) {
/* recv() needed for windows, dont change to read() */ /* recv() needed for windows, dont change to read() */
len = recv(dns_fd, in, sizeof(in), 0); len = recv(dns_fd, in, sizeof(in), 0);
if (len >= (17 + RAW_HDR_LEN)) { if (len >= (16 + RAW_HDR_LEN)) {
char hash[16]; char hash[16];
login_calculate(hash, 16, password, seed - 1); login_calculate(hash, 16, password, seed - 1);
if (memcmp(in, raw_header, RAW_HDR_IDENT_LEN) == 0 if (memcmp(in, raw_header, RAW_HDR_IDENT_LEN) == 0
&& in[RAW_HDR_CMD] == RAW_HDR_CMD_LOGIN && RAW_HDR_GET_CMD(in) == RAW_HDR_CMD_LOGIN
&& memcmp(&in[RAW_HDR_LEN], hash, sizeof(hash)) == 0 && memcmp(&in[RAW_HDR_LEN], hash, sizeof(hash)) == 0) {
&& in[16 + RAW_HDR_LEN] == userid) {
fprintf(stderr, "OK\n"); fprintf(stderr, "OK\n");
return 0; return 1;
} }
} }
} }
@ -761,7 +773,7 @@ handshake_raw_udp(int dns_fd, int seed)
} }
fprintf(stderr, "failed\n"); fprintf(stderr, "failed\n");
return 1; return 0;
} }
static int static int
@ -1016,22 +1028,24 @@ handshake(int dns_fd, int autodetect_frag_size, int fragsize)
return r; return r;
} }
handshake_raw_udp(dns_fd, seed); if (handshake_raw_udp(dns_fd, seed)) {
conn = CONN_RAW_UDP;
} else {
case_preserved = handshake_case_check(dns_fd);
case_preserved = handshake_case_check(dns_fd); if (case_preserved) {
handshake_switch_codec(dns_fd);
if (case_preserved) {
handshake_switch_codec(dns_fd);
}
if (autodetect_frag_size) {
fragsize = handshake_autoprobe_fragsize(dns_fd);
if (!fragsize) {
return 1;
} }
}
handshake_set_fragsize(dns_fd, fragsize); if (autodetect_frag_size) {
fragsize = handshake_autoprobe_fragsize(dns_fd);
if (!fragsize) {
return 1;
}
}
handshake_set_fragsize(dns_fd, fragsize);
}
return 0; return 0;
} }
@ -1178,6 +1192,7 @@ main(int argc, char **argv)
b32 = get_base32_encoder(); b32 = get_base32_encoder();
dataenc = get_base32_encoder(); dataenc = get_base32_encoder();
conn = CONN_DNS_NULL;
retval = 0; retval = 0;
@ -1312,7 +1327,11 @@ main(int argc, char **argv)
goto cleanup2; goto cleanup2;
} }
fprintf(stderr, "Sending queries for %s to %s\n", topdomain, nameserv_addr); if (conn == CONN_DNS_NULL) {
fprintf(stderr, "Sending queries for %s to %s\n", topdomain, nameserv_addr);
} else {
fprintf(stderr, "Sending raw traffic directly to %s\n", inet_ntoa(raw_serv.sin_addr));
}
if (foreground == 0) if (foreground == 0)
do_detach(); do_detach();

View File

@ -85,8 +85,9 @@ static int debug;
static char *__progname; static char *__progname;
#endif #endif
static int read_dns(int, struct query *); static int read_dns(int, int, struct query *);
static void write_dns(int, struct query *, char *, int); static void write_dns(int, struct query *, char *, int);
static void handle_full_packet(int, int);
static void static void
sigint(int sig) sigint(int sig)
@ -295,15 +296,12 @@ static void
handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
{ {
struct in_addr tempip; struct in_addr tempip;
struct ip *hdr;
unsigned long outlen;
char in[512]; char in[512];
char logindata[16]; char logindata[16];
char out[64*1024]; char out[64*1024];
char unpacked[64*1024]; char unpacked[64*1024];
char *tmp[2]; char *tmp[2];
int userid; int userid;
int touser;
int version; int version;
int code; int code;
int read; int read;
@ -589,30 +587,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
} }
if (lastfrag & 1) { /* packet is complete */ if (lastfrag & 1) { /* packet is complete */
int ret; handle_full_packet(tun_fd, userid);
outlen = sizeof(out);
ret = uncompress((uint8_t*)out, &outlen,
(uint8_t*)users[userid].inpacket.data, users[userid].inpacket.len);
if (ret == Z_OK) {
hdr = (struct ip*) (out + 4);
touser = find_user_by_ip(hdr->ip_dst.s_addr);
if (touser == -1) {
/* send the uncompressed packet to tun device */
write_tun(tun_fd, out, outlen);
} else {
/* send the compressed packet to other client
* if another packet is queued, throw away this one. TODO build queue */
if (users[touser].outpacket.len == 0) {
memcpy(users[touser].outpacket.data, users[userid].inpacket.data, users[userid].inpacket.len);
users[touser].outpacket.len = users[userid].inpacket.len;
}
}
} else {
fprintf(stderr, "Discarded data, uncompress() result: %d\n", ret);
}
users[userid].inpacket.len = users[userid].inpacket.offset = 0;
} }
/* Update seqno and maybe send immediate response packet */ /* Update seqno and maybe send immediate response packet */
update_downstream_seqno(dns_fd, userid, dn_seq, dn_frag); update_downstream_seqno(dns_fd, userid, dn_seq, dn_frag);
@ -730,7 +705,7 @@ tunnel_dns(int tun_fd, int dns_fd, int bind_fd)
int domain_len; int domain_len;
int inside_topdomain; int inside_topdomain;
if ((read = read_dns(dns_fd, &q)) <= 0) if ((read = read_dns(dns_fd, tun_fd, &q)) <= 0)
return 0; return 0;
if (debug >= 2) { if (debug >= 2) {
@ -820,15 +795,15 @@ tunnel(int tun_fd, int dns_fd, int bind_fd)
} }
} }
} else { } else {
if(FD_ISSET(tun_fd, &fds)) { if (FD_ISSET(tun_fd, &fds)) {
tunnel_tun(tun_fd, dns_fd); tunnel_tun(tun_fd, dns_fd);
continue; continue;
} }
if(FD_ISSET(dns_fd, &fds)) { if (FD_ISSET(dns_fd, &fds)) {
tunnel_dns(tun_fd, dns_fd, bind_fd); tunnel_dns(tun_fd, dns_fd, bind_fd);
continue; continue;
} }
if(FD_ISSET(bind_fd, &fds)) { if (FD_ISSET(bind_fd, &fds)) {
tunnel_bind(bind_fd, dns_fd); tunnel_bind(bind_fd, dns_fd);
continue; continue;
} }
@ -839,7 +814,42 @@ tunnel(int tun_fd, int dns_fd, int bind_fd)
} }
static void static void
send_raw(int fd, char *buf, int buflen, int cmd, struct query *q) handle_full_packet(int tun_fd, int userid)
{
unsigned long outlen;
char out[64*1024];
int touser;
int ret;
outlen = sizeof(out);
ret = uncompress((uint8_t*)out, &outlen,
(uint8_t*)users[userid].inpacket.data, users[userid].inpacket.len);
if (ret == Z_OK) {
struct ip *hdr;
hdr = (struct ip*) (out + 4);
touser = find_user_by_ip(hdr->ip_dst.s_addr);
if (touser == -1) {
/* send the uncompressed packet to tun device */
write_tun(tun_fd, out, outlen);
} else {
/* send the compressed packet to other client
* if another packet is queued, throw away this one. TODO build queue */
if (users[touser].outpacket.len == 0) {
memcpy(users[touser].outpacket.data, users[userid].inpacket.data, users[userid].inpacket.len);
users[touser].outpacket.len = users[userid].inpacket.len;
}
}
} else {
fprintf(stderr, "Discarded data, uncompress() result: %d\n", ret);
}
users[userid].inpacket.len = users[userid].inpacket.offset = 0;
}
static void
send_raw(int fd, char *buf, int buflen, int user, int cmd, struct query *q)
{ {
char packet[4096]; char packet[4096];
int len; int len;
@ -850,51 +860,96 @@ send_raw(int fd, char *buf, int buflen, int cmd, struct query *q)
memcpy(&packet[RAW_HDR_LEN], buf, len); memcpy(&packet[RAW_HDR_LEN], buf, len);
len += RAW_HDR_LEN; len += RAW_HDR_LEN;
packet[RAW_HDR_CMD] = cmd; packet[RAW_HDR_CMD] = cmd | (user & 0x0F);
sendto(fd, packet, len, 0, &q->from, q->fromlen); sendto(fd, packet, len, 0, &q->from, q->fromlen);
} }
static void static void
handle_raw_login(char *packet, int len, struct query *q, int fd) handle_raw_login(char *packet, int len, struct query *q, int fd, int userid)
{ {
int userid;
char myhash[16]; char myhash[16];
if (len < 17) return; if (len < 16) return;
userid = packet[16];
if (userid < 0 || userid > created_users) return; if (userid < 0 || userid > created_users) return;
if (!users[userid].active) return; if (!users[userid].active) return;
/* User sends hash of seed + 1 */
login_calculate(myhash, 16, password, users[userid].seed + 1); login_calculate(myhash, 16, password, users[userid].seed + 1);
if (memcmp(packet, myhash, 16) == 0) { if (memcmp(packet, myhash, 16) == 0) {
struct sockaddr_in *tempin;
/* Update query and time info for user */
users[userid].last_pkt = time(NULL);
memcpy(&(users[userid].q), q, sizeof(struct query));
/* 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 */ /* Correct hash, reply with hash of seed - 1 */
user_set_conn_type(userid, CONN_RAW_UDP);
users[userid].last_pkt = time(NULL); users[userid].last_pkt = time(NULL);
login_calculate(myhash, 16, password, users[userid].seed - 1); login_calculate(myhash, 16, password, users[userid].seed - 1);
memcpy(packet, myhash, 16); send_raw(fd, myhash, 16, userid, RAW_HDR_CMD_LOGIN, q);
send_raw(fd, packet, 17, RAW_HDR_CMD_LOGIN, q);
} }
} }
static int static void
raw_decode(char *packet, int len, struct query *q, int fd) 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) {
return;
}
/* Update query and time info for user */
users[userid].last_pkt = time(NULL);
memcpy(&(users[userid].q), q, sizeof(struct query));
/* copy to packet buffer, update length */
users[userid].inpacket.offset = 0;
memcpy(users[userid].inpacket.data, packet, len);
users[userid].inpacket.len = len;
if (debug >= 1) {
fprintf(stderr, "IN pkt raw, total %d, from user %d\n",
users[userid].inpacket.len, userid);
}
handle_full_packet(tun_fd, userid);
}
static int
raw_decode(char *packet, int len, struct query *q, int dns_fd, int tun_fd)
{
int raw_user;
/* minimum length */ /* minimum length */
if (len < RAW_HDR_LEN) return 0; if (len < RAW_HDR_LEN) return 0;
/* should start with header */ /* should start with header */
if (memcmp(packet, raw_header, RAW_HDR_IDENT_LEN)) return 0; if (memcmp(packet, raw_header, RAW_HDR_IDENT_LEN)) return 0;
if (packet[RAW_HDR_CMD] == RAW_HDR_CMD_LOGIN) { raw_user = RAW_HDR_GET_USR(packet);
handle_raw_login(&packet[RAW_HDR_LEN], len - RAW_HDR_LEN, q, fd); printf("raw %02x\n", packet[RAW_HDR_CMD]);
} else { switch (RAW_HDR_GET_CMD(packet)) {
warnx("Unhandled raw command %02X\n", packet[RAW_HDR_CMD]); case RAW_HDR_CMD_LOGIN:
/* Login challenge */
handle_raw_login(&packet[RAW_HDR_LEN], len - RAW_HDR_LEN, q, dns_fd, raw_user);
break;
case RAW_HDR_CMD_DATA:
/* Data packet */
handle_raw_data(&packet[RAW_HDR_LEN], len - RAW_HDR_LEN, q, dns_fd, tun_fd, raw_user);
break;
default:
warnx("Unhandled raw command %02X from user %d", RAW_HDR_GET_CMD(packet), raw_user);
break;
} }
return 1; return 1;
} }
static int static int
read_dns(int fd, struct query *q) read_dns(int fd, int tun_fd, struct query *q) /* FIXME: tun_fd is because of raw_decode() below */
{ {
struct sockaddr_in from; struct sockaddr_in from;
socklen_t addrlen; socklen_t addrlen;
@ -929,7 +984,7 @@ read_dns(int fd, struct query *q)
q->fromlen = addrlen; q->fromlen = addrlen;
/* TODO do not handle raw packets here! */ /* TODO do not handle raw packets here! */
if (raw_decode(packet, r, q, fd)) { if (raw_decode(packet, r, q, fd, tun_fd)) {
return 0; return 0;
} }
if (dns_decode(NULL, 0, q, QR_QUERY, packet, r) < 0) { if (dns_decode(NULL, 0, q, QR_QUERY, packet, r) < 0) {
@ -1177,7 +1232,7 @@ main(int argc, char **argv)
} }
topdomain = strdup(argv[1]); topdomain = strdup(argv[1]);
if(strlen(topdomain) <= 128) { if (strlen(topdomain) <= 128) {
if(check_topdomain(topdomain)) { if(check_topdomain(topdomain)) {
warnx("Topdomain contains invalid characters."); warnx("Topdomain contains invalid characters.");
usage(); usage();

View File

@ -90,6 +90,7 @@ init_users(in_addr_t my_ip, int netbits)
users[i].out_acked_seqno = 0; users[i].out_acked_seqno = 0;
users[i].out_acked_fragment = 0; users[i].out_acked_fragment = 0;
users[i].fragsize = 4096; users[i].fragsize = 4096;
users[i].conn = CONN_DNS_NULL;
} }
return created_users; return created_users;
@ -161,6 +162,8 @@ find_available_user()
if ((!users[i].active || users[i].last_pkt + 60 < time(NULL)) && !users[i].disabled) { if ((!users[i].active || users[i].last_pkt + 60 < time(NULL)) && !users[i].disabled) {
users[i].active = 1; users[i].active = 1;
users[i].last_pkt = time(NULL); users[i].last_pkt = time(NULL);
users[i].fragsize = 4096;
users[i].conn = CONN_DNS_NULL;
ret = i; ret = i;
break; break;
} }
@ -176,3 +179,16 @@ user_switch_codec(int userid, struct encoder *enc)
users[userid].encoder = enc; users[userid].encoder = enc;
} }
void
user_set_conn_type(int userid, enum connection c)
{
if (userid < 0 || userid >= USERS)
return;
if (c < 0 || c >= CONN_MAX)
return;
users[userid].conn = c;
}

View File

@ -34,6 +34,7 @@ struct user {
int out_acked_seqno; int out_acked_seqno;
int out_acked_fragment; int out_acked_fragment;
int fragsize; int fragsize;
enum connection conn;
}; };
extern struct user users[USERS]; extern struct user users[USERS];
@ -44,5 +45,6 @@ int find_user_by_ip(uint32_t);
int all_users_waiting_to_send(); int all_users_waiting_to_send();
int find_available_user(); int find_available_user();
void user_switch_codec(int userid, struct encoder *enc); void user_switch_codec(int userid, struct encoder *enc);
void user_set_conn_type(int userid, enum connection c);
#endif #endif