improve validation - add header length
[project/libubox.git] / usock.c
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <sys/un.h>
4 #include <netdb.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <errno.h>
9 #include <string.h>
10
11 #include "usock.h"
12
13 int usock(int type, const char *host, const char *service) {
14 int sock = -1;
15
16 if (service && !(type & USOCK_UNIX)) {
17 struct addrinfo *result, *rp;
18
19 struct addrinfo hints = {
20 .ai_family = (type & USOCK_IPV6ONLY) ? AF_INET6 :
21 (type & USOCK_IPV4ONLY) ? AF_INET : AF_UNSPEC,
22 .ai_socktype = ((type & 0xff) == USOCK_TCP)
23 ? SOCK_STREAM : SOCK_DGRAM,
24 .ai_flags = AI_ADDRCONFIG
25 | ((type & USOCK_SERVER) ? AI_PASSIVE : 0)
26 | ((type & USOCK_NUMERIC) ? AI_NUMERICHOST : 0),
27 };
28
29 if (getaddrinfo(host, service, &hints, &result)) {
30 return -1;
31 }
32
33 for (rp = result; rp != NULL; rp = rp->ai_next) {
34 if ((sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol))
35 == -1) {
36 continue;
37 }
38
39 if (!(type & USOCK_NOCLOEXEC)) {
40 fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
41 }
42
43 if (type & USOCK_NONBLOCK) {
44 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
45 }
46
47 if (type & USOCK_SERVER) {
48 const int one = 1;
49 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
50
51 if (!bind(sock, rp->ai_addr, rp->ai_addrlen)
52 && ((type & 0xff) != USOCK_TCP || !listen(sock, SOMAXCONN))) {
53 break;
54 }
55 } else {
56 if (!connect(sock, rp->ai_addr, rp->ai_addrlen)
57 || errno == EINPROGRESS) {
58 break;
59 }
60 }
61
62 close(sock);
63 sock = -1;
64 }
65 freeaddrinfo(result);
66 } else {
67 struct sockaddr_un sun = {.sun_family = AF_UNIX};
68 if (strlen(host) >= sizeof(sun.sun_path)) {
69 errno = EINVAL;
70 return -1;
71 }
72 strcpy(sun.sun_path, host);
73
74 if ((sock = socket(AF_UNIX, ((type & 0xff) == USOCK_TCP)
75 ? SOCK_STREAM : SOCK_DGRAM, 0)) == -1) {
76 return -1;
77 }
78
79 if (!(type & USOCK_NOCLOEXEC)) {
80 fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
81 }
82
83 if (type & USOCK_NONBLOCK) {
84 fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK);
85 }
86
87 if (type & USOCK_SERVER) {
88 if (bind(sock, (struct sockaddr*)&sun, sizeof(sun)) ||
89 ((type & 0xff) == USOCK_TCP && listen(sock, SOMAXCONN))) {
90 close(sock);
91 return -1;
92 }
93 } else {
94 if (connect(sock, (struct sockaddr*)&sun, sizeof(sun))
95 && errno != EINPROGRESS) {
96 close(sock);
97 return -1;
98 }
99 }
100 }
101 return sock;
102 }