/* compatibility wrapper */ static int inet_parse(QemuOpts *opts, const char *str) { const char *optstr, *h; char addr[64]; char port[33]; int pos; /* parse address */ if (str[0] == ':') { /* no host given */ addr[0] = '\0'; if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { fprintf(stderr, "%s: portonly parse error (%s)\n", __FUNCTION__, str); return -1; } } else if (str[0] == '[') { /* IPv6 addr */ if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { fprintf(stderr, "%s: ipv6 parse error (%s)\n", __FUNCTION__, str); return -1; } qemu_opt_set(opts, "ipv6", "on"); } else if (qemu_isdigit(str[0])) { /* IPv4 addr */ if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { fprintf(stderr, "%s: ipv4 parse error (%s)\n", __FUNCTION__, str); return -1; } qemu_opt_set(opts, "ipv4", "on"); } else { /* hostname */ if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { fprintf(stderr, "%s: hostname parse error (%s)\n", __FUNCTION__, str); return -1; } } qemu_opt_set(opts, "host", addr); qemu_opt_set(opts, "port", port); /* parse options */ optstr = str + pos; h = strstr(optstr, ",to="); if (h) qemu_opt_set(opts, "to", h+4); if (strstr(optstr, ",ipv4")) qemu_opt_set(opts, "ipv4", "on"); if (strstr(optstr, ",ipv6")) qemu_opt_set(opts, "ipv6", "on"); return 0; }
int inet_connect_opts(QemuOpts *opts, Error **errp) { struct addrinfo ai,*res,*e; const char *addr; const char *port; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int sock,rc; bool block; memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_STREAM; addr = qemu_opt_get(opts, "host"); port = qemu_opt_get(opts, "port"); block = qemu_opt_get_bool(opts, "block", 0); if (addr == NULL || port == NULL) { fprintf(stderr, "inet_connect: host and/or port not specified\n"); error_set(errp, QERR_SOCKET_CREATE_FAILED); return -1; } if (qemu_opt_get_bool(opts, "ipv4", 0)) ai.ai_family = PF_INET; if (qemu_opt_get_bool(opts, "ipv6", 0)) ai.ai_family = PF_INET6; /* lookup */ if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, gai_strerror(rc)); error_set(errp, QERR_SOCKET_CREATE_FAILED); return -1; } for (e = res; e != NULL; e = e->ai_next) { if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); continue; } sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); if (sock < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, inet_strfamily(e->ai_family), strerror(errno)); continue; } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); if (!block) { socket_set_nonblock(sock); } /* connect to peer */ do { rc = 0; if (connect(sock, e->ai_addr, e->ai_addrlen) < 0) { rc = -socket_error(); } } while (rc == -EINTR); #ifdef _WIN32 if (!block && (rc == -EINPROGRESS || rc == -EWOULDBLOCK || rc == -WSAEALREADY)) { #else if (!block && (rc == -EINPROGRESS)) { #endif error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS); } else if (rc < 0) { if (NULL == e->ai_next) fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, inet_strfamily(e->ai_family), e->ai_canonname, uaddr, uport, strerror(errno)); closesocket(sock); sock = -1; continue; } freeaddrinfo(res); return sock; } error_set(errp, QERR_SOCKET_CONNECT_FAILED); freeaddrinfo(res); return -1; } int inet_dgram_opts(QemuOpts *opts) { struct addrinfo ai, *peer = NULL, *local = NULL; const char *addr; const char *port; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int sock = -1, rc; /* lookup peer addr */ memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; ai.ai_family = PF_UNSPEC; ai.ai_socktype = SOCK_DGRAM; addr = qemu_opt_get(opts, "host"); port = qemu_opt_get(opts, "port"); if (addr == NULL || strlen(addr) == 0) { addr = "localhost"; } if (port == NULL || strlen(port) == 0) { fprintf(stderr, "inet_dgram: port not specified\n"); return -1; } if (qemu_opt_get_bool(opts, "ipv4", 0)) ai.ai_family = PF_INET; if (qemu_opt_get_bool(opts, "ipv6", 0)) ai.ai_family = PF_INET6; if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, gai_strerror(rc)); return -1; } /* lookup local addr */ memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE; ai.ai_family = peer->ai_family; ai.ai_socktype = SOCK_DGRAM; addr = qemu_opt_get(opts, "localaddr"); port = qemu_opt_get(opts, "localport"); if (addr == NULL || strlen(addr) == 0) { addr = NULL; } if (!port || strlen(port) == 0) port = "0"; if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) { fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, gai_strerror(rc)); return -1; } /* create socket */ sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); if (sock < 0) { fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, inet_strfamily(peer->ai_family), strerror(errno)); goto err; } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); /* bind socket */ if (getnameinfo((struct sockaddr*)local->ai_addr,local->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); goto err; } if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) { fprintf(stderr,"%s: bind(%s,%s,%d): OK\n", __FUNCTION__, inet_strfamily(local->ai_family), uaddr, inet_getport(local)); goto err; } /* connect to peer */ if (getnameinfo((struct sockaddr*)peer->ai_addr, peer->ai_addrlen, uaddr, INET6_ADDRSTRLEN, uport, 32, NI_NUMERICHOST | NI_NUMERICSERV) != 0) { fprintf(stderr, "%s: getnameinfo: oops\n", __FUNCTION__); goto err; } if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) { fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, inet_strfamily(peer->ai_family), peer->ai_canonname, uaddr, uport, strerror(errno)); goto err; } freeaddrinfo(local); freeaddrinfo(peer); return sock; err: if (-1 != sock) closesocket(sock); if (local) freeaddrinfo(local); if (peer) freeaddrinfo(peer); return -1; } /* compatibility wrapper */ static int inet_parse(QemuOpts *opts, const char *str) { const char *optstr, *h; char addr[64]; char port[33]; int pos; /* parse address */ if (str[0] == ':') { /* no host given */ addr[0] = '\0'; if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { fprintf(stderr, "%s: portonly parse error (%s)\n", __FUNCTION__, str); return -1; } } else if (str[0] == '[') { /* IPv6 addr */ if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { fprintf(stderr, "%s: ipv6 parse error (%s)\n", __FUNCTION__, str); return -1; } qemu_opt_set(opts, "ipv6", "on"); } else if (qemu_isdigit(str[0])) { /* IPv4 addr */ if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { fprintf(stderr, "%s: ipv4 parse error (%s)\n", __FUNCTION__, str); return -1; } qemu_opt_set(opts, "ipv4", "on"); } else { /* hostname */ if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { fprintf(stderr, "%s: hostname parse error (%s)\n", __FUNCTION__, str); return -1; } } qemu_opt_set(opts, "host", addr); qemu_opt_set(opts, "port", port); /* parse options */ optstr = str + pos; h = strstr(optstr, ",to="); if (h) qemu_opt_set(opts, "to", h+4); if (strstr(optstr, ",ipv4")) qemu_opt_set(opts, "ipv4", "on"); if (strstr(optstr, ",ipv6")) qemu_opt_set(opts, "ipv6", "on"); return 0; } int inet_listen(const char *str, char *ostr, int olen, int socktype, int port_offset, Error **errp) { QemuOpts *opts; char *optstr; int sock = -1; opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); if (inet_parse(opts, str) == 0) { sock = inet_listen_opts(opts, port_offset, errp); if (sock != -1 && ostr) { optstr = strchr(str, ','); if (qemu_opt_get_bool(opts, "ipv6", 0)) { snprintf(ostr, olen, "[%s]:%s%s", qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"), optstr ? optstr : ""); } else { snprintf(ostr, olen, "%s:%s%s", qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"), optstr ? optstr : ""); } } } else { error_set(errp, QERR_SOCKET_CREATE_FAILED); } qemu_opts_del(opts); return sock; }
/* compatibility wrapper */ static InetSocketAddress *inet_parse(const char *str, Error **errp) { InetSocketAddress *addr; const char *optstr, *h; char host[64]; char port[33]; int to; int pos; addr = g_new0(InetSocketAddress, 1); /* parse address */ if (str[0] == ':') { /* no host given */ host[0] = '\0'; if (1 != sscanf(str, ":%32[^,]%n", port, &pos)) { error_setg(errp, "error parsing port in address '%s'", str); goto fail; } } else if (str[0] == '[') { /* IPv6 addr */ if (2 != sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos)) { error_setg(errp, "error parsing IPv6 address '%s'", str); goto fail; } addr->ipv6 = addr->has_ipv6 = true; } else if (qemu_isdigit(str[0])) { /* IPv4 addr */ if (2 != sscanf(str, "%64[0-9.]:%32[^,]%n", host, port, &pos)) { error_setg(errp, "error parsing IPv4 address '%s'", str); goto fail; } addr->ipv4 = addr->has_ipv4 = true; } else { /* hostname */ if (2 != sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos)) { error_setg(errp, "error parsing address '%s'", str); goto fail; } } addr->host = g_strdup(host); addr->port = g_strdup(port); /* parse options */ optstr = str + pos; h = strstr(optstr, ",to="); if (h) { h += 4; if (sscanf(h, "%d%n", &to, &pos) != 1 || (h[pos] != '\0' && h[pos] != ',')) { error_setg(errp, "error parsing to= argument"); goto fail; } addr->has_to = true; addr->to = to; } if (strstr(optstr, ",ipv4")) { addr->ipv4 = addr->has_ipv4 = true; } if (strstr(optstr, ",ipv6")) { addr->ipv6 = addr->has_ipv6 = true; } return addr; fail: qapi_free_InetSocketAddress(addr); return NULL; }
/* * Allocate TAP device, returns opened fd. * Stores dev name in the first arg(must be large enough). */ static int tap_alloc(char *dev, size_t dev_size) { int tap_fd, if_fd, ppa = -1; static int ip_fd = 0; char *ptr; static int arp_fd = 0; int ip_muxid, arp_muxid; struct strioctl strioc_if, strioc_ppa; int link_type = I_PLINK;; struct lifreq ifr; char actual_name[32] = ""; memset(&ifr, 0x0, sizeof(ifr)); if( *dev ){ ptr = dev; while( *ptr && !qemu_isdigit((int)*ptr) ) ptr++; ppa = atoi(ptr); } /* Check if IP device was opened */ if( ip_fd ) close(ip_fd); TFR(ip_fd = open("/dev/udp", O_RDWR, 0)); if (ip_fd < 0) { syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)"); return -1; } TFR(tap_fd = open("/dev/tap", O_RDWR, 0)); if (tap_fd < 0) { syslog(LOG_ERR, "Can't open /dev/tap"); return -1; } /* Assign a new PPA and get its unit number. */ strioc_ppa.ic_cmd = TUNNEWPPA; strioc_ppa.ic_timout = 0; strioc_ppa.ic_len = sizeof(ppa); strioc_ppa.ic_dp = (char *)&ppa; if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0) syslog (LOG_ERR, "Can't assign new interface"); TFR(if_fd = open("/dev/tap", O_RDWR, 0)); if (if_fd < 0) { syslog(LOG_ERR, "Can't open /dev/tap (2)"); return -1; } if(ioctl(if_fd, I_PUSH, "ip") < 0){ syslog(LOG_ERR, "Can't push IP module"); return -1; } if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) syslog(LOG_ERR, "Can't get flags\n"); snprintf (actual_name, 32, "tap%d", ppa); pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name); ifr.lifr_ppa = ppa; /* Assign ppa according to the unit number returned by tun device */ if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0) syslog (LOG_ERR, "Can't set PPA %d", ppa); if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0) syslog (LOG_ERR, "Can't get flags\n"); /* Push arp module to if_fd */ if (ioctl (if_fd, I_PUSH, "arp") < 0) syslog (LOG_ERR, "Can't push ARP module (2)"); /* Push arp module to ip_fd */ if (ioctl (ip_fd, I_POP, NULL) < 0) syslog (LOG_ERR, "I_POP failed\n"); if (ioctl (ip_fd, I_PUSH, "arp") < 0) syslog (LOG_ERR, "Can't push ARP module (3)\n"); /* Open arp_fd */ TFR(arp_fd = open ("/dev/tap", O_RDWR, 0)); if (arp_fd < 0) syslog (LOG_ERR, "Can't open %s\n", "/dev/tap"); /* Set ifname to arp */ strioc_if.ic_cmd = SIOCSLIFNAME; strioc_if.ic_timout = 0; strioc_if.ic_len = sizeof(ifr); strioc_if.ic_dp = (char *)𝔦 if (ioctl(arp_fd, I_STR, &strioc_if) < 0){ syslog (LOG_ERR, "Can't set ifname to arp\n"); } if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){ syslog(LOG_ERR, "Can't link TAP device to IP"); return -1; } if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0) syslog (LOG_ERR, "Can't link TAP device to ARP"); close (if_fd); memset(&ifr, 0x0, sizeof(ifr)); pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name); ifr.lifr_ip_muxid = ip_muxid; ifr.lifr_arp_muxid = arp_muxid; if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0) { ioctl (ip_fd, I_PUNLINK , arp_muxid); ioctl (ip_fd, I_PUNLINK, ip_muxid); syslog (LOG_ERR, "Can't set multiplexor id"); } snprintf(dev, dev_size, "tap%d", ppa); return tap_fd; }
/* compatibility wrapper */ static int inet_parse(QemuOpts *opts, const char *str) { const char *optstr, *h; char addr[64]; char port[33]; int pos; /* parse address */ if (str[0] == ':') { /* no host given */ addr[0] = '\0'; if (1 != sscanf(str,":%32[^,]%n",port,&pos)) { fprintf(stderr, "%s: portonly parse error (%s)\n", __FUNCTION__, str); return -1; } } else if (str[0] == '[') { /* IPv6 addr */ if (2 != sscanf(str,"[%64[^]]]:%32[^,]%n",addr,port,&pos)) { fprintf(stderr, "%s: ipv6 parse error (%s)\n", __FUNCTION__, str); return -1; } qemu_opt_set(opts, "ipv6", "on"); } else if (qemu_isdigit(str[0])) { /* IPv4 addr */ if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) { fprintf(stderr, "%s: ipv4 parse error (%s)\n", __FUNCTION__, str); return -1; } qemu_opt_set(opts, "ipv4", "on"); } else { /* hostname */ if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) { fprintf(stderr, "%s: hostname parse error (%s)\n", __FUNCTION__, str); return -1; } } qemu_opt_set(opts, "host", addr); qemu_opt_set(opts, "port", port); /* parse options */ optstr = str + pos; h = strstr(optstr, ",to="); if (h) qemu_opt_set(opts, "to", h+4); if (strstr(optstr, ",ipv4")) qemu_opt_set(opts, "ipv4", "on"); if (strstr(optstr, ",ipv6")) qemu_opt_set(opts, "ipv6", "on"); #ifdef CONFIG_ANDROID h = strstr(optstr, ",socket="); if (h) { int socket_fd; char str_fd[12]; if (1 != sscanf(h+7,"%d",&socket_fd)) { fprintf(stderr,"%s: socket fd parse error (%s)\n", __FUNCTION__, h+7); return -1; } if (socket_fd < 0 || socket_fd >= INT_MAX) { fprintf(stderr,"%s: socket fd range error (%d)\n", __FUNCTION__, socket_fd); return -1; } snprintf(str_fd, sizeof str_fd, "%d", socket_fd); qemu_opt_set(opts, "socket", str_fd); } #endif return 0; }