source: src/iodine.c @ 692b59

Revision 692b59, 7.4 KB checked in by Bjorn Andersson <flex@…>, 6 years ago (diff)

#4 - moved common stuff to common.c and moved open_dns, close_dns there

  • 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 <signal.h>
22#include <unistd.h>
23#include <netinet/in.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 <pwd.h>
30#include <arpa/inet.h>
31#include <zlib.h>
32
33#include "common.h"
34#include "dns.h"
35#include "login.h"
36#include "tun.h"
37#include "version.h"
38
39#ifndef MAX
40#define MAX(a,b) ((a)>(b)?(a):(b))
41#endif
42
43int running = 1;
44char password[33];
45
46static void
47sighandler(int sig) {
48        running = 0;
49}
50
51static int
52tunnel_tun(int tun_fd, int dns_fd)
53{
54        char out[64*1024];
55        char in[64*1024];
56        size_t outlen;
57        int read;
58
59        read = read_tun(tun_fd, in, sizeof(in));
60        if(read > 0) {
61                outlen = sizeof(out);
62                compress2(out, &outlen, in, read, 9);
63                dns_handle_tun(dns_fd, out, outlen);
64        }
65
66        return read;
67}
68
69static int
70tunnel_dns(int tun_fd, int dns_fd)
71{
72        char out[64*1024];
73        char in[64*1024];
74        size_t outlen;
75        int read;
76
77        read = dns_read(dns_fd, in, sizeof(in));
78        if (read > 0) {
79                outlen = sizeof(out);
80                uncompress(out, &outlen, in, read);
81
82                write_tun(tun_fd, out, outlen);
83                if (!dns_sending())
84                        dns_ping(dns_fd);
85        }
86       
87        return read;
88}
89
90static int
91tunnel(int tun_fd, int dns_fd)
92{
93        struct timeval tv;
94        fd_set fds;
95        int i;
96        int rv;
97
98        rv = 0;
99
100        while (running) {
101                tv.tv_sec = 1;
102                tv.tv_usec = 0;
103
104                FD_ZERO(&fds);
105                if (!dns_sending())
106                        FD_SET(tun_fd, &fds);
107                FD_SET(dns_fd, &fds);
108
109                i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
110
111                if (running == 0 || i < 0) {
112                        rv = 1;
113                        break;
114                }
115               
116                if (i == 0) /* timeout */
117                        dns_ping(dns_fd);
118                else { 
119                        if(FD_ISSET(tun_fd, &fds)) {
120                                if (tunnel_tun(tun_fd, dns_fd) <= 0)
121                                        continue;
122                        }
123                        if(FD_ISSET(dns_fd, &fds)) {
124                                if (tunnel_dns(tun_fd, dns_fd) <= 0)
125                                        continue;
126                        }
127                }
128        }
129
130        return rv;
131}
132
133static int
134handshake(int dns_fd)
135{
136        struct timeval tv;
137        char server[65];
138        char client[65];
139        char login[16];
140        char in[4096];
141        fd_set fds;
142        int read;
143        int mtu;
144        int seed;
145        int version;
146        int i;
147        int r;
148
149        for (i=0; running && i<5 ;i++) {
150                tv.tv_sec = i + 1;
151                tv.tv_usec = 0;
152
153                dns_send_version(dns_fd, VERSION);
154               
155                FD_ZERO(&fds);
156                FD_SET(dns_fd, &fds);
157
158                r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
159
160                if(r > 0) {
161                        read = dns_read(dns_fd, in, sizeof(in));
162                       
163                        if(read < 0) {
164                                perror("read");
165                                continue;
166                        }
167
168                        if (read > 0) {
169                                if (strncmp("VACK", in, 4) == 0) {
170                                        if (read >= 8) {
171                                                memcpy(&seed, in + 4, 4);
172                                                seed = ntohl(seed);
173                                                printf("Version ok, both running 0x%08x\n", VERSION);
174                                                break;
175                                        } else {
176                                                printf("Version ok but did not receive proper login challenge\n");
177                                        }
178                                } else {
179                                        memcpy(&version, in + 4, 4);
180                                        version = ntohl(version);
181                                        printf("You run 0x%08x, server runs 0x%08x. Giving up\n", VERSION, version);
182                                        return 1;
183                                }
184                        }
185                }
186               
187                if (i == 4)
188                        return 1;
189                printf("Retrying version check...\n");
190        }
191       
192        login_calculate(login, 16, password, seed);
193        for (i=0; running && i<5 ;i++) {
194                tv.tv_sec = i + 1;
195                tv.tv_usec = 0;
196
197                dns_login(dns_fd, login, 16);
198               
199                FD_ZERO(&fds);
200                FD_SET(dns_fd, &fds);
201
202                r = select(dns_fd + 1, &fds, NULL, NULL, &tv);
203
204                if(r > 0) {
205                        read = dns_read(dns_fd, in, sizeof(in));
206                       
207                        if(read <= 0) {
208                                perror("read");
209                                continue;
210                        }
211
212                        if (read > 0) {
213                                if (strncmp("LNAK", in, 4) == 0) {
214                                        printf("Bad password\n");
215                                        return 1;
216                                } else if (sscanf(in, "%64[^-]-%64[^-]-%d",
217                                        server, client, &mtu) == 3) {
218                                       
219                                        server[64] = 0;
220                                        client[64] = 0;
221                                        if (tun_setip(client) == 0 &&
222                                                tun_setmtu(mtu) == 0) {
223                                                return 0;
224                                        } else {
225                                                warn("Received handshake with bad data");
226                                        }
227                                } else {
228                                        printf("Received bad handshake\n");
229                                }
230                        }
231                }
232
233                printf("Retrying login...\n");
234        }
235
236        return 1;
237}
238
239static void
240usage() {
241        extern char *__progname;
242
243        printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
244                        "nameserver topdomain\n", __progname);
245        exit(2);
246}
247
248static void
249help() {
250        extern char *__progname;
251
252        printf("iodine IP over DNS tunneling client\n");
253        printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] "
254                        "nameserver topdomain\n", __progname);
255        printf("  -v to print version info and exit\n");
256        printf("  -h to print this help and exit\n");
257        printf("  -f to keep running in foreground\n");
258        printf("  -u name to drop privileges and run as user 'name'\n");
259        printf("  -t dir to chroot to directory dir\n");
260        printf("  -d device to set tunnel device name\n");
261        printf("nameserver is the IP number of the relaying nameserver\n");
262        printf("topdomain is the FQDN that is delegated to the tunnel endpoint.\n");
263        exit(0);
264}
265
266static void
267version() {
268        char *svnver = "$Rev$ from $Date$";
269        printf("iodine IP over DNS tunneling client\n");
270        printf("SVN version: %s\n", svnver);
271        exit(0);
272}
273
274int
275main(int argc, char **argv)
276{
277        struct passwd *pw;
278        char *username;
279        int foreground;
280        char *newroot;
281        char *device;
282        int choice;
283        int tun_fd;
284        int dns_fd;
285
286        username = NULL;
287        memset(password, 0, 33);
288        foreground = 0;
289        newroot = NULL;
290        device = NULL;
291       
292        while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) {
293                switch(choice) {
294                case 'v':
295                        version();
296                        break;
297                case 'f':
298                        foreground = 1;
299                        break;
300                case 'h':
301                        help();
302                        break;
303                case 'u':
304                        username = optarg;
305                        break;
306                case 't':
307                        newroot = optarg;
308                        break;
309                case 'd':
310                        device = optarg;
311                        break;
312                case 'P':
313                        strncpy(password, optarg, 32);
314                        password[32] = 0;
315                        break;
316                default:
317                        usage();
318                        break;
319                }
320        }
321       
322        if (geteuid() != 0) {
323                printf("Run as root and you'll be happy.\n");
324                usage();
325        }
326
327        argc -= optind;
328        argv += optind;
329       
330        if (argc != 2)
331                usage();
332       
333        if(username) {
334                pw = getpwnam(username);
335                if (!pw) {
336                        printf("User %s does not exist!\n", username);
337                        usage();
338                }
339        }
340       
341        if (strlen(password) == 0) {
342                printf("Enter password on stdin:\n");
343                scanf("%32s", password);
344                password[32] = 0;
345        }
346
347        if ((tun_fd = open_tun(device)) == -1)
348                goto cleanup1;
349        dns_set_topdomain(argv[1]);
350        if ((dns_fd = open_dns(0, INADDR_ANY)) == -1)
351                goto cleanup2;
352        if (dns_settarget(argv[0]) == -1)
353                goto cleanup2;
354
355        signal(SIGINT, sighandler);
356        signal(SIGTERM, sighandler);
357
358        if(handshake(dns_fd))
359                goto cleanup2;
360       
361        printf("Sending queries for %s to %s\n", argv[1], argv[0]);
362
363        if (newroot) {
364                if (chroot(newroot) != 0 || chdir("/") != 0)
365                        err(1, "%s", newroot);
366                seteuid(geteuid());
367                setuid(getuid());
368        }
369       
370        if (!foreground) {
371                printf("Detaching from terminal...\n");
372                daemon(0, 0);
373                umask(0);
374                alarm(0);
375        }
376       
377        if (username) {
378                if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
379                        printf("Could not switch to user %s!\n", username);
380                        usage();
381                }
382        }
383
384        tunnel(tun_fd, dns_fd);
385
386cleanup2:
387        close_dns(dns_fd);
388        close_tun(tun_fd);
389cleanup1:
390
391        return 0;
392}
Note: See TracBrowser for help on using the repository browser.