sock.c (4386B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <arpa/inet.h> 3 #include <errno.h> 4 #include <fcntl.h> 5 #include <netdb.h> 6 #include <netinet/in.h> 7 #include <stddef.h> 8 #include <stdio.h> 9 #include <string.h> 10 #include <sys/types.h> 11 #include <sys/socket.h> 12 #include <sys/stat.h> 13 #include <sys/time.h> 14 #include <sys/un.h> 15 #include <unistd.h> 16 17 #include "sock.h" 18 #include "util.h" 19 20 int 21 sock_get_ips(const char *host, const char* port) 22 { 23 struct addrinfo hints = { 24 .ai_flags = AI_NUMERICSERV, 25 .ai_family = AF_UNSPEC, 26 .ai_socktype = SOCK_STREAM, 27 }; 28 struct addrinfo *ai, *p; 29 int ret, insock = 0; 30 31 if ((ret = getaddrinfo(host, port, &hints, &ai))) { 32 die("getaddrinfo: %s", gai_strerror(ret)); 33 } 34 35 for (p = ai; p; p = p->ai_next) { 36 if ((insock = socket(p->ai_family, p->ai_socktype, 37 p->ai_protocol)) < 0) { 38 continue; 39 } 40 if (setsockopt(insock, SOL_SOCKET, SO_REUSEADDR, 41 &(int){1}, sizeof(int)) < 0) { 42 die("setsockopt:"); 43 } 44 if (bind(insock, p->ai_addr, p->ai_addrlen) < 0) { 45 /* bind failed, close the insock and retry */ 46 if (close(insock) < 0) { 47 die("close:"); 48 } 49 continue; 50 } 51 break; 52 } 53 freeaddrinfo(ai); 54 if (!p) { 55 /* we exhaustet the addrinfo-list and found no connection */ 56 if (errno == EACCES) { 57 die("You need to run as root or have " 58 "CAP_NET_BIND_SERVICE set to bind to " 59 "privileged ports"); 60 } else { 61 die("bind:"); 62 } 63 } 64 65 if (listen(insock, SOMAXCONN) < 0) { 66 die("listen:"); 67 } 68 69 return insock; 70 } 71 72 int 73 sock_get_uds(const char *udsname, uid_t uid, gid_t gid) 74 { 75 struct sockaddr_un addr = { 76 .sun_family = AF_UNIX, 77 }; 78 size_t udsnamelen; 79 int insock, sockmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | 80 S_IROTH | S_IWOTH; 81 82 if ((insock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 83 die("socket:"); 84 } 85 86 if ((udsnamelen = strlen(udsname)) > sizeof(addr.sun_path) - 1) { 87 die("UNIX-domain socket name truncated"); 88 } 89 memcpy(addr.sun_path, udsname, udsnamelen + 1); 90 91 if (bind(insock, (const struct sockaddr *)&addr, sizeof(addr)) < 0) { 92 die("bind '%s':", udsname); 93 } 94 95 if (listen(insock, SOMAXCONN) < 0) { 96 sock_rem_uds(udsname); 97 die("listen:"); 98 } 99 100 if (chmod(udsname, sockmode) < 0) { 101 sock_rem_uds(udsname); 102 die("chmod '%s':", udsname); 103 } 104 105 if (chown(udsname, uid, gid) < 0) { 106 sock_rem_uds(udsname); 107 die("chown '%s':", udsname); 108 } 109 110 return insock; 111 } 112 113 void 114 sock_rem_uds(const char *udsname) 115 { 116 if (unlink(udsname) < 0) { 117 die("unlink '%s':", udsname); 118 } 119 } 120 121 int 122 sock_set_timeout(int fd, int sec) 123 { 124 struct timeval tv; 125 126 tv.tv_sec = sec; 127 tv.tv_usec = 0; 128 129 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 || 130 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) { 131 warn("setsockopt:"); 132 return 1; 133 } 134 135 return 0; 136 } 137 138 int 139 sock_set_nonblocking(int fd) 140 { 141 int flags; 142 143 if ((flags = fcntl(fd, F_GETFL, 0)) < 0) { 144 warn("fcntl:"); 145 return 1; 146 } 147 148 flags |= O_NONBLOCK; 149 150 if (fcntl(fd, F_SETFL, flags) < 0) { 151 warn("fcntl:"); 152 return 1; 153 } 154 155 return 0; 156 } 157 158 int 159 sock_get_inaddr_str(const struct sockaddr_storage *in_sa, char *str, 160 size_t len) 161 { 162 switch (in_sa->ss_family) { 163 case AF_INET: 164 if (!inet_ntop(AF_INET, 165 &(((struct sockaddr_in *)in_sa)->sin_addr), 166 str, len)) { 167 warn("inet_ntop:"); 168 return 1; 169 } 170 break; 171 case AF_INET6: 172 if (!inet_ntop(AF_INET6, 173 &(((struct sockaddr_in6 *)in_sa)->sin6_addr), 174 str, len)) { 175 warn("inet_ntop:"); 176 return 1; 177 } 178 break; 179 case AF_UNIX: 180 snprintf(str, len, "uds"); 181 break; 182 default: 183 snprintf(str, len, "-"); 184 } 185 186 return 0; 187 } 188 189 int 190 sock_same_addr(const struct sockaddr_storage *sa1, const struct sockaddr_storage *sa2) 191 { 192 /* return early if address-families don't match */ 193 if (sa1->ss_family != sa2->ss_family) { 194 return 0; 195 } 196 197 switch (sa1->ss_family) { 198 case AF_INET6: 199 return memcmp(((struct sockaddr_in6 *)sa1)->sin6_addr.s6_addr, 200 ((struct sockaddr_in6 *)sa2)->sin6_addr.s6_addr, 201 sizeof(((struct sockaddr_in6 *)sa1)->sin6_addr.s6_addr)) == 0; 202 case AF_INET: 203 return ((struct sockaddr_in *)sa1)->sin_addr.s_addr == 204 ((struct sockaddr_in *)sa2)->sin_addr.s_addr; 205 default: /* AF_UNIX */ 206 return strcmp(((struct sockaddr_un *)sa1)->sun_path, 207 ((struct sockaddr_un *)sa2)->sun_path) == 0; 208 } 209 }