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 /* used temporarely until all users are converted to QemuOpts */ 33 QemuOptsList dummy_opts = { 34 .name = "dummy", 35 .head = TAILQ_HEAD_INITIALIZER(dummy_opts.head), 36 .desc = { 37 { 38 .name = "path", 39 .type = QEMU_OPT_STRING, 40 }, 41 { /* end if list */ } 42 }, 43 }; 44 45 static int inet_getport(struct addrinfo *e) 46 { 47 struct sockaddr_in *i4; 48 struct sockaddr_in6 *i6; 49 50 switch (e->ai_family) { 51 case PF_INET6: 52 i6 = (void*)e->ai_addr; 53 return ntohs(i6->sin6_port); 54 case PF_INET: 55 i4 = (void*)e->ai_addr; 56 return ntohs(i4->sin_port); 57 default: 58 return 0; 59 } 60 } 61 62 static void inet_setport(struct addrinfo *e, int port) 63 { 64 struct sockaddr_in *i4; 65 struct sockaddr_in6 *i6; 66 67 switch (e->ai_family) { 68 case PF_INET6: 69 i6 = (void*)e->ai_addr; 70 i6->sin6_port = htons(port); 71 break; 72 case PF_INET: 73 i4 = (void*)e->ai_addr; 74 i4->sin_port = htons(port); 75 break; 76 } 77 } 78 79 static const char *inet_strfamily(int family) 80 { 81 switch (family) { 82 case PF_INET6: return "ipv6"; 83 case PF_INET: return "ipv4"; 84 case PF_UNIX: return "unix"; 85 } 86 return "????"; 87 } 88 89 static void inet_print_addrinfo(const char *tag, struct addrinfo *res) 90 { 91 struct addrinfo *e; 92 char uaddr[INET6_ADDRSTRLEN+1]; 93 char uport[33]; 94 95 for (e = res; e != NULL; e = e->ai_next) { 96 getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, 97 uaddr,INET6_ADDRSTRLEN,uport,32, 98 NI_NUMERICHOST | NI_NUMERICSERV); 99 fprintf(stderr,"%s: getaddrinfo: family %s, host %s, port %s\n", 100 tag, inet_strfamily(e->ai_family), uaddr, uport); 101 } 102 } 103 104 int inet_listen(const char *str, char *ostr, int olen, 105 int socktype, int port_offset) 106 { 107 struct addrinfo ai,*res,*e; 108 char addr[64]; 109 char port[33]; 110 char uaddr[INET6_ADDRSTRLEN+1]; 111 char uport[33]; 112 const char *opts, *h; 113 int slisten,rc,pos,to,try_next; 114 115 memset(&ai,0, sizeof(ai)); 116 ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; 117 ai.ai_family = PF_UNSPEC; 118 ai.ai_socktype = socktype; 119 120 /* parse address */ 121 if (str[0] == ':') { 122 /* no host given */ 123 addr[0] = '\0'; 124 if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { 125 fprintf(stderr, "%s: portonly parse error (%s)\n", 126 __FUNCTION__, str); 127 return -1; 128 } 129 } else if (str[0] == '[') { 130 /* IPv6 addr */ 131 if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { 132 fprintf(stderr, "%s: ipv6 parse error (%s)\n", 133 __FUNCTION__, str); 134 return -1; 135 } 136 ai.ai_family = PF_INET6; 137 } else if (qemu_isdigit(str[0])) { 138 /* IPv4 addr */ 139 if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { 140 fprintf(stderr, "%s: ipv4 parse error (%s)\n", 141 __FUNCTION__, str); 142 return -1; 143 } 144 ai.ai_family = PF_INET; 145 } else { 146 /* hostname */ 147 if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { 148 fprintf(stderr, "%s: hostname parse error (%s)\n", 149 __FUNCTION__, str); 150 return -1; 151 } 152 } 153 154 /* parse options */ 155 opts = str + pos; 156 h = strstr(opts, ",to="); 157 to = h ? atoi(h+4) : 0; 158 if (strstr(opts, ",ipv4")) 159 ai.ai_family = PF_INET; 160 if (strstr(opts, ",ipv6")) 161 ai.ai_family = PF_INET6; 162 163 /* lookup */ 164 if (port_offset) 165 snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); 166 rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res); 167 if (rc != 0) { 168 fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__, 169 addr, port, gai_strerror(rc)); 170 return -1; 171 } 172 if (sockets_debug) 173 inet_print_addrinfo(__FUNCTION__, res); 174 175 /* create socket + bind */ 176 for (e = res; e != NULL; e = e->ai_next) { 177 getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, 178 uaddr,INET6_ADDRSTRLEN,uport,32, 179 NI_NUMERICHOST | NI_NUMERICSERV); 180 slisten = socket(e->ai_family, e->ai_socktype, e->ai_protocol); 181 if (slisten < 0) { 182 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, 183 inet_strfamily(e->ai_family), strerror(errno)); 184 continue; 185 } 186 187 setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); 188 #ifdef IPV6_V6ONLY 189 if (e->ai_family == PF_INET6) { 190 /* listen on both ipv4 and ipv6 */ 191 setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off, 192 sizeof(off)); 193 } 194 #endif 195 196 for (;;) { 197 if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { 198 if (sockets_debug) 199 fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, 200 inet_strfamily(e->ai_family), uaddr, inet_getport(e)); 201 goto listen; 202 } 203 try_next = to && (inet_getport(e) <= to + port_offset); 204 if (!try_next || sockets_debug) 205 fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, 206 inet_strfamily(e->ai_family), uaddr, inet_getport(e), 207 strerror(errno)); 208 if (try_next) { 209 inet_setport(e, inet_getport(e) + 1); 210 continue; 211 } 212 break; 213 } 214 closesocket(slisten); 215 } 216 fprintf(stderr, "%s: FAILED\n", __FUNCTION__); 217 freeaddrinfo(res); 218 return -1; 219 220 listen: 221 if (listen(slisten,1) != 0) { 222 perror("listen"); 223 closesocket(slisten); 224 freeaddrinfo(res); 225 return -1; 226 } 227 if (ostr) { 228 if (e->ai_family == PF_INET6) { 229 snprintf(ostr, olen, "[%s]:%d%s", uaddr, 230 inet_getport(e) - port_offset, opts); 231 } else { 232 snprintf(ostr, olen, "%s:%d%s", uaddr, 233 inet_getport(e) - port_offset, opts); 234 } 235 } 236 freeaddrinfo(res); 237 return slisten; 238 } 239 240 int inet_connect(const char *str, int socktype) 241 { 242 struct addrinfo ai,*res,*e; 243 char addr[64]; 244 char port[33]; 245 char uaddr[INET6_ADDRSTRLEN+1]; 246 char uport[33]; 247 int sock,rc; 248 249 memset(&ai,0, sizeof(ai)); 250 ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; 251 ai.ai_family = PF_UNSPEC; 252 ai.ai_socktype = socktype; 253 254 /* parse address */ 255 if (str[0] == '[') { 256 /* IPv6 addr */ 257 if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) { 258 fprintf(stderr, "%s: ipv6 parse error (%s)\n", 259 __FUNCTION__, str); 260 return -1; 261 } 262 ai.ai_family = PF_INET6; 263 } else if (qemu_isdigit(str[0])) { 264 /* IPv4 addr */ 265 if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) { 266 fprintf(stderr, "%s: ipv4 parse error (%s)\n", 267 __FUNCTION__, str); 268 return -1; 269 } 270 ai.ai_family = PF_INET; 271 } else { 272 /* hostname */ 273 if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) { 274 fprintf(stderr, "%s: hostname parse error (%s)\n", 275 __FUNCTION__, str); 276 return -1; 277 } 278 } 279 280 /* parse options */ 281 if (strstr(str, ",ipv4")) 282 ai.ai_family = PF_INET; 283 if (strstr(str, ",ipv6")) 284 ai.ai_family = PF_INET6; 285 286 /* lookup */ 287 if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { 288 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", gai_strerror(rc), 289 addr, port); 290 return -1; 291 } 292 if (sockets_debug) 293 inet_print_addrinfo(__FUNCTION__, res); 294 295 for (e = res; e != NULL; e = e->ai_next) { 296 if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, 297 uaddr,INET6_ADDRSTRLEN,uport,32, 298 NI_NUMERICHOST | NI_NUMERICSERV) != 0) { 299 fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); 300 continue; 301 } 302 sock = socket(e->ai_family, e->ai_socktype, e->ai_protocol); 303 if (sock < 0) { 304 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, 305 inet_strfamily(e->ai_family), strerror(errno)); 306 continue; 307 } 308 setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); 309 310 /* connect to peer */ 311 if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) { 312 if (sockets_debug || NULL == e->ai_next) 313 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, 314 inet_strfamily(e->ai_family), 315 e->ai_canonname, uaddr, uport, strerror(errno)); 316 closesocket(sock); 317 continue; 318 } 319 if (sockets_debug) 320 fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, 321 inet_strfamily(e->ai_family), 322 e->ai_canonname, uaddr, uport); 323 freeaddrinfo(res); 324 return sock; 325 } 326 freeaddrinfo(res); 327 return -1; 328 } 329 330 #ifndef _WIN32 331 332 int unix_listen(const char *str, char *ostr, int olen) 333 { 334 struct sockaddr_un un; 335 char *path, *opts; 336 int sock, fd, len; 337 338 sock = socket(PF_UNIX, SOCK_STREAM, 0); 339 if (sock < 0) { 340 perror("socket(unix)"); 341 return -1; 342 } 343 344 opts = strchr(str, ','); 345 if (opts) { 346 len = opts - str; 347 path = qemu_malloc(len+1); 348 snprintf(path, len+1, "%.*s", len, str); 349 } else 350 path = qemu_strdup(str); 351 352 memset(&un, 0, sizeof(un)); 353 un.sun_family = AF_UNIX; 354 if (path && strlen(path)) { 355 snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); 356 } else { 357 char *tmpdir = getenv("TMPDIR"); 358 snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX", 359 tmpdir ? tmpdir : "/tmp"); 360 /* 361 * This dummy fd usage silences the mktemp() unsecure warning. 362 * Using mkstemp() doesn't make things more secure here 363 * though. bind() complains about existing files, so we have 364 * to unlink first and thus re-open the race window. The 365 * worst case possible is bind() failing, i.e. a DoS attack. 366 */ 367 fd = mkstemp(un.sun_path); close(fd); 368 } 369 snprintf(ostr, olen, "%s%s", un.sun_path, opts ? opts : ""); 370 371 unlink(un.sun_path); 372 if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { 373 fprintf(stderr, "bind(unix:%s): %s\n", un.sun_path, strerror(errno)); 374 goto err; 375 } 376 if (listen(sock, 1) < 0) { 377 fprintf(stderr, "listen(unix:%s): %s\n", un.sun_path, strerror(errno)); 378 goto err; 379 } 380 381 if (sockets_debug) 382 fprintf(stderr, "bind(unix:%s): OK\n", un.sun_path); 383 qemu_free(path); 384 return sock; 385 386 err: 387 qemu_free(path); 388 closesocket(sock); 389 return -1; 390 } 391 392 int unix_connect_opts(QemuOpts *opts) 393 { 394 struct sockaddr_un un; 395 const char *path = qemu_opt_get(opts, "path"); 396 int sock; 397 398 if (NULL == path) { 399 fprintf(stderr, "unix connect: no path specified\n"); 400 return -1; 401 } 402 403 sock = socket(PF_UNIX, SOCK_STREAM, 0); 404 if (sock < 0) { 405 perror("socket(unix)"); 406 return -1; 407 } 408 409 memset(&un, 0, sizeof(un)); 410 un.sun_family = AF_UNIX; 411 snprintf(un.sun_path, sizeof(un.sun_path), "%s", path); 412 if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) { 413 fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno)); 414 return -1; 415 } 416 417 if (sockets_debug) 418 fprintf(stderr, "connect(unix:%s): OK\n", path); 419 return sock; 420 } 421 422 /* compatibility wrapper */ 423 int unix_connect(const char *path) 424 { 425 QemuOpts *opts; 426 int sock; 427 428 opts = qemu_opts_create(&dummy_opts, NULL, 0); 429 qemu_opt_set(opts, "path", path); 430 sock = unix_connect_opts(opts); 431 qemu_opts_del(opts); 432 return sock; 433 } 434 435 #else 436 437 int unix_listen(const char *path, char *ostr, int olen) 438 { 439 fprintf(stderr, "unix sockets are not available on windows\n"); 440 return -1; 441 } 442 443 int unix_connect(const char *path) 444 { 445 fprintf(stderr, "unix sockets are not available on windows\n"); 446 return -1; 447 } 448 449 #endif 450