File:  [Qemu by Fabrice Bellard] / qemu / qemu-sockets.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:50:49 2018 UTC (3 years, 2 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0105, qemu0104, qemu0103, qemu0102, qemu0101, qemu0100, HEAD
qemu 0.10.0

    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:         addr[0] = '\0';
  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

unix.superglobalmegacorp.com