Ticket #75: iodine-trunk-CNAME2.patch
| File iodine-trunk-CNAME2.patch, 61.1 KB (added by guest, 3 years ago) |
|---|
-
src/base32.c
old new 26 26 27 27 static const char cb32[] = 28 28 "abcdefghijklmnopqrstuvwxyz012345"; 29 static const char cb32_ucase[] = 30 "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; 29 31 static unsigned char rev32[128]; 30 32 31 33 static int base32_decode(void *, size_t *, const char *, size_t); … … 80 82 for (i = 0; i < 32; i++) { 81 83 c = cb32[i]; 82 84 rev32[(int) c] = i; 85 c = cb32_ucase[i]; 86 rev32[(int) c] = i; 83 87 } 84 88 reverse_init = 1; 85 89 } -
src/dns.c
old new 38 38 #include "encoding.h" 39 39 #include "read.h" 40 40 41 #define CHECKLEN(x) if (buflen - (p-buf) < (x)) return 0 42 41 43 int 42 44 dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_t datalen) 43 45 { … … 46 48 char *p; 47 49 int len; 48 50 51 if (buflen < sizeof(HEADER)) 52 return 0; 53 49 54 memset(buf, 0, buflen); 50 55 51 56 header = (HEADER*)buf; … … 67 72 68 73 name = 0xc000 | ((p - buf) & 0x3fff); 69 74 70 putname(&p, sizeof(q->name), q->name); 75 /* Question section */ 76 putname(&p, buflen - (p - buf), q->name); 71 77 78 CHECKLEN(4); 72 79 putshort(&p, q->type); 73 80 putshort(&p, C_IN); 74 81 82 /* Answer section */ 83 CHECKLEN(10); 75 84 putshort(&p, name); 76 putshort(&p, q->type); 85 if (q->type == T_A) 86 putshort(&p, T_CNAME); /* answer CNAME to A question */ 87 else 88 putshort(&p, q->type); 77 89 putshort(&p, C_IN); 78 putlong(&p, 0); 90 putlong(&p, 0); /* TTL */ 91 92 if (q->type == T_CNAME || q->type == T_A || q->type == T_MX) { 93 /* data is expected to be like "Hblabla.host.name.com\0" */ 94 95 char *startp = p; 96 int namelen; 97 98 p += 2; /* skip 2 bytes length */ 99 CHECKLEN(2); 100 if (q->type == T_MX) 101 putshort(&p, 10); /* preference */ 102 putname(&p, buflen - (p - buf), data); 103 CHECKLEN(0); 104 namelen = p - startp; 105 namelen -= 2; 106 putshort(&startp, namelen); 107 } else if (q->type == T_TXT) { 108 /* TXT has binary or base-X data */ 109 char *startp = p; 110 int txtlen; 111 112 p += 2; /* skip 2 bytes length */ 113 puttxtbin(&p, buflen - (p - buf), data, datalen); 114 CHECKLEN(0); 115 txtlen = p - startp; 116 txtlen -= 2; 117 putshort(&startp, txtlen); 118 } else { 119 /* NULL has raw binary data */ 120 datalen = MIN(datalen, buflen - (p - buf)); 121 CHECKLEN(2); 122 putshort(&p, datalen); 123 CHECKLEN(datalen); 124 putdata(&p, data, datalen); 125 CHECKLEN(0); 126 } 79 127 80 putshort(&p, datalen);81 putdata(&p, data, datalen);82 128 break; 83 129 case QR_QUERY: 130 /* Note that iodined also uses this for forward queries */ 131 84 132 header->qdcount = htons(1); 85 133 header->arcount = htons(1); 86 134 87 putname(&p, datalen, data);135 putname(&p, buflen - (p - buf), data); 88 136 137 CHECKLEN(4); 89 138 putshort(&p, q->type); 90 139 putshort(&p, C_IN); 91 140 92 /* EDNS0 */ 141 /* 142 * EDNS0 to advertise maximum response length 143 * (even CNAME/A/MX, 255+255+header would be >512) 144 */ 145 CHECKLEN(11); 93 146 putbyte(&p, 0x00); /* Root */ 94 147 putshort(&p, 0x0029); /* OPT */ 95 148 putshort(&p, 0x1000); /* Payload size: 4096 */ … … 116 169 int domain_len; 117 170 char *p; 118 171 172 if (buflen < sizeof(HEADER)) 173 return 0; 174 119 175 memset(buf, 0, buflen); 120 176 121 177 header = (HEADER*)buf; 122 178 123 179 header->id = htons(q->id); 124 180 header->qr = 1; 125 181 header->opcode = 0; … … 147 203 topname = 0xc000 | ((p - buf + domain_len) & 0x3fff); 148 204 149 205 /* Query section */ 150 putname(&p, sizeof(q->name), q->name); /* Name */ 151 putshort(&p, q->type); /* Type */ 152 putshort(&p, C_IN); /* Class */ 206 putname(&p, buflen - (p - buf), q->name); /* Name */ 207 CHECKLEN(4); 208 putshort(&p, q->type); /* Type */ 209 putshort(&p, C_IN); /* Class */ 153 210 154 211 /* Answer section */ 155 putshort(&p, name); /* Name */ 156 putshort(&p, q->type); /* Type */ 157 putshort(&p, C_IN); /* Class */ 158 putlong(&p, 0x3ea7d011); /* TTL */ 159 putshort(&p, 5); /* Data length */ 212 CHECKLEN(12); 213 putshort(&p, name); /* Name */ 214 putshort(&p, q->type); /* Type */ 215 putshort(&p, C_IN); /* Class */ 216 putlong(&p, 3600); /* TTL */ 217 putshort(&p, 5); /* Data length */ 160 218 161 219 /* pointer to ns.topdomain */ 162 220 nsname = 0xc000 | ((p - buf) & 0x3fff); 221 CHECKLEN(5); 163 222 putbyte(&p, 2); 164 223 putbyte(&p, 'n'); 165 224 putbyte(&p, 's'); 166 putshort(&p, topname); /* Name Server */225 putshort(&p, topname); /* Name Server */ 167 226 168 227 /* Additional data (A-record of NS server) */ 169 putshort(&p, nsname); /* Name Server */ 170 putshort(&p, T_A); /* Type */ 171 putshort(&p, C_IN); /* Class */ 172 putlong(&p, 0x3ea7d011); /* TTL */ 173 putshort(&p, 4); /* Data length */ 228 CHECKLEN(12); 229 putshort(&p, nsname); /* Name Server */ 230 putshort(&p, T_A); /* Type */ 231 putshort(&p, C_IN); /* Class */ 232 putlong(&p, 3600); /* TTL */ 233 putshort(&p, 4); /* Data length */ 174 234 175 235 /* ugly hack to output IP address */ 176 236 domain = (char *) &q->destination; 237 CHECKLEN(4); 177 238 putbyte(&p, *domain++); 178 239 putbyte(&p, *domain++); 179 240 putbyte(&p, *domain++); … … 183 244 return len; 184 245 } 185 246 247 #undef CHECKLEN 248 186 249 unsigned short 187 250 dns_get_id(char *packet, size_t packetlen) 188 251 { … … 195 258 return ntohs(header->id); 196 259 } 197 260 261 #define CHECKLEN(x) if (packetlen - (data-packet) < (x)) return 0 262 198 263 int 199 264 dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen) 200 265 { … … 234 299 235 300 switch (qr) { 236 301 case QR_ANSWER: 237 if(qdcount != 1 || ancount != 1) { 302 if(qdcount < 1 || ancount < 1) { 303 /* We may get both CNAME and A, then ancount=2 */ 238 304 switch (header->rcode) { 239 case REFUSED: 240 warnx("Got REFUSED as reply"); 305 case NOERROR: /* 0 */ 306 if (header->tc) 307 warnx("Got TRUNCATION as reply: response too long for DNS path"); 308 else 309 warnx("Got reply without error, but also without question and/or answer"); 310 break; 311 312 case FORMERR: /* 1 */ 313 warnx("Got FORMERR as reply: server does not understand our request"); 241 314 break; 242 315 243 case NOTIMP: 244 warnx("Got NOTIMP as reply"); 316 case SERVFAIL: /* 2 */ 317 if (qdcount >= 1 318 && packetlen >= sizeof(HEADER) + 2 319 && (data[1] == 'r' || data[1] == 'R')) 320 warnx("Got SERVFAIL as reply on earlier fragsize autoprobe"); 321 else if (qdcount >= 1 322 && packetlen >= sizeof(HEADER) + 2 323 && (data[1] < '0' || data[1] > '9') 324 && (data[1] < 'a' || data[1] > 'f') 325 && (data[1] < 'A' || data[1] > 'F') 326 && data[1] != 'p' && data[1] != 'P') 327 warnx("Got SERVFAIL as reply on earlier config setting"); 328 else 329 warnx("Got SERVFAIL as reply: server failed or recursion timeout"); 245 330 break; 246 331 247 case NXDOMAIN: 248 warnx("Got NXDOMAIN as reply ");332 case NXDOMAIN: /* 3 */ 333 warnx("Got NXDOMAIN as reply: domain does not exist"); 249 334 break; 250 335 251 case SERVFAIL:252 warnx("Got SERVFAIL as reply");336 case NOTIMP: /* 4 */ 337 warnx("Got NOTIMP as reply: server does not support our request"); 253 338 break; 254 339 255 case NOERROR: 340 case REFUSED: /* 5 */ 341 warnx("Got REFUSED as reply"); 342 break; 343 256 344 default: 257 warnx(" no query or answer in reply packet");345 warnx("Got RCODE %u as reply", (unsigned int) header->rcode); 258 346 break; 259 347 } 260 348 return -1; … … 264 352 q->id = id; 265 353 266 354 readname(packet, packetlen, &data, name, sizeof(name)); 355 CHECKLEN(4); 267 356 readshort(packet, &data, &type); 268 357 readshort(packet, &data, &class); 269 358 359 /* Assume that first answer is NULL/CNAME that we wanted */ 270 360 readname(packet, packetlen, &data, name, sizeof(name)); 361 CHECKLEN(10); 271 362 readshort(packet, &data, &type); 272 363 readshort(packet, &data, &class); 273 364 readlong(packet, &data, &ttl); 274 365 readshort(packet, &data, &rlen); 275 rv = MIN(rlen, sizeof(rdata));276 rv = readdata(packet, &data, rdata, rv);277 366 278 if(type == T_NULL && rv >= 2 && buf) { 279 rv = MIN(rv, buflen); 280 memcpy(buf, rdata, rv); 367 if (type == T_NULL) { 368 rv = MIN(rlen, sizeof(rdata)); 369 rv = readdata(packet, &data, rdata, rv); 370 if (rv >= 2 && buf) { 371 rv = MIN(rv, buflen); 372 memcpy(buf, rdata, rv); 373 } 374 /* "else rv=0;" here? */ 281 375 } 376 if ((type == T_CNAME || type == T_MX) && buf) { 377 if (type == T_MX) 378 data += 2; /* skip preference */ 379 memset(name, 0, sizeof(name)); 380 readname(packet, packetlen, &data, name, sizeof(name) - 1); 381 name[sizeof(name)-1] = '\0'; 382 strncpy(buf, name, buflen); 383 buf[buflen - 1] = '\0'; 384 rv = strlen(buf); 385 } 386 if (type == T_TXT && buf) { 387 rv = readtxtbin(packet, &data, rlen, rdata, sizeof(rdata)); 388 if (rv >= 1) { 389 rv = MIN(rv, buflen); 390 memcpy(buf, rdata, rv); 391 } 392 } 393 if (q != NULL) 394 q->type = type; 282 395 break; 283 396 case QR_QUERY: 284 if (qdcount !=1) {397 if (qdcount < 1) { 285 398 warnx("no question section in name query"); 286 399 return -1; 287 400 } 288 401 402 memset(name, 0, sizeof(name)); 289 403 readname(packet, packetlen, &data, name, sizeof(name) - 1); 290 404 name[sizeof(name)-1] = '\0'; 405 CHECKLEN(4); 291 406 readshort(packet, &data, &type); 292 407 readshort(packet, &data, &class); 293 408 409 if (q == NULL) { 410 rv = 0; 411 break; 412 } 413 294 414 strncpy(q->name, name, sizeof(q->name)); 295 415 q->name[sizeof(q->name) - 1] = '\0'; 296 416 q->type = type; -
src/encoding.c
old new 27 27 } 28 28 29 29 int 30 inline_dotify(char *buf, size_t buflen )30 inline_dotify(char *buf, size_t buflen, int intv) 31 31 { 32 32 unsigned dots; 33 33 unsigned pos; … … 35 35 char *reader, *writer; 36 36 37 37 total = strlen(buf); 38 dots = total / 57;38 dots = total / intv; 39 39 40 40 writer = buf; 41 41 writer += total; … … 54 54 while (dots) { 55 55 *writer-- = *reader--; 56 56 pos--; 57 if (pos % 57== 0) {57 if (pos % intv == 0) { 58 58 *writer-- = '.'; 59 59 dots--; 60 60 } -
src/encoding.h
old new 28 28 }; 29 29 30 30 int unpack_data(char *, size_t, char *, size_t, struct encoder *); 31 int inline_dotify(char *, size_t );31 int inline_dotify(char *, size_t, int); 32 32 int inline_undotify(char *, size_t); 33 33 34 34 -
src/read.c
old new 126 126 } 127 127 128 128 int 129 readtxtbin(char *packet, char **src, size_t srcremain, char *dst, size_t dstremain) 130 { 131 unsigned char *uc; 132 int tocopy; 133 int dstused = 0; 134 135 while (srcremain > 0) 136 { 137 uc = (unsigned char*) (*src); 138 tocopy = *uc; 139 (*src)++; 140 srcremain--; 141 142 if (tocopy > srcremain) 143 return 0; /* illegal, better have nothing */ 144 if (tocopy > dstremain) 145 return 0; /* doesn't fit, better have nothing */ 146 147 memcpy(dst, *src, tocopy); 148 dst += tocopy; 149 (*src) += tocopy; 150 srcremain -= tocopy; 151 dstremain -= tocopy; 152 dstused += tocopy; 153 } 154 return dstused; 155 } 156 157 int 129 158 putname(char **buf, size_t buflen, const char *host) 130 159 { 131 160 char *word; … … 212 241 return len; 213 242 } 214 243 244 int 245 puttxtbin(char **buf, size_t bufremain, char *from, size_t fromremain) 246 { 247 unsigned char uc; 248 unsigned char *ucp = &uc; 249 char *cp = (char *) ucp; 250 int tocopy; 251 int bufused = 0; 252 253 while (fromremain > 0) 254 { 255 tocopy = fromremain; 256 if (tocopy > 252) 257 tocopy = 252; /* allow off-by-1s in caches etc */ 258 if (tocopy + 1 > bufremain) 259 return -1; /* doesn't fit, better have nothing */ 260 261 uc = tocopy; 262 **buf = *cp; 263 (*buf)++; 264 bufremain--; 265 bufused++; 266 267 memcpy(*buf, from, tocopy); 268 (*buf) += tocopy; 269 from += tocopy; 270 bufremain -= tocopy; 271 fromremain -= tocopy; 272 bufused += tocopy; 273 } 274 return bufused; 275 } -
src/read.h
old new 21 21 int readshort(char *, char **, short *); 22 22 int readlong(char *, char **, uint32_t *); 23 23 int readdata(char *, char **, char *, size_t); 24 int readtxtbin(char *, char **, size_t, char *, size_t); 24 25 25 26 int putname(char **, size_t, const char *); 26 27 int putbyte(char **, unsigned char); 27 28 int putshort(char **, unsigned short); 28 29 int putlong(char **, uint32_t); 29 30 int putdata(char **, char *, size_t); 31 int puttxtbin(char **, size_t, char *, size_t); 30 32 31 33 #endif -
src/user.h
old new 31 31 struct packet inpacket; 32 32 struct packet outpacket; 33 33 struct encoder *encoder; 34 char downenc; 34 35 int out_acked_seqno; 35 36 int out_acked_fragment; 36 37 int fragsize; … … 38 39 }; 39 40 40 41 extern struct user users[USERS]; 42 extern time_t now; 41 43 42 44 int init_users(in_addr_t, int); 43 45 int users_waiting_on_reply(); 44 46 int find_user_by_ip(uint32_t); 45 47 int all_users_waiting_to_send(); 46 int find_available_user( );48 int find_available_user(int forced_userid); 47 49 void user_switch_codec(int userid, struct encoder *enc); 48 50 void user_set_conn_type(int userid, enum connection c); 49 51 -
src/util.c
old new 29 29 rv = NULL; 30 30 31 31 if ((fp = fopen("/etc/resolv.conf", "r")) == NULL) 32 err(1, "/etc/resolv e.conf");32 err(1, "/etc/resolv.conf"); 33 33 34 34 while (feof(fp) == 0) { 35 35 fgets(buf, sizeof(buf), fp); -
src/windows.h
old new 28 28 #define T_A DNS_TYPE_A 29 29 #define T_NS DNS_TYPE_NS 30 30 #define T_NULL DNS_TYPE_NULL 31 #define T_CNAME DNS_TYPE_CNAME 32 #define T_MX DNS_TYPE_MX 33 #define T_TXT DNS_TYPE_TXT 31 34 32 35 #define C_IN 1 33 36 37 #define FORMERR 1 34 38 #define SERVFAIL 2 35 39 #define NXDOMAIN 3 36 40 #define NOTIMP 4 -
src/iodine.c
old new 48 48 static char *__progname; 49 49 #endif 50 50 51 extern int forced_userid; 52 extern void set_qtype(char *); 53 extern void set_downenc(char *); 54 51 55 static void 52 56 sighandler(int sig) 53 57 { … … 59 63 extern char *__progname; 60 64 61 65 fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] " 62 "[-P password] [-m maxfragsize] [- z context] [-F pidfile] "66 "[-P password] [-m maxfragsize] [-U userid] [-T type] [-O enc] [-z context] [-F pidfile] " 63 67 "[nameserver] topdomain\n", __progname); 64 68 exit(2); 65 69 } … … 70 74 71 75 fprintf(stderr, "iodine IP over DNS tunneling client\n"); 72 76 fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] " 73 "[-P password] [-m maxfragsize] [- z context] [-F pidfile] "77 "[-P password] [-m maxfragsize] [-U userid] [-T type] [-O enc] [-z context] [-F pidfile] " 74 78 "[nameserver] topdomain\n", __progname); 75 79 fprintf(stderr, " -v to print version info and exit\n"); 76 80 fprintf(stderr, " -h to print this help and exit\n"); … … 81 85 fprintf(stderr, " -d device to set tunnel device name\n"); 82 86 fprintf(stderr, " -P password used for authentication (max 32 chars will be used)\n"); 83 87 fprintf(stderr, " -m maxfragsize, to limit size of downstream packets\n"); 88 fprintf(stderr, " -U force userid (=IP address) on server, exit if unavailable\n"); 89 fprintf(stderr, " -T dns type: NULL (default, fastest), TXT, CNAME, A (CNAME answer), MX\n"); 90 fprintf(stderr, " -O downstream encoding (!NULL): Base32(default), Base64, or Raw (only TXT)\n"); 84 91 fprintf(stderr, " -z context, to apply specified SELinux context after initialization\n"); 85 92 fprintf(stderr, " -F pidfile to write pid to a file\n"); 86 93 fprintf(stderr, "nameserver is the IP number of the relaying nameserver, if absent /etc/resolv.conf is used\n"); … … 131 138 #endif 132 139 username = NULL; 133 140 memset(password, 0, 33); 141 srand(time(NULL)); 134 142 foreground = 0; 135 143 newroot = NULL; 136 144 context = NULL; … … 157 165 __progname++; 158 166 #endif 159 167 160 while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:F: ")) != -1) {168 while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:F:U:T:O:")) != -1) { 161 169 switch(choice) { 162 170 case 'v': 163 171 version(); … … 198 206 case 'F': 199 207 pidfile = optarg; 200 208 break; 209 case 'U': 210 forced_userid = atoi(optarg); 211 if (forced_userid < 0) 212 forced_userid = -1; 213 break; 214 case 'T': 215 set_qtype(optarg); 216 #if 0 217 if (!strcasecmp(optarg, "NULL")) 218 do_qtype = T_NULL; 219 else if (!strcasecmp(optarg, "CNAME")) 220 do_qtype = T_CNAME; 221 else if (!strcasecmp(optarg, "A")) 222 do_qtype = T_A; 223 else if (!strcasecmp(optarg, "MX")) 224 do_qtype = T_MX; 225 else if (!strcasecmp(optarg, "TXT")) 226 do_qtype = T_TXT; 227 #endif 228 break; 229 case 'O': /* not -D, is Debug in server */ 230 set_downenc(optarg); 231 #if 0 232 if (!strcasecmp(optarg, "base32")) 233 downenc = 'T'; 234 else if (!strcasecmp(optarg, "base64")) 235 downenc = 'S'; 236 else if (!strcasecmp(optarg, "raw")) 237 downenc = 'R'; 238 #endif 239 break; 201 240 default: 202 241 usage(); 203 242 /* NOTREACHED */ … … 232 271 if (nameserv_addr) { 233 272 client_set_nameserver(nameserv_addr); 234 273 } else { 274 warnx("No nameserver found - not connected to any network?\n"); 235 275 usage(); 236 276 /* NOTREACHED */ 237 277 } -
src/client.c
old new 14 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 15 */ 16 16 17 #include <ctype.h> 17 18 #include <stdio.h> 18 19 #include <stdint.h> 19 20 #include <stdlib.h> … … 75 76 76 77 /* My userid at the server */ 77 78 static char userid; 79 int forced_userid = -1; 78 80 79 81 /* DNS id for next packet */ 80 82 static uint16_t chunkid; 81 83 82 84 /* Base32 encoder used for non-data packets */ 83 85 static struct encoder *b32; 86 static struct encoder *b64; 84 87 85 88 /* The encoder used for data packets 86 89 * Defaults to Base32, can be changed after handshake */ 87 90 static struct encoder *dataenc; 88 91 92 static char downenc = ' '; 93 94 /* set query type to send */ 95 static unsigned short do_qtype = T_NULL; 96 89 97 /* My connection mode */ 90 98 static enum connection conn; 91 99 … … 99 107 downstream_fragment = 0; 100 108 down_ack_seqno = 0; 101 109 down_ack_fragment = 0; 102 chunkid = 0;110 chunkid = ((unsigned int) rand()) & 0xFFFF; 103 111 b32 = get_base32_encoder(); 112 b64 = get_base64_encoder(); 104 113 dataenc = get_base32_encoder(); 105 rand_seed = rand();114 rand_seed = ((unsigned int) rand()) & 0xFFFF; 106 115 conn = CONN_DNS_NULL; 107 116 } 108 117 … … 157 166 struct query q; 158 167 size_t len; 159 168 160 q.id = ++chunkid; 161 q.type = T_NULL; 169 chunkid += 7727; 170 if (chunkid == 0) 171 /* 0 is used as "no-query" in iodined.c */ 172 chunkid = 7727; 173 174 q.id = chunkid; 175 q.type = do_qtype; 162 176 163 177 len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, hostname, strlen(hostname)); 178 if (len < 1) { 179 warnx("dns_encode doesn't fit"); 180 return; 181 } 164 182 165 183 sendto(fd, packet, len, 0, (struct sockaddr*)&nameserv, sizeof(nameserv)); 166 184 } … … 208 226 encsize = encoder->encode(buf, &space, data, datalen); 209 227 210 228 if (!encoder->places_dots()) 211 inline_dotify(buf, buflen );229 inline_dotify(buf, buflen, 57); 212 230 231 /* Add dot (if it wasn't there already) and topdomain */ 213 232 b = buf; 214 233 b += strlen(buf); 215 234 … … 241 260 static void 242 261 send_chunk(int fd) 243 262 { 244 char hex[] = "0123456789 ABCDEF";263 char hex[] = "0123456789abcdef"; 245 264 char buf[4096]; 246 265 int avail; 247 266 int code; … … 295 314 296 315 rand_seed++; 297 316 298 send_packet(fd, ' P', data, sizeof(data));317 send_packet(fd, 'p', data, sizeof(data)); 299 318 } else { 300 319 send_raw(fd, NULL, 0, userid, RAW_HDR_CMD_PING); 301 320 } … … 322 341 323 342 rv = dns_decode(buf, buflen, &q, QR_ANSWER, data, r); 324 343 344 if ((q.type == T_CNAME || q.type == T_MX || q.type == T_TXT) 345 && rv >= 1) 346 /* CNAME an also be returned from an A (or MX) question */ 347 { 348 size_t space; 349 350 /* 351 * buf is a hostname or txt stream that we still need to 352 * decode to binary 353 * 354 * also update rv with the number of valid bytes 355 * 356 * data is unused here, and will certainly hold the smaller binary 357 */ 358 359 switch (buf[0]) { 360 case 'h': /* Hostname with base32 */ 361 case 'H': 362 if (rv < 5) { 363 /* 1 byte H, 3 bytes ".xy", >=1 byte data */ 364 rv = 0; 365 break; 366 } 367 368 rv -= 3; /* rv=strlen, strip ".xy" */ 369 rv = unpack_data (data, sizeof(data), buf + 1, rv - 1, b32); 370 /* this also does undotify */ 371 372 rv = MIN(rv, buflen); 373 memcpy(buf, data, rv); 374 break; 375 case 'i': /* Hostname++ with base64 */ 376 case 'I': 377 if (rv < 5) { 378 /* 1 byte H, 3 bytes ".xy", >=1 byte data */ 379 rv = 0; 380 break; 381 } 382 383 rv -= 3; /* rv=strlen, strip ".xy" */ 384 rv = unpack_data (data, sizeof(data), buf + 1, rv - 1, b64); 385 /* this also does undotify */ 386 387 rv = MIN(rv, buflen); 388 memcpy(buf, data, rv); 389 break; 390 case 't': /* plain base32(Thirty-two) from TXT */ 391 case 'T': 392 if (rv < 2) { 393 rv = 0; 394 break; 395 } 396 397 space = sizeof(data); 398 rv = b32->decode (data, &space, buf + 1, rv - 1); 399 rv = MIN(rv, buflen); 400 memcpy(buf, data, rv); 401 break; 402 case 's': /* plain base64(Sixty-four) from TXT */ 403 case 'S': 404 if (rv < 2) { 405 rv = 0; 406 break; 407 } 408 409 space = sizeof(data); 410 rv = b64->decode (data, &space, buf + 1, rv - 1); 411 rv = MIN(rv, buflen); 412 memcpy(buf, data, rv); 413 break; 414 case 'r': /* Raw binary from TXT */ 415 case 'R': 416 rv--; /* rv>=1 already checked */ 417 memmove(buf, buf+1, rv); 418 break; 419 default: 420 warnx("Received unsupported encoding"); 421 rv = 0; 422 break; 423 } 424 } 425 325 426 /* decode the data header, update seqno and frag before next request */ 326 427 if (rv >= 2) { 327 428 downstream_seqno = (buf[1] >> 5) & 7; … … 345 446 downstream_seqno != down_ack_seqno || 346 447 downstream_fragment != down_ack_fragment 347 448 )) { 348 449 349 450 send_ping(dns_fd); 350 451 } 351 452 } else { … … 521 622 522 623 rand_seed++; 523 624 524 send_packet(fd, ' L', data, sizeof(data));625 send_packet(fd, 'l', data, sizeof(data)); 525 626 } 526 627 527 628 static void … … 530 631 char probedata[256]; 531 632 char buf[4096]; 532 633 533 /* build a large query domain which is random and maximum size */ 534 memset(probedata, MIN(1, rand_seed & 0xff), sizeof(probedata)); 535 probedata[1] = MIN(1, (rand_seed >> 8) & 0xff); 634 /* 635 * build a large query domain which is random and maximum size, 636 * will also take up maximal space in the return packet 637 */ 638 memset(probedata, MAX(1, rand_seed & 0xff), sizeof(probedata)); 639 probedata[1] = MAX(1, (rand_seed >> 8) & 0xff); 536 640 rand_seed++; 537 641 build_hostname(buf + 4, sizeof(buf) - 4, probedata, sizeof(probedata), topdomain, dataenc); 538 642 … … 559 663 560 664 rand_seed++; 561 665 562 send_packet(fd, ' N', data, sizeof(data));666 send_packet(fd, 'n', data, sizeof(data)); 563 667 } 564 668 565 669 static void 566 670 send_version(int fd, uint32_t version) 567 671 { 568 char data[6]; 672 char data[7]; 673 int datalen; 569 674 570 675 data[0] = (version >> 24) & 0xff; 571 676 data[1] = (version >> 16) & 0xff; 572 677 data[2] = (version >> 8) & 0xff; 573 678 data[3] = (version >> 0) & 0xff; 574 679 575 data[4] = (rand_seed >> 8) & 0xff; 576 data[5] = (rand_seed >> 0) & 0xff; 680 if (forced_userid < 0) { 681 data[4] = (rand_seed >> 8) & 0xff; 682 data[5] = (rand_seed >> 0) & 0xff; 683 datalen = 6; 684 } else { 685 data[4] = (forced_userid + 1) & 0xff; 686 data[5] = (rand_seed >> 8) & 0xff; 687 data[6] = (rand_seed >> 0) & 0xff; 688 datalen = 7; 689 } 577 690 578 691 rand_seed++; 579 692 580 send_packet(fd, 'V', data, sizeof(data));693 send_packet(fd, 'V', data, datalen); 581 694 } 582 695 583 696 static void … … 619 732 static void 620 733 send_codec_switch(int fd, int userid, int bits) 621 734 { 622 char buf[512] = " S_____.";735 char buf[512] = "s_____."; 623 736 buf[1] = b32_5to8(userid); 624 737 buf[2] = b32_5to8(bits); 625 738 … … 631 744 strncat(buf, topdomain, 512 - strlen(buf)); 632 745 send_query(fd, buf); 633 746 } 747 748 749 static void 750 send_downenc_switch(int fd, int userid) 751 { 752 char buf[512] = "o_____."; 753 buf[1] = b32_5to8(userid); 754 buf[2] = tolower(downenc); 755 756 buf[3] = b32_5to8((rand_seed >> 10) & 0x1f); 757 buf[4] = b32_5to8((rand_seed >> 5) & 0x1f); 758 buf[5] = b32_5to8((rand_seed ) & 0x1f); 759 rand_seed++; 760 761 strncat(buf, topdomain, 512 - strlen(buf)); 762 send_query(fd, buf); 763 } 634 764 635 765 static int 636 766 handshake_version(int dns_fd, int *seed) … … 675 805 *seed = payload; 676 806 userid = in[8]; 677 807 808 if (forced_userid >= 0 && 809 (int) userid != forced_userid) { 810 warnx("Got userid %d instead of requested %d, probably old server version. Try again immediately.", (int) userid, forced_userid); 811 return 1; 812 } 813 678 814 fprintf(stderr, "Version ok, both using protocol v 0x%08x. You are user #%d\n", VERSION, userid); 679 815 return 0; 680 816 } else if (strncmp("VNAK", in, 4) == 0) { … … 682 818 VERSION, payload); 683 819 return 1; 684 820 } else if (strncmp("VFUL", in, 4) == 0) { 685 warnx("Server full, all %d slots are taken. Try again later", payload); 821 if (forced_userid >= 0) 822 warnx("Forced userid %d not available. Try again later.", forced_userid); 823 else 824 warnx("Server full, all %d slots are taken. Try again later", payload); 686 825 return 1; 687 826 } 688 827 } else … … 691 830 692 831 fprintf(stderr, "Retrying version check...\n"); 693 832 } 694 warnx("couldn't connect to server ");833 warnx("couldn't connect to server (maybe other -T options will work)"); 695 834 return 1; 696 835 } 697 836 … … 924 1063 int read; 925 1064 926 1065 dataenc = get_base64_encoder(); 927 fprintf(stderr, "Switching to %s codec\n", dataenc->name);1066 fprintf(stderr, "Switching upstream to %s codec\n", dataenc->name); 928 1067 /* Send to server that this user will use base64 from now on */ 929 1068 for (i=0; running && i<5 ;i++) { 930 1069 int bits; … … 955 1094 goto codec_revert; 956 1095 } 957 1096 in[read] = 0; /* zero terminate */ 958 fprintf(stderr, "Server switched to codec %s\n", in);1097 fprintf(stderr, "Server switched upstream to codec %s\n", in); 959 1098 return; 960 1099 } 961 1100 } … … 968 1107 dataenc = get_base32_encoder(); 969 1108 } 970 1109 1110 static void 1111 handshake_switch_downenc(int dns_fd) 1112 { 1113 struct timeval tv; 1114 char in[4096]; 1115 fd_set fds; 1116 int i; 1117 int r; 1118 int read; 1119 char *dname; 1120 1121 dname = "Base32"; 1122 if (downenc == 'S') 1123 dname = "Base64"; 1124 else if (downenc == 'R') 1125 dname = "Raw"; 1126 1127 fprintf(stderr, "Switching downstream to codec %s\n", dname); 1128 for (i=0; running && i<5 ;i++) { 1129 tv.tv_sec = i + 1; 1130 tv.tv_usec = 0; 1131 1132 send_downenc_switch(dns_fd, userid); 1133 1134 FD_ZERO(&fds); 1135 FD_SET(dns_fd, &fds); 1136 1137 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 1138 1139 if(r > 0) { 1140 read = read_dns(dns_fd, 0, in, sizeof(in)); 1141 1142 if (read > 0) { 1143 if (strncmp("BADLEN", in, 6) == 0) { 1144 fprintf(stderr, "Server got bad message length. "); 1145 goto codec_revert; 1146 } else if (strncmp("BADIP", in, 5) == 0) { 1147 fprintf(stderr, "Server rejected sender IP address. "); 1148 goto codec_revert; 1149 } else if (strncmp("BADCODEC", in, 8) == 0) { 1150 fprintf(stderr, "Server rejected the selected codec. "); 1151 goto codec_revert; 1152 } 1153 in[read] = 0; /* zero terminate */ 1154 fprintf(stderr, "Server switched downstream to codec %s\n", in); 1155 return; 1156 } 1157 } 1158 fprintf(stderr, "Retrying codec switch...\n"); 1159 } 1160 fprintf(stderr, "No reply from server on codec switch. "); 1161 1162 codec_revert: 1163 fprintf(stderr, "Falling back to base32\n"); 1164 } 1165 1166 1167 static int 1168 fragsize_check(char *in, int read, int proposed_fragsize, int *max_fragsize) 1169 /* Returns: 0: keep checking, 1: break loop (either okay or definitely wrong) */ 1170 { 1171 int acked_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff); 1172 static int nocheck_warned = 0; 1173 1174 if (read >= 5 && strncmp("BADIP", in, 5) == 0) { 1175 fprintf(stderr, "got BADIP (Try iodined -c)..\n"); 1176 fflush(stderr); 1177 return 0; /* maybe temporary error */ 1178 } 1179 1180 if (acked_fragsize != proposed_fragsize) { 1181 /* 1182 * got ack for wrong fragsize, maybe late response for 1183 * earlier query, or ack corrupted 1184 */ 1185 return 0; 1186 } 1187 1188 if (read != proposed_fragsize) { 1189 /* 1190 * correctly acked fragsize but read too little (or too 1191 * much): this fragsize is definitely not reliable 1192 */ 1193 return 1; 1194 } 1195 1196 /* here: read == proposed_fragsize == acked_fragsize */ 1197 1198 /* test: */ 1199 /* in[123] = 123; */ 1200 1201 /* Check for corruption */ 1202 if ((in[2] & 0xff) == 107) { 1203 int okay = 1; 1204 int i; 1205 unsigned int v = in[3] & 0xff; 1206 1207 for (i = 3; i < read; i++, v += 107) 1208 if ((in[i] & 0xff) != (v & 0xff)) { 1209 okay = 0; 1210 break; 1211 } 1212 1213 if (okay) { 1214 fprintf(stderr, "%d ok.. ", acked_fragsize); 1215 fflush(stderr); 1216 *max_fragsize = acked_fragsize; 1217 return 1; 1218 } else { 1219 if (downenc != ' ' && downenc != 'T') 1220 fprintf(stderr, "%d corrupted at %d.. (Try -O Base32)\n", acked_fragsize, i); 1221 else 1222 fprintf(stderr, "%d corrupted at %d.. ", acked_fragsize, i); 1223 fflush(stderr); 1224 return 1; 1225 } 1226 } /* always returns */ 1227 1228 /* here when uncheckable, so assume correct */ 1229 1230 if (read >= 3 && nocheck_warned == 0) { 1231 fprintf(stderr, "(Old server version, cannot check for corruption)\n"); 1232 fflush(stderr); 1233 nocheck_warned = 1; 1234 } 1235 fprintf(stderr, "%d ok.. ", acked_fragsize); 1236 fflush(stderr); 1237 *max_fragsize = acked_fragsize; 1238 return 1; 1239 } 1240 1241 971 1242 static int 972 1243 handshake_autoprobe_fragsize(int dns_fd) 973 1244 { … … 979 1250 int read; 980 1251 int proposed_fragsize = 768; 981 1252 int range = 768; 982 int max_fragsize = 0;1253 int max_fragsize; 983 1254 984 1255 max_fragsize = 0; 985 1256 fprintf(stderr, "Autoprobing max downstream fragment size... (skip with -m fragsize)\n"); 986 while (running && range > 0 && (range >= 8 || !max_fragsize)) { 1257 while (running && range > 0 && (range >= 8 || max_fragsize < 300)) { 1258 /* stop the slow probing early when we have enough bytes anyway */ 987 1259 for (i=0; running && i<3 ;i++) { 988 1260 tv.tv_sec = 1; 989 1261 tv.tv_usec = 0; … … 994 1266 995 1267 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 996 1268 997 if(r > 0) {1269 if(r >= 2) { 998 1270 read = read_dns(dns_fd, 0, in, sizeof(in)); 999 1271 1000 1272 if (read > 0) { 1001 1273 /* We got a reply */ 1002 int acked_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff); 1003 if (acked_fragsize == proposed_fragsize) { 1004 if (read == proposed_fragsize) { 1005 fprintf(stderr, "%d ok.. ", acked_fragsize); 1006 fflush(stderr); 1007 max_fragsize = acked_fragsize; 1008 } 1009 } 1010 if (strncmp("BADIP", in, 5) == 0) { 1011 fprintf(stderr, "got BADIP.. "); 1012 fflush(stderr); 1013 } 1014 break; 1274 if (fragsize_check(in, read, proposed_fragsize, &max_fragsize) == 1) 1275 break; 1015 1276 } 1016 1277 } 1017 1278 fprintf(stderr, "."); … … 1030 1291 } 1031 1292 if (!running) { 1032 1293 fprintf(stderr, "\n"); 1033 warnx("stopped while autodetecting fragment size (Try probing manually with -m)");1294 warnx("stopped while autodetecting fragment size (Try setting manually with -m)"); 1034 1295 return 0; 1035 1296 } 1036 if ( range == 0) {1297 if (max_fragsize <= 2) { 1037 1298 /* Tried all the way down to 2 and found no good size */ 1038 1299 fprintf(stderr, "\n"); 1039 warnx("found no accepted fragment size. (Try probing manually with -m)");1300 warnx("found no accepted fragment size. (Try forcing with -m, or try other -T or -O options)"); 1040 1301 return 0; 1041 1302 } 1042 fprintf(stderr, "will use %d\n", max_fragsize); 1043 return max_fragsize; 1303 /* data header adds 2 bytes */ 1304 fprintf(stderr, "will use %d-2=%d\n", max_fragsize, max_fragsize - 2); 1305 1306 if (do_qtype != T_NULL && downenc == ' ') 1307 fprintf(stderr, "(Maybe other -O options will increase throughput)\n"); 1308 1309 return max_fragsize - 2; 1044 1310 } 1045 1311 1046 1312 static void … … 1117 1383 handshake_switch_codec(dns_fd); 1118 1384 } 1119 1385 1386 if (downenc != ' ') { 1387 handshake_switch_downenc(dns_fd); 1388 } 1389 1120 1390 if (autodetect_frag_size) { 1121 1391 fragsize = handshake_autoprobe_fragsize(dns_fd); 1122 1392 if (!fragsize) { … … 1130 1400 return 0; 1131 1401 } 1132 1402 1403 void 1404 set_qtype(char *qtype) 1405 { 1406 if (!strcasecmp(qtype, "NULL")) 1407 do_qtype = T_NULL; 1408 else if (!strcasecmp(qtype, "CNAME")) 1409 do_qtype = T_CNAME; 1410 else if (!strcasecmp(qtype, "A")) 1411 do_qtype = T_A; 1412 else if (!strcasecmp(qtype, "MX")) 1413 do_qtype = T_MX; 1414 else if (!strcasecmp(qtype, "TXT")) 1415 do_qtype = T_TXT; 1416 } 1417 1418 void 1419 set_downenc(char *encoding) 1420 { 1421 if (!strcasecmp(encoding, "base32")) 1422 downenc = 'T'; 1423 else if (!strcasecmp(encoding, "base64")) 1424 downenc = 'S'; 1425 else if (!strcasecmp(encoding, "raw")) 1426 downenc = 'R'; 1427 } -
src/iodined.c
old new 69 69 static char *topdomain; 70 70 static char password[33]; 71 71 static struct encoder *b32; 72 static struct encoder *b64; 72 73 static int created_users; 73 74 74 75 static int check_ip; … … 86 87 #endif 87 88 88 89 static int read_dns(int, int, struct query *); 89 static void write_dns(int, struct query *, char *, int );90 static void write_dns(int, struct query *, char *, int, char); 90 91 static void handle_full_packet(int, int); 91 92 92 93 static void … … 120 121 if (userid < 0 || userid >= created_users ) { 121 122 return 1; 122 123 } 123 if (!users[userid].active) { 124 if (!users[userid].active || users[userid].disabled || 125 users[userid].last_pkt + 60 < now) { 124 126 return 1; 125 127 } 126 128 if (users[userid].last_pkt + 60 < time(NULL)) { … … 226 228 out[7] = ((payload) & 0xff); 227 229 out[8] = userid & 0xff; 228 230 229 write_dns(fd, q, out, sizeof(out) );231 write_dns(fd, q, out, sizeof(out), users[userid].downenc); 230 232 } 231 233 232 234 static void … … 271 273 users[userid].outpacket.seqno & 7, users[userid].outpacket.fragment & 15, 272 274 last, users[userid].outpacket.offset, datalen, users[userid].outpacket.len, userid); 273 275 } 274 write_dns(dns_fd, &users[userid].q, pkt, datalen + 2 );276 write_dns(dns_fd, &users[userid].q, pkt, datalen + 2, users[userid].downenc); 275 277 users[userid].q.id = 0; 276 278 277 279 if (users[userid].outpacket.len > 0 && … … 339 341 if(in[0] == 'V' || in[0] == 'v') { 340 342 int version = 0; 341 343 344 int forced_userid = -1; 342 345 read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), domain_len - 1, b32); 343 346 /* Version greeting, compare and send ack/nak */ 344 347 if (read > 4) { … … 348 351 ((unpacked[2] & 0xff) << 8) | 349 352 ((unpacked[3] & 0xff))); 350 353 } 354 if (read >= 7) { 355 /* Received V + 32bits version + 8bits userid + 16bits CMC */ 356 forced_userid = unpacked[4]; 357 forced_userid--; 358 } 351 359 352 360 if (version == VERSION) { 353 userid = find_available_user( );361 userid = find_available_user(forced_userid); 354 362 if (userid >= 0) { 355 363 struct sockaddr_in *tempin; 356 364 … … 361 369 362 370 memcpy(&(users[userid].q), q, sizeof(struct query)); 363 371 users[userid].encoder = get_base32_encoder(); 372 users[userid].downenc = 'T'; 364 373 send_version_response(dns_fd, VERSION_ACK, users[userid].seed, userid, q); 365 374 syslog(LOG_INFO, "accepted version for user #%d from %s", 366 375 userid, inet_ntoa(tempin->sin_addr)); 367 376 users[userid].q.id = 0; 377 users[userid].outpacket.len = 0; 378 users[userid].outpacket.offset = 0; 379 users[userid].outpacket.sentlen = 0; 380 users[userid].outpacket.seqno = 0; 381 users[userid].outpacket.fragment = 0; 382 users[userid].inpacket.len = 0; 383 users[userid].inpacket.offset = 0; 384 users[userid].inpacket.seqno = 0; 385 users[userid].inpacket.fragment = 0; 386 users[userid].fragsize = 100; /* very safe */ 368 387 } else { 369 388 /* No space for another user */ 370 389 send_version_response(dns_fd, VERSION_FULL, created_users, 0, q); 371 syslog(LOG_INFO, "dropped user from %s, server full", 372 inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr)); 390 if (forced_userid != -1) 391 syslog(LOG_INFO, "dropped user from %s, forced userid %d not available", 392 inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr), forced_userid); 393 else 394 syslog(LOG_INFO, "dropped user from %s, server full", 395 inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr)); 373 396 } 374 397 } else { 375 398 send_version_response(dns_fd, VERSION_NACK, VERSION, 0, q); … … 383 406 userid = unpacked[0]; 384 407 385 408 if (check_user_and_ip(userid, q) != 0) { 386 write_dns(dns_fd, q, "BADIP", 5 );409 write_dns(dns_fd, q, "BADIP", 5, 'T'); 387 410 syslog(LOG_WARNING, "dropped login request from user #%d from unexpected source %s", 388 411 userid, inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr)); 389 412 return; 390 413 } else { 391 users[userid].last_pkt = time(NULL);414 users[userid].last_pkt = now; 392 415 login_calculate(logindata, 16, password, users[userid].seed); 393 416 394 417 if (read >= 18 && (memcmp(logindata, unpacked+1, 16) == 0)) { … … 402 425 read = snprintf(out, sizeof(out), "%s-%s-%d-%d", 403 426 tmp[0], tmp[1], my_mtu, netmask); 404 427 405 write_dns(dns_fd, q, out, read );428 write_dns(dns_fd, q, out, read, users[userid].downenc); 406 429 q->id = 0; 407 430 syslog(LOG_NOTICE, "accepted password from user #%d, given IP %s", userid, tmp[1]); 408 431 409 432 free(tmp[1]); 410 433 free(tmp[0]); 411 434 } else { 412 write_dns(dns_fd, q, "LNAK", 4 );435 write_dns(dns_fd, q, "LNAK", 4, 'T'); 413 436 syslog(LOG_WARNING, "rejected login request from user #%d from %s, bad password", 414 437 userid, inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr)); 415 438 } … … 423 446 424 447 userid = b32_8to5(in[1]); 425 448 if (check_user_and_ip(userid, q) != 0) { 426 write_dns(dns_fd, q, "BADIP", 5 );449 write_dns(dns_fd, q, "BADIP", 5, 'T'); 427 450 return; /* illegal id */ 428 451 } 429 452 … … 441 464 reply[2] = (addr >> 16) & 0xFF; 442 465 reply[3] = (addr >> 8) & 0xFF; 443 466 reply[4] = (addr >> 0) & 0xFF; 444 write_dns(dns_fd, q, reply, sizeof(reply) );467 write_dns(dns_fd, q, reply, sizeof(reply), 'T'); 445 468 } else if(in[0] == 'Z' || in[0] == 'z') { 446 469 /* Check for case conservation and chars not allowed according to RFC */ 447 470 448 471 /* Reply with received hostname as data */ 449 write_dns(dns_fd, q, in, domain_len); 472 /* No userid here, reply with lowest-grade downenc */ 473 write_dns(dns_fd, q, in, domain_len, 'T'); 450 474 return; 451 475 } else if(in[0] == 'S' || in[0] == 's') { 452 476 int codec; 453 477 struct encoder *enc; 454 478 if (domain_len < 3) { /* len at least 3, example: "S15" */ 455 write_dns(dns_fd, q, "BADLEN", 6 );479 write_dns(dns_fd, q, "BADLEN", 6, 'T'); 456 480 return; 457 481 } 458 482 459 483 userid = b32_8to5(in[1]); 460 484 461 485 if (check_user_and_ip(userid, q) != 0) { 462 write_dns(dns_fd, q, "BADIP", 5 );486 write_dns(dns_fd, q, "BADIP", 5, 'T'); 463 487 return; /* illegal id */ 464 488 } 465 489 … … 469 493 case 5: /* 5 bits per byte = base32 */ 470 494 enc = get_base32_encoder(); 471 495 user_switch_codec(userid, enc); 472 write_dns(dns_fd, q, enc->name, strlen(enc->name) );496 write_dns(dns_fd, q, enc->name, strlen(enc->name), users[userid].downenc); 473 497 break; 474 498 case 6: /* 6 bits per byte = base64 */ 475 499 enc = get_base64_encoder(); 476 500 user_switch_codec(userid, enc); 477 write_dns(dns_fd, q, enc->name, strlen(enc->name)); 501 write_dns(dns_fd, q, enc->name, strlen(enc->name), users[userid].downenc); 502 break; 503 default: 504 write_dns(dns_fd, q, "BADCODEC", 8, users[userid].downenc); 505 break; 506 } 507 return; 508 } else if(in[0] == 'O' || in[0] == 'o') { 509 if (domain_len != 4) { /* len = 4, example: "O1T." */ 510 write_dns(dns_fd, q, "BADLEN", 6, 'T'); 511 return; 512 } 513 514 userid = b32_8to5(in[1]); 515 516 if (check_user_and_ip(userid, q) != 0) { 517 write_dns(dns_fd, q, "BADIP", 5, 'T'); 518 return; /* illegal id */ 519 } 520 521 switch (in[2]) { 522 case 'T': 523 case 't': 524 users[userid].downenc = 'T'; 525 write_dns(dns_fd, q, "Base32", 6, users[userid].downenc); 526 break; 527 case 'S': 528 case 's': 529 users[userid].downenc = 'S'; 530 write_dns(dns_fd, q, "Base64", 6, users[userid].downenc); 531 break; 532 case 'R': 533 case 'r': 534 users[userid].downenc = 'R'; 535 write_dns(dns_fd, q, "Raw", 3, users[userid].downenc); 478 536 break; 479 537 default: 480 write_dns(dns_fd, q, "BADCODEC", 8 );538 write_dns(dns_fd, q, "BADCODEC", 8, users[userid].downenc); 481 539 break; 482 540 } 483 541 return; … … 487 545 /* Downstream fragsize probe packet */ 488 546 userid = (b32_8to5(in[1]) >> 1) & 15; 489 547 if (check_user_and_ip(userid, q) != 0) { 490 write_dns(dns_fd, q, "BADIP", 5 );548 write_dns(dns_fd, q, "BADIP", 5, 'T'); 491 549 return; /* illegal id */ 492 550 } 493 551 494 552 req_frag_size = ((b32_8to5(in[1]) & 1) << 10) | ((b32_8to5(in[2]) & 31) << 5) | (b32_8to5(in[3]) & 31); 495 553 if (req_frag_size < 2 || req_frag_size > 2047) { 496 write_dns(dns_fd, q, "BADFRAG", 7 );554 write_dns(dns_fd, q, "BADFRAG", 7, users[userid].downenc); 497 555 } else { 498 556 char buf[2048]; 557 int i; 558 unsigned int v = (unsigned int) rand(); 499 559 500 560 memset(buf, 0, sizeof(buf)); 501 561 buf[0] = (req_frag_size >> 8) & 0xff; 502 562 buf[1] = req_frag_size & 0xff; 503 write_dns(dns_fd, q, buf, req_frag_size); 563 /* make checkable pseudo-random sequence */ 564 buf[2] = 107; 565 for (i = 3; i < 2048; i++, v += 107) 566 buf[i] = (char) (v & 0xff); 567 write_dns(dns_fd, q, buf, req_frag_size, users[userid].downenc); 504 568 } 505 569 return; 506 570 } else if(in[0] == 'N' || in[0] == 'n') { … … 510 574 /* Downstream fragsize packet */ 511 575 userid = unpacked[0]; 512 576 if (check_user_and_ip(userid, q) != 0) { 513 write_dns(dns_fd, q, "BADIP", 5 );577 write_dns(dns_fd, q, "BADIP", 5, 'T'); 514 578 return; /* illegal id */ 515 579 } 516 580 517 581 max_frag_size = ((unpacked[1] & 0xff) << 8) | (unpacked[2] & 0xff); 518 582 if (max_frag_size < 2) { 519 write_dns(dns_fd, q, "BADFRAG", 7 );583 write_dns(dns_fd, q, "BADFRAG", 7, users[userid].downenc); 520 584 } else { 521 585 users[userid].fragsize = max_frag_size; 522 write_dns(dns_fd, q, &unpacked[1], 2 );586 write_dns(dns_fd, q, &unpacked[1], 2, users[userid].downenc); 523 587 } 524 588 return; 525 589 } else if(in[0] == 'P' || in[0] == 'p') { … … 530 594 /* Ping packet, store userid */ 531 595 userid = unpacked[0]; 532 596 if (check_user_and_ip(userid, q) != 0) { 533 write_dns(dns_fd, q, "BADIP", 5 );597 write_dns(dns_fd, q, "BADIP", 5, 'T'); 534 598 return; /* illegal id */ 535 599 } 536 600 … … 546 610 dn_seq = unpacked[1] >> 4; 547 611 dn_frag = unpacked[1] & 15; 548 612 memcpy(&(users[userid].q), q, sizeof(struct query)); 549 users[userid].last_pkt = time(NULL);613 users[userid].last_pkt = now; 550 614 551 615 /* Update seqno and maybe send immediate response packet */ 552 616 update_downstream_seqno(dns_fd, userid, dn_seq, dn_frag); … … 565 629 userid = code; 566 630 /* Check user and sending ip number */ 567 631 if (check_user_and_ip(userid, q) != 0) { 568 write_dns(dns_fd, q, "BADIP", 5 );632 write_dns(dns_fd, q, "BADIP", 5, 'T'); 569 633 } else { 570 634 /* Decode data header */ 571 635 int up_seq = (b32_8to5(in[1]) >> 2) & 7; … … 580 644 } 581 645 582 646 /* Update query and time info for user */ 583 users[userid].last_pkt = time(NULL);647 users[userid].last_pkt = now; 584 648 memcpy(&(users[userid].q), q, sizeof(struct query)); 585 649 586 650 if (up_seq == users[userid].inpacket.seqno && … … 638 702 } 639 703 640 704 len = dns_encode_ns_response(buf, sizeof(buf), q, topdomain); 705 if (len < 1) { 706 warnx("dns_encode_ns_response doesn't fit"); 707 return; 708 } 641 709 642 710 if (debug >= 2) { 643 711 struct sockaddr_in *tempin; … … 660 728 in_addr_t newaddr; 661 729 662 730 len = dns_encode(buf, sizeof(buf), q, QR_QUERY, q->name, strlen(q->name)); 731 if (len < 1) { 732 warnx("dns_encode doesn't fit"); 733 return; 734 } 663 735 664 736 /* Store sockaddr for q->id */ 665 737 memcpy(&(fwq.addr), &(q->from), q->fromlen); … … 756 828 757 829 if (inside_topdomain) { 758 830 /* This is a query we can handle */ 831 759 832 switch (q.type) { 760 833 case T_NULL: 834 case T_CNAME: 835 case T_A: 836 case T_MX: 837 case T_TXT: 838 /* encoding is "transparent" here */ 761 839 handle_null_request(tun_fd, dns_fd, &q, domain_len); 762 840 break; 763 841 case T_NS: … … 782 860 fd_set fds; 783 861 int i; 784 862 863 now = time(NULL); 864 785 865 while (running) { 786 866 int maxfd; 787 867 if (users_waiting_on_reply()) { … … 810 890 } 811 891 812 892 i = select(maxfd + 1, &fds, NULL, NULL, &tv); 893 894 now = time(NULL); 813 895 814 896 if(i < 0) { 815 897 if (running) … … 1045 1127 } 1046 1128 1047 1129 static void 1048 write_dns(int fd, struct query *q, char *data, int datalen )1130 write_dns(int fd, struct query *q, char *data, int datalen, char downenc) 1049 1131 { 1050 1132 char buf[64*1024]; 1051 int len; 1133 int len = 0; 1134 1135 if (q->type == T_CNAME || q->type == T_A || q->type == T_MX) { 1136 static int td1 = 0; 1137 static int td2 = 0; 1138 char cnamebuf[1024]; /* max 255 */ 1139 size_t space; 1140 char *b; 1141 1142 /* Make a rotating topdomain to prevent filtering */ 1143 td1+=3; 1144 td2+=7; 1145 if (td1>=26) td1-=26; 1146 if (td2>=25) td2-=25; 1147 1148 /* encode data,datalen to CNAME/MX answer */ 1149 /* (adapted from build_hostname() in iodine.c) */ 1150 1151 space = MIN(0xFF, sizeof(cnamebuf)) - 4 - 2; 1152 /* -1 encoding type, -3 ".xy", -2 for safety */ 1153 1154 memset(cnamebuf, 0, sizeof(cnamebuf)); 1155 1156 if (downenc == 'S') { 1157 cnamebuf[0] = 'I'; 1158 if (!b64->places_dots()) 1159 space -= (space / 57); /* space for dots */ 1160 b64->encode(cnamebuf+1, &space, data, datalen); 1161 if (!b64->places_dots()) 1162 inline_dotify(cnamebuf, sizeof(cnamebuf), 57); 1163 } else { 1164 cnamebuf[0] = 'H'; 1165 if (!b32->places_dots()) 1166 space -= (space / 57); /* space for dots */ 1167 b32->encode(cnamebuf+1, &space, data, datalen); 1168 if (!b32->places_dots()) 1169 inline_dotify(cnamebuf, sizeof(cnamebuf), 57); 1170 } 1171 1172 /* Add dot (if it wasn't there already) and topdomain */ 1173 b = cnamebuf; 1174 b += strlen(cnamebuf); 1175 if (*b != '.') 1176 *b++ = '.'; 1177 1178 *b = 'a' + td1; 1179 b++; 1180 *b = 'a' + td2; 1181 b++; 1182 *b = '\0'; 1183 1184 len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, cnamebuf, sizeof(cnamebuf)); 1185 } 1186 else if (q->type == T_TXT) { 1187 /* TXT with base32 */ 1188 char txtbuf[64*1024]; 1189 size_t space = sizeof(txtbuf) - 1;; 1190 1191 memset(txtbuf, 0, sizeof(txtbuf)); 1192 1193 if (downenc == 'S') { 1194 txtbuf[0] = 'S'; /* plain base64(Sixty-four) */ 1195 len = b64->encode(txtbuf+1, &space, data, datalen); 1196 } 1197 else if (downenc == 'R') { 1198 txtbuf[0] = 'R'; /* Raw binary data */ 1199 len = MIN(datalen, sizeof(txtbuf) - 1); 1200 memcpy(txtbuf + 1, data, len); 1201 } else { 1202 txtbuf[0] = 'T'; /* plain base32(Thirty-two) */ 1203 len = b32->encode(txtbuf+1, &space, data, datalen); 1204 } 1205 len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, txtbuf, len+1); 1206 } else { 1207 /* Normal NULL-record encode */ 1208 len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, data, datalen); 1209 } 1052 1210 1053 len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, data, datalen); 1211 if (len < 1) { 1212 warnx("dns_encode doesn't fit"); 1213 return; 1214 } 1054 1215 1055 1216 if (debug >= 2) { 1056 1217 struct sockaddr_in *tempin; … … 1167 1328 pidfile = NULL; 1168 1329 1169 1330 b32 = get_base32_encoder(); 1331 b64 = get_base64_encoder(); 1170 1332 1171 1333 retval = 0; 1172 1334 -
src/user.c
old new 39 39 #include "user.h" 40 40 41 41 struct user users[USERS]; 42 time_t now = 0; /* set in iodined.c after select() */ 42 43 43 44 int 44 45 init_users(in_addr_t my_ip, int netbits) … … 83 84 users[i].disabled = 0; 84 85 created_users++; 85 86 } 87 users[i].active = 0; 86 88 users[i].inpacket.len = 0; 87 89 users[i].inpacket.offset = 0; 88 90 users[i].outpacket.len = 0; … … 104 106 105 107 ret = 0; 106 108 for (i = 0; i < USERS; i++) { 107 if (users[i].active && !users[i].disabled && 108 users[i].last_pkt + 60 > time(NULL)&&109 if (users[i].active && !users[i].disabled && 110 users[i].last_pkt + 60 > now && 109 111 users[i].q.id != 0 && users[i].conn == CONN_DNS_NULL) { 110 112 ret++; 111 113 } … … 123 125 ret = -1; 124 126 for (i = 0; i < USERS; i++) { 125 127 if (users[i].active && !users[i].disabled && 126 users[i].last_pkt + 60 > time(NULL)&&128 users[i].last_pkt + 60 > now && 127 129 ip == users[i].tun_ip) { 128 130 ret = i; 129 131 break; … … 135 137 int 136 138 all_users_waiting_to_send() 137 139 { 138 time_t now;139 140 int ret; 140 141 int i; 141 142 142 143 ret = 1; 143 now = time(NULL);144 144 for (i = 0; i < USERS; i++) { 145 145 if (users[i].active && !users[i].disabled && 146 146 users[i].last_pkt + 60 > now && … … 155 155 } 156 156 157 157 int 158 find_available_user( )158 find_available_user(int forced_userid) 159 159 { 160 160 int ret = -1; 161 161 int i; 162 163 if (forced_userid != -1) { 164 if (forced_userid < 0 || forced_userid >= USERS) 165 return -1; 166 167 if ((users[forced_userid].active && 168 users[forced_userid].last_pkt + 60 > now) || 169 users[forced_userid].disabled) 170 return -1; 171 172 users[forced_userid].active = 1; 173 users[forced_userid].last_pkt = now; 174 175 return forced_userid; 176 } 177 162 178 for (i = 0; i < USERS; i++) { 163 179 /* Not used at all or not used in one minute */ 164 if ((!users[i].active || users[i].last_pkt + 60 < time(NULL)) && !users[i].disabled) {180 if ((!users[i].active || users[i].last_pkt + 60 < now) && !users[i].disabled) { 165 181 users[i].active = 1; 166 users[i].last_pkt = time(NULL);182 users[i].last_pkt = now; 167 183 users[i].fragsize = 4096; 168 184 users[i].conn = CONN_DNS_NULL; 169 185 ret = i; -
README
old new 90 90 So your domain name and subdomain should be as short as possible to allow 91 91 maximum upstream throughput. 92 92 93 The default is to use DNS NULL-type queries, as this provides the largest 94 downstream bandwidth. If your DNS server blocks NULL requests, try TXT or 95 CNAME queries via the -T option. Also supported are A (returning CNAME) and 96 MX requests, but these may/will cause additional lookups by "smart" caching 97 nameservers to get an actual IP address, which may either slow down or fail 98 completely. DNS responses for non-NULL are Base32 encoded by default, which 99 should always work. For more bandwidth, try Base64 or Raw (TXT only) via the 100 -O option. If Base64/Raw doesn't work, you'll see many failures in the 101 fragment size autoprobe. 102 103 If you have problems, try inspecting the traffic with network monitoring tools 104 and make sure that the relaying DNS server has not cached the response. A 105 cached error message could mean that you started the client before the server. 106 93 107 94 108 TIPS & TRICKS: 95 109 … … 99 113 iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to :5353 100 114 (Sent in by Tom Schouten) 101 115 116 Iodined will reject data from clients that have not been active (data/pings) 117 for more than 60 seconds. In case of a long network outage or similar, just 118 stop iodine and restart (re-login), possibly multiple times until you get 119 your old IP address back. Once that's done, just wait a while, and you'll 120 eventually see the tunneled TCP traffic continue to flow from where it left 121 off before the outage. Use iodine -U to force getting a specific IP address. 122 102 123 103 124 PORTABILITY: 104 125 -
new file doc/proto_00000502.txt
- + 1 Detailed specification of protocol in version 00000501 2 ====================================================== 3 4 Note: work in progress!! 5 6 ====================================================== 7 1. DNS protocol 8 ====================================================== 9 10 CMC = 2 byte Cache Miss Counter, increased every time it is used 11 12 Version: 13 Client sends: 14 First byte v or V 15 Rest encoded with base32: 16 4 bytes big endian protocol version 17 Optional: 1 byte forced userid + 1: 0 = dynamically assigned userid; 18 1 = force userid 0; etc (ignored by earlier server versions) 19 CMC 20 Server replies: 21 4 chars: 22 VACK (version ok), followed by login challenge 23 VNAK (version differs), followed by server protocol version 24 VFUL (server has no free slots or forced userid not available), 25 followed by max users 26 4 byte value: means login challenge/server protocol version/max users 27 1 byte userid of the new user, or any byte if not VACK 28 29 Login: 30 Client sends: 31 First byte l or L 32 Rest encoded with base32: 33 1 byte userid 34 16 bytes MD5 hash of: (first 32 bytes of password) xor (8 repetitions of login challenge) 35 CMC 36 Server replies: 37 LNAK means not accepted 38 x.x.x.x-y.y.y.y-mtu-netmask means accepted (server ip, client ip, mtu, netmask bits) 39 40 IP Request: 41 Client sends: 42 First byte i or I 43 5 bits coded as Base32 char, meaning userid 44 CMC 45 Server replies 46 BADIP if bad userid, or 47 I and then 4 bytes network order external IP address of iodined server 48 49 Case check: 50 Client sends: 51 First byte z or Z 52 Lots of data that should not be decoded 53 Server replies: 54 The requested domain copied raw 55 56 Switch codec: 57 Client sends: 58 First byte s or S 59 5 bits coded as Base32 char, meaning userid 60 5 bits coded as Base32 char, with value 5 or 6, representing number of raw 61 bits per encoded byte 62 CMC 63 Server sends: 64 Name of codec if accepted. After this all upstream data packets must 65 be encoded with the new codec. 66 BADCODEC if not accepted. Client must then revert to Base32 67 BADLEN if length of query is too short 68 69 Options: 70 Client sends: 71 First byte o or O 72 5 bits coded as Base32 char, meaning userid 73 1 char, meaning option 74 Server sends: 75 Full name of option if accepted. After this, option immediately takes 76 effect in server. 77 BADCODEC if not accepted. Previous situation remains. 78 All options affect only the requesting client. 79 80 Option chars: 81 t or T: Downstream encoding Base32, for TXT/CNAME/A/MX (default) 82 s or S: Downstream encoding Base64, for TXT/CNAME/A/MX 83 r or R: Downstream encoding Raw, for TXT/NULL (default for NULL) 84 If codec unsupported for request type, server will use Base32; note 85 that server will answer any mix of request types that a client sends. 86 Server may disregard this option; client must always use the downstream 87 encoding type indicated in every downstream DNS packet. 88 89 Probe downstream fragment size: 90 Client sends: 91 First byte r or R 92 15 bits coded as 3 Base32 chars: UUUUF FFFFF FFFFF 93 meaning 4 bits userid, 11 bits fragment size 94 Then follows a long random query which contents does not matter 95 Server sends: 96 Requested number of bytes as a response. The first two bytes contains 97 the requested length. Rest of message can be any data. 98 BADFRAG if requested length not accepted. 99 100 Set downstream fragment size: 101 Client sends: 102 First byte n or N 103 Rest encoded with base32: 104 1 byte userid 105 2 bytes new downstream fragment size 106 CMC 107 Server sends: 108 2 bytes new downstream fragment size. After this all downstream 109 payloads will be max (fragsize + 2) bytes long. 110 BADFRAG if not accepted. 111 112 Data: 113 Upstream data header: 114 3210 432 10 43 210 4321 0 115 +----+---+--+--+---+----+-+ 116 |UUUU|SSS|FF|FF|DDD|GGGG|L| 117 +----+---+--+--+---+----+-+ 118 119 Downstream data header: 120 7 654 3210 765 4321 0 121 +-+---+----+---+----+-+ 122 |C|SSS|FFFF|DDD|GGGG|L| 123 +-+---+----+---+----+-+ 124 125 UUUU = Userid 126 L = Last fragment in packet flag 127 SS = Upstream packet sequence number 128 FFFF = Upstream fragment number 129 DDD = Downstream packet sequence number 130 GGGG = Downstream fragment number 131 C = Compression enabled for downstream packet 132 133 Upstream data packet starts with 1 byte ASCII hex coded user byte, then 3 bytes 134 Base32 encoded header, then comes the payload data, encoded with chosen codec. 135 136 Downstream data starts with 2 byte header. Then payload data, which may be 137 compressed. 138 139 In NULL responses, downstream data is always raw. In all other response types, 140 downstream data is encoded (see Options above). 141 Encoding type is indicated by 1 prefix char: 142 TXT: 143 End result is always DNS-chopped (series of len-prefixed strings 144 <=255 bytes) 145 t or T: Base32 encoded before chop, decoded after un-chop 146 s or S: Base64 encoded before chop, decoded after un-chop 147 r or R: Raw no encoding, only DNS-chop 148 CNAME/A/MX: 149 h or H: Hostname encoded with Base32 150 i or I: Hostname encoded with Base64 151 152 Ping: 153 Client sends: 154 First byte p or P 155 Rest encoded with Base32: 156 1 byte with 4 bits userid 157 1 byte with: 158 3 bits downstream seqno 159 4 bits downstream fragment 160 CMC 161 162 The server response to Ping and Data packets is a DNS NULL type response: 163 If server has nothing to send, data length is 0 bytes. 164 If server has something to send, it will send a downstream data packet, 165 prefixed with 2 bytes header as shown above. 166 167 168 ====================================================== 169 2. Raw UDP protocol 170 ====================================================== 171 172 All Raw UDP protcol messages start with a 3 byte header: 0x10d19e 173 This is not the start of a valid DNS message so it is easy to identify. 174 The fourth byte contains the command and the user id. 175 176 7654 3210 177 +----+----+ 178 |CCCC|UUUU| 179 +----+----+ 180 181 Login message (command = 1): 182 The header is followed by a MD5 hash with the same password as in the DNS 183 login. The client starts the raw mode by sending this message, and uses 184 the login challenge +1, and the server responds using the login challenge -1. 185 After the login message has been exchanged, both the server and the client 186 switch to raw udp mode for the rest of the connection. 187 188 Data message (command = 2): 189 After the header comes the payload data, which may be compressed. 190 191 Ping message (command = 3): 192 Sent from client to server and back to keep session open. Has no payload. 193 -
man/iodine.8
old new 13 13 .I password 14 14 .B ] [-m 15 15 .I fragsize 16 .B ] [-U 17 .I userid 18 .B ] [-T 19 .I dnstype 20 .B ] [-O 21 .I downenc 16 22 .B ] [-t 17 23 .I chrootdir 18 24 .B ] [-d … … 46 52 .B ] [-p 47 53 .I port 48 54 .B ] [-n 49 .I external ip55 .I external_ip 50 56 .B ] [-b 51 57 .I dnsport 52 58 .B ] [-P … … 111 117 will be sent to the server instead of the DNS relay. 112 118 .TP 113 119 .B -m fragsize 114 Maximum downstream fragsize. Not setting this will cause the client to probe 115 the maximum accepted downstream packet size. 120 Force maximum downstream fragsize. Not setting this will cause the 121 client to automatically probe the maximum accepted downstream fragment size. 122 .TP 123 .B -U userid 124 Force userid on server, to get predictable IP address. Userid is 0 \- 15 125 on current servers, or less if server is started with small subnet. 126 Normally, userids are dynamically assigned from 0 upwards; suggestion for 127 static userids is to use from 15 downwards. 128 .TP 129 .B -T dnstype 130 DNS request type. 131 .I NULL 132 is default. If this doesn't work, try 133 .I TXT 134 (some less bandwidth) or 135 .I CNAME 136 (much less bandwidth). Also supported are 137 .I A 138 (returning CNAME) and 139 .I MX 140 requests, but these may/will cause additional lookups by "smart" caching 141 nameservers to get an actual IP address, which may either slow down or fail 142 completely. 143 .TP 144 .B -O downenc 145 Downstream encoding for all query type responses except NULL. 146 .I Base32 147 is default and should always work. 148 .I Base64 149 provides more bandwidth, but may not work on all nameservers. 150 For TXT queries, 151 .I Raw 152 will provide maximum performance. This will only work if the nameserver 153 +path is fully 8-bit-clean for responses that are assumed to be 154 "legible text". 116 155 .SS Server Options: 117 156 .TP 118 157 .B -c 119 Disable checks on client IP on all incoming requests. 158 Disable checking the client IP on all incoming requests. 159 By default, requests originating from non-matching IP adresses will be 160 rejected, however this will cause problems when requests are routed 161 via a cluster of DNS servers. 120 162 .TP 121 163 .B -s 122 Don't try to configure IP address or MTU. This should only be used if 164 Don't try to configure IP address and MTU for the tun device. 165 This should only be used if 123 166 you have already configured the device that will be used. 124 167 .TP 125 168 .B -D 126 169 Increase debug level. Level 1 prints info about each RX/TX packet. 170 Implies the 171 .B -f 172 option. 127 173 .TP 128 174 .B -m mtu 129 Set 'mtu' as mtu size for the tunnel device. This will be sent to the client 130 on connect, and the client will use the same mtu. 175 Set 'mtu' as mtu size for the tun device. This will be sent to the client 176 on login, and the client will use the same mtu for its tun device. 177 Default 1200. 178 Note that the DNS traffic will be automatically fragmented when needed. 131 179 .TP 132 180 .B -l listen_ip 133 Make the server listen only on 'listen_ip' instead of on 0.0.0.0 for incoming134 connections.181 Make the server listen only on 'listen_ip' for incoming requests. 182 By default, incoming requests are accepted from all interfaces. 135 183 .TP 136 184 .B -p port 137 185 Make the server listen on 'port' instead of 53 for traffic. 138 186 .B Note: 139 187 You must make sure the dns requests are forwarded to this port yourself. 140 188 .TP 141 .B -n external ip189 .B -n external_ip 142 190 The IP address to return in NS responses. Default is to return the address used 143 191 as destination in the query. 144 192 .TP 145 193 .B -b dnsport 146 194 If this port is specified, all incoming requests not inside the tunnel domain 147 195 will be forwarded to this port on localhost, to be handled by a real dns. 196 .B Note: 197 The forwarding is not fully transparent, and not advised for use 198 in production environments. 148 199 .SS Client Arguments: 149 200 .TP 150 201 .B nameserver … … 156 207 file. 157 208 .TP 158 209 .B topdomain 159 The dns traffic will be sent as quer ys of type NULLfor subdomains under210 The dns traffic will be sent as queries for subdomains under 160 211 \'topdomain'. This is normally a subdomain to a domain you own. Use a short 161 212 domain name to get better throughput. If 162 213 .B nameserver … … 165 216 .SS Server Arguments: 166 217 .TP 167 218 .B tunnel_ip[/netmask] 168 This is the server s ip address on the tunnelinterface. The client will be219 This is the server's ip address on the tun interface. The client will be 169 220 given the next ip number in the range. It is recommended to use the 170 221 10.0.0.0 or 172.16.0.0 ranges. The default netmask is /27, can be overriden 171 222 by specifying it here. Using a smaller network will limit the number of 172 223 concurrent users. 173 224 .TP 174 225 .B topdomain 175 The dns traffic will is expected to be sent as querys of type NULL for226 The dns traffic is expected to arrive as querys for 176 227 subdomains under 'topdomain'. This is normally a subdomain to a domain you 177 228 own. Use a short domain name to get better throughput. This argument must be 178 the same on both the client and the server. 229 the same on both the client and the server. Queries for domains other 230 than 'topdomain' will be forwarded if the \-b option is given, otherwise 231 they will be dropped. 179 232 .SH EXAMPLES 180 233 .SS Quickstart: 181 234 .TP … … 254 307 .B MTU issues: 255 308 These issues should be solved now, with automatic fragmentation of downstream 256 309 packets. There should be no need to set the MTU explicitly on the server. 310 .SH SECURITY 311 Login is a relatively secure challenge-response MD5 hash, with the 312 password never passing the wire. 313 However, all other data is 314 .B NOT 315 encrypted in any way. The DNS traffic is also vulnerable to replay, 316 injection and man-in-the-middle attacks, especially when iodined is used 317 with the \-c option. Use of ssh or vpn tunneling is strongly recommended. 318 On both server and client, use 319 .I iptables 320 to block all traffic coming in from the tun interfaces, 321 except to the used ssh or vpn ports. 257 322 .SH ENVIRONMENT 258 323 .SS IODINE_PASS 259 324 If the environment variable … … 272 337 .El 273 338 .SH BUGS 274 339 File bugs at http://dev.kryo.se/iodine/ 340 .SH SEE ALSO 341 The README file in the source distribution contains some more elaborate 342 information. 275 343 .SH AUTHORS 276 344 Erik Ekman <yarrick@kryo.se> and Bjorn Andersson <flex@kryo.se>
