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 *);