Ticket #75: iodine-trunk-CNAME2.patch

File iodine-trunk-CNAME2.patch, 61.1 KB (added by guest, 3 years ago)
  • src/base32.c

    old new  
    2626 
    2727static const char cb32[] =  
    2828        "abcdefghijklmnopqrstuvwxyz012345"; 
     29static const char cb32_ucase[] =  
     30        "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; 
    2931static unsigned char rev32[128]; 
    3032 
    3133static int base32_decode(void *, size_t *, const char *, size_t); 
     
    8082                for (i = 0; i < 32; i++) { 
    8183                        c = cb32[i]; 
    8284                        rev32[(int) c] = i; 
     85                        c = cb32_ucase[i]; 
     86                        rev32[(int) c] = i; 
    8387                } 
    8488                reverse_init = 1; 
    8589        } 
  • src/dns.c

    old new  
    3838#include "encoding.h" 
    3939#include "read.h" 
    4040 
     41#define CHECKLEN(x) if (buflen - (p-buf) < (x))  return 0 
     42 
    4143int 
    4244dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_t datalen) 
    4345{ 
     
    4648        char *p; 
    4749        int len; 
    4850 
     51        if (buflen < sizeof(HEADER)) 
     52                return 0; 
     53 
    4954        memset(buf, 0, buflen); 
    5055         
    5156        header = (HEADER*)buf; 
     
    6772         
    6873                name = 0xc000 | ((p - buf) & 0x3fff); 
    6974 
    70                 putname(&p, sizeof(q->name), q->name); 
     75                /* Question section */ 
     76                putname(&p, buflen - (p - buf), q->name); 
    7177 
     78                CHECKLEN(4); 
    7279                putshort(&p, q->type); 
    7380                putshort(&p, C_IN); 
    7481 
     82                /* Answer section */ 
     83                CHECKLEN(10); 
    7584                putshort(&p, name);      
    76                 putshort(&p, q->type); 
     85                if (q->type == T_A) 
     86                        putshort(&p, T_CNAME);  /* answer CNAME to A question */ 
     87                else 
     88                        putshort(&p, q->type); 
    7789                putshort(&p, C_IN); 
    78                 putlong(&p, 0); 
     90                putlong(&p, 0);         /* TTL */ 
     91 
     92                if (q->type == T_CNAME || q->type == T_A || q->type == T_MX) { 
     93                        /* data is expected to be like "Hblabla.host.name.com\0" */ 
     94 
     95                        char *startp = p; 
     96                        int namelen; 
     97 
     98                        p += 2;                 /* skip 2 bytes length */ 
     99                        CHECKLEN(2); 
     100                        if (q->type == T_MX) 
     101                                putshort(&p, 10);       /* preference */ 
     102                        putname(&p, buflen - (p - buf), data); 
     103                        CHECKLEN(0); 
     104                        namelen = p - startp; 
     105                        namelen -= 2; 
     106                        putshort(&startp, namelen); 
     107                } else if (q->type == T_TXT) { 
     108                        /* TXT has binary or base-X data */ 
     109                        char *startp = p; 
     110                        int txtlen; 
     111 
     112                        p += 2;                 /* skip 2 bytes length */ 
     113                        puttxtbin(&p, buflen - (p - buf), data, datalen); 
     114                        CHECKLEN(0); 
     115                        txtlen = p - startp; 
     116                        txtlen -= 2; 
     117                        putshort(&startp, txtlen); 
     118                } else { 
     119                        /* NULL has raw binary data */ 
     120                        datalen = MIN(datalen, buflen - (p - buf)); 
     121                        CHECKLEN(2); 
     122                        putshort(&p, datalen); 
     123                        CHECKLEN(datalen); 
     124                        putdata(&p, data, datalen); 
     125                         CHECKLEN(0); 
     126                } 
    79127 
    80                 putshort(&p, datalen); 
    81                 putdata(&p, data, datalen); 
    82128                break; 
    83129        case QR_QUERY: 
     130                /* Note that iodined also uses this for forward queries */ 
     131 
    84132                header->qdcount = htons(1); 
    85133                header->arcount = htons(1); 
    86134         
    87                 putname(&p, datalen, data); 
     135                putname(&p, buflen - (p - buf), data); 
    88136 
     137                CHECKLEN(4); 
    89138                putshort(&p, q->type); 
    90139                putshort(&p, C_IN); 
    91140 
    92                 /* EDNS0 */ 
     141                /* 
     142                 * EDNS0 to advertise maximum response length 
     143                 * (even CNAME/A/MX, 255+255+header would be >512) 
     144                 */ 
     145                CHECKLEN(11); 
    93146                putbyte(&p, 0x00);    /* Root */ 
    94147                putshort(&p, 0x0029); /* OPT */ 
    95148                putshort(&p, 0x1000); /* Payload size: 4096 */ 
     
    116169        int domain_len; 
    117170        char *p; 
    118171 
     172        if (buflen < sizeof(HEADER)) 
     173                return 0; 
     174 
    119175        memset(buf, 0, buflen); 
    120          
     176 
    121177        header = (HEADER*)buf; 
    122          
     178 
    123179        header->id = htons(q->id); 
    124180        header->qr = 1; 
    125181        header->opcode = 0; 
     
    147203        topname = 0xc000 | ((p - buf + domain_len) & 0x3fff); 
    148204 
    149205        /* Query section */ 
    150         putname(&p, sizeof(q->name), q->name);  /* Name */ 
    151         putshort(&p, q->type);                  /* Type */ 
    152         putshort(&p, C_IN);                     /* Class */ 
     206        putname(&p, buflen - (p - buf), q->name);       /* Name */ 
     207        CHECKLEN(4); 
     208        putshort(&p, q->type);                          /* Type */ 
     209        putshort(&p, C_IN);                             /* Class */ 
    153210 
    154211        /* Answer section */ 
    155         putshort(&p, name);                     /* Name */ 
    156         putshort(&p, q->type);                  /* Type */ 
    157         putshort(&p, C_IN);                     /* Class */ 
    158         putlong(&p, 0x3ea7d011);                /* TTL */ 
    159         putshort(&p, 5);                        /* Data length */ 
     212        CHECKLEN(12); 
     213        putshort(&p, name);                             /* Name */ 
     214        putshort(&p, q->type);                          /* Type */ 
     215        putshort(&p, C_IN);                             /* Class */ 
     216        putlong(&p, 3600);                              /* TTL */ 
     217        putshort(&p, 5);                                /* Data length */ 
    160218 
    161219        /* pointer to ns.topdomain */ 
    162220        nsname = 0xc000 | ((p - buf) & 0x3fff); 
     221        CHECKLEN(5); 
    163222        putbyte(&p, 2); 
    164223        putbyte(&p, 'n'); 
    165224        putbyte(&p, 's'); 
    166         putshort(&p, topname);                  /* Name Server */ 
     225        putshort(&p, topname);                          /* Name Server */ 
    167226 
    168227        /* Additional data (A-record of NS server) */ 
    169         putshort(&p, nsname);                   /* Name Server */ 
    170         putshort(&p, T_A);                      /* Type */ 
    171         putshort(&p, C_IN);                     /* Class */ 
    172         putlong(&p, 0x3ea7d011);                /* TTL */ 
    173         putshort(&p, 4);                        /* Data length */ 
     228        CHECKLEN(12); 
     229        putshort(&p, nsname);                           /* Name Server */ 
     230        putshort(&p, T_A);                              /* Type */ 
     231        putshort(&p, C_IN);                             /* Class */ 
     232        putlong(&p, 3600);                              /* TTL */ 
     233        putshort(&p, 4);                                /* Data length */ 
    174234 
    175235        /* ugly hack to output IP address */ 
    176236        domain = (char *) &q->destination; 
     237        CHECKLEN(4); 
    177238        putbyte(&p, *domain++); 
    178239        putbyte(&p, *domain++); 
    179240        putbyte(&p, *domain++); 
     
    183244        return len; 
    184245} 
    185246 
     247#undef CHECKLEN 
     248 
    186249unsigned short 
    187250dns_get_id(char *packet, size_t packetlen) 
    188251{ 
     
    195258        return ntohs(header->id); 
    196259} 
    197260 
     261#define CHECKLEN(x) if (packetlen - (data-packet) < (x))  return 0 
     262 
    198263int 
    199264dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen) 
    200265{ 
     
    234299 
    235300        switch (qr) { 
    236301        case QR_ANSWER: 
    237                 if(qdcount != 1 || ancount != 1) { 
     302                if(qdcount < 1 || ancount < 1) { 
     303                        /* We may get both CNAME and A, then ancount=2 */ 
    238304                        switch (header->rcode) { 
    239                         case REFUSED: 
    240                                 warnx("Got REFUSED as reply"); 
     305                        case NOERROR:   /* 0 */ 
     306                                if (header->tc) 
     307                                        warnx("Got TRUNCATION as reply: response too long for DNS path"); 
     308                                else 
     309                                        warnx("Got reply without error, but also without question and/or answer"); 
     310                                break; 
     311 
     312                        case FORMERR:   /* 1 */ 
     313                                warnx("Got FORMERR as reply: server does not understand our request"); 
    241314                                break; 
    242315 
    243                         case NOTIMP: 
    244                                 warnx("Got NOTIMP as reply"); 
     316                        case SERVFAIL:  /* 2 */ 
     317                                if (qdcount >= 1 
     318                                    && packetlen >= sizeof(HEADER) + 2 
     319                                    && (data[1] == 'r' || data[1] == 'R')) 
     320                                        warnx("Got SERVFAIL as reply on earlier fragsize autoprobe"); 
     321                                else if (qdcount >= 1 
     322                                    && packetlen >= sizeof(HEADER) + 2 
     323                                    && (data[1] < '0' || data[1] > '9') 
     324                                    && (data[1] < 'a' || data[1] > 'f') 
     325                                    && (data[1] < 'A' || data[1] > 'F') 
     326                                    && data[1] != 'p' && data[1] != 'P') 
     327                                        warnx("Got SERVFAIL as reply on earlier config setting"); 
     328                                else 
     329                                        warnx("Got SERVFAIL as reply: server failed or recursion timeout"); 
    245330                                break; 
    246331 
    247                         case NXDOMAIN: 
    248                                 warnx("Got NXDOMAIN as reply"); 
     332                        case NXDOMAIN:  /* 3 */ 
     333                                warnx("Got NXDOMAIN as reply: domain does not exist"); 
    249334                                break; 
    250335 
    251                         case SERVFAIL: 
    252                                 warnx("Got SERVFAIL as reply"); 
     336                        case NOTIMP:    /* 4 */ 
     337                                warnx("Got NOTIMP as reply: server does not support our request"); 
    253338                                break; 
    254339 
    255                         case NOERROR: 
     340                        case REFUSED:   /* 5 */ 
     341                                warnx("Got REFUSED as reply"); 
     342                                break; 
     343 
    256344                        default: 
    257                                 warnx("no query or answer in reply packet"); 
     345                                warnx("Got RCODE %u as reply", (unsigned int) header->rcode); 
    258346                                break; 
    259347                        } 
    260348                        return -1; 
     
    264352                        q->id = id; 
    265353 
    266354                readname(packet, packetlen, &data, name, sizeof(name)); 
     355                CHECKLEN(4); 
    267356                readshort(packet, &data, &type); 
    268357                readshort(packet, &data, &class); 
    269                  
     358 
     359                /* Assume that first answer is NULL/CNAME that we wanted */ 
    270360                readname(packet, packetlen, &data, name, sizeof(name)); 
     361                CHECKLEN(10); 
    271362                readshort(packet, &data, &type); 
    272363                readshort(packet, &data, &class); 
    273364                readlong(packet, &data, &ttl); 
    274365                readshort(packet, &data, &rlen); 
    275                 rv = MIN(rlen, sizeof(rdata)); 
    276                 rv = readdata(packet, &data, rdata, rv); 
    277366 
    278                 if(type == T_NULL && rv >= 2 && buf) { 
    279                         rv = MIN(rv, buflen); 
    280                         memcpy(buf, rdata, rv); 
     367                if (type == T_NULL) { 
     368                        rv = MIN(rlen, sizeof(rdata)); 
     369                        rv = readdata(packet, &data, rdata, rv); 
     370                        if (rv >= 2 && buf) { 
     371                                rv = MIN(rv, buflen); 
     372                                memcpy(buf, rdata, rv); 
     373                        } 
     374                        /* "else rv=0;" here? */ 
    281375                } 
     376                if ((type == T_CNAME || type == T_MX) && buf) { 
     377                        if (type == T_MX) 
     378                                data += 2;      /* skip preference */ 
     379                        memset(name, 0, sizeof(name)); 
     380                        readname(packet, packetlen, &data, name, sizeof(name) - 1); 
     381                        name[sizeof(name)-1] = '\0'; 
     382                        strncpy(buf, name, buflen); 
     383                        buf[buflen - 1] = '\0'; 
     384                        rv = strlen(buf); 
     385                } 
     386                if (type == T_TXT && buf) { 
     387                        rv = readtxtbin(packet, &data, rlen, rdata, sizeof(rdata)); 
     388                        if (rv >= 1) { 
     389                                rv = MIN(rv, buflen); 
     390                                memcpy(buf, rdata, rv); 
     391                        } 
     392                } 
     393                if (q != NULL) 
     394                        q->type = type; 
    282395                break; 
    283396        case QR_QUERY: 
    284                 if (qdcount != 1) { 
     397                if (qdcount < 1) { 
    285398                        warnx("no question section in name query"); 
    286399                        return -1; 
    287400                } 
    288401 
     402                memset(name, 0, sizeof(name)); 
    289403                readname(packet, packetlen, &data, name, sizeof(name) - 1); 
    290404                name[sizeof(name)-1] = '\0'; 
     405                CHECKLEN(4); 
    291406                readshort(packet, &data, &type); 
    292407                readshort(packet, &data, &class); 
    293408 
     409                if (q == NULL) { 
     410                        rv = 0; 
     411                        break; 
     412                } 
     413 
    294414                strncpy(q->name, name, sizeof(q->name)); 
    295415                q->name[sizeof(q->name) - 1] = '\0'; 
    296416                q->type = type; 
  • src/encoding.c

    old new  
    2727} 
    2828 
    2929int  
    30 inline_dotify(char *buf, size_t buflen) 
     30inline_dotify(char *buf, size_t buflen, int intv) 
    3131{ 
    3232        unsigned dots; 
    3333        unsigned pos; 
     
    3535        char *reader, *writer; 
    3636 
    3737        total = strlen(buf); 
    38         dots = total / 57; 
     38        dots = total / intv; 
    3939 
    4040        writer = buf; 
    4141        writer += total; 
     
    5454        while (dots) { 
    5555                *writer-- = *reader--; 
    5656                pos--; 
    57                 if (pos % 57 == 0) { 
     57                if (pos % intv == 0) { 
    5858                        *writer-- = '.'; 
    5959                        dots--; 
    6060                } 
  • src/encoding.h

    old new  
    2828}; 
    2929 
    3030int unpack_data(char *, size_t, char *, size_t, struct encoder *); 
    31 int inline_dotify(char *, size_t); 
     31int inline_dotify(char *, size_t, int); 
    3232int inline_undotify(char *, size_t); 
    3333 
    3434 
  • src/read.c

    old new  
    126126} 
    127127 
    128128int 
     129readtxtbin(char *packet, char **src, size_t srcremain, char *dst, size_t dstremain) 
     130{ 
     131        unsigned char *uc; 
     132        int tocopy; 
     133        int dstused = 0; 
     134 
     135        while (srcremain > 0) 
     136        { 
     137                uc = (unsigned char*) (*src); 
     138                tocopy = *uc; 
     139                (*src)++; 
     140                srcremain--; 
     141 
     142                if (tocopy > srcremain) 
     143                        return 0;       /* illegal, better have nothing */ 
     144                if (tocopy > dstremain) 
     145                        return 0;       /* doesn't fit, better have nothing */ 
     146 
     147                memcpy(dst, *src, tocopy); 
     148                dst += tocopy; 
     149                (*src) += tocopy; 
     150                srcremain -= tocopy; 
     151                dstremain -= tocopy; 
     152                dstused += tocopy; 
     153        } 
     154        return dstused; 
     155} 
     156 
     157int 
    129158putname(char **buf, size_t buflen, const char *host) 
    130159{ 
    131160        char *word; 
     
    212241        return len; 
    213242} 
    214243 
     244int 
     245puttxtbin(char **buf, size_t bufremain, char *from, size_t fromremain) 
     246{ 
     247        unsigned char uc; 
     248        unsigned char *ucp = &uc; 
     249        char *cp = (char *) ucp; 
     250        int tocopy; 
     251        int bufused = 0; 
     252 
     253        while (fromremain > 0) 
     254        { 
     255                tocopy = fromremain; 
     256                if (tocopy > 252) 
     257                        tocopy = 252;   /* allow off-by-1s in caches etc */ 
     258                if (tocopy + 1 > bufremain) 
     259                        return -1;      /* doesn't fit, better have nothing */ 
     260 
     261                uc = tocopy; 
     262                **buf = *cp; 
     263                (*buf)++; 
     264                bufremain--; 
     265                bufused++; 
     266 
     267                memcpy(*buf, from, tocopy); 
     268                (*buf) += tocopy; 
     269                from += tocopy; 
     270                bufremain -= tocopy; 
     271                fromremain -= tocopy; 
     272                bufused += tocopy; 
     273        } 
     274        return bufused; 
     275} 
  • src/read.h

    old new  
    2121int readshort(char *, char **, short *); 
    2222int readlong(char *, char **, uint32_t *); 
    2323int readdata(char *, char **, char *, size_t); 
     24int readtxtbin(char *, char **, size_t, char *, size_t); 
    2425 
    2526int putname(char **, size_t, const char *); 
    2627int putbyte(char **, unsigned char); 
    2728int putshort(char **, unsigned short); 
    2829int putlong(char **, uint32_t); 
    2930int putdata(char **, char *, size_t); 
     31int puttxtbin(char **, size_t, char *, size_t); 
    3032 
    3133#endif 
  • src/user.h

    old new  
    3131        struct packet inpacket; 
    3232        struct packet outpacket; 
    3333        struct encoder *encoder; 
     34        char downenc; 
    3435        int out_acked_seqno; 
    3536        int out_acked_fragment; 
    3637        int fragsize; 
     
    3839}; 
    3940 
    4041extern struct user users[USERS]; 
     42extern time_t now; 
    4143 
    4244int init_users(in_addr_t, int); 
    4345int users_waiting_on_reply(); 
    4446int find_user_by_ip(uint32_t); 
    4547int all_users_waiting_to_send(); 
    46 int find_available_user(); 
     48int find_available_user(int forced_userid); 
    4749void user_switch_codec(int userid, struct encoder *enc); 
    4850void user_set_conn_type(int userid, enum connection c); 
    4951 
  • src/util.c

    old new  
    2929        rv = NULL; 
    3030 
    3131        if ((fp = fopen("/etc/resolv.conf", "r")) == NULL)  
    32                 err(1, "/etc/resolve.conf"); 
     32                err(1, "/etc/resolv.conf"); 
    3333         
    3434        while (feof(fp) == 0) { 
    3535                fgets(buf, sizeof(buf), fp); 
  • src/windows.h

    old new  
    2828#define T_A DNS_TYPE_A 
    2929#define T_NS DNS_TYPE_NS 
    3030#define T_NULL DNS_TYPE_NULL 
     31#define T_CNAME DNS_TYPE_CNAME 
     32#define T_MX DNS_TYPE_MX 
     33#define T_TXT DNS_TYPE_TXT 
    3134 
    3235#define C_IN 1 
    3336 
     37#define FORMERR 1 
    3438#define SERVFAIL 2 
    3539#define NXDOMAIN 3 
    3640#define NOTIMP 4 
  • src/iodine.c

    old new  
    4848static char *__progname; 
    4949#endif 
    5050 
     51extern int forced_userid; 
     52extern void set_qtype(char *); 
     53extern void set_downenc(char *); 
     54 
    5155static void 
    5256sighandler(int sig)  
    5357{ 
     
    5963        extern char *__progname; 
    6064 
    6165        fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] " 
    62                         "[-P password] [-m maxfragsize] [-z context] [-F pidfile] " 
     66                        "[-P password] [-m maxfragsize] [-U userid] [-T type] [-O enc] [-z context] [-F pidfile] " 
    6367                        "[nameserver] topdomain\n", __progname); 
    6468        exit(2); 
    6569} 
     
    7074 
    7175        fprintf(stderr, "iodine IP over DNS tunneling client\n"); 
    7276        fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] " 
    73                         "[-P password] [-m maxfragsize] [-z context] [-F pidfile] " 
     77                        "[-P password] [-m maxfragsize] [-U userid] [-T type] [-O enc] [-z context] [-F pidfile] " 
    7478                        "[nameserver] topdomain\n", __progname); 
    7579        fprintf(stderr, "  -v to print version info and exit\n"); 
    7680        fprintf(stderr, "  -h to print this help and exit\n"); 
     
    8185        fprintf(stderr, "  -d device to set tunnel device name\n"); 
    8286        fprintf(stderr, "  -P password used for authentication (max 32 chars will be used)\n"); 
    8387        fprintf(stderr, "  -m maxfragsize, to limit size of downstream packets\n"); 
     88        fprintf(stderr, "  -U force userid (=IP address) on server, exit if unavailable\n"); 
     89        fprintf(stderr, "  -T dns type: NULL (default, fastest), TXT, CNAME, A (CNAME answer), MX\n"); 
     90        fprintf(stderr, "  -O downstream encoding (!NULL): Base32(default), Base64, or Raw (only TXT)\n"); 
    8491        fprintf(stderr, "  -z context, to apply specified SELinux context after initialization\n"); 
    8592        fprintf(stderr, "  -F pidfile to write pid to a file\n"); 
    8693        fprintf(stderr, "nameserver is the IP number of the relaying nameserver, if absent /etc/resolv.conf is used\n"); 
     
    131138#endif 
    132139        username = NULL; 
    133140        memset(password, 0, 33); 
     141        srand(time(NULL)); 
    134142        foreground = 0; 
    135143        newroot = NULL; 
    136144        context = NULL; 
     
    157165                __progname++; 
    158166#endif 
    159167 
    160         while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:F:")) != -1) { 
     168        while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:F:U:T:O:")) != -1) { 
    161169                switch(choice) { 
    162170                case 'v': 
    163171                        version(); 
     
    198206                case 'F': 
    199207                        pidfile = optarg; 
    200208                        break;     
     209                case 'U': 
     210                        forced_userid = atoi(optarg); 
     211                        if (forced_userid < 0) 
     212                                forced_userid = -1; 
     213                        break; 
     214                case 'T': 
     215                        set_qtype(optarg); 
     216#if 0 
     217                        if (!strcasecmp(optarg, "NULL")) 
     218                                do_qtype = T_NULL; 
     219                        else if (!strcasecmp(optarg, "CNAME")) 
     220                                do_qtype = T_CNAME; 
     221                        else if (!strcasecmp(optarg, "A")) 
     222                                do_qtype = T_A; 
     223                        else if (!strcasecmp(optarg, "MX")) 
     224                                do_qtype = T_MX; 
     225                        else if (!strcasecmp(optarg, "TXT")) 
     226                                do_qtype = T_TXT; 
     227#endif 
     228                        break; 
     229                case 'O':       /* not -D, is Debug in server */ 
     230                        set_downenc(optarg); 
     231#if 0 
     232                        if (!strcasecmp(optarg, "base32")) 
     233                                downenc = 'T'; 
     234                        else if (!strcasecmp(optarg, "base64")) 
     235                                downenc = 'S'; 
     236                        else if (!strcasecmp(optarg, "raw")) 
     237                                downenc = 'R'; 
     238#endif 
     239                        break; 
    201240                default: 
    202241                        usage(); 
    203242                        /* NOTREACHED */ 
     
    232271        if (nameserv_addr) { 
    233272                client_set_nameserver(nameserv_addr); 
    234273        } else { 
     274                warnx("No nameserver found - not connected to any network?\n"); 
    235275                usage(); 
    236276                /* NOTREACHED */ 
    237277        }        
  • src/client.c

    old new  
    1414 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
    1515 */ 
    1616 
     17#include <ctype.h> 
    1718#include <stdio.h> 
    1819#include <stdint.h> 
    1920#include <stdlib.h> 
     
    7576 
    7677/* My userid at the server */ 
    7778static char userid; 
     79int forced_userid = -1; 
    7880 
    7981/* DNS id for next packet */ 
    8082static uint16_t chunkid; 
    8183 
    8284/* Base32 encoder used for non-data packets */ 
    8385static struct encoder *b32; 
     86static struct encoder *b64; 
    8487 
    8588/* The encoder used for data packets 
    8689 * Defaults to Base32, can be changed after handshake */ 
    8790static struct encoder *dataenc; 
    8891 
     92static char downenc = ' '; 
     93 
     94/* set query type to send */ 
     95static unsigned short do_qtype = T_NULL; 
     96 
    8997/* My connection mode */ 
    9098static enum connection conn; 
    9199 
     
    99107        downstream_fragment = 0; 
    100108        down_ack_seqno = 0; 
    101109        down_ack_fragment = 0; 
    102         chunkid = 0; 
     110        chunkid = ((unsigned int) rand()) & 0xFFFF; 
    103111        b32 = get_base32_encoder(); 
     112        b64 = get_base64_encoder(); 
    104113        dataenc = get_base32_encoder(); 
    105         rand_seed = rand(); 
     114        rand_seed = ((unsigned int) rand()) & 0xFFFF; 
    106115        conn = CONN_DNS_NULL; 
    107116} 
    108117 
     
    157166        struct query q; 
    158167        size_t len; 
    159168 
    160         q.id = ++chunkid; 
    161         q.type = T_NULL; 
     169        chunkid += 7727; 
     170        if (chunkid == 0) 
     171                /* 0 is used as "no-query" in iodined.c */ 
     172                chunkid = 7727; 
     173 
     174        q.id = chunkid; 
     175        q.type = do_qtype; 
    162176 
    163177        len = dns_encode(packet, sizeof(packet), &q, QR_QUERY, hostname, strlen(hostname)); 
     178        if (len < 1) { 
     179                warnx("dns_encode doesn't fit"); 
     180                return; 
     181        } 
    164182 
    165183        sendto(fd, packet, len, 0, (struct sockaddr*)&nameserv, sizeof(nameserv)); 
    166184} 
     
    208226        encsize = encoder->encode(buf, &space, data, datalen); 
    209227 
    210228        if (!encoder->places_dots()) 
    211                 inline_dotify(buf, buflen); 
     229                inline_dotify(buf, buflen, 57); 
    212230 
     231        /* Add dot (if it wasn't there already) and topdomain */ 
    213232        b = buf; 
    214233        b += strlen(buf); 
    215234 
     
    241260static void 
    242261send_chunk(int fd) 
    243262{ 
    244         char hex[] = "0123456789ABCDEF"; 
     263        char hex[] = "0123456789abcdef"; 
    245264        char buf[4096]; 
    246265        int avail; 
    247266        int code; 
     
    295314                 
    296315                rand_seed++; 
    297316 
    298                 send_packet(fd, 'P', data, sizeof(data)); 
     317                send_packet(fd, 'p', data, sizeof(data)); 
    299318        } else { 
    300319                send_raw(fd, NULL, 0, userid, RAW_HDR_CMD_PING); 
    301320        } 
     
    322341 
    323342                rv = dns_decode(buf, buflen, &q, QR_ANSWER, data, r); 
    324343 
     344                if ((q.type == T_CNAME || q.type == T_MX || q.type == T_TXT) 
     345                    && rv >= 1) 
     346                /* CNAME an also be returned from an A (or MX) question */ 
     347                { 
     348                        size_t space; 
     349 
     350                        /* 
     351                         * buf is a hostname or txt stream that we still need to 
     352                         * decode to binary 
     353                         *  
     354                         * also update rv with the number of valid bytes 
     355                         *  
     356                         * data is unused here, and will certainly hold the smaller binary 
     357                         */ 
     358 
     359                        switch (buf[0]) { 
     360                        case 'h': /* Hostname with base32 */ 
     361                        case 'H': 
     362                                if (rv < 5) { 
     363                                        /* 1 byte H, 3 bytes ".xy", >=1 byte data */ 
     364                                        rv = 0; 
     365                                        break; 
     366                                } 
     367 
     368                                rv -= 3;        /* rv=strlen, strip ".xy" */ 
     369                                rv = unpack_data (data, sizeof(data), buf + 1, rv - 1, b32); 
     370                                /* this also does undotify */ 
     371 
     372                                rv = MIN(rv, buflen); 
     373                                memcpy(buf, data, rv); 
     374                                break; 
     375                        case 'i': /* Hostname++ with base64 */ 
     376                        case 'I': 
     377                                if (rv < 5) { 
     378                                        /* 1 byte H, 3 bytes ".xy", >=1 byte data */ 
     379                                        rv = 0; 
     380                                        break; 
     381                                } 
     382 
     383                                rv -= 3;        /* rv=strlen, strip ".xy" */ 
     384                                rv = unpack_data (data, sizeof(data), buf + 1, rv - 1, b64); 
     385                                /* this also does undotify */ 
     386 
     387                                rv = MIN(rv, buflen); 
     388                                memcpy(buf, data, rv); 
     389                                break; 
     390                        case 't': /* plain base32(Thirty-two) from TXT */ 
     391                        case 'T': 
     392                                if (rv < 2) { 
     393                                        rv = 0; 
     394                                        break; 
     395                                } 
     396 
     397                                space = sizeof(data); 
     398                                rv = b32->decode (data, &space, buf + 1, rv - 1); 
     399                                rv = MIN(rv, buflen); 
     400                                memcpy(buf, data, rv); 
     401                                break; 
     402                        case 's': /* plain base64(Sixty-four) from TXT */ 
     403                        case 'S': 
     404                                if (rv < 2) { 
     405                                        rv = 0; 
     406                                        break; 
     407                                } 
     408 
     409                                space = sizeof(data); 
     410                                rv = b64->decode (data, &space, buf + 1, rv - 1); 
     411                                rv = MIN(rv, buflen); 
     412                                memcpy(buf, data, rv); 
     413                                break; 
     414                        case 'r': /* Raw binary from TXT */ 
     415                        case 'R': 
     416                                rv--;                   /* rv>=1 already checked */ 
     417                                memmove(buf, buf+1, rv); 
     418                                break; 
     419                        default: 
     420                                warnx("Received unsupported encoding"); 
     421                                rv = 0; 
     422                                break; 
     423                        } 
     424                } 
     425 
    325426                /* decode the data header, update seqno and frag before next request */ 
    326427                if (rv >= 2) { 
    327428                        downstream_seqno = (buf[1] >> 5) & 7; 
     
    345446                                                downstream_seqno != down_ack_seqno || 
    346447                                                downstream_fragment != down_ack_fragment 
    347448                                                )) { 
    348                                                  
     449 
    349450                                                send_ping(dns_fd); 
    350451                                        } 
    351452                                } else { 
     
    521622         
    522623        rand_seed++; 
    523624 
    524         send_packet(fd, 'L', data, sizeof(data)); 
     625        send_packet(fd, 'l', data, sizeof(data)); 
    525626} 
    526627 
    527628static void 
     
    530631        char probedata[256]; 
    531632        char buf[4096]; 
    532633 
    533         /* build a large query domain which is random and maximum size */ 
    534         memset(probedata, MIN(1, rand_seed & 0xff), sizeof(probedata)); 
    535         probedata[1] = MIN(1, (rand_seed >> 8) & 0xff); 
     634        /* 
     635         * build a large query domain which is random and maximum size, 
     636         * will also take up maximal space in the return packet 
     637         */ 
     638        memset(probedata, MAX(1, rand_seed & 0xff), sizeof(probedata)); 
     639        probedata[1] = MAX(1, (rand_seed >> 8) & 0xff); 
    536640        rand_seed++; 
    537641        build_hostname(buf + 4, sizeof(buf) - 4, probedata, sizeof(probedata), topdomain, dataenc); 
    538642 
     
    559663         
    560664        rand_seed++; 
    561665 
    562         send_packet(fd, 'N', data, sizeof(data)); 
     666        send_packet(fd, 'n', data, sizeof(data)); 
    563667} 
    564668 
    565669static void  
    566670send_version(int fd, uint32_t version) 
    567671{ 
    568         char data[6]; 
     672        char data[7]; 
     673        int datalen; 
    569674 
    570675        data[0] = (version >> 24) & 0xff; 
    571676        data[1] = (version >> 16) & 0xff; 
    572677        data[2] = (version >> 8) & 0xff; 
    573678        data[3] = (version >> 0) & 0xff; 
    574679 
    575         data[4] = (rand_seed >> 8) & 0xff; 
    576         data[5] = (rand_seed >> 0) & 0xff; 
     680        if (forced_userid < 0) { 
     681                data[4] = (rand_seed >> 8) & 0xff; 
     682                data[5] = (rand_seed >> 0) & 0xff; 
     683                datalen = 6; 
     684        } else { 
     685                data[4] = (forced_userid + 1) & 0xff; 
     686                data[5] = (rand_seed >> 8) & 0xff; 
     687                data[6] = (rand_seed >> 0) & 0xff; 
     688                datalen = 7; 
     689        } 
    577690         
    578691        rand_seed++; 
    579692 
    580         send_packet(fd, 'V', data, sizeof(data)); 
     693        send_packet(fd, 'V', data, datalen); 
    581694} 
    582695 
    583696static void 
     
    619732static void 
    620733send_codec_switch(int fd, int userid, int bits) 
    621734{ 
    622         char buf[512] = "S_____."; 
     735        char buf[512] = "s_____."; 
    623736        buf[1] = b32_5to8(userid); 
    624737        buf[2] = b32_5to8(bits); 
    625738         
     
    631744        strncat(buf, topdomain, 512 - strlen(buf)); 
    632745        send_query(fd, buf); 
    633746} 
     747 
     748 
     749static void 
     750send_downenc_switch(int fd, int userid) 
     751{ 
     752        char buf[512] = "o_____."; 
     753        buf[1] = b32_5to8(userid); 
     754        buf[2] = tolower(downenc); 
     755 
     756        buf[3] = b32_5to8((rand_seed >> 10) & 0x1f); 
     757        buf[4] = b32_5to8((rand_seed >> 5) & 0x1f); 
     758        buf[5] = b32_5to8((rand_seed ) & 0x1f); 
     759        rand_seed++; 
     760 
     761        strncat(buf, topdomain, 512 - strlen(buf)); 
     762        send_query(fd, buf); 
     763} 
    634764         
    635765static int 
    636766handshake_version(int dns_fd, int *seed) 
     
    675805                                        *seed = payload; 
    676806                                        userid = in[8]; 
    677807 
     808                                        if (forced_userid >= 0 && 
     809                                            (int) userid != forced_userid) { 
     810                                                warnx("Got userid %d instead of requested %d, probably old server version. Try again immediately.", (int) userid, forced_userid); 
     811                                                return 1; 
     812                                        } 
     813 
    678814                                        fprintf(stderr, "Version ok, both using protocol v 0x%08x. You are user #%d\n", VERSION, userid); 
    679815                                        return 0; 
    680816                                } else if (strncmp("VNAK", in, 4) == 0) { 
     
    682818                                                        VERSION, payload); 
    683819                                        return 1; 
    684820                                } else if (strncmp("VFUL", in, 4) == 0) { 
    685                                         warnx("Server full, all %d slots are taken. Try again later", payload); 
     821                                        if (forced_userid >= 0) 
     822                                                warnx("Forced userid %d not available. Try again later.", forced_userid); 
     823                                        else 
     824                                                warnx("Server full, all %d slots are taken. Try again later", payload); 
    686825                                        return 1; 
    687826                                } 
    688827                        } else  
     
    691830                 
    692831                fprintf(stderr, "Retrying version check...\n"); 
    693832        } 
    694         warnx("couldn't connect to server"); 
     833        warnx("couldn't connect to server (maybe other -T options will work)"); 
    695834        return 1; 
    696835} 
    697836 
     
    9241063        int read; 
    9251064 
    9261065        dataenc = get_base64_encoder(); 
    927         fprintf(stderr, "Switching to %s codec\n", dataenc->name); 
     1066        fprintf(stderr, "Switching upstream to %s codec\n", dataenc->name); 
    9281067        /* Send to server that this user will use base64 from now on */ 
    9291068        for (i=0; running && i<5 ;i++) { 
    9301069                int bits; 
     
    9551094                                        goto codec_revert; 
    9561095                                } 
    9571096                                in[read] = 0; /* zero terminate */ 
    958                                 fprintf(stderr, "Server switched to codec %s\n", in); 
     1097                                fprintf(stderr, "Server switched upstream to codec %s\n", in); 
    9591098                                return; 
    9601099                        } 
    9611100                } 
     
    9681107        dataenc = get_base32_encoder(); 
    9691108} 
    9701109 
     1110static void 
     1111handshake_switch_downenc(int dns_fd) 
     1112{ 
     1113        struct timeval tv; 
     1114        char in[4096]; 
     1115        fd_set fds; 
     1116        int i; 
     1117        int r; 
     1118        int read; 
     1119        char *dname; 
     1120 
     1121        dname = "Base32"; 
     1122        if (downenc == 'S') 
     1123                dname = "Base64"; 
     1124        else if (downenc == 'R') 
     1125                dname = "Raw"; 
     1126 
     1127        fprintf(stderr, "Switching downstream to codec %s\n", dname); 
     1128        for (i=0; running && i<5 ;i++) { 
     1129                tv.tv_sec = i + 1; 
     1130                tv.tv_usec = 0; 
     1131 
     1132                send_downenc_switch(dns_fd, userid); 
     1133 
     1134                FD_ZERO(&fds); 
     1135                FD_SET(dns_fd, &fds); 
     1136 
     1137                r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
     1138 
     1139                if(r > 0) { 
     1140                        read = read_dns(dns_fd, 0, in, sizeof(in)); 
     1141 
     1142                        if (read > 0) { 
     1143                                if (strncmp("BADLEN", in, 6) == 0) { 
     1144                                        fprintf(stderr, "Server got bad message length. "); 
     1145                                        goto codec_revert; 
     1146                                } else if (strncmp("BADIP", in, 5) == 0) { 
     1147                                        fprintf(stderr, "Server rejected sender IP address. "); 
     1148                                        goto codec_revert; 
     1149                                } else if (strncmp("BADCODEC", in, 8) == 0) { 
     1150                                        fprintf(stderr, "Server rejected the selected codec. "); 
     1151                                        goto codec_revert; 
     1152                                } 
     1153                                in[read] = 0; /* zero terminate */ 
     1154                                fprintf(stderr, "Server switched downstream to codec %s\n", in); 
     1155                                return; 
     1156                        } 
     1157                } 
     1158                fprintf(stderr, "Retrying codec switch...\n"); 
     1159        } 
     1160        fprintf(stderr, "No reply from server on codec switch. "); 
     1161 
     1162codec_revert:  
     1163        fprintf(stderr, "Falling back to base32\n"); 
     1164} 
     1165 
     1166 
     1167static int 
     1168fragsize_check(char *in, int read, int proposed_fragsize, int *max_fragsize) 
     1169/* Returns: 0: keep checking, 1: break loop (either okay or definitely wrong) */ 
     1170{ 
     1171        int acked_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff); 
     1172        static int nocheck_warned = 0; 
     1173 
     1174        if (read >= 5 && strncmp("BADIP", in, 5) == 0) { 
     1175                fprintf(stderr, "got BADIP (Try iodined -c)..\n"); 
     1176                fflush(stderr); 
     1177                return 0;               /* maybe temporary error */ 
     1178        } 
     1179 
     1180        if (acked_fragsize != proposed_fragsize) { 
     1181                /* 
     1182                 * got ack for wrong fragsize, maybe late response for 
     1183                 * earlier query, or ack corrupted 
     1184                 */ 
     1185                return 0; 
     1186        } 
     1187 
     1188        if (read != proposed_fragsize) { 
     1189                /* 
     1190                 * correctly acked fragsize but read too little (or too 
     1191                 * much): this fragsize is definitely not reliable 
     1192                 */ 
     1193                return 1; 
     1194        } 
     1195 
     1196        /* here: read == proposed_fragsize == acked_fragsize */ 
     1197 
     1198        /* test: */ 
     1199        /* in[123] = 123; */ 
     1200 
     1201        /* Check for corruption */ 
     1202        if ((in[2] & 0xff) == 107) { 
     1203                int okay = 1; 
     1204                int i; 
     1205                unsigned int v = in[3] & 0xff; 
     1206 
     1207                for (i = 3; i < read; i++, v += 107) 
     1208                        if ((in[i] & 0xff) != (v & 0xff)) { 
     1209                                okay = 0; 
     1210                                break; 
     1211                        } 
     1212 
     1213                if (okay) { 
     1214                        fprintf(stderr, "%d ok.. ", acked_fragsize); 
     1215                        fflush(stderr); 
     1216                        *max_fragsize = acked_fragsize; 
     1217                        return 1; 
     1218                } else { 
     1219                        if (downenc != ' ' && downenc != 'T') 
     1220                                fprintf(stderr, "%d corrupted at %d.. (Try -O Base32)\n", acked_fragsize, i); 
     1221                        else 
     1222                                fprintf(stderr, "%d corrupted at %d.. ", acked_fragsize, i); 
     1223                                fflush(stderr); 
     1224                        return 1; 
     1225                } 
     1226        }               /* always returns */ 
     1227 
     1228        /* here when uncheckable, so assume correct */ 
     1229 
     1230        if (read >= 3 && nocheck_warned == 0) { 
     1231                fprintf(stderr, "(Old server version, cannot check for corruption)\n"); 
     1232                fflush(stderr); 
     1233                nocheck_warned = 1; 
     1234        } 
     1235        fprintf(stderr, "%d ok.. ", acked_fragsize); 
     1236        fflush(stderr); 
     1237        *max_fragsize = acked_fragsize; 
     1238        return 1; 
     1239} 
     1240 
     1241 
    9711242static int 
    9721243handshake_autoprobe_fragsize(int dns_fd) 
    9731244{ 
     
    9791250        int read; 
    9801251        int proposed_fragsize = 768; 
    9811252        int range = 768; 
    982         int max_fragsize = 0; 
     1253        int max_fragsize; 
    9831254 
    9841255        max_fragsize = 0; 
    9851256        fprintf(stderr, "Autoprobing max downstream fragment size... (skip with -m fragsize)\n");  
    986         while (running && range > 0 && (range >= 8 || !max_fragsize)) { 
     1257        while (running && range > 0 && (range >= 8 || max_fragsize < 300)) { 
     1258                /* stop the slow probing early when we have enough bytes anyway */ 
    9871259                for (i=0; running && i<3 ;i++) { 
    9881260                        tv.tv_sec = 1; 
    9891261                        tv.tv_usec = 0; 
     
    9941266 
    9951267                        r = select(dns_fd + 1, &fds, NULL, NULL, &tv); 
    9961268 
    997                         if(r > 0) { 
     1269                        if(r >= 2) { 
    9981270                                read = read_dns(dns_fd, 0, in, sizeof(in)); 
    9991271                                 
    10001272                                if (read > 0) { 
    10011273                                        /* We got a reply */ 
    1002                                         int acked_fragsize = ((in[0] & 0xff) << 8) | (in[1] & 0xff); 
    1003                                         if (acked_fragsize == proposed_fragsize) { 
    1004                                                 if (read == proposed_fragsize) { 
    1005                                                         fprintf(stderr, "%d ok.. ", acked_fragsize); 
    1006                                                         fflush(stderr); 
    1007                                                         max_fragsize = acked_fragsize; 
    1008                                                 } 
    1009                                         } 
    1010                                         if (strncmp("BADIP", in, 5) == 0) { 
    1011                                                 fprintf(stderr, "got BADIP.. "); 
    1012                                                 fflush(stderr); 
    1013                                         } 
    1014                                         break; 
     1274                                        if (fragsize_check(in, read, proposed_fragsize, &max_fragsize) == 1) 
     1275                                                break; 
    10151276                                } 
    10161277                        } 
    10171278                        fprintf(stderr, "."); 
     
    10301291        } 
    10311292        if (!running) { 
    10321293                fprintf(stderr, "\n"); 
    1033                 warnx("stopped while autodetecting fragment size (Try probing manually with -m)"); 
     1294                warnx("stopped while autodetecting fragment size (Try setting manually with -m)"); 
    10341295                return 0; 
    10351296        } 
    1036         if (range == 0) { 
     1297        if (max_fragsize <= 2) { 
    10371298                /* Tried all the way down to 2 and found no good size */ 
    10381299                fprintf(stderr, "\n"); 
    1039                 warnx("found no accepted fragment size. (Try probing manually with -m)"); 
     1300                warnx("found no accepted fragment size. (Try forcing with -m, or try other -T or -O options)"); 
    10401301                return 0; 
    10411302        } 
    1042         fprintf(stderr, "will use %d\n", max_fragsize); 
    1043         return max_fragsize; 
     1303        /* data header adds 2 bytes */ 
     1304        fprintf(stderr, "will use %d-2=%d\n", max_fragsize, max_fragsize - 2); 
     1305 
     1306        if (do_qtype != T_NULL && downenc == ' ') 
     1307                fprintf(stderr, "(Maybe other -O options will increase throughput)\n"); 
     1308 
     1309        return max_fragsize - 2; 
    10441310} 
    10451311 
    10461312static void 
     
    11171383                        handshake_switch_codec(dns_fd); 
    11181384                } 
    11191385 
     1386                if (downenc != ' ') { 
     1387                        handshake_switch_downenc(dns_fd); 
     1388                } 
     1389 
    11201390                if (autodetect_frag_size) { 
    11211391                        fragsize = handshake_autoprobe_fragsize(dns_fd); 
    11221392                        if (!fragsize) { 
     
    11301400        return 0; 
    11311401} 
    11321402 
     1403void 
     1404set_qtype(char *qtype) 
     1405{ 
     1406        if (!strcasecmp(qtype, "NULL")) 
     1407                do_qtype = T_NULL; 
     1408        else if (!strcasecmp(qtype, "CNAME")) 
     1409                do_qtype = T_CNAME; 
     1410        else if (!strcasecmp(qtype, "A")) 
     1411                do_qtype = T_A; 
     1412        else if (!strcasecmp(qtype, "MX")) 
     1413                do_qtype = T_MX; 
     1414        else if (!strcasecmp(qtype, "TXT")) 
     1415                do_qtype = T_TXT; 
     1416} 
     1417 
     1418void 
     1419set_downenc(char *encoding) 
     1420{ 
     1421        if (!strcasecmp(encoding, "base32")) 
     1422                downenc = 'T'; 
     1423        else if (!strcasecmp(encoding, "base64")) 
     1424                downenc = 'S'; 
     1425        else if (!strcasecmp(encoding, "raw")) 
     1426                downenc = 'R'; 
     1427} 
  • src/iodined.c

    old new  
    6969static char *topdomain; 
    7070static char password[33]; 
    7171static struct encoder *b32; 
     72static struct encoder *b64; 
    7273static int created_users; 
    7374 
    7475static int check_ip; 
     
    8687#endif 
    8788 
    8889static int read_dns(int, int, struct query *); 
    89 static void write_dns(int, struct query *, char *, int); 
     90static void write_dns(int, struct query *, char *, int, char); 
    9091static void handle_full_packet(int, int); 
    9192 
    9293static void 
     
    120121        if (userid < 0 || userid >= created_users ) { 
    121122                return 1;  
    122123        } 
    123         if (!users[userid].active) { 
     124        if (!users[userid].active || users[userid].disabled || 
     125            users[userid].last_pkt + 60 < now) { 
    124126                return 1; 
    125127        } 
    126128        if (users[userid].last_pkt + 60 < time(NULL)) { 
     
    226228        out[7] = ((payload) & 0xff); 
    227229        out[8] = userid & 0xff; 
    228230 
    229         write_dns(fd, q, out, sizeof(out)); 
     231        write_dns(fd, q, out, sizeof(out), users[userid].downenc); 
    230232} 
    231233 
    232234static void 
     
    271273                        users[userid].outpacket.seqno & 7, users[userid].outpacket.fragment & 15,  
    272274                        last, users[userid].outpacket.offset, datalen, users[userid].outpacket.len, userid); 
    273275        } 
    274         write_dns(dns_fd, &users[userid].q, pkt, datalen + 2); 
     276        write_dns(dns_fd, &users[userid].q, pkt, datalen + 2, users[userid].downenc); 
    275277        users[userid].q.id = 0; 
    276278 
    277279        if (users[userid].outpacket.len > 0 &&  
     
    339341        if(in[0] == 'V' || in[0] == 'v') { 
    340342                int version = 0; 
    341343 
     344                int forced_userid = -1; 
    342345                read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), domain_len - 1, b32); 
    343346                /* Version greeting, compare and send ack/nak */ 
    344347                if (read > 4) {  
     
    348351                                           ((unpacked[2] & 0xff) << 8) | 
    349352                                           ((unpacked[3] & 0xff))); 
    350353                } 
     354                if (read >= 7) { 
     355                        /* Received V + 32bits version + 8bits userid + 16bits CMC */ 
     356                        forced_userid = unpacked[4]; 
     357                        forced_userid--; 
     358                } 
    351359 
    352360                if (version == VERSION) { 
    353                         userid = find_available_user(); 
     361                        userid = find_available_user(forced_userid); 
    354362                        if (userid >= 0) { 
    355363                                struct sockaddr_in *tempin; 
    356364 
     
    361369                                 
    362370                                memcpy(&(users[userid].q), q, sizeof(struct query)); 
    363371                                users[userid].encoder = get_base32_encoder(); 
     372                                users[userid].downenc = 'T'; 
    364373                                send_version_response(dns_fd, VERSION_ACK, users[userid].seed, userid, q); 
    365374                                syslog(LOG_INFO, "accepted version for user #%d from %s", 
    366375                                        userid, inet_ntoa(tempin->sin_addr)); 
    367376                                users[userid].q.id = 0; 
     377                                users[userid].outpacket.len = 0; 
     378                                users[userid].outpacket.offset = 0; 
     379                                users[userid].outpacket.sentlen = 0; 
     380                                users[userid].outpacket.seqno = 0; 
     381                                users[userid].outpacket.fragment = 0; 
     382                                users[userid].inpacket.len = 0; 
     383                                users[userid].inpacket.offset = 0; 
     384                                users[userid].inpacket.seqno = 0; 
     385                                users[userid].inpacket.fragment = 0; 
     386                                users[userid].fragsize = 100; /* very safe */ 
    368387                        } else { 
    369388                                /* No space for another user */ 
    370389                                send_version_response(dns_fd, VERSION_FULL, created_users, 0, q); 
    371                                 syslog(LOG_INFO, "dropped user from %s, server full",  
    372                                         inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr)); 
     390                                if (forced_userid != -1) 
     391                                        syslog(LOG_INFO, "dropped user from %s, forced userid %d not available", 
     392                                                inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr), forced_userid); 
     393                                else 
     394                                        syslog(LOG_INFO, "dropped user from %s, server full", 
     395                                                inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr)); 
    373396                        } 
    374397                } else { 
    375398                        send_version_response(dns_fd, VERSION_NACK, VERSION, 0, q); 
     
    383406                userid = unpacked[0]; 
    384407 
    385408                if (check_user_and_ip(userid, q) != 0) { 
    386                         write_dns(dns_fd, q, "BADIP", 5); 
     409                        write_dns(dns_fd, q, "BADIP", 5, 'T'); 
    387410                        syslog(LOG_WARNING, "dropped login request from user #%d from unexpected source %s", 
    388411                                userid, inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr)); 
    389412                        return; 
    390413                } else { 
    391                         users[userid].last_pkt = time(NULL); 
     414                        users[userid].last_pkt = now; 
    392415                        login_calculate(logindata, 16, password, users[userid].seed); 
    393416 
    394417                        if (read >= 18 && (memcmp(logindata, unpacked+1, 16) == 0)) { 
     
    402425                                read = snprintf(out, sizeof(out), "%s-%s-%d-%d",  
    403426                                                tmp[0], tmp[1], my_mtu, netmask); 
    404427 
    405                                 write_dns(dns_fd, q, out, read); 
     428                                write_dns(dns_fd, q, out, read, users[userid].downenc); 
    406429                                q->id = 0; 
    407430                                syslog(LOG_NOTICE, "accepted password from user #%d, given IP %s", userid, tmp[1]); 
    408431 
    409432                                free(tmp[1]); 
    410433                                free(tmp[0]); 
    411434                        } else { 
    412                                 write_dns(dns_fd, q, "LNAK", 4); 
     435                                write_dns(dns_fd, q, "LNAK", 4, 'T'); 
    413436                                syslog(LOG_WARNING, "rejected login request from user #%d from %s, bad password", 
    414437                                        userid, inet_ntoa(((struct sockaddr_in *) &q->from)->sin_addr)); 
    415438                        } 
     
    423446                 
    424447                userid = b32_8to5(in[1]); 
    425448                if (check_user_and_ip(userid, q) != 0) { 
    426                         write_dns(dns_fd, q, "BADIP", 5); 
     449                        write_dns(dns_fd, q, "BADIP", 5, 'T'); 
    427450                        return; /* illegal id */ 
    428451                } 
    429452 
     
    441464                reply[2] = (addr >> 16) & 0xFF; 
    442465                reply[3] = (addr >>  8) & 0xFF; 
    443466                reply[4] = (addr >>  0) & 0xFF; 
    444                 write_dns(dns_fd, q, reply, sizeof(reply)); 
     467                write_dns(dns_fd, q, reply, sizeof(reply), 'T'); 
    445468        } else if(in[0] == 'Z' || in[0] == 'z') { 
    446469                /* Check for case conservation and chars not allowed according to RFC */ 
    447470 
    448471                /* Reply with received hostname as data */ 
    449                 write_dns(dns_fd, q, in, domain_len); 
     472                /* No userid here, reply with lowest-grade downenc */ 
     473                write_dns(dns_fd, q, in, domain_len, 'T'); 
    450474                return; 
    451475        } else if(in[0] == 'S' || in[0] == 's') { 
    452476                int codec; 
    453477                struct encoder *enc; 
    454478                if (domain_len < 3) { /* len at least 3, example: "S15" */ 
    455                         write_dns(dns_fd, q, "BADLEN", 6); 
     479                        write_dns(dns_fd, q, "BADLEN", 6, 'T'); 
    456480                        return; 
    457481                } 
    458482 
    459483                userid = b32_8to5(in[1]); 
    460484                 
    461485                if (check_user_and_ip(userid, q) != 0) { 
    462                         write_dns(dns_fd, q, "BADIP", 5); 
     486                        write_dns(dns_fd, q, "BADIP", 5, 'T'); 
    463487                        return; /* illegal id */ 
    464488                } 
    465489                 
     
    469493                case 5: /* 5 bits per byte = base32 */ 
    470494                        enc = get_base32_encoder(); 
    471495                        user_switch_codec(userid, enc); 
    472                         write_dns(dns_fd, q, enc->name, strlen(enc->name)); 
     496                        write_dns(dns_fd, q, enc->name, strlen(enc->name), users[userid].downenc); 
    473497                        break; 
    474498                case 6: /* 6 bits per byte = base64 */ 
    475499                        enc = get_base64_encoder(); 
    476500                        user_switch_codec(userid, enc); 
    477                         write_dns(dns_fd, q, enc->name, strlen(enc->name)); 
     501                        write_dns(dns_fd, q, enc->name, strlen(enc->name), users[userid].downenc); 
     502                        break; 
     503                default: 
     504                        write_dns(dns_fd, q, "BADCODEC", 8, users[userid].downenc); 
     505                        break; 
     506                } 
     507                return; 
     508        } else if(in[0] == 'O' || in[0] == 'o') { 
     509                if (domain_len != 4) { /* len = 4, example: "O1T." */ 
     510                        write_dns(dns_fd, q, "BADLEN", 6, 'T'); 
     511                        return; 
     512                } 
     513 
     514                userid = b32_8to5(in[1]); 
     515 
     516                if (check_user_and_ip(userid, q) != 0) { 
     517                        write_dns(dns_fd, q, "BADIP", 5, 'T'); 
     518                        return; /* illegal id */ 
     519                } 
     520 
     521                switch (in[2]) { 
     522                case 'T': 
     523                case 't': 
     524                        users[userid].downenc = 'T'; 
     525                        write_dns(dns_fd, q, "Base32", 6, users[userid].downenc); 
     526                        break; 
     527                case 'S': 
     528                case 's': 
     529                        users[userid].downenc = 'S'; 
     530                        write_dns(dns_fd, q, "Base64", 6, users[userid].downenc); 
     531                        break; 
     532                case 'R': 
     533                case 'r': 
     534                        users[userid].downenc = 'R'; 
     535                        write_dns(dns_fd, q, "Raw", 3, users[userid].downenc); 
    478536                        break; 
    479537                default: 
    480                         write_dns(dns_fd, q, "BADCODEC", 8); 
     538                        write_dns(dns_fd, q, "BADCODEC", 8, users[userid].downenc); 
    481539                        break; 
    482540                } 
    483541                return; 
     
    487545                /* Downstream fragsize probe packet */ 
    488546                userid = (b32_8to5(in[1]) >> 1) & 15; 
    489547                if (check_user_and_ip(userid, q) != 0) { 
    490                         write_dns(dns_fd, q, "BADIP", 5); 
     548                        write_dns(dns_fd, q, "BADIP", 5, 'T'); 
    491549                        return; /* illegal id */ 
    492550                } 
    493551                                 
    494552                req_frag_size = ((b32_8to5(in[1]) & 1) << 10) | ((b32_8to5(in[2]) & 31) << 5) | (b32_8to5(in[3]) & 31); 
    495553                if (req_frag_size < 2 || req_frag_size > 2047) {         
    496                         write_dns(dns_fd, q, "BADFRAG", 7); 
     554                        write_dns(dns_fd, q, "BADFRAG", 7, users[userid].downenc); 
    497555                } else { 
    498556                        char buf[2048]; 
     557                        int i; 
     558                        unsigned int v = (unsigned int) rand(); 
    499559 
    500560                        memset(buf, 0, sizeof(buf)); 
    501561                        buf[0] = (req_frag_size >> 8) & 0xff; 
    502562                        buf[1] = req_frag_size & 0xff; 
    503                         write_dns(dns_fd, q, buf, req_frag_size); 
     563                        /* make checkable pseudo-random sequence */ 
     564                        buf[2] = 107; 
     565                        for (i = 3; i < 2048; i++, v += 107) 
     566                                buf[i] = (char) (v & 0xff); 
     567                        write_dns(dns_fd, q, buf, req_frag_size, users[userid].downenc); 
    504568                } 
    505569                return; 
    506570        } else if(in[0] == 'N' || in[0] == 'n') { 
     
    510574                /* Downstream fragsize packet */ 
    511575                userid = unpacked[0]; 
    512576                if (check_user_and_ip(userid, q) != 0) { 
    513                         write_dns(dns_fd, q, "BADIP", 5); 
     577                        write_dns(dns_fd, q, "BADIP", 5, 'T'); 
    514578                        return; /* illegal id */ 
    515579                } 
    516580                                 
    517581                max_frag_size = ((unpacked[1] & 0xff) << 8) | (unpacked[2] & 0xff); 
    518582                if (max_frag_size < 2) {         
    519                         write_dns(dns_fd, q, "BADFRAG", 7); 
     583                        write_dns(dns_fd, q, "BADFRAG", 7, users[userid].downenc); 
    520584                } else { 
    521585                        users[userid].fragsize = max_frag_size; 
    522                         write_dns(dns_fd, q, &unpacked[1], 2); 
     586                        write_dns(dns_fd, q, &unpacked[1], 2, users[userid].downenc); 
    523587                } 
    524588                return; 
    525589        } else if(in[0] == 'P' || in[0] == 'p') { 
     
    530594                /* Ping packet, store userid */ 
    531595                userid = unpacked[0]; 
    532596                if (check_user_and_ip(userid, q) != 0) { 
    533                         write_dns(dns_fd, q, "BADIP", 5); 
     597                        write_dns(dns_fd, q, "BADIP", 5, 'T'); 
    534598                        return; /* illegal id */ 
    535599                } 
    536600                                 
     
    546610                dn_seq = unpacked[1] >> 4; 
    547611                dn_frag = unpacked[1] & 15; 
    548612                memcpy(&(users[userid].q), q, sizeof(struct query)); 
    549                 users[userid].last_pkt = time(NULL); 
     613                users[userid].last_pkt = now; 
    550614 
    551615                /* Update seqno and maybe send immediate response packet */ 
    552616                update_downstream_seqno(dns_fd, userid, dn_seq, dn_frag); 
     
    565629                userid = code; 
    566630                /* Check user and sending ip number */ 
    567631                if (check_user_and_ip(userid, q) != 0) { 
    568                         write_dns(dns_fd, q, "BADIP", 5); 
     632                        write_dns(dns_fd, q, "BADIP", 5, 'T'); 
    569633                } else { 
    570634                        /* Decode data header */ 
    571635                        int up_seq = (b32_8to5(in[1]) >> 2) & 7; 
     
    580644                        } 
    581645 
    582646                        /* Update query and time info for user */ 
    583                         users[userid].last_pkt = time(NULL); 
     647                        users[userid].last_pkt = now; 
    584648                        memcpy(&(users[userid].q), q, sizeof(struct query)); 
    585649 
    586650                        if (up_seq == users[userid].inpacket.seqno &&  
     
    638702        } 
    639703 
    640704        len = dns_encode_ns_response(buf, sizeof(buf), q, topdomain); 
     705        if (len < 1) { 
     706                warnx("dns_encode_ns_response doesn't fit"); 
     707                return; 
     708        } 
    641709         
    642710        if (debug >= 2) { 
    643711                struct sockaddr_in *tempin; 
     
    660728        in_addr_t newaddr; 
    661729 
    662730        len = dns_encode(buf, sizeof(buf), q, QR_QUERY, q->name, strlen(q->name)); 
     731        if (len < 1) { 
     732                warnx("dns_encode doesn't fit"); 
     733                return; 
     734        } 
    663735 
    664736        /* Store sockaddr for q->id */ 
    665737        memcpy(&(fwq.addr), &(q->from), q->fromlen); 
     
    756828         
    757829        if (inside_topdomain) { 
    758830                /* This is a query we can handle */ 
     831 
    759832                switch (q.type) { 
    760833                case T_NULL: 
     834                case T_CNAME: 
     835                case T_A: 
     836                case T_MX: 
     837                case T_TXT: 
     838                        /* encoding is "transparent" here */ 
    761839                        handle_null_request(tun_fd, dns_fd, &q, domain_len); 
    762840                        break; 
    763841                case T_NS: 
     
    782860        fd_set fds; 
    783861        int i; 
    784862 
     863        now = time(NULL); 
     864 
    785865        while (running) { 
    786866                int maxfd; 
    787867                if (users_waiting_on_reply()) { 
     
    810890                } 
    811891 
    812892                i = select(maxfd + 1, &fds, NULL, NULL, &tv); 
     893 
     894                now = time(NULL); 
    813895                 
    814896                if(i < 0) { 
    815897                        if (running)  
     
    10451127} 
    10461128 
    10471129static void 
    1048 write_dns(int fd, struct query *q, char *data, int datalen) 
     1130write_dns(int fd, struct query *q, char *data, int datalen, char downenc) 
    10491131{ 
    10501132        char buf[64*1024]; 
    1051         int len; 
     1133        int len = 0; 
     1134 
     1135        if (q->type == T_CNAME || q->type == T_A || q->type == T_MX) { 
     1136                static int td1 = 0; 
     1137                static int td2 = 0; 
     1138                char cnamebuf[1024];            /* max 255 */ 
     1139                size_t space; 
     1140                char *b; 
     1141 
     1142                /* Make a rotating topdomain to prevent filtering */ 
     1143                td1+=3; 
     1144                td2+=7; 
     1145                if (td1>=26) td1-=26; 
     1146                if (td2>=25) td2-=25; 
     1147 
     1148                /* encode data,datalen to CNAME/MX answer */ 
     1149                /* (adapted from build_hostname() in iodine.c) */ 
     1150 
     1151                space = MIN(0xFF, sizeof(cnamebuf)) - 4 - 2; 
     1152                /* -1 encoding type, -3 ".xy", -2 for safety */ 
     1153 
     1154                memset(cnamebuf, 0, sizeof(cnamebuf)); 
     1155 
     1156                if (downenc == 'S') { 
     1157                        cnamebuf[0] = 'I'; 
     1158                        if (!b64->places_dots()) 
     1159                                space -= (space / 57);  /* space for dots */ 
     1160                        b64->encode(cnamebuf+1, &space, data, datalen); 
     1161                        if (!b64->places_dots()) 
     1162                                inline_dotify(cnamebuf, sizeof(cnamebuf), 57); 
     1163                } else { 
     1164                        cnamebuf[0] = 'H'; 
     1165                        if (!b32->places_dots()) 
     1166                                space -= (space / 57);  /* space for dots */ 
     1167                        b32->encode(cnamebuf+1, &space, data, datalen); 
     1168                        if (!b32->places_dots()) 
     1169                                inline_dotify(cnamebuf, sizeof(cnamebuf), 57); 
     1170                } 
     1171 
     1172                /* Add dot (if it wasn't there already) and topdomain */ 
     1173                b = cnamebuf; 
     1174                b += strlen(cnamebuf); 
     1175                if (*b != '.')  
     1176                        *b++ = '.'; 
     1177 
     1178                *b = 'a' + td1; 
     1179                b++; 
     1180                *b = 'a' + td2; 
     1181                b++; 
     1182                *b = '\0'; 
     1183 
     1184                len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, cnamebuf, sizeof(cnamebuf)); 
     1185        } 
     1186        else if (q->type == T_TXT) { 
     1187                /* TXT with base32 */ 
     1188                char txtbuf[64*1024]; 
     1189                size_t space = sizeof(txtbuf) - 1;; 
     1190 
     1191                memset(txtbuf, 0, sizeof(txtbuf)); 
     1192 
     1193                if (downenc == 'S') { 
     1194                        txtbuf[0] = 'S';        /* plain base64(Sixty-four) */ 
     1195                        len = b64->encode(txtbuf+1, &space, data, datalen); 
     1196                } 
     1197                else if (downenc == 'R') { 
     1198                        txtbuf[0] = 'R';        /* Raw binary data */ 
     1199                        len = MIN(datalen, sizeof(txtbuf) - 1); 
     1200                        memcpy(txtbuf + 1, data, len); 
     1201                } else { 
     1202                        txtbuf[0] = 'T';        /* plain base32(Thirty-two) */ 
     1203                        len = b32->encode(txtbuf+1, &space, data, datalen); 
     1204                } 
     1205                len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, txtbuf, len+1); 
     1206        } else { 
     1207                /* Normal NULL-record encode */ 
     1208                len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, data, datalen); 
     1209        } 
    10521210 
    1053         len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, data, datalen); 
     1211        if (len < 1) { 
     1212                warnx("dns_encode doesn't fit"); 
     1213                return; 
     1214        } 
    10541215         
    10551216        if (debug >= 2) { 
    10561217                struct sockaddr_in *tempin; 
     
    11671328        pidfile = NULL; 
    11681329 
    11691330        b32 = get_base32_encoder(); 
     1331        b64 = get_base64_encoder(); 
    11701332         
    11711333        retval = 0; 
    11721334 
  • src/user.c

    old new  
    3939#include "user.h" 
    4040 
    4141struct user users[USERS]; 
     42time_t now = 0;                                 /* set in iodined.c after select() */ 
    4243 
    4344int 
    4445init_users(in_addr_t my_ip, int netbits) 
     
    8384                        users[i].disabled = 0; 
    8485                        created_users++; 
    8586                } 
     87                users[i].active = 0; 
    8688                users[i].inpacket.len = 0; 
    8789                users[i].inpacket.offset = 0; 
    8890                users[i].outpacket.len = 0; 
     
    104106 
    105107        ret = 0; 
    106108        for (i = 0; i < USERS; i++) { 
    107                 if (users[i].active && !users[i].disabled &&  
    108                         users[i].last_pkt + 60 > time(NULL) && 
     109                if (users[i].active && !users[i].disabled && 
     110                        users[i].last_pkt + 60 > now && 
    109111                        users[i].q.id != 0 && users[i].conn == CONN_DNS_NULL) { 
    110112                        ret++; 
    111113                } 
     
    123125        ret = -1; 
    124126        for (i = 0; i < USERS; i++) { 
    125127                if (users[i].active && !users[i].disabled && 
    126                         users[i].last_pkt + 60 > time(NULL) && 
     128                        users[i].last_pkt + 60 > now && 
    127129                        ip == users[i].tun_ip) { 
    128130                        ret = i; 
    129131                        break; 
     
    135137int 
    136138all_users_waiting_to_send() 
    137139{ 
    138         time_t now; 
    139140        int ret; 
    140141        int i; 
    141142 
    142143        ret = 1; 
    143         now = time(NULL); 
    144144        for (i = 0; i < USERS; i++) { 
    145145                if (users[i].active && !users[i].disabled && 
    146146                        users[i].last_pkt + 60 > now && 
     
    155155} 
    156156 
    157157int 
    158 find_available_user() 
     158find_available_user(int forced_userid) 
    159159{ 
    160160        int ret = -1; 
    161161        int i; 
     162 
     163        if (forced_userid != -1) { 
     164                if (forced_userid < 0 || forced_userid >= USERS) 
     165                        return -1; 
     166 
     167                if ((users[forced_userid].active && 
     168                    users[forced_userid].last_pkt + 60 > now) || 
     169                    users[forced_userid].disabled) 
     170                        return -1; 
     171 
     172                users[forced_userid].active = 1; 
     173                users[forced_userid].last_pkt = now; 
     174 
     175                return forced_userid; 
     176        } 
     177 
    162178        for (i = 0; i < USERS; i++) { 
    163179                /* Not used at all or not used in one minute */ 
    164                 if ((!users[i].active || users[i].last_pkt + 60 < time(NULL)) && !users[i].disabled) { 
     180                if ((!users[i].active || users[i].last_pkt + 60 < now) && !users[i].disabled) { 
    165181                        users[i].active = 1; 
    166                         users[i].last_pkt = time(NULL); 
     182                        users[i].last_pkt = now; 
    167183                        users[i].fragsize = 4096; 
    168184                        users[i].conn = CONN_DNS_NULL; 
    169185                        ret = i; 
  • README

    old new  
    9090So your domain name and subdomain should be as short as possible to allow 
    9191maximum upstream throughput. 
    9292 
     93The default is to use DNS NULL-type queries, as this provides the largest 
     94downstream bandwidth. If your DNS server blocks NULL requests, try TXT or 
     95CNAME queries via the -T option. Also supported are A (returning CNAME) and 
     96MX requests, but these may/will cause additional lookups by "smart" caching 
     97nameservers to get an actual IP address, which may either slow down or fail 
     98completely. DNS responses for non-NULL are Base32 encoded by default, which 
     99should always work. For more bandwidth, try Base64 or Raw (TXT only) via the 
     100-O option. If Base64/Raw doesn't work, you'll see many failures in the 
     101fragment size autoprobe. 
     102 
     103If you have problems, try inspecting the traffic with network monitoring tools 
     104and make sure that the relaying DNS server has not cached the response. A 
     105cached error message could mean that you started the client before the server. 
     106 
    93107 
    94108TIPS & TRICKS: 
    95109 
     
    99113iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to :5353 
    100114(Sent in by Tom Schouten) 
    101115 
     116Iodined will reject data from clients that have not been active (data/pings) 
     117for more than 60 seconds. In case of a long network outage or similar, just 
     118stop iodine and restart (re-login), possibly multiple times until you get 
     119your old IP address back. Once that's done, just wait a while, and you'll 
     120eventually see the tunneled TCP traffic continue to flow from where it left 
     121off before the outage. Use iodine -U to force getting a specific IP address. 
     122 
    102123 
    103124PORTABILITY: 
    104125 
  • new file doc/proto_00000502.txt

    - +  
     1Detailed specification of protocol in version 00000501 
     2====================================================== 
     3 
     4Note: work in progress!! 
     5 
     6====================================================== 
     71. DNS protocol 
     8====================================================== 
     9 
     10CMC = 2 byte Cache Miss Counter, increased every time it is used 
     11 
     12Version: 
     13Client sends: 
     14        First byte v or V 
     15        Rest encoded with base32: 
     16        4 bytes big endian protocol version 
     17        Optional: 1 byte forced userid + 1: 0 = dynamically assigned userid; 
     18                  1 = force userid 0; etc (ignored by earlier server versions) 
     19        CMC 
     20Server replies: 
     21        4 chars: 
     22                VACK (version ok), followed by login challenge 
     23                VNAK (version differs), followed by server protocol version 
     24                VFUL (server has no free slots or forced userid not available), 
     25                     followed by max users 
     26        4 byte value: means login challenge/server protocol version/max users 
     27        1 byte userid of the new user, or any byte if not VACK 
     28         
     29Login: 
     30Client sends: 
     31        First byte l or L 
     32        Rest encoded with base32: 
     33        1 byte userid 
     34        16 bytes MD5 hash of: (first 32 bytes of password) xor (8 repetitions of login challenge) 
     35        CMC 
     36Server replies: 
     37        LNAK means not accepted 
     38        x.x.x.x-y.y.y.y-mtu-netmask means accepted (server ip, client ip, mtu, netmask bits) 
     39 
     40IP Request: 
     41Client sends: 
     42        First byte i or I 
     43        5 bits coded as Base32 char, meaning userid 
     44        CMC 
     45Server replies 
     46        BADIP if bad userid, or 
     47        I and then 4 bytes network order external IP address of iodined server 
     48 
     49Case check: 
     50Client sends:  
     51        First byte z or Z 
     52        Lots of data that should not be decoded 
     53Server replies: 
     54        The requested domain copied raw 
     55 
     56Switch codec: 
     57Client sends: 
     58        First byte s or S 
     59        5 bits coded as Base32 char, meaning userid 
     60        5 bits coded as Base32 char, with value 5 or 6, representing number of raw 
     61        bits per encoded byte 
     62        CMC 
     63Server sends: 
     64        Name of codec if accepted. After this all upstream data packets must  
     65        be encoded with the new codec. 
     66        BADCODEC if not accepted. Client must then revert to Base32 
     67        BADLEN if length of query is too short 
     68 
     69Options: 
     70Client sends: 
     71        First byte o or O 
     72        5 bits coded as Base32 char, meaning userid 
     73        1 char, meaning option 
     74Server sends: 
     75        Full name of option if accepted. After this, option immediately takes 
     76        effect in server. 
     77        BADCODEC if not accepted. Previous situation remains. 
     78        All options affect only the requesting client. 
     79 
     80        Option chars: 
     81        t or T: Downstream encoding Base32, for TXT/CNAME/A/MX (default) 
     82        s or S: Downstream encoding Base64, for TXT/CNAME/A/MX 
     83        r or R: Downstream encoding Raw, for TXT/NULL (default for NULL) 
     84        If codec unsupported for request type, server will use Base32; note 
     85        that server will answer any mix of request types that a client sends. 
     86        Server may disregard this option; client must always use the downstream 
     87        encoding type indicated in every downstream DNS packet. 
     88 
     89Probe downstream fragment size: 
     90Client sends: 
     91        First byte r or R 
     92        15 bits coded as 3 Base32 chars: UUUUF FFFFF FFFFF 
     93                meaning 4 bits userid, 11 bits fragment size 
     94        Then follows a long random query which contents does not matter 
     95Server sends: 
     96        Requested number of bytes as a response. The first two bytes contains 
     97        the requested length. Rest of message can be any data. 
     98        BADFRAG if requested length not accepted. 
     99 
     100Set downstream fragment size: 
     101Client sends: 
     102        First byte n or N 
     103        Rest encoded with base32: 
     104        1 byte userid 
     105        2 bytes new downstream fragment size 
     106        CMC 
     107Server sends: 
     108        2 bytes new downstream fragment size. After this all downstream 
     109        payloads will be max (fragsize + 2) bytes long. 
     110        BADFRAG if not accepted. 
     111 
     112Data: 
     113Upstream data header: 
     114         3210 432 10 43 210 4321 0 
     115        +----+---+--+--+---+----+-+ 
     116        |UUUU|SSS|FF|FF|DDD|GGGG|L| 
     117        +----+---+--+--+---+----+-+ 
     118 
     119Downstream data header: 
     120         7 654 3210 765 4321 0 
     121        +-+---+----+---+----+-+ 
     122        |C|SSS|FFFF|DDD|GGGG|L| 
     123        +-+---+----+---+----+-+ 
     124 
     125UUUU = Userid 
     126L = Last fragment in packet flag 
     127SS = Upstream packet sequence number 
     128FFFF = Upstream fragment number 
     129DDD = Downstream packet sequence number 
     130GGGG = Downstream fragment number 
     131C = Compression enabled for downstream packet 
     132 
     133Upstream data packet starts with 1 byte ASCII hex coded user byte, then 3 bytes  
     134Base32 encoded header, then comes the payload data, encoded with chosen codec. 
     135 
     136Downstream data starts with 2 byte header. Then payload data, which may be 
     137compressed. 
     138 
     139In NULL responses, downstream data is always raw. In all other response types, 
     140downstream data is encoded (see Options above). 
     141Encoding type is indicated by 1 prefix char: 
     142TXT: 
     143        End result is always DNS-chopped (series of len-prefixed strings 
     144        <=255 bytes) 
     145        t or T: Base32   encoded before chop, decoded after un-chop 
     146        s or S: Base64   encoded before chop, decoded after un-chop 
     147        r or R: Raw      no encoding, only DNS-chop 
     148CNAME/A/MX: 
     149        h or H: Hostname encoded with Base32 
     150        i or I: Hostname encoded with Base64 
     151 
     152Ping: 
     153Client sends: 
     154        First byte p or P 
     155        Rest encoded with Base32: 
     156        1 byte with 4 bits userid 
     157        1 byte with: 
     158                3 bits downstream seqno 
     159                4 bits downstream fragment 
     160        CMC 
     161 
     162The server response to Ping and Data packets is a DNS NULL type response: 
     163If server has nothing to send, data length is 0 bytes. 
     164If server has something to send, it will send a downstream data packet,  
     165prefixed with 2 bytes header as shown above. 
     166 
     167 
     168====================================================== 
     1692. Raw UDP protocol 
     170====================================================== 
     171 
     172All Raw UDP protcol messages start with a 3 byte header: 0x10d19e 
     173This is not the start of a valid DNS message so it is easy to identify. 
     174The fourth byte contains the command and the user id. 
     175 
     176         7654 3210 
     177        +----+----+ 
     178        |CCCC|UUUU| 
     179        +----+----+ 
     180 
     181Login message (command = 1): 
     182The header is followed by a MD5 hash with the same password as in the DNS 
     183login. The client starts the raw mode by sending this message, and uses 
     184the login challenge +1, and the server responds using the login challenge -1. 
     185After the login message has been exchanged, both the server and the client 
     186switch to raw udp mode for the rest of the connection. 
     187 
     188Data message (command = 2): 
     189After the header comes the payload data, which may be compressed. 
     190 
     191Ping message (command = 3): 
     192Sent from client to server and back to keep session open. Has no payload. 
     193 
  • man/iodine.8

    old new  
    1313.I password 
    1414.B ] [-m 
    1515.I fragsize 
     16.B ] [-U 
     17.I userid 
     18.B ] [-T 
     19.I dnstype 
     20.B ] [-O 
     21.I downenc 
    1622.B ] [-t 
    1723.I chrootdir 
    1824.B ] [-d 
     
    4652.B ] [-p 
    4753.I port 
    4854.B ] [-n 
    49 .I external ip 
     55.I external_ip 
    5056.B ] [-b 
    5157.I dnsport 
    5258.B ] [-P 
     
    111117will be sent to the server instead of the DNS relay. 
    112118.TP 
    113119.B -m fragsize 
    114 Maximum downstream fragsize. Not setting this will cause the client to probe 
    115 the maximum accepted downstream packet size. 
     120Force maximum downstream fragsize. Not setting this will cause the 
     121client to automatically probe the maximum accepted downstream fragment size. 
     122.TP 
     123.B -U userid 
     124Force userid on server, to get predictable IP address. Userid is 0 \- 15 
     125on current servers, or less if server is started with small subnet. 
     126Normally, userids are dynamically assigned from 0 upwards; suggestion for 
     127static userids is to use from 15 downwards. 
     128.TP 
     129.B -T dnstype 
     130DNS request type. 
     131.I NULL 
     132is default. If this doesn't work, try 
     133.I TXT 
     134(some less bandwidth) or 
     135.I CNAME 
     136(much less bandwidth). Also supported are 
     137.I A 
     138(returning CNAME) and 
     139.I MX 
     140requests, but these may/will cause additional lookups by "smart" caching 
     141nameservers to get an actual IP address, which may either slow down or fail 
     142completely. 
     143.TP 
     144.B -O downenc 
     145Downstream encoding for all query type responses except NULL. 
     146.I Base32 
     147is default and should always work. 
     148.I Base64 
     149provides more bandwidth, but may not work on all nameservers. 
     150For TXT queries, 
     151.I Raw 
     152will provide maximum performance. This will only work if the nameserver 
     153+path is fully 8-bit-clean for responses that are assumed to be 
     154"legible text". 
    116155.SS Server Options: 
    117156.TP 
    118157.B -c 
    119 Disable checks on client IP on all incoming requests. 
     158Disable checking the client IP on all incoming requests. 
     159By default, requests originating from non-matching IP adresses will be 
     160rejected, however this will cause problems when requests are routed 
     161via a cluster of DNS servers. 
    120162.TP 
    121163.B -s 
    122 Don't try to configure IP address or MTU. This should only be used if 
     164Don't try to configure IP address and MTU for the tun device. 
     165This should only be used if 
    123166you have already configured the device that will be used. 
    124167.TP 
    125168.B -D 
    126169Increase debug level. Level 1 prints info about each RX/TX packet. 
     170Implies the 
     171.B -f 
     172option. 
    127173.TP 
    128174.B -m mtu 
    129 Set 'mtu' as mtu size for the tunnel device. This will be sent to the client 
    130 on connect, and the client will use the same mtu. 
     175Set 'mtu' as mtu size for the tun device. This will be sent to the client 
     176on login, and the client will use the same mtu for its tun device. 
     177Default 1200. 
     178Note that the DNS traffic will be automatically fragmented when needed. 
    131179.TP 
    132180.B -l listen_ip 
    133 Make the server listen only on 'listen_ip' instead of on 0.0.0.0 for incoming 
    134 connections. 
     181Make the server listen only on 'listen_ip' for incoming requests. 
     182By default, incoming requests are accepted from all interfaces. 
    135183.TP 
    136184.B -p port 
    137185Make the server listen on 'port' instead of 53 for traffic.  
    138186.B Note: 
    139187You must make sure the dns requests are forwarded to this port yourself. 
    140188.TP 
    141 .B -n external ip 
     189.B -n external_ip 
    142190The IP address to return in NS responses. Default is to return the address used 
    143191as destination in the query. 
    144192.TP 
    145193.B -b dnsport 
    146194If this port is specified, all incoming requests not inside the tunnel domain 
    147195will be forwarded to this port on localhost, to be handled by a real dns. 
     196.B Note: 
     197The forwarding is not fully transparent, and not advised for use 
     198in production environments. 
    148199.SS Client Arguments: 
    149200.TP 
    150201.B nameserver 
     
    156207file. 
    157208.TP 
    158209.B topdomain 
    159 The dns traffic will be sent as querys of type NULL for subdomains under 
     210The dns traffic will be sent as queries for subdomains under 
    160211\'topdomain'. This is normally a subdomain to a domain you own. Use a short 
    161212domain name to get better throughput. If  
    162213.B nameserver 
     
    165216.SS Server Arguments: 
    166217.TP 
    167218.B tunnel_ip[/netmask] 
    168 This is the servers ip address on the tunnel interface. The client will be 
     219This is the server's ip address on the tun interface. The client will be 
    169220given the next ip number in the range. It is recommended to use the  
    17022110.0.0.0 or 172.16.0.0 ranges. The default netmask is /27, can be overriden 
    171222by specifying it here. Using a smaller network will limit the number of 
    172223concurrent users. 
    173224.TP 
    174225.B topdomain 
    175 The dns traffic will is expected to be sent as querys of type NULL for  
     226The dns traffic is expected to arrive as querys for 
    176227subdomains under 'topdomain'. This is normally a subdomain to a domain you  
    177228own. Use a short domain name to get better throughput. This argument must be  
    178 the same on both the client and the server. 
     229the same on both the client and the server. Queries for domains other 
     230than 'topdomain' will be forwarded if the \-b option is given, otherwise 
     231they will be dropped. 
    179232.SH EXAMPLES 
    180233.SS Quickstart: 
    181234.TP 
     
    254307.B MTU issues: 
    255308These issues should be solved now, with automatic fragmentation of downstream  
    256309packets. There should be no need to set the MTU explicitly on the server. 
     310.SH SECURITY 
     311Login is a relatively secure challenge-response MD5 hash, with the 
     312password never passing the wire. 
     313However, all other data is 
     314.B NOT 
     315encrypted in any way. The DNS traffic is also vulnerable to replay, 
     316injection and man-in-the-middle attacks, especially when iodined is used 
     317with the \-c option. Use of ssh or vpn tunneling is strongly recommended. 
     318On both server and client, use 
     319.I iptables 
     320to block all traffic coming in from the tun interfaces, 
     321except to the used ssh or vpn ports. 
    257322.SH ENVIRONMENT 
    258323.SS IODINE_PASS 
    259324If the environment variable 
     
    272337.El 
    273338.SH BUGS 
    274339File bugs at http://dev.kryo.se/iodine/ 
     340.SH SEE ALSO 
     341The README file in the source distribution contains some more elaborate 
     342information. 
    275343.SH AUTHORS 
    276344Erik Ekman <yarrick@kryo.se> and Bjorn Andersson <flex@kryo.se>