update libressl to v2.7.4
[unleashed.git] / lib / libcrypto / bio / b_sock.c
blob152b08090225202cf5406d1f4861fc7caf3d5765
1 /* $OpenBSD: b_sock.c,v 1.69 2018/02/07 00:52:05 bluhm Exp $ */
2 /*
3 * Copyright (c) 2017 Bob Beck <beck@openbsd.org>
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.
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.
18 #include <sys/ioctl.h>
19 #include <sys/socket.h>
20 #include <string.h>
22 #include <arpa/inet.h>
23 #include <netinet/in.h>
24 #include <netinet/tcp.h>
26 #include <errno.h>
27 #include <limits.h>
28 #include <netdb.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
33 #include <openssl/bio.h>
34 #include <openssl/buffer.h>
35 #include <openssl/err.h>
37 int
38 BIO_get_host_ip(const char *str, unsigned char *ip)
40 struct addrinfo *res = NULL;
41 struct addrinfo hints = {
42 .ai_family = AF_INET,
43 .ai_socktype = SOCK_STREAM,
44 .ai_flags = AI_PASSIVE,
46 uint32_t *iap = (in_addr_t *)ip;
47 int error;
49 if (str == NULL) {
50 ERR_asprintf_error_data("NULL host provided");
51 return (0);
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);
60 *iap = (uint32_t)(((struct sockaddr_in *)(res->ai_addr))->sin_addr.s_addr);
61 freeaddrinfo(res);
62 return (1);
65 int
66 BIO_get_port(const char *str, unsigned short *port_ptr)
68 struct addrinfo *res = NULL;
69 struct addrinfo hints = {
70 .ai_family = AF_UNSPEC,
71 .ai_socktype = SOCK_STREAM,
72 .ai_flags = AI_PASSIVE,
74 int error;
76 if (str == NULL) {
77 BIOerror(BIO_R_NO_PORT_SPECIFIED);
78 return (0);
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);
86 *port_ptr = ntohs(((struct sockaddr_in *)(res->ai_addr))->sin_port);
87 freeaddrinfo(res);
88 return (1);
91 int
92 BIO_sock_error(int sock)
94 socklen_t len;
95 int err;
97 len = sizeof(err);
98 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len) != 0)
99 return (1);
100 return (err);
103 struct hostent *
104 BIO_gethostbyname(const char *name)
106 return gethostbyname(name);
110 BIO_socket_ioctl(int fd, long type, void *arg)
112 int ret;
114 ret = ioctl(fd, type, arg);
115 if (ret < 0)
116 SYSerror(errno);
117 return (ret);
121 BIO_get_accept_socket(char *host, int bind_mode)
123 struct addrinfo hints = {
124 .ai_family = AF_INET,
125 .ai_socktype = SOCK_STREAM,
126 .ai_flags = AI_PASSIVE,
128 struct addrinfo *res = NULL;
129 char *h, *p, *str = NULL;
130 int error, ret = 0, s = -1;
132 if (host == NULL || (str = strdup(host)) == NULL)
133 return (-1);
134 p = NULL;
135 h = str;
136 if ((p = strrchr(str, ':')) == NULL) {
137 /* A string without a colon is treated as a port. */
138 p = str;
139 h = NULL;
140 } else {
141 *p++ = '\0';
142 if (*p == '\0') {
143 BIOerror(BIO_R_NO_PORT_SPECIFIED);
144 goto err;
146 if (*h == '\0' || strcmp(h, "*") == 0)
147 h = NULL;
150 if ((error = getaddrinfo(h, p, &hints, &res)) != 0) {
151 ERR_asprintf_error_data("getaddrinfo: '%s:%s': %s'", h, p,
152 gai_strerror(error));
153 goto err;
155 if (h == NULL) {
156 struct sockaddr_in *sin = (struct sockaddr_in *)res->ai_addr;
157 sin->sin_addr.s_addr = INADDR_ANY;
160 s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
161 if (s == -1) {
162 SYSerror(errno);
163 ERR_asprintf_error_data("host='%s'", host);
164 BIOerror(BIO_R_UNABLE_TO_CREATE_SOCKET);
165 goto err;
167 if (bind_mode == BIO_BIND_REUSEADDR) {
168 int i = 1;
170 ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
171 bind_mode = BIO_BIND_NORMAL;
173 if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
174 SYSerror(errno);
175 ERR_asprintf_error_data("host='%s'", host);
176 BIOerror(BIO_R_UNABLE_TO_BIND_SOCKET);
177 goto err;
179 if (listen(s, SOMAXCONN) == -1) {
180 SYSerror(errno);
181 ERR_asprintf_error_data("host='%s'", host);
182 BIOerror(BIO_R_UNABLE_TO_LISTEN_SOCKET);
183 goto err;
185 ret = 1;
187 err:
188 free(str);
189 if (res != NULL)
190 freeaddrinfo(res);
191 if ((ret == 0) && (s != -1)) {
192 close(s);
193 s = -1;
195 return (s);
199 BIO_accept(int sock, char **addr)
201 char h[NI_MAXHOST], s[NI_MAXSERV];
202 struct sockaddr_in sin;
203 socklen_t sin_len = sizeof(sin);
204 int ret = -1;
206 if (addr == NULL)
207 goto end;
209 ret = accept(sock, (struct sockaddr *)&sin, &sin_len);
210 if (ret == -1) {
211 if (BIO_sock_should_retry(ret))
212 return -2;
213 SYSerror(errno);
214 BIOerror(BIO_R_ACCEPT_ERROR);
215 goto end;
217 /* XXX Crazy API. Can't be helped */
218 if (*addr != NULL) {
219 free(*addr);
220 *addr = NULL;
223 if (sin.sin_family != AF_INET)
224 goto end;
226 if (getnameinfo((struct sockaddr *)&sin, sin_len, h, sizeof(h),
227 s, sizeof(s), NI_NUMERICHOST|NI_NUMERICSERV) != 0)
228 goto end;
230 if ((asprintf(addr, "%s:%s", h, s)) == -1) {
231 BIOerror(ERR_R_MALLOC_FAILURE);
232 *addr = NULL;
233 goto end;
235 end:
236 return (ret);
240 BIO_set_tcp_ndelay(int s, int on)
242 return (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == 0);