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 (c) 2017 Joyent, Inc.
  14  */
  15 
  16 /*
  17  * Designed to be backgrounded and just killed. Open a PF_KEY socket, do
  18  * an extended-REGISTER so the kernel will send extended-ACQUIRE messages,
  19  * and then read-and-discard everything off the socket.
  20  */
  21 
  22 #include <sys/socket.h>
  23 #include <net/pfkeyv2.h>
  24 #include <stdio.h>
  25 #include <errno.h>
  26 #include <err.h>
  27 #include <unistd.h>
  28 
  29 /* ARGSUSED */
  30 int
  31 main(int argc, char *argv[])
  32 {
  33         int s, rc;
  34         uint64_t buf[1024];     /* PF_KEY likes 64-bit alignment. */
  35         sadb_msg_t *samsg;
  36         sadb_x_ereg_t *ereg;
  37         boolean_t ah_ack, esp_ack;
  38         pid_t pid = getpid();
  39 
  40         s = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
  41         if (s == -1)
  42                 err(-1, "socket(PF_KEY)");
  43 
  44         /* Base message. */
  45         samsg = (sadb_msg_t *)buf;
  46         ereg = (sadb_x_ereg_t *)(samsg + 1);
  47         samsg->sadb_msg_version = PF_KEY_V2;
  48         samsg->sadb_msg_type = SADB_REGISTER;
  49         samsg->sadb_msg_errno = 0;
  50         samsg->sadb_msg_satype = SADB_SATYPE_UNSPEC;
  51         samsg->sadb_msg_reserved = 0;
  52         samsg->sadb_msg_seq = 1;
  53         samsg->sadb_msg_pid = pid;
  54         samsg->sadb_msg_len = SADB_8TO64(sizeof (*samsg) + sizeof (*ereg));
  55 
  56         /* extended REGISTER so we can listen for extended ACQUIREs. */
  57         ereg->sadb_x_ereg_len = SADB_8TO64(sizeof (*ereg));
  58         ereg->sadb_x_ereg_exttype = SADB_X_EXT_EREG;
  59         ereg->sadb_x_ereg_satypes[0] = SADB_SATYPE_ESP;
  60         ereg->sadb_x_ereg_satypes[1] = SADB_SATYPE_AH;
  61         ereg->sadb_x_ereg_satypes[2] = SADB_SATYPE_UNSPEC;
  62 
  63         rc = write(s, buf, sizeof (*samsg) + sizeof (*ereg));
  64         if (rc == -1)
  65                 err(-1, "Extended register write error");
  66 
  67         /*
  68          * Extended REGISTER expects a regular REGISTER reply for EACH protocol
  69          * requested.  In our case, AH and ESP.
  70          */
  71         do {
  72 
  73                 do {
  74                         rc = read(s, buf, sizeof (buf));
  75                         if (rc == -1)
  76                                 err(-1, "Extended register read error");
  77 
  78                 } while (samsg->sadb_msg_seq != 1 ||
  79                     samsg->sadb_msg_pid != pid ||
  80                     samsg->sadb_msg_type != SADB_REGISTER);
  81 
  82                 if (samsg->sadb_msg_errno != 0) {
  83                         if (samsg->sadb_msg_errno == EPROTONOSUPPORT) {
  84                                 warn("Protocol %d not supported.",
  85                                     samsg->sadb_msg_satype);
  86                         } else {
  87                                 errno = samsg->sadb_msg_errno;
  88                                 err(-1, "Extended REGISTER returned");
  89                         }
  90                 }
  91 
  92                 switch (samsg->sadb_msg_satype) {
  93                 case SADB_SATYPE_ESP:
  94                         esp_ack = B_TRUE;
  95                         break;
  96                 case SADB_SATYPE_AH:
  97                         ah_ack = B_TRUE;
  98                         break;
  99                 default:
 100                         err(-1, "Bad satype in extended register ACK %d.",
 101                             samsg->sadb_msg_satype);
 102                 }
 103         } while (!esp_ack || !ah_ack);
 104 
 105         /* Expect this loop to never end. This program ends via signal. */
 106         do {
 107                 rc = read(s, buf, sizeof (buf));
 108         } while (rc != -1);
 109 
 110         err(-1, "PF_KEY read error");
 111 }