1 /* $NetBSD: srvtest.c,v 1.2 2025/02/11 17:43:16 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #ifdef HAVE_CONFIG_H 32 #include "config.h" 33 #endif 34 35 #ifdef HAVE_SYS_CDEFS_H 36 #include <sys/cdefs.h> 37 #endif 38 __RCSID("$NetBSD: srvtest.c,v 1.2 2025/02/11 17:43:16 christos Exp $"); 39 40 #include <sys/types.h> 41 #include <sys/socket.h> 42 #include <netinet/in.h> 43 44 #include <stdio.h> 45 #include <signal.h> 46 #include <string.h> 47 #include <syslog.h> 48 #include <unistd.h> 49 #include <stdlib.h> 50 #include <poll.h> 51 #include <err.h> 52 53 #include "blocklist.h" 54 #ifdef BLDEBUG 55 #include "bl.h" 56 static void *b; 57 #endif 58 59 #ifndef INFTIM 60 #define INFTIM -1 61 #endif 62 63 static void 64 process_tcp(int afd) 65 { 66 ssize_t n; 67 char buffer[256]; 68 69 memset(buffer, 0, sizeof(buffer)); 70 71 if ((n = read(afd, buffer, sizeof(buffer))) == -1) 72 err(1, "read"); 73 buffer[sizeof(buffer) - 1] = '\0'; 74 printf("%s: sending %d %s\n", getprogname(), afd, buffer); 75 #ifdef BLDEBUG 76 blocklist_r(b, 1, afd, buffer); 77 #else 78 blocklist(1, afd, buffer); 79 #endif 80 exit(0); 81 } 82 83 static void 84 process_udp(int afd) 85 { 86 ssize_t n; 87 char buffer[256]; 88 struct sockaddr_storage ss; 89 socklen_t slen; 90 91 memset(buffer, 0, sizeof(buffer)); 92 93 slen = (socklen_t)sizeof(ss); 94 memset(&ss, 0, sizeof(ss)); 95 if ((n = recvfrom(afd, buffer, sizeof(buffer), 0, (void *)&ss, 96 &slen)) == -1) 97 err(1, "recvfrom"); 98 buffer[sizeof(buffer) - 1] = '\0'; 99 printf("%s: sending %d %s\n", getprogname(), afd, buffer); 100 blocklist_sa(1, afd, (void *)&ss, slen, buffer); 101 exit(0); 102 } 103 static int 104 cr(int af, int type, in_port_t p) 105 { 106 int sfd; 107 struct sockaddr_storage ss; 108 socklen_t slen; 109 sfd = socket(af == AF_INET ? PF_INET : PF_INET6, type, 0); 110 if (sfd == -1) 111 err(1, "socket"); 112 113 p = htons(p); 114 memset(&ss, 0, sizeof(ss)); 115 if (af == AF_INET) { 116 struct sockaddr_in *s = (void *)&ss; 117 s->sin_family = AF_INET; 118 slen = sizeof(*s); 119 s->sin_port = p; 120 } else { 121 struct sockaddr_in6 *s6 = (void *)&ss; 122 s6->sin6_family = AF_INET6; 123 slen = sizeof(*s6); 124 s6->sin6_port = p; 125 } 126 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 127 ss.ss_len = (uint8_t)slen; 128 #endif 129 130 if (bind(sfd, (const void *)&ss, slen) == -1) 131 err(1, "bind"); 132 133 if (type != SOCK_DGRAM) 134 if (listen(sfd, 5) == -1) 135 err(1, "listen"); 136 return sfd; 137 } 138 139 static void 140 handle(int type, int sfd) 141 { 142 struct sockaddr_storage ss; 143 socklen_t alen = sizeof(ss); 144 int afd; 145 146 if (type != SOCK_DGRAM) { 147 if ((afd = accept(sfd, (void *)&ss, &alen)) == -1) 148 err(1, "accept"); 149 } else 150 afd = sfd; 151 152 /* Create child process */ 153 switch (fork()) { 154 case -1: 155 err(1, "fork"); 156 case 0: 157 if (type == SOCK_DGRAM) 158 process_udp(afd); 159 else 160 process_tcp(afd); 161 break; 162 default: 163 close(afd); 164 break; 165 } 166 } 167 168 static __dead void 169 usage(int c) 170 { 171 warnx("Unknown option `%c'", (char)c); 172 fprintf(stderr, "Usage: %s [-u] [-p <num>]" 173 #ifdef BLDEBUG 174 " [-s <sockpath>]" 175 #endif 176 "\n", getprogname()); 177 exit(EXIT_FAILURE); 178 } 179 180 int 181 main(int argc, char *argv[]) 182 { 183 #ifdef __linux__ 184 #define NUMFD 1 185 #else 186 #define NUMFD 2 187 #endif 188 struct pollfd pfd[NUMFD]; 189 int type = SOCK_STREAM, c; 190 in_port_t port = 6161; 191 #ifdef BLDEBUG 192 char *sockpath = "blsock"; 193 const char *optstr = "up:s:"; 194 #else 195 const char *optstr = "up:"; 196 #endif 197 198 signal(SIGCHLD, SIG_IGN); 199 200 while ((c = getopt(argc, argv, optstr)) != -1) 201 switch (c) { 202 case 'u': 203 type = SOCK_DGRAM; 204 break; 205 case 'p': 206 port = (in_port_t)atoi(optarg); 207 break; 208 #ifdef BLDEBUG 209 case 's': 210 sockpath = (char *)optarg; 211 break; 212 #endif 213 default: 214 usage(c); 215 } 216 217 #ifdef BLDEBUG 218 b = bl_create(false, sockpath, vsyslog_r); 219 #endif 220 221 222 pfd[0].fd = cr(AF_INET, type, port); 223 pfd[0].events = POLLIN; 224 #if NUMFD > 1 225 pfd[1].fd = cr(AF_INET6, type, port); 226 pfd[1].events = POLLIN; 227 #endif 228 229 for (;;) { 230 if (poll(pfd, __arraycount(pfd), INFTIM) == -1) 231 err(1, "poll"); 232 for (size_t i = 0; i < __arraycount(pfd); i++) { 233 if ((pfd[i].revents & POLLIN) == 0) 234 continue; 235 handle(type, pfd[i].fd); 236 } 237 } 238 } 239