Use base64 is case is preserved and plus sign is allowed

This commit is contained in:
Erik Ekman 2008-09-14 11:34:56 +00:00 committed by Erik Ekman
parent 612d142819
commit d7f2d60d56
5 changed files with 126 additions and 17 deletions

View file

@ -21,6 +21,8 @@ CHANGES:
- iodine client now shuts down if it detects a server restart. - iodine client now shuts down if it detects a server restart.
- iodined now replies to NS request on its own domain, fixes issue #33. - iodined now replies to NS request on its own domain, fixes issue #33.
The destination IP address is sent as reply. The destination IP address is sent as reply.
- Upstream data is now Base64 encoded if relay server preserves case and
supports the plus (+) character in domain names, fixes #16.
2008-08-06: 0.4.2 "Opened Zone" 2008-08-06: 0.4.2 "Opened Zone"
- Applied a few small patches from Maxim Bourmistrov and Gregor Herrmann - Applied a few small patches from Maxim Bourmistrov and Gregor Herrmann

View file

@ -40,6 +40,7 @@
#include "common.h" #include "common.h"
#include "encoding.h" #include "encoding.h"
#include "base32.h" #include "base32.h"
#include "base64.h"
#include "dns.h" #include "dns.h"
#include "login.h" #include "login.h"
#include "tun.h" #include "tun.h"
@ -146,13 +147,13 @@ build_hostname(char *buf, size_t buflen,
return space; return space;
} }
int static int
is_sending() is_sending()
{ {
return (packet.len != 0); return (packet.len != 0);
} }
int static int
read_dns(int fd, char *buf, int buflen) read_dns(int fd, char *buf, int buflen)
{ {
struct sockaddr_in from; struct sockaddr_in from;
@ -324,7 +325,7 @@ send_chunk(int fd)
send_query(fd, buf); send_query(fd, buf);
} }
void static void
send_login(int fd, char *login, int len) send_login(int fd, char *login, int len)
{ {
char data[19]; char data[19];
@ -361,7 +362,7 @@ send_ping(int fd)
send_packet(fd, 'P', data, sizeof(data)); send_packet(fd, 'P', data, sizeof(data));
} }
void static void
send_version(int fd, uint32_t version) send_version(int fd, uint32_t version)
{ {
char data[6]; char data[6];
@ -379,15 +380,33 @@ send_version(int fd, uint32_t version)
send_packet(fd, 'V', data, sizeof(data)); send_packet(fd, 'V', data, sizeof(data));
} }
void static void
send_case_check(int fd) send_case_check(int fd)
{ {
char buf[512] = "zZaAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyY123-4560789."; /* The '+' plus character is not allowed according to RFC.
* Expect to get SERVFAIL or similar if it is rejected.
*/
char buf[512] = "zZ+-aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyY1234.";
strncat(buf, topdomain, 512 - strlen(buf)); strncat(buf, topdomain, 512 - strlen(buf));
send_query(fd, buf); send_query(fd, buf);
} }
static void
send_codec_switch(int fd, int userid, int bits)
{
char buf[512] = "S00.";
if (userid >= 0 && userid < 9) {
buf[1] += userid;
}
if (bits >= 0 && bits < 9) {
buf[2] += bits;
}
strncat(buf, topdomain, 512 - strlen(buf));
send_query(fd, buf);
}
static int static int
handshake(int dns_fd) handshake(int dns_fd)
{ {
@ -519,30 +538,30 @@ perform_case_check:
if(r > 0) { if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in)); read = read_dns(dns_fd, in, sizeof(in));
if(read <= 0) {
warn("read");
continue;
}
if (read > 0) { if (read > 0) {
if (in[0] == 'z' || in[0] == 'Z') { if (in[0] == 'z' || in[0] == 'Z') {
if (read < (26 * 2)) { if (read < (27 * 2)) {
printf("Received short case reply...\n"); printf("Received short case check reply. Will use base32 encoder\n");
goto switch_codec;
} else { } else {
int k; int k;
/* TODO enhance this, base128 is probably also possible */
case_preserved = 1; case_preserved = 1;
for (k = 0; k < 26 && case_preserved; k += 2) { for (k = 0; k < 27 && case_preserved; k += 2) {
if (in[k] == in[k+1]) { if (in[k] == in[k+1]) {
/* test string: zZaAbBcCdD... */ /* test string: zZ+-aAbBcCdDeE... */
case_preserved = 0; case_preserved = 0;
} }
} }
return 0; goto switch_codec;
} }
} else { } else {
printf("Received bad case check reply\n"); printf("Received bad case check reply\n");
} }
} else {
printf("Got error on case check, will use base32\n");
goto switch_codec;
} }
} }
@ -550,6 +569,52 @@ perform_case_check:
} }
printf("No reply on case check, continuing\n"); printf("No reply on case check, continuing\n");
switch_codec:
if (!case_preserved)
return 0;
dataenc = get_base64_encoder();
printf("Switching to %s codec\n", dataenc->name);
/* Send to server that this user will use base64 from now on */
for (i=0; running && i<5 ;i++) {
int bits;
tv.tv_sec = i + 1;
tv.tv_usec = 0;
bits = 6; /* base64 = 6 bits per byte */
send_codec_switch(dns_fd, userid, bits);
FD_ZERO(&fds);
FD_SET(dns_fd, &fds);
r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
if(r > 0) {
read = read_dns(dns_fd, in, sizeof(in));
if (read > 0) {
if (strncmp("BADLEN", in, 6) == 0) {
printf("Server got bad message length. ");
goto codec_revert;
} else if (strncmp("BADIP", in, 5) == 0) {
printf("Server rejected sender IP address. ");
goto codec_revert;
} else if (strncmp("BADCODEC", in, 8) == 0) {
printf("Server rejected the selected codec. ");
goto codec_revert;
}
in[read] = 0; /* zero terminate */
printf("Server switched to codec %s\n", in);
return 0;
}
}
printf("Retrying codec switch...\n");
}
printf("No reply from server on codec switch. ");
codec_revert:
printf("Falling back to base32\n");
dataenc = get_base32_encoder();
return 0; return 0;
} }

View file

@ -44,6 +44,7 @@
#include "dns.h" #include "dns.h"
#include "encoding.h" #include "encoding.h"
#include "base32.h" #include "base32.h"
#include "base64.h"
#include "user.h" #include "user.h"
#include "login.h" #include "login.h"
#include "tun.h" #include "tun.h"
@ -261,11 +262,43 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len)
memcpy(&(users[userid].q), q, sizeof(struct query)); memcpy(&(users[userid].q), q, sizeof(struct query));
users[userid].last_pkt = time(NULL); users[userid].last_pkt = time(NULL);
} else if(in[0] == 'Z' || in[0] == 'z') { } else if(in[0] == 'Z' || in[0] == 'z') {
/* Case conservation check */ /* Check for case conservation and chars not allowed according to RFC */
/* Reply with received hostname as data */ /* Reply with received hostname as data */
write_dns(dns_fd, q, in, domain_len); write_dns(dns_fd, q, in, domain_len);
return; return;
} else if(in[0] == 'S' || in[0] == 's') {
int codec;
struct encoder *enc;
if (domain_len != 4) { /* len = 4, example: "S15." */
write_dns(dns_fd, q, "BADLEN", 6);
return;
}
userid = in[1] & 0x7;
if (ip_cmp(userid, q) != 0) {
write_dns(dns_fd, q, "BADIP", 5);
return; /* illegal id */
}
codec = in[2] & 0xF;
switch (codec) {
case 5: /* 5 bits per byte = base32 */
enc = get_base32_encoder();
user_switch_codec(userid, enc);
write_dns(dns_fd, q, enc->name, strlen(enc->name));
break;
case 6: /* 6 bits per byte = base64 */
enc = get_base64_encoder();
user_switch_codec(userid, enc);
write_dns(dns_fd, q, enc->name, strlen(enc->name));
break;
default:
write_dns(dns_fd, q, "BADCODEC", 8);
break;
}
return;
} 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')) {

View file

@ -106,3 +106,11 @@ find_available_user()
return ret; return ret;
} }
void
user_switch_codec(int userid, struct encoder *enc)
{
if (userid < 0 || userid >= USERS)
return;
users[userid].encoder = enc;
}

View file

@ -38,5 +38,6 @@ void init_users(in_addr_t);
int find_user_by_ip(uint32_t); 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);
#endif #endif