chiark / gitweb /
uslip: New program providing a fake SLIP interface.
[tripe] / server / tripe.c
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
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * TrIPE is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with TrIPE; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include "tripe.h"
30
31 /*----- Global variables --------------------------------------------------*/
32
33 sel_state sel;
34
35 /*----- Static variables --------------------------------------------------*/
36
37 static sel_timer it;
38 #define T_INTERVAL MIN(1)
39
40 /*----- Main code ---------------------------------------------------------*/
41
42 /* --- @interval@ --- *
43  *
44  * Arguments:   @struct timeval *tv@ = time when called
45  *              @void *v@ = boring pointer
46  *
47  * Returns:     ---
48  *
49  * Use:         Called periodically to do housekeeping tasks.
50  */
51
52 static void interval(struct timeval *tv, void *v)
53 {
54   struct timeval tvv;
55   T( trace(T_PEER, "peer: interval timer"); )
56   rand_seed(RAND_GLOBAL, MAXHASHSZ);
57   p_interval();
58   tvv = *tv;
59   tvv.tv_sec += T_INTERVAL;
60   sel_addtimer(&sel, &it, &tvv, interval, v);
61 }
62
63 /* --- @main@ --- *
64  *
65  * Arguments:   @int argc@ = number of command line arguments
66  *              @char *argv[]@ = vector of arguments
67  *
68  * Returns:     Zero if OK, nonzero on error.
69  *
70  * Use:         Main program.  Provides a simple VPN.
71  */
72
73 static void usage(FILE *fp)
74 {
75   pquis(fp, "Usage: $ [-D] [-d DIR] [-b ADDR] [-p PORT] [-n TUNNEL]\n\
76         [-U USER] [-G GROUP] [-a SOCKET] [-T TRACE-OPTS]\n\
77         [-k PRIV-KEYRING] [-K PUB-KEYRING] [-t KEY-TAG]\n");
78 }
79
80 static void version(FILE *fp) { pquis(fp, "$, version " VERSION "\n"); }
81
82 static void help(FILE *fp)
83 {
84   version(fp);
85   fputc('\n', fp);
86   usage(fp);
87   fputs("\n\
88 Options:\n\
89 \n\
90 -h, --help              Display this help text.\n\
91 -v, --version           Display version number.\n\
92 -u, --usage             Display pointless usage message.\n\
93     --tunnels           Display IP tunnel drivers and exit.\n\
94 \n\
95 -D, --daemon            Run in the background.\n\
96 -d, --directory=DIR     Switch to directory DIR [default " CONFIGDIR "].\n\
97 -b, --bind-address=ADDR Bind UDP socket to this IP ADDR.\n\
98 -p, --port=PORT         Select UDP port to listen to "
99         "[default " STR(TRIPE_PORT) "].\n\
100 -n, --tunnel=TUNNEL     Seelect default tunnel driver.\n\
101 -U, --setuid=USER       Set uid to USER after initialization.\n\
102 -G, --setgid=GROUP      Set gid to GROUP after initialization.\n\
103 -k, --priv-keyring=FILE Get private key from FILE.\n\
104 -K, --pub-keyring=FILE  Get public keys from FILE.\n\
105 -t, --tag=KEYTAG        Use private key labelled TAG.\n\
106 -a, --admin-socket=FILE Use FILE as the adminstration socket.\n\
107 " T( "\
108 -T, --trace=OPTIONS     Turn on tracing options.\n\
109 " ) "\
110 ", fp);
111 }
112
113 int main(int argc, char *argv[])
114 {
115   const char *kr_priv = "keyring", *kr_pub = "keyring.pub";
116   const char *tag_priv = "tripe-dh";
117   const char *csock = SOCKETDIR "/tripesock";
118   const char *dir = CONFIGDIR;
119   const char *p;
120   unsigned port = TRIPE_PORT;
121   struct in_addr baddr = { INADDR_ANY };
122   unsigned f = 0;
123   int i;
124   int selerr = 0;
125   struct timeval tv;
126   uid_t u = -1;
127   gid_t g = -1;
128
129 #define f_bogus 1u
130 #define f_daemon 2u
131
132   ego(argv[0]);
133   T( trace_on(stderr, 0); )
134
135   if ((p = getenv("TRIPEDIR")) != 0)
136     dir = p;
137   if ((p = getenv("TRIPESOCK")) != 0)
138     csock = p;
139   tun_default = tunnels[0];
140
141   for (;;) {
142     static const struct option opts[] = {
143       { "help",         0,              0,      'h' },
144       { "version",      0,              0,      'v' },
145       { "usage",        0,              0,      'u' },
146       { "tunnels",      0,              0,      '0' },
147
148       { "daemon",       0,              0,      'D' },
149       { "uid",          OPTF_ARGREQ,    0,      'U' },
150       { "setuid",       OPTF_ARGREQ,    0,      'U' },
151       { "gid",          OPTF_ARGREQ,    0,      'G' },
152       { "setgid",       OPTF_ARGREQ,    0,      'G' },
153       { "bind-address", OPTF_ARGREQ,    0,      'b' },
154       { "tunnel",       OPTF_ARGREQ,    0,      'n' },
155       { "port",         OPTF_ARGREQ,    0,      'p' },
156       { "directory",    OPTF_ARGREQ,    0,      'd' },
157       { "priv-keyring", OPTF_ARGREQ,    0,      'k' },
158       { "pub-keyring",  OPTF_ARGREQ,    0,      'K' },
159       { "tag",          OPTF_ARGREQ,    0,      't' },
160       { "admin-socket", OPTF_ARGREQ,    0,      'a' },
161 #ifndef NTRACE
162       { "trace",        OPTF_ARGREQ,    0,      'T' },
163 #endif
164
165       { 0,              0,              0,      0 }
166     };
167
168     i = mdwopt(argc, argv, "hvuDU:G:b:p:d:k:K:t:a:" T("T:"),
169                opts, 0, 0, 0);
170     if (i < 0)
171       break;
172     switch (i) {
173       case 'h':
174         help(stdout);
175         exit(0);
176       case 'v':
177         version(stdout);
178         exit(0);
179       case 'u':
180         usage(stdout);
181         exit(0);
182
183       case 'D':
184         f |= f_daemon;
185         break;
186       case 'U':
187         u = u_getuser(optarg, &g);
188         break;
189       case 'G':
190         g = u_getgroup(optarg);
191         break;
192
193       case 'b': {
194         struct hostent *h = gethostbyname(optarg);
195         if (!h)
196           die(EXIT_FAILURE, "unknown host name `%s'", optarg);
197         memcpy(&baddr, h->h_addr, sizeof(struct in_addr));
198       } break;
199       case 'p': {
200         char *p;
201         unsigned long i = strtoul(optarg, &p, 0);
202         if (*p) {
203           struct servent *s = getservbyname(optarg, "udp");
204           if (!s)
205             die(EXIT_FAILURE, "unknown service name `%s'", optarg);
206           i = ntohs(s->s_port);
207         }
208         if (i >= 65536)
209           die(EXIT_FAILURE, "bad port number %lu", i);
210         port = i;
211       } break;
212       case 'n': {
213         int i;
214         for (i = 0;; i++) {
215           if (!tunnels[i])
216             die(EXIT_FAILURE, "unknown tunnel `%s'", optarg);
217           if (mystrieq(optarg, tunnels[i]->name))
218             break;
219         }
220         tun_default = tunnels[i];
221       } break;
222       case 'd':
223         dir = optarg;
224         break;
225       case 'k':
226         kr_priv = optarg;
227         break;
228       case 'K':
229         kr_pub = optarg;
230         break;
231       case 'a':
232         csock = optarg;
233         break;
234       case 't':
235         tag_priv = optarg;
236         break;
237 #ifndef NTRACE
238       case 'T':
239         tr_flags = traceopt(tr_opts, optarg, tr_flags, 0);
240         trace_level(tr_flags);
241         break;
242 #endif
243       case '0': {
244         int i;
245         for (i = 0; tunnels[i]; i++)
246           puts(tunnels[i]->name);
247         exit(0);
248       } break;
249       default:
250         f |= f_bogus;
251         break;
252     }
253   }
254
255   if (optind < argc || (f & f_bogus)) {
256     usage(stderr);
257     exit(EXIT_FAILURE);
258   }
259
260   if (chdir(dir)) {
261     die(EXIT_FAILURE, "can't set current directory to `%s': %s",
262         dir, strerror(errno));
263   }
264
265   sel_init(&sel);
266   sig_init(&sel);
267   rand_noisesrc(RAND_GLOBAL, &noise_source);
268   rand_seed(RAND_GLOBAL, MAXHASHSZ);
269   signal(SIGPIPE, SIG_IGN);
270   for (i = 0; tunnels[i]; i++)
271     tunnels[i]->init();
272   p_init(baddr, port);
273   if (!(f & f_daemon)) {
274 #ifndef NTRACE
275     a_create(STDIN_FILENO, STDOUT_FILENO, AF_TRACE | AF_WARN);
276 #else
277     a_create(STDIN_FILENO, STDOUT_FILENO, AF_WARN);
278 #endif
279   }
280   u_setugid(u, g);
281   km_init(kr_priv, kr_pub, tag_priv);
282   a_init(csock);
283   if (f & f_daemon) {
284     if (daemonize())
285       die(EXIT_FAILURE, "couldn't become a daemon: %s", strerror(errno));
286     a_daemon();
287   }
288
289   tv.tv_sec = time(0) + T_INTERVAL;
290   tv.tv_usec = 0;
291   sel_addtimer(&sel, &it, &tv, interval, 0);
292
293   for (;;) {
294     a_preselect();
295     if (!sel_select(&sel))
296       selerr = 0;
297     else if (errno != EINTR && errno != EAGAIN) {
298       a_warn("SERVER", "select-error", "?ERRNO", A_END);
299       selerr++;
300       if (selerr > 8) {
301         a_warn("ABORT", "repeated-select-errors", A_END);
302         abort();
303       }
304     }
305   }
306
307   return (0);
308 }
309
310 /*----- That's all, folks -------------------------------------------------*/