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