source: src/iodined.c @ 1965b0

Revision 1965b0, 14.3 KB checked in by Bjorn Andersson <flex@…>, 6 years ago (diff)

cleaning commandline on server too

  • Property mode set to 100644
Line 
1/*
2 * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <stdio.h>
18#include <stdint.h>
19#include <stdlib.h>
20#include <string.h>
21#include <signal.h>
22#include <unistd.h>
23#include <sys/types.h>
24#include <sys/time.h>
25#include <sys/socket.h>
26#include <fcntl.h>
27#include <err.h>
28#include <time.h>
29#include <pwd.h>
30#include <arpa/inet.h>
31#include <netinet/in.h>
32#include <netinet/in_systm.h>
33#include <netinet/ip.h>
34#include <zlib.h>
35
36#include "common.h"
37#include "dns.h"
38#include "encoding.h"
39#include "base32.h"
40#include "user.h"
41#include "login.h"
42#include "tun.h"
43#include "version.h"
44
45int running = 1;
46
47char *topdomain;
48
49char password[33];
50
51struct encoder *b32;
52
53int my_mtu;
54in_addr_t my_ip;
55
56static int read_dns(int, struct query *, char *, int);
57static void write_dns(int, struct query *, char *, int);
58
59static void
60sigint(int sig)
61{
62        running = 0;
63}
64
65static int
66tunnel_tun(int tun_fd, int dns_fd)
67{
68        unsigned long outlen;
69        struct ip *header;
70        char out[64*1024];
71        char in[64*1024];
72        int userid;
73        int read;
74
75        if ((read = read_tun(tun_fd, in, sizeof(in))) <= 0)
76                return 0;
77       
78        /* find target ip in packet, in is padded with 4 bytes TUN header */
79        header = (struct ip*) (in + 4);
80        userid = find_user_by_ip(header->ip_dst.s_addr);
81        if (userid < 0)
82                return 0;
83
84        outlen = sizeof(out);
85        compress2((uint8_t*)out, &outlen, (uint8_t*)in, read, 9);
86
87        /* if another packet is queued, throw away this one. TODO build queue */
88        if (users[userid].outpacket.len == 0) {
89                memcpy(users[userid].outpacket.data, out, outlen);
90                users[userid].outpacket.len = outlen;
91                return outlen;
92        } else {
93                return 0;
94        }
95}
96
97typedef enum {
98        VERSION_ACK,
99        VERSION_NACK,
100        VERSION_FULL
101} version_ack_t;
102
103static void
104send_version_response(int fd, version_ack_t ack, uint32_t payload, struct user *u)
105{
106        char out[9];
107       
108        switch (ack) {
109        case VERSION_ACK:
110                strncpy(out, "VACK", sizeof(out));
111                break;
112        case VERSION_NACK:
113                strncpy(out, "VNAK", sizeof(out));
114                break;
115        case VERSION_FULL:
116                strncpy(out, "VFUL", sizeof(out));
117                break;
118        }
119       
120        out[4] = ((payload >> 24) & 0xff);
121        out[5] = ((payload >> 16) & 0xff);
122        out[6] = ((payload >> 8) & 0xff);
123        out[7] = ((payload) & 0xff);
124        out[8] = u->id;
125
126
127        write_dns(fd, &u->q, out, sizeof(out));
128}
129
130static int
131cmp_remote_ip(int userid, struct query *q) {
132        struct sockaddr_in *tempin;
133
134        tempin = (struct sockaddr_in *) &(q->from);
135        return memcmp(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
136}
137
138static int
139tunnel_dns(int tun_fd, int dns_fd)
140{
141        struct in_addr tempip;
142        struct sockaddr_in *tempin;
143        struct user dummy;
144        struct ip *hdr;
145        unsigned long outlen;
146        char logindata[16];
147        char out[64*1024];
148        char in[64*1024];
149        char unpacked[64*1024];
150        char *tmp[2];
151        int userid;
152        int touser;
153        int version;
154        int read;
155        int code;
156
157        userid = -1;
158        if ((read = read_dns(dns_fd, &(dummy.q), in, sizeof(in))) <= 0)
159                return 0;
160                               
161        if(in[0] == 'V' || in[0] == 'v') {
162                read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
163                /* Version greeting, compare and send ack/nak */
164                if (read > 4) {
165                        /* Received V + 32bits version */
166
167                        version = (((unpacked[0] & 0xff) << 24) |
168                                           ((unpacked[1] & 0xff) << 16) |
169                                           ((unpacked[2] & 0xff) << 8) |
170                                           ((unpacked[3] & 0xff)));
171
172                        if (version == VERSION) {
173                                userid = find_available_user();
174                                if (userid >= 0) {
175                                        users[userid].seed = rand();
176                                        /* Store remote IP number */
177                                        tempin = (struct sockaddr_in *) &(dummy.q.from);
178                                        memcpy(&(users[userid].host), &(tempin->sin_addr), sizeof(struct in_addr));
179                                        memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
180                                        users[userid].encoder = get_base32_encoder();
181                                        send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]);
182                                        users[userid].q.id = 0;
183                                } else {
184                                        /* No space for another user */
185                                        send_version_response(dns_fd, VERSION_FULL, USERS, &dummy);
186                                }
187                        } else {
188                                send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy);
189                        }
190                } else {
191                        send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy);
192                }
193        } else if(in[0] == 'L' || in[0] == 'l') {
194                read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
195                /* Login phase, handle auth */
196                userid = unpacked[0];
197                if (userid < 0 || userid >= USERS) {
198                        write_dns(dns_fd, &(dummy.q), "BADIP", 5);
199                        return 0; /* illegal id */
200                }
201                users[userid].last_pkt = time(NULL);
202                login_calculate(logindata, 16, password, users[userid].seed);
203
204                if (cmp_remote_ip(userid, &(dummy.q)) != 0) {
205                        write_dns(dns_fd, &(dummy.q), "BADIP", 5);
206                } else {
207                        if (read >= 18 && (memcmp(logindata, unpacked+1, 16) == 0)) {
208                                /* Login ok, send ip/mtu info */
209
210                                tempip.s_addr = my_ip;
211                                tmp[0] = strdup(inet_ntoa(tempip));
212                                tempip.s_addr = users[userid].tun_ip;
213                                tmp[1] = strdup(inet_ntoa(tempip));
214
215                                read = snprintf(out, sizeof(out), "%s-%s-%d",
216                                                tmp[0], tmp[1], my_mtu);
217
218                                write_dns(dns_fd, &(dummy.q), out, read);
219                                dummy.q.id = 0;
220
221                                free(tmp[1]);
222                                free(tmp[0]);
223                        } else {
224                                write_dns(dns_fd, &(dummy.q), "LNAK", 4);
225                        }
226                }
227        } else if(in[0] == 'P' || in[0] == 'p') {
228                read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
229                /* Ping packet, store userid */
230                userid = unpacked[0];
231                if (userid < 0 || userid >= USERS) {
232                        write_dns(dns_fd, &(dummy.q), "BADIP", 5);
233                        return 0; /* illegal id */
234                }
235                if (cmp_remote_ip(userid, &(dummy.q)) != 0) {
236                        memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
237                        users[userid].last_pkt = time(NULL);
238                }
239        } else if(in[0] == 'Z' || in[0] == 'z') {
240                /* Case conservation check */
241
242                /* Reply with received hostname as data */
243                write_dns(dns_fd, &(dummy.q), in, read);
244                return 0;
245        } else if((in[0] >= '0' && in[0] <= '9')
246                        || (in[0] >= 'a' && in[0] <= 'f')
247                        || (in[0] >= 'A' && in[0] <= 'F')) {
248                if ((in[0] >= '0' && in[0] <= '9'))
249                        code = in[0] - '0';
250                if ((in[0] >= 'a' && in[0] <= 'f'))
251                        code = in[0] - 'a' + 10;
252                if ((in[0] >= 'A' && in[0] <= 'F'))
253                        code = in[0] - 'A' + 10;
254
255                userid = code >> 1;
256                if (userid < 0 || userid >= USERS) {
257                        write_dns(dns_fd, &(dummy.q), "BADIP", 5);
258                        return 0; /* illegal id */
259                }
260
261                /* Check sending ip number */
262                if (cmp_remote_ip(userid, &(dummy.q)) != 0) {
263                        write_dns(dns_fd, &(dummy.q), "BADIP", 5);
264                } else {
265                        /* decode with this users encoding */
266                        read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1,
267                                           users[userid].encoder);
268
269                        users[userid].last_pkt = time(NULL);
270                        memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
271                        memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, unpacked, read);
272                        users[userid].inpacket.len += read;
273                        users[userid].inpacket.offset += read;
274
275                        if (code & 1) {
276                                outlen = sizeof(out);
277                                uncompress((uint8_t*)out, &outlen,
278                                                   (uint8_t*)users[userid].inpacket.data, users[userid].inpacket.len);
279
280                                hdr = (struct ip*) (out + 4);
281                                touser = find_user_by_ip(hdr->ip_dst.s_addr);
282
283                                if (touser == -1) {
284                                        /* send the uncompressed packet to tun device */
285                                        write_tun(tun_fd, out, outlen);
286                                } else {
287                                        /* send the compressed packet to other client
288                                         * if another packet is queued, throw away this one. TODO build queue */
289                                        if (users[touser].outpacket.len == 0) {
290                                                memcpy(users[touser].outpacket.data, users[userid].inpacket.data, users[userid].inpacket.len);
291                                                users[touser].outpacket.len = users[userid].inpacket.len;
292                                        }
293                                }
294                                users[userid].inpacket.len = users[userid].inpacket.offset = 0;
295                        }
296                }
297        }
298        /* userid must be set for a reply to be sent */
299        if (userid >= 0 && userid < USERS &&
300                        cmp_remote_ip(userid, &(dummy.q)) != 0 &&
301                        users[userid].outpacket.len > 0) {
302
303                write_dns(dns_fd, &(dummy.q), users[userid].outpacket.data, users[userid].outpacket.len);
304                users[userid].outpacket.len = 0;
305                users[userid].q.id = 0;
306        }
307
308        return 0;
309}
310
311static int
312tunnel(int tun_fd, int dns_fd)
313{
314        struct timeval tv;
315        fd_set fds;
316        int i;
317        int j;
318
319        while (running) {
320                if (users_waiting_on_reply()) {
321                        tv.tv_sec = 0;
322                        tv.tv_usec = 5000;
323                } else {
324                        tv.tv_sec = 1;
325                        tv.tv_usec = 0;
326                }
327
328                FD_ZERO(&fds);
329                /* TODO : use some kind of packet queue */
330                if(!all_users_waiting_to_send()) {
331                        FD_SET(tun_fd, &fds);
332                }
333                FD_SET(dns_fd, &fds);
334
335                i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
336               
337                if(i < 0) {
338                        if (running)
339                                warn("select");
340                        return 1;
341                }
342       
343                if (i==0) {     
344                        for (j = 0; j < USERS; j++) {
345                                if (users[j].q.id != 0) {
346                                        write_dns(dns_fd, &(users[j].q), users[j].outpacket.data, users[j].outpacket.len);
347                                        users[j].outpacket.len = 0;
348                                        users[j].q.id = 0;
349                                }
350                        }
351                } else {
352                        if(FD_ISSET(tun_fd, &fds)) {
353                                tunnel_tun(tun_fd, dns_fd);
354                                continue;
355                        }
356                        if(FD_ISSET(dns_fd, &fds)) {
357                                tunnel_dns(tun_fd, dns_fd);
358                                continue;
359                        }
360                }
361        }
362
363        return 0;
364}
365
366static int
367read_dns(int fd, struct query *q, char *buf, int buflen)
368{
369        struct sockaddr_in from;
370        char packet[64*1024];
371        char *domain;
372        socklen_t addrlen;
373        int rv;
374        int r;
375
376        addrlen = sizeof(struct sockaddr);
377        r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
378
379        if (r > 0) {
380                dns_decode(buf, buflen, q, QR_QUERY, packet, r);
381                domain = strstr(q->name, topdomain);
382                if (domain) {
383                        rv = (int) (domain - q->name);
384                        memcpy(buf, q->name, MIN(rv, buflen));
385                        q->fromlen = addrlen;
386                        memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
387                } else {
388                        rv = 0;
389                }
390        } else if (r < 0) {
391                /* Error */
392                warn("read dns");
393                rv = 0;
394        }
395
396        return rv;
397}
398
399static void
400write_dns(int fd, struct query *q, char *data, int datalen)
401{
402        char buf[64*1024];
403        int len;
404
405        len = dns_encode(buf, sizeof(buf), q, QR_ANSWER, data, datalen);
406       
407        sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen);
408}
409
410static void
411usage() {
412        extern char *__progname;
413
414        printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
415                "[-l ip address to listen on] [-p port] [-P password]"
416                " tunnel_ip topdomain\n", __progname);
417        exit(2);
418}
419
420static void
421help() {
422        extern char *__progname;
423
424        printf("iodine IP over DNS tunneling server\n");
425        printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
426                "[-l ip address to listen on] [-p port] [-P password]"
427                " tunnel_ip topdomain\n", __progname);
428        printf("  -v to print version info and exit\n");
429        printf("  -h to print this help and exit\n");
430        printf("  -f to keep running in foreground\n");
431        printf("  -u name to drop privileges and run as user 'name'\n");
432        printf("  -t dir to chroot to directory dir\n");
433        printf("  -d device to set tunnel device name\n");
434        printf("  -m mtu to set tunnel device mtu\n");
435        printf("  -l ip address to listen on for incoming dns traffic (default 0.0.0.0)\n");
436        printf("  -p port to listen on for incoming dns traffic (default 53)\n");
437        printf("  -P password used for authentication (max 32 chars will be used)\n");
438        printf("tunnel_ip is the IP number of the local tunnel interface.\n");
439        printf("topdomain is the FQDN that is delegated to this server.\n");
440        exit(0);
441}
442
443static void
444version() {
445        char *svnver = "$Rev$ from $Date$";
446        printf("iodine IP over DNS tunneling server\n");
447        printf("SVN version: %s\n", svnver);
448        exit(0);
449}
450
451int
452main(int argc, char **argv)
453{
454        in_addr_t listen_ip;
455        struct passwd *pw;
456        int foreground;
457        char *username;
458        char *newroot;
459        char *device;
460        int dnsd_fd;
461        int tun_fd;
462        int choice;
463        int port;
464        int mtu;
465
466        username = NULL;
467        newroot = NULL;
468        device = NULL;
469        foreground = 0;
470        mtu = 1024;
471        listen_ip = INADDR_ANY;
472        port = 53;
473
474        b32 = get_base32_encoder();
475
476        memset(password, 0, sizeof(password));
477        srand(time(NULL));
478       
479        while ((choice = getopt(argc, argv, "vfhu:t:d:m:l:p:P:")) != -1) {
480                switch(choice) {
481                case 'v':
482                        version();
483                        break;
484                case 'f':
485                        foreground = 1;
486                        break;
487                case 'h':
488                        help();
489                        break;
490                case 'u':
491                        username = optarg;
492                        break;
493                case 't':
494                        newroot = optarg;
495                        break;
496                case 'd':
497                        device = optarg;
498                        break;
499                case 'm':
500                        mtu = atoi(optarg);
501                        break;
502                case 'l':
503                        listen_ip = inet_addr(optarg);
504                        break;
505                case 'p':
506                        port = atoi(optarg);
507                        if (port) {
508                                printf("ALERT! Other dns servers expect you to run on port 53.\n");
509                                printf("You must manually forward port 53 to port %d for things to work.\n", port);
510                        }
511                        break;
512                case 'P':
513                        strncpy(password, optarg, 32);
514                        password[32] = 0;
515                       
516                        /* XXX: find better way of cleaning up ps(1) */
517                        memset(optarg, 0, strlen(optarg));
518                        break;
519                default:
520                        usage();
521                        break;
522                }
523        }
524
525        argc -= optind;
526        argv += optind;
527
528        if (geteuid() != 0) {
529                printf("Run as root and you'll be happy.\n");
530                usage();
531        }
532
533        if (argc != 2)
534                usage();
535
536        topdomain = strdup(argv[1]);
537        if (strlen(topdomain) > 128 || topdomain[0] == '.') {
538                printf("Use a topdomain max 128 chars long. Do not start it with a dot.\n");
539                usage();
540        }
541
542        if (username) {
543                pw = getpwnam(username);
544                if (!pw) {
545                        printf("User %s does not exist!\n", username);
546                        usage();
547                }
548        }
549
550        if (mtu == 0) {
551                printf("Bad MTU given.\n");
552                usage();
553        }
554
555        if (listen_ip == INADDR_NONE) {
556                printf("Bad IP address to listen on.\n");
557                usage();
558        }
559
560        if (strlen(password) == 0) {
561                printf("Enter password on stdin:\n");
562                scanf("%32s", password);
563                password[32] = 0;
564        }
565
566        if ((tun_fd = open_tun(device)) == -1)
567                goto cleanup0;
568        if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
569                goto cleanup1;
570        if ((dnsd_fd = open_dns(port, listen_ip)) == -1)
571                goto cleanup2;
572
573        my_ip = inet_addr(argv[0]);
574        my_mtu = mtu;
575        init_users(my_ip);
576
577        printf("Listening to dns for domain %s\n", argv[1]);
578
579        if (newroot != NULL)
580                do_chroot(newroot);
581
582        signal(SIGINT, sigint);
583        if (username) {
584                if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
585                        printf("Could not switch to user %s!\n", username);
586                        usage();
587                }
588        }
589       
590        if (!foreground) {
591                do_detach();
592        }
593       
594        tunnel(tun_fd, dnsd_fd);
595
596cleanup2:
597        close_dns(dnsd_fd);
598cleanup1:
599        close_tun(tun_fd);     
600cleanup0:
601
602        return 0;
603}
Note: See TracBrowser for help on using the repository browser.