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