1 /*	$NetBSD: inet_listen.c,v 1.1.1.1 2009/06/23 10:09:00 tron 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 
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 
84 int     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 
171 int     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