Changeset 3c4860
- Timestamp:
- 09/20/09 23:10:44 (3 years ago)
- Branches:
- master
- Children:
- 85104a
- Parents:
- d59733
- git-author:
- J. A. Bezemer <J.A.Bezemer@…> (09/20/09 23:10:44)
- git-committer:
- Erik Ekman <erik@…> (02/04/12 20:34:04)
- Location:
- src
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
src/client.c
r92b160 r3c4860 52 52 #include "client.h" 53 53 54 #define PING_TIMEOUT(t) ((t) >= (conn == CONN_DNS_NULL ? 1 : 20)) 54 static void handshake_lazyoff(int dns_fd); 55 55 56 56 static int running; … … 62 62 63 63 static uint16_t rand_seed; 64 static int downstream_seqno;65 static int downstream_fragment;66 static int down_ack_seqno;67 static int down_ack_fragment;68 64 69 65 /* Current up/downstream IP packet */ 70 66 static struct packet outpkt; 71 67 static struct packet inpkt; 68 int outchunkresent = 0; 72 69 73 70 /* My userid at the server */ 74 71 static char userid; 72 static char userid_char; /* used when sending (uppercase) */ 73 static char userid_char2; /* also accepted when receiving (lowercase) */ 75 74 76 75 /* DNS id for next packet */ 77 76 static uint16_t chunkid; 77 static uint16_t chunkid_prev; 78 static uint16_t chunkid_prev2; 78 79 79 80 /* Base32 encoder used for non-data packets and replies */ … … 95 96 static enum connection conn; 96 97 98 int selecttimeout; /* RFC says timeout minimum 5sec */ 99 100 int lazymode; 101 102 long send_ping_soon; 103 104 time_t lastdownstreamtime; 105 97 106 void 98 107 client_init() 99 108 { 100 109 running = 1; 101 outpkt.seqno = 0;102 inpkt.len = 0;103 downstream_seqno = 0;104 downstream_fragment = 0;105 down_ack_seqno = 0;106 down_ack_fragment = 0;107 chunkid = ((unsigned int) rand()) & 0xFFFF;108 110 b32 = get_base32_encoder(); 109 111 b64 = get_base64_encoder(); 110 112 dataenc = get_base32_encoder(); 111 113 rand_seed = ((unsigned int) rand()) & 0xFFFF; 114 send_ping_soon = 1; /* send ping immediately after startup */ 112 115 conn = CONN_DNS_NULL; 116 117 chunkid = ((unsigned int) rand()) & 0xFFFF; 118 chunkid_prev = 0; 119 chunkid_prev2 = 0; 120 121 outpkt.len = 0; 122 outpkt.seqno = 0; 123 outpkt.fragment = 0; 124 outchunkresent = 0; 125 inpkt.len = 0; 126 inpkt.seqno = 0; 127 inpkt.fragment = 0; 113 128 } 114 129 … … 177 192 } 178 193 194 void 195 client_set_selecttimeout(int select_timeout) 196 { 197 selecttimeout = select_timeout; 198 } 199 200 void 201 client_set_lazymode(int lazy_mode) { 202 lazymode = lazymode; 203 } 204 179 205 const char * 180 206 client_get_raw_addr() … … 190 216 size_t len; 191 217 218 chunkid_prev2 = chunkid_prev; 219 chunkid_prev = chunkid; 192 220 chunkid += 7727; 193 221 if (chunkid == 0) … … 230 258 { 231 259 send_raw(dns_fd, outpkt.data, outpkt.len, userid, RAW_HDR_CMD_DATA); 260 outpkt.len = 0; 232 261 } 233 262 … … 244 273 } 245 274 246 static in t275 static inline int 247 276 is_sending() 248 277 { … … 253 282 send_chunk(int fd) 254 283 { 255 char hex[] = "0123456789abcdef";256 284 char buf[4096]; 257 285 int avail; … … 267 295 /* Build upstream data header (see doc/proto_xxxxxxxx.txt) */ 268 296 269 buf[0] = hex[userid & 15]; /* First byte is 4 bitsuserid */270 297 buf[0] = userid_char; /* First byte is hex userid */ 298 271 299 code = ((outpkt.seqno & 7) << 2) | ((outpkt.fragment & 15) >> 2); 272 300 buf[1] = b32_5to8(code); /* Second byte is 3 bits seqno, 2 upper bits fragment count */ 273 301 274 code = ((outpkt.fragment & 3) << 3) | ( downstream_seqno & 7);302 code = ((outpkt.fragment & 3) << 3) | (inpkt.seqno & 7); 275 303 buf[2] = b32_5to8(code); /* Third byte is 2 bits lower fragment count, 3 bits downstream packet seqno */ 276 304 277 code = (( downstream_fragment & 15) << 1) | (outpkt.sentlen == avail);305 code = ((inpkt.fragment & 15) << 1) | (outpkt.sentlen == avail); 278 306 buf[3] = b32_5to8(code); /* Fourth byte is 4 bits downstream fragment count, 1 bit last frag flag */ 279 280 down_ack_seqno = downstream_seqno; 281 down_ack_fragment = downstream_fragment; 282 283 outpkt.fragment++; 307 308 #if 0 309 fprintf(stderr, " Send: down %d/%d up %d/%d, %d bytes\n", 310 inpkt.seqno, inpkt.fragment, outpkt.seqno, outpkt.fragment, 311 outpkt.sentlen); 312 #endif 313 284 314 send_query(fd, buf); 285 315 } … … 291 321 char data[4]; 292 322 293 if (is_sending()) {294 outpkt.sentlen = 0;295 outpkt.offset = 0;296 outpkt.len = 0;297 }298 299 323 data[0] = userid; 300 data[1] = (( downstream_seqno & 7) << 4) | (downstream_fragment & 15);324 data[1] = ((inpkt.seqno & 7) << 4) | (inpkt.fragment & 15); 301 325 data[2] = (rand_seed >> 8) & 0xff; 302 326 data[3] = (rand_seed >> 0) & 0xff; 303 327 304 down_ack_seqno = downstream_seqno;305 down_ack_fragment = downstream_fragment;306 307 328 rand_seed++; 329 330 #if 0 331 fprintf(stderr, " Send: down %d/%d (ping)\n", 332 inpkt.seqno, inpkt.fragment); 333 #endif 308 334 309 335 send_packet(fd, 'p', data, sizeof(data)); … … 314 340 315 341 static int 316 read_dns (int dns_fd, int tun_fd, char *buf, int buflen) /* FIXME: tun_fd needed for raw handling */342 read_dns_withq(int dns_fd, int tun_fd, char *buf, int buflen, struct query *q) /* FIXME: tun_fd needed for raw handling */ 317 343 { 318 344 struct sockaddr_in from; 319 345 char data[64*1024]; 320 346 socklen_t addrlen; 321 struct query q;322 347 int r; 323 348 324 349 addrlen = sizeof(struct sockaddr); 325 350 if ((r = recvfrom(dns_fd, data, sizeof(data), 0, 326 (struct sockaddr*)&from, &addrlen)) == -1) {351 (struct sockaddr*)&from, &addrlen)) < 0) { 327 352 warn("recvfrom"); 328 return 0;353 return -1; 329 354 } 330 355 331 356 if (conn == CONN_DNS_NULL) { 332 357 int rv; 333 334 rv = dns_decode(buf, buflen, &q, QR_ANSWER, data, r); 335 336 if ((q.type == T_CNAME || q.type == T_MX || q.type == T_TXT) 337 && rv >= 1) 358 if (r <= 0) 359 /* useless packet */ 360 return 0; 361 362 rv = dns_decode(buf, buflen, q, QR_ANSWER, data, r); 363 if (rv <= 0) 364 return rv; 365 366 if (q->type == T_CNAME || q->type == T_MX || q->type == T_TXT) 338 367 /* CNAME an also be returned from an A (or MX) question */ 339 368 { … … 416 445 } 417 446 418 /* decode the data header, update seqno and frag before next request */419 if (rv >= 2) {420 downstream_seqno = (buf[1] >> 5) & 7;421 downstream_fragment = (buf[1] >> 1) & 15;422 }423 424 425 if (is_sending()) {426 if (chunkid == q.id) {427 /* Got ACK on sent packet */428 outpkt.offset += outpkt.sentlen;429 if (outpkt.offset == outpkt.len) {430 /* Packet completed */431 outpkt.offset = 0;432 outpkt.len = 0;433 outpkt.sentlen = 0;434 435 /* If the ack contains unacked frag number but no data,436 * send a ping to ack the frag number and get more data*/437 if (rv == 2 && (438 downstream_seqno != down_ack_seqno ||439 downstream_fragment != down_ack_fragment440 )) {441 442 send_ping(dns_fd);443 }444 } else {445 /* More to send */446 send_chunk(dns_fd);447 }448 }449 }450 447 return rv; 451 448 } else { /* CONN_RAW_UDP */ … … 471 468 } 472 469 470 static inline int 471 read_dns_namecheck(int dns_fd, int tun_fd, char *buf, int buflen, char c1, char c2) 472 /* Only returns >0 when the query hostname in the received packet matches 473 either c1 or c2; used to tell handshake-dupes apart. 474 */ 475 { 476 struct query q; 477 int rv; 478 479 rv = read_dns_withq(dns_fd, tun_fd, buf, buflen, &q); 480 481 if (rv > 0 && q.name[0] != c1 && q.name[0] != c2) 482 return 0; 483 484 return rv; /* may also be 0 = useless or -1 = error (printed) */ 485 } 473 486 474 487 static int … … 484 497 return -1; 485 498 499 /* We may be here only to empty the tun device; then return -1 500 to force continue in select loop. */ 501 if (is_sending()) 502 return -1; 503 486 504 outlen = sizeof(out); 487 505 inlen = read; … … 491 509 outpkt.sentlen = 0; 492 510 outpkt.offset = 0; 511 outpkt.seqno = (outpkt.seqno + 1) & 7; 493 512 outpkt.len = outlen; 494 outpkt.seqno++;495 513 outpkt.fragment = 0; 514 outchunkresent = 0; 496 515 497 516 if (conn == CONN_DNS_NULL) { 498 517 send_chunk(dns_fd); 518 519 send_ping_soon = 0; 499 520 } else { 500 521 send_raw_data(dns_fd); … … 507 528 tunnel_dns(int tun_fd, int dns_fd) 508 529 { 530 static long packrecv = 0; 531 static long packrecv_oos = 0; 532 int up_ack_seqno; 533 int up_ack_fragment; 534 int new_down_seqno; 535 int new_down_fragment; 536 struct query q; 509 537 unsigned long datalen; 510 538 char buf[64*1024]; 511 size_t read; 512 513 if ((read = read_dns(dns_fd, tun_fd, buf, sizeof(buf))) <= 2) 514 return -1; 515 516 if (downstream_seqno != inpkt.seqno) { 517 /* New packet */ 518 inpkt.seqno = downstream_seqno; 519 inpkt.fragment = downstream_fragment; 539 int read; 540 int send_something_now = 0; 541 542 if ((read = read_dns_withq(dns_fd, tun_fd, buf, sizeof(buf), &q)) < 2) { 543 /* Maybe SERVFAIL etc. Send ping to get things back in order, 544 but wait a bit to prevent fast ping-pong loops. */ 545 send_ping_soon = 900; 546 return -1; /* nothing done */ 547 } 548 549 /* Don't process anything that isn't data; already checked read>=2 */ 550 if (q.name[0] != 'P' && q.name[0] != 'p' && 551 q.name[0] != userid_char && q.name[0] != userid_char2) 552 return -1; /* nothing done */ 553 554 if (read == 5 && !strncmp("BADIP", buf, 5)) { 555 warnx("BADIP: Server rejected sender IP address (maybe iodined -c will help), or server kicked us due to timeout. Will exit if no downstream data is received in 60 seconds."); 556 return -1; /* nothing done */ 557 } 558 559 560 if (send_ping_soon) { 561 send_something_now = 1; 562 send_ping_soon = 0; 563 } 564 565 566 /* Decode the data header, update seqno and frag; 567 already checked read>=2 568 Note that buf[] gets overwritten when down-pkt complete */ 569 new_down_seqno = (buf[1] >> 5) & 7; 570 new_down_fragment = (buf[1] >> 1) & 15; 571 up_ack_seqno = (buf[0] >> 4) & 7; 572 up_ack_fragment = buf[0] & 15; 573 574 #if 0 575 fprintf(stderr, " Recv: down %d/%d up %d/%d, %d bytes\n", 576 new_down_seqno, new_down_fragment, up_ack_seqno, 577 up_ack_fragment, read); 578 #endif 579 580 /* Downstream data traffic */ 581 582 if (read > 2 && new_down_seqno != inpkt.seqno && 583 recent_seqno(inpkt.seqno, new_down_seqno)) { 584 /* This is the previous seqno, or a bit earlier. 585 Probably out-of-sequence dupe due to unreliable 586 intermediary DNS. Don't get distracted, but send 587 ping quickly to get things back in order. 588 Ping will send our current seqno idea. 589 If it's really a new packet that skipped multiple seqnos 590 (why??), server will re-send and drop a few times and 591 eventually everything will work again. */ 592 read = 2; 593 send_ping_soon = 500; 594 /* Still process upstream ack, if any */ 595 } 596 597 packrecv++; 598 599 /* Don't process any non-recent stuff any further */ 600 if (q.id != chunkid && q.id != chunkid_prev && q.id != chunkid_prev2) { 601 packrecv_oos++; 602 #if 0 603 fprintf(stderr, " q=%c Packs received = %8ld Out-of-sequence = %8ld\n", q.name[0], packrecv, packrecv_oos); 604 #endif 605 if (lazymode && packrecv < 600 && packrecv_oos == 5) 606 warnx("Hmm, getting some out-of-sequence DNS replies. You may want to try -I1 or -L0 if you notice hiccups in the data traffic."); 607 if (lazymode && packrecv < 600 && packrecv_oos == 15) { 608 warnx("Your DNS server connection causes severe re-ordering of DNS traffic. Lazy mode doesn't work well here, switching off. Next time on this network, start with -L0."); 609 lazymode = 0; 610 selecttimeout = 1; 611 handshake_lazyoff(dns_fd); 612 } 613 614 if (send_something_now) { 615 send_ping(dns_fd); 616 send_ping_soon = 0; 617 } 618 return -1; /* nothing done */ 619 } 620 #if 0 621 fprintf(stderr, " q=%c Packs received = %8ld Out-of-sequence = %8ld\n", q.name[0], packrecv, packrecv_oos); 622 #endif 623 624 /* Okay, we have a recent downstream packet */ 625 lastdownstreamtime = time(NULL); 626 627 /* In lazy mode, we shouldn't get much replies to our most-recent 628 query, only during heavy data transfer. Except when severe packet 629 reordering occurs, such as opendns... Since this means the server 630 doesn't have any packets left, send one relatively fast (but not 631 too fast, to avoid runaway ping-pong loops..) */ 632 if (q.id == chunkid && lazymode) { 633 if (!send_ping_soon || send_ping_soon > 900) 634 send_ping_soon = 900; 635 } 636 637 if (read == 2 && new_down_seqno != inpkt.seqno && 638 !recent_seqno(inpkt.seqno, new_down_seqno)) { 639 /* This is a seqno that we didn't see yet, but it has 640 no data any more. Possible since iodined will send 641 fitting packs just once and not wait for ack. 642 Real data got lost, or will arrive shortly. 643 Update our idea of the seqno, and drop any waiting 644 old pack. Send ping to get things back on track. */ 645 inpkt.seqno = new_down_seqno; 646 inpkt.fragment = new_down_fragment; 520 647 inpkt.len = 0; 521 } else if (downstream_fragment <= inpkt.fragment) { 522 /* Duplicate fragment */ 523 return -1; 524 } 525 inpkt.fragment = downstream_fragment; 526 527 datalen = MIN(read - 2, sizeof(inpkt.data) - inpkt.len); 528 529 /* Skip 2 byte data header and append to packet */ 530 memcpy(&inpkt.data[inpkt.len], &buf[2], datalen); 531 inpkt.len += datalen; 532 533 if (buf[1] & 1) { /* If last fragment flag is set */ 534 /* Uncompress packet and send to tun */ 535 datalen = sizeof(buf); 536 if (uncompress((uint8_t*)buf, &datalen, (uint8_t*) inpkt.data, inpkt.len) == Z_OK) { 537 write_tun(tun_fd, buf, datalen); 538 } 539 inpkt.len = 0; 540 } 541 542 /* If we have nothing to send, send a ping to get more data */ 543 if (!is_sending()) 648 send_ping_soon = 500; 649 } 650 651 while (read > 2) { 652 /* "if" with easy exit */ 653 654 if (new_down_seqno != inpkt.seqno) { 655 /* New packet (and not dupe of recent; checked above) */ 656 /* Forget any old packet, even if incomplete */ 657 inpkt.seqno = new_down_seqno; 658 inpkt.fragment = new_down_fragment; /* hopefully 0 */ 659 inpkt.len = 0; 660 } else if (inpkt.fragment == 0 && new_down_fragment == 0 && 661 inpkt.len == 0) { 662 /* Weird situation: we probably got a no-data reply 663 for this seqno (see above), and the actual data 664 is following now. */ 665 /* okay, nothing to do here, just so that next else-if 666 doesn't trigger */ 667 } else if (new_down_fragment <= inpkt.fragment) { 668 /* Same packet but duplicate fragment, ignore. 669 If the server didn't get our ack for it, the next 670 ping or chunk will do that. */ 671 send_ping_soon = 500; 672 break; 673 } else if (new_down_fragment > inpkt.fragment + 1) { 674 /* Quite impossible. We missed a fragment, but the 675 server got our ack for it and is sending the next 676 fragment already. Don't handle it but let server 677 re-send and drop. */ 678 send_ping_soon = 500; 679 break; 680 } 681 inpkt.fragment = new_down_fragment; 682 683 datalen = MIN(read - 2, sizeof(inpkt.data) - inpkt.len); 684 685 /* we are here only when read > 2, so datalen "always" >=1 */ 686 687 /* Skip 2 byte data header and append to packet */ 688 memcpy(&inpkt.data[inpkt.len], &buf[2], datalen); 689 inpkt.len += datalen; 690 691 if (buf[1] & 1) { /* If last fragment flag is set */ 692 /* Uncompress packet and send to tun */ 693 /* RE-USES buf[] */ 694 datalen = sizeof(buf); 695 if (uncompress((uint8_t*)buf, &datalen, (uint8_t*) inpkt.data, inpkt.len) == Z_OK) { 696 write_tun(tun_fd, buf, datalen); 697 } 698 inpkt.len = 0; 699 /* Keep .seqno and .fragment as is, so that we won't 700 reassemble from duplicate fragments */ 701 } 702 703 /* Send anything to ack the received seqno/frag, and get more */ 704 if (inpkt.len == 0) { 705 /* was last frag; wait just a trifle because our 706 tun will probably return TCP-ack immediately. 707 5msec = 200 DNSreq/sec */ 708 send_ping_soon = 5; 709 } else { 710 /* server certainly has more data */ 711 send_something_now = 1; 712 } 713 714 break; 715 } 716 717 /* NOTE: buf[] was overwritten when down-packet complete */ 718 719 720 /* Upstream data traffic */ 721 722 if (is_sending()) { 723 /* already checked read>=2 */ 724 #if 0 725 fprintf(stderr, "Got ack for %d,%d - expecting %d,%d - id=%d cur=%d prev=%d prev2=%d\n", 726 up_ack_seqno, up_ack_fragment, outpkt.seqno, outpkt.fragment, 727 q.id, chunkid, chunkid_prev, chunkid_prev2); 728 #endif 729 730 if (up_ack_seqno == outpkt.seqno && 731 up_ack_fragment == outpkt.fragment) { 732 /* Okay, previously sent fragment has arrived */ 733 734 outpkt.offset += outpkt.sentlen; 735 if (outpkt.offset >= outpkt.len) { 736 /* Packet completed */ 737 outpkt.offset = 0; 738 outpkt.len = 0; 739 outpkt.sentlen = 0; 740 outchunkresent = 0; 741 742 /* Normally, server still has a query in queue, 743 but sometimes not. So send a ping. 744 (Comment this out and you'll see occasional 745 hiccups.) 746 But since the server often still has a 747 query and we can expect a TCP-ack returned 748 from our tun device quickly in many cases, 749 don't be too fast. 750 20msec still is 50 DNSreq/second... */ 751 if (!send_ping_soon || send_ping_soon > 20) 752 send_ping_soon = 20; 753 } else { 754 /* More to send */ 755 outpkt.fragment++; 756 outchunkresent = 0; 757 send_chunk(dns_fd); 758 send_ping_soon = 0; 759 send_something_now = 0; 760 } 761 } 762 /* else: Some wrong fragment has arrived, or old fragment is 763 acked again, mostly by ping responses. 764 Don't resend chunk, usually not needed; select loop will 765 re-send on timeout (1sec if is_sending()). */ 766 } 767 768 769 /* Send ping if we didn't send anything yet */ 770 if (send_something_now) { 544 771 send_ping(dns_fd); 545 772 send_ping_soon = 0; 773 } 774 546 775 return read; 547 776 } … … 554 783 int rv; 555 784 int i; 556 int seconds;557 785 558 786 rv = 0; 559 seconds = 0;787 lastdownstreamtime = time(NULL); 560 788 561 789 while (running) { 562 tv.tv_sec = 1;790 tv.tv_sec = selecttimeout; 563 791 tv.tv_usec = 0; 564 792 793 if (is_sending()) { 794 /* fast timeout for retransmits */ 795 tv.tv_sec = 1; 796 tv.tv_usec = 0; 797 } 798 799 if (send_ping_soon) { 800 tv.tv_sec = 0; 801 tv.tv_usec = send_ping_soon * 1000; 802 } 565 803 566 804 FD_ZERO(&fds); 567 if ((!is_sending()) || conn == CONN_RAW_UDP) { 805 if (!is_sending() || outchunkresent >= 2) { 806 /* If re-sending upstream data, chances are that 807 we're several seconds behind already and TCP 808 will start filling tun buffer with (useless) 809 retransmits. 810 Get up-to-date fast by simply dropping stuff, 811 that's what TCP is designed to handle. */ 568 812 FD_SET(tun_fd, &fds); 569 813 } … … 571 815 572 816 i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv); 817 818 if (lastdownstreamtime + 60 < time(NULL)) { 819 warnx("No downstream data received in 60 seconds, shutting down."); 820 running = 0; 821 } 573 822 574 823 if (running == 0) … … 578 827 err(1, "select"); 579 828 580 if (i == 0) { /* timeout */ 581 seconds++; 829 if (i == 0) { 830 /* timeout */ 831 if (is_sending()) { 832 /* Re-send current fragment; either frag 833 or ack probably dropped somewhere. 834 But problem: no cache-miss-counter, 835 so hostname will be identical. 836 Just drop whole packet after 3 retries, 837 and TCP retransmit will solve it. 838 NOTE: tun dropping above should be 839 >=(value_here - 1) */ 840 if (outchunkresent < 3) { 841 outchunkresent++; 842 send_chunk(dns_fd); 843 } else { 844 outpkt.offset = 0; 845 outpkt.len = 0; 846 outpkt.sentlen = 0; 847 outchunkresent = 0; 848 849 send_ping(dns_fd); 850 } 851 } else { 852 send_ping(dns_fd); 853 } 854 send_ping_soon = 0; 855 582 856 } else { 857 583 858 if (FD_ISSET(tun_fd, &fds)) { 584 seconds = 0;585 859 if (tunnel_tun(tun_fd, dns_fd) <= 0) 586 860 continue; 861 /* Returns -1 on error OR when quickly 862 dropping data in case of DNS congestion; 863 we need to _not_ do tunnel_dns() then. 864 If chunk sent, sets send_ping_soon=0. */ 587 865 } 588 866 if (FD_ISSET(dns_fd, &fds)) { … … 590 868 continue; 591 869 } 592 }593 594 if (PING_TIMEOUT(seconds)) {595 send_ping(dns_fd);596 seconds = 0;597 870 } 598 871 } … … 745 1018 send_query(fd, buf); 746 1019 } 747 1020 1021 static void 1022 send_lazy_switch(int fd, int userid) 1023 { 1024 char buf[512] = "o__."; 1025 buf[1] = b32_5to8(userid); 1026 1027 if (lazymode) 1028 buf[2] = 'l'; 1029 else 1030 buf[2] = 'i'; 1031 1032 strncat(buf, topdomain, 512 - strlen(buf)); 1033 send_query(fd, buf); 1034 } 1035 748 1036 static int 749 1037 handshake_version(int dns_fd, int *seed) 750 1038 { 1039 char hex[] = "0123456789abcdef"; 1040 char hex2[] = "0123456789ABCDEF"; 751 1041 struct timeval tv; 752 1042 char in[4096]; … … 769 1059 770 1060 if(r > 0) { 771 read = read_dns(dns_fd, 0, in, sizeof(in)); 772 773 if(read <= 0) { 774 if (read == 0) { 775 warn("handshake read"); 776 } 777 /* if read < 0 then warning has been printed already */ 1061 read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'v', 'V'); 1062 1063 if(read <= 0) 778 1064 continue; 779 }780 1065 781 1066 if (read >= 9) { … … 788 1073 *seed = payload; 789 1074 userid = in[8]; 1075 userid_char = hex[userid & 15]; 1076 userid_char2 = hex2[userid & 15]; 790 1077 791 1078 fprintf(stderr, "Version ok, both using protocol v 0x%08x. You are user #%d\n", VERSION, userid); … … 837 1124 838 1125 if(r > 0) { 839 read = read_dns(dns_fd, 0, in, sizeof(in)); 840 841 if(read <= 0) { 842 warn("read"); 1126 read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'l', 'L'); 1127 1128 if(read <= 0) 843 1129 continue; 844 }845 1130 846 1131 if (read > 0) { … … 899 1184 900 1185 if(r > 0) { 901 len = read_dns (dns_fd, 0, in, sizeof(in));1186 len = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'i', 'I'); 902 1187 if (len == 5 && in[0] == 'I') { 903 1188 /* Received IP address */ … … 992 1277 993 1278 if(r > 0) { 994 read = read_dns (dns_fd, 0, in, sizeof(in));1279 read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'z', 'Z'); 995 1280 996 1281 if (read > 0) { 997 if (in[0] == 'z' || in[0] == 'Z') { 998 if (read < (27 * 2)) { 999 fprintf(stderr, "Received short case check reply. Will use base32 encoder\n"); 1000 return case_preserved; 1001 } else { 1002 int k; 1003 1004 /* TODO enhance this, base128 is probably also possible */ 1005 case_preserved = 1; 1006 for (k = 0; k < 27 && case_preserved; k += 2) { 1007 if (in[k] == in[k+1]) { 1008 /* test string: zZ+-aAbBcCdDeE... */ 1009 case_preserved = 0; 1010 } 1282 if (read < (27 * 2)) { 1283 fprintf(stderr, "Received short case check reply. Will use base32 encoder\n"); 1284 return case_preserved; 1285 } else { 1286 int k; 1287 1288 /* TODO enhance this, base128 is probably also possible */ 1289 case_preserved = 1; 1290 for (k = 0; k < 27 && case_preserved; k += 2) { 1291 if (in[k] == in[k+1]) { 1292 /* test string: zZ+-aAbBcCdDeE... */ 1293 case_preserved = 0; 1011 1294 } 1012 return case_preserved;1013 1295 } 1014 } else { 1015 fprintf(stderr, "Received bad case check reply\n"); 1296 return case_preserved; 1016 1297 } 1017 1298 } else { … … 1056 1337 1057 1338 if(r > 0) { 1058 read = read_dns (dns_fd, 0, in, sizeof(in));1339 read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 's', 'S'); 1059 1340 1060 1341 if (read > 0) { … … 1113 1394 1114 1395 if(r > 0) { 1115 read = read_dns (dns_fd, 0, in, sizeof(in));1396 read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'o', 'O'); 1116 1397 1117 1398 if (read > 0) { … … 1139 1420 } 1140 1421 1422 static void 1423 handshake_try_lazy(int dns_fd) 1424 { 1425 struct timeval tv; 1426 char in[4096]; 1427 fd_set fds; 1428 int i; 1429 int r; 1430 int read; 1431 1432 fprintf(stderr, "Switching to lazy mode for low-latency\n"); 1433 for (i=0; running && i<3; i++) { 1434 tv.tv_sec = i + 1; 1435 tv.tv_usec = 0; 1436 1437 send_lazy_switch(dns_fd, userid); 1438 1439 FD_ZERO(&fds); 1440 FD_SET(dns_fd, &fds); 1441 1442 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 1443 1444 if(r > 0) { 1445 read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'o', 'O'); 1446 1447 if (read > 0) { 1448 if (strncmp("BADLEN", in, 6) == 0) { 1449 fprintf(stderr, "Server got bad message length. "); 1450 goto codec_revert; 1451 } else if (strncmp("BADIP", in, 5) == 0) { 1452 fprintf(stderr, "Server rejected sender IP address. "); 1453 goto codec_revert; 1454 } else if (strncmp("BADCODEC", in, 8) == 0) { 1455 fprintf(stderr, "Server rejected lazy mode. "); 1456 goto codec_revert; 1457 } else if (strncmp("Lazy", in, 4) == 0) { 1458 fprintf(stderr, "Server switched to lazy mode\n"); 1459 lazymode = 1; 1460 return; 1461 } 1462 } 1463 } 1464 fprintf(stderr, "Retrying lazy mode switch...\n"); 1465 } 1466 fprintf(stderr, "No reply from server on lazy switch, probably old server version. "); 1467 1468 codec_revert: 1469 fprintf(stderr, "Falling back to legacy mode\n"); 1470 lazymode = 0; 1471 selecttimeout = 1; 1472 } 1473 1474 static void 1475 handshake_lazyoff(int dns_fd) 1476 /* Used in the middle of data transfer, timing is different and no error msgs */ 1477 { 1478 struct timeval tv; 1479 char in[4096]; 1480 fd_set fds; 1481 int i; 1482 int r; 1483 int read; 1484 1485 for (i=0; running && i<5; i++) { 1486 tv.tv_sec = 0; 1487 tv.tv_usec = 500000; 1488 1489 send_lazy_switch(dns_fd, userid); 1490 1491 FD_ZERO(&fds); 1492 FD_SET(dns_fd, &fds); 1493 1494 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 1495 1496 if(r > 0) { 1497 read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'o', 'O'); 1498 1499 if (read > 0) { 1500 if (read == 4 && strncmp("Immediate", in, 9) == 0) { 1501 fprintf(stderr, "Server switched back to legacy mode.\n"); 1502 lazymode = 0; 1503 selecttimeout = 1; 1504 return; 1505 } 1506 } 1507 } 1508 } 1509 } 1141 1510 1142 1511 static int … … 1244 1613 1245 1614 if(r > 0) { 1246 read = read_dns (dns_fd, 0, in, sizeof(in));1615 read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'r', 'R'); 1247 1616 1248 1617 if (read > 0) { … … 1309 1678 1310 1679 if(r > 0) { 1311 read = read_dns (dns_fd, 0, in, sizeof(in));1680 read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'n', 'N'); 1312 1681 1313 1682 if (read > 0) { … … 1350 1719 if (raw_mode && handshake_raw_udp(dns_fd, seed)) { 1351 1720 conn = CONN_RAW_UDP; 1721 selecttimeout = 20; 1352 1722 } else { 1353 1723 if (raw_mode == 0) { … … 1362 1732 if (downenc != ' ') { 1363 1733 handshake_switch_downenc(dns_fd); 1734 } 1735 1736 if (lazymode) { 1737 handshake_try_lazy(dns_fd); 1364 1738 } 1365 1739 -
src/client.h
r55cfed r3c4860 29 29 void set_qtype(char *qtype); 30 30 void set_downenc(char *encoding); 31 void client_set_selecttimeout(int select_timeout); 32 void client_set_lazymode(int lazy_mode); 31 33 32 34 int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize); -
src/iodine.c
r55cfed r3c4860 62 62 63 63 fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] " 64 "[-P password] [-m maxfragsize] [-T type] [-O enc] [- z context] [-F pidfile] "65 "[ nameserver] topdomain\n", __progname);64 "[-P password] [-m maxfragsize] [-T type] [-O enc] [-L 0|1] [-I sec] " 65 "[-z context] [-F pidfile] [nameserver] topdomain\n", __progname); 66 66 exit(2); 67 67 } … … 73 73 fprintf(stderr, "iodine IP over DNS tunneling client\n"); 74 74 fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] " 75 "[-P password] [-m maxfragsize] [-T type] [-O enc] [- z context] [-F pidfile] "76 "[ nameserver] topdomain\n", __progname);75 "[-P password] [-m maxfragsize] [-T type] [-O enc] [-L 0|1] [-I sec] " 76 "[-z context] [-F pidfile] [nameserver] topdomain\n", __progname); 77 77 fprintf(stderr, " -v to print version info and exit\n"); 78 78 fprintf(stderr, " -h to print this help and exit\n"); … … 86 86 fprintf(stderr, " -T dns type: NULL (default, fastest), TXT, CNAME, A (CNAME answer), MX\n"); 87 87 fprintf(stderr, " -O downstream encoding (!NULL): Base32(default), Base64, or Raw (only TXT)\n"); 88 fprintf(stderr, " -L 1: try lazy mode for low-latency (default). 0: don't (implies -I1)\n"); 89 fprintf(stderr, " -I max interval between requests (default 4 sec) to prevent server timeouts\n"); 88 90 fprintf(stderr, " -z context, to apply specified SELinux context after initialization\n"); 89 91 fprintf(stderr, " -F pidfile to write pid to a file\n"); … … 128 130 int retval; 129 131 int raw_mode; 132 int lazymode; 133 int selecttimeout; 130 134 131 135 nameserv_addr = NULL; … … 147 151 retval = 0; 148 152 raw_mode = 1; 153 lazymode = 1; 154 selecttimeout = 4; 149 155 150 156 #ifdef WINDOWS32 … … 163 169 #endif 164 170 165 while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:F:T:O: ")) != -1) {171 while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:F:T:O:L:I:")) != -1) { 166 172 switch(choice) { 167 173 case 'v': … … 209 215 case 'O': /* not -D, is Debug in server */ 210 216 set_downenc(optarg); 217 break; 218 case 'L': 219 lazymode = atoi(optarg); 220 if (lazymode > 1) 221 lazymode = 1; 222 if (lazymode < 0) 223 lazymode = 0; 224 if (!lazymode) 225 selecttimeout = 1; 226 break; 227 case 'I': 228 selecttimeout = atoi(optarg); 229 if (selecttimeout < 1) 230 selecttimeout = 1; 211 231 break; 212 232 default: … … 261 281 } 262 282 283 client_set_selecttimeout(selecttimeout); 284 client_set_lazymode(lazymode); 263 285 client_set_topdomain(topdomain); 264 286
Note: See TracChangeset
for help on using the changeset viewer.
