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 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 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