[svn-inject] Installing original source of iodine
[debian/iodine.git] / iodined.c
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 <pwd.h>
30 #include <arpa/inet.h>
31 #include <netinet/in.h>
32 #include <zlib.h>
33
34 #include "tun.h"
35 #include "structs.h"
36 #include "dns.h"
37
38 #ifndef MAX
39 #define MAX(a,b) ((a)>(b)?(a):(b))
40 #endif
41
42 int running = 1;
43
44 struct packet packetbuf;
45 struct packet outpacket;
46 int outid;
47
48 struct query q;
49
50 int my_mtu;
51 in_addr_t my_ip;
52
53 static void
54 sigint(int sig) {
55         running = 0;
56 }
57
58 static int
59 tunnel(int tun_fd, int dns_fd)
60 {
61         struct in_addr clientip;
62         struct in_addr myip;
63         struct timeval tv;
64         char out[64*1024];
65         char in[64*1024];
66         char *tmp[2];
67         long outlen;
68         fd_set fds;
69         int read;
70         int code;
71         int i;
72
73         while (running) {
74                 if (q.id != 0) {
75                         tv.tv_sec = 0;
76                         tv.tv_usec = 5000;
77                 } else {
78                         tv.tv_sec = 1;
79                         tv.tv_usec = 0;
80                 }
81
82                 FD_ZERO(&fds);
83                 if(outpacket.len == 0)
84                         FD_SET(tun_fd, &fds);
85                 FD_SET(dns_fd, &fds);
86
87                 i = select(MAX(tun_fd, dns_fd) + 1, &fds, NULL, NULL, &tv);
88                 
89                 if(i < 0) {
90                         if (running) 
91                                 warn("select");
92                         return 1;
93                 }
94         
95                 if (i==0) {     
96                         if (q.id != 0) {
97                                 dnsd_send(dns_fd, &q, outpacket.data, outpacket.len);
98                                 outpacket.len = 0;
99                                 q.id = 0;
100                         }
101                 } else {
102                         if(FD_ISSET(tun_fd, &fds)) {
103                                 read = read_tun(tun_fd, in, sizeof(in));
104                                 if (read <= 0)
105                                         continue;
106                                 
107                                 outlen = sizeof(out);
108                                 compress2(out, &outlen, in, read, 9);
109                                 memcpy(outpacket.data, out, outlen);
110                                 outpacket.len = outlen;
111                         }
112                         if(FD_ISSET(dns_fd, &fds)) {
113                                 read = dnsd_read(dns_fd, &q, in, sizeof(in));
114                                 if (read <= 0)
115                                         continue;
116
117                                 if(in[0] == 'H' || in[0] == 'h') {
118                                         myip.s_addr = my_ip;    
119                                         clientip.s_addr = my_ip + inet_addr("0.0.0.1");
120
121                                         tmp[0] = strdup(inet_ntoa(myip));
122                                         tmp[1] = strdup(inet_ntoa(clientip));
123                                         
124                                         read = snprintf(out, sizeof(out), "%s-%s-%d", 
125                                                         tmp[0], tmp[1], my_mtu);
126
127                                         dnsd_send(dns_fd, &q, out, read);
128                                         q.id = 0;
129
130                                         free(tmp[1]);
131                                         free(tmp[0]);
132                                 } else if((in[0] >= '0' && in[0] <= '9')
133                                                 || (in[0] >= 'a' && in[0] <= 'f')
134                                                 || (in[0] >= 'A' && in[0] <= 'F')) {
135                                         if ((in[0] >= '0' && in[0] <= '9'))
136                                                 code = in[0] - '0';
137                                         if ((in[0] >= 'a' && in[0] <= 'f'))
138                                                 code = in[0] - 'a' + 10;
139                                         if ((in[0] >= 'A' && in[0] <= 'F'))
140                                                 code = in[0] - 'A' + 10;
141
142                                         memcpy(packetbuf.data + packetbuf.offset, in + 1, read - 1);
143                                         packetbuf.len += read - 1;
144                                         packetbuf.offset += read - 1;
145
146                                         if (code & 1) {
147                                                 outlen = sizeof(out);
148                                                 uncompress(out, &outlen, packetbuf.data, packetbuf.len);
149
150                                                 write_tun(tun_fd, out, outlen);
151
152                                                 packetbuf.len = packetbuf.offset = 0;
153                                         }
154                                 }
155                                 if (outpacket.len > 0) {
156                                         dnsd_send(dns_fd, &q, outpacket.data, outpacket.len);
157                                         outpacket.len = 0;
158                                         q.id = 0;
159                                 }
160                         } 
161                 }
162         }
163
164         return 0;
165 }
166
167 static void
168 usage() {
169         extern char *__progname;
170
171         printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] [-l ip address to listen on] [-p port]"
172                         " tunnel_ip topdomain\n", __progname);
173         exit(2);
174 }
175
176 static void
177 help() {
178         extern char *__progname;
179
180         printf("iodine IP over DNS tunneling server\n");
181         printf("Usage: %s [-v] [-h] [-f] [-u user] [-t chrootdir] [-d device] [-m mtu] [-l ip address to listen on] [-p port]"
182                    " tunnel_ip topdomain\n", __progname);
183         printf("  -v to print version info and exit\n");
184         printf("  -h to print this help and exit\n");
185         printf("  -f to keep running in foreground\n");
186         printf("  -u name to drop privileges and run as user 'name'\n");
187         printf("  -t dir to chroot to directory dir\n");
188         printf("  -d device to set tunnel device name\n");
189         printf("  -m mtu to set tunnel device mtu\n");
190         printf("  -l ip address to listen on for incoming dns traffic (default 0.0.0.0)\n");
191         printf("  -p port to listen on for incoming dns traffic (default 53)\n");
192         printf("tunnel_ip is the IP number of the local tunnel interface.\n");
193         printf("topdomain is the FQDN that is delegated to this server.\n");
194         exit(0);
195 }
196
197 static void
198 version() {
199         printf("iodine IP over DNS tunneling server\n");
200         printf("version: 0.3.4 from 2006-11-08\n");
201         exit(0);
202 }
203
204 int
205 main(int argc, char **argv)
206 {
207         int choice;
208         int tun_fd;
209         int dnsd_fd;
210         char *newroot;
211         char *username;
212         char *device;
213         int foreground;
214         int mtu;
215         struct passwd *pw;
216         in_addr_t listen_ip;
217         int port;
218
219         username = NULL;
220         newroot = NULL;
221         device = NULL;
222         foreground = 0;
223         mtu = 1024;
224         listen_ip = INADDR_ANY;
225         port = 53;
226
227         packetbuf.len = 0;
228         packetbuf.offset = 0;
229         outpacket.len = 0;
230         q.id = 0;
231         
232         while ((choice = getopt(argc, argv, "vfhu:t:d:m:l:p:")) != -1) {
233                 switch(choice) {
234                 case 'v':
235                         version();
236                         break;
237                 case 'f':
238                         foreground = 1;
239                         break;
240                 case 'h':
241                         help();
242                         break;
243                 case 'u':
244                         username = optarg;
245                         break;
246                 case 't':
247                         newroot = optarg;
248                         break;
249                 case 'd':
250                         device = optarg;
251                         break;
252                 case 'm':
253                         mtu = atoi(optarg);
254                         break;
255                 case 'l':
256                         listen_ip = inet_addr(optarg);
257                         break;
258                 case 'p':
259                         port = atoi(optarg);
260                         break;
261                 default:
262                         usage();
263                         break;
264                 }
265         }
266
267         argc -= optind;
268         argv += optind;
269         
270         if (geteuid() != 0) {
271                 printf("Run as root and you'll be happy.\n");
272                 usage();
273         }
274
275         if (argc != 2) 
276                 usage();
277
278         if (username) {
279                 pw = getpwnam(username);
280                 if (!pw) {
281                         printf("User %s does not exist!\n", username);
282                         usage();
283                 }
284         }
285
286         if (mtu == 0) {
287                 printf("Bad MTU given.\n");
288                 usage();
289         }
290
291         if (listen_ip == INADDR_NONE) {
292                 printf("Bad IP address to listen on.\n");
293                 usage();
294         }
295
296         if ((tun_fd = open_tun(device)) == -1)
297                 goto cleanup0;
298         if (tun_setip(argv[0]) != 0 || tun_setmtu(mtu) != 0)
299                 goto cleanup1;
300         if ((dnsd_fd = open_dns(argv[1], port, listen_ip)) == -1) 
301                 goto cleanup2;
302
303         my_ip = inet_addr(argv[0]);
304         my_mtu = mtu;
305
306         printf("Listening to dns for domain %s\n", argv[1]);
307
308         if (newroot) {
309                 if (chroot(newroot) != 0 || chdir("/") != 0)
310                         err(1, "%s", newroot);
311                 seteuid(geteuid());
312                 setuid(getuid());
313         }
314         
315         if (!foreground) {
316                 printf("Detaching from terminal...\n");
317                 daemon(0, 0);
318                 umask(0);
319                 alarm(0);
320         }
321
322         signal(SIGINT, sigint);
323         if (username) {
324                 if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
325                         printf("Could not switch to user %s!\n", username);
326                         usage();
327                 }
328         }
329         
330         tunnel(tun_fd, dnsd_fd);
331
332 cleanup2:
333         close_dns(dnsd_fd);
334 cleanup1:
335         close_tun(tun_fd);      
336 cleanup0:
337
338         return 0;
339 }