diff --git a/doc/proto_00000501.txt b/doc/proto_00000501.txt new file mode 100644 index 0000000..4b36685 --- /dev/null +++ b/doc/proto_00000501.txt @@ -0,0 +1,125 @@ +Detailed specification of protocol in version 00000501 +====================================================== + +Note: work in progress!! + +====================================================== + +CMC = 2 byte Cache Miss Counter, increased every time it is used + +Version: +Client sends: + First byte v or V + Rest encoded with base32: + 4 bytes big endian protocol version + CMC +Server replies: + 4 chars: + VACK (version ok), followed by login challenge + VNAK (version differs), followed by server protocol version + VFUL (server has no free slots), followed by max users + 4 byte value: means login challenge/server protocol version/max users + 1 byte userid of the new user, or any byte if not VACK + +Login: +Client sends: + First byte l or L + Rest encoded with base32: + 1 byte userid + 16 bytes MD5 hash of: (first 32 bytes of password) xor (8 repetitions of login challenge) + CMC +Server replies: + LNAK means not accepted + x.x.x.x-y.y.y.y-mtu-netmask means accepted (server ip, client ip, mtu, netmask bits) + +IP Request: +Client sends: + First byte i or I + 5 bits coded as Base32 char, meaning userid + CMC +Server replies + BADIP if bad userid, or + I and then 4 bytes network order external IP address of iodined server + +Case check: +Client sends: + First byte z or Z + Lots of data that should not be decoded +Server replies: + The requested domain copied raw + +Switch codec: +Client sends: + First byte s or S + 5 bits coded as Base32 char, meaning userid + 5 bits coded as Base32 char, with value 5 or 6, representing number of raw + bits per encoded byte +Server sends: + Name of codec if accepted. After this all upstream data packets must + 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 + Rest encoded with base32: + 1 byte userid + 2 bytes new downstream fragment size + CMC +Server sends: + 2 bytes new downstream fragment size. After this all downstream + payloads will be max (fragsize + 2) bytes long. + BADFRAG if not accepted. + +Data: +Upstream data header: + 3210 432 10 43 210 4321 0 + +----+---+--+--+---+----+-+ + |UUUU|SSS|FF|FF|DDD|GGGG|L| + +----+---+--+--+---+----+-+ + +Downstream data header: + 7 654 3210 765 4321 0 + +-+---+----+---+----+-+ + |C|SSS|FFFF|DDD|GGGG|L| + +-+---+----+---+----+-+ + +UUUU = Userid +L = Last fragment in packet flag +SS = Upstream packet sequence number +FFFF = Upstream fragment number +DDD = Downstream packet sequence number +GGGG = Downstream fragment number +C = Compression enabled for downstream packet + +Upstream data packet starts with 1 byte ASCII hex coded user byte, then 3 bytes +Base32 encoded header, then comes the payload data, encoded with chosen codec. + +Downstream data starts with 2 byte header. Then payload data, which may be +compressed. + +Ping: +Client sends: + First byte p or P + Rest encoded with Base32: + 1 byte with 4 bits userid + 1 byte with: + 3 bits downstream seqno + 4 bits downstream fragment + CMC + +The server response to Ping and Data packets is a DNS NULL type response: +If server has nothing to send, data length is 0 bytes. +If server has something to send, it will send a downstream data packet, +prefixed with 2 bytes header as shown above. diff --git a/src/iodined.c b/src/iodined.c index 5f17bf1..5a92c20 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -389,6 +389,33 @@ handle_null_request(int tun_fd, int dns_fd, struct query *q, int domain_len) } } return; + } else if(in[0] == 'I' || in[0] == 'i') { + /* Request for IP number */ + in_addr_t replyaddr; + unsigned addr; + char reply[5]; + + userid = b32_8to5(in[1]); + if (check_user_and_ip(userid, q) != 0) { + write_dns(dns_fd, q, "BADIP", 5); + return; /* illegal id */ + } + + if (ns_ip != INADDR_ANY) { + /* If set, use assigned external ip (-n option) */ + replyaddr = ns_ip; + } else { + /* otherwise return destination ip from packet */ + memcpy(&replyaddr, &q->destination.s_addr, sizeof(in_addr_t)); + } + + addr = htonl(replyaddr); + reply[0] = 'I'; + reply[1] = (addr >> 24) & 0xFF; + reply[2] = (addr >> 16) & 0xFF; + reply[3] = (addr >> 8) & 0xFF; + reply[4] = (addr >> 0) & 0xFF; + write_dns(dns_fd, q, reply, sizeof(reply)); } else if(in[0] == 'Z' || in[0] == 'z') { /* Check for case conservation and chars not allowed according to RFC */ @@ -600,6 +627,8 @@ handle_ns_request(int dns_fd, struct query *q) int len; if (ns_ip != INADDR_ANY) { + /* If ns_ip set, overwrite destination addr with it. + * Destination addr will be sent as additional record (A, IN) */ memcpy(&q->destination.s_addr, &ns_ip, sizeof(in_addr_t)); } diff --git a/src/version.h b/src/version.h index 7856fde..05a979a 100644 --- a/src/version.h +++ b/src/version.h @@ -19,7 +19,7 @@ /* This is the version of the network protocol It is usually equal to the latest iodine version number */ -#define VERSION 0x00000500 +#define VERSION 0x00000501 #endif /* _VERSION_H_ */