xref: /openbsd-src/lib/libcrypto/bio/b_sock.c (revision 9de46b9d1aad1aa7cad438b4f35596a7fd3a4b4b)
1 /* $OpenBSD: b_sock.c,v 1.68 2018/02/06 14:45:52 bluhm Exp $ */
2 /*
3  * Copyright (c) 2017 Bob Beck <beck@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/ioctl.h>
19 #include <sys/socket.h>
20 #include <string.h>
21 
22 #include <arpa/inet.h>
23 #include <netinet/in.h>
24 #include <netinet/tcp.h>
25 
26 #include <errno.h>
27 #include <limits.h>
28 #include <netdb.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 
33 #include <openssl/bio.h>
34 #include <openssl/buffer.h>
35 #include <openssl/err.h>
36 
37 int
38 BIO_get_host_ip(const char *str, unsigned char *ip)
39 {
40 	struct addrinfo *res = NULL;
41 	struct addrinfo hints = {
42 		.ai_family = AF_INET,
43 		.ai_socktype = SOCK_STREAM,
44 		.ai_flags = AI_PASSIVE,
45 	};
46 	uint32_t *iap = (in_addr_t *)ip;
47 	int error;
48 
49 	if (str == NULL) {
50 		ERR_asprintf_error_data("NULL host provided");
51 		return (0);
52 	}
53 
54 	if ((error = getaddrinfo(str, NULL, &hints, &res)) != 0) {
55 		BIOerror(BIO_R_BAD_HOSTNAME_LOOKUP);
56 		ERR_asprintf_error_data("getaddrinfo: host='%s' : %s'", str,
57 		    gai_strerror(error));
58 		return (0);
59 	}
60 	*iap = (uint32_t)(((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr);
61 	freeaddrinfo(res);
62 	return (1);
63 }
64 
65 int
66 BIO_get_port(const char *str, unsigned short *port_ptr)
67 {
68 	struct addrinfo *res = NULL;
69 	struct addrinfo hints = {
70 		.ai_family = AF_UNSPEC,
71 		.ai_socktype = SOCK_STREAM,
72 		.ai_flags = AI_PASSIVE,
73 	};
74 	int error;
75 
76 	if (str == NULL) {
77 		BIOerror(BIO_R_NO_PORT_SPECIFIED);
78 		return (0);
79 	}
80 
81 	if ((error = getaddrinfo(NULL, str, &hints, &res)) != 0) {
82 		ERR_asprintf_error_data("getaddrinfo: service='%s' : %s'", str,
83 		    gai_strerror(error));
84 		return (0);
85 	}
86 	*port_ptr = ntohs(((struct sockaddr_in *)(res->ai_addr))->sin_port);
87 	freeaddrinfo(res);
88 	return (1);
89 }
90 
91 int
92 BIO_sock_error(int sock)
93 {
94 	socklen_t len;
95 	int err;
96 
97 	len = sizeof(err);
98 	if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) != 0)
99 		return (1);
100 	return (err);
101 }
102 
103 struct hostent *
104 BIO_gethostbyname(const char *name)
105 {
106 	return gethostbyname(name);
107 }
108 
109 int
110 BIO_socket_ioctl(int fd, long type, void *arg)
111 {
112 	int ret;
113 
114 	ret = ioctl(fd, type, arg);
115 	if (ret < 0)
116 		SYSerror(errno);
117 	return (ret);
118 }
119 
120 int
121 BIO_get_accept_socket(char *host, int bind_mode)
122 {
123 	struct addrinfo hints = {
124 		.ai_family = AF_INET,
125 		.ai_socktype = SOCK_STREAM,
126 		.ai_flags = AI_PASSIVE,
127 	};
128 	struct addrinfo *res = NULL;
129 	char *h, *p, *str = NULL;
130 	int error, ret = 0, s = -1;
131 
132 	if (host == NULL || (str = strdup(host)) == NULL)
133 		return (-1);
134 	p = NULL;
135 	h = str;
136 	if ((p = strrchr(str, ':')) == NULL) {
137 		BIOerror(BIO_R_NO_PORT_SPECIFIED);
138 		goto err;
139 	}
140 	*p++ = '\0';
141 	if (*p == '\0') {
142 		BIOerror(BIO_R_NO_PORT_SPECIFIED);
143 		goto err;
144 	}
145 	if (*h == '\0' || strcmp(h, "*") == 0)
146 		h = NULL;
147 
148 	if ((error = getaddrinfo(h, p, &hints, &res)) != 0) {
149 		ERR_asprintf_error_data("getaddrinfo: '%s:%s': %s'", h, p,
150 		    gai_strerror(error));
151 		goto err;
152 	}
153 	if (h == NULL) {
154 		struct sockaddr_in *sin = (struct sockaddr_in *)res->ai_addr;
155 		sin->sin_addr.s_addr = INADDR_ANY;
156 	}
157 
158 	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
159 	if (s == -1) {
160 		SYSerror(errno);
161 		ERR_asprintf_error_data("host='%s'", host);
162 		BIOerror(BIO_R_UNABLE_TO_CREATE_SOCKET);
163 		goto err;
164 	}
165 	if (bind_mode == BIO_BIND_REUSEADDR) {
166 		int i = 1;
167 
168 		ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
169 		bind_mode = BIO_BIND_NORMAL;
170 	}
171 	if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
172 		SYSerror(errno);
173 		ERR_asprintf_error_data("host='%s'", host);
174 		BIOerror(BIO_R_UNABLE_TO_BIND_SOCKET);
175 		goto err;
176 	}
177 	if (listen(s, SOMAXCONN) == -1) {
178 		SYSerror(errno);
179 		ERR_asprintf_error_data("host='%s'", host);
180 		BIOerror(BIO_R_UNABLE_TO_LISTEN_SOCKET);
181 		goto err;
182 	}
183 	ret = 1;
184 
185 err:
186 	free(str);
187 	if (res != NULL)
188 		freeaddrinfo(res);
189 	if ((ret == 0) && (s != -1)) {
190 		close(s);
191 		s = -1;
192 	}
193 	return (s);
194 }
195 
196 int
197 BIO_accept(int sock, char **addr)
198 {
199 	char   h[NI_MAXHOST], s[NI_MAXSERV];
200 	struct sockaddr_in sin;
201 	socklen_t sin_len = sizeof(sin);
202 	int ret = -1;
203 
204 	if (addr == NULL)
205 		goto end;
206 
207 	ret = accept(sock, (struct sockaddr *)&sin, &sin_len);
208 	if (ret == -1) {
209 		if (BIO_sock_should_retry(ret))
210 			return -2;
211 		SYSerror(errno);
212 		BIOerror(BIO_R_ACCEPT_ERROR);
213 		goto end;
214 	}
215 	/* XXX Crazy API. Can't be helped */
216 	if (*addr != NULL) {
217 		free(*addr);
218 		*addr = NULL;
219 	}
220 
221 	if (sin.sin_family != AF_INET)
222 		goto end;
223 
224 	if (getnameinfo((struct sockaddr *)&sin, sin_len, h, sizeof(h),
225 		s, sizeof(s), NI_NUMERICHOST|NI_NUMERICSERV) != 0)
226 		goto end;
227 
228 	if ((asprintf(addr, "%s:%s", h, s)) == -1) {
229 		BIOerror(ERR_R_MALLOC_FAILURE);
230 		*addr = NULL;
231 		goto end;
232 	}
233 end:
234 	return (ret);
235 }
236 
237 int
238 BIO_set_tcp_ndelay(int s, int on)
239 {
240 	return (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == 0);
241 }
242