1 /* $NetBSD: srvtest.c,v 1.10 2015/05/30 22:40:38 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 #include <sys/cdefs.h> 36 __RCSID("$NetBSD: srvtest.c,v 1.10 2015/05/30 22:40:38 christos Exp $"); 37 38 #include <sys/types.h> 39 #include <sys/socket.h> 40 #include <netinet/in.h> 41 42 #include <stdio.h> 43 #include <signal.h> 44 #include <string.h> 45 #include <syslog.h> 46 #include <unistd.h> 47 #include <stdlib.h> 48 #include <poll.h> 49 #include <err.h> 50 51 #include "blacklist.h" 52 #ifdef BLDEBUG 53 #include "bl.h" 54 static void *b; 55 #endif 56 57 #ifndef INFTIM 58 #define INFTIM -1 59 #endif 60 61 static void 62 process_tcp(int afd) 63 { 64 ssize_t n; 65 char buffer[256]; 66 67 memset(buffer, 0, sizeof(buffer)); 68 69 if ((n = read(afd, buffer, sizeof(buffer))) == -1) 70 err(1, "read"); 71 buffer[sizeof(buffer) - 1] = '\0'; 72 printf("%s: sending %d %s\n", getprogname(), afd, buffer); 73 #ifdef BLDEBUG 74 blacklist_r(b, 1, afd, buffer); 75 #else 76 blacklist(1, afd, buffer); 77 #endif 78 exit(0); 79 } 80 81 static void 82 process_udp(int afd) 83 { 84 ssize_t n; 85 char buffer[256]; 86 struct sockaddr_storage ss; 87 socklen_t slen; 88 89 memset(buffer, 0, sizeof(buffer)); 90 91 slen = (socklen_t)sizeof(ss); 92 memset(&ss, 0, sizeof(ss)); 93 if ((n = recvfrom(afd, buffer, sizeof(buffer), 0, (void *)&ss, 94 &slen)) == -1) 95 err(1, "recvfrom"); 96 buffer[sizeof(buffer) - 1] = '\0'; 97 printf("%s: sending %d %s\n", getprogname(), afd, buffer); 98 blacklist_sa(1, afd, (void *)&ss, slen, buffer); 99 exit(0); 100 } 101 static int 102 cr(int af, int type, in_port_t p) 103 { 104 int sfd; 105 struct sockaddr_storage ss; 106 socklen_t slen; 107 sfd = socket(af == AF_INET ? PF_INET : PF_INET6, type, 0); 108 if (sfd == -1) 109 err(1, "socket"); 110 111 p = htons(p); 112 memset(&ss, 0, sizeof(ss)); 113 if (af == AF_INET) { 114 struct sockaddr_in *s = (void *)&ss; 115 s->sin_family = AF_INET; 116 slen = sizeof(*s); 117 s->sin_port = p; 118 } else { 119 struct sockaddr_in6 *s6 = (void *)&ss; 120 s6->sin6_family = AF_INET6; 121 slen = sizeof(*s6); 122 s6->sin6_port = p; 123 } 124 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 125 ss.ss_len = (uint8_t)slen; 126 #endif 127 128 if (bind(sfd, (const void *)&ss, slen) == -1) 129 err(1, "bind"); 130 131 if (type != SOCK_DGRAM) 132 if (listen(sfd, 5) == -1) 133 err(1, "listen"); 134 return sfd; 135 } 136 137 static void 138 handle(int type, int sfd) 139 { 140 struct sockaddr_storage ss; 141 socklen_t alen = sizeof(ss); 142 int afd; 143 144 if (type != SOCK_DGRAM) { 145 if ((afd = accept(sfd, (void *)&ss, &alen)) == -1) 146 err(1, "accept"); 147 } else 148 afd = sfd; 149 150 /* Create child process */ 151 switch (fork()) { 152 case -1: 153 err(1, "fork"); 154 case 0: 155 if (type == SOCK_DGRAM) 156 process_udp(afd); 157 else 158 process_tcp(afd); 159 break; 160 default: 161 close(afd); 162 break; 163 } 164 } 165 166 static __dead void 167 usage(int c) 168 { 169 warnx("Unknown option `%c'", (char)c); 170 fprintf(stderr, "Usage: %s [-u] [-p <num>]\n", getprogname()); 171 exit(EXIT_FAILURE); 172 } 173 174 int 175 main(int argc, char *argv[]) 176 { 177 #ifdef __linux__ 178 #define NUMFD 1 179 #else 180 #define NUMFD 2 181 #endif 182 struct pollfd pfd[NUMFD]; 183 int type = SOCK_STREAM, c; 184 in_port_t port = 6161; 185 186 signal(SIGCHLD, SIG_IGN); 187 188 #ifdef BLDEBUG 189 b = bl_create(false, "blsock", vsyslog); 190 #endif 191 192 while ((c = getopt(argc, argv, "up:")) != -1) 193 switch (c) { 194 case 'u': 195 type = SOCK_DGRAM; 196 break; 197 case 'p': 198 port = (in_port_t)atoi(optarg); 199 break; 200 default: 201 usage(c); 202 } 203 204 pfd[0].fd = cr(AF_INET, type, port); 205 pfd[0].events = POLLIN; 206 #if NUMFD > 1 207 pfd[1].fd = cr(AF_INET6, type, port); 208 pfd[1].events = POLLIN; 209 #endif 210 211 for (;;) { 212 if (poll(pfd, __arraycount(pfd), INFTIM) == -1) 213 err(1, "poll"); 214 for (size_t i = 0; i < __arraycount(pfd); i++) { 215 if ((pfd[i].revents & POLLIN) == 0) 216 continue; 217 handle(type, pfd[i].fd); 218 } 219 } 220 } 221