1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2017 Joyent, Inc.
14 */
15
16 #include <pthread.h>
17 #include <errno.h>
18 #include <err.h>
19 #include <signal.h>
20 #include <port.h>
21 #include <bunyan.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <libgen.h>
25 #include <sys/types.h>
26 #include <sys/debug.h>
27 #include <locale.h>
28 #include <ucontext.h>
29 #include "pkcs11.h"
30 #include "defs.h"
31 #include "timer.h"
32 #include "worker.h"
33 #include "config.h"
34
35 extern void pkt_init(void);
36 extern void pkt_fini(void);
37 extern void ikev2_sa_init(void);
38 extern void random_init(void);
39 extern void pfkey_init(void);
40
41 static void signal_init(void);
42 static void event(event_t, void *);
43 static void do_signal(int);
44 static void main_loop(void);
45
46 static const char *port_source_str(ushort_t);
47 static const char *event_str(event_t);
48
49 static boolean_t done;
50 static pthread_t signal_tid;
51
52 bunyan_logger_t *log = NULL;
53 int port = -1;
54
55 static void
56 usage(const char *name)
57 {
58 (void) fprintf(stderr, "Usage: %s [-d] [-f cfgfile]\n"
59 " %s -c [-f cfgfile]\n", name, name);
60 exit(1);
61 }
62
63 int
64 main(int argc, char **argv)
65 {
66 FILE *f = NULL;
67 char *cfgfile = "/etc/inet/ike/config";
68 int c, rc;
69 boolean_t debug_mode = B_FALSE;
70 boolean_t check_cfg = B_FALSE;
71
72 (void) setlocale(LC_ALL, "");
73 #if !defined(TEXT_DOMAIN)
74 #define TEXT_DOMAIN "SYS_TEST"
75 #endif
76 (void) textdomain(TEXT_DOMAIN);
77
78 while ((c = getopt(argc, argv, "cdf:")) != -1) {
79 switch (c) {
80 case 'd':
81 debug_mode = B_TRUE;
82 break;
83 case 'c':
84 check_cfg = B_TRUE;
85 break;
86 case 'f':
87 cfgfile = optarg;
88 break;
89 case '?':
90 (void) fprintf(stderr,
91 "Unrecognized option: -%c\n", optopt);
92 usage(argv[0]);
93 break;
94 }
95 }
96
97 if (check_cfg && debug_mode) {
98 (void) fprintf(stderr, "-d and -c options cannot both be "
99 "set\n");
100 usage(argv[0]);
101 return (1);
102 }
103
104 if ((rc = bunyan_init(basename(argv[0]), &log)) < 0)
105 errx(EXIT_FAILURE, "bunyan_init() failed: %s", strerror(errno));
106
107 /* hard coded just during development */
108 if ((rc = bunyan_stream_add(log, "stdout", BUNYAN_L_TRACE,
109 bunyan_stream_fd, (void *)STDOUT_FILENO)) < 0)
110 errx(EXIT_FAILURE, "bunyan_stream_add() failed: %s",
111 strerror(errno));
112
113 if ((f = fopen(cfgfile, "rF")) == NULL)
114 STDERR(fatal, log, "cannot open config file",
115 BUNYAN_T_STRING, "filename", cfgfile);
116
117 process_config(f, check_cfg, log);
118
119 (void) fclose(f);
120
121 if ((port = port_create()) < 0)
122 STDERR(fatal, log, "port_create() failed");
123
124 signal_init();
125 random_init();
126 pkcs11_init();
127 pkt_init();
128 ike_timer_init();
129 pfkey_init();
130
131 /* XXX: make these configurable */
132 worker_init(8, 8);
133
134 main_loop();
135
136 pkt_fini();
137 pkcs11_fini();
138
139 return (0);
140 }
141
142 static void
143 main_loop(void)
144 {
145 port_event_t pe;
146 int rc;
147
148 (void) bunyan_trace(log, "starting main loop", BUNYAN_T_END);
149
150 /*CONSTCOND*/
151 while (!done) {
152 if (port_get(port, &pe, NULL) < 0) {
153 STDERR(error, log, "port_get() failed");
154 continue;
155 }
156
157 switch (pe.portev_source) {
158 case PORT_SOURCE_USER:
159 (void) bunyan_trace(log, "received event",
160 BUNYAN_T_STRING, "source",
161 port_source_str(pe.portev_source),
162 BUNYAN_T_UINT32, "source val",
163 (uint32_t)pe.portev_events,
164 BUNYAN_T_STRING, "event",
165 event_str(pe.portev_events),
166 BUNYAN_T_UINT32, "event num",
167 (int32_t)pe.portev_events,
168 BUNYAN_T_POINTER, "event arg", pe.portev_user,
169 BUNYAN_T_END);
170 event(pe.portev_events, pe.portev_user);
171 break;
172
173 case PORT_SOURCE_FD: {
174 char buf[128] = { 0 };
175 (void) addrtosymstr(pe.portev_user, buf, sizeof (buf));
176
177 (void) bunyan_trace(log, "received event",
178 BUNYAN_T_STRING, "source",
179 port_source_str(pe.portev_source),
180 BUNYAN_T_UINT32, "source val",
181 (uint32_t)pe.portev_events,
182 BUNYAN_T_INT32, "fd", (int32_t)pe.portev_object,
183 BUNYAN_T_STRING, "cb", buf,
184 BUNYAN_T_POINTER, "cbval", pe.portev_user,
185 BUNYAN_T_END);
186
187 void (*fn)(int) = (void (*)(int))pe.portev_user;
188 int fd = (int)pe.portev_object;
189 fn(fd);
190 break;
191 }
192
193 case PORT_SOURCE_ALERT:
194 (void) bunyan_trace(log, "received event",
195 BUNYAN_T_STRING, "source",
196 port_source_str(pe.portev_source),
197 BUNYAN_T_UINT32, "source val",
198 (uint32_t)pe.portev_events,
199 BUNYAN_T_END);
200 break;
201
202 default:
203 INVALID("pe.portev_source");
204 }
205 }
206
207 (void) bunyan_info(log, "Exiting", BUNYAN_T_END);
208 }
209
210 static void
211 event(event_t evt, void *arg)
212 {
213 switch (evt) {
214 case EVENT_NONE:
215 return;
216 case EVENT_SIGNAL:
217 do_signal((int)(uintptr_t)arg);
218 break;
219 }
220 }
221
222 void
223 reload(void)
224 {
225 }
226
227 void
228 schedule_socket(int fd, void (*cb)(int, void *))
229 {
230 if (port_associate(port, PORT_SOURCE_FD, fd, POLLIN, cb) < 0)
231 STDERR(error, log, "port_associate() failed");
232 }
233
234 static void
235 do_signal(int signum)
236 {
237 switch (signum) {
238 case SIGINT:
239 case SIGTERM:
240 case SIGQUIT:
241 done = B_TRUE;
242 break;
243 case SIGHUP:
244 reload();
245 break;
246 case SIGUSR1:
247 (void) worker_add();
248 break;
249 case SIGUSR2:
250 (void) worker_del();
251 break;
252 default:
253 break;
254 }
255 }
256
257 /*ARGSUSED*/
258 static void *
259 signal_thread(void *arg)
260 {
261 char sigbuf[SIG2STR_MAX + 3]; /* add room for 'SIG' */
262 sigset_t sigset;
263 int signo, ret;
264
265 bunyan_trace(log, "signal thread awaiting signals", BUNYAN_T_END);
266
267 (void) sigfillset(&sigset);
268
269 /*CONSTCOND*/
270 while (1) {
271 if (sigwait(&sigset, &signo) != 0) {
272 STDERR(error, log, "sigwait() failed");
273 continue;
274 }
275
276 (void) memset(sigbuf, 0, sizeof (sigbuf));
277 (void) strlcat(sigbuf, "SIG", sizeof (sigbuf));
278 sig2str(signo, sigbuf + 3);
279
280 (void) bunyan_info(log, "signal received",
281 BUNYAN_T_STRING, "signal", sigbuf,
282 BUNYAN_T_INT32, "signum", (int32_t)signo,
283 BUNYAN_T_END);
284
285 if (port_send(port, EVENT_SIGNAL, (void *)(uintptr_t)signo) < 0)
286 STDERR(error, log, "port_send() failed");
287 }
288
289 /*NOTREACHED*/
290 return (NULL);
291 }
292
293 static void
294 signal_init(void)
295 {
296 pthread_attr_t attr;
297 sigset_t nset;
298
299 /* block all signals in main thread */
300 (void) sigfillset(&nset);
301 (void) pthread_sigmask(SIG_SETMASK, &nset, NULL);
302
303 PTH(pthread_attr_init(&attr));
304 PTH(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
305 PTH(pthread_create(&signal_tid, &attr, signal_thread, NULL));
306 PTH(pthread_attr_destroy(&attr));
307 }
308
309 static const char *
310 port_source_str(ushort_t src)
311 {
312 #define STR(x) case x: return (#x)
313
314 switch (src) {
315 STR(PORT_SOURCE_AIO);
316 STR(PORT_SOURCE_FD);
317 STR(PORT_SOURCE_MQ);
318 STR(PORT_SOURCE_TIMER);
319 STR(PORT_SOURCE_USER);
320 STR(PORT_SOURCE_ALERT);
321 STR(PORT_SOURCE_FILE);
322 default:
323 return ("UNKNOWN");
324 }
325 #undef STR
326 }
327
328 static const char *
329 event_str(event_t evt)
330 {
331 #define STR(x) case x: return (#x)
332
333 switch (evt) {
334 STR(EVENT_NONE);
335 STR(EVENT_SIGNAL);
336 default:
337 return ("UNKNOWN");
338 }
339 }
340
341 bunyan_logfn_t
342 getlog(bunyan_level_t level)
343 {
344 switch (level) {
345 case BUNYAN_L_TRACE:
346 return (bunyan_trace);
347 case BUNYAN_L_DEBUG:
348 return (bunyan_debug);
349 case BUNYAN_L_INFO:
350 return (bunyan_info);
351 case BUNYAN_L_WARN:
352 return (bunyan_warn);
353 case BUNYAN_L_ERROR:
354 return (bunyan_error);
355 case BUNYAN_L_FATAL:
356 return (bunyan_fatal);
357 }
358
359 return (NULL);
360 }
361
362 extern uint32_t ss_port(const struct sockaddr_storage *);
363 extern const void *ss_addr(const struct sockaddr_storage *);
364 extern int ss_bunyan(const struct sockaddr_storage *);