source: trunk/src/ocat.c @ 365

Last change on this file since 365 was 365, checked in by eagle, 8 years ago

replaced setup by CNF() and setup_

File size: 10.5 KB
Line 
1/* Copyright 2008 Bernhard R. Fischer, Daniel Haslinger.
2 *
3 * This file is part of OnionCat.
4 *
5 * OnionCat is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License.
8 *
9 * OnionCat is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with OnionCat. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <string.h>
24#include <stdarg.h>
25#include <arpa/inet.h>
26#include <sys/socket.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#include <pwd.h>
31#include <errno.h>
32#include <time.h>
33#include <pthread.h>
34#ifdef HAVE_NET_IF_H
35#include <net/if.h>
36#endif
37
38#include "ocat.h"
39
40
41void usage(const char *s)
42{
43   fprintf(stderr, 
44         "%s (c) Bernhard R. Fischer -- compiled %s %s\n"
45         "usage: %s [OPTIONS] <onion_hostname>\n"
46         "   -a                    create connect log at \"$HOME/%s/%s\" (default = %d)\n"
47         "   -b                    daemonize\n"
48         "   -h                    display usage message\n"
49         "   -C                    disable local controller interface\n"
50         "   -d <n>                set debug level to n, default = %d\n"
51         "   -f <config_file>      read config from config_file\n"
52         "   -i                    convert onion hostname to IPv6 and exit\n"
53         "   -l <port>             set ocat listen port, default = %d\n"
54         "   -L <log_file>         log output to <log_file> (default = stderr)\n"
55         "   -o <ipv6_addr>        convert IPv6 address to onion url and exit\n"
56         "   -p                    use TAP device instead of TUN\n"
57         "   -P <pid_file>         create pid file at location of <pid_file> (default = %s)\n"
58         "   -r                    run as root, i.e. do not change uid/gid\n"
59         "   -s <port>             set hidden service virtual port, default = %d\n"
60         "   -t <port>             set tor SOCKS port, default = %d\n"
61#ifndef WITHOUT_TUN
62         "   -T <tun_device>       path to tun character device, default = \"%s\"\n"
63#endif
64         "   -u <user>             change UID to user, default = \"%s\"\n"
65         "   -4                    enable IPv4 support (default = %d)\n"
66         , PACKAGE_STRING, __DATE__, __TIME__, s,
67         // option defaults start here
68         OCAT_DIR, OCAT_CONNECT_LOG, CNF(create_clog), CNF(debug_level), CNF(ocat_listen_port),
69         CNF(pid_file),
70         CNF(ocat_dest_port), CNF(tor_socks_port), 
71#ifndef WITHOUT_TUN
72         TUN_DEV,
73#endif
74         OCAT_UNAME, CNF(ipv4_enable)
75            );
76}
77
78
79void open_logfile(void)
80{
81   if (CNF(logfn))
82   {
83      if ((CNF(logf) = fopen(CNF(logfn), "a")))
84      {
85         log_debug("logfile %s opened", CNF(logfn));
86         if (setvbuf(CNF(logf), NULL, _IOLBF, 0))
87            log_msg(L_ERROR, "could not setup line buffering: %s", strerror(errno));
88         fflush(CNF(logf));
89         return;
90      }
91      CNF(logf) = stderr;
92      log_msg(L_ERROR, "could not open logfile %s: %s. Defaulting to stderr", CNF(logfn), strerror(errno));
93   }
94}
95
96
97int mk_pid_file(void)
98{
99   FILE *f;
100
101   if (!(f = fopen(CNF(pid_file), "w")))
102   {
103      log_msg(L_ERROR, "could not create pid_file %s: %s", CNF(pid_file), strerror(errno));
104      return -1;
105   }
106
107   fprintf(f, "%d\n", getpid());
108   fclose(f);
109   log_debug("pid_file %s created, pid = %d", CNF(pid_file), getpid());
110
111   return 0;
112}
113
114
115void background(void)
116{
117   log_msg(L_NOTICE, "backgrounding");
118
119   switch(fork())
120   {
121      case -1:
122         log_msg(L_ERROR, "fork failed: %s. Staying in foreground", strerror(errno));
123         return;
124
125      case 0:
126         log_debug("child successfully forked");
127         return;
128
129      default:
130         exit(0);
131   }
132}
133
134
135int main(int argc, char *argv[])
136{
137   char tunname[IFNAMSIZ] = {0}, *s, ip6addr[INET6_ADDRSTRLEN];
138   int c, runasroot = 0;
139   struct passwd *pwd;
140   int urlconv = 0;
141
142   init_setup();
143
144   if (argc < 2)
145      usage(argv[0]), exit(1);
146
147   while ((c = getopt(argc, argv, "abCd:f:hriopl:t:T:s:u:4L:P:")) != -1)
148      switch (c)
149      {
150         case 'a':
151            CNF(create_clog) = 1;
152            break;
153
154         case 'b':
155            CNF(daemon) = 1;
156            break;
157
158         case 'C':
159            CNF(controller) = 0;
160            break;
161
162         case 'd':
163            CNF(debug_level) = atoi(optarg);
164            break;
165
166         case 'f':
167            CNF(config_file) = optarg;
168            CNF(config_read) = 0;
169            break;
170
171         case 'i':
172            urlconv = 1;
173            break;
174
175         case 'l':
176            CNF(ocat_listen_port) = atoi(optarg);
177            break;
178
179         case 'L':
180            CNF(logfn) = optarg;
181            break;
182
183         case 'o':
184            urlconv = 2;
185            break;
186
187         case 'p':
188            CNF(use_tap) = 1;
189            break;
190
191         case 'P':
192            CNF(pid_file) = optarg;
193            break;
194
195         case 'r':
196            runasroot = 1;
197            CNF(usrname) = "root";
198            break;
199
200         case 's':
201            CNF(ocat_dest_port) = atoi(optarg);
202            break;
203
204         case 't':
205            CNF(tor_socks_port) = atoi(optarg);
206            break;
207
208#ifndef WITHOUT_TUN
209         case 'T':
210            tun_dev_ = optarg;
211            break;
212#endif
213
214         case 'u':
215            CNF(usrname) = optarg;
216            break;
217
218         case '4':
219            CNF(ipv4_enable) = 1;
220            break;
221
222         case 'h':
223         default:
224            usage(argv[0]);
225            exit(1);
226      }
227
228   if (!argv[optind])
229      usage(argv[0]), exit(1);
230
231   // init main thread
232   (void) init_ocat_thread("main");
233
234   if (urlconv == 2)
235   {
236      if ((c = inet_pton(AF_INET6, argv[optind], &CNF(ocat_addr))) < 0)
237         log_msg(L_ERROR, "inet_pton failed: %s", strerror(errno)), exit(1);
238      else if (!c)
239         log_msg(L_ERROR, "%s is not a valid IPv6 address", argv[optind]), exit(1);
240      if (!has_tor_prefix(&CNF(ocat_addr)))
241         log_msg(L_ERROR, "address does not have TOR prefix"), exit(1);
242      ipv6tonion(&CNF(ocat_addr), CNF(onion_url));
243      printf("%s.onion\n", CNF(onion_url));
244      exit(0);
245   }
246
247   // convert parameter to IPv6 address
248   strncpy(CNF(onion_url), argv[optind], ONION_NAME_SIZE);
249   if ((s = strchr(CNF(onion_url), '.')))
250         *s = '\0';
251   if (strlen(CNF(onion_url)) != 16)
252      log_msg(L_ERROR, "parameter seems not to be valid onion hostname"), exit(1);
253   if (oniontipv6(CNF(onion_url), &CNF(ocat_addr)) == -1)
254      log_msg(L_ERROR, "parameter seems not to be valid onion hostname"), exit(1);
255   if (CNF(ipv4_enable))
256      oniontipv4(CNF(onion_url), &CNF(ocat_addr4), ntohl(CNF(ocat_addr4_mask)));
257
258   inet_ntop(AF_INET6, &CNF(ocat_addr), ip6addr, INET6_ADDRSTRLEN);
259
260   if (urlconv == 1)
261   {
262      printf("%s\n", ip6addr);
263      if (CNF(ipv4_enable))
264         printf("%s\n", inet_ntoa(CNF(ocat_addr4)));
265      exit(0);
266   }
267
268   log_msg(L_NOTICE, "%s (c) Bernhard R. Fischer -- compiled %s %s", PACKAGE_STRING, __DATE__, __TIME__);
269
270#if 0
271   if (CNF(config_file))
272   {
273      log_msg(L_NOTICE, "reading config file %s", CNF(config_file));
274      if ((c = open(CNF(config_file), O_RDONLY)) == -1)
275         log_msg(L_ERROR, "error opening file: %s", strerror(errno)), exit(1);
276      ctrl_handler((void*) c);
277   }
278#endif
279
280   memcpy(&CNF(ocat_hwaddr[3]), &CNF(ocat_addr.s6_addr[13]), 3);
281   if (CNF(use_tap));
282   {
283      log_msg(L_NOTICE, "MAC address %02x:%02x:%02x:%02x:%02x:%02x",
284            CNF(ocat_hwaddr[0]), CNF(ocat_hwaddr[1]), CNF(ocat_hwaddr[2]), CNF(ocat_hwaddr[3]), CNF(ocat_hwaddr[4]), CNF(ocat_hwaddr[5]));
285      /*if (pipe(CNF(icmpv6fd)) == -1)
286         log_msg(L_FATAL, "cannot create multicast pipe: %s", strerror(errno)), exit(1);
287      run_ocat_thread("icmpv6", icmpv6_handler, NULL);*/
288   }
289
290#ifndef WITHOUT_TUN
291   // create TUN device
292   CNF(tunfd[0]) = CNF(tunfd[1]) = tun_alloc(tunname, CNF(ocat_addr));
293#endif
294
295   log_msg(L_NOTICE, "IPv6 address %s", ip6addr);
296   log_msg(L_NOTICE, "TUN/TAP device %s", tunname);
297   if (CNF(ipv4_enable))
298      log_msg(L_NOTICE, "IP address %s", inet_ntoa(CNF(ocat_addr4)));
299 
300   log_debug("tun frameheader v6 = 0x%08x, v4 = 0x%08x", ntohl(CNF(fhd_key[IPV6_KEY])), ntohl(CNF(fhd_key[IPV4_KEY])));
301
302   // daemonize of required
303   if (CNF(daemon))
304      background();
305
306   // start socket receiver thread
307   run_ocat_thread("receiver", socket_receiver, NULL);
308   // create listening socket and start socket acceptor
309   run_ocat_thread("acceptor", socket_acceptor, NULL);
310   // starting socket cleaner
311   run_ocat_thread("cleaner", socket_cleaner, NULL);
312
313   // getting passwd info for user
314   errno = 0;
315   if (!(pwd = getpwnam(CNF(usrname))))
316      log_msg(L_FATAL, "can't get information for user \"%s\": \"%s\"", CNF(usrname), errno ? strerror(errno) : "user not found"), exit(1);
317
318   // create pid_file
319   mk_pid_file();
320
321   if (!runasroot && !getuid())
322   {
323      log_msg(L_NOTICE, "running as root, changing uid/gid to %s (uid %d/gid %d)", CNF(usrname), pwd->pw_uid, pwd->pw_gid);
324      if (setgid(pwd->pw_gid))
325         log_msg(L_ERROR, "could not change gid: \"%s\"", strerror(errno)), exit(1);
326      if (setuid(pwd->pw_uid))
327         log_msg(L_ERROR, "could not change uid: \"%d\"", strerror(errno)), exit(1);
328   }
329   log_debug("uid/gid = %d/%d", getuid(), getgid());
330
331   // opening logfile
332   open_logfile();
333
334   if (CNF(create_clog))
335      open_connect_log(pwd->pw_dir);
336
337   // create socks connector thread
338   run_ocat_thread("connector", socks_connector, NULL);
339#ifdef PACKET_QUEUE
340   // start packet dequeuer
341   run_ocat_thread("dequeuer", packet_dequeuer, NULL);
342#endif
343   // start controller socket thread
344   if (CNF(controller))
345      run_ocat_thread("controller", ocat_controller, NULL);
346
347   // initiate connections to permanent root peers
348   log_debug("connecting root peers");
349   for (c = 0; c < ROOT_PEERS; c++)
350      socks_queue(&CNF(root_peer[c]), 1);
351
352   // reading config file
353   if (CNF(config_file))
354   {
355      log_msg(L_NOTICE, "reading config file %s", CNF(config_file));
356      if ((c = open(CNF(config_file), O_RDONLY)) == -1)
357         log_msg(L_ERROR, "error opening file: %s", strerror(errno)), exit(1);
358      ctrl_handler((void*) c);
359   }
360
361   // start forwarding packets from tunnel
362   log_msg(L_NOTICE, "starting packet forwarder");
363   packet_forwarder();
364
365   return 0;
366}
367
Note: See TracBrowser for help on using the repository browser.