1 /* $OpenBSD: b_sock.c,v 1.69 2018/02/07 00:52:05 bluhm Exp $ */
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>
22 #include <arpa/inet.h>
23 #include <netinet/in.h>
24 #include <netinet/tcp.h>
33 #include <openssl/bio.h>
34 #include <openssl/buffer.h>
35 #include <openssl/err.h>
38 BIO_get_host_ip(const char *str
, unsigned char *ip
)
40 struct addrinfo
*res
= NULL
;
41 struct addrinfo hints
= {
43 .ai_socktype
= SOCK_STREAM
,
44 .ai_flags
= AI_PASSIVE
,
46 uint32_t *iap
= (in_addr_t
*)ip
;
50 ERR_asprintf_error_data("NULL host provided");
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
,
60 *iap
= (uint32_t)(((struct sockaddr_in
*)(res
->ai_addr
))->sin_addr
.s_addr
);
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
,
77 BIOerror(BIO_R_NO_PORT_SPECIFIED
);
81 if ((error
= getaddrinfo(NULL
, str
, &hints
, &res
)) != 0) {
82 ERR_asprintf_error_data("getaddrinfo: service='%s' : %s'", str
,
86 *port_ptr
= ntohs(((struct sockaddr_in
*)(res
->ai_addr
))->sin_port
);
92 BIO_sock_error(int sock
)
98 if (getsockopt(sock
, SOL_SOCKET
, SO_ERROR
, &err
, &len
) != 0)
104 BIO_gethostbyname(const char *name
)
106 return gethostbyname(name
);
110 BIO_socket_ioctl(int fd
, long type
, void *arg
)
114 ret
= ioctl(fd
, type
, arg
);
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
)
136 if ((p
= strrchr(str
, ':')) == NULL
) {
137 /* A string without a colon is treated as a port. */
143 BIOerror(BIO_R_NO_PORT_SPECIFIED
);
146 if (*h
== '\0' || strcmp(h
, "*") == 0)
150 if ((error
= getaddrinfo(h
, p
, &hints
, &res
)) != 0) {
151 ERR_asprintf_error_data("getaddrinfo: '%s:%s': %s'", h
, p
,
152 gai_strerror(error
));
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
);
163 ERR_asprintf_error_data("host='%s'", host
);
164 BIOerror(BIO_R_UNABLE_TO_CREATE_SOCKET
);
167 if (bind_mode
== BIO_BIND_REUSEADDR
) {
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) {
175 ERR_asprintf_error_data("host='%s'", host
);
176 BIOerror(BIO_R_UNABLE_TO_BIND_SOCKET
);
179 if (listen(s
, SOMAXCONN
) == -1) {
181 ERR_asprintf_error_data("host='%s'", host
);
182 BIOerror(BIO_R_UNABLE_TO_LISTEN_SOCKET
);
191 if ((ret
== 0) && (s
!= -1)) {
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
);
209 ret
= accept(sock
, (struct sockaddr
*)&sin
, &sin_len
);
211 if (BIO_sock_should_retry(ret
))
214 BIOerror(BIO_R_ACCEPT_ERROR
);
217 /* XXX Crazy API. Can't be helped */
223 if (sin
.sin_family
!= AF_INET
)
226 if (getnameinfo((struct sockaddr
*)&sin
, sin_len
, h
, sizeof(h
),
227 s
, sizeof(s
), NI_NUMERICHOST
|NI_NUMERICSERV
) != 0)
230 if ((asprintf(addr
, "%s:%s", h
, s
)) == -1) {
231 BIOerror(ERR_R_MALLOC_FAILURE
);
240 BIO_set_tcp_ndelay(int s
, int on
)
242 return (setsockopt(s
, IPPROTO_TCP
, TCP_NODELAY
, &on
, sizeof(on
)) == 0);