source: trunk/src/ocat.c @ 411

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

SOCKS destination IP configurable

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