1/* $NetBSD$ */ 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 56/* System libraries. */ 57 58#include <sys_defs.h> 59#include <sys/socket.h> 60#include <netinet/in.h> 61#include <arpa/inet.h> 62#include <netdb.h> 63#ifndef MAXHOSTNAMELEN 64#include <sys/param.h> 65#endif 66#include <errno.h> 67#include <string.h> 68#include <unistd.h> 69 70/* Utility library. */ 71 72#include "mymalloc.h" 73#include "msg.h" 74#include "host_port.h" 75#include "iostuff.h" 76#include "listen.h" 77#include "sane_accept.h" 78#include "myaddrinfo.h" 79#include "sock_addr.h" 80#include "inet_proto.h" 81 82/* inet_listen - create TCP listener */ 83 84int inet_listen(const char *addr, int backlog, int block_mode) 85{ 86 struct addrinfo *res; 87 struct addrinfo *res0; 88 int aierr; 89 int sock; 90 int on = 1; 91 char *buf; 92 char *host; 93 char *port; 94 const char *parse_err; 95 MAI_HOSTADDR_STR hostaddr; 96 MAI_SERVPORT_STR portnum; 97 INET_PROTO_INFO *proto_info; 98 99 /* 100 * Translate address information to internal form. 101 */ 102 buf = mystrdup(addr); 103 if ((parse_err = host_port(buf, &host, "", &port, (char *) 0)) != 0) 104 msg_fatal("%s: %s", addr, parse_err); 105 if (*host == 0) 106 host = 0; 107 if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res0)) != 0) 108 msg_fatal("%s: %s", addr, MAI_STRERROR(aierr)); 109 myfree(buf); 110 /* No early returns or res0 leaks. */ 111 112 proto_info = inet_proto_info(); 113 for (res = res0; /* see below */ ; res = res->ai_next) { 114 115 /* 116 * No usable address found. 117 */ 118 if (res == 0) 119 msg_fatal("%s: host found but no usable address", addr); 120 121 /* 122 * Safety net. 123 */ 124 if (strchr((char *) proto_info->sa_family_list, res->ai_family) != 0) 125 break; 126 127 msg_info("skipping address family %d for %s", res->ai_family, addr); 128 } 129 130 /* 131 * Show what address we're trying. 132 */ 133 if (msg_verbose) { 134 SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen, 135 &hostaddr, &portnum, 0); 136 msg_info("trying... [%s]:%s", hostaddr.buf, portnum.buf); 137 } 138 139 /* 140 * Create a listener socket. 141 */ 142 if ((sock = socket(res->ai_family, res->ai_socktype, 0)) < 0) 143 msg_fatal("socket: %m"); 144#ifdef HAS_IPV6 145# if defined(IPV6_V6ONLY) && !defined(BROKEN_AI_PASSIVE_NULL_HOST) 146 if (res->ai_family == AF_INET6 147 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, 148 (char *) &on, sizeof(on)) < 0) 149 msg_fatal("setsockopt(IPV6_V6ONLY): %m"); 150# endif 151#endif 152 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 153 (char *) &on, sizeof(on)) < 0) 154 msg_fatal("setsockopt(SO_REUSEADDR): %m"); 155 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { 156 SOCKADDR_TO_HOSTADDR(res->ai_addr, res->ai_addrlen, 157 &hostaddr, &portnum, 0); 158 msg_fatal("bind %s port %s: %m", hostaddr.buf, portnum.buf); 159 } 160 freeaddrinfo(res0); 161 non_blocking(sock, block_mode); 162 if (inet_windowsize > 0) 163 set_inet_windowsize(sock, inet_windowsize); 164 if (listen(sock, backlog) < 0) 165 msg_fatal("listen: %m"); 166 return (sock); 167} 168 169/* inet_accept - accept connection */ 170 171int inet_accept(int fd) 172{ 173 struct sockaddr_storage ss; 174 SOCKADDR_SIZE ss_len = sizeof(ss); 175 176 return (sane_accept(fd, (struct sockaddr *) & ss, &ss_len)); 177} 178