Changeset 3c4860


Ignore:
Timestamp:
09/20/09 23:10:44 (3 years ago)
Author:
J. A. Bezemer <J.A.Bezemer@…>
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)
Message:

merge client code #76

Location:
src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/client.c

    r92b160 r3c4860  
    5252#include "client.h" 
    5353 
    54 #define PING_TIMEOUT(t) ((t) >= (conn == CONN_DNS_NULL ? 1 : 20)) 
     54static void handshake_lazyoff(int dns_fd); 
    5555 
    5656static int running; 
     
    6262 
    6363static 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; 
    6864 
    6965/* Current up/downstream IP packet */ 
    7066static struct packet outpkt; 
    7167static struct packet inpkt; 
     68int outchunkresent = 0; 
    7269 
    7370/* My userid at the server */ 
    7471static char userid; 
     72static char userid_char;                /* used when sending (uppercase) */ 
     73static char userid_char2;               /* also accepted when receiving (lowercase) */ 
    7574 
    7675/* DNS id for next packet */ 
    7776static uint16_t chunkid; 
     77static uint16_t chunkid_prev; 
     78static uint16_t chunkid_prev2; 
    7879 
    7980/* Base32 encoder used for non-data packets and replies */ 
     
    9596static enum connection conn; 
    9697 
     98int selecttimeout;              /* RFC says timeout minimum 5sec */ 
     99 
     100int lazymode; 
     101 
     102long send_ping_soon; 
     103 
     104time_t lastdownstreamtime; 
     105 
    97106void 
    98107client_init() 
    99108{ 
    100109        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; 
    108110        b32 = get_base32_encoder(); 
    109111        b64 = get_base64_encoder(); 
    110112        dataenc = get_base32_encoder(); 
    111113        rand_seed = ((unsigned int) rand()) & 0xFFFF; 
     114        send_ping_soon = 1;     /* send ping immediately after startup */ 
    112115        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; 
    113128} 
    114129 
     
    177192} 
    178193 
     194void  
     195client_set_selecttimeout(int select_timeout) 
     196{ 
     197        selecttimeout = select_timeout; 
     198} 
     199 
     200void 
     201client_set_lazymode(int lazy_mode) { 
     202        lazymode = lazymode; 
     203} 
     204 
    179205const char * 
    180206client_get_raw_addr() 
     
    190216        size_t len; 
    191217 
     218        chunkid_prev2 = chunkid_prev; 
     219        chunkid_prev = chunkid; 
    192220        chunkid += 7727; 
    193221        if (chunkid == 0) 
     
    230258{ 
    231259        send_raw(dns_fd, outpkt.data, outpkt.len, userid, RAW_HDR_CMD_DATA); 
     260        outpkt.len = 0; 
    232261} 
    233262 
     
    244273} 
    245274 
    246 static int 
     275static inline int 
    247276is_sending() 
    248277{ 
     
    253282send_chunk(int fd) 
    254283{ 
    255         char hex[] = "0123456789abcdef"; 
    256284        char buf[4096]; 
    257285        int avail; 
     
    267295        /* Build upstream data header (see doc/proto_xxxxxxxx.txt) */ 
    268296 
    269         buf[0] = hex[userid & 15]; /* First byte is 4 bits userid */ 
    270  
     297        buf[0] = userid_char;           /* First byte is hex userid */ 
     298   
    271299        code = ((outpkt.seqno & 7) << 2) | ((outpkt.fragment & 15) >> 2); 
    272300        buf[1] = b32_5to8(code); /* Second byte is 3 bits seqno, 2 upper bits fragment count */ 
    273301 
    274         code = ((outpkt.fragment & 3) << 3) | (downstream_seqno & 7); 
     302        code = ((outpkt.fragment & 3) << 3) | (inpkt.seqno & 7); 
    275303        buf[2] = b32_5to8(code); /* Third byte is 2 bits lower fragment count, 3 bits downstream packet seqno */ 
    276304 
    277         code = ((downstream_fragment & 15) << 1) | (outpkt.sentlen == avail); 
     305        code = ((inpkt.fragment & 15) << 1) | (outpkt.sentlen == avail); 
    278306        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 
    284314        send_query(fd, buf); 
    285315} 
     
    291321                char data[4]; 
    292322                 
    293                 if (is_sending()) { 
    294                         outpkt.sentlen = 0; 
    295                         outpkt.offset = 0; 
    296                         outpkt.len = 0; 
    297                 } 
    298  
    299323                data[0] = userid; 
    300                 data[1] = ((downstream_seqno & 7) << 4) | (downstream_fragment & 15); 
     324                data[1] = ((inpkt.seqno & 7) << 4) | (inpkt.fragment & 15); 
    301325                data[2] = (rand_seed >> 8) & 0xff; 
    302326                data[3] = (rand_seed >> 0) & 0xff; 
    303327                 
    304                 down_ack_seqno = downstream_seqno; 
    305                 down_ack_fragment = downstream_fragment; 
    306                  
    307328                rand_seed++; 
     329 
     330#if 0 
     331                fprintf(stderr, "  Send: down %d/%d         (ping)\n", 
     332                        inpkt.seqno, inpkt.fragment); 
     333#endif 
    308334 
    309335                send_packet(fd, 'p', data, sizeof(data)); 
     
    314340 
    315341static int 
    316 read_dns(int dns_fd, int tun_fd, char *buf, int buflen) /* FIXME: tun_fd needed for raw handling */ 
     342read_dns_withq(int dns_fd, int tun_fd, char *buf, int buflen, struct query *q) /* FIXME: tun_fd needed for raw handling */ 
    317343{ 
    318344        struct sockaddr_in from; 
    319345        char data[64*1024]; 
    320346        socklen_t addrlen; 
    321         struct query q; 
    322347        int r; 
    323348 
    324349        addrlen = sizeof(struct sockaddr); 
    325350        if ((r = recvfrom(dns_fd, data, sizeof(data), 0,  
    326                           (struct sockaddr*)&from, &addrlen)) == -1) { 
     351                          (struct sockaddr*)&from, &addrlen)) < 0) { 
    327352                warn("recvfrom"); 
    328                 return 0; 
     353                return -1; 
    329354        } 
    330355 
    331356        if (conn == CONN_DNS_NULL) { 
    332357                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) 
    338367                /* CNAME an also be returned from an A (or MX) question */ 
    339368                { 
     
    416445                } 
    417446 
    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_fragment 
    440                                                 )) { 
    441  
    442                                                 send_ping(dns_fd); 
    443                                         } 
    444                                 } else { 
    445                                         /* More to send */ 
    446                                         send_chunk(dns_fd); 
    447                                 } 
    448                         } 
    449                 } 
    450447                return rv; 
    451448        } else { /* CONN_RAW_UDP */ 
     
    471468} 
    472469 
     470static inline int 
     471read_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} 
    473486 
    474487static int 
     
    484497                return -1; 
    485498 
     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 
    486504        outlen = sizeof(out); 
    487505        inlen = read; 
     
    491509        outpkt.sentlen = 0; 
    492510        outpkt.offset = 0; 
     511        outpkt.seqno = (outpkt.seqno + 1) & 7; 
    493512        outpkt.len = outlen; 
    494         outpkt.seqno++; 
    495513        outpkt.fragment = 0; 
     514        outchunkresent = 0; 
    496515 
    497516        if (conn == CONN_DNS_NULL) { 
    498517                send_chunk(dns_fd); 
     518 
     519                send_ping_soon = 0; 
    499520        } else { 
    500521                send_raw_data(dns_fd); 
     
    507528tunnel_dns(int tun_fd, int dns_fd) 
    508529{ 
     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; 
    509537        unsigned long datalen; 
    510538        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; 
    520647                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) { 
    544771                send_ping(dns_fd); 
    545          
     772                send_ping_soon = 0; 
     773        } 
     774 
    546775        return read; 
    547776} 
     
    554783        int rv; 
    555784        int i; 
    556         int seconds; 
    557785 
    558786        rv = 0; 
    559         seconds = 0; 
     787        lastdownstreamtime = time(NULL); 
    560788 
    561789        while (running) { 
    562                 tv.tv_sec = 1; 
     790                tv.tv_sec = selecttimeout; 
    563791                tv.tv_usec = 0; 
    564792 
     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                } 
    565803 
    566804                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. */ 
    568812                        FD_SET(tun_fd, &fds); 
    569813                } 
     
    571815 
    572816                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                } 
    573822                 
    574823                if (running == 0) 
     
    578827                        err(1, "select"); 
    579828 
    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 
    582856                } else { 
     857 
    583858                        if (FD_ISSET(tun_fd, &fds)) { 
    584                                 seconds = 0; 
    585859                                if (tunnel_tun(tun_fd, dns_fd) <= 0) 
    586860                                        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. */ 
    587865                        } 
    588866                        if (FD_ISSET(dns_fd, &fds)) { 
     
    590868                                        continue; 
    591869                        }  
    592                 } 
    593  
    594                 if (PING_TIMEOUT(seconds)) { 
    595                         send_ping(dns_fd); 
    596                         seconds = 0; 
    597870                } 
    598871        } 
     
    7451018        send_query(fd, buf); 
    7461019} 
    747          
     1020 
     1021static void 
     1022send_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 
    7481036static int 
    7491037handshake_version(int dns_fd, int *seed) 
    7501038{ 
     1039        char hex[] = "0123456789abcdef"; 
     1040        char hex2[] = "0123456789ABCDEF"; 
    7511041        struct timeval tv; 
    7521042        char in[4096]; 
     
    7691059 
    7701060                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) 
    7781064                                continue; 
    779                         } 
    7801065 
    7811066                        if (read >= 9) { 
     
    7881073                                        *seed = payload; 
    7891074                                        userid = in[8]; 
     1075                                        userid_char = hex[userid & 15]; 
     1076                                        userid_char2 = hex2[userid & 15]; 
    7901077 
    7911078                                        fprintf(stderr, "Version ok, both using protocol v 0x%08x. You are user #%d\n", VERSION, userid); 
     
    8371124 
    8381125                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) 
    8431129                                continue; 
    844                         } 
    8451130 
    8461131                        if (read > 0) { 
     
    8991184 
    9001185                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'); 
    9021187                        if (len == 5 && in[0] == 'I') { 
    9031188                                /* Received IP address */ 
     
    9921277 
    9931278                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'); 
    9951280                         
    9961281                        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; 
    10111294                                                } 
    1012                                                 return case_preserved; 
    10131295                                        } 
    1014                                 } else { 
    1015                                         fprintf(stderr, "Received bad case check reply\n"); 
     1296                                        return case_preserved; 
    10161297                                } 
    10171298                        } else { 
     
    10561337 
    10571338                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'); 
    10591340                         
    10601341                        if (read > 0) { 
     
    11131394 
    11141395                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'); 
    11161397 
    11171398                        if (read > 0) { 
     
    11391420} 
    11401421 
     1422static void 
     1423handshake_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 
     1468codec_revert:  
     1469        fprintf(stderr, "Falling back to legacy mode\n"); 
     1470        lazymode = 0; 
     1471        selecttimeout = 1; 
     1472} 
     1473 
     1474static void 
     1475handshake_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} 
    11411510 
    11421511static int 
     
    12441613 
    12451614                        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'); 
    12471616                                 
    12481617                                if (read > 0) { 
     
    13091678 
    13101679                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'); 
    13121681                         
    13131682                        if (read > 0) { 
     
    13501719        if (raw_mode && handshake_raw_udp(dns_fd, seed)) { 
    13511720                conn = CONN_RAW_UDP; 
     1721                selecttimeout = 20; 
    13521722        } else { 
    13531723                if (raw_mode == 0) { 
     
    13621732                if (downenc != ' ') { 
    13631733                        handshake_switch_downenc(dns_fd); 
     1734                } 
     1735 
     1736                if (lazymode) { 
     1737                        handshake_try_lazy(dns_fd); 
    13641738                } 
    13651739 
  • src/client.h

    r55cfed r3c4860  
    2929void set_qtype(char *qtype); 
    3030void set_downenc(char *encoding); 
     31void client_set_selecttimeout(int select_timeout); 
     32void client_set_lazymode(int lazy_mode); 
    3133 
    3234int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize); 
  • src/iodine.c

    r55cfed r3c4860  
    6262 
    6363        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); 
    6666        exit(2); 
    6767} 
     
    7373        fprintf(stderr, "iodine IP over DNS tunneling client\n"); 
    7474        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); 
    7777        fprintf(stderr, "  -v to print version info and exit\n"); 
    7878        fprintf(stderr, "  -h to print this help and exit\n"); 
     
    8686        fprintf(stderr, "  -T dns type: NULL (default, fastest), TXT, CNAME, A (CNAME answer), MX\n"); 
    8787        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"); 
    8890        fprintf(stderr, "  -z context, to apply specified SELinux context after initialization\n"); 
    8991        fprintf(stderr, "  -F pidfile to write pid to a file\n"); 
     
    128130        int retval; 
    129131        int raw_mode; 
     132        int lazymode; 
     133        int selecttimeout; 
    130134 
    131135        nameserv_addr = NULL; 
     
    147151        retval = 0; 
    148152        raw_mode = 1; 
     153        lazymode = 1; 
     154        selecttimeout = 4; 
    149155 
    150156#ifdef WINDOWS32 
     
    163169#endif 
    164170 
    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) { 
    166172                switch(choice) { 
    167173                case 'v': 
     
    209215                case 'O':       /* not -D, is Debug in server */ 
    210216                        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; 
    211231                        break; 
    212232                default: 
     
    261281        } 
    262282 
     283        client_set_selecttimeout(selecttimeout); 
     284        client_set_lazymode(lazymode); 
    263285        client_set_topdomain(topdomain); 
    264286         
Note: See TracChangeset for help on using the changeset viewer.