Changeset b17790


Ignore:
Timestamp:
12/29/09 21:00:57 (2 years ago)
Author:
J. A. Bezemer <J.A.Bezemer@…>
Branches:
master
Children:
aa818c
Parents:
1a26a9
git-author:
J. A. Bezemer <J.A.Bezemer@…> (12/29/09 21:00:57)
git-committer:
Erik Ekman <erik@…> (02/04/12 20:34:04)
Message:

Applied patch from #88, thanks a lot!

Files:
2 added
16 edited
1 moved

Legend:

Unmodified
Added
Removed
  • README

    r05e99c rb17790  
    1212 
    1313Try it out within your own LAN! Follow these simple steps: 
    14 - On your server, run: ./iodined -f 10.0.0.1 test.asdf 
     14- On your server, run: ./iodined -f 10.0.0.1 test.com 
    1515  (If you already use the 10.0.0.0 network, use another internal net like  
    1616  172.16.0.0) 
    1717- Enter a password 
    18 - On the client, run: ./iodine -f 192.168.0.1 test.asdf 
    19   (Replace 192.168.0.1 with the server's ip address) 
     18- On the client, run: ./iodine -f -r 192.168.0.1 test.com 
     19  (Replace 192.168.0.1 with your server's ip address) 
    2020- Enter the same password 
    2121- Now the client has the tunnel ip 10.0.0.2 and the server has 10.0.0.1 
     
    2727HOW TO USE: 
    2828 
     29Note: server and client are required to speak the exact same protocol. In most 
     30cases, this means running the same iodine version. Unfortunately, implementing 
     31backward and forward protocol compatibility is usually not feasible. 
     32 
    2933Server side: 
    30 To use this tunnel, you need control over a real domain (like mytunnel.com), 
    31 and a server with a public IP number. If the server already runs a DNS 
    32 server, change the listening port and then use the -b option to let 
    33 iodined forward the DNS requests. Then, delegate a subdomain  
    34 (say, tunnel1.mytunnel.com) to the server. If you use BIND for the domain,  
    35 add these lines to the zone file: 
    36  
    37 tunnel1host     IN      A       10.15.213.99 
    38 tunnel1         IN      NS      tunnel1host.mytunnel.com. 
    39  
    40 Do not use CNAME instead of A above. 
    41 If your server has a dynamic IP, use a dynamic dns provider: 
    42  
    43 tunnel1         IN      NS      tunnel1host.mydyndnsprovider.com 
    44  
    45 Now any DNS querys for domains ending with tunnel1.mytunnnel.com will be sent 
    46 to your server. Start iodined on the server. The first argument is the tunnel 
    47 IP address (like 192.168.99.1) and the second is the assigned domain (in this 
    48 case tunnel1.mytunnel.com). The -f argument will keep iodined running in the 
    49 foreground, which helps when testing. iodined will start a virtual interface, 
    50 and also start listening for DNS queries on UDP port 53. Either enter a 
    51 password on the commandline (-P pass) or after the server has started. Now  
    52 everything is ready for the client. 
     34To use this tunnel, you need control over a real domain (like mydomain.com), 
     35and a server with a public IP address to run iodined on. If this server 
     36already runs a DNS program, change its listening port and then use iodined's 
     37-b option to let iodined forward the DNS requests. (Note that this procedure 
     38is not advised in production environments, because iodined's DNS forwarding 
     39is not completely transparent.) 
     40 
     41Then, delegate a subdomain (say, t1.mydomain.com) to the iodined server. 
     42If you use BIND for your domain, add two lines like these to the zone file: 
     43 
     44t1              IN      NS      t1ns.mydomain.com.              ; note the dot! 
     45t1ns            IN      A       10.15.213.99 
     46 
     47The "NS" line is all that's needed to route queries for the "t1" subdomain 
     48to the "t1ns" server. We use a short name for the subdomain, to keep as much 
     49space as possible available for the data traffic. At the end of the "NS" line 
     50is the name of your iodined server. This can be any name, pointing anywhere, 
     51but in this case it's easily kept in the same zone file. It must be a name 
     52(not an IP address), and that name itself must have an A record (not a CNAME). 
     53 
     54If your iodined server has a dynamic IP, use a dynamic dns provider. Simply 
     55point the "NS" line to it, and leave the "A" line out: 
     56 
     57t1              IN      NS      myname.mydyndnsprovider.com.    ; note the dot! 
     58 
     59Then reload or restart your nameserver program. Now any DNS queries for 
     60domains ending in t1.mydomain.com will be sent to your iodined server. 
     61 
     62Finally start iodined on your server. The first argument is the IP address 
     63inside the tunnel, which can be from any range that you don't use yet (for 
     64example 192.168.99.1), and the second argument is the assigned domain (in this 
     65case t1.mydomain.com). Using the -f option will keep iodined running in the 
     66foreground, which helps when testing. iodined will open a virtual interface 
     67("tun device"), and will also start listening for DNS queries on UDP port 53. 
     68Either enter a password on the commandline (-P pass) or after the server has 
     69started. Now everything is ready for the client. 
     70 
     71If there is a chance you'll be using an iodine tunnel from unexpected 
     72environments, start iodined with a -c option. 
     73 
     74Resulting commandline in this example situation: 
     75./iodined -f -c -P secretpassword 192.168.99.1 t1.mydomain.com 
    5376 
    5477Client side:  
    55 All the setup is done, just start iodine. It takes up to two arguments, the 
     78All the setup is done, just start iodine. It takes one or two arguments, the 
    5679first is the local relaying DNS server (optional) and the second is the domain 
    57 used (tunnel1.mytunnnel.com). If DNS queries are allowed to any computer, you 
    58 can use the tunnel endpoint (example: 10.15.213.99 or tunnel1host.mytunnel.com) 
    59 as the first argument. The tunnel interface will get an IP close to the servers 
    60 (in this case 192.168.99.2) and a suitable MTU.  Enter the same password as on 
    61 the server either by argument or after the client has started. Now you should 
    62 be able to ping the other end of the tunnel from either side.   
     80you used (t1.mydomain.com). If you don't specify the first argument, the 
     81system's current DNS setting will be consulted. 
     82 
     83If DNS queries are allowed to any computer, you can directly give the iodined 
     84server's address as first argument (in the example: t1ns.mydomain.com or 
     8510.15.213.99). In that case, it may also happen that _any_ traffic is allowed 
     86to the DNS port (53 UDP) of any computer. Iodine will detect this, and switch 
     87to raw UDP tunneling if possible. To force DNS tunneling in any case, use the 
     88-r option (especially useful when testing within your own network). 
     89 
     90The client's tunnel interface will get an IP close to the server's (in this 
     91case 192.168.99.2 or .3 etc.) and a suitable MTU. Enter the same password as 
     92on the server either as commandline option or after the client has started. 
     93Using the -f option will keep the iodine client running in the foreground. 
     94 
     95Resulting commandline in this example situation: 
     96./iodine -f -P secretpassword t1.mydomain.com 
     97(add -r to force DNS tunneling even if raw UDP tunneling would be possible) 
     98 
     99From either side, you should now be able to ping the IP address on the other 
     100end of the tunnel. In this case, ping 192.168.99.1 from the iodine client, and 
     101192.168.99.2 or .3 etc. from the iodine server. 
    63102 
    64103 
     
    66105 
    67106Routing: 
    68 The normal case is to route all traffic through the DNS tunnel. To do this, first 
    69 add a route to the nameserver you use with the default gateway as gateway. Then 
    70 replace the default gateway with the servers IP address within the DNS tunnel, 
    71 and configure the server to do NAT. 
    72  
     107It is possible to route all traffic through the DNS tunnel. To do this, first 
     108add a host route to the nameserver used by iodine over the wired/wireless 
     109interface with the default gateway as gateway. Then replace the default 
     110gateway with the iodined server's IP address inside the DNS tunnel, and 
     111configure the server to do NAT. 
     112 
     113However, note that the tunneled data traffic is not encrypted at all, and can 
     114be read and changed by external parties relatively easily. For maximum 
     115security, run a VPN through the DNS tunnel (=double tunneling), or use secure 
     116shell (SSH) access, possibly with port forwarding. The latter can also be used 
     117for web browsing, when you run a web proxy (for example Privoxy) on your 
     118server. 
     119 
     120Testing: 
     121The iodined server replies to NS requests sent for subdomains of the tunnel 
     122domain. If your iodined subdomain is t1.mydomain.com, send a NS request for 
     123foo123.t1.mydomain.com to see if the delegation works. dig is a good tool 
     124for this: 
     125dig -t NS foo123.t1.mydomain.com 
     126 
     127Also, the iodined server will answer requests starting with 'z' for any of the 
     128supported request types, for example: 
     129dig -t TXT z456.t1.mydomain.com 
     130dig -t SRV z456.t1.mydomain.com 
     131dig -t CNAME z456.t1.mydomain.com 
     132The reply should look like garbled text in all these cases. 
     133 
     134Operational info: 
    73135The DNS-response fragment size is normally autoprobed to get maximum bandwidth. 
    74136To force a specific value (and speed things up), use the -m option. 
    75137 
    76 The iodined server replies to NS requests sent for subdomains of the tunnel 
    77 domain. If your domain is tunnel.com, send a NS request for foo.tunnel.com 
    78 to see if the delegation works. dig is a good tool for this: 
    79 dig -t NS foo123.tunnel.com 
    80  
    81 The upstream data is sent gzipped encoded with Base32, or Base64 if the relay 
    82 server support '+' in domain names. DNS protocol allows one query per packet, 
    83 and one query can be max 256 chars. Each domain name part can be max 63 chars. 
    84 So your domain name and subdomain should be as short as possible to allow 
    85 maximum upstream throughput. 
    86  
    87 The default is to use DNS NULL-type queries, as this provides the largest 
    88 downstream bandwidth. If your DNS server blocks NULL requests, try TXT or 
    89 CNAME queries via the -T option. Also supported are A (returning CNAME) and 
    90 MX requests, but these may/will cause additional lookups by "smart" caching 
    91 nameservers to get an actual IP address, which may either slow down or fail 
    92 completely. DNS responses for non-NULL are Base32 encoded by default, which 
    93 should always work. For more bandwidth, try Base64 or Raw (TXT only) via the 
    94 -O option. If Base64/Raw doesn't work, you'll see many failures in the 
    95 fragment size autoprobe. 
     138The DNS hostnames are normally used up to their maximum length, 255 characters. 
     139Some DNS relays have been found that answer full-length queries rather 
     140unreliably, giving widely varying (and mostly very bad) results of the 
     141fragment size autoprobe on repeated tries. In these cases, use the -M switch 
     142to reduce the DNS hostname length to for example 200 characters, which makes 
     143these DNS relays much more stable. This is also useful on some "de-optimizing" 
     144DNS relays that stuff the response with two full copies of the query, leaving 
     145very little space for downstream data (also not capable of EDNS0). The -M 
     146switch can trade some upstream bandwidth for downstream bandwidth. Note that 
     147the minimum -M value is about 100, since the protocol can split packets (1200 
     148bytes max) in only 16 fragments, requiring at least 75 real data bytes per 
     149fragment. 
     150 
     151The upstream data is sent gzipped encoded with Base32; or Base64 if the relay 
     152server supports mixed case and '+' in domain names; or Base64u if '_' is 
     153supported instead; or Base128 if high-byte-value characters are supported. 
     154This upstream encoding is autodetected. The DNS protocol allows one query per 
     155packet, and one query can be max 256 chars. Each domain name part can be max 
     15663 chars. So your domain name and subdomain should be as short as possible to 
     157allow maximum upstream throughput. 
     158 
     159Several DNS request types are supported, with the NULL type expected to provide 
     160the largest downstream bandwidth. Other available types are TXT, SRV, MX, 
     161CNAME and A (returning CNAME), in decreasing bandwidth order. Normally the 
     162"best" request type is autodetected and used. However, DNS relays may impose 
     163limits on for example NULL and TXT, making SRV or MX actually the best choice. 
     164This is not autodetected, but can be forced using the -T option. It is 
     165advisable to try various alternatives especially when the autodetected request 
     166type provides a downstream fragment size of less than 200 bytes. 
     167 
     168Note that SRV, MX and A (returning CNAME) queries may/will cause additional 
     169lookups by "smart" caching nameservers to get an actual IP address, which may 
     170either slow down or fail completely. 
     171 
     172DNS responses for non-NULL queries can be encoded with the same set of codecs 
     173as upstream data. This is normally also autodetected, but no fully exhaustive 
     174tests are done, so some problems may not be noticed when selecting more 
     175advanced codecs. In that case, you'll see failures/corruption in the fragment 
     176size autoprobe. In particular, several DNS relays have been found that change 
     177replies returning hostnames (SRV, MX, CNAME, A) to lowercase only when that 
     178hostname exceeds ca. 180 characters. In these and similar cases, use the -O 
     179option to try other downstream codecs; Base32 should always work. 
    96180 
    97181Normal operation now is for the server to _not_ answer a DNS request until 
     
    99183will always have a DNS request handy when new downstream data has to be sent. 
    100184This greatly improves (interactive) performance and latency, and allows to 
    101 slow down the quiescent ping requests to 4 second intervals by default. 
    102 In fact, the main purpose of the pings now is to force a reply to the previous 
    103 ping, and prevent DNS server timeouts (usually 5-10 seconds per RFC1035). 
    104 In the unlikely case that you do experience DNS server timeouts (SERVFAIL), 
    105 decrease the -I option to 1. If you are running on a local network without 
    106 any DNS server in-between, try -I 50 (iodine and iodined time out after 60 
    107 seconds). The only time you'll notice a slowdown, is when DNS reply packets 
    108 go missing; the iodined server then has to wait for a new ping to re-send the 
    109 data. You can speed this up by generating some upstream traffic (keypress, 
    110 ping). If this happens often, check your network for bottlenecks and/or run 
    111 with -I1 . 
    112  
    113 Some DNS servers appear to be quite impatient and start retrying DNS requests 
    114 (with _different_ DNS ids!) when an answer does not appear within a few 
    115 milliseconds. Usually they scale back retries when iodined's lazy mode 
    116 repeatedly takes several seconds to answer; and they scale up retries again 
    117 when iodined answers fast during heavy data transfer. Some commercial DNS 
    118 servers advertise this as "carrier-grade adaptive retransmission techniques". 
    119 The effect will only be visible in the network traffic at the iodined server, 
    120 and will not affect the client's connection. Iodined has rather elaborate 
    121 logic to deal with (i.e., ignore) these unwanted duplicates. 
    122  
    123 Other DNS servers, notably the opendns.com network, seem to regard iodined's 
    124 lazyness as incompetency, and will start shuffling requests around, possibly 
    125 in an attempt to reduce iodined's workload. The resulting out-of-sequence DNS 
    126 traffic works quite badly for lazy mode. The iodine client will detect this, 
    127 and switch back to legacy mode ("immediate ping-pong") automatically. In these 
    128 cases, start the iodine client with -L0 to prevent it from operating in lazy 
    129 mode altogether. Note that this will negatively affect interactive performance 
    130 and latency, especially in the downstream direction. 
     185slow down the quiescent ping requests to 4 second intervals by default, and 
     186possibly much slower. In fact, the main purpose of the pings now is to force 
     187a reply to the previous ping, and prevent DNS server timeouts (usually at 
     188least 5-10 seconds per RFC1035). Some DNS servers are more impatient and will 
     189give SERVFAIL errors (timeouts) in periods without tunneled data traffic. All 
     190data should still get through in these cases, but iodine will reduce the ping 
     191interval to 1 second anyway (-I1) to reduce the number of error messages. This 
     192may not help for very impatient DNS relays like dnsadvantage.com (ultradns), 
     193which time out in 1 second or even less. Yet data will still get trough, and 
     194you can ignore the SERVFAIL errors. 
     195 
     196If you are running on a local network without any DNS server in-between, try 
     197-I 50 (iodine and iodined close the connection after 60 seconds of silence). 
     198The only time you'll notice a slowdown, is when DNS reply packets go missing; 
     199the iodined server then has to wait for a new ping to re-send the data. You can 
     200speed this up by generating some upstream traffic (keypress, ping). If this 
     201happens often, check your network for bottlenecks and/or run with -I1. 
     202 
     203The delayed answering in lazy mode will cause some "carrier grade" commercial 
     204DNS relays to repeatedly re-send the same DNS query to the iodined server. 
     205If the DNS relay is actually implemented as a pool of parallel servers, 
     206duplicate requests may even arrive from multiple sources. This effect will 
     207only be visible in the network traffic at the iodined server, and will not 
     208affect the client's connection. Iodined will notice these duplicates, and send 
     209the same answer (when its time has come) to both the original query and the 
     210latest duplicate. After that, the full answer is cached for a short while. 
     211Delayed duplicates that arrive at the server even later, get a reply that the 
     212iodine client will ignore (if it ever arrives there). 
    131213 
    132214If you have problems, try inspecting the traffic with network monitoring tools 
    133 and make sure that the relaying DNS server has not cached the response. A 
    134 cached error message could mean that you started the client before the server. 
    135 The -D (and -DD) option on the server can also show received and sent queries. 
     215like tcpdump or ethereal/wireshark, and make sure that the relaying DNS server 
     216has not cached the response. A cached error message could mean that you 
     217started the client before the server. The -D (and -DD) option on the server 
     218can also show received and sent queries. 
    136219 
    137220 
     
    166249a fixed-width font like Courier. 
    167250 
    168 Measurements were done in protocol 00000500 with lazy mode unless indicated 
    169 otherwise. Upstream encoding always Base64. 
     251Measurements were done in protocol 00000502 in lazy mode; upstream encoding 
     252always Base128; iodine -M255; iodined -m1130. Network conditions were not 
     253extremely favorable; results are not benchmarks but a realistic indication of 
     254real-world performance that can be expected in similar situations. 
     255 
    170256Upstream/downstream throughput was measured by scp'ing a file previously 
    171257read from /dev/urandom (i.e. incompressible), and measuring size with 
    172258"ls -l ; sleep 30 ; ls -l" on a separate non-tunneled connection. Given the 
    173259large scp block size of 16 kB, this gives a resolution of 4.3 kbit/s, which 
    174 explains why many values are exactly equal. 
     260explains why some values are exactly equal. 
    175261Ping round-trip times measured with "ping -c100", presented are average rtt 
    176262and mean deviation (indicating spread around the average), in milliseconds. 
     
    186272 
    187273iodine -> Wifi AP :53 
    188   -Tnull (= -Oraw)           982    39.3    148.5   26.7    3.1   26.6    3.0 
     274  -Tnull (= -Oraw)           982    43.6    131.0   28.0    4.6   26.8    3.4 
    189275 
    190276iodine -> Home server :53 
    191   -Tnull (= -Oraw)          1174    43.6    174.7   25.2    4.0   25.5    3.4 
     277  -Tnull (= -Oraw)          1174    48.0    305.8   26.6    5.0   26.9    8.4 
    192278 
    193279iodine -> DSL provider :53   
    194   -Tnull (= -Oraw)          1174    52.4    200.9   20.3    3.2   20.3    2.7 
    195   -Ttxt -Obase32             730    52.4    192.2* 
    196   -Ttxt -Obase64             874    52.4    192.2 
    197   -Ttxt -Oraw               1162    52.4    192.2 
    198   -Tcname -Obase32           148    52.4     48.0 
    199   -Tcname -Obase64           181    52.4     61.1 
     280  -Tnull (= -Oraw)          1174    56.7    367.0   20.6    3.1   21.2    4.4 
     281  -Ttxt -Obase32             730    56.7    174.7* 
     282  -Ttxt -Obase64             874    56.7    174.7 
     283  -Ttxt -Obase128           1018    56.7    174.7 
     284  -Ttxt -Oraw               1162    56.7    358.2 
     285  -Tsrv -Obase128            910    56.7    174.7 
     286  -Tcname -Obase32           151    56.7     43.6 
     287  -Tcname -Obase128          212    56.7     52.4 
    200288 
    201289iodine -> DSL provider :53   
    202   wired (no Wifi) -Tnull    1174    65.5    244.6   17.7    1.9   17.8    1.6 
    203  
    204  [192.2* : nice, because still 2frag/packet] 
     290  wired (no Wifi) -Tnull    1174    74.2    585.4   20.2    5.6   19.6    3.4 
     291 
     292 [174.7* : these all have 2frag/packet] 
    205293 
    206294 
    207295Situation 2: 
    208 Laptop -> (wire) -> (Home server) -> (DSL) ->  opendns.com ->  Datacenter 
    209  iodine                                         DNS cache       iodined 
     296Laptop  ->  Wifi+vpn / wired  ->  Home server 
     297 iodine                            iodined 
    210298 
    211299                        downstr.  upstream downstr.  ping-up       ping-down 
     
    213301------------------------------------------------------------------------------ 
    214302 
    215 iodine -> opendns.com :53 
    216   -Tnull -L1 (lazy mode)     230      -        -   404.4  196.2  663.8  679.6 
    217                                                     (20% lost)     (2% lost) 
    218  
    219   -Tnull -L0 (legacy mode)   230     5.6      7.4  197.3    4.7  610.8  323.5 
    220  
    221  [Note: Throughput measured over 300 seconds to get better resolution] 
    222  
    223  
    224 Situation 3: 
    225 Laptop  ->  Wifi+vpn / wired  ->  Home server 
    226  iodine                            iodined 
    227  
    228                         downstr.  upstream downstr.  ping-up       ping-down 
    229                         fragsize   kbit/s   kbit/s  avg +/-mdev   avg +/-mdev 
    230 ------------------------------------------------------------------------------ 
    231  
    232 wifi + openvpn  -Tnull      1186   183.5    611.6    5.7    1.4    7.0    2.7 
    233  
    234 wired  -Tnull               1186   685.9   2350.5    1.3    0.1    1.4    0.4 
     303wifi + openvpn  -Tnull      1186   166.0   1022.3    6.3    1.3    6.6    1.6 
     304 
     305wired  -Tnull               1186   677.2   2464.1    1.3    0.2    1.3    0.1 
    235306 
    236307 
  • doc/proto_00000502.txt

    r05e99c rb17790  
    1 Detailed specification of protocol in version 00000501 
     1Detailed specification of protocol in version 00000502 
    22====================================================== 
    33 
     
    771. DNS protocol 
    88====================================================== 
     9 
     10Quick alphabetical index / register: 
     11        0-9     Data packet 
     12        A-F     Data packet 
     13        I       IP address 
     14        L       Login 
     15        N       Downstream fragsize     (NS.topdomain A-type reply) 
     16        O       Options 
     17        P       Ping 
     18        R       Downstream fragsize probe 
     19        S       Switch upstream codec 
     20        V       Version 
     21        W                               (WWW.topdomain A-type reply) 
     22        Y       Downstream codec check 
     23        Z       Upstream codec check 
     24 
    925 
    1026CMC = 2 byte Cache Miss Counter, increased every time it is used 
     
    3955        First byte i or I 
    4056        5 bits coded as Base32 char, meaning userid 
    41         CMC 
     57        CMC as 3 Base32 chars 
    4258Server replies 
    4359        BADIP if bad userid, or 
    4460        I and then 4 bytes network order external IP address of iodined server 
    4561 
    46 Case check: 
     62Upstream codec check / bounce: 
    4763Client sends:  
    4864        First byte z or Z 
    4965        Lots of data that should not be decoded 
    5066Server replies: 
    51         The requested domain copied raw 
     67        The requested domain copied raw, in the lowest-grade downstream codec 
     68        available for the request type. 
     69 
     70Downstream codec check: 
     71Client sends: 
     72        First byte y or Y 
     73        1 char, meaning downstream codec to use 
     74        5 bits coded as Base32 char, meaning check variant 
     75        CMC as 3 Base32 chars 
     76        Possibly extra data, depending on check variant 
     77Server sends: 
     78        Data encoded with requested downstream codec; data content depending 
     79        on check variant number. 
     80        BADCODEC if requested downstream codec not available. 
     81        BADLEN if check variant is not available, or problem with extra data. 
     82 
     83        Downstream codec chars are same as in 'O' Option request, below. 
     84 
     85        Check variants: 
     86        1: Send encoded DOWNCODECCHECK1 string as defined in encoding.h 
     87 
     88        (Other variants reserved; possibly variant that sends a decoded-encoded 
     89        copy of Base32-encoded extra data in the request) 
    5290 
    5391Switch codec: 
     
    5593        First byte s or S 
    5694        5 bits coded as Base32 char, meaning userid 
    57         5 bits coded as Base32 char, with value 5 or 6, representing number of raw 
    58         bits per encoded byte 
    59         CMC 
     95        5 bits coded as Base32 char, representing number of raw bits per 
     96        encoded byte: 
     97                5: Base32   (a-z0-5) 
     98                6: Base64   (a-zA-Z0-9+-) 
     99                26: Base64u (a-zA-Z0-9_-) 
     100                7: Base128  (a-zA-Z0-9\274-\375) 
     101        CMC as 3 Base32 chars 
    60102Server sends: 
    61103        Name of codec if accepted. After this all upstream data packets must  
    62104        be encoded with the new codec. 
    63         BADCODEC if not accepted. Client must then revert to Base32 
     105        BADCODEC if not accepted. Client must then revert to previous codec 
    64106        BADLEN if length of query is too short 
    65107 
     
    69111        5 bits coded as Base32 char, meaning userid 
    70112        1 char, meaning option 
     113        CMC as 3 Base32 chars 
    71114Server sends: 
    72115        Full name of option if accepted. After this, option immediately takes 
     
    78121        t or T: Downstream encoding Base32, for TXT/CNAME/A/MX (default) 
    79122        s or S: Downstream encoding Base64, for TXT/CNAME/A/MX 
     123        u or U: Downstream encoding Base64u, for TXT/CNAME/A/MX 
     124        v or V: Downstream encoding Base128, for TXT/CNAME/A/MX 
    80125        r or R: Downstream encoding Raw, for TXT/NULL (default for NULL) 
    81126        If codec unsupported for request type, server will use Base32; note 
     
    97142        Then follows a long random query which contents does not matter 
    98143Server sends: 
    99         Requested number of bytes as a response. The first two bytes contains 
    100         the requested length. Rest of message can be any data. 
     144        Requested number of bytes as a response. The first two bytes contain 
     145        the requested length. The third byte is 107 (0x6B). The fourth byte 
     146        is a random value, and each following byte is incremented with 107. 
     147        This is checked by the client to determine corruption. 
    101148        BADFRAG if requested length not accepted. 
    102149 
     
    115162Data: 
    116163Upstream data header: 
    117          3210 432 10 43 210 4321 0 
    118         +----+---+--+--+---+----+-+ 
    119         |UUUU|SSS|FF|FF|DDD|GGGG|L| 
    120         +----+---+--+--+---+----+-+ 
     164         3210 432 10 43 210 4321 0 43210 
     165        +----+---+--+--+---+----+-+-----+ 
     166        |UUUU|SSS|FF|FF|DDD|GGGG|L|UDCMC| 
     167        +----+---+--+--+---+----+-+-----+ 
    121168 
    122169Downstream data header: 
     
    133180GGGG = Downstream fragment number 
    134181C = Compression enabled for downstream packet 
    135  
    136 Upstream data packet starts with 1 byte ASCII hex coded user byte, then 3 bytes  
    137 Base32 encoded header, then comes the payload data, encoded with chosen codec. 
     182UDCMC = Upstream Data CMC, 36 steps a-z0-9, case-insensitive 
     183 
     184Upstream data packet starts with 1 byte ASCII hex coded user byte; then 3 bytes  
     185Base32 encoded header; then 1 char data-CMC; then comes the payload data, 
     186encoded with the chosen upstream codec. 
    138187 
    139188Downstream data starts with 2 byte header. Then payload data, which may be 
     
    148197        t or T: Base32   encoded before chop, decoded after un-chop 
    149198        s or S: Base64   encoded before chop, decoded after un-chop 
     199        u or U: Base64u  encoded before chop, decoded after un-chop 
     200        v or V: Base128  encoded before chop, decoded after un-chop 
    150201        r or R: Raw      no encoding, only DNS-chop 
    151 CNAME/A/MX: 
     202SRV/MX/CNAME/A: 
    152203        h or H: Hostname encoded with Base32 
    153204        i or I: Hostname encoded with Base64 
     205        j or J: Hostname encoded with Base64u 
     206        k or K: Hostname encoded with Base128 
     207SRV and MX may reply with multiple hostnames, each encoded separately. Each 
     208has a 10-multiple priority, and encoding/decoding is done in strictly 
     209increasing priority sequence 10, 20, 30, etc. without gaps. Note that some DNS 
     210relays will shuffle the answer records in the response. 
    154211 
    155212Ping: 
     
    163220        CMC 
    164221 
    165 The server response to Ping and Data packets is a DNS NULL type response: 
    166 If server has nothing to send, data length is 0 bytes. 
    167 If server has something to send, it will send a downstream data packet,  
    168 prefixed with 2 bytes header as shown above. 
     222The server response to Ping and Data packets is a DNS NULL/TXT/.. type response, 
     223always starting with the 2 bytes downstream data header as shown above. 
     224If server has nothing to send, no data is added after the header. 
     225If server has something to send, it will add the downstream data packet 
     226(or some fragment of it) after the header. 
    169227  
    170228  
  • man/iodine.8

    r1a26a9 rb17790  
    11.\" groff -man -Tascii iodine.8 
    2 .TH IODINE 8 "SEP 2009" "User Manuals" 
     2.TH IODINE 8 "DEC 2009" "User Manuals" 
    33.SH NAME 
    44iodine, iodined \- tunnel IPv4 over DNS 
     
    2020.B ] [-m 
    2121.I fragsize 
     22.B ] [-M 
     23.I namelen 
    2224.B ] [-z 
    2325.I context 
     
    8587.B iodined 
    8688is the server. 
     89 
     90Note: server and client are required to speak the exact same protocol. In most 
     91cases, this means running the same iodine version. Unfortunately, implementing 
     92backward and forward protocol compatibility is usually not feasible. 
    8793.SH OPTIONS 
    8894.SS Common Options: 
     
    128134client to automatically probe the maximum accepted downstream fragment size. 
    129135.TP 
     136.B -M namelen 
     137Maximum length of upstream hostnames, default 255. 
     138Usable range ca. 100 to 255. 
     139Use this option to scale back upstream bandwidth in favor of downstream 
     140bandwidth. 
     141Also useful for DNS servers that perform unreliably when using full-length 
     142hostnames, noticable when fragment size autoprobe returns very 
     143different results each time. 
     144.TP 
    130145.B -T dnstype 
    131 DNS request type. 
    132 .I NULL 
    133 is default. If this doesn't work, try 
    134 .I TXT 
    135 (some less bandwidth) or 
     146DNS request type override. 
     147By default, autodetection will probe for working DNS request types, and 
     148will select the request type that is expected to provide the most bandwidth. 
     149However, it may turn out that a DNS relay imposes limits that skew the 
     150picture, which may lead to an "unexpected" DNS request type providing 
     151more bandwidth. 
     152In that case, use this option to override the autodetection. 
     153In (expected) decreasing bandwidth order, the supported DNS request types are: 
     154.IR NULL , 
     155.IR TXT , 
     156.IR SRV , 
     157.IR MX , 
    136158.I CNAME 
    137 (much less bandwidth). Also supported are 
     159and 
    138160.I A 
    139 (returning CNAME) and 
     161(returning CNAME). 
     162Note that 
     163.IR SRV , 
    140164.I MX 
    141 requests, but these may/will cause additional lookups by "smart" caching 
     165and 
     166.I A 
     167may/will cause additional lookups by "smart" caching 
    142168nameservers to get an actual IP address, which may either slow down or fail 
    143169completely. 
    144170.TP 
    145171.B -O downenc 
    146 Downstream encoding for all query type responses except NULL. 
     172Force downstream encoding type for all query type responses except NULL. 
     173Default is autodetected, but may not spot all problems for the more advanced 
     174codecs. 
     175Use this option to override the autodetection. 
    147176.I Base32 
    148 is default and should always work. 
     177is the lowest-grade codec and should always work; this is used when 
     178autodetection fails. 
    149179.I Base64 
    150180provides more bandwidth, but may not work on all nameservers. 
     181.I Base64u 
     182is equal to Base64 except in using underscore ('_') 
     183instead of plus sign ('+'), possibly working where 
     184.I Base64 
     185does not. 
     186.I Base128 
     187uses high byte values (mostly accented letters in iso8859-1), 
     188which might work with some nameservers. 
    151189For TXT queries, 
    152190.I Raw 
    153 will provide maximum performance. This will only work if the nameserver 
     191will provide maximum performance, but this will only work if the nameserver 
    154192path is fully 8-bit-clean for responses that are assumed to be "legible text". 
    155193.TP 
    156194.B -L 0|1 
    157195Lazy-mode switch. 
    158 \-L1 (default): Use lazy mode if server supports it, for improved 
    159 performance and decreased latency. 
    160 Some DNS servers, notably the opendns.com network, appear unstable when 
    161 handling lazy mode DNS traffic and will re-order requests. If this occurs, 
    162 you will notice fluctuating response speed in interactive sessions. 
    163 The iodine client will eventually detect this and switch back to legacy 
    164 mode automatically. Use \-L0 to force running in legacy mode 
     196\-L1 (default): Use lazy mode for improved performance and decreased latency. 
     197A very small minority of DNS relays appears to be unable to handle the 
     198lazy mode traffic pattern, resulting in no or very little data coming through. 
     199The iodine client will detect this and try to switch back to legacy mode, 
     200but this may not always work. 
     201In these situations use \-L0 to force running in legacy mode 
    165202(implies \-I1). 
    166203.TP 
     
    168205Maximum interval between requests (pings) so that intermediate DNS 
    169206servers will not time out. Default is 4 in lazy mode, which will work 
    170 fine in almost all cases. Decrease if you get SERVFAIL errors in periods 
    171 without tunneled data traffic. To get absolute minimum DNS traffic, 
    172 increase well above 4 until SERVFAIL errors start to occur. 
     207fine in most cases. When too many SERVFAIL errors occur, iodine 
     208will automatically reduce this to 1. 
     209To get absolute minimum DNS traffic, 
     210increase well above 4, but not so high that SERVFAIL errors start to occur. 
     211There are some DNS relays with very small timeouts, 
     212notably dnsadvantage.com (ultradns), that will give 
     213SERVFAIL errors even with \-I1; data will still get trough, 
     214and these errors can be ignored. 
    173215Maximum useful value is 59, since iodined will close a client's 
    174216connection after 60 seconds of inactivity. 
     
    191233.B -f 
    192234option. 
     235On level 2 (-DD) or higher, DNS queries will be printed literally. 
     236When using Base128 upstream encoding, this is best viewed as 
     237ISO Latin-1 text instead of (illegal) UTF-8. 
     238This is easily done with : "LC_ALL=C luit iodined -DD ..." 
     239(see luit(1)). 
    193240.TP 
    194241.B -m mtu 
    195242Set 'mtu' as mtu size for the tun device.  
    196243This will be sent to the client on login, and the client will use the same mtu 
    197 for its tun device.  Default 1200.  Note that the DNS traffic will be 
     244for its tun device.  Default 1130.  Note that the DNS traffic will be 
    198245automatically fragmented when needed. 
    199246.TP 
     
    237284.TP 
    238285.B tunnel_ip[/netmask] 
    239 +This is the server's ip address on the tun interface. The client will be 
     286This is the server's ip address on the tun interface. The client will be 
    240287given the next ip number in the range. It is recommended to use the  
    24128810.0.0.0 or 172.16.0.0 ranges. The default netmask is /27, can be overriden 
     
    244291.TP 
    245292.B topdomain 
    246 +The dns traffic is expected to arrive as queries for 
     293The dns traffic is expected to arrive as queries for 
    247294subdomains under 'topdomain'. This is normally a subdomain to a domain you  
    248295own. Use a short domain name to get better throughput. This argument must be  
     
    251298they will be dropped. 
    252299.SH EXAMPLES 
    253 .SS Quickstart: 
    254 .TP 
    255 Try it out within your own LAN! Follow these simple steps: 
    256 .TP 
    257 - On your server, run: ./iodined \-f 10.0.0.1 test.asdf 
    258 (If you already use the 10.0.0.0 network, use another internal net like  
    259 172.16.0.0) 
    260 .TP 
    261 - Enter a password 
    262 .TP 
    263 - On the client, run: ./iodine \-f 192.168.0.1 test.asdf 
    264 (Replace 192.168.0.1 with the server's ip address) 
    265 .TP 
    266 - Enter the same password 
    267 .TP 
    268 - Now the client has the tunnel ip 10.0.0.2 and the server has 10.0.0.1 
    269 .TP 
    270 - Try pinging each other through the tunnel 
    271 .TP 
    272 - Done! :) 
    273 .TP 
    274 To actually use it through a relaying nameserver, see below. 
    275 .SS Full setup: 
    276  
    277 .TP 
    278 .B Server side: 
    279 To use this tunnel, you need control over a real domain (like mytunnel.com), 
    280 and a server with a public IP number. If the server already runs a DNS 
    281 server, change the listening port and then use the \-b option to let 
    282 iodined forward the DNS requests. Then, delegate a subdomain  
    283 (say, tunnel1.mytunnel.com) to the server. If you use BIND for the domain,  
    284 add these lines to the zone file (replace 10.15.213.99 with your server ip): 
    285  
    286 .nf 
    287 tunnel1host     IN      A       10.15.213.99 
    288 tunnel1         IN      NS      tunnel1host.mytunnel.com. 
    289 .fi 
    290  
    291 Now any DNS querys for domains ending with tunnel1.mytunnnel.com will be sent 
    292 to your server. Start iodined on the server. The first argument is the tunnel 
    293 IP address (like 192.168.99.1) and the second is the assigned domain (in this 
    294 case tunnel1.mytunnel.com). The \-f argument will keep iodined running in the 
    295 foreground, which helps when testing. iodined will start a virtual interface, 
    296 and also start listening for DNS queries on UDP port 53. Either enter a 
    297 password on the commandline (\-P pass) or after the server has started. Now  
    298 everything is ready for the client. 
    299 .TP 
    300 .B Client side:  
    301 All the setup is done, just start iodine. It also takes two 
    302 arguments, the first is the local relaying DNS server and the second is the 
    303 domain used (tunnel1.mytunnnel.com). If DNS queries are allowed to any 
    304 computer, you can use the tunnel endpoint (example: 10.15.213.99 or 
    305 tunnel1host.mytunnel.com) as the first argument. The tunnel interface will get 
    306 an IP close to the servers (in this case 192.168.99.2) and a suitable MTU.  
    307 Enter the same password as on the server either by argument or after the client 
    308 has started. Now you should be able to ping the other end of the tunnel from  
    309 either side.   
    310 .TP 
    311 .B Routing: 
    312 The normal case is to route all traffic through the DNS tunnel. To do this, first 
    313 add a route to the nameserver you use with the default gateway as gateway. Then 
    314 replace the default gateway with the servers IP address within the DNS tunnel, 
    315 and configure the server to do NAT. 
    316 .TP 
    317 .B Troubleshooting: 
    318 Use the \-D option on the server to show received and sent queries, or use a  
    319 tool like Wireshark/tcpdump. The iodined server replies to NS requests sent for 
    320 subdomains of the tunnel domain. If your domain is tunnel.com, send a NS 
    321 request for foo.tunnel.com to see if the delegation works. dig is a good tool 
    322 for this:  
    323 .nf 
    324 dig \-t NS foo123.tunnel.com 
    325 .fi 
    326 .TP 
    327 .B MTU issues: 
    328 These issues should be solved now, with automatic fragmentation of downstream  
    329 packets. There should be no need to set the MTU explicitly on the server. 
     300See the README file for both a quick test scenario, and a detailed description 
     301of real-world deployment. 
    330302.SH SECURITY 
    331303Login is a relatively secure challenge-response MD5 hash, with the 
     
    337309with the \-c option. Use of ssh or vpn tunneling is strongly recommended. 
    338310On both server and client, use 
    339 .I iptables 
    340 , 
     311.IR iptables , 
    341312.I pf 
    342 or other firewlls to block all traffic coming in from the tun interfaces, 
     313or other firewalls to block all traffic coming in from the tun interfaces, 
    343314except to the used ssh or vpn ports. 
    344315.SH ENVIRONMENT 
     
    349320for one. The  
    350321.B -P 
    351 option still has preference. 
     322option still has precedence. 
    352323.SS IODINED_PASS 
    353324If the environment variable 
     
    356327for one. The 
    357328.B -P 
    358 option still has preference. 
     329option still has precedence. 
    359330.El 
    360331.SH SEE ALSO 
  • src/Makefile

    r27fdc2 rb17790  
    1 COMMONOBJS = tun.o dns.o read.o encoding.o login.o base32.o base64.o md5.o common.o 
     1COMMONOBJS = tun.o dns.o read.o encoding.o login.o base32.o base64.o base64u.o base128.o md5.o common.o 
    22CLIENTOBJS = iodine.o client.o util.o 
    33CLIENT = ../bin/iodine 
     
    3131        @$(CC) $(CFLAGS) $< -o $@ 
    3232 
     33base64u.o client.o iodined.o: base64u.h 
     34base64u.c: base64.c 
     35        @echo Making $@ 
     36        @echo '/* No use in editing, produced by Makefile! */' > $@ 
     37        @sed -e 's/\(base64\)/\1u/ig ; s/0123456789+/0123456789_/' < $< >> $@ 
     38base64u.h: base64.h 
     39        @echo Making $@ 
     40        @echo '/* No use in editing, produced by Makefile! */' > $@ 
     41        @sed -e 's/\(base64\)/\1u/ig ; s/0123456789+/0123456789_/' < $< >> $@ 
     42 
    3343clean: 
    3444        @echo "Cleaning src/" 
    35         @rm -f $(CLIENT){,.exe} $(SERVER){,.exe} *~ *.o *.core 
     45        @rm -f $(CLIENT){,.exe} $(SERVER){,.exe} *~ *.o *.core base64u.* 
    3646 
  • src/base32.c

    rfb1747 rb17790  
    11/* 
    22 * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se> 
     3 * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl 
    34 * 
    45 * Permission to use, copy, modify, and distribute this software for any 
     
    2930static const char cb32_ucase[] =  
    3031        "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; 
    31 static unsigned char rev32[128]; 
    32  
     32static unsigned char rev32[256]; 
     33static int reverse_init = 0; 
     34 
     35static int base32_encode(char *, size_t *, const void *, size_t); 
    3336static int base32_decode(void *, size_t *, const char *, size_t); 
    34 static int base32_encode(char *, size_t *, const void *, size_t); 
    3537static int base32_handles_dots(); 
    3638static int base32_blksize_raw(); 
     
    7274} 
    7375 
    74 static void 
     76inline static void 
    7577base32_reverse_init() 
    7678{ 
    7779        int i; 
    7880        unsigned char c; 
    79         static int reverse_init = 0; 
    8081 
    8182        if (!reverse_init) { 
     83                memset (rev32, 0, 256); 
    8284                for (i = 0; i < 32; i++) { 
    8385                        c = cb32[i]; 
     
    105107static int  
    106108base32_encode(char *buf, size_t *buflen, const void *data, size_t size) 
    107 { 
    108         size_t newsize; 
    109         size_t maxsize; 
    110         unsigned char *p; 
    111         unsigned char *q; 
    112         int i; 
    113  
    114         memset(buf, 0, *buflen); 
    115  
    116         /* how many chars can we encode within the buf */ 
    117         maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC); 
    118         /* how big will the encoded data be */ 
    119         newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW); 
    120         if (size % BLKSIZE_RAW) { 
    121                 newsize += BLKSIZE_ENC; 
     109/* 
     110 * Fills *buf with max. *buflen characters, encoding size bytes of *data. 
     111 * 
     112 * NOTE: *buf space should be at least 1 byte _more_ than *buflen 
     113 * to hold the trailing '\0'. 
     114 * 
     115 * return value    : #bytes filled in buf   (excluding \0) 
     116 * sets *buflen to : #bytes encoded from data 
     117 */ 
     118{ 
     119        unsigned char *udata = (unsigned char *) data; 
     120        int iout = 0;   /* to-be-filled output char */ 
     121        int iin = 0;    /* one more than last input byte that can be 
     122                           successfully decoded */ 
     123 
     124        /* Note: Don't bother to optimize manually. GCC optimizes 
     125           better(!) when using simplistic array indexing. */ 
     126 
     127        while (1) { 
     128                if (iout >= *buflen || iin >= size) 
     129                        break; 
     130                buf[iout] = cb32[((udata[iin] & 0xf8) >> 3)]; 
     131                iout++; 
     132 
     133                if (iout >= *buflen || iin >= size) { 
     134                        iout--;         /* previous char is useless */ 
     135                        break; 
     136                } 
     137                buf[iout] = cb32[((udata[iin] & 0x07) << 2) | 
     138                                  ((iin + 1 < size) ? 
     139                                   ((udata[iin + 1] & 0xc0) >> 6) : 0)]; 
     140                iin++;                  /* 0 complete, iin=1 */ 
     141                iout++; 
     142 
     143                if (iout >= *buflen || iin >= size) 
     144                        break; 
     145                buf[iout] = cb32[((udata[iin] & 0x3e) >> 1)]; 
     146                iout++; 
     147 
     148                if (iout >= *buflen || iin >= size) { 
     149                        iout--;         /* previous char is useless */ 
     150                        break; 
     151                } 
     152                buf[iout] = cb32[((udata[iin] & 0x01) << 4) | 
     153                                  ((iin + 1 < size) ? 
     154                                   ((udata[iin + 1] & 0xf0) >> 4) : 0)]; 
     155                iin++;                  /* 1 complete, iin=2 */ 
     156                iout++; 
     157 
     158                if (iout >= *buflen || iin >= size) 
     159                        break; 
     160                buf[iout] = cb32[((udata[iin] & 0x0f) << 1) | 
     161                                  ((iin + 1 < size) ? 
     162                                   ((udata[iin + 1] & 0x80) >> 7) : 0)]; 
     163                iin++;                  /* 2 complete, iin=3 */ 
     164                iout++; 
     165 
     166                if (iout >= *buflen || iin >= size) 
     167                        break; 
     168                buf[iout] = cb32[((udata[iin] & 0x7c) >> 2)]; 
     169                iout++; 
     170 
     171                if (iout >= *buflen || iin >= size) { 
     172                        iout--;         /* previous char is useless */ 
     173                        break; 
     174                } 
     175                buf[iout] = cb32[((udata[iin] & 0x03) << 3) | 
     176                                  ((iin + 1 < size) ? 
     177                                   ((udata[iin + 1] & 0xe0) >> 5) : 0)]; 
     178                iin++;                  /* 3 complete, iin=4 */ 
     179                iout++; 
     180 
     181                if (iout >= *buflen || iin >= size) 
     182                        break; 
     183                buf[iout] = cb32[((udata[iin] & 0x1f))]; 
     184                iin++;                  /* 4 complete, iin=5 */ 
     185                iout++; 
    122186        } 
    123         /* if the buffer is too small, eat some of the data */ 
    124         if (*buflen < newsize) { 
    125                 size = maxsize; 
    126         } 
    127  
    128         p = (unsigned char *) buf; 
    129         q = (unsigned char *)data; 
    130  
    131         for(i=0;i<size;i+=BLKSIZE_RAW) { 
    132                 p[0] = cb32[((q[0] & 0xf8) >> 3)]; 
    133                 p[1] = cb32[(((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6))]; 
    134                 p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0'; 
    135                 p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0'; 
    136                 p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0'; 
    137                 p[5] = (i+3 < size) ? cb32[((q[3] & 0x7c) >> 2)] : '\0'; 
    138                 p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) >> 5)] : '\0'; 
    139                 p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0'; 
    140                  
    141                 q += BLKSIZE_RAW; 
    142                 p += BLKSIZE_ENC; 
    143         }        
    144         *p = 0; 
     187 
     188        buf[iout] = '\0'; 
    145189 
    146190        /* store number of bytes from data that was used */ 
    147         *buflen = size; 
    148  
    149         return strlen(buf); 
    150 } 
    151  
    152 #define DECODE_ERROR 0xffffffff 
     191        *buflen = iin; 
     192 
     193        return iout; 
     194} 
     195 
    153196#define REV32(x) rev32[(int) (x)] 
    154  
    155 static int 
    156 decode_token(const unsigned char *t, unsigned char *data, size_t len)  
    157 { 
    158         if (len < 2) 
    159                 return 0; 
    160  
    161         data[0] = ((REV32(t[0]) & 0x1f) << 3) |  
    162                           ((REV32(t[1]) & 0x1c) >> 2); 
    163          
    164         if (len < 4) 
    165                 return 1; 
    166  
    167         data[1] = ((REV32(t[1]) & 0x03) << 6) |  
    168                           ((REV32(t[2]) & 0x1f) << 1) |  
    169                           ((REV32(t[3]) & 0x10) >> 4); 
    170  
    171         if (len < 5) 
    172                 return 2; 
    173  
    174         data[2] = ((REV32(t[3]) & 0x0f) << 4) | 
    175                           ((REV32(t[4]) & 0x1e) >> 1); 
    176  
    177         if (len < 7) 
    178                 return 3; 
    179  
    180         data[3] = ((REV32(t[4]) & 0x01) << 7) | 
    181                           ((REV32(t[5]) & 0x1f) << 2) | 
    182                           ((REV32(t[6]) & 0x18) >> 3); 
    183  
    184         if (len < 8) 
    185                 return 4; 
    186  
    187         data[4] = ((REV32(t[6]) & 0x07) << 5) | 
    188                           ((REV32(t[7]) & 0x1f)); 
    189  
    190         return 5; 
    191 } 
    192197 
    193198static int 
    194199base32_decode(void *buf, size_t *buflen, const char *str, size_t slen) 
    195 { 
    196         unsigned char *q; 
    197         size_t newsize; 
    198         size_t maxsize; 
    199         const char *p; 
    200         int len; 
    201  
    202         base32_reverse_init(); 
    203          
    204         /* chars needed to decode slen */ 
    205         newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1; 
    206         /* encoded chars that fit in buf */ 
    207         maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1; 
    208         /* if the buffer is too small, eat some of the data */ 
    209         if (*buflen < newsize) { 
    210                 slen = maxsize; 
     200/* 
     201 * Fills *buf with max. *buflen bytes, decoded from slen chars in *str. 
     202 * Decoding stops early when *str contains \0. 
     203 * Illegal encoded chars are assumed to decode to zero. 
     204 * 
     205 * NOTE: *buf space should be at least 1 byte _more_ than *buflen 
     206 * to hold a trailing '\0' that is added (though *buf will usually 
     207 * contain full-binary data). 
     208 * 
     209 * return value    : #bytes filled in buf   (excluding \0) 
     210 */ 
     211{ 
     212        unsigned char *ubuf = (unsigned char *) buf; 
     213        int iout = 0;   /* to-be-filled output byte */ 
     214        int iin = 0;    /* next input char to use in decoding */ 
     215 
     216        base32_reverse_init (); 
     217 
     218        /* Note: Don't bother to optimize manually. GCC optimizes 
     219           better(!) when using simplistic array indexing. */ 
     220 
     221        while (1) { 
     222                if (iout >= *buflen || iin + 1 >= slen || 
     223                    str[iin] == '\0' || str[iin + 1] == '\0') 
     224                        break; 
     225                ubuf[iout] = ((REV32(str[iin]) & 0x1f) << 3) |  
     226                             ((REV32(str[iin + 1]) & 0x1c) >> 2); 
     227                iin++;                  /* 0 used up, iin=1 */ 
     228                iout++; 
     229 
     230                if (iout >= *buflen || iin + 2 >= slen || 
     231                    str[iin] == '\0' || str[iin + 1] == '\0' || 
     232                    str[iin + 2] == '\0') 
     233                        break; 
     234                ubuf[iout] = ((REV32(str[iin]) & 0x03) << 6) |  
     235                             ((REV32(str[iin + 1]) & 0x1f) << 1) |  
     236                             ((REV32(str[iin + 2]) & 0x10) >> 4); 
     237                iin += 2;               /* 1,2 used up, iin=3 */ 
     238                iout++; 
     239 
     240                if (iout >= *buflen || iin + 1 >= slen || 
     241                    str[iin] == '\0' || str[iin + 1] == '\0') 
     242                        break; 
     243                ubuf[iout] = ((REV32(str[iin]) & 0x0f) << 4) | 
     244                             ((REV32(str[iin + 1]) & 0x1e) >> 1); 
     245                iin++;                  /* 3 used up, iin=4 */ 
     246                iout++; 
     247 
     248                if (iout >= *buflen || iin + 2 >= slen || 
     249                    str[iin] == '\0' || str[iin + 1] == '\0' || 
     250                    str[iin + 2] == '\0') 
     251                        break; 
     252                ubuf[iout] = ((REV32(str[iin]) & 0x01) << 7) | 
     253                             ((REV32(str[iin + 1]) & 0x1f) << 2) | 
     254                             ((REV32(str[iin + 2]) & 0x18) >> 3); 
     255                iin += 2;               /* 4,5 used up, iin=6 */ 
     256                iout++; 
     257 
     258                if (iout >= *buflen || iin + 1 >= slen || 
     259                    str[iin] == '\0' || str[iin + 1] == '\0') 
     260                        break; 
     261                ubuf[iout] = ((REV32(str[iin]) & 0x07) << 5) | 
     262                             ((REV32(str[iin + 1]) & 0x1f)); 
     263                iin += 2;               /* 6,7 used up, iin=8 */ 
     264                iout++; 
    211265        } 
    212266 
    213         q = buf; 
    214         for (p = str; *p && strchr(cb32, *p); p += BLKSIZE_ENC) { 
    215                 len = decode_token((unsigned char *) p, (unsigned char *) q, slen);      
    216                 q += len; 
    217                 slen -= BLKSIZE_ENC; 
    218                  
    219                 if (len < BLKSIZE_RAW) 
    220                         break; 
    221         } 
    222         *q = '\0'; 
    223          
    224         return q - (unsigned char *) buf; 
    225 } 
    226  
     267        ubuf[iout] = '\0'; 
     268 
     269        return iout; 
     270} 
  • src/base64.c

    r0b280b rb17790  
    11/* 
    22 * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se> 
     3 * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl 
    34 * 
    45 * Permission to use, copy, modify, and distribute this software for any 
     
    2021 
    2122#include "encoding.h" 
    22 #include "common.h" 
    2323#include "base64.h" 
    2424 
     
    2626#define BLKSIZE_ENC 4 
    2727 
     28/* Note: the "unofficial" char is last here, which means that the \377 pattern 
     29   in DOWNCODECCHECK1 ('Y' request) will properly test it. */ 
    2830static const char cb64[] =  
    2931        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789+"; 
    30 static unsigned char rev64[128]; 
     32static unsigned char rev64[256]; 
    3133static int reverse_init = 0; 
    3234 
     
    3638static int base64_blksize_raw(); 
    3739static int base64_blksize_enc(); 
    38  
    39 #define REV64(x) rev64[(int) (x)] 
    4040 
    4141static struct encoder base64_encoder = 
     
    7474} 
    7575 
    76 static int  
    77 base64_encode(char *buf, size_t *buflen, const void *data, size_t size) 
    78 { 
    79         size_t newsize; 
    80         size_t maxsize; 
    81         unsigned char *s; 
    82         unsigned char *p; 
    83         unsigned char *q; 
     76inline static void 
     77base64_reverse_init() 
     78{ 
    8479        int i; 
    85  
    86         memset(buf, 0, *buflen); 
    87          
    88         /* how many chars can we encode within the buf */ 
    89         maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC); 
    90         /* how big will the encoded data be */ 
    91         newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW); 
    92         if (size % BLKSIZE_RAW) { 
    93                 newsize += BLKSIZE_ENC; 
    94         } 
    95  
    96         /* if the buffer is too small, eat some of the data */ 
    97         if (*buflen < newsize) { 
    98                 size = maxsize; 
    99         } 
    100  
    101         p = s = (unsigned char *) buf; 
    102         q = (unsigned char *)data; 
    103  
    104         for(i=0;i<size;i+=BLKSIZE_RAW) { 
    105                 p[0] = cb64[((q[0] & 0xfc) >> 2)]; 
    106                 p[1] = cb64[(((q[0] & 0x03) << 4) | ((q[1] & 0xf0) >> 4))]; 
    107                 p[2] = (i+1 < size) ? cb64[((q[1] & 0x0f) << 2 ) | ((q[2] & 0xc0) >> 6)] : '\0'; 
    108                 p[3] = (i+2 < size) ? cb64[(q[2] & 0x3f)] : '\0'; 
    109                  
    110                 q += BLKSIZE_RAW; 
    111                 p += BLKSIZE_ENC; 
    112         }        
    113         *p = 0; 
    114  
    115         /* store number of bytes from data that was used */ 
    116         *buflen = size; 
    117  
    118         return strlen(buf); 
    119 } 
    120  
    121 #define DECODE_ERROR 0xffffffff 
    122  
    123 static int 
    124 decode_token(const unsigned char *t, unsigned char *data, size_t len)  
    125 { 
    126         if (len < 2) 
    127                 return 0; 
    128  
    129         data[0] = ((REV64(t[0]) & 0x3f) << 2) |  
    130                           ((REV64(t[1]) & 0x30) >> 4); 
    131  
    132         if (len < 3) 
    133                 return 1; 
    134  
    135         data[1] = ((REV64(t[1]) & 0x0f) << 4) |  
    136                           ((REV64(t[2]) & 0x3c) >> 2); 
    137  
    138         if (len < 4) 
    139                 return 2; 
    140  
    141         data[2] = ((REV64(t[2]) & 0x03) << 6) | 
    142                           (REV64(t[3]) & 0x3f); 
    143  
    144         return 3; 
    145 } 
    146  
    147 static int 
    148 base64_decode(void *buf, size_t *buflen, const char *str, size_t slen) 
    149 { 
    150         unsigned char *q; 
    151         size_t newsize; 
    152         size_t maxsize; 
    153         const char *p; 
    15480        unsigned char c; 
    155         unsigned char block[BLKSIZE_ENC]; 
    156         int len; 
    157         int i; 
    15881 
    15982        if (!reverse_init) { 
     83                memset (rev64, 0, 256); 
    16084                for (i = 0; i < 64; i++) { 
    16185                        c = cb64[i]; 
     
    16488                reverse_init = 1; 
    16589        } 
    166          
    167         /* chars needed to decode slen */ 
    168         newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1; 
    169         /* encoded chars that fit in buf */ 
    170         maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1; 
    171         /* if the buffer is too small, eat some of the data */ 
    172         if (*buflen < newsize) { 
    173                 slen = maxsize; 
     90} 
     91 
     92static int  
     93base64_encode(char *buf, size_t *buflen, const void *data, size_t size) 
     94/* 
     95 * Fills *buf with max. *buflen characters, encoding size bytes of *data. 
     96 * 
     97 * NOTE: *buf space should be at least 1 byte _more_ than *buflen 
     98 * to hold the trailing '\0'. 
     99 * 
     100 * return value    : #bytes filled in buf   (excluding \0) 
     101 * sets *buflen to : #bytes encoded from data 
     102 */ 
     103{ 
     104        unsigned char *udata = (unsigned char *) data; 
     105        int iout = 0;   /* to-be-filled output char */ 
     106        int iin = 0;    /* one more than last input byte that can be 
     107                           successfully decoded */ 
     108 
     109        /* Note: Don't bother to optimize manually. GCC optimizes 
     110           better(!) when using simplistic array indexing. */ 
     111 
     112        while (1) { 
     113                if (iout >= *buflen || iin >= size) 
     114                        break; 
     115                buf[iout] = cb64[((udata[iin] & 0xfc) >> 2)]; 
     116                iout++; 
     117 
     118                if (iout >= *buflen || iin >= size) { 
     119                        iout--;         /* previous char is useless */ 
     120                        break; 
     121                } 
     122                buf[iout] = cb64[((udata[iin] & 0x03) << 4) | 
     123                                  ((iin + 1 < size) ? 
     124                                   ((udata[iin + 1] & 0xf0) >> 4) : 0)]; 
     125                iin++;                  /* 0 complete, iin=1 */ 
     126                iout++; 
     127 
     128                if (iout >= *buflen || iin >= size) 
     129                        break; 
     130                buf[iout] = cb64[((udata[iin] & 0x0f) << 2 ) | 
     131                                  ((iin + 1 < size) ? 
     132                                   ((udata[iin + 1] & 0xc0) >> 6) : 0)]; 
     133                iin++;                  /* 1 complete, iin=2 */ 
     134                iout++; 
     135 
     136                if (iout >= *buflen || iin >= size) 
     137                        break; 
     138                buf[iout] = cb64[(udata[iin] & 0x3f)]; 
     139                iin++;                  /* 2 complete, iin=3 */ 
     140                iout++; 
    174141        } 
    175          
    176  
    177         q = buf; 
    178         for (p = str; *p; p += BLKSIZE_ENC) { 
    179                 /* since the str is const, we unescape in another buf */ 
    180                 for (i = 0; i < BLKSIZE_ENC; i++) { 
    181                         block[i] = p[i]; 
    182                 } 
    183                 len = decode_token(block, (unsigned char *) q, slen);    
    184                 q += len; 
    185                 slen -= BLKSIZE_ENC; 
    186                  
    187                 if (len < BLKSIZE_RAW) 
    188                         break; 
     142 
     143        buf[iout] = '\0'; 
     144 
     145        /* store number of bytes from data that was used */ 
     146        *buflen = iin; 
     147 
     148        return iout; 
     149} 
     150 
     151#define REV64(x) rev64[(int) (x)] 
     152 
     153static int 
     154base64_decode(void *buf, size_t *buflen, const char *str, size_t slen) 
     155/* 
     156 * Fills *buf with max. *buflen bytes, decoded from slen chars in *str. 
     157 * Decoding stops early when *str contains \0. 
     158 * Illegal encoded chars are assumed to decode to zero. 
     159 * 
     160 * NOTE: *buf space should be at least 1 byte _more_ than *buflen 
     161 * to hold a trailing '\0' that is added (though *buf will usually 
     162 * contain full-binary data). 
     163 * 
     164 * return value    : #bytes filled in buf   (excluding \0) 
     165 */ 
     166{ 
     167        unsigned char *ubuf = (unsigned char *) buf; 
     168        int iout = 0;   /* to-be-filled output byte */ 
     169        int iin = 0;    /* next input char to use in decoding */ 
     170 
     171        base64_reverse_init (); 
     172 
     173        /* Note: Don't bother to optimize manually. GCC optimizes 
     174           better(!) when using simplistic array indexing. */ 
     175 
     176        while (1) { 
     177                if (iout >= *buflen || iin + 1 >= slen || 
     178                    str[iin] == '\0' || str[iin + 1] == '\0') 
     179                        break; 
     180                ubuf[iout] = ((REV64(str[iin]) & 0x3f) << 2) |  
     181                             ((REV64(str[iin + 1]) & 0x30) >> 4); 
     182                iin++;                  /* 0 used up, iin=1 */ 
     183                iout++; 
     184 
     185                if (iout >= *buflen || iin + 1 >= slen || 
     186                    str[iin] == '\0' || str[iin + 1] == '\0') 
     187                        break; 
     188                ubuf[iout] = ((REV64(str[iin]) & 0x0f) << 4) |  
     189                             ((REV64(str[iin + 1]) & 0x3c) >> 2); 
     190                iin++;                  /* 1 used up, iin=2 */ 
     191                iout++; 
     192 
     193                if (iout >= *buflen || iin + 1 >= slen || 
     194                    str[iin] == '\0' || str[iin + 1] == '\0') 
     195                        break; 
     196                ubuf[iout] = ((REV64(str[iin]) & 0x03) << 6) | 
     197                             (REV64(str[iin + 1]) & 0x3f); 
     198                iin += 2;               /* 2,3 used up, iin=4 */ 
     199                iout++; 
    189200        } 
    190         *q = '\0'; 
    191          
    192         return q - (unsigned char *) buf; 
    193 } 
    194  
     201 
     202        ubuf[iout] = '\0'; 
     203 
     204        return iout; 
     205} 
  • src/client.c

    r1a26a9 rb17790  
    4646#include "base32.h" 
    4747#include "base64.h" 
     48#include "base64u.h" 
     49#include "base128.h" 
    4850#include "dns.h" 
    4951#include "login.h" 
     
    7072/* My userid at the server */ 
    7173static char userid; 
    72 static char userid_char;                /* used when sending (uppercase) */ 
    73 static char userid_char2;               /* also accepted when receiving (lowercase) */ 
     74static char userid_char;                /* used when sending (lowercase) */ 
     75static char userid_char2;               /* also accepted when receiving (uppercase) */ 
    7476 
    7577/* DNS id for next packet */ 
     
    8082/* Base32 encoder used for non-data packets and replies */ 
    8183static struct encoder *b32; 
    82 /* Base64 encoder for replies */ 
     84/* Base64 etc encoders for replies */ 
    8385static struct encoder *b64; 
     86static struct encoder *b64u; 
     87static struct encoder *b128; 
    8488 
    8589/* The encoder used for data packets 
     
    9195  
    9296/* set query type to send */ 
    93 static unsigned short do_qtype = T_NULL; 
     97static unsigned short do_qtype = T_UNSET; 
    9498 
    9599/* My connection mode */ 
    96100static enum connection conn; 
    97101 
    98 int selecttimeout;              /* RFC says timeout minimum 5sec */ 
    99  
    100 int lazymode; 
    101  
    102 long send_ping_soon; 
    103  
    104 time_t lastdownstreamtime; 
     102static int selecttimeout;               /* RFC says timeout minimum 5sec */ 
     103static int lazymode; 
     104static long send_ping_soon; 
     105static time_t lastdownstreamtime; 
     106static long send_query_sendcnt = -1; 
     107static long send_query_recvcnt = 0; 
     108static int hostname_maxlen = 0xFF; 
    105109 
    106110void 
     
    110114        b32 = get_base32_encoder(); 
    111115        b64 = get_base64_encoder(); 
     116        b64u = get_base64u_encoder(); 
     117        b128 = get_base128_encoder(); 
    112118        dataenc = get_base32_encoder(); 
    113119        rand_seed = ((unsigned int) rand()) & 0xFFFF; 
     
    209215        else if (!strcasecmp(qtype, "MX")) 
    210216                do_qtype = T_MX; 
     217        else if (!strcasecmp(qtype, "SRV")) 
     218                do_qtype = T_SRV; 
    211219        else if (!strcasecmp(qtype, "TXT")) 
    212220                do_qtype = T_TXT; 
     221} 
     222 
     223char * 
     224get_qtype() 
     225{ 
     226        char *c = "UNDEFINED"; 
     227 
     228        if (do_qtype == T_NULL)         c = "NULL"; 
     229        else if (do_qtype == T_CNAME)   c = "CNAME"; 
     230        else if (do_qtype == T_A)       c = "A"; 
     231        else if (do_qtype == T_MX)      c = "MX"; 
     232        else if (do_qtype == T_SRV)     c = "SRV"; 
     233        else if (do_qtype == T_TXT)     c = "TXT"; 
     234 
     235        return c; 
    213236} 
    214237 
     
    220243        else if (!strcasecmp(encoding, "base64")) 
    221244                downenc = 'S'; 
     245        else if (!strcasecmp(encoding, "base64u")) 
     246                downenc = 'U'; 
     247        else if (!strcasecmp(encoding, "base128")) 
     248                downenc = 'V'; 
    222249        else if (!strcasecmp(encoding, "raw")) 
    223250                downenc = 'R'; 
     
    234261{ 
    235262        lazymode = lazy_mode; 
     263} 
     264 
     265void 
     266client_set_hostname_maxlen(int i) 
     267{ 
     268        if (i <= 0xFF) 
     269                hostname_maxlen = i; 
    236270} 
    237271 
     
    265299        } 
    266300 
     301#if 0 
     302        fprintf(stderr, "  Sendquery: id %5d name[0] '%c'\n", q.id, hostname[0]); 
     303#endif 
     304 
    267305        sendto(fd, packet, len, 0, (struct sockaddr*)&nameserv, sizeof(nameserv)); 
     306 
     307        /* There are DNS relays that time out quickly but don't send anything 
     308           back on timeout. 
     309           And there are relays where, in lazy mode, our new query apparently 
     310           _replaces_ our previous query, and we get no answers at all in 
     311           lazy mode while legacy immediate-ping-pong works just fine. 
     312           Here we detect and fix these situations. 
     313           (Can't very well do this anywhere else; this is the only place 
     314           we'll reliably get to in such situations.) 
     315         */ 
     316 
     317        if (send_query_sendcnt >= 0 && send_query_sendcnt < 100 && lazymode) { 
     318                send_query_sendcnt++; 
     319 
     320                if ((send_query_sendcnt > 6 && send_query_recvcnt <= 0) || 
     321                    (send_query_sendcnt > 10 && 
     322                     4 * send_query_recvcnt < send_query_sendcnt)) { 
     323                        if (selecttimeout > 1) { 
     324                                warnx("Receiving too few answers. Setting interval to 1 (-I1)"); 
     325                                selecttimeout = 1; 
     326                                /* restart counting */ 
     327                                send_query_sendcnt = 0; 
     328                                send_query_recvcnt = 0; 
     329                        } else if (lazymode) { 
     330                                warnx("Receiving too few answers. Will try to switch lazy mode off, but that may not always work any more. Start with -L0 next time on this network."); 
     331                                lazymode = 0; 
     332                                selecttimeout = 1; 
     333                                handshake_lazyoff(fd); 
     334                        } 
     335                } 
     336        } 
    268337} 
    269338 
     
    302371        buf[0] = cmd; 
    303372         
    304         build_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain, b32); 
     373        build_hostname(buf + 1, sizeof(buf) - 1, data, datalen, topdomain, 
     374                       b32, hostname_maxlen); 
    305375        send_query(fd, buf); 
    306376} 
     
    319389        int code; 
    320390        char *p; 
     391        static int datacmc = 0; 
     392        char *datacmcchars = "abcdefghijklmnopqrstuvwxyz0123456789"; 
    321393 
    322394        p = outpkt.data; 
     
    324396        avail = outpkt.len - outpkt.offset; 
    325397 
    326         outpkt.sentlen = build_hostname(buf + 4, sizeof(buf) - 4, p, avail, topdomain, dataenc); 
     398        /* Note: must be same, or smaller than send_fragsize_probe() */ 
     399        outpkt.sentlen = build_hostname(buf + 5, sizeof(buf) - 5, p, avail, 
     400                                        topdomain, dataenc, hostname_maxlen); 
    327401 
    328402        /* Build upstream data header (see doc/proto_xxxxxxxx.txt) */ 
     
    338412        code = ((inpkt.fragment & 15) << 1) | (outpkt.sentlen == avail); 
    339413        buf[3] = b32_5to8(code); /* Fourth byte is 4 bits downstream fragment count, 1 bit last frag flag */ 
     414 
     415        buf[4] = datacmcchars[datacmc]; /* Fifth byte is data-CMC */ 
     416        datacmc++; 
     417        if (datacmc >= 36) 
     418                datacmc = 0; 
    340419   
    341420#if 0 
     
    373452 
    374453static void 
    375 write_dns_error(struct query *q) 
     454write_dns_error(struct query *q, int ignore_some_errors) 
     455/* This is called from: 
     456   1. handshake_waitdns() when already checked that reply fits to our 
     457      latest query. 
     458   2. tunnel_dns() when already checked that reply is for our ping or data 
     459      packet, but not necessarily the most recent (SERVFAIL mostly comes 
     460      after long delay). 
     461   So ignorable errors are never printed. 
     462*/ 
    376463{ 
    377464        if (!q) return; 
     
    379466        switch (q->rcode) { 
    380467        case NOERROR:   /* 0 */ 
    381                 warnx("Got reply without error, but also without question and/or answer"); 
     468                if (!ignore_some_errors) 
     469                        warnx("Got reply without error, but also without question and/or answer"); 
    382470                break; 
    383471        case FORMERR:   /* 1 */ 
     
    385473                break; 
    386474        case SERVFAIL:  /* 2 */ 
    387                 warnx("Got SERVFAIL as reply: server failed or recursion timeout"); 
     475                if (!ignore_some_errors) 
     476                        warnx("Got SERVFAIL as reply: server failed or recursion timeout"); 
    388477                break; 
    389478        case NXDOMAIN:  /* 3 */ 
     
    403492 
    404493static int 
    405 read_dns_withq(int dns_fd, int tun_fd, char *buf, int buflen, struct query *q) /* FIXME: tun_fd needed for raw handling */ 
     494dns_namedec(char *outdata, int outdatalen, char *buf, int buflen) 
     495/* Decodes *buf to *outdata. 
     496 * *buf WILL be changed by undotify. 
     497 * Note: buflen must be _exactly_ strlen(buf) before undotifying. 
     498 * (undotify of reduced-len won't copy \0, base-X decode will decode too much.) 
     499 * Returns #bytes usefully filled in outdata. 
     500 */ 
     501{ 
     502        size_t outdatalenu = outdatalen; 
     503 
     504        switch (buf[0]) { 
     505        case 'h': /* Hostname with base32 */ 
     506        case 'H': 
     507                /* Need 1 byte H, 3 bytes ".xy", >=1 byte data */ 
     508                if (buflen < 5) 
     509                        return 0; 
     510 
     511                /* this also does undotify */ 
     512                return unpack_data(outdata, outdatalen, buf + 1, buflen - 4, 
     513                                   b32); 
     514 
     515        case 'i': /* Hostname++ with base64 */ 
     516        case 'I': 
     517                /* Need 1 byte I, 3 bytes ".xy", >=1 byte data */ 
     518                if (buflen < 5) 
     519                        return 0; 
     520 
     521                /* this also does undotify */ 
     522                return unpack_data(outdata, outdatalen, buf + 1, buflen - 4, 
     523                                   b64); 
     524 
     525        case 'j': /* Hostname++ with base64u */ 
     526        case 'J': 
     527                /* Need 1 byte J, 3 bytes ".xy", >=1 byte data */ 
     528                if (buflen < 5) 
     529                        return 0; 
     530 
     531                /* this also does undotify */ 
     532                return unpack_data(outdata, outdatalen, buf + 1, buflen - 4, 
     533                                   b64u); 
     534 
     535        case 'k': /* Hostname++ with base128 */ 
     536        case 'K': 
     537                /* Need 1 byte J, 3 bytes ".xy", >=1 byte data */ 
     538                if (buflen < 5) 
     539                        return 0; 
     540 
     541                /* this also does undotify */ 
     542                return unpack_data(outdata, outdatalen, buf + 1, buflen - 4, 
     543                                   b128); 
     544 
     545        case 't': /* plain base32(Thirty-two) from TXT */ 
     546        case 'T': 
     547                if (buflen < 2) 
     548                        return 0; 
     549 
     550                return b32->decode(outdata, &outdatalenu, buf + 1, buflen - 1); 
     551 
     552        case 's': /* plain base64(Sixty-four) from TXT */ 
     553        case 'S': 
     554                if (buflen < 2) 
     555                        return 0; 
     556 
     557                return b64->decode(outdata, &outdatalenu, buf + 1, buflen - 1); 
     558 
     559        case 'u': /* plain base64u (Underscore) from TXT */ 
     560        case 'U': 
     561                if (buflen < 2) 
     562                        return 0; 
     563 
     564                return b64u->decode(outdata, &outdatalenu, buf + 1, buflen - 1); 
     565 
     566        case 'v': /* plain base128 from TXT */ 
     567        case 'V': 
     568                if (buflen < 2) 
     569                        return 0; 
     570 
     571                return b128->decode(outdata, &outdatalenu, buf + 1, buflen - 1); 
     572 
     573        case 'r': /* Raw binary from TXT */ 
     574        case 'R': 
     575                /* buflen>=1 already checked */ 
     576                buflen--; 
     577                buflen = MIN(buflen, outdatalen); 
     578                memcpy(outdata, buf + 1, buflen); 
     579                return buflen; 
     580 
     581        default: 
     582                warnx("Received unsupported encoding"); 
     583                return 0; 
     584        } 
     585 
     586        /* notreached */ 
     587        return 0; 
     588} 
     589 
     590static int 
     591read_dns_withq(int dns_fd, int tun_fd, char *buf, int buflen, struct query *q) 
     592/* FIXME: tun_fd needed for raw handling */ 
     593/* Returns -1 on receive error or decode error, including DNS error replies. 
     594   Returns 0 on replies that could be correct but are useless, and are not 
     595   DNS error replies. 
     596   Returns >0 on correct replies; value is #valid bytes in *buf. 
     597*/ 
    406598{ 
    407599        struct sockaddr_in from; 
     
    427619                        return rv; 
    428620 
    429                 if (q->type == T_CNAME || q->type == T_MX || q->type == T_TXT) 
    430                 /* CNAME an also be returned from an A (or MX) question */ 
     621                if (q->type == T_CNAME || q->type == T_TXT) 
     622                /* CNAME can also be returned from an A question */ 
    431623                { 
    432                         size_t space; 
    433  
    434624                        /* 
    435625                         * buf is a hostname or txt stream that we still need to 
     
    441631                         */ 
    442632 
    443                         switch (buf[0]) { 
    444                         case 'h': /* Hostname with base32 */ 
    445                         case 'H': 
    446                                 if (rv < 5) { 
    447                                         /* 1 byte H, 3 bytes ".xy", >=1 byte data */ 
    448                                         rv = 0; 
     633                        rv = dns_namedec(data, sizeof(data), buf, rv); 
     634 
     635                        rv = MIN(rv, buflen); 
     636                        if (rv > 0) 
     637                                memcpy(buf, data, rv); 
     638 
     639                } else if (q->type == T_MX || q->type == T_SRV) { 
     640                        /* buf is like "Hname.com\0Hanother.com\0\0" */ 
     641                        int buftotal = rv;      /* idx of last \0 */ 
     642                        int bufoffset = 0; 
     643                        int dataoffset = 0; 
     644                        int thispartlen, dataspace, datanew; 
     645 
     646                        while (1) { 
     647                                thispartlen = strlen(buf); 
     648                                thispartlen = MIN(thispartlen, buftotal-bufoffset); 
     649                                dataspace = sizeof(data) - dataoffset; 
     650                                if (thispartlen <= 0 || dataspace <= 0) 
    449651                                        break; 
    450                                 } 
    451  
    452                                 rv -= 3;        /* rv=strlen, strip ".xy" */ 
    453                                 rv = unpack_data (data, sizeof(data), buf + 1, rv - 1, b32); 
    454                                 /* this also does undotify */ 
    455  
    456                                 rv = MIN(rv, buflen); 
     652 
     653                                datanew = dns_namedec(data + dataoffset, dataspace, 
     654                                                      buf + bufoffset, thispartlen); 
     655                                if (datanew <= 0) 
     656                                        break; 
     657 
     658                                bufoffset += thispartlen + 1; 
     659                                dataoffset += datanew; 
     660                        } 
     661                        rv = dataoffset; 
     662                        rv = MIN(rv, buflen); 
     663                        if (rv > 0) 
    457664                                memcpy(buf, data, rv); 
    458                                 break; 
    459                         case 'i': /* Hostname++ with base64 */ 
    460                         case 'I': 
    461                                 if (rv < 5) { 
    462                                         /* 1 byte H, 3 bytes ".xy", >=1 byte data */ 
    463                                         rv = 0; 
    464                                         break; 
    465                                 } 
    466  
    467                                 rv -= 3;        /* rv=strlen, strip ".xy" */ 
    468                                 rv = unpack_data (data, sizeof(data), buf + 1, rv - 1, b64); 
    469                                 /* this also does undotify */ 
    470  
    471                                 rv = MIN(rv, buflen); 
    472                                 memcpy(buf, data, rv); 
    473                                 break; 
    474                         case 't': /* plain base32(Thirty-two) from TXT */ 
    475                         case 'T': 
    476                                 if (rv < 2) { 
    477                                         rv = 0; 
    478                                         break; 
    479                                 } 
    480  
    481                                 space = sizeof(data); 
    482                                 rv = b32->decode (data, &space, buf + 1, rv - 1); 
    483                                 rv = MIN(rv, buflen); 
    484                                 memcpy(buf, data, rv); 
    485                                 break; 
    486                         case 's': /* plain base64(Sixty-four) from TXT */ 
    487                         case 'S': 
    488                                 if (rv < 2) { 
    489                                         rv = 0; 
    490                                         break; 
    491                                 } 
    492  
    493                                 space = sizeof(data); 
    494                                 rv = b64->decode (data, &space, buf + 1, rv - 1); 
    495                                 rv = MIN(rv, buflen); 
    496                                 memcpy(buf, data, rv); 
    497                                 break; 
    498                         case 'r': /* Raw binary from TXT */ 
    499                         case 'R': 
    500                                 rv--;                   /* rv>=1 already checked */ 
    501                                 memmove(buf, buf+1, rv); 
    502                                 break; 
    503                         default: 
    504                                 warnx("Received unsupported encoding"); 
    505                                 rv = 0; 
    506                                 break; 
    507                         } 
    508665                } 
    509666 
     
    517674                /* should start with header */ 
    518675                if (memcmp(data, raw_header, RAW_HDR_IDENT_LEN)) return 0; 
     676                /* should be my user id */ 
     677                if (RAW_HDR_GET_USR(data) != userid) return 0; 
     678 
     679                if (RAW_HDR_GET_CMD(data) == RAW_HDR_CMD_DATA || 
     680                    RAW_HDR_GET_CMD(data) == RAW_HDR_CMD_PING) 
     681                        lastdownstreamtime = time(NULL); 
     682 
    519683                /* should be data packet */ 
    520684                if (RAW_HDR_GET_CMD(data) != RAW_HDR_CMD_DATA) return 0; 
    521                 /* should be my user id */ 
    522                 if (RAW_HDR_GET_USR(data) != userid) return 0; 
    523685 
    524686                r -= RAW_HDR_LEN; 
     
    527689                        write_tun(tun_fd, buf, datalen); 
    528690                } 
     691 
     692                /* don't process any further */ 
    529693                return 0; 
    530694        } 
    531695} 
    532696 
    533 static inline int 
    534 read_dns_namecheck(int dns_fd, int tun_fd, char *buf, int buflen, char c1, char c2) 
    535 /* Only returns >0 when the query hostname in the received packet matches 
    536    either c1 or c2; used to tell handshake-dupes apart. 
     697static int 
     698handshake_waitdns(int dns_fd, char *buf, int buflen, char c1, char c2, int timeout) 
     699/* Wait for DNS reply fitting to our latest query and returns it. 
     700   Returns length of reply = #bytes used in buf. 
     701   Returns 0 if fitting reply happens to be useless. 
     702   Returns -2 on (at least) DNS error that fits to our latest query, 
     703   error message already printed. 
     704   Returns -3 on timeout (given in seconds). 
     705   Returns -1 on other errors. 
     706 
     707   Timeout is restarted when "wrong" (previous/delayed) replies are received, 
     708   so effective timeout may be longer than specified. 
    537709*/ 
    538710{ 
    539711        struct query q; 
    540         int rv; 
    541  
    542         rv = read_dns_withq(dns_fd, tun_fd, buf, buflen, &q); 
    543  
    544         /* Filter out any other replies */ 
    545         if (q.name[0] != c1 && q.name[0] != c2) 
    546                 return 0; 
    547          
    548         /* Print rcode errors */ 
    549         if (rv < 0) { 
    550                 write_dns_error(&q); 
    551         } 
    552          
    553         return rv;      /* may also be 0 = useless or -1 = error (printed) */ 
     712        int r, rv; 
     713        fd_set fds; 
     714        struct timeval tv; 
     715 
     716        while (1) { 
     717                tv.tv_sec = timeout; 
     718                tv.tv_usec = 0; 
     719                FD_ZERO(&fds); 
     720                FD_SET(dns_fd, &fds); 
     721                r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
     722 
     723                if (r < 0) 
     724                        return -1;      /* select error */ 
     725                if (r == 0) 
     726                        return -3;      /* select timeout */ 
     727 
     728                q.id = 0; 
     729                q.name[0] = '\0'; 
     730                rv = read_dns_withq(dns_fd, 0, buf, buflen, &q); 
     731 
     732                if (q.id != chunkid || (q.name[0] != c1 && q.name[0] != c2)) { 
     733#if 0 
     734                        fprintf(stderr, "Ignoring unfitting reply id %d starting with '%c'\n", q.id, q.name[0]); 
     735#endif 
     736                        continue; 
     737                } 
     738 
     739                /* if still here: reply matches our latest query */ 
     740 
     741                /* Non-recursive DNS servers (such as [a-m].root-servers.net) 
     742                   return no answer, but only additional and authority records. 
     743                   Can't explicitly test for that here, just assume that 
     744                   NOERROR is such situation. Only trigger on the very first 
     745                   requests (Y or V, depending if -T given). 
     746                 */ 
     747                if (rv < 0 && q.rcode == NOERROR && 
     748                    (q.name[0] == 'Y' || q.name[0] == 'y' || 
     749                     q.name[0] == 'V' || q.name[0] == 'v')) { 
     750                        fprintf(stderr, "Got empty reply. This nameserver may not be resolving recursively, use another.\n"); 
     751                        fprintf(stderr, "Try \"iodine [options] ns.%s %s\" first, it might just work.\n", 
     752                                topdomain, topdomain); 
     753                        return -2; 
     754                } 
     755 
     756                /* If we get an immediate SERVFAIL on the handshake query 
     757                   we're waiting for, wait a while before sending the next. 
     758                   SERVFAIL reliably happens during fragsize autoprobe, but 
     759                   mostly long after we've moved along to some other queries. 
     760                   However, some DNS relays, once they throw a SERVFAIL, will 
     761                   for several seconds apply it immediately to _any_ new query 
     762                   for the same topdomain. When this happens, waiting a while 
     763                   is the only option that works. 
     764                 */ 
     765                if (rv < 0 && q.rcode == SERVFAIL) 
     766                        sleep(1); 
     767 
     768                if (rv < 0) { 
     769                        write_dns_error(&q, 1); 
     770                        return -2; 
     771                } 
     772                /* rv either 0 or >0, return it as is. */ 
     773                return rv; 
     774        } 
     775 
     776        /* not reached */ 
     777        return -1; 
    554778} 
    555779 
     
    599823        static long packrecv = 0; 
    600824        static long packrecv_oos = 0; 
     825        static long packrecv_servfail = 0; 
    601826        int up_ack_seqno; 
    602827        int up_ack_fragment; 
     
    612837        read = read_dns_withq(dns_fd, tun_fd, buf, sizeof(buf), &q); 
    613838 
    614         /* Don't process anything that isn't data for us */ 
     839        if (conn != CONN_DNS_NULL) 
     840                return 1;  /* everything already done */ 
     841 
     842#if 0 
     843        fprintf(stderr, "                               Recv: id %5d name[0]='%c'\n", 
     844                q.id, q.name[0]); 
     845#endif 
     846 
     847        /* Don't process anything that isn't data for us; usually error 
     848           replies from fragsize probes etc. However a sequence of those, 
     849           mostly 1 sec apart, will continuously break the >=2-second select 
     850           timeout, which means we won't send a proper ping for a while. 
     851           So make select a bit faster, <1sec. */ 
    615852        if (q.name[0] != 'P' && q.name[0] != 'p' && 
    616             q.name[0] != userid_char && q.name[0] != userid_char2) 
     853            q.name[0] != userid_char && q.name[0] != userid_char2) { 
     854                send_ping_soon = 700; 
    617855                return -1;      /* nothing done */ 
     856        } 
    618857 
    619858        if (read < 2) { 
    620859                /* Maybe SERVFAIL etc. Send ping to get things back in order, 
    621860                   but wait a bit to prevent fast ping-pong loops. */ 
    622                 write_dns_error(&q); 
     861 
     862                if (read < 0) 
     863                        write_dns_error(&q, 0); 
     864 
     865                if (read < 0 && q.rcode == SERVFAIL && lazymode && 
     866                    selecttimeout > 1) { 
     867                        if (packrecv < 500 && packrecv_servfail < 4) { 
     868                                packrecv_servfail++; 
     869                                warnx("Hmm, that's %ld. Your data should still go through...", packrecv_servfail); 
     870                        } else if (packrecv < 500 && packrecv_servfail == 4) { 
     871                                packrecv_servfail++; 
     872                                warnx("I think %ld is too many. Setting interval to 1 to hopefully reduce SERVFAILs. But just ignore them if data still comes through. (Use -I1 next time on this network.)", packrecv_servfail); 
     873                                selecttimeout = 1; 
     874                                send_query_sendcnt = 0; 
     875                                send_query_recvcnt = 0; 
     876                        } else if (packrecv >= 500 && packrecv_servfail > 0) { 
     877                                warnx("(Sorry, stopped counting; try -I1 if you experience hiccups.)"); 
     878                                packrecv_servfail = 0; 
     879                        } 
     880                } 
     881 
     882                /* read==1 happens with "QMEM" illegal replies, caused by 
     883                   heavy reordering, or after short disconnections when 
     884                   data-CMC has looped around into the "duplicate" values. 
     885                   All these cases are helped by faster pinging. */ 
     886#if 0 
     887                if (read == 1) 
     888                        fprintf(stderr, "   q=%c id %5d 1-byte illegal \"QMEM\" reply\n", q.name[0], q.id); 
     889#endif 
     890 
    623891                send_ping_soon = 900; 
    624892                return -1;      /* nothing done */ 
     
    644912 
    645913#if 0 
    646         fprintf(stderr, "                                       Recv: down %d/%d up %d/%d, %d bytes\n", 
    647                 new_down_seqno, new_down_fragment, up_ack_seqno, 
     914        fprintf(stderr, "                               Recv: id %5d down %d/%d up %d/%d, %d bytes\n", 
     915                q.id, new_down_seqno, new_down_fragment, up_ack_seqno, 
    648916                up_ack_fragment, read); 
    649917#endif 
     
    666934        } 
    667935 
    668         packrecv++; 
    669  
    670         /* Don't process any non-recent stuff any further */ 
     936        if (!(packrecv & 0x1000000)) 
     937                packrecv++; 
     938        send_query_recvcnt++;  /* overflow doesn't matter */ 
     939 
     940        /* Don't process any non-recent stuff any further. 
     941           No need to remember more than 3 ids: in practice any older replies 
     942           arrive after new/current replies, and whatever data the old replies 
     943           have, it has become useless in the mean time. 
     944           Actually, ever since iodined is replying to both the original query 
     945           and the last dupe, this hardly triggers any more. 
     946         */ 
    671947        if (q.id != chunkid && q.id != chunkid_prev && q.id != chunkid_prev2) { 
    672948                packrecv_oos++; 
     
    674950                fprintf(stderr, "   q=%c Packs received = %8ld  Out-of-sequence = %8ld\n", q.name[0], packrecv, packrecv_oos); 
    675951#endif 
    676                 if (lazymode && packrecv < 600 && packrecv_oos == 5) 
    677                         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."); 
    678                 if (lazymode && packrecv < 600 && packrecv_oos == 15) { 
    679                         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."); 
    680                         lazymode = 0; 
     952                if (lazymode && packrecv < 1000 && packrecv_oos == 5) { 
     953                        if (selecttimeout > 1) 
     954                                warnx("Hmm, getting some out-of-sequence DNS replies. Setting interval to 1 (use -I1 next time on this network). If data traffic still has large hiccups, try if -L0 works better."); 
     955                        else 
     956                                warnx("Hmm, getting some out-of-sequence DNS replies. If data traffic often has large hiccups, try running with -L0 ."); 
    681957                        selecttimeout = 1; 
    682                         handshake_lazyoff(dns_fd); 
     958                        send_query_sendcnt = 0; 
     959                        send_query_recvcnt = 0; 
    683960                } 
    684961 
     
    697974 
    698975        /* In lazy mode, we shouldn't get much replies to our most-recent 
    699            query, only during heavy data transfer. Except when severe packet 
    700            reordering occurs, such as opendns... Since this means the server 
     976           query, only during heavy data transfer. Since this means the server 
    701977           doesn't have any packets left, send one relatively fast (but not 
    702978           too fast, to avoid runaway ping-pong loops..) */ 
     
    8571133        rv = 0; 
    8581134        lastdownstreamtime = time(NULL); 
     1135        send_query_sendcnt = 0;  /* start counting now */ 
    8591136 
    8601137        while (running) { 
     
    9751252        probedata[1] = MAX(1, (rand_seed >> 8) & 0xff); 
    9761253        rand_seed++; 
    977         build_hostname(buf + 4, sizeof(buf) - 4, probedata, sizeof(probedata), topdomain, dataenc); 
     1254 
     1255        /* Note: must either be same, or larger, than send_chunk() */ 
     1256        build_hostname(buf + 5, sizeof(buf) - 5, probedata, sizeof(probedata), 
     1257                       topdomain, dataenc, hostname_maxlen); 
    9781258 
    9791259        fragsize &= 2047; 
     
    9831263        buf[2] = b32_5to8((fragsize >> 5) & 31); 
    9841264        buf[3] = b32_5to8(fragsize & 31); 
     1265        buf[4] = 'd'; /* dummy to match send_chunk() */ 
    9851266 
    9861267        send_query(fd, buf); 
     
    10181299        rand_seed++; 
    10191300 
    1020         send_packet(fd, 'V', data, sizeof(data)); 
     1301        send_packet(fd, 'v', data, sizeof(data)); 
    10211302} 
    10221303 
     
    10241305send_ip_request(int fd, int userid) 
    10251306{ 
    1026         char buf[512] = "I____."; 
     1307        char buf[512] = "i____."; 
    10271308        buf[1] = b32_5to8(userid); 
    10281309         
     
    10461327 
    10471328static void 
    1048 send_case_check(int fd) 
    1049 { 
    1050         /* The '+' plus character is not allowed according to RFC.  
    1051          * Expect to get SERVFAIL or similar if it is rejected. 
    1052          */ 
    1053         char buf[512] = "zZ+-aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyY1234."; 
     1329send_upenctest(int fd, char *s) 
     1330/* NOTE: String may be at most 63-4=59 chars to fit in 1 dns chunk. */ 
     1331{ 
     1332        char buf[512] = "z___"; 
     1333         
     1334        buf[1] = b32_5to8((rand_seed >> 10) & 0x1f); 
     1335        buf[2] = b32_5to8((rand_seed >> 5) & 0x1f); 
     1336        buf[3] = b32_5to8((rand_seed ) & 0x1f); 
     1337        rand_seed++; 
     1338 
     1339        strncat(buf, s, 512); 
     1340        strncat(buf, ".", 512); 
     1341        strncat(buf, topdomain, 512 - strlen(buf)); 
     1342        send_query(fd, buf); 
     1343} 
     1344 
     1345static void 
     1346send_downenctest(int fd, char downenc, int variant, char *s, int slen) 
     1347/* Note: content/handling of s is not defined yet. */ 
     1348{ 
     1349        char buf[512] = "y_____."; 
     1350 
     1351        buf[1] = tolower(downenc); 
     1352        buf[2] = b32_5to8(variant); 
     1353 
     1354        buf[3] = b32_5to8((rand_seed >> 10) & 0x1f); 
     1355        buf[4] = b32_5to8((rand_seed >> 5) & 0x1f); 
     1356        buf[5] = b32_5to8((rand_seed ) & 0x1f); 
     1357        rand_seed++; 
    10541358 
    10551359        strncat(buf, topdomain, 512 - strlen(buf)); 
     
    10931397send_lazy_switch(int fd, int userid) 
    10941398{ 
    1095         char buf[512] = "o__."; 
     1399        char buf[512] = "o_____."; 
    10961400        buf[1] = b32_5to8(userid); 
    10971401 
     
    11011405                buf[2] = 'i'; 
    11021406 
     1407        buf[3] = b32_5to8((rand_seed >> 10) & 0x1f); 
     1408        buf[4] = b32_5to8((rand_seed >> 5) & 0x1f); 
     1409        buf[5] = b32_5to8((rand_seed ) & 0x1f); 
     1410        rand_seed++; 
     1411 
    11031412        strncat(buf, topdomain, 512 - strlen(buf)); 
    11041413        send_query(fd, buf); 
     
    11101419        char hex[] = "0123456789abcdef"; 
    11111420        char hex2[] = "0123456789ABCDEF"; 
    1112         struct timeval tv; 
    11131421        char in[4096]; 
    1114         fd_set fds; 
    11151422        uint32_t payload; 
    11161423        int i; 
    1117         int r; 
    11181424        int read; 
    11191425 
    11201426        for (i = 0; running && i < 5; i++) { 
    1121                 tv.tv_sec = i + 1; 
    1122                 tv.tv_usec = 0; 
    11231427 
    11241428                send_version(dns_fd, VERSION); 
    1125                  
    1126                 FD_ZERO(&fds); 
    1127                 FD_SET(dns_fd, &fds); 
    1128  
    1129                 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
    1130  
    1131                 if(r > 0) { 
    1132                         read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'v', 'V'); 
    1133  
    1134                         if(read <= 0) 
    1135                                 continue; 
    1136  
     1429 
     1430                read = handshake_waitdns(dns_fd, in, sizeof(in), 'v', 'V', i+1); 
     1431 
     1432                /*XXX START adjust indent 1 tab back*/ 
    11371433                        if (read >= 9) { 
    11381434                                payload =  (((in[4] & 0xff) << 24) | 
     
    11571453                                        return 1; 
    11581454                                } 
    1159                         } else  
     1455                        } else if (read > 0) 
    11601456                                warnx("did not receive proper login challenge"); 
    1161                 } 
     1457                /*XXX END adjust indent 1 tab back*/ 
    11621458                 
    11631459                fprintf(stderr, "Retrying version check...\n"); 
     
    11701466handshake_login(int dns_fd, int seed) 
    11711467{ 
    1172         struct timeval tv; 
    11731468        char in[4096]; 
    11741469        char login[16]; 
     
    11761471        char client[65]; 
    11771472        int mtu; 
    1178         fd_set fds; 
    11791473        int i; 
    1180         int r; 
    11811474        int read; 
    11821475 
     
    11841477         
    11851478        for (i=0; running && i<5 ;i++) { 
    1186                 tv.tv_sec = i + 1; 
    1187                 tv.tv_usec = 0; 
    11881479 
    11891480                send_login(dns_fd, login, 16); 
    1190                  
    1191                 FD_ZERO(&fds); 
    1192                 FD_SET(dns_fd, &fds); 
    1193  
    1194                 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
    1195  
    1196                 if(r > 0) { 
    1197                         read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'l', 'L'); 
    1198  
    1199                         if(read <= 0) 
    1200                                 continue; 
    1201  
     1481 
     1482                read = handshake_waitdns(dns_fd, in, sizeof(in), 'l', 'L', i+1); 
     1483 
     1484                /*XXX START adjust indent 1 tab back*/ 
    12021485                        if (read > 0) { 
    12031486                                int netmask; 
     
    12221505                                } 
    12231506                        } 
    1224                 } 
     1507                /*XXX END adjust indent 1 tab back*/ 
    12251508 
    12261509                fprintf(stderr, "Retrying login...\n"); 
     
    12421525        struct in_addr server; 
    12431526 
    1244         fprintf(stderr, "Testing raw UDP data to the server (skip with -r)\n"); 
     1527        fprintf(stderr, "Testing raw UDP data to the server (skip with -r)"); 
    12451528        for (i=0; running && i<3 ;i++) { 
    1246                 tv.tv_sec = i + 1; 
    1247                 tv.tv_usec = 0; 
    12481529 
    12491530                send_ip_request(dns_fd, userid); 
    1250                  
    1251                 FD_ZERO(&fds); 
    1252                 FD_SET(dns_fd, &fds); 
    1253  
    1254                 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
    1255  
    1256                 if(r > 0) { 
    1257                         len = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'i', 'I'); 
     1531 
     1532                len = handshake_waitdns(dns_fd, in, sizeof(in), 'i', 'I', i+1); 
     1533 
     1534                /*XXX START adjust indent 1 tab back*/ 
    12581535                        if (len == 5 && in[0] == 'I') { 
    12591536                                /* Received IP address */ 
     
    12681545                                break; 
    12691546                        } 
    1270                 } else { 
    1271                         fprintf(stderr, "."); 
    1272                         fflush(stderr); 
    1273                 } 
    1274         } 
     1547                /*XXX END adjust indent 1 tab back*/ 
     1548 
     1549                fprintf(stderr, "."); 
     1550                fflush(stderr); 
     1551        } 
     1552        fprintf(stderr, "\n"); 
     1553        if (!running) 
     1554                return 0; 
    12751555         
    12761556        if (!remoteaddr) { 
     
    13251605 
    13261606static int 
    1327 handshake_case_check(int dns_fd) 
    1328 { 
    1329         struct timeval tv; 
     1607handshake_upenctest(int dns_fd, char *s) 
     1608/* NOTE: *s may be max 59 chars; must start with "aA" for case-swap check 
     1609   Returns: 
     1610   -1: case swap, no need for any further test: error printed; or Ctrl-C 
     1611   0: not identical or error or timeout 
     1612   1: identical string returned 
     1613*/ 
     1614{ 
    13301615        char in[4096]; 
    1331         fd_set fds; 
     1616        unsigned char *uin = (unsigned char *) in; 
     1617        unsigned char *us = (unsigned char *) s; 
    13321618        int i; 
    1333         int r; 
    13341619        int read; 
    1335         int case_preserved; 
    1336  
    1337         case_preserved = 0; 
     1620        int slen; 
     1621 
     1622        slen = strlen(s); 
     1623        for (i=0; running && i<3 ;i++) { 
     1624 
     1625                send_upenctest(dns_fd, s); 
     1626 
     1627                read = handshake_waitdns(dns_fd, in, sizeof(in), 'z', 'Z', i+1); 
     1628 
     1629                if (read == -2) 
     1630                        return 0;       /* hard error */ 
     1631 
     1632                if (read > 0 && read < slen + 4) 
     1633                        return 0;       /* reply too short (chars dropped) */ 
     1634 
     1635                if (read > 0) { 
     1636                        int k; 
     1637#if 0 
     1638                        /* in[56] = '@'; */ 
     1639                        /* in[56] = '_'; */ 
     1640                        /* if (in[29] == '\344') in[29] = 'a'; */ 
     1641                        in[read] = '\0'; 
     1642                        fprintf(stderr, "BounceReply: >%s<\n", in); 
     1643#endif 
     1644                        /* quick check if case swapped, to give informative error msg */ 
     1645                        if (in[4] == 'A') { 
     1646                                fprintf(stderr, "DNS queries get changed to uppercase, keeping upstream codec Base32\n"); 
     1647                                return -1; 
     1648                        } 
     1649                        if (in[5] == 'a') { 
     1650                                fprintf(stderr, "DNS queries get changed to lowercase, keeping upstream codec Base32\n"); 
     1651                                return -1; 
     1652                        } 
     1653 
     1654                        for (k = 0; k < slen; k++) { 
     1655                                if (in[k+4] != s[k]) { 
     1656                                        /* Definitely not reliable */ 
     1657                                        if (in[k+4] >= ' ' && in[k+4] <= '~' && 
     1658                                            s[k] >= ' ' && s[k] <= '~') { 
     1659                                                fprintf(stderr, "DNS query char '%c' gets changed into '%c'\n", 
     1660                                                        s[k], in[k+4]); 
     1661                                        } else { 
     1662                                                fprintf(stderr, "DNS query char 0x%02X gets changed into 0x%02X\n", 
     1663                                                        (unsigned int) us[k], 
     1664                                                        (unsigned int) uin[k+4]); 
     1665                                        } 
     1666                                        return 0; 
     1667                                } 
     1668                        } 
     1669                        /* if still here, then all okay */ 
     1670                        return 1; 
     1671                } 
     1672 
     1673                fprintf(stderr, "Retrying upstream codec test...\n"); 
     1674        } 
     1675 
     1676        if (!running) 
     1677                return -1; 
     1678 
     1679        /* timeout */ 
     1680        return 0; 
     1681} 
     1682 
     1683static int 
     1684handshake_upenc_autodetect(int dns_fd) 
     1685/* Returns: 
     1686   0: keep Base32 
     1687   1: Base64 is okay 
     1688   2: Base64u is okay 
     1689   3: Base128 is okay 
     1690*/ 
     1691{ 
     1692        /* Note: max 59 chars, must start with "aA". 
     1693           pat64: If 0129 work, assume 3-8 are okay too. 
     1694 
     1695           RFC1035 par 2.3.1 states that [A-Z0-9-] allowed, but only 
     1696           [A-Z] as first, and [A-Z0-9] as last char _per label_. 
     1697           Test by having '-' as last char. 
     1698         */ 
     1699        char *pat64="aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ+0129-"; 
     1700        char *pat64u="aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ_0129-"; 
     1701        char *pat128a="aA-Aaahhh-Drink-mal-ein-J\344germeister-"; 
     1702        char *pat128b="aA-La-fl\373te-na\357ve-fran\347aise-est-retir\351-\340-Cr\350te"; 
     1703        char *pat128c="aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"; 
     1704        char *pat128d="aA0123456789\274\275\276\277" 
     1705                      "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"; 
     1706        char *pat128e="aA" 
     1707                      "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" 
     1708                      "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" 
     1709                      "\360\361\362\363\364\365\366\367\370\371\372\373\374\375"; 
     1710        int res; 
     1711 
     1712        /* Try Base128, starting very gently to not draw attention */ 
     1713        while (1) { 
     1714                res = handshake_upenctest(dns_fd, pat128a); 
     1715                if (res < 0) { 
     1716                        /* DNS swaps case, msg already printed; or Ctrl-C */ 
     1717                        return 0; 
     1718                } else if (res == 0) { 
     1719                        /* Probably not okay, skip Base128 entirely */ 
     1720                        break; 
     1721                } 
     1722 
     1723                res = handshake_upenctest(dns_fd, pat128b); 
     1724                if (res < 0) 
     1725                        return 0; 
     1726                else if (res == 0) 
     1727                        break; 
     1728 
     1729                /* if this works, we can test the real stuff */ 
     1730 
     1731                res = handshake_upenctest(dns_fd, pat128c); 
     1732                if (res < 0) 
     1733                        return 0; 
     1734                else if (res == 0) 
     1735                        break; 
     1736 
     1737                res = handshake_upenctest(dns_fd, pat128d); 
     1738                if (res < 0) 
     1739                        return 0; 
     1740                else if (res == 0) 
     1741                        break; 
     1742 
     1743                res = handshake_upenctest(dns_fd, pat128e); 
     1744                if (res < 0) 
     1745                        return 0; 
     1746                else if (res == 0) 
     1747                        break; 
     1748 
     1749                /* if still here, then base128 works completely */ 
     1750                return 3; 
     1751        } 
     1752 
     1753        /* Try Base64 (with plus sign) */ 
     1754        res = handshake_upenctest(dns_fd, pat64); 
     1755        if (res < 0) { 
     1756                /* DNS swaps case, msg already printed; or Ctrl-C */ 
     1757                return 0; 
     1758        } else if (res > 0) { 
     1759                /* All okay, Base64 msg will be printed later */ 
     1760                return 1; 
     1761        } 
     1762 
     1763        /* Try Base64u (with _u_nderscore) */ 
     1764        res = handshake_upenctest(dns_fd, pat64u); 
     1765        if (res < 0) { 
     1766                /* DNS swaps case, msg already printed; or Ctrl-C */ 
     1767                return 0; 
     1768        } else if (res > 0) { 
     1769                /* All okay, Base64u msg will be printed later */ 
     1770                return 2; 
     1771        } 
     1772 
     1773        /* if here, then nonthing worked */ 
     1774        fprintf(stderr, "Keeping upstream codec Base32\n"); 
     1775        return 0; 
     1776} 
     1777 
     1778static int 
     1779handshake_downenctest(int dns_fd, char trycodec) 
     1780/* Returns: 
     1781   0: not identical or error or timeout 
     1782   1: identical string returned 
     1783*/ 
     1784{ 
     1785        char in[4096]; 
     1786        int i; 
     1787        int read; 
     1788        char *s = DOWNCODECCHECK1; 
     1789        int slen = DOWNCODECCHECK1_LEN; 
     1790 
     1791        for (i=0; running && i<3 ;i++) { 
     1792 
     1793                send_downenctest(dns_fd, trycodec, 1, NULL, 0); 
     1794 
     1795                read = handshake_waitdns(dns_fd, in, sizeof(in), 'y', 'Y', i+1); 
     1796 
     1797                if (read == -2) 
     1798                        return 0;       /* hard error */ 
     1799 
     1800                if (read > 0 && read != slen) 
     1801                        return 0;       /* reply incorrect = unreliable */ 
     1802 
     1803                if (read > 0) { 
     1804                        int k; 
     1805                        for (k = 0; k < slen; k++) { 
     1806                                if (in[k] != s[k]) { 
     1807                                        /* Definitely not reliable */ 
     1808                                        return 0; 
     1809                                } 
     1810                        } 
     1811                        /* if still here, then all okay */ 
     1812                        return 1; 
     1813                } 
     1814 
     1815                fprintf(stderr, "Retrying downstream codec test...\n"); 
     1816        } 
     1817 
     1818        /* timeout */ 
     1819        return 0; 
     1820} 
     1821 
     1822static char 
     1823handshake_downenc_autodetect(int dns_fd) 
     1824/* Returns codec char (or ' ' if no advanced codec works) */ 
     1825{ 
     1826        int base64ok = 0; 
     1827        int base64uok = 0; 
     1828        int base128ok = 0; 
     1829 
     1830        if (do_qtype == T_NULL) { 
     1831                /* no other choice than raw */ 
     1832                fprintf(stderr, "No alternative downstream codec available, using default (Raw)\n"); 
     1833                return ' '; 
     1834        } 
     1835 
     1836        fprintf(stderr, "Autodetecting downstream codec (use -O to override)\n"); 
     1837 
     1838        /* Try Base64 */ 
     1839        if (handshake_downenctest(dns_fd, 'S')) 
     1840                base64ok = 1; 
     1841        else if (running && handshake_downenctest(dns_fd, 'U')) 
     1842                base64uok = 1; 
     1843 
     1844        /* Try Base128 only if 64 gives us some perspective */ 
     1845        if (running && (base64ok || base64uok)) { 
     1846                if (handshake_downenctest(dns_fd, 'V')) 
     1847                        base128ok = 1; 
     1848        } 
     1849 
     1850        /* If 128 works, then TXT may give us Raw as well */ 
     1851        if (running && (base128ok && do_qtype == T_TXT)) { 
     1852                if (handshake_downenctest(dns_fd, 'R')) 
     1853                        return 'R'; 
     1854        } 
     1855 
     1856        if (!running) 
     1857                return ' '; 
     1858 
     1859        if (base128ok) 
     1860                return 'V'; 
     1861        if (base64ok) 
     1862                return 'S'; 
     1863        if (base64uok) 
     1864                return 'U'; 
     1865 
     1866        fprintf(stderr, "No advanced downstream codecs seem to work, using default (Base32)\n"); 
     1867        return ' '; 
     1868} 
     1869 
     1870static int 
     1871handshake_qtypetest(int dns_fd, int timeout) 
     1872/* Returns: 
     1873   0: doesn't work with this timeout 
     1874   1: works properly 
     1875*/ 
     1876{ 
     1877        char in[4096]; 
     1878        int read; 
     1879        char *s = DOWNCODECCHECK1; 
     1880        int slen = DOWNCODECCHECK1_LEN; 
     1881        int trycodec; 
     1882        int k; 
     1883 
     1884        if (do_qtype == T_NULL) 
     1885                trycodec = 'R'; 
     1886        else 
     1887                trycodec = 'T'; 
     1888 
     1889        /* We could use 'Z' bouncing here, but 'Y' also tests that 0-255 
     1890           byte values can be returned, which is needed for NULL to work. */ 
     1891 
     1892        send_downenctest(dns_fd, trycodec, 1, NULL, 0); 
     1893 
     1894        read = handshake_waitdns(dns_fd, in, sizeof(in), 'y', 'Y', timeout); 
     1895 
     1896        if (read != slen) 
     1897                return 0;       /* incorrect */ 
     1898 
     1899        for (k = 0; k < slen; k++) { 
     1900                if (in[k] != s[k]) { 
     1901                        /* corrupted */ 
     1902                        return 0; 
     1903                } 
     1904        } 
     1905 
     1906        /* if still here, then all okay */ 
     1907        return 1; 
     1908} 
     1909 
     1910static int 
     1911handshake_qtype_numcvt(int num) 
     1912{ 
     1913        switch (num) { 
     1914        case 0: return T_NULL; 
     1915        case 1: return T_TXT; 
     1916        case 2: return T_SRV; 
     1917        case 3: return T_MX; 
     1918        case 4: return T_CNAME; 
     1919        case 5: return T_A; 
     1920        } 
     1921        return T_UNSET; 
     1922} 
     1923 
     1924static int 
     1925handshake_qtype_autodetect(int dns_fd) 
     1926/* Returns: 
     1927   0: okay, do_qtype set 
     1928   1: problem, program exit 
     1929*/ 
     1930{ 
     1931        int highestworking = 100; 
     1932        int timeout; 
     1933        int qtypenum; 
     1934 
     1935        fprintf(stderr, "Autodetecting DNS query type (use -T to override)"); 
     1936        fflush(stderr); 
     1937 
     1938        /* Method: try all "interesting" qtypes with a 1-sec timeout, then try 
     1939           all "still-interesting" qtypes with a 2-sec timeout, etc. 
     1940           "Interesting" means: qtypes that (are expected to) have higher 
     1941           bandwidth than what we know is working already (highestworking). 
     1942 
     1943           Note that DNS relays may not immediately resolve the first (NULL) 
     1944           query in 1 sec, due to long recursive lookups, so we keep trying 
     1945           to see if things will start working after a while. 
     1946         */ 
     1947 
     1948        for (timeout = 1; running && timeout <= 3; timeout++) { 
     1949                for (qtypenum = 0; running && qtypenum < highestworking; qtypenum++) { 
     1950                        do_qtype = handshake_qtype_numcvt(qtypenum); 
     1951                        if (do_qtype == T_UNSET) 
     1952                                break;  /* this round finished */ 
     1953 
     1954                        fprintf(stderr, "."); 
     1955                        fflush(stderr); 
     1956 
     1957                        if (handshake_qtypetest(dns_fd, timeout)) { 
     1958                                /* okay */ 
     1959                                highestworking = qtypenum; 
     1960#if 0 
     1961                                fprintf(stderr, " Type %s timeout %d works\n", 
     1962                                        get_qtype(), timeout); 
     1963#endif 
     1964                                break; 
     1965                                /* try others with longer timeout */ 
     1966                        } 
     1967                        /* else: try next qtype with same timeout */ 
     1968                } 
     1969                if (highestworking == 0) 
     1970                        /* good, we have NULL; abort immediately */ 
     1971                        break; 
     1972        } 
     1973 
     1974        fprintf(stderr, "\n"); 
     1975 
     1976        if (!running) { 
     1977                warnx("Stopped while autodetecting DNS query type (try setting manually with -T)"); 
     1978                return 1;  /* problem */ 
     1979        } 
     1980 
     1981        /* finished */ 
     1982        do_qtype = handshake_qtype_numcvt(highestworking); 
     1983 
     1984        if (do_qtype == T_UNSET) { 
     1985                /* also catches highestworking still 100 */ 
     1986                warnx("No suitable DNS query type found. Are you connected to a network?"); 
     1987                warnx("If you expect very long roundtrip delays, use -T explicitly."); 
     1988                warnx("(Also, connecting to an \"ancient\" version of iodined won't work.)"); 
     1989                return 1;  /* problem */ 
     1990        } 
     1991 
     1992        /* "using qtype" message printed in handshake function */ 
     1993        return 0;  /* okay */ 
     1994} 
     1995 
     1996static int 
     1997handshake_edns0_check(int dns_fd) 
     1998/* Returns: 
     1999   0: EDNS0 not supported; or Ctrl-C 
     2000   1: EDNS0 works 
     2001*/ 
     2002{ 
     2003        char in[4096]; 
     2004        int i; 
     2005        int read; 
     2006        char *s = DOWNCODECCHECK1; 
     2007        int slen = DOWNCODECCHECK1_LEN; 
     2008        char trycodec; 
     2009 
     2010        if (do_qtype == T_NULL) 
     2011                trycodec = 'R'; 
     2012        else 
     2013                trycodec = 'T'; 
     2014 
     2015        for (i=0; running && i<3 ;i++) { 
     2016 
     2017                send_downenctest(dns_fd, trycodec, 1, NULL, 0); 
     2018 
     2019                read = handshake_waitdns(dns_fd, in, sizeof(in), 'y', 'Y', i+1); 
     2020 
     2021                if (read == -2) 
     2022                        return 0;       /* hard error */ 
     2023 
     2024                if (read > 0 && read != slen) 
     2025                        return 0;       /* reply incorrect = unreliable */ 
     2026 
     2027                if (read > 0) { 
     2028                        int k; 
     2029                        for (k = 0; k < slen; k++) { 
     2030                                if (in[k] != s[k]) { 
     2031                                        /* Definitely not reliable */ 
     2032                                        return 0; 
     2033                                } 
     2034                        } 
     2035                        /* if still here, then all okay */ 
     2036                        return 1; 
     2037                } 
     2038 
     2039                fprintf(stderr, "Retrying EDNS0 support test...\n"); 
     2040        } 
     2041 
     2042        /* timeout or Ctrl-C */ 
     2043        return 0; 
     2044} 
     2045 
     2046static void 
     2047handshake_switch_codec(int dns_fd, int bits) 
     2048{ 
     2049        char in[4096]; 
     2050        int i; 
     2051        int read; 
     2052        struct encoder *tempenc; 
     2053 
     2054        if (bits == 5) 
     2055                tempenc = get_base32_encoder(); 
     2056        else if (bits == 6) 
     2057                tempenc = get_base64_encoder(); 
     2058        else if (bits == 26)    /* "2nd" 6 bits per byte, with underscore */ 
     2059                tempenc = get_base64u_encoder(); 
     2060        else if (bits == 7) 
     2061                tempenc = get_base128_encoder(); 
     2062        else return; 
     2063 
     2064        fprintf(stderr, "Switching upstream to codec %s\n", tempenc->name); 
     2065 
    13382066        for (i=0; running && i<5 ;i++) { 
    1339                 tv.tv_sec = i + 1; 
    1340                 tv.tv_usec = 0; 
    1341  
    1342                 send_case_check(dns_fd); 
    1343                  
    1344                 FD_ZERO(&fds); 
    1345                 FD_SET(dns_fd, &fds); 
    1346  
    1347                 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
    1348  
    1349                 if(r > 0) { 
    1350                         read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'z', 'Z'); 
    1351                          
    1352                         if (read > 0) { 
    1353                                 if (read < (27 * 2)) { 
    1354                                         fprintf(stderr, "Received short case check reply. Will use base32 encoder\n"); 
    1355                                         return case_preserved; 
    1356                                 } else { 
    1357                                         int k; 
    1358  
    1359                                         /* TODO enhance this, base128 is probably also possible */ 
    1360                                         case_preserved = 1; 
    1361                                         for (k = 0; k < 27 && case_preserved; k += 2) { 
    1362                                                 if (in[k] == in[k+1]) { 
    1363                                                         /* test string: zZ+-aAbBcCdDeE... */ 
    1364                                                         case_preserved = 0; 
    1365                                                 } 
    1366                                         } 
    1367                                         return case_preserved; 
    1368                                 } 
    1369                         } else { 
    1370                                 fprintf(stderr, "Got error on case check, will use base32\n"); 
    1371                                 return case_preserved; 
    1372                         } 
    1373                 } 
    1374  
    1375                 fprintf(stderr, "Retrying case check...\n"); 
    1376         } 
    1377  
    1378         fprintf(stderr, "No reply on case check, continuing\n"); 
    1379         return case_preserved; 
    1380 } 
    1381  
    1382 static void 
    1383 handshake_switch_codec(int dns_fd) 
    1384 { 
    1385         struct timeval tv; 
    1386         char in[4096]; 
    1387         fd_set fds; 
    1388         int i; 
    1389         int r; 
    1390         int read; 
    1391  
    1392         dataenc = get_base64_encoder(); 
    1393         fprintf(stderr, "Switching upstream to %s codec\n", dataenc->name); 
    1394         /* Send to server that this user will use base64 from now on */ 
    1395         for (i=0; running && i<5 ;i++) { 
    1396                 int bits; 
    1397                 tv.tv_sec = i + 1; 
    1398                 tv.tv_usec = 0; 
    1399  
    1400                 bits = 6; /* base64 = 6 bits per byte */ 
    14012067 
    14022068                send_codec_switch(dns_fd, userid, bits); 
    14032069                 
    1404                 FD_ZERO(&fds); 
    1405                 FD_SET(dns_fd, &fds); 
    1406  
    1407                 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
    1408  
    1409                 if(r > 0) { 
    1410                         read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 's', 'S'); 
    1411                          
     2070                read = handshake_waitdns(dns_fd, in, sizeof(in), 's', 'S', i+1); 
     2071 
     2072                /*XXX START adjust indent 1 tab back*/                   
    14122073                        if (read > 0) { 
    14132074                                if (strncmp("BADLEN", in, 6) == 0) { 
     
    14232084                                in[read] = 0; /* zero terminate */ 
    14242085                                fprintf(stderr, "Server switched upstream to codec %s\n", in); 
     2086                                dataenc = tempenc; 
    14252087                                return; 
    14262088                        } 
    1427                 } 
     2089                /*XXX END adjust indent 1 tab back*/ 
     2090 
    14282091                fprintf(stderr, "Retrying codec switch...\n"); 
    14292092        } 
     2093        if (!running) 
     2094                return; 
     2095 
    14302096        fprintf(stderr, "No reply from server on codec switch. "); 
    14312097 
    14322098codec_revert:  
    1433         fprintf(stderr, "Falling back to base32\n"); 
    1434         dataenc = get_base32_encoder(); 
     2099        fprintf(stderr, "Falling back to upstream codec %s\n", dataenc->name); 
    14352100} 
    14362101 
     
    14382103handshake_switch_downenc(int dns_fd) 
    14392104{ 
    1440         struct timeval tv; 
    14412105        char in[4096]; 
    1442         fd_set fds; 
    14432106        int i; 
    1444         int r; 
    14452107        int read; 
    14462108        char *dname; 
     
    14492111        if (downenc == 'S') 
    14502112                dname = "Base64"; 
     2113        else if (downenc == 'U') 
     2114                dname = "Base64u"; 
     2115        else if (downenc == 'V') 
     2116                dname = "Base128"; 
    14512117        else if (downenc == 'R') 
    14522118                dname = "Raw"; 
     
    14542120        fprintf(stderr, "Switching downstream to codec %s\n", dname); 
    14552121        for (i=0; running && i<5 ;i++) { 
    1456                 tv.tv_sec = i + 1; 
    1457                 tv.tv_usec = 0; 
    14582122 
    14592123                send_downenc_switch(dns_fd, userid); 
    14602124 
    1461                 FD_ZERO(&fds); 
    1462                 FD_SET(dns_fd, &fds); 
    1463  
    1464                 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
    1465  
    1466                 if(r > 0) { 
    1467                         read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'o', 'O'); 
    1468  
     2125                read = handshake_waitdns(dns_fd, in, sizeof(in), 'o', 'O', i+1); 
     2126 
     2127                /*XXX START adjust indent 1 tab back*/ 
    14692128                        if (read > 0) { 
    14702129                                if (strncmp("BADLEN", in, 6) == 0) { 
     
    14822141                                return; 
    14832142                        } 
    1484                 } 
     2143                /*XXX END adjust indent 1 tab back*/ 
     2144 
    14852145                fprintf(stderr, "Retrying codec switch...\n"); 
    14862146        } 
     2147        if (!running) 
     2148                return; 
     2149 
    14872150        fprintf(stderr, "No reply from server on codec switch. "); 
    14882151 
    14892152codec_revert:  
    1490         fprintf(stderr, "Falling back to base32\n"); 
     2153        fprintf(stderr, "Falling back to downstream codec Base32\n"); 
    14912154} 
    14922155 
     
    14942157handshake_try_lazy(int dns_fd) 
    14952158{ 
    1496         struct timeval tv; 
    14972159        char in[4096]; 
    1498         fd_set fds; 
    14992160        int i; 
    1500         int r; 
    15012161        int read; 
    15022162 
    15032163        fprintf(stderr, "Switching to lazy mode for low-latency\n"); 
    1504         for (i=0; running && i<3; i++) { 
    1505                 tv.tv_sec = i + 1; 
    1506                 tv.tv_usec = 0; 
     2164        for (i=0; running && i<5; i++) { 
    15072165 
    15082166                send_lazy_switch(dns_fd, userid); 
    15092167 
    1510                 FD_ZERO(&fds); 
    1511                 FD_SET(dns_fd, &fds); 
    1512  
    1513                 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
    1514  
    1515                 if(r > 0) { 
    1516                         read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'o', 'O'); 
    1517  
     2168                read = handshake_waitdns(dns_fd, in, sizeof(in), 'o', 'O', i+1); 
     2169 
     2170                /*XXX START adjust indent 1 tab back*/ 
    15182171                        if (read > 0) { 
    15192172                                if (strncmp("BADLEN", in, 6) == 0) { 
     
    15322185                                } 
    15332186                        } 
    1534                 } 
     2187                /*XXX END adjust indent 1 tab back*/ 
     2188 
    15352189                fprintf(stderr, "Retrying lazy mode switch...\n"); 
    15362190        } 
    1537         fprintf(stderr, "No reply from server on lazy switch, probably old server version. "); 
     2191        if (!running) 
     2192                return; 
     2193 
     2194        fprintf(stderr, "No reply from server on lazy switch. "); 
    15382195 
    15392196codec_revert:  
     
    15472204/* Used in the middle of data transfer, timing is different and no error msgs */ 
    15482205{ 
    1549         struct timeval tv; 
    15502206        char in[4096]; 
    1551         fd_set fds; 
    15522207        int i; 
    1553         int r; 
    15542208        int read; 
    15552209 
    15562210        for (i=0; running && i<5; i++) { 
    1557                 tv.tv_sec = 0; 
    1558                 tv.tv_usec = 500000; 
    15592211 
    15602212                send_lazy_switch(dns_fd, userid); 
    15612213 
    1562                 FD_ZERO(&fds); 
    1563                 FD_SET(dns_fd, &fds); 
    1564  
    1565                 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
    1566  
    1567                 if(r > 0) { 
    1568                         read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'o', 'O'); 
    1569  
    1570                         if (read > 0) { 
    1571                                 if (read == 4 && strncmp("Immediate", in, 9) == 0) { 
    1572                                         fprintf(stderr, "Server switched back to legacy mode.\n"); 
     2214                read = handshake_waitdns(dns_fd, in, sizeof(in), 'o', 'O', 1); 
     2215 
     2216                /*XXX START adjust indent 2 tabs back*/ 
     2217                                if (read == 9 && strncmp("Immediate", in, 9) == 0) { 
     2218                                        warnx("Server switched back to legacy mode.\n"); 
    15732219                                        lazymode = 0; 
    15742220                                        selecttimeout = 1; 
    15752221                                        return; 
    15762222                                } 
    1577                         } 
    1578                 } 
    1579         } 
     2223                /*XXX END adjust indent 2 tabs back*/ 
     2224        } 
     2225        if (!running) 
     2226                return; 
     2227 
     2228        warnx("No reply from server on legacy mode switch.\n"); 
    15802229} 
    15812230 
     
    15852234{ 
    15862235        int acked_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff); 
    1587         static int nocheck_warned = 0; 
     2236        int okay; 
     2237        int i; 
     2238        unsigned int v; 
    15882239 
    15892240        if (read >= 5 && strncmp("BADIP", in, 5) == 0) { 
     
    16142265        /* in[123] = 123; */ 
    16152266 
     2267        if ((in[2] & 0xff) != 107) { 
     2268                fprintf(stderr, "\n"); 
     2269                warnx("corruption at byte 2, this won't work. Try -O Base32, or other -T options."); 
     2270                *max_fragsize = -1; 
     2271                return 1; 
     2272        } 
     2273 
    16162274        /* Check for corruption */ 
    1617         if ((in[2] & 0xff) == 107) { 
    1618                 int okay = 1; 
    1619                 int i; 
    1620                 unsigned int v = in[3] & 0xff; 
    1621  
    1622                 for (i = 3; i < read; i++, v += 107) 
    1623                         if ((in[i] & 0xff) != (v & 0xff)) { 
     2275        okay = 1; 
     2276        v = in[3] & 0xff; 
     2277 
     2278        /*XXX START adjust indent 1 tab back*/ 
     2279                for (i = 3; i < read; i++, v = (v + 107) & 0xff) 
     2280                        if ((in[i] & 0xff) != v) { 
    16242281                                okay = 0; 
    16252282                                break; 
     
    16362293                        } else { 
    16372294                                fprintf(stderr, "%d corrupted at %d.. ", acked_fragsize, i); 
    1638                                 fflush(stderr); 
    16392295                        } 
     2296                        fflush(stderr); 
    16402297                        return 1; 
    16412298                } 
    1642         }               /* always returns */ 
    1643  
    1644         /* here when uncheckable, so assume correct */ 
    1645  
    1646         if (read >= 3 && nocheck_warned == 0) { 
    1647                 fprintf(stderr, "(Old server version, cannot check for corruption)\n"); 
    1648                 fflush(stderr); 
    1649                 nocheck_warned = 1; 
    1650         } 
    1651         fprintf(stderr, "%d ok.. ", acked_fragsize); 
    1652         fflush(stderr); 
    1653         *max_fragsize = acked_fragsize; 
     2299        /*XXX END adjust indent 1 tab back*/ 
     2300 
     2301        /* notreached */ 
    16542302        return 1; 
    16552303} 
     
    16592307handshake_autoprobe_fragsize(int dns_fd) 
    16602308{ 
    1661         struct timeval tv; 
    16622309        char in[4096]; 
    1663         fd_set fds; 
    16642310        int i; 
    1665         int r; 
    16662311        int read; 
    16672312        int proposed_fragsize = 768; 
     
    16742319                /* stop the slow probing early when we have enough bytes anyway */ 
    16752320                for (i=0; running && i<3 ;i++) { 
    1676                         tv.tv_sec = 1; 
    1677                         tv.tv_usec = 0; 
     2321 
    16782322                        send_fragsize_probe(dns_fd, proposed_fragsize); 
    16792323 
    1680                         FD_ZERO(&fds); 
    1681                         FD_SET(dns_fd, &fds); 
    1682  
    1683                         r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
    1684  
    1685                         if(r > 0) { 
    1686                                 read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'r', 'R'); 
     2324                        read = handshake_waitdns(dns_fd, in, sizeof(in), 'r', 'R', 1); 
    16872325                                 
     2326                        /*XXX START adjust indent 1 tab back*/ 
    16882327                                if (read > 0) { 
    16892328                                        /* We got a reply */ 
     
    16912330                                                break; 
    16922331                                } 
    1693                         } 
     2332                        /*XXX END adjust indent 1 tab back*/ 
     2333 
    16942334                        fprintf(stderr, "."); 
    16952335                        fflush(stderr); 
    16962336                } 
     2337                if (max_fragsize < 0) 
     2338                        break; 
     2339 
    16972340                range >>= 1; 
    16982341                if (max_fragsize == proposed_fragsize) { 
     
    17122355        } 
    17132356        if (max_fragsize <= 2) { 
    1714                 /* Tried all the way down to 2 and found no good size */ 
     2357                /* Tried all the way down to 2 and found no good size. 
     2358                   But we _did_ do all handshake before this, so there must 
     2359                   be some workable connection. */ 
    17152360                fprintf(stderr, "\n"); 
    1716                 warnx("found no accepted fragment size. (Try forcing with -m, or try other -T or -O options)"); 
     2361                warnx("found no accepted fragment size."); 
     2362                warnx("try setting -M to 200 or lower, or try other -T or -O options."); 
    17172363                return 0; 
    17182364        } 
     
    17202366        fprintf(stderr, "will use %d-2=%d\n", max_fragsize, max_fragsize - 2); 
    17212367 
    1722         if (do_qtype != T_NULL && downenc == ' ') 
    1723                 fprintf(stderr, "(Maybe other -O options will increase throughput)\n"); 
     2368        /* need 1200 / 16frags = 75 bytes fragsize */ 
     2369        if (max_fragsize < 82) { 
     2370                fprintf(stderr, "Note: this probably won't work well.\n"); 
     2371                fprintf(stderr, "Try setting -M to 200 or lower, or try other DNS types (-T option).\n"); 
     2372        } else if (max_fragsize < 202 && 
     2373            (do_qtype == T_NULL || do_qtype == T_TXT || 
     2374             do_qtype == T_SRV || do_qtype == T_MX)) { 
     2375                fprintf(stderr, "Note: this isn't very much.\n"); 
     2376                fprintf(stderr, "Try setting -M to 200 or lower, or try other DNS types (-T option).\n"); 
     2377        } 
    17242378 
    17252379        return max_fragsize - 2; 
     
    17292383handshake_set_fragsize(int dns_fd, int fragsize) 
    17302384{ 
    1731         struct timeval tv; 
    17322385        char in[4096]; 
    1733         fd_set fds; 
    17342386        int i; 
    1735         int r; 
    17362387        int read; 
    17372388 
    17382389        fprintf(stderr, "Setting downstream fragment size to max %d...\n", fragsize); 
    17392390        for (i=0; running && i<5 ;i++) { 
    1740                 tv.tv_sec = i + 1; 
    1741                 tv.tv_usec = 0; 
    17422391 
    17432392                send_set_downstream_fragsize(dns_fd, fragsize); 
    1744                  
    1745                 FD_ZERO(&fds); 
    1746                 FD_SET(dns_fd, &fds); 
    1747  
    1748                 r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
    1749  
    1750                 if(r > 0) { 
    1751                         read = read_dns_namecheck(dns_fd, 0, in, sizeof(in), 'n', 'N'); 
    1752                          
     2393 
     2394                read = handshake_waitdns(dns_fd, in, sizeof(in), 'n', 'N', i+1); 
     2395 
     2396                /*XXX START adjust indent 1 tab back*/                   
    17532397                        if (read > 0) { 
    17542398                                int accepted_fragsize; 
     
    17652409                                return; 
    17662410                        } 
    1767                 } 
     2411                /*XXX END adjust indent 1 tab back*/ 
     2412 
    17682413                fprintf(stderr, "Retrying set fragsize...\n"); 
    17692414        } 
     2415        if (!running) 
     2416                return; 
     2417 
    17702418        fprintf(stderr, "No reply from server when setting fragsize. Keeping default.\n"); 
    17712419} 
     
    17752423{ 
    17762424        int seed; 
    1777         int case_preserved; 
     2425        int upcodec; 
    17782426        int r; 
     2427 
     2428        dnsc_use_edns0 = 0; 
     2429 
     2430        /* qtype message printed in handshake function */ 
     2431        if (do_qtype == T_UNSET) { 
     2432                r = handshake_qtype_autodetect(dns_fd); 
     2433                if (r) { 
     2434                        return r; 
     2435                } 
     2436        } 
     2437 
     2438        fprintf(stderr, "Using DNS type %s queries\n", get_qtype()); 
    17792439 
    17802440        r = handshake_version(dns_fd, &seed); 
     
    17952455                        fprintf(stderr, "Skipping raw mode\n"); 
    17962456                } 
    1797                 case_preserved = handshake_case_check(dns_fd); 
    1798  
    1799                 if (case_preserved) { 
    1800                         handshake_switch_codec(dns_fd); 
    1801                 } 
     2457 
     2458                dnsc_use_edns0 = 1; 
     2459                if (handshake_edns0_check(dns_fd) && running) { 
     2460                        fprintf(stderr, "Using EDNS0 extension\n"); 
     2461                } else if (!running) { 
     2462                        return -1; 
     2463                } else { 
     2464                        fprintf(stderr, "DNS relay does not support EDNS0 extension\n"); 
     2465                        dnsc_use_edns0 = 0; 
     2466                } 
     2467 
     2468                upcodec = handshake_upenc_autodetect(dns_fd); 
     2469                if (!running) 
     2470                        return -1; 
     2471 
     2472                if (upcodec == 1) { 
     2473                        handshake_switch_codec(dns_fd, 6); 
     2474                } else if (upcodec == 2) { 
     2475                        handshake_switch_codec(dns_fd, 26); 
     2476                } else if (upcodec == 3) { 
     2477                        handshake_switch_codec(dns_fd, 7); 
     2478                } 
     2479                if (!running) 
     2480                        return -1; 
     2481 
     2482                if (downenc == ' ') { 
     2483                        downenc = handshake_downenc_autodetect(dns_fd); 
     2484                } 
     2485                if (!running) 
     2486                        return -1; 
    18022487 
    18032488                if (downenc != ' ') { 
    18042489                        handshake_switch_downenc(dns_fd); 
    18052490                } 
     2491                if (!running) 
     2492                        return -1; 
    18062493 
    18072494                if (lazymode) { 
    18082495                        handshake_try_lazy(dns_fd); 
    18092496                } 
     2497                if (!running) 
     2498                        return -1; 
    18102499 
    18112500                if (autodetect_frag_size) { 
     
    18172506 
    18182507                handshake_set_fragsize(dns_fd, fragsize); 
     2508                if (!running) 
     2509                        return -1; 
    18192510        } 
    18202511 
  • src/client.h

    r3c4860 rb17790  
    2828void client_set_password(const char *cp); 
    2929void set_qtype(char *qtype); 
     30char *get_qtype(); 
    3031void set_downenc(char *encoding); 
    3132void client_set_selecttimeout(int select_timeout); 
    3233void client_set_lazymode(int lazy_mode); 
     34void client_set_hostname_maxlen(int i); 
    3335 
    3436int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize); 
  • src/common.h

    r269499 rb17790  
    7575#endif 
    7676 
     77#define T_UNSET 65432 
     78/* Unused RR type; "private use" range, see http://www.bind9.net/dns-parameters */ 
     79 
    7780struct packet  
    7881{ 
     
    9093        unsigned short rcode; 
    9194        unsigned short id; 
    92         unsigned short iddupe;          /* only used for dupe checking */ 
    9395        struct in_addr destination; 
    9496        struct sockaddr from; 
    9597        int fromlen; 
     98        unsigned short id2; 
     99        struct sockaddr from2; 
     100        int fromlen2; 
    96101}; 
    97102 
  • src/dns.c

    racd264 rb17790  
    4040#include "read.h" 
    4141 
     42int dnsc_use_edns0 = 1; 
     43 
    4244#define CHECKLEN(x) if (buflen - (p-buf) < (x))  return 0 
    4345 
     
    4951        char *p; 
    5052        int len; 
     53        int ancnt; 
    5154 
    5255        if (buflen < sizeof(HEADER)) 
     
    6972        switch (qr) { 
    7073        case QR_ANSWER: 
    71                 header->ancount = htons(1); 
    7274                header->qdcount = htons(1); 
    7375         
     
    8284 
    8385                /* Answer section */ 
    84                 CHECKLEN(10); 
    85                 putshort(&p, name);      
    86                 if (q->type == T_A) 
    87                         putshort(&p, T_CNAME);  /* answer CNAME to A question */ 
    88                 else 
    89                         putshort(&p, q->type); 
    90                 putshort(&p, C_IN); 
    91                 putlong(&p, 0);         /* TTL */ 
    92  
    93                 if (q->type == T_CNAME || q->type == T_A || q->type == T_MX) { 
     86 
     87                if (q->type == T_CNAME || q->type == T_A) { 
    9488                        /* data is expected to be like "Hblabla.host.name.com\0" */ 
    9589 
    96                         char *startp = p; 
     90                        char *startp; 
    9791                        int namelen; 
    9892 
     93                        CHECKLEN(10); 
     94                        putshort(&p, name);      
     95                        if (q->type == T_A) 
     96                                /* answer CNAME to A question */ 
     97                                putshort(&p, T_CNAME); 
     98                        else 
     99                                putshort(&p, q->type); 
     100                        putshort(&p, C_IN); 
     101                        putlong(&p, 0);         /* TTL */ 
     102 
     103                        startp = p; 
    99104                        p += 2;                 /* skip 2 bytes length */ 
    100                         CHECKLEN(2); 
    101                         if (q->type == T_MX) 
    102                                 putshort(&p, 10);       /* preference */ 
    103105                        putname(&p, buflen - (p - buf), data); 
    104106                        CHECKLEN(0); 
     
    106108                        namelen -= 2; 
    107109                        putshort(&startp, namelen); 
     110                        ancnt = 1; 
     111                } else if (q->type == T_MX || q->type == T_SRV) { 
     112                        /* Data is expected to be like 
     113                           "Hblabla.host.name.com\0Hanother.com\0\0" 
     114                           For SRV, see RFC2782. 
     115                         */ 
     116 
     117                        char *mxdata = data; 
     118                        char *startp; 
     119                        int namelen; 
     120 
     121                        ancnt = 1; 
     122                        while (1) { 
     123                                CHECKLEN(10); 
     124                                putshort(&p, name);      
     125                                putshort(&p, q->type); 
     126                                putshort(&p, C_IN); 
     127                                putlong(&p, 0);         /* TTL */ 
     128 
     129                                startp = p; 
     130                                p += 2;                 /* skip 2 bytes length */ 
     131                                CHECKLEN(2); 
     132                                putshort(&p, 10 * ancnt);       /* preference */ 
     133 
     134                                if (q->type == T_SRV) { 
     135                                        /* weight, port (5060 = SIP) */ 
     136                                        CHECKLEN(4); 
     137                                        putshort(&p, 10); 
     138                                        putshort(&p, 5060); 
     139                                } 
     140 
     141                                putname(&p, buflen - (p - buf), mxdata); 
     142                                CHECKLEN(0); 
     143                                namelen = p - startp; 
     144                                namelen -= 2; 
     145                                putshort(&startp, namelen); 
     146 
     147                                mxdata = mxdata + strlen(mxdata) + 1; 
     148                                if (*mxdata == '\0') 
     149                                        break; 
     150 
     151                                ancnt++; 
     152                        } 
    108153                } else if (q->type == T_TXT) { 
    109154                        /* TXT has binary or base-X data */ 
    110                         char *startp = p; 
     155                        char *startp; 
    111156                        int txtlen; 
    112157 
     158                        CHECKLEN(10); 
     159                        putshort(&p, name);      
     160                        putshort(&p, q->type); 
     161                        putshort(&p, C_IN); 
     162                        putlong(&p, 0);         /* TTL */ 
     163 
     164                        startp = p; 
    113165                        p += 2;                 /* skip 2 bytes length */ 
    114166                        puttxtbin(&p, buflen - (p - buf), data, datalen); 
     
    117169                        txtlen -= 2; 
    118170                        putshort(&startp, txtlen); 
     171                        ancnt = 1; 
    119172                } else { 
    120173                        /* NULL has raw binary data */ 
     174 
     175                        CHECKLEN(10); 
     176                        putshort(&p, name);      
     177                        putshort(&p, q->type); 
     178                        putshort(&p, C_IN); 
     179                        putlong(&p, 0);         /* TTL */ 
     180 
    121181                        datalen = MIN(datalen, buflen - (p - buf)); 
    122182                        CHECKLEN(2); 
     
    125185                        putdata(&p, data, datalen); 
    126186                        CHECKLEN(0); 
    127                 } 
     187                        ancnt = 1; 
     188                } 
     189                header->ancount = htons(ancnt); 
    128190                break; 
    129191        case QR_QUERY: 
     
    131193 
    132194                header->qdcount = htons(1); 
    133                 header->arcount = htons(1); 
    134195         
    135196                datalen = MIN(datalen, buflen - (p - buf)); 
     
    142203                /* EDNS0 to advertise maximum response length 
    143204                   (even CNAME/A/MX, 255+255+header would be >512) */ 
     205                if (dnsc_use_edns0) { 
     206                        header->arcount = htons(1); 
     207                        /*XXX START adjust indent 1 tab forward*/ 
    144208                CHECKLEN(11); 
    145209                putbyte(&p, 0x00);    /* Root */ 
     
    149213                putshort(&p, 0x8000); /* Z */ 
    150214                putshort(&p, 0x0000); /* Data length */ 
     215                        /*XXX END adjust indent 1 tab forward*/ 
     216                } 
     217 
    151218                break; 
    152219        } 
     
    160227dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain) 
    161228/* Only used when iodined gets an NS type query */ 
     229/* Mostly same as dns_encode_a_response() below */ 
    162230{ 
    163231        HEADER *header; 
     
    166234        short topname; 
    167235        short nsname; 
    168         char *domain; 
     236        char *ipp; 
    169237        int domain_len; 
    170238        char *p; 
     
    194262        name = 0xc000 | ((p - buf) & 0x3fff); 
    195263 
    196         domain = strstr(q->name, topdomain); 
    197         if (domain) { 
    198                 domain_len = (int) (domain - q->name);  
    199         } else { 
     264        domain_len = strlen(q->name) - strlen(topdomain); 
     265        if (domain_len < 0 || domain_len == 1) 
    200266                return -1; 
    201         } 
    202         /* pointer to start of topdomain */ 
     267        if (strcasecmp(q->name + domain_len, topdomain)) 
     268                return -1; 
     269        if (domain_len >= 1 && q->name[domain_len - 1] != '.') 
     270                return -1; 
     271 
     272        /* pointer to start of topdomain; instead of dots at the end 
     273           we have length-bytes in front, so total length is the same */ 
    203274        topname = 0xc000 | ((p - buf + domain_len) & 0x3fff); 
    204275 
     
    234305 
    235306        /* ugly hack to output IP address */ 
    236         domain = (char *) &q->destination; 
     307        ipp = (char *) &q->destination; 
    237308        CHECKLEN(4); 
    238         putbyte(&p, *domain++); 
    239         putbyte(&p, *domain++); 
    240         putbyte(&p, *domain++); 
    241         putbyte(&p, *domain); 
     309        putbyte(&p, *(ipp++)); 
     310        putbyte(&p, *(ipp++)); 
     311        putbyte(&p, *(ipp++)); 
     312        putbyte(&p, *ipp); 
     313 
     314        len = p - buf; 
     315        return len; 
     316} 
     317 
     318int 
     319dns_encode_a_response(char *buf, size_t buflen, struct query *q) 
     320/* Only used when iodined gets an A type query for ns.topdomain or www.topdomain */ 
     321/* Mostly same as dns_encode_ns_response() above */ 
     322{ 
     323        HEADER *header; 
     324        int len; 
     325        short name; 
     326        char *ipp; 
     327        char *p; 
     328 
     329        if (buflen < sizeof(HEADER)) 
     330                return 0; 
     331 
     332        memset(buf, 0, buflen); 
     333         
     334        header = (HEADER*)buf; 
     335         
     336        header->id = htons(q->id); 
     337        header->qr = 1; 
     338        header->opcode = 0; 
     339        header->aa = 1; 
     340        header->tc = 0; 
     341        header->rd = 0; 
     342        header->ra = 0; 
     343 
     344        p = buf + sizeof(HEADER); 
     345 
     346        header->qdcount = htons(1); 
     347        header->ancount = htons(1); 
     348 
     349        /* pointer to start of name */ 
     350        name = 0xc000 | ((p - buf) & 0x3fff); 
     351 
     352        /* Query section */ 
     353        putname(&p, buflen - (p - buf), q->name);       /* Name */ 
     354        CHECKLEN(4); 
     355        putshort(&p, q->type);                  /* Type */ 
     356        putshort(&p, C_IN);                     /* Class */ 
     357 
     358        /* Answer section */ 
     359        CHECKLEN(12); 
     360        putshort(&p, name);                     /* Name */ 
     361        putshort(&p, q->type);                  /* Type */ 
     362        putshort(&p, C_IN);                     /* Class */ 
     363        putlong(&p, 3600);                      /* TTL */ 
     364        putshort(&p, 4);                        /* Data length */ 
     365 
     366        /* ugly hack to output IP address */ 
     367        ipp = (char *) &q->destination; 
     368        CHECKLEN(4); 
     369        putbyte(&p, *(ipp++)); 
     370        putbyte(&p, *(ipp++)); 
     371        putbyte(&p, *(ipp++)); 
     372        putbyte(&p, *ipp); 
    242373 
    243374        len = p - buf; 
     
    277408        int rv; 
    278409 
     410        q->id2 = 0; 
    279411        rv = 0; 
    280412        header = (HEADER*)packet; 
     
    325457                 
    326458                if (ancount < 1) { 
    327                         /* We may get both CNAME and A, then ancount=2 */ 
     459                        /* DNS errors like NXDOMAIN have ancount=0 and 
     460                           stop here. CNAME may also have A; MX/SRV may have 
     461                           multiple results. */ 
    328462                        return -1; 
    329463                } 
    330464 
    331                 /* Assume that first answer is NULL/CNAME that we wanted */ 
    332                 readname(packet, packetlen, &data, name, sizeof(name)); 
    333                 CHECKLEN(10); 
    334                 readshort(packet, &data, &type); 
    335                 readshort(packet, &data, &class); 
    336                 readlong(packet, &data, &ttl); 
    337                 readshort(packet, &data, &rlen); 
    338  
     465                /* Here type is still the question type */ 
    339466                if (type == T_NULL) { 
     467                        /* Assume that first answer is what we wanted */ 
     468                        readname(packet, packetlen, &data, name, sizeof(name)); 
     469                        CHECKLEN(10); 
     470                        readshort(packet, &data, &type); 
     471                        readshort(packet, &data, &class); 
     472                        readlong(packet, &data, &ttl); 
     473                        readshort(packet, &data, &rlen); 
     474 
    340475                        rv = MIN(rlen, sizeof(rdata)); 
    341476                        rv = readdata(packet, &data, rdata, rv); 
     
    347482                        } 
    348483                } 
    349                 if ((type == T_CNAME || type == T_MX) && buf) { 
    350                         if (type == T_MX) 
    351                                 data += 2;      /* skip preference */ 
     484                else if ((type == T_A || type == T_CNAME) && buf) { 
     485                        /* Assume that first answer is what we wanted */ 
     486                        readname(packet, packetlen, &data, name, sizeof(name)); 
     487                        CHECKLEN(10); 
     488                        readshort(packet, &data, &type); 
     489                        readshort(packet, &data, &class); 
     490                        readlong(packet, &data, &ttl); 
     491                        readshort(packet, &data, &rlen); 
     492 
    352493                        memset(name, 0, sizeof(name)); 
    353494                        readname(packet, packetlen, &data, name, sizeof(name) - 1); 
     
    357498                        rv = strlen(buf); 
    358499                } 
    359                 if (type == T_TXT && buf) { 
     500                else if ((type == T_MX || type == T_SRV) && buf) { 
     501                        /* We support 250 records, 250*(255+header) ~= 64kB. 
     502                           Only exact 10-multiples are accepted, and gaps in 
     503                           numbering are not jumped over (->truncated). 
     504                           Hopefully DNS servers won't mess around too much. 
     505                         */ 
     506                        char names[250][QUERY_NAME_SIZE]; 
     507                        char *rdatastart; 
     508                        short pref; 
     509                        int i; 
     510                        int offset; 
     511 
     512                        memset(names, 0, sizeof(names)); 
     513 
     514                        for (i=0; i < ancount; i++) { 
     515                                readname(packet, packetlen, &data, name, sizeof(name)); 
     516                                CHECKLEN(12); 
     517                                readshort(packet, &data, &type); 
     518                                readshort(packet, &data, &class); 
     519                                readlong(packet, &data, &ttl); 
     520                                readshort(packet, &data, &rlen); 
     521                                rdatastart = data; 
     522                                readshort(packet, &data, &pref); 
     523 
     524                                if (type == T_SRV) { 
     525                                        /* skip weight, port */ 
     526                                        data += 4; 
     527                                        CHECKLEN(0); 
     528                                } 
     529 
     530                                if (pref % 10 == 0 && pref >= 10 && 
     531                                    pref < 2500) { 
     532                                        readname(packet, packetlen, &data, 
     533                                                 names[pref / 10 - 1], 
     534                                                 QUERY_NAME_SIZE - 1); 
     535                                        names[pref / 10 - 1][QUERY_NAME_SIZE-1] = '\0'; 
     536                                } 
     537 
     538                                /* always trust rlen, not name encoding */  
     539                                data = rdatastart + rlen; 
     540                                CHECKLEN(0); 
     541                        } 
     542 
     543                        /* output is like Hname10.com\0Hname20.com\0\0 */ 
     544                        offset = 0; 
     545                        i = 0; 
     546                        while (names[i][0] != '\0') { 
     547                                int l = MIN(strlen(names[i]), buflen-offset-2); 
     548                                if (l <= 0) 
     549                                        break; 
     550                                memcpy(buf + offset, names[i], l); 
     551                                offset += l; 
     552                                *(buf + offset) = '\0'; 
     553                                offset++; 
     554                                i++; 
     555                        } 
     556                        *(buf + offset) = '\0'; 
     557                        rv = offset; 
     558                } 
     559                else if (type == T_TXT && buf) { 
     560                        /* Assume that first answer is what we wanted */ 
     561                        readname(packet, packetlen, &data, name, sizeof(name)); 
     562                        CHECKLEN(10); 
     563                        readshort(packet, &data, &type); 
     564                        readshort(packet, &data, &class); 
     565                        readlong(packet, &data, &ttl); 
     566                        readshort(packet, &data, &rlen); 
     567 
    360568                        rv = readtxtbin(packet, &data, rlen, rdata, sizeof(rdata)); 
    361569                        if (rv >= 1) { 
     
    366574                        } 
    367575                } 
     576 
     577                /* Here type is the answer type (note A->CNAME) */ 
    368578                if (q != NULL) 
    369579                        q->type = type; 
  • src/dns.h

    rb6fc3f rb17790  
    2525} qr_t; 
    2626 
     27extern int dnsc_use_edns0; 
     28 
    2729int dns_encode(char *, size_t, struct query *, qr_t, char *, size_t); 
    2830int dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain); 
     31int dns_encode_a_response(char *buf, size_t buflen, struct query *q); 
    2932unsigned short dns_get_id(char *packet, size_t packetlen); 
    3033int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t); 
  • src/encoding.c

    r93a313 rb17790  
    2222build_hostname(char *buf, size_t buflen,  
    2323                const char *data, const size_t datalen,  
    24                 const char *topdomain, struct encoder *encoder) 
     24                const char *topdomain, struct encoder *encoder, int maxlen) 
    2525{ 
    2626        int encsize; 
     
    2828        char *b; 
    2929 
    30         space = MIN(0xFF, buflen) - strlen(topdomain) - 7; 
     30        space = MIN(maxlen, buflen) - strlen(topdomain) - 8; 
     31        /* 8 = 5 max header length + 1 dot before topdomain + 2 safety */ 
     32 
    3133        if (!encoder->places_dots()) 
    3234                space -= (space / 57); /* space for dots */ 
  • src/encoding.h

    ra1a2e3 rb17790  
    1818#define _ENCODING_H_ 
    1919 
     20/* All-0, all-1, 01010101, 10101010: each 4 times to make sure the pattern 
     21   spreads across multiple encoded chars -> 16 bytes total. 
     22   Followed by 32 bytes from my /dev/random; should be enough. 
     23 */ 
     24#define DOWNCODECCHECK1      "\000\000\000\000\377\377\377\377\125\125\125\125\252\252\252\252\201\143\310\322\307\174\262\027\137\117\316\311\111\055\122\041\141\251\161\040\045\263\006\163\346\330\104\060\171\120\127\277" 
     25#define DOWNCODECCHECK1_LEN  48 
     26 
    2027struct encoder { 
    2128        char name[8]; 
     
    2835}; 
    2936 
    30 int build_hostname(char *, size_t, const char *, const size_t, const char *, struct encoder *); 
     37int build_hostname(char *, size_t, const char *, const size_t, const char *, struct encoder *, int); 
    3138int unpack_data(char *, size_t, char *, size_t, struct encoder *); 
    3239int inline_dotify(char *, size_t); 
  • src/iodine.c

    r1a26a9 rb17790  
    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] [-L 0|1] [-I sec] " 
     64                        "[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec] " 
    6565                        "[-z context] [-F pidfile] [nameserver] topdomain\n", __progname); 
    6666        exit(2); 
     
    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] [-L 0|1] [-I sec] " 
     75                        "[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec] " 
    7676                        "[-z context] [-F pidfile] [nameserver] topdomain\n", __progname); 
     77        fprintf(stderr, "Options to try if connection doesn't work:\n"); 
     78        fprintf(stderr, "  -T force dns type: NULL, TXT, SRV, MX, CNAME, A (default: autodetect)\n"); 
     79        fprintf(stderr, "  -O force downstream encoding for -T other than NULL: Base32, Base64, Base64u,\n"); 
     80        fprintf(stderr, "     Base128, or (only for TXT:) Raw  (default: autodetect)\n"); 
     81        fprintf(stderr, "  -I max interval between requests (default 4 sec) to prevent DNS timeouts\n"); 
     82        fprintf(stderr, "  -L 1: use lazy mode for low-latency (default). 0: don't (implies -I1)\n"); 
     83        fprintf(stderr, "  -m max size of downstream fragments (default: autodetect)\n"); 
     84        fprintf(stderr, "  -M max size of upstream hostnames (~100-255, default: 255)\n"); 
     85        fprintf(stderr, "  -r to skip raw UDP mode attempt\n"); 
     86        fprintf(stderr, "  -P password used for authentication (max 32 chars will be used)\n"); 
     87        fprintf(stderr, "Other options:\n"); 
    7788        fprintf(stderr, "  -v to print version info and exit\n"); 
    7889        fprintf(stderr, "  -h to print this help and exit\n"); 
    7990        fprintf(stderr, "  -f to keep running in foreground\n"); 
    80         fprintf(stderr, "  -r to skip raw UDP mode attempt\n"); 
    8191        fprintf(stderr, "  -u name to drop privileges and run as user 'name'\n"); 
    8292        fprintf(stderr, "  -t dir to chroot to directory dir\n"); 
    8393        fprintf(stderr, "  -d device to set tunnel device name\n"); 
    84         fprintf(stderr, "  -P password used for authentication (max 32 chars will be used)\n"); 
    85         fprintf(stderr, "  -m maxfragsize, to limit size of downstream packets\n"); 
    86         fprintf(stderr, "  -T dns type: NULL (default, fastest), TXT, CNAME, A (CNAME answer), MX\n"); 
    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"); 
    9094        fprintf(stderr, "  -z context, to apply specified SELinux context after initialization\n"); 
    9195        fprintf(stderr, "  -F pidfile to write pid to a file\n"); 
     
    132136        int lazymode; 
    133137        int selecttimeout; 
     138        int hostname_maxlen; 
    134139 
    135140        nameserv_addr = NULL; 
     
    153158        lazymode = 1; 
    154159        selecttimeout = 4; 
     160        hostname_maxlen = 0xFF; 
    155161 
    156162#ifdef WINDOWS32 
     
    169175#endif 
    170176 
    171         while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:F:T:O:L:I:")) != -1) { 
     177        while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:M:F:T:O:L:I:")) != -1) { 
    172178                switch(choice) { 
    173179                case 'v': 
     
    203209                        autodetect_frag_size = 0; 
    204210                        max_downstream_frag_size = atoi(optarg); 
     211                        break; 
     212                case 'M': 
     213                        hostname_maxlen = atoi(optarg); 
     214                        if (hostname_maxlen > 255) 
     215                                hostname_maxlen = 255; 
     216                        if (hostname_maxlen < 10) 
     217                                hostname_maxlen = 10; 
    205218                        break; 
    206219                case 'z': 
     
    284297        client_set_lazymode(lazymode); 
    285298        client_set_topdomain(topdomain); 
     299        client_set_hostname_maxlen(hostname_maxlen); 
    286300         
    287301        if (username != NULL) { 
     
    316330        signal(SIGTERM, sighandler); 
    317331 
     332        fprintf(stderr, "Sending DNS queries for %s to %s\n", 
     333                topdomain, nameserv_addr); 
     334 
    318335        if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) { 
    319336                retval = 1; 
     
    321338        } 
    322339         
    323         if (client_get_conn() == CONN_DNS_NULL) { 
    324                 fprintf(stderr, "Sending queries for %s to %s\n", topdomain, nameserv_addr); 
    325         } else { 
     340        if (client_get_conn() == CONN_RAW_UDP) { 
    326341                fprintf(stderr, "Sending raw traffic directly to %s\n", client_get_raw_addr()); 
    327342        } 
     343 
     344        fprintf(stderr, "Connection setup complete, transmitting data.\n"); 
    328345 
    329346        if (foreground == 0)  
  • src/iodined.c

    rd87432 rb17790  
    5252#include "base32.h" 
    5353#include "base64.h" 
     54#include "base64u.h" 
     55#include "base128.h" 
    5456#include "user.h" 
    5557#include "login.h" 
     
    7072static struct encoder *b32; 
    7173static struct encoder *b64; 
     74static struct encoder *b64u; 
     75static struct encoder *b128; 
    7276static int created_users; 
    7377 
     
    118122        struct sockaddr_in *tempin; 
    119123 
     124        /* Note: duplicate in handle_raw_login() except IP-address check */ 
     125 
    120126        if (userid < 0 || userid >= created_users ) { 
    121127                return 1;  
     
    152158        len += RAW_HDR_LEN; 
    153159        packet[RAW_HDR_CMD] = cmd | (user & 0x0F); 
     160 
     161        if (debug >= 2) { 
     162                struct sockaddr_in *tempin; 
     163                tempin = (struct sockaddr_in *) &(q->from); 
     164                fprintf(stderr, "TX-raw: client %s, cmd %d, %d bytes\n",  
     165                        inet_ntoa(tempin->sin_addr), cmd, len); 
     166        } 
    154167 
    155168        sendto(fd, packet, len, 0, &q->from, q->fromlen); 
     
    244257   actually get an answer instead of silence. 
    245258 
    246    We normally use either CMC (ping) or seqno/frag (upstream data) to prevent 
    247    cache hits on in-between caching DNS servers. Also, the iodine client is 
    248    designed to mostly operate properly when cached results are returned. 
    249    Two cache-hit situations: 
    250    - Repeated DNS query when our ack got lost: has same seqno/frag and doesn't 
    251      have CMC; but the client will not have sent any new data or pings 
    252      in-between, so this is always cacheable. Even in lazy mode, since we send 
    253      the first answer to the actual DNS query only on receipt of the first 
    254      client retransmit. 
    255    - Identical second+ fragment of mod-8 packets ago, same seqno/frag and no 
    256      TCP counter in those fragments to tell them apart. This is _not_ 
    257      cachable, so our cache length should never exceed 7 packets. 
     259   Because of the CMC in both ping and upstream data, unwanted cache hits 
     260   are prevented. Data-CMC is only 36 counts, so our cache length should 
     261   not exceed 36/2=18 packets. (This quick rule assumes all packets are 
     262   otherwise equal, which they arent: up/downstream seq/frag, tcp sequence 
     263   number, and of course data.) 
    258264*/ 
    259265 
     
    303309 
    304310                /* okay, match */ 
     311                if (debug >= 1) 
     312                        fprintf(stderr, "OUT  user %d %s from dnscache\n", userid, q->name); 
     313 
    305314                write_dns(dns_fd, q, users[userid].dnscache_answer[use], 
    306315                          users[userid].dnscache_answerlen[use], 
     
    316325 
    317326#endif /* DNSCACHE_LEN */ 
     327 
     328static inline void 
     329save_to_qmem(unsigned char *qmem_cmc, unsigned short *qmem_type, int qmem_len, 
     330             int *qmem_lastfilled, unsigned char *cmc_to_add, 
     331             unsigned short type_to_add) 
     332/* Remember query to check for duplicates */ 
     333{ 
     334        int fill; 
     335 
     336        fill = *qmem_lastfilled + 1; 
     337        if (fill >= qmem_len) 
     338                fill = 0; 
     339 
     340        memcpy(qmem_cmc + fill * 4, cmc_to_add, 4); 
     341        qmem_type[fill] = type_to_add; 
     342        *qmem_lastfilled = fill; 
     343} 
     344 
     345static inline void 
     346save_to_qmem_pingordata(int userid, struct query *q) 
     347{ 
     348        /* Our CMC is a bit more than the "official" CMC; we store 4 bytes 
     349           just because we can, and because it may prevent some false matches. 
     350           For ping, we save the 4 decoded bytes: userid + seq/frag + CMC. 
     351           For data, we save the 4 _un_decoded chars in lowercase: seq/frag's 
     352           + 1 char CMC; that last char is non-Base32. 
     353         */ 
     354 
     355        char cmc[8]; 
     356        int i; 
     357 
     358        if (q->name[0] == 'P' || q->name[0] == 'p') { 
     359                /* Ping packet */ 
     360 
     361                size_t cmcsize = sizeof(cmc); 
     362                char *cp = strchr(q->name, '.'); 
     363 
     364                if (cp == NULL) 
     365                        return;  /* illegal hostname; shouldn't happen */ 
     366 
     367                /* We already unpacked in handle_null_request(), but that's 
     368                   lost now... Note: b32 directly, we want no undotify here! */ 
     369                i = b32->decode(cmc, &cmcsize, q->name + 1, (cp - q->name) - 1); 
     370 
     371                if (i < 4) 
     372                        return;  /* illegal ping; shouldn't happen */ 
     373 
     374                save_to_qmem(users[userid].qmemping_cmc, 
     375                             users[userid].qmemping_type, QMEMPING_LEN, 
     376                             &users[userid].qmemping_lastfilled, 
     377                             (void *) cmc, q->type); 
     378        } else { 
     379                /* Data packet, hopefully not illegal */ 
     380                if (strlen(q->name) < 5) 
     381                        return; 
     382 
     383                /* We store CMC in lowercase; if routing via multiple parallel 
     384                   DNS servers, one may do case-switch and another may not, 
     385                   and we still want to detect duplicates. 
     386                   Data-header is always base32, so case-swap won't hurt. 
     387                 */ 
     388                for (i = 0; i < 4; i++) 
     389                        if (q->name[i+1] >= 'A' && q->name[i+1] <= 'Z') 
     390                                cmc[i] = q->name[i+1] + ('a' - 'A'); 
     391                        else 
     392                                cmc[i] = q->name[i+1]; 
     393 
     394                save_to_qmem(users[userid].qmemdata_cmc, 
     395                             users[userid].qmemdata_type, QMEMDATA_LEN, 
     396                             &users[userid].qmemdata_lastfilled, 
     397                             (void *) cmc, q->type); 
     398        } 
     399} 
     400 
     401static int 
     402answer_from_qmem(int dns_fd, struct query *q, unsigned char *qmem_cmc, 
     403                 unsigned short *qmem_type, int qmem_len, 
     404                 unsigned char *cmc_to_check) 
     405/* Checks query memory and sends an (illegal) answer if this is a duplicate. 
     406   Returns: 1 = answer sent, drop this query, 0 = no answer sent, this is 
     407   not a duplicate. */ 
     408{ 
     409        int i; 
     410 
     411        for (i = 0; i < qmem_len ; i++) { 
     412 
     413                if (qmem_type[i] == T_UNSET) 
     414                        continue; 
     415                if (qmem_type[i] != q->type) 
     416                        continue; 
     417                if (memcmp(qmem_cmc + i * 4, cmc_to_check, 4)) 
     418                        continue; 
     419 
     420                /* okay, match */ 
     421                if (debug >= 1) 
     422                        fprintf(stderr, "OUT  from qmem for %s == duplicate, sending illegal reply\n", q->name); 
     423 
     424                write_dns(dns_fd, q, "x", 1, 'T'); 
     425 
     426                q->id = 0;      /* this query was used */ 
     427                return 1; 
     428        } 
     429 
     430        /* here only when no match found */ 
     431        return 0; 
     432} 
     433 
     434static inline int 
     435answer_from_qmem_data(int dns_fd, int userid, struct query *q) 
     436/* Quick helper function to keep handle_null_request() clean */ 
     437{ 
     438        char cmc[4]; 
     439        int i; 
     440 
     441        for (i = 0; i < 4; i++) 
     442                if (q->name[i+1] >= 'A' && q->name[i+1] <= 'Z') 
     443                        cmc[i] = q->name[i+1] + ('a' - 'A'); 
     444                else 
     445                        cmc[i] = q->name[i+1]; 
     446 
     447        return answer_from_qmem(dns_fd, q, users[userid].qmemdata_cmc, 
     448                                users[userid].qmemdata_type, QMEMDATA_LEN, 
     449                                (void *) cmc); 
     450} 
    318451 
    319452static int 
     
    374507        write_dns(dns_fd, q, pkt, datalen + 2, users[userid].downenc); 
    375508 
     509        if (q->id2 != 0) { 
     510                q->id = q->id2; 
     511                q->fromlen = q->fromlen2; 
     512                memcpy(&(q->from), &(q->from2), q->fromlen2); 
     513                if (debug >= 1) 
     514                        fprintf(stderr, "OUT  again to last duplicate\n"); 
     515                write_dns(dns_fd, q, pkt, datalen + 2, users[userid].downenc); 
     516        } 
     517 
     518        save_to_qmem_pingordata(userid, q); 
     519 
    376520#ifdef DNSCACHE_LEN 
    377521        save_to_dnscache(userid, q, pkt, datalen + 2); 
     
    379523 
    380524        q->id = 0;                      /* this query is used */ 
    381         /* .iddupe is _not_ reset on purpose */ 
    382525 
    383526        if (datalen > 0 && datalen == users[userid].outpacket.len) { 
     
    505648 
    506649        /* Is packet done? */ 
    507         if (users[userid].outpacket.offset == users[userid].outpacket.len) { 
     650        if (users[userid].outpacket.offset >= users[userid].outpacket.len) { 
    508651                users[userid].outpacket.len = 0; 
    509652                users[userid].outpacket.offset = 0; 
    510653                users[userid].outpacket.fragment--;     /* unneeded ++ above */ 
    511                 /* last seqno/frag are always returned on pings */ 
     654                /* ^keep last seqno/frag, are always returned on pings */ 
    512655                /* users[userid].outfragresent = 0; already above */ 
    513656 
     
    555698                        userid = find_available_user(); 
    556699                        if (userid >= 0) { 
     700                                int i; 
    557701                                struct sockaddr_in *tempin; 
    558702 
     
    569713                                        userid, inet_ntoa(tempin->sin_addr)); 
    570714                                users[userid].q.id = 0; 
    571                                 users[userid].q.iddupe = 0; 
    572                                 users[userid].q_prev.id = 0; 
    573                                 users[userid].q_prev.iddupe = 0; 
     715                                users[userid].q.id2 = 0; 
    574716                                users[userid].q_sendrealsoon.id = 0; 
     717                                users[userid].q_sendrealsoon.id2 = 0; 
    575718                                users[userid].q_sendrealsoon_new = 0; 
    576719                                users[userid].outpacket.len = 0; 
     
    593736#ifdef DNSCACHE_LEN 
    594737                                { 
    595                                         int i; 
    596738                                        for (i = 0; i < DNSCACHE_LEN; i++) { 
    597739                                                users[userid].dnscache_q[i].id = 0; 
     
    601743                                users[userid].dnscache_lastfilled = 0; 
    602744#endif 
     745                                for (i = 0; i < QMEMPING_LEN; i++) 
     746                                        users[userid].qmemping_type[i] = T_UNSET; 
     747                                users[userid].qmemping_lastfilled = 0; 
     748                                for (i = 0; i < QMEMDATA_LEN; i++) 
     749                                        users[userid].qmemdata_type[i] = T_UNSET; 
     750                                users[userid].qmemdata_lastfilled = 0; 
    603751                        } else { 
    604752                                /* No space for another user */ 
     
    615763        } else if(in[0] == 'L' || in[0] == 'l') { 
    616764                read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), domain_len - 1, b32); 
     765                if (read < 17) { 
     766                        write_dns(dns_fd, q, "BADLEN", 6, 'T'); 
     767                        return; 
     768                } 
     769 
    617770                /* Login phase, handle auth */ 
    618771                userid = unpacked[0]; 
     
    713866                        write_dns(dns_fd, q, enc->name, strlen(enc->name), users[userid].downenc); 
    714867                        break; 
     868                case 26: /* "2nd" 6 bits per byte = base64u, with underscore */ 
     869                        enc = get_base64u_encoder(); 
     870                        user_switch_codec(userid, enc); 
     871                        write_dns(dns_fd, q, enc->name, strlen(enc->name), users[userid].downenc); 
     872                        break; 
     873                case 7: /* 7 bits per byte = base128 */ 
     874                        enc = get_base128_encoder(); 
     875                        user_switch_codec(userid, enc); 
     876                        write_dns(dns_fd, q, enc->name, strlen(enc->name), users[userid].downenc); 
     877                        break; 
    715878                default: 
    716879                        write_dns(dns_fd, q, "BADCODEC", 8, users[userid].downenc); 
     
    719882                return; 
    720883        } else if(in[0] == 'O' || in[0] == 'o') { 
    721                 if (domain_len != 4) { /* len = 4, example: "O1T." */ 
     884                if (domain_len < 3) { /* len at least 3, example: "O1T" */ 
    722885                        write_dns(dns_fd, q, "BADLEN", 6, 'T'); 
    723886                        return; 
     
    742905                        write_dns(dns_fd, q, "Base64", 6, users[userid].downenc); 
    743906                        break; 
     907                case 'U': 
     908                case 'u': 
     909                        users[userid].downenc = 'U'; 
     910                        write_dns(dns_fd, q, "Base64u", 7, users[userid].downenc); 
     911                        break; 
     912                case 'V': 
     913                case 'v': 
     914                        users[userid].downenc = 'V'; 
     915                        write_dns(dns_fd, q, "Base128", 7, users[userid].downenc); 
     916                        break; 
    744917                case 'R': 
    745918                case 'r': 
     
    762935                } 
    763936                return; 
     937        } else if(in[0] == 'Y' || in[0] == 'y') { 
     938                int i; 
     939                char *datap; 
     940                int datalen; 
     941 
     942                if (domain_len < 6) { /* len at least 6, example: "YTxCMC" */ 
     943                        write_dns(dns_fd, q, "BADLEN", 6, 'T'); 
     944                        return; 
     945                } 
     946 
     947                i = b32_8to5(in[2]);    /* check variant */ 
     948 
     949                switch (i) { 
     950                case 1: 
     951                        datap = DOWNCODECCHECK1; 
     952                        datalen = DOWNCODECCHECK1_LEN; 
     953                        break; 
     954                default: 
     955                        write_dns(dns_fd, q, "BADLEN", 6, 'T'); 
     956                        return; 
     957                } 
     958 
     959                switch (in[1]) { 
     960                case 'T': 
     961                case 't': 
     962                        if (q->type == T_TXT || 
     963                            q->type == T_SRV || q->type == T_MX || 
     964                            q->type == T_CNAME || q->type == T_A) { 
     965                                write_dns(dns_fd, q, datap, datalen, 'T'); 
     966                                return; 
     967                        } 
     968                        break; 
     969                case 'S': 
     970                case 's': 
     971                        if (q->type == T_TXT || 
     972                            q->type == T_SRV || q->type == T_MX || 
     973                            q->type == T_CNAME || q->type == T_A) { 
     974                                write_dns(dns_fd, q, datap, datalen, 'S'); 
     975                                return; 
     976                        } 
     977                        break; 
     978                case 'U': 
     979                case 'u': 
     980                        if (q->type == T_TXT || 
     981                            q->type == T_SRV || q->type == T_MX || 
     982                            q->type == T_CNAME || q->type == T_A) { 
     983                                write_dns(dns_fd, q, datap, datalen, 'U'); 
     984                                return; 
     985                        } 
     986                        break; 
     987                case 'V': 
     988                case 'v': 
     989                        if (q->type == T_TXT || 
     990                            q->type == T_SRV || q->type == T_MX || 
     991                            q->type == T_CNAME || q->type == T_A) { 
     992                                write_dns(dns_fd, q, datap, datalen, 'V'); 
     993                                return; 
     994                        } 
     995                        break; 
     996                case 'R': 
     997                case 'r': 
     998                        if (q->type == T_NULL || q->type == T_TXT) { 
     999                                write_dns(dns_fd, q, datap, datalen, 'R'); 
     1000                                return; 
     1001                        } 
     1002                        break; 
     1003                } 
     1004 
     1005                /* if still here, then codec not available */ 
     1006                write_dns(dns_fd, q, "BADCODEC", 8, 'T'); 
     1007                return; 
     1008 
    7641009        } else if(in[0] == 'R' || in[0] == 'r') { 
    7651010                int req_frag_size; 
     1011 
     1012                if (domain_len < 16) {  /* we'd better have some chars for data... */ 
     1013                        write_dns(dns_fd, q, "BADLEN", 6, 'T'); 
     1014                        return; 
     1015                } 
    7661016 
    7671017                /* Downstream fragsize probe packet */ 
     
    7781028                        char buf[2048]; 
    7791029                        int i; 
    780                         unsigned int v = (unsigned int) rand(); 
     1030                        unsigned int v = ((unsigned int) rand()) & 0xff ; 
    7811031 
    7821032                        memset(buf, 0, sizeof(buf)); 
     
    7851035                        /* make checkable pseudo-random sequence */ 
    7861036                        buf[2] = 107; 
    787                         for (i = 3; i < 2048; i++, v += 107) 
    788                                 buf[i] = (char) (v & 0xff); 
     1037                        for (i = 3; i < 2048; i++, v = (v + 107) & 0xff) 
     1038                                buf[i] = v; 
    7891039                        write_dns(dns_fd, q, buf, req_frag_size, users[userid].downenc); 
    7901040                } 
     
    7941044 
    7951045                read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), domain_len - 1, b32); 
     1046 
     1047                if (read < 3) { 
     1048                        write_dns(dns_fd, q, "BADLEN", 6, 'T'); 
     1049                        return; 
     1050                } 
     1051 
    7961052                /* Downstream fragsize packet */ 
    7971053                userid = unpacked[0]; 
     
    8361092#ifdef DNSCACHE_LEN 
    8371093                /* Check if cached */ 
    838                 if (answer_from_dnscache(dns_fd, userid, q)) { 
    839                         /* Answer sent. But if this is our currently waiting 
    840                            request in the queue, invalidate now since we can't 
    841                            be sure that our coming new answer will ever reach 
    842                            client. Happens on 3+ retransmits in the "lost pings 
    843                            problem" with agressive DNS server. 
    844                         */ 
    845                         if (users[userid].q.id != 0 && 
    846                             q->type == users[userid].q.type && 
    847                             !strcmp(q->name, users[userid].q.name)) 
    848                                 users[userid].q.id = 0; 
     1094                if (answer_from_dnscache(dns_fd, userid, q)) 
    8491095                        return; 
    850                 } 
    8511096#endif 
    8521097 
    853                 /* Dupe pruning */ 
    854                 if (users[userid].q.iddupe != 0 && 
     1098                /* Check if duplicate (and not in full dnscache any more) */ 
     1099                if (answer_from_qmem(dns_fd, q, users[userid].qmemping_cmc, 
     1100                                     users[userid].qmemping_type, QMEMPING_LEN, 
     1101                                     (void *) unpacked)) 
     1102                        return; 
     1103 
     1104                /* Check if duplicate of waiting queries; impatient DNS relays 
     1105                   like to re-try early and often (with _different_ .id!)  */ 
     1106                if (users[userid].q.id != 0 && 
    8551107                    q->type == users[userid].q.type && 
    8561108                    !strcmp(q->name, users[userid].q.name) && 
    8571109                    users[userid].lazy) { 
    858                         /* We have this ping already. Aggressively impatient 
    859                            DNS servers resend queries with _different_ id. 
    860                            But hostname check is sufficient, includes CMC. 
    861                            Just drop this ping. 
    862                            If we already answered it (e.g. data available some 
    863                            milliseconds ago), DNS server should have noticed 
    864                            by now (race condition, happens rarely). 
    865                            If we didn't answer yet, we'll do later (to the 
    866                            first id, thank you very much). */ 
     1110                        /* We have this ping already, and it's waiting to be 
     1111                           answered. Always keep the last duplicate, since the 
     1112                           relay may have forgotten its first version already. 
     1113                           Our answer will go to both. 
     1114                           (If we already sent an answer, qmem/cache will 
     1115                           have triggered.) */ 
    8671116                        if (debug >= 2) { 
    868                                 fprintf(stderr, "PING pkt from user %d = dupe from impatient DNS server, ignoring\n", 
     1117                                fprintf(stderr, "PING pkt from user %d = dupe from impatient DNS server, remembering\n", 
    8691118                                        userid); 
    8701119                        } 
     1120                        users[userid].q.id2 = q->id; 
     1121                        users[userid].q.fromlen2 = q->fromlen; 
     1122                        memcpy(&(users[userid].q.from2), &(q->from), q->fromlen); 
    8711123                        return; 
    8721124                } 
    8731125  
    874                 if (users[userid].q_prev.iddupe != 0 && 
    875                     q->type == users[userid].q_prev.type && 
    876                     !strcmp(q->name, users[userid].q_prev.name) && 
    877                     users[userid].lazy) { 
    878                         /* Okay, even older ping that we already saw 
    879                            and probably answered just milliseconds ago. 
    880                            This is a race condition that agressive DNS servers 
    881                            actually train into; happens quite often. 
    882                            Just drop this new version. */ 
    883                         /* If using dnscache, this new query probably got a 
    884                            cached answer already, and this shouldn't trigger. */ 
    885                         if (debug >= 2) { 
    886                                 fprintf(stderr, "PING pkt from user %d = dupe (previous) from impatient DNS server, ignoring\n", 
    887                                         userid); 
    888                         } 
    889                         return; 
    890                 } 
    891  
    8921126                if (users[userid].q_sendrealsoon.id != 0 && 
    8931127                    q->type == users[userid].q_sendrealsoon.type && 
    8941128                    !strcmp(q->name, users[userid].q_sendrealsoon.name)) { 
    895                         /* Outer select loop will send answer immediately. */ 
     1129                        /* Outer select loop will send answer immediately, 
     1130                           to both queries. */ 
    8961131                        if (debug >= 2) { 
    897                                 fprintf(stderr, "PING pkt from user %d = dupe from impatient DNS server, ignoring\n", 
     1132                                fprintf(stderr, "PING pkt from user %d = dupe from impatient DNS server, remembering\n", 
    8981133                                        userid); 
    8991134                        } 
     1135                        users[userid].q_sendrealsoon.id2 = q->id; 
     1136                        users[userid].q_sendrealsoon.fromlen2 = q->fromlen; 
     1137                        memcpy(&(users[userid].q_sendrealsoon.from2), 
     1138                               &(q->from), q->fromlen); 
    9001139                        return; 
    9011140                } 
     
    9351174                } 
    9361175 
    937                 /* Save previous query for dupe checking */ 
    938                 memcpy(&(users[userid].q_prev), &(users[userid].q), 
    939                        sizeof(struct query)); 
    940  
    9411176                /* Save new query and time info */ 
    9421177                memcpy(&(users[userid].q), q, sizeof(struct query)); 
     
    9561191                int upstream_ok = 1; 
    9571192                int didsend = 0; 
    958                 int thisisdupe = 0; 
    9591193                int code = -1; 
    9601194 
    961                 /* Need 4char header + >=1 char data */ 
    962                 if (domain_len < 5) 
     1195                /* Need 5char header + >=1 char data */ 
     1196                if (domain_len < 6) 
    9631197                        return; 
    9641198 
     
    9881222#ifdef DNSCACHE_LEN 
    9891223                /* Check if cached */ 
    990                 if (answer_from_dnscache(dns_fd, userid, q)) { 
    991                         /* Answer sent. But if this is our currently waiting 
    992                            request in the queue, invalidate now since we can't 
    993                            be sure that our coming new answer will ever reach 
    994                            client. Happens on 3+ retransmits in the "lost pings 
    995                            problem" with agressive DNS server. 
    996                         */ 
    997                         if (users[userid].q.id != 0 && 
    998                             q->type == users[userid].q.type && 
    999                             !strcmp(q->name, users[userid].q.name)) 
    1000                                 users[userid].q.id = 0; 
     1224                if (answer_from_dnscache(dns_fd, userid, q)) 
    10011225                        return; 
    1002                 } 
    10031226#endif 
    10041227 
    1005                 /* Dupe pruning */ 
    1006                 if (users[userid].q.iddupe != 0 && 
    1007                     q->id == users[userid].q.iddupe && 
     1228                /* Check if duplicate (and not in full dnscache any more) */ 
     1229                if (answer_from_qmem_data(dns_fd, userid, q)) 
     1230                        return; 
     1231 
     1232                /* Check if duplicate of waiting queries; impatient DNS relays 
     1233                   like to re-try early and often (with _different_ .id!)  */ 
     1234                if (users[userid].q.id != 0 && 
    10081235                    q->type == users[userid].q.type && 
    1009                     !strcmp(q->name, users[userid].q.name) && 
     1236                    !strcmp(q->name, users[userid].q.name) &&  
    10101237                    users[userid].lazy) { 
    1011                         /* We have this exact query already, with same id. 
    1012                            So this is surely a honest dupe. */ 
     1238                        /* We have this packet already, and it's waiting to be 
     1239                           answered. Always keep the last duplicate, since the 
     1240                           relay may have forgotten its first version already. 
     1241                           Our answer will go to both. 
     1242                           (If we already sent an answer, qmem/cache will 
     1243                           have triggered.) */ 
    10131244                        if (debug >= 2) { 
    1014                                 fprintf(stderr, "IN   pkt from user %d = dupe from impatient DNS server, ignoring\n", 
    1015                                         userid); 
    1016                         } 
    1017                         return; 
    1018                 } 
    1019                 /* Note: Upstream data packet retransmits have exact same 
    1020                    hostname, so can't reliably ignore the id here. 
    1021                    And that's not even needed because of send_ping_soon in 
    1022                    client. Nice. We still do need a queue-flush on data1-data1, 
    1023                    see thisisdupe. 
    1024                    But then there's the race condition in two variants: 
    1025                    data1 - ping - data1 
    1026                    data1 - data2 - data1 
    1027                    These are surely dupes, irrespective of id, because client 
    1028                    will only send ping/data2 when it has received our ack for 
    1029                    data1. (Okay, and ping/data2 should be dupe-pruned 
    1030                    themselves already...) 
    1031                    Draw pictures if you don't understand immediately. 
    1032                 */ 
    1033                 /* If using dnscache, the new data1 probably got a 
    1034                    cached answer already, and this shouldn't trigger. */ 
    1035                 if (users[userid].q.iddupe != 0 && 
    1036                     (q->type != users[userid].q.type || 
    1037                      strcmp(q->name, users[userid].q.name)) && 
    1038                     users[userid].q_prev.iddupe != 0 && 
    1039                     q->type == users[userid].q_prev.type && 
    1040                     !strcmp(q->name, users[userid].q_prev.name) && 
    1041                     users[userid].lazy) { 
    1042                         if (debug >= 2) { 
    1043                                 fprintf(stderr, "IN   pkt from user %d = dupe (previous) from impatient DNS server, ignoring\n", 
     1245                                fprintf(stderr, "IN   pkt from user %d = dupe from impatient DNS server, remembering\n", 
    10441246                                        userid); 
    10451247                        } 
     1248                        users[userid].q.id2 = q->id; 
     1249                        users[userid].q.fromlen2 = q->fromlen; 
     1250                        memcpy(&(users[userid].q.from2), &(q->from), q->fromlen); 
    10461251                        return; 
    10471252                } 
     
    10501255                    q->type == users[userid].q_sendrealsoon.type && 
    10511256                    !strcmp(q->name, users[userid].q_sendrealsoon.name)) { 
    1052                         /* Outer select loop will send answer immediately. */ 
     1257                        /* Outer select loop will send answer immediately, 
     1258                           to both queries. */ 
    10531259                        if (debug >= 2) { 
    1054                                 fprintf(stderr, "IN   pkt from user %d = dupe from impatient DNS server, ignoring\n", 
     1260                                fprintf(stderr, "IN   pkt from user %d = dupe from impatient DNS server, remembering\n", 
    10551261                                        userid); 
    10561262                        } 
     1263                        users[userid].q_sendrealsoon.id2 = q->id; 
     1264                        users[userid].q_sendrealsoon.fromlen2 = q->fromlen; 
     1265                        memcpy(&(users[userid].q_sendrealsoon.from2), 
     1266                               &(q->from), q->fromlen); 
    10571267                        return; 
    10581268                } 
    10591269   
    1060                 /* We need to flush our queue on dupes, since our new answer 
    1061                    to the first query may/will be duplicated by DNS caches to 
    1062                    also answer the client's re-sent (=dupe) query. 
    1063                    (Caches take TTL=0 to mean: "good for current and earlier 
    1064                    queries") */ 
    1065                 if (users[userid].q.iddupe != 0 && 
    1066                     q->type == users[userid].q.type && 
    1067                     !strcmp(q->name, users[userid].q.name)) 
    1068                         thisisdupe = 1; 
    1069  
    10701270 
    10711271                /* Decode data header */ 
     
    11231323 
    11241324                if (upstream_ok) { 
    1125                         /* decode with this users encoding */ 
    1126                         read = unpack_data(unpacked, sizeof(unpacked), &(in[4]), domain_len - 4,  
     1325                        /* decode with this user's encoding */ 
     1326                        read = unpack_data(unpacked, sizeof(unpacked), &(in[5]), domain_len - 5, 
    11271327                                           users[userid].encoder); 
    11281328 
     
    11611361                   - If we are in non-lazy mode, there should be no query 
    11621362                     waiting, but if there is, send immediately. 
    1163                    - If we are flushing queue due to dupe, send immediately. 
    11641363                   - In all other cases (mostly the last-fragment cases), 
    11651364                     we can afford to wait just a tiny little while for the 
     
    11711370                            (upstream_ok && !lastfrag && !didsend) || 
    11721371                            (!upstream_ok && !didsend) || 
    1173                             !users[userid].lazy || 
    1174                             thisisdupe) { 
     1372                            !users[userid].lazy) { 
    11751373                                didsend = 1; 
    11761374                                if (send_chunk_or_dataless(dns_fd, userid, &users[userid].q) == 1) 
     
    11871385                } 
    11881386 
    1189                 /* Save previous query for dupe checking */ 
    1190                 memcpy(&(users[userid].q_prev), &(users[userid].q), 
    1191                        sizeof(struct query)); 
    1192  
    11931387                /* Save new query and time info */ 
    11941388                memcpy(&(users[userid].q), q, sizeof(struct query)); 
     
    11991393                   - If we have new data waiting and not yet sent above, 
    12001394                     send immediately. 
    1201                    - If we are flushing queue due to dupe, send immediately. 
    12021395                   - If this wasn't the last upstream fragment, then we expect 
    12031396                     more, so ack immediately if we didn't already or are 
     
    12091402                   - In all other cases, don't send anything now. 
    12101403                */ 
    1211                 if ((users[userid].outpacket.len > 0 && !didsend) 
    1212                     || thisisdupe) 
     1404                if (users[userid].outpacket.len > 0 && !didsend) 
    12131405                        send_chunk_or_dataless(dns_fd, userid, &users[userid].q); 
    12141406                else if (!didsend || !users[userid].lazy) { 
     
    12281420static void 
    12291421handle_ns_request(int dns_fd, struct query *q) 
     1422/* Mostly identical to handle_a_request() below */ 
    12301423{ 
    12311424        char buf[64*1024]; 
     
    12521445        if (sendto(dns_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) { 
    12531446                warn("ns reply send error"); 
     1447        } 
     1448} 
     1449 
     1450static void 
     1451handle_a_request(int dns_fd, struct query *q, int fakeip) 
     1452/* Mostly identical to handle_ns_request() above */ 
     1453{ 
     1454        char buf[64*1024]; 
     1455        int len; 
     1456 
     1457        if (fakeip) { 
     1458                in_addr_t ip = inet_addr("127.0.0.1"); 
     1459                memcpy(&q->destination.s_addr, &ip, sizeof(in_addr_t)); 
     1460 
     1461        } else if (ns_ip != INADDR_ANY) { 
     1462                /* If ns_ip set, overwrite destination addr with it. 
     1463                 * Destination addr will be sent as additional record (A, IN) */ 
     1464                memcpy(&q->destination.s_addr, &ns_ip, sizeof(in_addr_t)); 
     1465        } 
     1466 
     1467        len = dns_encode_a_response(buf, sizeof(buf), q); 
     1468        if (len < 1) { 
     1469                warnx("dns_encode_a_response doesn't fit"); 
     1470                return; 
     1471        } 
     1472         
     1473        if (debug >= 2) { 
     1474                struct sockaddr_in *tempin; 
     1475                tempin = (struct sockaddr_in *) &(q->from); 
     1476                fprintf(stderr, "TX: client %s, type %d, name %s, %d bytes A reply\n", 
     1477                        inet_ntoa(tempin->sin_addr), q->type, q->name, len); 
     1478        } 
     1479        if (sendto(dns_fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen) <= 0) { 
     1480                warn("a reply send error"); 
    12541481        } 
    12551482} 
     
    13401567        struct query q; 
    13411568        int read; 
    1342         char *domain; 
    13431569        int domain_len; 
    13441570        int inside_topdomain; 
     
    13531579                        inet_ntoa(tempin->sin_addr), q.type, q.name); 
    13541580        } 
    1355          
    1356         domain = strstr(q.name, topdomain); 
    1357         inside_topdomain = 0; 
    1358         if (domain) { 
    1359                 domain_len = (int) (domain - q.name);  
    1360                 if (domain_len + strlen(topdomain) == strlen(q.name)) { 
    1361                         inside_topdomain = 1; 
    1362                 } 
    1363         } 
    1364          
     1581 
     1582        domain_len = strlen(q.name) - strlen(topdomain); 
     1583        if (domain_len >= 0 && !strcasecmp(q.name + domain_len, topdomain)) 
     1584                inside_topdomain = 1; 
     1585        /* require dot before topdomain */ 
     1586        if (domain_len >= 1 && q.name[domain_len - 1] != '.') 
     1587                inside_topdomain = 0; 
     1588 
    13651589        if (inside_topdomain) { 
    13661590                /* This is a query we can handle */ 
     1591 
     1592                /* Handle A-type query for ns.topdomain, possibly caused 
     1593                   by our proper response to any NS request */ 
     1594                if (domain_len == 3 && q.type == T_A && 
     1595                    (q.name[0] == 'n' || q.name[0] == 'N') && 
     1596                    (q.name[1] == 's' || q.name[1] == 'S') && 
     1597                     q.name[2] == '.') { 
     1598                        handle_a_request(dns_fd, &q, 0); 
     1599                        return 0; 
     1600                } 
     1601 
     1602                /* Handle A-type query for www.topdomain, for anyone that's 
     1603                   poking around */ 
     1604                if (domain_len == 4 && q.type == T_A && 
     1605                    (q.name[0] == 'w' || q.name[0] == 'W') && 
     1606                    (q.name[1] == 'w' || q.name[1] == 'W') && 
     1607                    (q.name[2] == 'w' || q.name[2] == 'W') && 
     1608                     q.name[3] == '.') { 
     1609                        handle_a_request(dns_fd, &q, 1); 
     1610                        return 0; 
     1611                } 
    13671612 
    13681613                switch (q.type) { 
     
    13711616                case T_A: 
    13721617                case T_MX: 
     1618                case T_SRV: 
    13731619                case T_TXT: 
    13741620                        /* encoding is "transparent" here */ 
     
    14971743                } else { 
    14981744                        /* send the compressed(!) packet to other client */ 
     1745                /*XXX START adjust indent 1 tab forward*/ 
     1746                if (users[touser].conn == CONN_DNS_NULL) { 
    14991747                        if (users[touser].outpacket.len == 0) { 
    15001748                                start_new_outpacket(touser, 
     
    15061754                                        send_chunk_or_dataless(dns_fd, touser, &users[touser].q_sendrealsoon); 
    15071755                                else if (users[touser].q.id != 0) 
    1508                                         send_chunk_or_dataless(dns_fd, touser, &users[userid].q); 
     1756                                        send_chunk_or_dataless(dns_fd, touser, &users[touser].q); 
    15091757#ifdef OUTPACKETQ_LEN 
    15101758                        } else { 
     
    15141762#endif 
    15151763                        } 
     1764                } else{ /* CONN_RAW_UDP */ 
     1765                        send_raw(dns_fd, users[userid].inpacket.data, 
     1766                                 users[userid].inpacket.len, touser, 
     1767                                 RAW_HDR_CMD_DATA, &users[touser].q); 
     1768                } 
     1769                /*XXX END adjust indent 1 tab forward*/ 
    15161770                } 
    15171771        } else { 
     
    15321786        if (len < 16) return; 
    15331787 
    1534         if (userid < 0 || userid > created_users) return; 
    1535         if (!users[userid].active) return; 
     1788        /* can't use check_user_and_ip() since IP address will be different, 
     1789           so duplicate here except IP address */ 
     1790        if (userid < 0 || userid >= created_users) return; 
     1791        if (!users[userid].active || users[userid].disabled) return; 
     1792        if (users[userid].last_pkt + 60 < time(NULL)) return; 
     1793 
     1794        if (debug >= 1) { 
     1795                fprintf(stderr, "IN   login raw, len %d, from user %d\n", 
     1796                        len, userid); 
     1797        } 
    15361798 
    15371799        /* User sends hash of seed + 1 */ 
     
    15501812                /* Correct hash, reply with hash of seed - 1 */ 
    15511813                user_set_conn_type(userid, CONN_RAW_UDP); 
    1552                 users[userid].last_pkt = time(NULL); 
    15531814                login_calculate(myhash, 16, password, users[userid].seed - 1); 
    15541815                send_raw(fd, myhash, 16, userid, RAW_HDR_CMD_LOGIN, q); 
     
    15901851        users[userid].last_pkt = time(NULL); 
    15911852        memcpy(&(users[userid].q), q, sizeof(struct query)); 
     1853 
     1854        if (debug >= 1) { 
     1855                fprintf(stderr, "IN   ping raw, from user %d\n", userid); 
     1856        } 
    15921857 
    15931858        /* Send ping reply */ 
     
    16911956} 
    16921957 
     1958static size_t 
     1959write_dns_nameenc(char *buf, size_t buflen, char *data, int datalen, char downenc) 
     1960/* Returns #bytes of data that were encoded */ 
     1961{ 
     1962        static int td1 = 0; 
     1963        static int td2 = 0; 
     1964        size_t space; 
     1965        char *b; 
     1966 
     1967        /* Make a rotating topdomain to prevent filtering */ 
     1968        td1+=3; 
     1969        td2+=7; 
     1970        if (td1>=26) td1-=26; 
     1971        if (td2>=25) td2-=25; 
     1972 
     1973        /* encode data,datalen to CNAME/MX answer 
     1974           (adapted from build_hostname() in encoding.c) 
     1975         */ 
     1976 
     1977        space = MIN(0xFF, buflen) - 4 - 2; 
     1978        /* -1 encoding type, -3 ".xy", -2 for safety */ 
     1979 
     1980        memset(buf, 0, sizeof(buf)); 
     1981 
     1982        if (downenc == 'S') { 
     1983                buf[0] = 'i'; 
     1984                if (!b64->places_dots()) 
     1985                        space -= (space / 57);  /* space for dots */ 
     1986                b64->encode(buf+1, &space, data, datalen); 
     1987                if (!b64->places_dots()) 
     1988                        inline_dotify(buf, buflen); 
     1989        } else if (downenc == 'U') { 
     1990                buf[0] = 'j'; 
     1991                if (!b64u->places_dots()) 
     1992                        space -= (space / 57);  /* space for dots */ 
     1993                b64u->encode(buf+1, &space, data, datalen); 
     1994                if (!b64u->places_dots()) 
     1995                        inline_dotify(buf, buflen); 
     1996        } else if (downenc == 'V') { 
     1997                buf[0] = 'k'; 
     1998                if (!b128->places_dots()) 
     1999                        space -= (space / 57);  /* space for dots */ 
     2000                b128->encode(buf+1, &space, data, datalen); 
     2001                if (!b128->places_dots()) 
     2002                        inline_dotify(buf, buflen); 
     2003        } else { 
     2004                buf[0] = 'h'; 
     2005                if (!b32->places_dots()) 
     2006                        space -= (space / 57);  /* space for dots */ 
     2007                b32->encode(buf+1, &space, data, datalen); 
     2008                if (!b32->places_dots()) 
     2009                        inline_dotify(buf, buflen); 
     2010        } 
     2011 
     2012        /* Add dot (if it wasn't there already) and topdomain */ 
     2013        b = buf; 
     2014        b += strlen(buf) - 1; 
     2015        if (*b != '.')  
     2016                *++b = '.'; 
     2017        b++; 
     2018 
     2019        *b = 'a' + td1; 
     2020        b++; 
     2021        *b = 'a' + td2; 
     2022        b++; 
     2023        *b = '\0'; 
     2024 
     2025        return space; 
     2026} 
     2027 
    16932028static void 
    16942029write_dns(int fd, struct query *q, char *data, int datalen, char downenc) 
     
    16972032        int len = 0; 
    16982033 
    1699         if (q->type == T_CNAME || q->type == T_A || q->type == T_MX) { 
    1700                 static int td1 = 0; 
    1701                 static int td2 = 0; 
     2034        if (q->type == T_CNAME || q->type == T_A) { 
    17022035                char cnamebuf[1024];            /* max 255 */ 
    1703                 size_t space; 
    1704                 char *b; 
    1705  
    1706                 /* Make a rotating topdomain to prevent filtering */ 
    1707                 td1+=3; 
    1708                 td2+=7; 
    1709                 if (td1>=26) td1-=26; 
    1710                 if (td2>=25) td2-=25; 
    1711  
    1712                 /* encode data,datalen to CNAME/MX answer */ 
    1713                 /* (adapted from build_hostname() in iodine.c) */ 
    1714  
    1715                 space = MIN(0xFF, sizeof(cnamebuf)) - 4 - 2; 
    1716                 /* -1 encoding type, -3 ".xy", -2 for safety */ 
    1717  
    1718                 memset(cnamebuf, 0, sizeof(cnamebuf)); 
    1719  
    1720                 if (downenc == 'S') { 
    1721                         cnamebuf[0] = 'I'; 
    1722                         if (!b64->places_dots()) 
    1723                                 space -= (space / 57);  /* space for dots */ 
    1724                         b64->encode(cnamebuf+1, &space, data, datalen); 
    1725                         if (!b64->places_dots()) 
    1726                                 inline_dotify(cnamebuf, sizeof(cnamebuf)); 
    1727                 } else { 
    1728                         cnamebuf[0] = 'H'; 
    1729                         if (!b32->places_dots()) 
    1730                                 space -= (space / 57);  /* space for dots */ 
    1731                         b32->encode(cnamebuf+1, &space, data, datalen); 
    1732                         if (!b32->places_dots()) 
    1733                                 inline_dotify(cnamebuf, sizeof(cnamebuf)); 
    1734                 } 
    1735  
    1736                 /* Add dot (if it wasn't there already) and topdomain */ 
    1737                 b = cnamebuf; 
    1738                 b += strlen(cnamebuf); 
    1739                 if (*b != '.')  
    1740                         *b++ = '.'; 
    1741  
    1742                 *b = 'a' + td1; 
    1743                 b++; 
    1744                 *b = 'a' + td2; 
    1745                 b++; 
     2036 
     2037                write_dns_nameenc(cnamebuf, sizeof(cnamebuf), 
     2038                                  data, datalen, downenc); 
     2039 
     2040                len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, cnamebuf, 
     2041                                 sizeof(cnamebuf)); 
     2042        } else if (q->type == T_MX || q->type == T_SRV) { 
     2043                char mxbuf[64*1024]; 
     2044                char *b = mxbuf; 
     2045                int offset = 0; 
     2046                int res; 
     2047 
     2048                while (1) { 
     2049                        res = write_dns_nameenc(b, sizeof(mxbuf) - (b - mxbuf), 
     2050                                                data + offset, 
     2051                                                datalen - offset, downenc); 
     2052                        if (res < 1) { 
     2053                                /* nothing encoded */ 
     2054                                b++;    /* for final \0 */ 
     2055                                break; 
     2056                        } 
     2057 
     2058                        b = b + strlen(b) + 1; 
     2059 
     2060                        offset += res; 
     2061                        if (offset >= datalen) 
     2062                                break; 
     2063                } 
     2064 
     2065                /* Add final \0 */ 
    17462066                *b = '\0'; 
    17472067 
    1748                 len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, cnamebuf, sizeof(cnamebuf)); 
    1749         } 
    1750         else if (q->type == T_TXT) { 
     2068                len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, mxbuf, 
     2069                                 sizeof(mxbuf)); 
     2070        } else if (q->type == T_TXT) { 
    17512071                /* TXT with base32 */ 
    17522072                char txtbuf[64*1024]; 
     
    17562076 
    17572077                if (downenc == 'S') { 
    1758                         txtbuf[0] = 'S';        /* plain base64(Sixty-four) */ 
     2078                        txtbuf[0] = 's';        /* plain base64(Sixty-four) */ 
    17592079                        len = b64->encode(txtbuf+1, &space, data, datalen); 
    17602080                } 
     2081                else if (downenc == 'U') { 
     2082                        txtbuf[0] = 'u';        /* Base64 with Underscore */ 
     2083                        len = b64u->encode(txtbuf+1, &space, data, datalen); 
     2084                } 
     2085                else if (downenc == 'V') { 
     2086                        txtbuf[0] = 'v';        /* Base128 */ 
     2087                        len = b128->encode(txtbuf+1, &space, data, datalen); 
     2088                } 
    17612089                else if (downenc == 'R') { 
    1762                         txtbuf[0] = 'R';        /* Raw binary data */ 
     2090                        txtbuf[0] = 'r';        /* Raw binary data */ 
    17632091                        len = MIN(datalen, sizeof(txtbuf) - 1); 
    17642092                        memcpy(txtbuf + 1, data, len); 
    17652093                } else { 
    1766                         txtbuf[0] = 'T';        /* plain base32(Thirty-two) */ 
     2094                        txtbuf[0] = 't';        /* plain base32(Thirty-two) */ 
    17672095                        len = b32->encode(txtbuf+1, &space, data, datalen); 
    17682096                } 
     
    18162144        fprintf(stderr, "  -f to keep running in foreground\n"); 
    18172145        fprintf(stderr, "  -D to increase debug level\n"); 
     2146        fprintf(stderr, "     (using -DD in UTF-8 terminal: \"LC_ALL=C luit iodined -DD ...\")\n"); 
    18182147        fprintf(stderr, "  -u name to drop privileges and run as user 'name'\n"); 
    18192148        fprintf(stderr, "  -t dir to chroot to directory dir\n"); 
     
    18822211        bind_enable = 0; 
    18832212        bind_fd = 0; 
    1884         mtu = 1200; 
     2213        mtu = 1130;     /* Very many relays give fragsize 1150 or slightly 
     2214                           higher for NULL; tun/zlib adds ~17 bytes. */ 
    18852215        listen_ip = INADDR_ANY; 
    18862216        port = 53; 
     
    18942224        b32 = get_base32_encoder(); 
    18952225        b64 = get_base64_encoder(); 
     2226        b64u = get_base64u_encoder(); 
     2227        b128 = get_base128_encoder(); 
    18962228         
    18972229        retval = 0; 
  • src/user.h

    r60dfbf rb17790  
    2525 
    2626#define DNSCACHE_LEN 4 
    27 /* Undefine to disable. MUST be less than 7; also see comments in iodined.c */ 
     27/* Undefine to disable. Should be less than 18; also see comments in iodined.c */ 
     28 
     29 
     30#define QMEMPING_LEN 30 
     31/* Max advisable: 64k/2 = 32000. Total mem usage: QMEMPING_LEN * USERS * 6 bytes */ 
     32 
     33#define QMEMDATA_LEN 15 
     34/* Max advisable: 36/2 = 18. Total mem usage: QMEMDATA_LEN * USERS * 6 bytes */ 
    2835 
    2936struct user { 
     
    3643        struct in_addr host; 
    3744        struct query q; 
    38         struct query q_prev; 
    3945        struct query q_sendrealsoon; 
    4046        int q_sendrealsoon_new; 
     
    4955        enum connection conn; 
    5056        int lazy; 
     57        unsigned char qmemping_cmc[QMEMPING_LEN * 4]; 
     58        unsigned short qmemping_type[QMEMPING_LEN]; 
     59        int qmemping_lastfilled; 
     60        unsigned char qmemdata_cmc[QMEMDATA_LEN * 4]; 
     61        unsigned short qmemdata_type[QMEMDATA_LEN]; 
     62        int qmemdata_lastfilled; 
    5163#ifdef OUTPACKETQ_LEN 
    5264        struct packet outpacketq[OUTPACKETQ_LEN]; 
  • src/version.h

    r27fc03 rb17790  
    2020/* This is the version of the network protocol 
    2121   It is usually equal to the latest iodine version number */ 
    22 #define VERSION 0x00000501 
     22#define VERSION 0x00000502 
    2323 
    2424#endif /* _VERSION_H_ */ 
Note: See TracChangeset for help on using the changeset viewer.