* New upstream release:
[debian/iodine.git] / src / common.c
1 /* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
2  * Copyright (c) 2007 Albert Lee <trisk@acm.jhu.edu>.
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 <time.h>
18 #include <sys/types.h>
19 #include <sys/param.h>
20 #include <sys/stat.h>
21 #include <stdio.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <stdint.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <fcntl.h>
29 #include <errno.h>
30
31 #ifdef WINDOWS32
32 #include <winsock2.h>
33 #include <conio.h>
34 #else
35 #include <arpa/nameser.h>
36 #ifdef DARWIN
37 #define BIND_8_COMPAT
38 #include <arpa/nameser_compat.h>
39 #endif
40 #include <termios.h>
41 #include <err.h>
42 #include <arpa/inet.h>
43 #include <netinet/in.h>
44 #include <syslog.h>
45 #endif
46
47 #ifdef HAVE_SETCON
48 # include <selinux/selinux.h>
49 #endif
50
51 #include "common.h"
52
53 /* The raw header used when not using DNS protocol */
54 const unsigned char raw_header[RAW_HDR_LEN] = { 0x10, 0xd1, 0x9e, 0x00 };
55
56 /* daemon(3) exists only in 4.4BSD or later, and in GNU libc */
57 #if !defined(WINDOWS32) && !(defined(BSD) && (BSD >= 199306)) && !defined(__GLIBC__)
58 static int daemon(int nochdir, int noclose)
59 {
60         int fd, i;
61  
62         switch (fork()) {
63                 case 0:
64                         break;
65                 case -1:
66                         return -1;
67                 default:
68                         _exit(0);
69         }
70  
71         if (!nochdir) {
72                 chdir("/");
73         }
74  
75         if (setsid() < 0) {
76                 return -1;
77         }
78         
79         if (!noclose) {
80                 if ((fd = open("/dev/null", O_RDWR)) >= 0) {
81                         for (i = 0; i < 3; i++) {
82                                 dup2(fd, i);
83                         }
84                         if (fd > 2) {
85                                 close(fd);
86                         }
87                 }
88         }
89         return 0;
90 }
91 #endif
92
93 #if defined(__BEOS__) && !defined(__HAIKU__)
94 int setgroups(int count, int *groups)
95 {
96         /* errno = ENOSYS; */
97         return -1;
98 }
99 #endif
100
101
102 void
103 check_superuser(void (*usage_fn)(void))
104 {
105 #ifndef WINDOWS32
106         if (geteuid() != 0) {
107                 warnx("Run as root and you'll be happy.\n");
108                 usage_fn();
109                 /* NOTREACHED */
110         }
111 #endif
112 }
113
114 int 
115 open_dns(int localport, in_addr_t listen_ip) 
116 {
117         struct sockaddr_in addr;
118         int flag = 1;
119         int fd;
120
121         memset(&addr, 0, sizeof(addr));
122         addr.sin_family = AF_INET;
123         addr.sin_port = htons(localport);
124         /* listen_ip already in network byte order from inet_addr, or 0 */
125         addr.sin_addr.s_addr = listen_ip; 
126
127         if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
128                 fprintf(stderr, "got fd %d\n", fd);
129                 err(1, "socket");
130         }
131
132         flag = 1;
133 #ifdef SO_REUSEPORT
134         setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (const void*) &flag, sizeof(flag));
135 #endif
136         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void*) &flag, sizeof(flag));
137
138 #ifndef WINDOWS32
139         /* To get destination address from each UDP datagram, see iodined.c:read_dns() */
140         setsockopt(fd, IPPROTO_IP, DSTADDR_SOCKOPT, (const void*) &flag, sizeof(flag));
141 #endif
142
143 #ifdef IP_OPT_DONT_FRAG
144         /* Set dont-fragment ip header flag */
145         flag = DONT_FRAG_VALUE;
146         setsockopt(fd, IPPROTO_IP, IP_OPT_DONT_FRAG, (const void*) &flag, sizeof(flag));
147 #endif
148
149         if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) 
150                 err(1, "bind");
151
152         fprintf(stderr, "Opened UDP socket\n");
153
154         return fd;
155 }
156
157 void
158 close_dns(int fd)
159 {
160         close(fd);
161 }
162
163 void
164 do_chroot(char *newroot)
165 {
166 #if !(defined(WINDOWS32) || defined(__BEOS__) || defined(__HAIKU__))
167         if (chroot(newroot) != 0 || chdir("/") != 0)
168                 err(1, "%s", newroot);
169
170         seteuid(geteuid());
171         setuid(getuid());
172 #else
173         warnx("chroot not available");
174 #endif
175 }
176
177 void
178 do_setcon(char *context)
179 {
180 #ifdef HAVE_SETCON
181         if (-1 == setcon(context))
182                 err(1, "%s", context);
183 #else
184         warnx("No SELinux support built in");
185 #endif
186 }
187
188 void
189 do_pidfile(char *pidfile)
190 {
191 #ifndef WINDOWS32
192         FILE *file;
193
194         if ((file = fopen(pidfile, "w")) == NULL) {
195                 syslog(LOG_ERR, "Cannot write pidfile to %s, exiting", pidfile);
196                 err(1, "do_pidfile: Can not write pidfile to %s", pidfile);
197         } else {
198                 fprintf(file, "%d\n", (int)getpid());
199                 fclose(file);
200         }
201 #else
202         fprintf(stderr, "Windows version does not support pid file\n");
203 #endif
204 }
205
206 void
207 do_detach()
208 {
209 #ifndef WINDOWS32
210         fprintf(stderr, "Detaching from terminal...\n");
211         daemon(0, 0);
212         umask(0);
213         alarm(0);
214 #else
215         fprintf(stderr, "Windows version does not support detaching\n");
216 #endif
217 }
218
219 void
220 read_password(char *buf, size_t len)
221 {
222         char pwd[80];
223 #ifndef WINDOWS32
224         struct termios old;
225         struct termios tp;
226
227         tcgetattr(0, &tp);
228         old = tp;
229         
230         tp.c_lflag &= (~ECHO);
231         tcsetattr(0, TCSANOW, &tp);
232 #else
233         int i;
234 #endif
235
236         fprintf(stderr, "Enter password: ");
237         fflush(stderr);
238 #ifndef WINDOWS32
239         scanf("%79s", pwd);
240 #else
241         for (i = 0; i < sizeof(pwd); i++) {
242                 pwd[i] = getch();
243                 if (pwd[i] == '\r' || pwd[i] == '\n') {
244                         pwd[i] = 0;
245                         break;
246                 } else if (pwd[i] == '\b') {
247                         i--;                    /* Remove the \b char */
248                         if (i >=0) i--;         /* If not first char, remove one more */
249                 }
250         }
251 #endif
252         fprintf(stderr, "\n");
253
254 #ifndef WINDOWS32
255         tcsetattr(0, TCSANOW, &old);    
256 #endif
257
258         strncpy(buf, pwd, len);
259         buf[len-1] = '\0';
260 }
261
262 int
263 check_topdomain(char *str)
264 {
265        int i;
266
267        if(str[0] == '.') /* special case */
268                return 1;
269
270        for( i = 0; i < strlen(str); i++) {
271                if( isalpha(str[i]) || isdigit(str[i]) || str[i] == '-' || str[i] == '.' )
272                        continue;
273                else 
274                        return 1;
275        }
276        return 0;
277 }
278
279 #ifdef WINDOWS32
280 int
281 inet_aton(const char *cp, struct in_addr *inp)
282 {
283  inp->s_addr = inet_addr(cp);
284  return inp->s_addr != INADDR_ANY;
285 }
286
287 void
288 warn(const char *fmt, ...)
289 {
290         va_list list;
291
292         va_start(list, fmt);
293         if (fmt) fprintf(stderr, fmt, list);
294         if (errno == 0) {
295                 fprintf(stderr, ": WSA error %d\n", WSAGetLastError()); 
296         } else {
297                 fprintf(stderr, ": %s\n", strerror(errno));
298         }
299         va_end(list);
300 }
301
302 void
303 warnx(const char *fmt, ...)
304 {
305         va_list list;
306
307         va_start(list, fmt);
308         if (fmt) fprintf(stderr, fmt, list);
309         fprintf(stderr, "\n");
310         va_end(list);
311 }
312
313 void
314 err(int eval, const char *fmt, ...)
315 {
316         va_list list;
317
318         va_start(list, fmt);
319         warn(fmt, list);
320         va_end(list);
321         exit(eval);
322 }
323
324 void
325 errx(int eval, const char *fmt, ...)
326 {
327         va_list list;
328
329         va_start(list, fmt);
330         warnx(fmt, list);
331         va_end(list);
332         exit(eval);
333 }
334 #endif
335
336
337 int recent_seqno(int ourseqno, int gotseqno)
338 /* Return 1 if we've seen gotseqno recently (current or up to 3 back).
339    Return 0 if gotseqno is new (or very old).
340 */
341 {
342         int i;
343         for (i = 0; i < 4; i++, ourseqno--) {
344                 if (ourseqno < 0)
345                         ourseqno = 7;
346                 if (gotseqno == ourseqno)
347                         return 1;
348         }
349         return 0;
350 }