diff --git a/doc/proto_00000403.txt b/doc/proto_00000403.txt index e3a43f5..752e5d5 100644 --- a/doc/proto_00000403.txt +++ b/doc/proto_00000403.txt @@ -46,6 +46,17 @@ Server sends: be encoded with the new codec. BADCODEC if not accepted. Client must then revert to Base32 +Probe downstream fragment size: +Client sends: + First byte r or R + 15 bits coded as 3 Base32 chars: UUUUF FFFFF FFFFF + meaning 4 bits userid, 11 bits fragment size + Then follows a long random query which contents does not matter +Server sends: + Requested number of bytes as a response. The first two bytes contains + the requested length. Rest of message can be any data. + BADFRAG if requested length not accepted. + Set downstream fragment size: Client sends: First byte n or N diff --git a/src/iodined.c b/src/iodined.c index 44f0bef..31340b1 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -377,6 +377,28 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) break; } return; + } else if(in[0] == 'R' || in[0] == 'r') { + int req_frag_size; + + /* Downstream fragsize probe packet */ + userid = (b32_8to5(in[1]) >> 1) & 15; + if (userid < 0 || userid >= USERS || ip_cmp(userid, q) != 0) { + write_dns(dns_fd, q, "BADIP", 5); + return; /* illegal id */ + } + + req_frag_size = ((b32_8to5(in[1]) & 1) << 10) | ((b32_8to5(in[2]) & 31) << 5) | (b32_8to5(in[3]) & 31); + if (req_frag_size < 2 || req_frag_size > 2047) { + write_dns(dns_fd, q, "BADFRAG", 7); + } else { + char buf[2048]; + + memset(buf, 0, sizeof(buf)); + buf[0] = (req_frag_size >> 8) & 0xff; + buf[1] = req_frag_size & 0xff; + write_dns(dns_fd, q, buf, req_frag_size); + } + return; } else if(in[0] == 'N' || in[0] == 'n') { int max_frag_size; @@ -389,7 +411,7 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) } max_frag_size = ((unpacked[1] & 0xff) << 8) | (unpacked[2] & 0xff); - if (max_frag_size < 1) { + if (max_frag_size < 2) { write_dns(dns_fd, q, "BADFRAG", 7); } else { users[userid].fragsize = max_frag_size;