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" 54static void *b; 55#endif 56 57#ifndef INFTIM 58#define INFTIM -1 59#endif 60 61static void 62process_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 81static void 82process_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} 101static int 102cr(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 137static void 138handle(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 166static __dead void 167usage(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 174int 175main(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