Home | History | Annotate | Line # | Download | only in util
      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