1 /* 2 * inet and unix socket functions for qemu 3 * 4 * (c) 2008 Gerd Hoffmann <kraxel (at) 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 const char *sock_address_strfamily(SockAddress *s) 33 { 34 switch (sock_address_get_family(s)) { 35 case SOCKET_IN6: return "ipv6"; 36 case SOCKET_INET: return "ipv4"; 37 case SOCKET_UNIX: return "unix"; 38 default: return "????"; 39 } 40 } 41 42 int inet_listen(const char *str, char *ostr, int olen, 43 SocketType socktype, int port_offset) 44 { 45 SockAddress** list; 46 SockAddress* e; 47 unsigned flags = SOCKET_LIST_PASSIVE; 48 char addr[64]; 49 char port[33]; 50 char uaddr[256+1]; 51 const char *opts, *h; 52 int slisten,pos,to,try_next,nn; 53 54 /* parse address */ 55 if (str[0] == ':') { 56 /* no host given */ 57 addr[0] = '\0'; 58 if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { 59 fprintf(stderr, "%s: portonly parse error (%s)\n", 60 __FUNCTION__, str); 61 return -1; 62 } 63 } else if (str[0] == '[') { 64 /* IPv6 addr */ 65 if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { 66 fprintf(stderr, "%s: ipv6 parse error (%s)\n", 67 __FUNCTION__, str); 68 return -1; 69 } 70 flags |= SOCKET_LIST_FORCE_IN6; 71 } else if (qemu_isdigit(str[0])) { 72 /* IPv4 addr */ 73 if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { 74 fprintf(stderr, "%s: ipv4 parse error (%s)\n", 75 __FUNCTION__, str); 76 return -1; 77 } 78 flags |= SOCKET_LIST_FORCE_INET; 79 } else { 80 /* hostname */ 81 if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { 82 fprintf(stderr, "%s: hostname parse error (%s)\n", 83 __FUNCTION__, str); 84 return -1; 85 } 86 } 87 88 /* parse options */ 89 opts = str + pos; 90 h = strstr(opts, ",to="); 91 to = h ? atoi(h+4) : 0; 92 if (strstr(opts, ",ipv4")) { 93 flags &= ~SOCKET_LIST_FORCE_IN6; 94 flags |= SOCKET_LIST_FORCE_INET; 95 } 96 if (strstr(opts, ",ipv6")) { 97 flags &= SOCKET_LIST_FORCE_INET; 98 flags |= SOCKET_LIST_FORCE_IN6; 99 } 100 101 /* lookup */ 102 if (port_offset) 103 snprintf(port, sizeof(port), "%d", atoi(port) + port_offset); 104 105 list = sock_address_list_create( strlen(addr) ? addr : NULL, 106 port, 107 flags ); 108 if (list == NULL) { 109 fprintf(stderr,"%s: getaddrinfo(%s,%s): %s\n", __FUNCTION__, 110 addr, port, errno_str); 111 return -1; 112 } 113 114 /* create socket + bind */ 115 for (nn = 0; list[nn] != NULL; nn++) { 116 SocketFamily family; 117 118 e = list[nn]; 119 family = sock_address_get_family(e); 120 slisten = socket_create(family, socktype); 121 if (slisten < 0) { 122 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, 123 sock_address_strfamily(e), errno_str); 124 continue; 125 } 126 127 socket_set_xreuseaddr(slisten); 128 #ifdef IPV6_V6ONLY 129 /* listen on both ipv4 and ipv6 */ 130 if (family == PF_INET6) { 131 socket_set_ipv6only(slisten); 132 } 133 #endif 134 135 for (;;) { 136 if (socket_bind(slisten, e) == 0) { 137 if (sockets_debug) 138 fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, 139 sock_address_strfamily(e), uaddr, sock_address_get_port(e)); 140 goto listen; 141 } 142 socket_close(slisten); 143 try_next = to && (sock_address_get_port(e) <= to + port_offset); 144 if (!try_next || sockets_debug) 145 fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__, 146 sock_address_strfamily(e), uaddr, sock_address_get_port(e), 147 strerror(errno)); 148 if (try_next) { 149 sock_address_set_port(e, sock_address_get_port(e) + 1); 150 continue; 151 } 152 break; 153 } 154 } 155 sock_address_list_free(list); 156 fprintf(stderr, "%s: FAILED\n", __FUNCTION__); 157 return -1; 158 159 listen: 160 if (socket_listen(slisten,1) != 0) { 161 perror("listen"); 162 socket_close(slisten); 163 return -1; 164 } 165 if (ostr) { 166 if (flags & SOCKET_LIST_FORCE_IN6) { 167 snprintf(ostr, olen, "[%s]:%d%s", uaddr, 168 sock_address_get_port(e) - port_offset, opts); 169 } else { 170 snprintf(ostr, olen, "%s:%d%s", uaddr, 171 sock_address_get_port(e) - port_offset, opts); 172 } 173 } 174 sock_address_list_free(list); 175 return slisten; 176 } 177 178 int inet_connect(const char *str, SocketType socktype) 179 { 180 SockAddress** list; 181 SockAddress* e; 182 unsigned flags = 0; 183 char addr[64]; 184 char port[33]; 185 int sock, nn; 186 187 /* parse address */ 188 if (str[0] == '[') { 189 /* IPv6 addr */ 190 if (2 != sscanf(str,"[%64[^]]]:%32[^,]",addr,port)) { 191 fprintf(stderr, "%s: ipv6 parse error (%s)\n", 192 __FUNCTION__, str); 193 return -1; 194 } 195 flags |= SOCKET_LIST_FORCE_IN6; 196 } else if (qemu_isdigit(str[0])) { 197 /* IPv4 addr */ 198 if (2 != sscanf(str,"%64[0-9.]:%32[^,]",addr,port)) { 199 fprintf(stderr, "%s: ipv4 parse error (%s)\n", 200 __FUNCTION__, str); 201 return -1; 202 } 203 flags |= SOCKET_LIST_FORCE_INET; 204 } else { 205 /* hostname */ 206 if (2 != sscanf(str,"%64[^:]:%32[^,]",addr,port)) { 207 fprintf(stderr, "%s: hostname parse error (%s)\n", 208 __FUNCTION__, str); 209 return -1; 210 } 211 } 212 213 /* parse options */ 214 if (strstr(str, ",ipv4")) { 215 flags &= SOCKET_LIST_FORCE_IN6; 216 flags |= SOCKET_LIST_FORCE_INET; 217 } 218 if (strstr(str, ",ipv6")) { 219 flags &= SOCKET_LIST_FORCE_INET; 220 flags |= SOCKET_LIST_FORCE_IN6; 221 } 222 223 /* lookup */ 224 list = sock_address_list_create(addr, port, flags); 225 if (list == NULL) { 226 fprintf(stderr,"getaddrinfo(%s,%s): %s\n", 227 addr, port, errno_str); 228 return -1; 229 } 230 231 for (nn = 0; list[nn] != NULL; nn++) { 232 e = list[nn]; 233 sock = socket_create(sock_address_get_family(e), socktype); 234 if (sock < 0) { 235 fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, 236 sock_address_strfamily(e), errno_str); 237 continue; 238 } 239 socket_set_xreuseaddr(sock); 240 241 /* connect to peer */ 242 if (socket_connect(sock,e) < 0) { 243 if (sockets_debug) 244 fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, 245 sock_address_strfamily(e), 246 sock_address_to_string(e), addr, port, strerror(errno)); 247 socket_close(sock); 248 continue; 249 } 250 if (sockets_debug) 251 fprintf(stderr, "%s: connect(%s,%s,%s,%s): OK\n", __FUNCTION__, 252 sock_address_strfamily(e), 253 sock_address_to_string(e), addr, port); 254 255 goto EXIT; 256 } 257 sock = -1; 258 EXIT: 259 sock_address_list_free(list); 260 return sock; 261 } 262 263 #ifndef _WIN32 264 265 int unix_listen(const char *str, char *ostr, int olen) 266 { 267 SockAddress un; 268 char unpath[PATH_MAX]; 269 char *path, *upath, *opts; 270 int sock, fd, len; 271 272 opts = strchr(str, ','); 273 if (opts) { 274 len = opts - str; 275 path = qemu_malloc(len+1); 276 snprintf(path, len+1, "%.*s", len, str); 277 } else 278 path = qemu_strdup(str); 279 280 if (path || strlen(path) > 0) { 281 upath = path; 282 } else { 283 char *tmpdir = getenv("TMPDIR"); 284 snprintf(unpath, sizeof(unpath), "%s/qemu-socket-XXXXXX", 285 tmpdir ? tmpdir : "/tmp"); 286 /* 287 * This dummy fd usage silences the mktemp() unsecure warning. 288 * Using mkstemp() doesn't make things more secure here 289 * though. bind() complains about existing files, so we have 290 * to unlink first and thus re-open the race window. The 291 * worst case possible is bind() failing, i.e. a DoS attack. 292 */ 293 fd = mkstemp(unpath); close(fd); 294 upath = unpath; 295 } 296 snprintf(ostr, olen, "%s%s", path, opts ? opts : ""); 297 298 sock = socket_unix_server(upath, SOCKET_STREAM); 299 sock_address_done(&un); 300 301 if (sock < 0) { 302 fprintf(stderr, "bind(unix:%s): %s\n", upath, errno_str); 303 goto err; 304 } 305 306 if (sockets_debug) 307 fprintf(stderr, "bind(unix:%s): OK\n", upath); 308 309 qemu_free(path); 310 return sock; 311 312 err: 313 qemu_free(path); 314 socket_close(sock); 315 return -1; 316 } 317 318 int unix_connect(const char *path) 319 { 320 SockAddress un; 321 int ret, sock; 322 323 sock = socket_create_unix(SOCKET_STREAM); 324 if (sock < 0) { 325 perror("socket(unix)"); 326 return -1; 327 } 328 329 sock_address_init_unix(&un, path); 330 ret = socket_connect(sock, &un); 331 sock_address_done(&un); 332 if (ret < 0) { 333 fprintf(stderr, "connect(unix:%s): %s\n", path, errno_str); 334 return -1; 335 } 336 337 338 if (sockets_debug) 339 fprintf(stderr, "connect(unix:%s): OK\n", path); 340 return sock; 341 } 342 343 #else 344 345 int unix_listen(const char *path, char *ostr, int olen) 346 { 347 fprintf(stderr, "unix sockets are not available on windows\n"); 348 return -1; 349 } 350 351 int unix_connect(const char *path) 352 { 353 fprintf(stderr, "unix sockets are not available on windows\n"); 354 return -1; 355 } 356 357 #endif 358