1 /* 2 * inet and unix socket functions for qemu 3 * 4 * (c) 2008 Gerd Hoffmann <kraxel@redhat.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; under version 2 of the License. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <ctype.h> 19 #include <errno.h> 20 #include <unistd.h> 21 22 #include "qemu_socket.h" 23 #include "qemu-common.h" /* for qemu_isdigit */ 24 25 #ifndef AI_ADDRCONFIG 26 # define AI_ADDRCONFIG 0 27 #endif 28 29 static int sockets_debug = 0; 30 static const int on=1, off=0; 31 32 static int inet_getport(struct addrinfo *e) 33 { 34 struct sockaddr_in *i4; 35 struct sockaddr_in6 *i6; 36 37 switch (e->ai_family) { 38 case PF_INET6: 39 i6 = (void*)e->ai_addr; 40 return ntohs(i6->sin6_port); 41 case PF_INET: 42 i4 = (void*)e->ai_addr; 43 return ntohs(i4->sin_port); 44 default: 45 return 0; 46 } 47 } 48 49 static void inet_setport(struct addrinfo *e, int port) 50 { 51 struct sockaddr_in *i4; 52 struct sockaddr_in6 *i6; 53 54 switch (e->ai_family) { 55 case PF_INET6: 56 i6 = (void*)e->ai_addr; 57 i6->sin6_port = htons(port); 58 break; 59 case PF_INET: 60 i4 = (void*)e->ai_addr; 61 i4->sin_port = htons(port); 62 break; 63 } 64 } 65 66 static const char *inet_strfamily(int family) 67 { 68 switch (family) { 69 case PF_INET6: return "ipv6"; 70 case PF_INET: return "ipv4"; 71 case PF_UNIX: return "unix"; 72 } 73 return "????"; 74 } 75 76 static void inet_print_addrinfo(const char *tag, struct addrinfo *res) 77 { 78 struct addrinfo *e; 79 char uaddr[INET6_ADDRSTRLEN+1]; 80 char uport[33]; 81 82 for (e = res; e != NULL; e = e->ai_next) { 83 getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, 84 uaddr,INET6_ADDRSTRLEN,uport,32, 85 NI_NUMERICHOST | NI_NUMERICSERV); 86 fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n", 87 tag, inet_strfamily(e->ai_family), uaddr, uport); 88 } 89 } 90 91 int inet_listen(const char *str, char *ostr, int olen, 92 int socktype, int port_offset) 93 { 94 struct addrinfo ai,*res,*e; 95 char addr[64]; 96 char port[33]; 97 char uaddr[INET6_ADDRSTRLEN+1]; 98 char uport[33]; 99 const char *opts, *h; 100 int slisten,rc,pos,to,try_next; 101 102 memset(&ai,0, sizeof(ai)); 103 ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; 104 ai.ai_family = PF_UNSPEC; 105 ai.ai_socktype = socktype; 106 107 /* parse address */ 108 if (str[0] == ':') { 109 /* no host given */ 110 strcpy(addr,""); 111 if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { 112 fprintf(stderr, "%s: portonly parse error (%s)\n", 113 __FUNCTION__, str); 114 return -1; 115 } 116 } else if (str[0] == '[') { 117 /* IPv6 addr */ 118 if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { 119 fprintf(stderr, "%s: ipv6 parse error (%s)\n", 120 __FUNCTION__, str); 121 return -1; 122 } 123 ai.ai_family = PF_INET6; 124 } else if (qemu_isdigit(str[0])) { 125 /* IPv4 addr */ 126 if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { 127 fprintf(stderr, "%s: ipv4 parse error (%s)\n", 128 __FUNCTION__, str); 129 return -1; 130 } 131 ai.ai_family = PF_INET; 132 } else { 133 /* hostname */ 134 if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { 135 fprintf(stderr, "%s: hostname parse error (%s)\n", 136 __FUNCTION__, str); 137 return -1; 138 } 139 } 140 141 /* parse options */ 142 opts = str + pos; 143 h = strstr(opts, ",to="); 144 to = h ? atoi(h+4) : 0; 145 if (strstr(opts, ",ipv4")) 146 ai.ai_family = PF_INET; 147 if (strstr(opts, ",ipv6")) 148 ai.ai_family = PF_INET6; 149 150 /* lookup */ 151 if (port_offset) 152 snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); 153 rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); 154 if (rc != 0) { 155 fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__, 156 addr, port, gai_strerror(rc)); 157 return -1; 158 } 159 if (sockets_debug) 160 inet_print_addrinfo(__FUNCTION__, res); 161 162 /* create socket + bind */ 163 for (e = res; e != NULL; e = e->ai_next) { 164 getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, 165 uaddr,INET6_ADDRSTRLEN,uport,32, 166 NI_NUMERICHOST | NI_NUMERICSERV); 167 slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol); 168 if (slisten < 0) { 169 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, 170 inet_strfamily(e->ai_family), strerror(errno)); 171 continue; 172 } 173 174 setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); 175 #ifdef IPV6_V6ONLY 176 if (e->ai_family == PF_INET6) { 177 /* listen on both ipv4 and ipv6 */ 178 setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,sizeof(off)); 179 } 180 #endif 181 182 for (;;) { 183 if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { 184 if (sockets_debug) 185 fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, 186 inet_strfamily(e->ai_family), uaddr, inet_getport(e)); 187 goto listen; 188 } 189 try_next = to && (inet_getport(e) <= to + port_offset); 190 if (!try_next || sockets_debug) 191 fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, 192 inet_strfamily(e->ai_family), uaddr, inet_getport(e), 193 strerror(errno)); 194 if (try_next) { 195 inet_setport(e, inet_getport(e) + 1); 196 continue; 197 } 198 break; 199 } 200 closesocket(slisten); 201 } 202 fprintf(stderr, "%s: FAILED\n", __FUNCTION__); 203 freeaddrinfo(res); 204 return -1; 205 206 listen: 207 if (listen(slisten,1) != 0) { 208 perror("listen"); 209 closesocket(slisten); 210 return -1; 211 } 212 if (ostr) { 213 if (e->ai_family == PF_INET6) { 214 snprintf(ostr, olen, "[%s]:%d%s", uaddr, 215 inet_getport(e) - port_offset, opts); 216 } else { 217 snprintf(ostr, olen, "%s:%d%s", uaddr, 218 inet_getport(e) - port_offset, opts); 219 } 220 } 221 freeaddrinfo(res); 222 return slisten; 223 } 224 225 int inet_connect(const char *str, int socktype) 226 { 227 struct addrinfo ai,*res,*e; 228 char addr[64]; 229 char port[33]; 230 char uaddr[INET6_ADDRSTRLEN+1]; 231 char uport[33]; 232 int sock,rc; 233 234 memset(&ai,0, sizeof(ai)); 235 ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; 236 ai.ai_family = PF_UNSPEC; 237 ai.ai_socktype = socktype; 238 239 /* parse address */ 240 if (str[0] == '[') { 241 /* IPv6 addr */ 242 if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) { 243 fprintf(stderr, "%s: ipv6 parse error (%s)\n", 244 __FUNCTION__, str); 245 return -1; 246 } 247 ai.ai_family = PF_INET6; 248 } else if (qemu_isdigit(str[0])) { 249 /* IPv4 addr */ 250 if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) { 251 fprintf(stderr, "%s: ipv4 parse error (%s)\n", 252 __FUNCTION__, str); 253 return -1; 254 } 255 ai.ai_family = PF_INET; 256 } else { 257 /* hostname */ 258 if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) { 259 fprintf(stderr, "%s: hostname parse error (%s)\n", 260 __FUNCTION__, str); 261 return -1; 262 } 263 } 264 265 /* parse options */ 266 if (strstr(str, ",ipv4")) 267 ai.ai_family = PF_INET; 268 if (strstr(str, ",ipv6")) 269 ai.ai_family = PF_INET6; 270 271 /* lookup */ 272 if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { 273 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", gai_strerror(rc), 274 addr, port); 275 return -1; 276 } 277 if (sockets_debug) 278 inet_print_addrinfo(__FUNCTION__, res); 279 280 for (e = res; e != NULL; e = e->ai_next) { 281 if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, 282 uaddr,INET6_ADDRSTRLEN,uport,32, 283 NI_NUMERICHOST | NI_NUMERICSERV) != 0) { 284 fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); 285 continue; 286 } 287 sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol); 288 if (sock < 0) { 289 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, 290 inet_strfamily(e->ai_family), strerror(errno)); 291 continue; 292 } 293 setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); 294 295 /* connect to peer */ 296 if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) { 297 if (sockets_debug || NULL == e->ai_next) 298 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, 299 inet_strfamily(e->ai_family), 300 e->ai_canonname, uaddr, uport, strerror(errno)); 301 closesocket(sock); 302 continue; 303 } 304 if (sockets_debug) 305 fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, 306 inet_strfamily(e->ai_family), 307 e->ai_canonname, uaddr, uport); 308 freeaddrinfo(res); 309 return sock; 310 } 311 freeaddrinfo(res); 312 return -1; 313 } 314 315 #ifndef _WIN32 316 317 int unix_listen(const char *str, char *ostr, int olen) 318 { 319 struct sockaddr_un un; 320 char *path, *opts; 321 int sock, fd, len; 322 323 sock = socket(PF_UNIX, SOCK_STREAM, 0); 324 if (sock < 0) { 325 perror("socket(unix)"); 326 return -1; 327 } 328 329 opts = strchr(str, ','); 330 if (opts) { 331 len = opts - str; 332 path = malloc(len+1); 333 snprintf(path, len+1, "%.*s", len, str); 334 } else 335 path = strdup(str); 336 337 memset(&un, 0, sizeof(un)); 338 un.sun_family = AF_UNIX; 339 if (path && strlen(path)) { 340 snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); 341 } else { 342 char *tmpdir = getenv("TMPDIR"); 343 snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX", 344 tmpdir ? tmpdir : "/tmp"); 345 /* 346 * This dummy fd usage silences the mktemp() unsecure warning. 347 * Using mkstemp() doesn't make things more secure here 348 * though. bind() complains about existing files, so we have 349 * to unlink first and thus re-open the race window. The 350 * worst case possible is bind() failing, i.e. a DoS attack. 351 */ 352 fd = mkstemp(un.sun_path); close(fd); 353 } 354 snprintf(ostr, olen, "%s%s", un.sun_path, opts ? opts : ""); 355 356 unlink(un.sun_path); 357 if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { 358 fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno)); 359 goto err; 360 } 361 if (listen(sock, 1) < 0) { 362 fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno)); 363 goto err; 364 } 365 366 if (sockets_debug) 367 fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path); 368 free(path); 369 return sock; 370 371 err: 372 free(path); 373 closesocket(sock); 374 return -1; 375 } 376 377 int unix_connect(const char *path) 378 { 379 struct sockaddr_un un; 380 int sock; 381 382 sock = socket(PF_UNIX, SOCK_STREAM, 0); 383 if (sock < 0) { 384 perror("socket(unix)"); 385 return -1; 386 } 387 388 memset(&un, 0, sizeof(un)); 389 un.sun_family = AF_UNIX; 390 snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); 391 if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { 392 fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno)); 393 return -1; 394 } 395 396 if (sockets_debug) 397 fprintf(stderr, "connect(unix:%s): OK\n", path); 398 return sock; 399 } 400 401 #else 402 403 int unix_listen(const char *path, char *ostr, int olen) 404 { 405 fprintf(stderr, "unix sockets are not available on windows\n"); 406 return -1; 407 } 408 409 int unix_connect(const char *path) 410 { 411 fprintf(stderr, "unix sockets are not available on windows\n"); 412 return -1; 413 } 414 415 #endif 416