source: trunk/src/ocat.c @ 347

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

added background option
added pid file creation
added optional logfile

File size: 10.4 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, setup.create_clog, setup.debug_level, setup.ocat_listen_port,
69         setup.pid_file,
70         setup.ocat_dest_port, setup.tor_socks_port, 
71#ifndef WITHOUT_TUN
72         TUN_DEV,
73#endif
74         OCAT_UNAME, setup.ipv4_enable
75            );
76}
77
78
79void open_logfile(void)
80{
81   if (setup.logfn)
82   {
83      if ((setup.logf = fopen(setup.logfn, "a")))
84      {
85         log_debug("logfile %s opened", setup.logfn);
86         if (setvbuf(setup.logf, NULL, _IOLBF, 0))
87            log_msg(L_ERROR, "could not setup line buffering: %s", strerror(errno));
88         fflush(setup.logf);
89         return;
90      }
91      setup.logf = stderr;
92      log_msg(L_ERROR, "could not open logfile %s: %s. Defaulting to stderr", setup.logfn, strerror(errno));
93   }
94}
95
96
97int mk_pid_file(void)
98{
99   FILE *f;
100
101   if (!(f = fopen(setup.pid_file, "w")))
102   {
103      log_msg(L_ERROR, "could not create pid_file %s: %s", setup.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", setup.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            setup.create_clog = 1;
152            break;
153
154         case 'b':
155            setup.daemon = 1;
156            break;
157
158         case 'C':
159            setup.controller = 0;
160            break;
161
162         case 'd':
163            setup.debug_level = atoi(optarg);
164            break;
165
166         case 'f':
167            setup.config_file = optarg;
168            setup.config_read = 0;
169            break;
170
171         case 'i':
172            urlconv = 1;
173            break;
174
175         case 'l':
176            setup.ocat_listen_port = atoi(optarg);
177            break;
178
179         case 'L':
180            setup.logfn = optarg;
181            break;
182
183         case 'o':
184            urlconv = 2;
185            break;
186
187         case 'p':
188            setup.use_tap = 1;
189            break;
190
191         case 'P':
192            setup.pid_file = optarg;
193            break;
194
195         case 'r':
196            runasroot = 1;
197            setup.usrname = "root";
198            break;
199
200         case 's':
201            setup.ocat_dest_port = atoi(optarg);
202            break;
203
204         case 't':
205            setup.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            setup.usrname = optarg;
216            break;
217
218         case '4':
219            setup.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], &setup.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(&setup.ocat_addr))
241         log_msg(L_ERROR, "address does not have TOR prefix"), exit(1);
242      ipv6tonion(&setup.ocat_addr, setup.onion_url);
243      printf("%s.onion\n", setup.onion_url);
244      exit(0);
245   }
246
247   // convert parameter to IPv6 address
248   strncpy(setup.onion_url, argv[optind], ONION_NAME_SIZE);
249   if ((s = strchr(setup.onion_url, '.')))
250         *s = '\0';
251   if (strlen(setup.onion_url) != 16)
252      log_msg(L_ERROR, "parameter seems not to be valid onion hostname"), exit(1);
253   if (oniontipv6(setup.onion_url, &setup.ocat_addr) == -1)
254      log_msg(L_ERROR, "parameter seems not to be valid onion hostname"), exit(1);
255   if (setup.ipv4_enable)
256      oniontipv4(setup.onion_url, &setup.ocat_addr4, ntohl(setup.ocat_addr4_mask));
257
258   inet_ntop(AF_INET6, &setup.ocat_addr, ip6addr, INET6_ADDRSTRLEN);
259
260   if (urlconv == 1)
261   {
262      printf("%s\n", ip6addr);
263      if (setup.ipv4_enable)
264         printf("%s\n", inet_ntoa(setup.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 (setup.config_file)
272   {
273      log_msg(L_NOTICE, "reading config file %s", setup.config_file);
274      if ((c = open(setup.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(&setup.ocat_hwaddr[3], &setup.ocat_addr.s6_addr[13], 3);
281   if (setup.use_tap);
282   {
283      log_msg(L_NOTICE, "MAC address %02x:%02x:%02x:%02x:%02x:%02x",
284            setup.ocat_hwaddr[0], setup.ocat_hwaddr[1], setup.ocat_hwaddr[2], setup.ocat_hwaddr[3], setup.ocat_hwaddr[4], setup.ocat_hwaddr[5]);
285      /*if (pipe(setup.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   setup.tunfd[0] = setup.tunfd[1] = tun_alloc(tunname, setup.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 (setup.ipv4_enable)
298      log_msg(L_NOTICE, "IP address %s", inet_ntoa(setup.ocat_addr4));
299 
300   log_debug("tun frameheader v6 = 0x%08x, v4 = 0x%08x", ntohl(setup.fhd_key[IPV6_KEY]), ntohl(setup.fhd_key[IPV4_KEY]));
301
302   // daemonize of required
303   if (setup.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(setup.usrname)))
316      log_msg(L_FATAL, "can't get information for user \"%s\": \"%s\"", setup.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)", setup.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 (setup.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 (setup.controller)
345      run_ocat_thread("controller", ocat_controller, NULL);
346
347   // reading config file
348   if (setup.config_file)
349   {
350      log_msg(L_NOTICE, "reading config file %s", setup.config_file);
351      if ((c = open(setup.config_file, O_RDONLY)) == -1)
352         log_msg(L_ERROR, "error opening file: %s", strerror(errno)), exit(1);
353      ctrl_handler((void*) c);
354   }
355
356   // start forwarding packets from tunnel
357   log_msg(L_NOTICE, "starting packet forwarder");
358   packet_forwarder();
359
360   return 0;
361}
362
Note: See TracBrowser for help on using the repository browser.