1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* kdc/t_sockact.c - socket activation test harness */ 3 /* 4 * Copyright (C) 2025 by the Massachusetts Institute of Technology. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * * Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 30 * OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Usage: t_sockact address... -- program args... 35 * 36 * This program simulates systemd socket activation by creating one or more 37 * listener sockets at the specified addresses, setting LISTEN_FDS and 38 * LISTEN_PID in the environment, and executing the specified command. (The 39 * real systemd would not execute the program until there is input on one of 40 * the listener sockets, but we do not need to simulate that, and executing the 41 * command immediately allow easier integration with k5test.py.) 42 */ 43 44 #include "k5-int.h" 45 #include "socket-utils.h" 46 47 static int max_fd; 48 49 static void 50 create_socket(const struct sockaddr *addr) 51 { 52 int fd, one = 1; 53 54 fd = socket(addr->sa_family, SOCK_STREAM, 0); 55 if (fd < 0) 56 abort(); 57 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0) 58 abort(); 59 #if defined(SO_REUSEPORT) && defined(__APPLE__) 60 if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) != 0) 61 abort(); 62 #endif 63 #if defined(IPV6_V6ONLY) 64 if (addr->sa_family == AF_INET6) { 65 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) != 0) 66 abort(); 67 } 68 #endif 69 if (bind(fd, addr, sa_socklen(addr)) != 0) 70 abort(); 71 if (listen(fd, 5) != 0) 72 abort(); 73 max_fd = fd; 74 } 75 76 int 77 main(int argc, char **argv) 78 { 79 const char *addrstr; 80 struct sockaddr_storage ss = { 0 }; 81 struct addrinfo hints = { 0 }, *ai_list = NULL, *ai = NULL; 82 char *host, nbuf[128]; 83 int i, port; 84 85 for (i = 1; i < argc; i++) { 86 if (strcmp(argv[i], "--") == 0) 87 break; 88 addrstr = argv[i]; 89 if (*addrstr == '/') { 90 ss.ss_family = AF_UNIX; 91 strlcpy(ss2sun(&ss)->sun_path, addrstr, 92 sizeof(ss2sun(&ss)->sun_path)); 93 create_socket(ss2sa(&ss)); 94 } else { 95 if (k5_parse_host_string(addrstr, 0, &host, &port) != 0 || !port) 96 abort(); 97 hints.ai_socktype = SOCK_STREAM; 98 hints.ai_family = AF_UNSPEC; 99 hints.ai_flags = AI_PASSIVE; 100 #ifdef AI_NUMERICSERV 101 hints.ai_flags |= AI_NUMERICSERV; 102 #endif 103 (void)snprintf(nbuf, sizeof(nbuf), "%d", port); 104 if (getaddrinfo(host, nbuf, &hints, &ai_list) != 0) 105 abort(); 106 for (ai = ai_list; ai != NULL; ai = ai->ai_next) 107 create_socket(ai->ai_addr); 108 freeaddrinfo(ai_list); 109 free(host); 110 } 111 } 112 argv += i + 1; 113 114 (void)snprintf(nbuf, sizeof(nbuf), "%d", max_fd - 2); 115 setenv("LISTEN_FDS", nbuf, 1); 116 (void)snprintf(nbuf, sizeof(nbuf), "%lu", (unsigned long)getpid()); 117 setenv("LISTEN_PID", nbuf, 1); 118 execv(argv[0], argv); 119 abort(); 120 return 1; 121 } 122