1 /* $NetBSD: inet_listen.c,v 1.3 2022/10/08 16:12:50 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* inet_listen 3
6 /* SUMMARY
7 /* start TCP listener
8 /* SYNOPSIS
9 /* #include <listen.h>
10 /*
11 /* int inet_windowsize;
12 /*
13 /* int inet_listen(addr, backlog, block_mode)
14 /* const char *addr;
15 /* int backlog;
16 /* int block_mode;
17 /*
18 /* int inet_accept(fd)
19 /* int fd;
20 /* DESCRIPTION
21 /* The \fBinet_listen\fR routine starts a TCP listener
22 /* on the specified address, with the specified backlog, and returns
23 /* the resulting file descriptor.
24 /*
25 /* inet_accept() accepts a connection and sanitizes error results.
26 /*
27 /* Specify an inet_windowsize value > 0 to override the TCP
28 /* window size that the server advertises to the client.
29 /*
30 /* Arguments:
31 /* .IP addr
32 /* The communication endpoint to listen on. The syntax is "host:port".
33 /* Host and port may be specified in symbolic form or numerically.
34 /* A null host field means listen on all network interfaces.
35 /* .IP backlog
36 /* This argument is passed on to the \fIlisten(2)\fR routine.
37 /* .IP block_mode
38 /* Either NON_BLOCKING for a non-blocking socket, or BLOCKING for
39 /* blocking mode.
40 /* .IP fd
41 /* File descriptor returned by inet_listen().
42 /* DIAGNOSTICS
43 /* Fatal errors: inet_listen() aborts upon any system call failure.
44 /* inet_accept() leaves all error handling up to the caller.
45 /* LICENSE
46 /* .ad
47 /* .fi
48 /* The Secure Mailer license must be distributed with this software.
49 /* AUTHOR(S)
50 /* Wietse Venema
51 /* IBM T.J. Watson Research
52 /* P.O. Box 704
53 /* Yorktown Heights, NY 10598, USA
54 /*
55 /* Wietse Venema
56 /* Google, Inc.
57 /* 111 8th Avenue
58 /* New York, NY 10011, USA
59 /*--*/
60
61 /* System libraries. */
62
63 #include <sys_defs.h>
64 #include <sys/socket.h>
65 #include <netinet/in.h>
66 #include <arpa/inet.h>
67 #include <netdb.h>
68 #ifndef MAXHOSTNAMELEN
69 #include <sys/param.h>
70 #endif
71 #include <errno.h>
72 #include <string.h>
73 #include <unistd.h>
74
75 /* Utility library. */
76
77 #include "mymalloc.h"
78 #include "msg.h"
79 #include "host_port.h"
80 #include "iostuff.h"
81 #include "listen.h"
82 #include "sane_accept.h"
83 #include "myaddrinfo.h"
84 #include "sock_addr.h"
85 #include "inet_proto.h"
86
87 /* inet_listen - create TCP listener */
88
inet_listen(const char * addr,int backlog,int block_mode)89 int inet_listen(const char *addr, int backlog, int block_mode)
90 {
91 struct addrinfo *res;
92 struct addrinfo *res0;
93 int aierr;
94 int sock;
95 int on = 1;
96 char *buf;
97 char *host;
98 char *port;
99 const char *parse_err;
100 MAI_HOSTADDR_STR hostaddr;
101 MAI_SERVPORT_STR portnum;
102 const INET_PROTO_INFO *proto_info;
103
104 /*
105 * Translate address information to internal form.
106 */
107 buf = mystrdup(addr);
108 if ((parse_err = host_port(buf, &host, "", &port, (char *) 0)) != 0)
109 msg_fatal("%s: %s", addr, parse_err);
110 if (*host == 0)
111 host = 0;
112 if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res0)) != 0)
113 msg_fatal("%s: %s", addr, MAI_STRERROR(aierr));
114 myfree(buf);
115 /* No early returns or res0 leaks. */
116
117 proto_info = inet_proto_info();
118 for (res = res0; /* see below */ ; res = res->ai_next) {
119
120 /*
121 * No usable address found.
122 */
123 if (res == 0)
124 msg_fatal("%s: host found but no usable address", addr);
125
126 /*
127 * Safety net.
128 */
129 if (strchr((char *) proto_info->sa_family_list, res->ai_family) != 0)
130 break;
131
132 msg_info("skipping address family %d for %s", res->ai_family, addr);
133 }
134
135 /*
136 * Show what address we're trying.
137 */
138 if (msg_verbose) {
139 SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen,
140 &hostaddr, &portnum, 0);
141 msg_info("trying... [%s]:%s", hostaddr.buf, portnum.buf);
142 }
143
144 /*
145 * Create a listener socket.
146 */
147 if ((sock = socket(res->ai_family, res->ai_socktype, 0)) < 0)
148 msg_fatal("socket: %m");
149 #ifdef HAS_IPV6
150 #if defined(IPV6_V6ONLY) && !defined(BROKEN_AI_PASSIVE_NULL_HOST)
151 if (res->ai_family == AF_INET6
152 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
153 (void *) &on, sizeof(on)) < 0)
154 msg_fatal("setsockopt(IPV6_V6ONLY): %m");
155 #endif
156 #endif
157 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
158 (void *) &on, sizeof(on)) < 0)
159 msg_fatal("setsockopt(SO_REUSEADDR): %m");
160 #if defined(SO_REUSEPORT_LB)
161 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT_LB,
162 (void *) &on, sizeof(on)) < 0)
163 msg_fatal("setsockopt(SO_REUSEPORT_LB): %m");
164 #elif defined(SO_REUSEPORT)
165 if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
166 (void *) &on, sizeof(on)) < 0)
167 msg_fatal("setsockopt(SO_REUSEPORT): %m");
168 #endif
169 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
170 SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen,
171 &hostaddr, &portnum, 0);
172 msg_fatal("bind %s port %s: %m", hostaddr.buf, portnum.buf);
173 }
174 freeaddrinfo(res0);
175 non_blocking(sock, block_mode);
176 if (inet_windowsize > 0)
177 set_inet_windowsize(sock, inet_windowsize);
178 if (listen(sock, backlog) < 0)
179 msg_fatal("listen: %m");
180 return (sock);
181 }
182
183 /* inet_accept - accept connection */
184
inet_accept(int fd)185 int inet_accept(int fd)
186 {
187 struct sockaddr_storage ss;
188 SOCKADDR_SIZE ss_len = sizeof(ss);
189
190 return (sane_accept(fd, (struct sockaddr *) &ss, &ss_len));
191 }
192