#36, basic raw mode tunnel works

This commit is contained in:
Erik Ekman 2009-08-06 20:42:26 +00:00 committed by Erik Ekman
parent 58d9615160
commit e5370ad95b
3 changed files with 103 additions and 74 deletions

View File

@ -189,58 +189,77 @@ is_sending()
} }
static int static int
read_dns(int fd, char *buf, int buflen) read_dns(int dns_fd, int tun_fd, char *buf, int buflen) /* FIXME: tun_fd needed for raw handling */
{ {
struct sockaddr_in from; struct sockaddr_in from;
char data[64*1024]; char data[64*1024];
socklen_t addrlen; socklen_t addrlen;
struct query q; struct query q;
int rv;
int r; int r;
addrlen = sizeof(struct sockaddr); addrlen = sizeof(struct sockaddr);
if ((r = recvfrom(fd, data, sizeof(data), 0, if ((r = recvfrom(dns_fd, data, sizeof(data), 0,
(struct sockaddr*)&from, &addrlen)) == -1) { (struct sockaddr*)&from, &addrlen)) == -1) {
warn("recvfrom"); warn("recvfrom");
return 0; return 0;
} }
rv = dns_decode(buf, buflen, &q, QR_ANSWER, data, r); if (conn == CONN_DNS_NULL) {
int rv;
/* decode the data header, update seqno and frag before next request */ rv = dns_decode(buf, buflen, &q, QR_ANSWER, data, r);
if (rv >= 2) {
downstream_seqno = (buf[1] >> 5) & 7;
downstream_fragment = (buf[1] >> 1) & 15;
}
if (is_sending()) {
if (chunkid == q.id) {
/* Got ACK on sent packet */
outpkt.offset += outpkt.sentlen;
if (outpkt.offset == outpkt.len) {
/* Packet completed */
outpkt.offset = 0;
outpkt.len = 0;
outpkt.sentlen = 0;
/* If the ack contains unacked frag number but no data,
* send a ping to ack the frag number and get more data*/
if (rv == 2 && (
downstream_seqno != down_ack_seqno ||
downstream_fragment != down_ack_fragment
)) {
send_ping(fd);
}
} else {
/* More to send */
send_chunk(fd);
}
/* decode the data header, update seqno and frag before next request */
if (rv >= 2) {
downstream_seqno = (buf[1] >> 5) & 7;
downstream_fragment = (buf[1] >> 1) & 15;
} }
if (is_sending()) {
if (chunkid == q.id) {
/* Got ACK on sent packet */
outpkt.offset += outpkt.sentlen;
if (outpkt.offset == outpkt.len) {
/* Packet completed */
outpkt.offset = 0;
outpkt.len = 0;
outpkt.sentlen = 0;
/* If the ack contains unacked frag number but no data,
* send a ping to ack the frag number and get more data*/
if (rv == 2 && (
downstream_seqno != down_ack_seqno ||
downstream_fragment != down_ack_fragment
)) {
send_ping(dns_fd);
}
} else {
/* More to send */
send_chunk(dns_fd);
}
}
}
return rv;
} else { /* CONN_RAW_UDP */
unsigned long datalen;
char buf[64*1024];
int raw_user;
/* minimum length */
if (r < RAW_HDR_LEN) return 0;
/* should start with header */
if (memcmp(data, raw_header, RAW_HDR_IDENT_LEN)) return 0;
/* should be data packet */
if (RAW_HDR_GET_CMD(data) != RAW_HDR_CMD_DATA) return 0;
raw_user = RAW_HDR_GET_USR(data);
if (uncompress((uint8_t*)buf, &datalen, (uint8_t*) &data[RAW_HDR_LEN], r) == Z_OK) {
write_tun(tun_fd, buf, datalen);
}
return 0;
} }
return rv;
} }
@ -283,7 +302,7 @@ tunnel_dns(int tun_fd, int dns_fd)
char buf[64*1024]; char buf[64*1024];
size_t read; size_t read;
if ((read = read_dns(dns_fd, buf, sizeof(buf))) <= 2) if ((read = read_dns(dns_fd, tun_fd, buf, sizeof(buf))) <= 2)
return -1; return -1;
if (downstream_seqno != inpkt.seqno) { if (downstream_seqno != inpkt.seqno) {
@ -578,7 +597,7 @@ handshake_version(int dns_fd, int *seed)
r = select(dns_fd + 1, &fds, NULL, NULL, &tv); r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) { if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in)); read = read_dns(dns_fd, 0, in, sizeof(in));
if(read <= 0) { if(read <= 0) {
if (read == 0) { if (read == 0) {
@ -646,7 +665,7 @@ handshake_login(int dns_fd, int seed)
r = select(dns_fd + 1, &fds, NULL, NULL, &tv); r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) { if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in)); read = read_dns(dns_fd, 0, in, sizeof(in));
if(read <= 0) { if(read <= 0) {
warn("read"); warn("read");
@ -707,7 +726,7 @@ handshake_raw_udp(int dns_fd, int seed)
r = select(dns_fd + 1, &fds, NULL, NULL, &tv); r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) { if(r > 0) {
len = read_dns(dns_fd, in, sizeof(in)); len = read_dns(dns_fd, 0, in, sizeof(in));
if (len == 5 && in[0] == 'I') { if (len == 5 && in[0] == 'I') {
/* Received IP address */ /* Received IP address */
remoteaddr = (in[1] & 0xff); remoteaddr = (in[1] & 0xff);
@ -800,7 +819,7 @@ handshake_case_check(int dns_fd)
r = select(dns_fd + 1, &fds, NULL, NULL, &tv); r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) { if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in)); read = read_dns(dns_fd, 0, in, sizeof(in));
if (read > 0) { if (read > 0) {
if (in[0] == 'z' || in[0] == 'Z') { if (in[0] == 'z' || in[0] == 'Z') {
@ -864,7 +883,7 @@ handshake_switch_codec(int dns_fd)
r = select(dns_fd + 1, &fds, NULL, NULL, &tv); r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) { if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in)); read = read_dns(dns_fd, 0, in, sizeof(in));
if (read > 0) { if (read > 0) {
if (strncmp("BADLEN", in, 6) == 0) { if (strncmp("BADLEN", in, 6) == 0) {
@ -918,7 +937,7 @@ handshake_autoprobe_fragsize(int dns_fd)
r = select(dns_fd + 1, &fds, NULL, NULL, &tv); r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) { if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in)); read = read_dns(dns_fd, 0, in, sizeof(in));
if (read > 0) { if (read > 0) {
/* We got a reply */ /* We got a reply */
@ -989,7 +1008,7 @@ handshake_set_fragsize(int dns_fd, int fragsize)
r = select(dns_fd + 1, &fds, NULL, NULL, &tv); r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) { if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in)); read = read_dns(dns_fd, 0, in, sizeof(in));
if (read > 0) { if (read > 0) {
int accepted_fragsize; int accepted_fragsize;

View File

@ -123,6 +123,9 @@ check_user_and_ip(int userid, struct query *q)
if (!users[userid].active) { if (!users[userid].active) {
return 1; return 1;
} }
if (users[userid].last_pkt + 60 < time(NULL)) {
return 1;
}
/* return early if IP checking is disabled */ /* return early if IP checking is disabled */
if (!check_ip) { if (!check_ip) {
@ -133,6 +136,24 @@ check_user_and_ip(int userid, struct query *q)
return memcmp(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr)); return memcmp(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
} }
static void
send_raw(int fd, char *buf, int buflen, int user, int cmd, struct query *q)
{
char packet[4096];
int len;
len = MIN(sizeof(packet) - RAW_HDR_LEN, buflen);
memcpy(packet, raw_header, RAW_HDR_LEN);
memcpy(&packet[RAW_HDR_LEN], buf, len);
len += RAW_HDR_LEN;
packet[RAW_HDR_CMD] = cmd | (user & 0x0F);
sendto(fd, packet, len, 0, &q->from, q->fromlen);
}
static int static int
tunnel_tun(int tun_fd, int dns_fd) tunnel_tun(int tun_fd, int dns_fd)
{ {
@ -155,17 +176,22 @@ tunnel_tun(int tun_fd, int dns_fd)
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);
/* if another packet is queued, throw away this one. TODO build queue */ if (users[userid].conn == CONN_DNS_NULL) {
if (users[userid].outpacket.len == 0) { /* if another packet is queued, throw away this one. TODO build queue */
memcpy(users[userid].outpacket.data, out, outlen); if (users[userid].outpacket.len == 0) {
users[userid].outpacket.len = outlen; memcpy(users[userid].outpacket.data, out, outlen);
users[userid].outpacket.offset = 0; users[userid].outpacket.len = outlen;
users[userid].outpacket.sentlen = 0; users[userid].outpacket.offset = 0;
users[userid].outpacket.seqno = (++users[userid].outpacket.seqno & 7); users[userid].outpacket.sentlen = 0;
users[userid].outpacket.fragment = 0; users[userid].outpacket.seqno = (++users[userid].outpacket.seqno & 7);
users[userid].outpacket.fragment = 0;
return outlen;
} else {
return 0;
}
} else { /* CONN_RAW_UDP */
send_raw(dns_fd, out, outlen, userid, RAW_HDR_CMD_DATA, &users[userid].q);
return outlen; return outlen;
} else {
return 0;
} }
} }
@ -790,7 +816,7 @@ tunnel(int tun_fd, int dns_fd, int bind_fd)
if (i==0) { if (i==0) {
int j; int j;
for (j = 0; j < USERS; j++) { for (j = 0; j < USERS; j++) {
if (users[j].q.id != 0) { if (users[j].q.id != 0 && users[j].conn == CONN_DNS_NULL) {
send_chunk(dns_fd, j); send_chunk(dns_fd, j);
} }
} }
@ -848,23 +874,6 @@ handle_full_packet(int tun_fd, int userid)
users[userid].inpacket.len = users[userid].inpacket.offset = 0; 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];
int len;
len = MIN(sizeof(packet) - RAW_HDR_LEN, buflen);
memcpy(packet, raw_header, RAW_HDR_LEN);
memcpy(&packet[RAW_HDR_LEN], buf, len);
len += RAW_HDR_LEN;
packet[RAW_HDR_CMD] = cmd | (user & 0x0F);
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, int userid) handle_raw_login(char *packet, int len, struct query *q, int fd, int userid)
{ {
@ -931,7 +940,6 @@ raw_decode(char *packet, int len, struct query *q, int dns_fd, int tun_fd)
if (memcmp(packet, raw_header, RAW_HDR_IDENT_LEN)) return 0; if (memcmp(packet, raw_header, RAW_HDR_IDENT_LEN)) return 0;
raw_user = RAW_HDR_GET_USR(packet); raw_user = RAW_HDR_GET_USR(packet);
printf("raw %02x\n", packet[RAW_HDR_CMD]);
switch (RAW_HDR_GET_CMD(packet)) { switch (RAW_HDR_GET_CMD(packet)) {
case RAW_HDR_CMD_LOGIN: case RAW_HDR_CMD_LOGIN:
/* Login challenge */ /* Login challenge */

View File

@ -106,7 +106,7 @@ users_waiting_on_reply()
for (i = 0; i < USERS; i++) { for (i = 0; i < USERS; i++) {
if (users[i].active && !users[i].disabled && if (users[i].active && !users[i].disabled &&
users[i].last_pkt + 60 > time(NULL) && users[i].last_pkt + 60 > time(NULL) &&
users[i].q.id != 0) { users[i].q.id != 0 && users[i].conn == CONN_DNS_NULL) {
ret++; ret++;
} }
} }
@ -144,7 +144,9 @@ all_users_waiting_to_send()
for (i = 0; i < USERS; i++) { for (i = 0; i < USERS; i++) {
if (users[i].active && !users[i].disabled && if (users[i].active && !users[i].disabled &&
users[i].last_pkt + 60 > now && users[i].last_pkt + 60 > now &&
users[i].outpacket.len == 0) { ((users[i].outpacket.len == 0 && users[i].conn == CONN_DNS_NULL)
|| users[i].conn == CONN_RAW_UDP)) {
ret = 0; ret = 0;
break; break;
} }