server/: Build a proper interface for handling tunnel classes.
[tripe] / server / tripe.c
... / ...
CommitLineData
1/* -*-c-*-
2 *
3 * Main program
4 *
5 * (c) 2001 Straylight/Edgeware
6 */
7
8/*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of Trivial IP Encryption (TrIPE).
11 *
12 * TrIPE is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 3 of the License, or (at your
15 * option) any later version.
16 *
17 * TrIPE is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
24 */
25
26/*----- Header files ------------------------------------------------------*/
27
28#include "tripe.h"
29
30/*----- Global variables --------------------------------------------------*/
31
32sel_state sel;
33
34/*----- Static variables --------------------------------------------------*/
35
36static sel_timer it;
37#define T_INTERVAL MIN(1)
38
39static unsigned iv_nreasons = 0;
40static struct timeval iv_next = { 0, 0 };
41static int lpdone = 0;
42
43/*----- The interval timer ------------------------------------------------*/
44
45/* --- @interval@ --- *
46 *
47 * Arguments: @struct timeval *tv@ = time when called
48 * @void *v@ = boring pointer
49 *
50 * Returns: ---
51 *
52 * Use: Called periodically to do housekeeping tasks.
53 */
54
55static void interval(struct timeval *tv, void *v)
56{
57 T( trace(T_PEER, "peer: interval timer"); )
58 iv_next = *tv;
59 rand_seed(RAND_GLOBAL, MAXHASHSZ);
60 p_interval();
61 iv_next.tv_sec += T_INTERVAL;
62 sel_addtimer(&sel, &it, &iv_next, interval, v);
63}
64
65/* --- @iv_addreason@ --- *
66 *
67 * Arguments: ---
68 *
69 * Returns: ---
70 *
71 * Use: Adds an `interval timer reason'; if there are no others, the
72 * interval timer is engaged.
73 */
74
75void iv_addreason(void)
76{
77 struct timeval tv;
78
79 if (!iv_nreasons) {
80 gettimeofday(&tv, 0);
81 if (TV_CMP(&tv, >=, &iv_next)) interval(&tv, 0);
82 else sel_addtimer(&sel, &it, &iv_next, interval, 0);
83 }
84 iv_nreasons++;
85}
86
87/* --- @iv_rmreason@ --- *
88 *
89 * Arguments: ---
90 *
91 * Returns: ---
92 *
93 * Use: Removes an interval timer reason; if there are none left, the
94 * interval timer is disengaged.
95 */
96
97void iv_rmreason(void)
98{
99 assert(iv_nreasons); iv_nreasons--;
100 if (!iv_nreasons) sel_rmtimer(&it);
101}
102
103/*----- The main loop -----------------------------------------------------*/
104
105/* --- @lp_init@ --- *
106 *
107 * Arguments: ---
108 *
109 * Returns: ---
110 *
111 * Use: Initializes the main loop. Most importantly, this sets up
112 * the select multiplexor that everything else hooks onto.
113 */
114
115void lp_init(void)
116{
117 rand_noisesrc(RAND_GLOBAL, &noise_source);
118 rand_seed(RAND_GLOBAL, MAXHASHSZ);
119 gettimeofday(&iv_next, 0); iv_next.tv_sec += T_INTERVAL;
120 signal(SIGPIPE, SIG_IGN);
121 sel_init(&sel);
122 sig_init(&sel);
123}
124
125/* --- @lp_end@ --- *
126 *
127 * Arguments: ---
128 *
129 * Returns: ---
130 *
131 * Use: Requests an exit from the main loop.
132 */
133
134void lp_end(void) { lpdone = 1; }
135
136/* --- @lp_run@ --- *
137 *
138 * Arguments: ---
139 *
140 * Returns: Zero on successful termination; @-1@ if things went wrong.
141 *
142 * Use: Cranks the main loop until it should be cranked no more.
143 */
144
145int lp_run(void)
146{
147 int nerr = 0;
148
149 for (;;) {
150 a_preselect();
151 if (lpdone) break;
152 if (!sel_select(&sel)) nerr = 0;
153 else if (errno != EINTR && errno != EAGAIN) {
154 a_warn("SERVER", "select-error", "?ERRNO", A_END);
155 nerr++;
156 if (nerr > 8) {
157 a_warn("ABORT", "repeated-select-errors", A_END);
158 abort();
159 }
160 }
161 }
162 lpdone = 0;
163 return (0);
164}
165
166/*----- Tunnel table ------------------------------------------------------*/
167
168static const tunnel_ops *tunnels[] = {
169#ifdef TUN_LINUX
170 &tun_linux,
171#endif
172#ifdef TUN_BSD
173 &tun_bsd,
174#endif
175#ifdef TUN_UNET
176 &tun_unet,
177#endif
178 &tun_slip,
179};
180
181/*----- Main code ---------------------------------------------------------*/
182
183/* --- @main@ --- *
184 *
185 * Arguments: @int argc@ = number of command line arguments
186 * @char *argv[]@ = vector of arguments
187 *
188 * Returns: Zero if OK, nonzero on error.
189 *
190 * Use: Main program. Provides a simple VPN.
191 */
192
193static void usage(FILE *fp)
194{
195 pquis(fp, "Usage: $ [-DF] [-d DIR] [-b ADDR] [-p PORT] [-n TUNNEL]\n\
196 [-U USER] [-G GROUP] [-a SOCKET] [-m MODE] [-T TRACE-OPTS]\n\
197 [-k PRIV-KEYRING] [-K PUB-KEYRING] [-t KEY-TAG]\n");
198}
199
200static void version(FILE *fp) { pquis(fp, "$, version " VERSION "\n"); }
201
202static void help(FILE *fp)
203{
204 version(fp);
205 fputc('\n', fp);
206 usage(fp);
207 fputs("\n\
208Options:\n\
209\n\
210-h, --help Display this help text.\n\
211-v, --version Display version number.\n\
212-u, --usage Display pointless usage message.\n\
213 --tunnels Display IP tunnel drivers and exit.\n\
214\n\
215-4, --ipv4 Transport over IPv4 only.\n\
216-6, --ipv6 Transport over IPv6 only.\n\
217-D, --daemon Run in the background.\n\
218-F, --foreground Quit when stdin reports end-of-file.\n\
219-d, --directory=DIR Switch to directory DIR [default " CONFIGDIR "].\n\
220-b, --bind-address=ADDR Bind UDP socket to this IP ADDR.\n\
221-p, --port=PORT Select UDP port to listen to "
222 "[default " STR(TRIPE_PORT) "].\n\
223-n, --tunnel=TUNNEL Seelect default tunnel driver.\n\
224-U, --setuid=USER Set uid to USER after initialization.\n\
225-G, --setgid=GROUP Set gid to GROUP after initialization.\n\
226-k, --priv-keyring=FILE Get private key from FILE.\n\
227-K, --pub-keyring=FILE Get public keys from FILE.\n\
228-t, --tag=KEYTAG Use private key labelled TAG.\n\
229-a, --admin-socket=FILE Use FILE as the adminstration socket.\n\
230-m, --admin-perms=MODE Permissions to set on admin socket [default 600].\n\
231" T( "\
232-T, --trace=OPTIONS Turn on tracing options.\n\
233" ) "\
234", fp);
235}
236
237int main(int argc, char *argv[])
238{
239 const char *kr_priv = "keyring", *kr_pub = "keyring.pub";
240 const char *tag_priv = 0;
241 const char *csock = SOCKETDIR "/tripesock";
242 int csockmode = 0600;
243 const char *dir = CONFIGDIR;
244 const char *p;
245 const char *bindhost = 0, *bindsvc = STR(TRIPE_PORT);
246 struct addrinfo aihint = { 0 }, *ailist;
247 const tunnel_ops *dflt = 0;
248 unsigned f = 0;
249 int i;
250 int err;
251 unsigned af;
252 uid_t u = -1;
253 gid_t g = -1;
254
255#define f_bogus 1u
256#define f_daemon 2u
257#define f_foreground 4u
258
259 ego(argv[0]);
260 T( trace_on(stderr, 0); )
261
262 if ((p = getenv("TRIPEDIR")) != 0)
263 dir = p;
264 if ((p = getenv("TRIPESOCK")) != 0)
265 csock = p;
266 aihint.ai_family = AF_UNSPEC;
267
268 for (;;) {
269 static const struct option opts[] = {
270 { "help", 0, 0, 'h' },
271 { "version", 0, 0, 'v' },
272 { "usage", 0, 0, 'u' },
273 { "tunnels", 0, 0, '0' },
274
275 { "ipv4", 0, 0, '4' },
276 { "ipv6", 0, 0, '6' },
277 { "daemon", 0, 0, 'D' },
278 { "foreground", 0, 0, 'F' },
279 { "uid", OPTF_ARGREQ, 0, 'U' },
280 { "setuid", OPTF_ARGREQ, 0, 'U' },
281 { "gid", OPTF_ARGREQ, 0, 'G' },
282 { "setgid", OPTF_ARGREQ, 0, 'G' },
283 { "bind-address", OPTF_ARGREQ, 0, 'b' },
284 { "tunnel", OPTF_ARGREQ, 0, 'n' },
285 { "port", OPTF_ARGREQ, 0, 'p' },
286 { "directory", OPTF_ARGREQ, 0, 'd' },
287 { "priv-keyring", OPTF_ARGREQ, 0, 'k' },
288 { "pub-keyring", OPTF_ARGREQ, 0, 'K' },
289 { "tag", OPTF_ARGREQ, 0, 't' },
290 { "admin-socket", OPTF_ARGREQ, 0, 'a' },
291 { "admin-perms", OPTF_ARGREQ, 0, 'm' },
292#ifndef NTRACE
293 { "trace", OPTF_ARGREQ, 0, 'T' },
294#endif
295
296 { 0, 0, 0, 0 }
297 };
298
299 i = mdwopt(argc, argv, "hvu46DFU:G:b:n:p:d:k:K:t:a:m:" T("T:"),
300 opts, 0, 0, 0);
301 if (i < 0)
302 break;
303 switch (i) {
304 case 'h':
305 help(stdout);
306 exit(0);
307 case 'v':
308 version(stdout);
309 exit(0);
310 case 'u':
311 usage(stdout);
312 exit(0);
313
314 case '4':
315 aihint.ai_family = AF_INET;
316 break;
317 case '6':
318 aihint.ai_family = AF_INET6;
319 break;
320 case 'D':
321 f |= f_daemon;
322 break;
323 case 'U':
324 u = u_getuser(optarg, &g);
325 break;
326 case 'G':
327 g = u_getgroup(optarg);
328 break;
329 case 'F':
330 f |= f_foreground;
331 break;
332
333 case 'b':
334 bindhost = optarg;
335 break;
336 case 'p':
337 bindsvc = optarg;
338 break;
339 case 'n': {
340 int i;
341 for (i = 0; i < N(tunnels); i++)
342 if (mystrieq(optarg, tunnels[i]->name))
343 { dflt = tunnels[i]; goto found_tun; }
344 die(EXIT_FAILURE, "unknown tunnel `%s'", optarg);
345 found_tun:;
346 } break;
347 case 'd':
348 dir = optarg;
349 break;
350 case 'k':
351 kr_priv = optarg;
352 break;
353 case 'K':
354 kr_pub = optarg;
355 break;
356 case 'a':
357 csock = optarg;
358 break;
359 case 'm': {
360 char *p;
361 csockmode = strtol(optarg, &p, 8);
362 if (*p) die(EXIT_FAILURE, "bad permissions: `%s'", optarg);
363 } break;
364 case 't':
365 tag_priv = optarg;
366 break;
367#ifndef NTRACE
368 case 'T':
369 tr_flags = traceopt(tr_opts, optarg, tr_flags, 0);
370 trace_level(tr_flags);
371 break;
372#endif
373 case '0': {
374 int i;
375 for (i = 0; i < N(tunnels); i++)
376 puts(tunnels[i]->name);
377 exit(0);
378 } break;
379 default:
380 f |= f_bogus;
381 break;
382 }
383 }
384
385 if (optind < argc || (f & f_bogus)) {
386 usage(stderr);
387 exit(EXIT_FAILURE);
388 }
389 if (!(~f & (f_daemon | f_foreground)))
390 die(EXIT_FAILURE, "foreground operation for a daemon is silly");
391
392 aihint.ai_protocol = IPPROTO_UDP;
393 aihint.ai_socktype = SOCK_DGRAM;
394 aihint.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
395 if ((err = getaddrinfo(bindhost, bindsvc, &aihint, &ailist)) != 0) {
396 die(EXIT_FAILURE, "couldn't resolve hostname %c%s%c, port `%s': %s",
397 bindhost ? '`' : '<',
398 bindhost ? bindhost : "nil",
399 bindhost ? '\'' : '>',
400 bindsvc, gai_strerror(err));
401 }
402
403 if (chdir(dir)) {
404 die(EXIT_FAILURE, "can't set current directory to `%s': %s",
405 dir, strerror(errno));
406 }
407
408 lp_init();
409
410 if (!(f & f_daemon)) {
411 af = AF_WARN;
412#ifndef NTRACE
413 af |= AF_TRACE;
414#endif
415 if (f & f_foreground)
416 af |= AF_FOREGROUND;
417 a_create(STDIN_FILENO, STDOUT_FILENO, af);
418 a_switcherr();
419 }
420
421 p_init();
422 for (i = 0; i < N(tunnels); i++)
423 p_addtun(tunnels[i]);
424 if (dflt) p_setdflttun(dflt);
425 p_bind(ailist); freeaddrinfo(ailist);
426
427 for (i = 0; tunnels[i]; i++) {
428 if (tunnels[i]->flags&TUNF_PRIVOPEN) {
429 ps_split(f & f_daemon);
430 break;
431 }
432 }
433
434 a_init();
435 a_signals();
436 a_listen(csock, u, g, csockmode);
437 u_setugid(u, g);
438 km_init(kr_priv, kr_pub, tag_priv);
439 kx_init();
440 if (f & f_daemon) {
441 if (daemonize()) {
442 a_warn("SERVER", "daemon-error", "?ERRNO", A_END);
443 exit(EXIT_FAILURE);
444 }
445 a_daemon();
446 a_switcherr();
447 }
448
449 lp_run();
450
451 p_destroyall();
452 p_unbind();
453 a_unlisten();
454 km_clear();
455 ps_quit();
456 return (0);
457}
458
459/*----- That's all, folks -------------------------------------------------*/