source: src/iodined.c @ c5317f

Revision c5317f, 9.7 KB checked in by Erik Ekman <yarrick@…>, 6 years ago (diff)

#3 move dnsd_read from dns.c to iodined.c, now named read_dns

  • Property mode set to 100644
Line 
1/*
2 * Copyright (c) 2006 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 <netinet/in.h>
22#include <signal.h>
23#include <unistd.h>
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#include <err.h>
29#include <time.h>
30#include <pwd.h>
31#include <arpa/inet.h>
32#include <netinet/in.h>
33#include <zlib.h>
34
35#include "common.h"
36#include "dns.h"
37#include "login.h"
38#include "tun.h"
39#include "version.h"
40
41#ifndef MAX
42#define MAX(a,b) ((a)>(b)?(a):(b))
43#endif
44
45int running = 1;
46
47struct packet packetbuf;
48struct packet outpacket;
49int outid;
50
51struct query q;
52
53struct user u;
54char password[33];
55
56int my_mtu;
57in_addr_t my_ip;
58
59static int read_dns(int, struct query *, char *, int);
60
61static void
62sigint(int sig) {
63        running = 0;
64}
65
66static int
67tunnel(int tun_fd, int dns_fd)
68{
69        struct in_addr clientip;
70        struct in_addr myip;
71        struct timeval tv;
72        char out[64*1024];
73        char in[64*1024];
74        char *tmp[2];
75        char logindata[16];
76        long outlen;
77        fd_set fds;
78        int read;
79        int code;
80        int version;
81        int seed;
82        int nseed;
83        int i;
84
85        while (running) {
86                if (q.id != 0) {
87                        tv.tv_sec = 0;
88                        tv.tv_usec = 5000;
89                } else {
90                        tv.tv_sec = 1;
91                        tv.tv_usec = 0;
92                }
93
94                FD_ZERO(&fds);
95                if(outpacket.len == 0)
96                        FD_SET(tun_fd, &fds);
97                FD_SET(dns_fd, &fds);
98
99                i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
100               
101                if(i < 0) {
102                        if (running)
103                                warn("select");
104                        return 1;
105                }
106       
107                if (i==0) {     
108                        if (q.id != 0) {
109                                dnsd_send(dns_fd, &q, outpacket.data, outpacket.len);
110                                outpacket.len = 0;
111                                q.id = 0;
112                        }
113                } else {
114                        if(FD_ISSET(tun_fd, &fds)) {
115                                read = read_tun(tun_fd, in, sizeof(in));
116                                if (read <= 0)
117                                        continue;
118                               
119                                outlen = sizeof(out);
120                                compress2(out, &outlen, in, read, 9);
121                                memcpy(outpacket.data, out, outlen);
122                                outpacket.len = outlen;
123                        }
124                        if(FD_ISSET(dns_fd, &fds)) {
125                                read = read_dns(dns_fd, &q, in, sizeof(in));
126                                if (read <= 0)
127                                        continue;
128
129                                if(in[0] == 'V' || in[0] == 'v') {
130                                        // Version greeting, compare and send ack/nak
131                                        if (read >= 5) { // Received V + 32bits version
132                                                memcpy(&version, in + 1, 4);
133                                                version = ntohl(version);
134                                                if (version == VERSION) {
135                                                        seed = rand();
136                                                        nseed = htonl(seed);
137                                                        strncpy(out, "VACK", sizeof(out));
138                                                        memcpy(out+4, &nseed, 4);
139                                                        dnsd_send(dns_fd, &q, out, 8);
140                                                } else {
141                                                        version = htonl(VERSION);
142                                                        strncpy(out, "VNAK", sizeof(out));
143                                                        memcpy(out+4, &version, 4);
144                                                        dnsd_send(dns_fd, &q, out, 8);
145                                                }
146                                        } else {
147                                                version = htonl(VERSION);
148                                                strncpy(out, "VNAK", sizeof(out));
149                                                memcpy(out+4, &version, 4);
150                                                dnsd_send(dns_fd, &q, out, 8);
151                                        }
152                                } else if(in[0] == 'L' || in[0] == 'l') {
153                                        // Login phase, handle auth
154                                        login_calculate(logindata, 16, password, seed);
155                                        if (read >= 17 && (memcmp(logindata, in+1, 16) == 0)) {
156                                                // Login ok, send ip/mtu info
157                                                myip.s_addr = my_ip;
158                                                clientip.s_addr = my_ip + inet_addr("0.0.0.1");
159
160                                                tmp[0] = strdup(inet_ntoa(myip));
161                                                tmp[1] = strdup(inet_ntoa(clientip));
162                                               
163                                                read = snprintf(out, sizeof(out), "%s-%s-%d",
164                                                                tmp[0], tmp[1], my_mtu);
165                                               
166                                                // Store user ip
167                                                memcpy(&(u.host), &(q.from), q.fromlen);
168                                                u.addrlen = q.fromlen;
169
170                                                dnsd_send(dns_fd, &q, out, read);
171                                                q.id = 0;
172
173                                                free(tmp[1]);
174                                                free(tmp[0]);
175                                        } else {
176                                                dnsd_send(dns_fd, &q, "LNAK", 4);
177                                        }
178                                } else if((in[0] >= '0' && in[0] <= '9')
179                                                || (in[0] >= 'a' && in[0] <= 'f')
180                                                || (in[0] >= 'A' && in[0] <= 'F')) {
181                                        if ((in[0] >= '0' && in[0] <= '9'))
182                                                code = in[0] - '0';
183                                        if ((in[0] >= 'a' && in[0] <= 'f'))
184                                                code = in[0] - 'a' + 10;
185                                        if ((in[0] >= 'A' && in[0] <= 'F'))
186                                                code = in[0] - 'A' + 10;
187                                       
188                                        // Check sending ip number
189                                        if (q.fromlen != u.addrlen ||
190                                                memcmp(&(u.host), &(q.from), q.fromlen) != 0) {
191                                                dnsd_send(dns_fd, &q, "BADIP", 5);
192                                        } else {
193                                                memcpy(packetbuf.data + packetbuf.offset, in + 1, read - 1);
194                                                packetbuf.len += read - 1;
195                                                packetbuf.offset += read - 1;
196
197                                                if (code & 1) {
198                                                        outlen = sizeof(out);
199                                                        uncompress(out, &outlen, packetbuf.data, packetbuf.len);
200
201                                                        write_tun(tun_fd, out, outlen);
202
203                                                        packetbuf.len = packetbuf.offset = 0;
204                                                }
205                                        }
206                                }
207                                if (q.fromlen == u.addrlen &&
208                                        memcmp(&(u.host), &(q.from), q.fromlen) == 0 &&
209                                        outpacket.len > 0) {
210
211                                        dnsd_send(dns_fd, &q, outpacket.data, outpacket.len);
212                                        outpacket.len = 0;
213                                        q.id = 0;
214                                }
215                        }
216                }
217        }
218
219        return 0;
220}
221
222static int
223read_dns(int fd, struct query *q, char *buf, int buflen)
224{
225        struct sockaddr_in from;
226        char packet[64*1024];
227        socklen_t addrlen;
228        int len;
229        int rv;
230        int r;
231
232        addrlen = sizeof(struct sockaddr);
233        r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
234
235        if (r > 0) {
236                len = dns_decode(buf, buflen, q, QR_QUERY, packet, r);
237
238                q->fromlen = addrlen;
239                memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
240                rv = len;
241        } else if (r < 0) {     // Error
242                perror("recvfrom");
243                rv = 0;
244        }
245
246        return rv;
247}
248
249static void
250usage() {
251        extern char *__progname;
252
253        printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
254                "[-l ip address to listen on] [-p port] [-P password]"
255                " tunnel_ip topdomain\n", __progname);
256        exit(2);
257}
258
259static void
260help() {
261        extern char *__progname;
262
263        printf("iodine IP over DNS tunneling server\n");
264        printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] "
265                "[-l ip address to listen on] [-p port] [-P password]"
266                " tunnel_ip topdomain\n", __progname);
267        printf("  -v to print version info and exit\n");
268        printf("  -h to print this help and exit\n");
269        printf("  -f to keep running in foreground\n");
270        printf("  -u name to drop privileges and run as user 'name'\n");
271        printf("  -t dir to chroot to directory dir\n");
272        printf("  -d device to set tunnel device name\n");
273        printf("  -m mtu to set tunnel device mtu\n");
274        printf("  -l ip address to listen on for incoming dns traffic (default 0.0.0.0)\n");
275        printf("  -p port to listen on for incoming dns traffic (default 53)\n");
276        printf("  -P password used for authentication (max 32 chars will be used)\n");
277        printf("tunnel_ip is the IP number of the local tunnel interface.\n");
278        printf("topdomain is the FQDN that is delegated to this server.\n");
279        exit(0);
280}
281
282static void
283version() {
284        char *svnver = "$Rev$ from $Date$";
285        printf("iodine IP over DNS tunneling server\n");
286        printf("SVN version: %s\n", svnver);
287        exit(0);
288}
289
290int
291main(int argc, char **argv)
292{
293        int choice;
294        int tun_fd;
295        int dnsd_fd;
296        char *newroot;
297        char *username;
298        char *device;
299        int foreground;
300        int mtu;
301        struct passwd *pw;
302        in_addr_t listen_ip;
303        int port;
304
305        username = NULL;
306        newroot = NULL;
307        device = NULL;
308        foreground = 0;
309        mtu = 1024;
310        listen_ip = INADDR_ANY;
311        port = 53;
312
313        packetbuf.len = 0;
314        packetbuf.offset = 0;
315        outpacket.len = 0;
316        q.id = 0;
317        memset(password, 0, 33);
318        srand(time(NULL));
319       
320        while ((choice = getopt(argc, argv, "vfhu:t:d:m:l:p:P:")) != -1) {
321                switch(choice) {
322                case 'v':
323                        version();
324                        break;
325                case 'f':
326                        foreground = 1;
327                        break;
328                case 'h':
329                        help();
330                        break;
331                case 'u':
332                        username = optarg;
333                        break;
334                case 't':
335                        newroot = optarg;
336                        break;
337                case 'd':
338                        device = optarg;
339                        break;
340                case 'm':
341                        mtu = atoi(optarg);
342                        break;
343                case 'l':
344                        listen_ip = inet_addr(optarg);
345                        break;
346                case 'p':
347                        port = atoi(optarg);
348                        if (port) {
349                                printf("ALERT! Other dns servers expect you to run on port 53.\n");
350                                printf("You must manually forward port 53 to port %d for things to work.\n", port);
351                        }
352                        break;
353                case 'P':
354                        strncpy(password, optarg, 32);
355                        password[32] = 0;
356                        break;
357                default:
358                        usage();
359                        break;
360                }
361        }
362
363        argc -= optind;
364        argv += optind;
365       
366        if (geteuid() != 0) {
367                printf("Run as root and you'll be happy.\n");
368                usage();
369        }
370
371        if (argc != 2)
372                usage();
373
374        if (username) {
375                pw = getpwnam(username);
376                if (!pw) {
377                        printf("User %s does not exist!\n", username);
378                        usage();
379                }
380        }
381
382        if (mtu == 0) {
383                printf("Bad MTU given.\n");
384                usage();
385        }
386
387        if (listen_ip == INADDR_NONE) {
388                printf("Bad IP address to listen on.\n");
389                usage();
390        }
391
392        if (strlen(password) == 0) {
393                printf("Enter password on stdin:\n");
394                scanf("%32s", password);
395                password[32] = 0;
396        }
397
398        if ((tun_fd = open_tun(device)) == -1)
399                goto cleanup0;
400        if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
401                goto cleanup1;
402        dns_set_topdomain(argv[1]);
403        if ((dnsd_fd = open_dns(port, listen_ip)) == -1)
404                goto cleanup2;
405
406        my_ip = inet_addr(argv[0]);
407        my_mtu = mtu;
408
409        printf("Listening to dns for domain %s\n", argv[1]);
410
411        if (newroot) {
412                if (chroot(newroot) != 0 || chdir("/") != 0)
413                        err(1, "%s", newroot);
414                seteuid(geteuid());
415                setuid(getuid());
416        }
417       
418        if (!foreground) {
419                printf("Detaching from terminal...\n");
420                daemon(0, 0);
421                umask(0);
422                alarm(0);
423        }
424
425        signal(SIGINT, sigint);
426        if (username) {
427                if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
428                        printf("Could not switch to user %s!\n", username);
429                        usage();
430                }
431        }
432       
433        tunnel(tun_fd, dnsd_fd);
434
435cleanup2:
436        close_dns(dnsd_fd);
437cleanup1:
438        close_tun(tun_fd);     
439cleanup0:
440
441        return 0;
442}
Note: See TracBrowser for help on using the repository browser.