1*3df6c9b8Sozaki-r /* $NetBSD: tcp_shutdown.c,v 1.1 2022/11/04 08:01:42 ozaki-r Exp $ */
2*3df6c9b8Sozaki-r
3*3df6c9b8Sozaki-r /*-
4*3df6c9b8Sozaki-r * Copyright (c) 2022 Internet Initiative Japan Inc.
5*3df6c9b8Sozaki-r * All rights reserved.
6*3df6c9b8Sozaki-r *
7*3df6c9b8Sozaki-r * This code is derived from software contributed to The NetBSD Foundation
8*3df6c9b8Sozaki-r * by Christos Zoulas.
9*3df6c9b8Sozaki-r *
10*3df6c9b8Sozaki-r * Redistribution and use in source and binary forms, with or without
11*3df6c9b8Sozaki-r * modification, are permitted provided that the following conditions
12*3df6c9b8Sozaki-r * are met:
13*3df6c9b8Sozaki-r * 1. Redistributions of source code must retain the above copyright
14*3df6c9b8Sozaki-r * notice, this list of conditions and the following disclaimer.
15*3df6c9b8Sozaki-r * 2. Redistributions in binary form must reproduce the above copyright
16*3df6c9b8Sozaki-r * notice, this list of conditions and the following disclaimer in the
17*3df6c9b8Sozaki-r * documentation and/or other materials provided with the distribution.
18*3df6c9b8Sozaki-r *
19*3df6c9b8Sozaki-r * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*3df6c9b8Sozaki-r * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*3df6c9b8Sozaki-r * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*3df6c9b8Sozaki-r * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*3df6c9b8Sozaki-r * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*3df6c9b8Sozaki-r * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*3df6c9b8Sozaki-r * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*3df6c9b8Sozaki-r * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*3df6c9b8Sozaki-r * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*3df6c9b8Sozaki-r * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*3df6c9b8Sozaki-r * POSSIBILITY OF SUCH DAMAGE.
30*3df6c9b8Sozaki-r */
31*3df6c9b8Sozaki-r #include <sys/cdefs.h>
32*3df6c9b8Sozaki-r #ifdef __RCSID
33*3df6c9b8Sozaki-r __RCSID("$NetBSD: tcp_shutdown.c,v 1.1 2022/11/04 08:01:42 ozaki-r Exp $");
34*3df6c9b8Sozaki-r #else
35*3df6c9b8Sozaki-r extern const char *__progname;
36*3df6c9b8Sozaki-r #define getprogname() __progname
37*3df6c9b8Sozaki-r #endif
38*3df6c9b8Sozaki-r
39*3df6c9b8Sozaki-r #include <sys/types.h>
40*3df6c9b8Sozaki-r #include <sys/socket.h>
41*3df6c9b8Sozaki-r #include <netinet/in.h>
42*3df6c9b8Sozaki-r #include <arpa/inet.h>
43*3df6c9b8Sozaki-r
44*3df6c9b8Sozaki-r #include <stdio.h>
45*3df6c9b8Sozaki-r #include <string.h>
46*3df6c9b8Sozaki-r #include <stdlib.h>
47*3df6c9b8Sozaki-r #include <unistd.h>
48*3df6c9b8Sozaki-r #include <err.h>
49*3df6c9b8Sozaki-r #include <errno.h>
50*3df6c9b8Sozaki-r #include <stdbool.h>
51*3df6c9b8Sozaki-r
52*3df6c9b8Sozaki-r static inline bool
match(const char * a,const char * b)53*3df6c9b8Sozaki-r match(const char *a, const char *b)
54*3df6c9b8Sozaki-r {
55*3df6c9b8Sozaki-r
56*3df6c9b8Sozaki-r return strncmp(a, b, strlen(b)) == 0;
57*3df6c9b8Sozaki-r }
58*3df6c9b8Sozaki-r
59*3df6c9b8Sozaki-r int
main(int argc,char * argv[])60*3df6c9b8Sozaki-r main(int argc, char *argv[])
61*3df6c9b8Sozaki-r {
62*3df6c9b8Sozaki-r int s, e;
63*3df6c9b8Sozaki-r char *target;
64*3df6c9b8Sozaki-r
65*3df6c9b8Sozaki-r if (argc != 2)
66*3df6c9b8Sozaki-r errx(EXIT_FAILURE, "invalid argument");
67*3df6c9b8Sozaki-r target = argv[1];
68*3df6c9b8Sozaki-r
69*3df6c9b8Sozaki-r s = socket(AF_INET, SOCK_STREAM, 0);
70*3df6c9b8Sozaki-r if (s == -1)
71*3df6c9b8Sozaki-r err(EXIT_FAILURE, "socket");
72*3df6c9b8Sozaki-r e = shutdown(s, SHUT_RDWR);
73*3df6c9b8Sozaki-r if (e == -1)
74*3df6c9b8Sozaki-r err(EXIT_FAILURE, "shutdown");
75*3df6c9b8Sozaki-r
76*3df6c9b8Sozaki-r if (match(target, "connect")) {
77*3df6c9b8Sozaki-r struct sockaddr_in sin;
78*3df6c9b8Sozaki-r
79*3df6c9b8Sozaki-r memset(&sin, 0, sizeof(sin));
80*3df6c9b8Sozaki-r sin.sin_port = htons(31522);
81*3df6c9b8Sozaki-r sin.sin_addr.s_addr = inet_addr("127.0.0.1");
82*3df6c9b8Sozaki-r sin.sin_family = AF_INET;
83*3df6c9b8Sozaki-r
84*3df6c9b8Sozaki-r e = connect(s, (struct sockaddr *)&sin, sizeof(sin));
85*3df6c9b8Sozaki-r if (e == 0)
86*3df6c9b8Sozaki-r err(EXIT_FAILURE, "connect didn't fail on a shudown socket");
87*3df6c9b8Sozaki-r if (e == -1 && errno != EINVAL)
88*3df6c9b8Sozaki-r err(EXIT_FAILURE, "connect failed with unexpected error");
89*3df6c9b8Sozaki-r } else if (match(target, "setsockopt")) {
90*3df6c9b8Sozaki-r int opt = 1;
91*3df6c9b8Sozaki-r e = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
92*3df6c9b8Sozaki-r if (e == 0)
93*3df6c9b8Sozaki-r err(EXIT_FAILURE, "setsockopt didn't fail on a shutdown socket");
94*3df6c9b8Sozaki-r if (e == -1 && errno != ECONNRESET)
95*3df6c9b8Sozaki-r err(EXIT_FAILURE, "setsockopt failed with unexpected error");
96*3df6c9b8Sozaki-r } else if (match(target, "getsockname")) {
97*3df6c9b8Sozaki-r struct sockaddr_storage ss;
98*3df6c9b8Sozaki-r socklen_t len;
99*3df6c9b8Sozaki-r e = getsockname(s, (struct sockaddr *)&ss, &len);
100*3df6c9b8Sozaki-r if (e == 0)
101*3df6c9b8Sozaki-r err(EXIT_FAILURE, "getsockname didn't fail on a shutdown socket");
102*3df6c9b8Sozaki-r if (e == -1 && errno != EINVAL)
103*3df6c9b8Sozaki-r err(EXIT_FAILURE, "getsockname failed with unexpected error");
104*3df6c9b8Sozaki-r } else if (match(target, "listen")) {
105*3df6c9b8Sozaki-r e = listen(s, 5);
106*3df6c9b8Sozaki-r if (e == 0)
107*3df6c9b8Sozaki-r err(EXIT_FAILURE, "listen didn't fail on a shutdown socket");
108*3df6c9b8Sozaki-r if (e == -1 && errno != EINVAL)
109*3df6c9b8Sozaki-r err(EXIT_FAILURE, "listen failed with unexpected error");
110*3df6c9b8Sozaki-r } else if (match(target, "bind")) {
111*3df6c9b8Sozaki-r struct sockaddr_in sin;
112*3df6c9b8Sozaki-r
113*3df6c9b8Sozaki-r memset(&sin, 0, sizeof(sin));
114*3df6c9b8Sozaki-r sin.sin_port = htons(31522);
115*3df6c9b8Sozaki-r sin.sin_addr.s_addr = inet_addr("127.0.0.1");
116*3df6c9b8Sozaki-r sin.sin_family = AF_INET;
117*3df6c9b8Sozaki-r
118*3df6c9b8Sozaki-r e = bind(s, (struct sockaddr *)&sin, sizeof(sin));
119*3df6c9b8Sozaki-r if (e == 0)
120*3df6c9b8Sozaki-r err(EXIT_FAILURE, "bind didn't fail on a shutdown socket");
121*3df6c9b8Sozaki-r if (e == -1 && errno != EINVAL)
122*3df6c9b8Sozaki-r err(EXIT_FAILURE, "bind failed with unexpected error");
123*3df6c9b8Sozaki-r } else if (match(target, "shutdown")) {
124*3df6c9b8Sozaki-r e = shutdown(s, SHUT_RDWR);
125*3df6c9b8Sozaki-r if (e == 0)
126*3df6c9b8Sozaki-r err(EXIT_FAILURE, "shutdown didn't fail on a shutdown socket");
127*3df6c9b8Sozaki-r if (e == -1 && errno != EINVAL)
128*3df6c9b8Sozaki-r err(EXIT_FAILURE, "shutdown failed with unexpected error");
129*3df6c9b8Sozaki-r } else {
130*3df6c9b8Sozaki-r errx(EXIT_FAILURE, "unknown target: %s", target);
131*3df6c9b8Sozaki-r }
132*3df6c9b8Sozaki-r
133*3df6c9b8Sozaki-r e = close(s);
134*3df6c9b8Sozaki-r if (e == -1)
135*3df6c9b8Sozaki-r err(EXIT_FAILURE, "close");
136*3df6c9b8Sozaki-r return 0;
137*3df6c9b8Sozaki-r }
138