aliguori | 305b0eb | 2008-11-13 16:19:54 +0000 | [diff] [blame] | 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. |
Paolo Bonzini | e6d91ab | 2012-07-09 11:08:39 +0200 | [diff] [blame] | 14 | * |
| 15 | * Contributions after 2012-01-13 are licensed under the terms of the |
| 16 | * GNU GPL, version 2 or (at your option) any later version. |
aliguori | 305b0eb | 2008-11-13 16:19:54 +0000 | [diff] [blame] | 17 | */ |
Peter Maydell | aafd758 | 2016-01-29 17:49:55 +0000 | [diff] [blame] | 18 | #include "qemu/osdep.h" |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 19 | |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 20 | #ifdef CONFIG_AF_VSOCK |
| 21 | #include <linux/vm_sockets.h> |
| 22 | #endif /* CONFIG_AF_VSOCK */ |
| 23 | |
Markus Armbruster | a8d2532 | 2019-05-23 16:35:08 +0200 | [diff] [blame] | 24 | #include "qemu-common.h" |
Paolo Bonzini | 83c9089 | 2012-12-17 18:19:49 +0100 | [diff] [blame] | 25 | #include "monitor/monitor.h" |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 26 | #include "qapi/clone-visitor.h" |
Markus Armbruster | da34e65 | 2016-03-14 09:01:28 +0100 | [diff] [blame] | 27 | #include "qapi/error.h" |
Markus Armbruster | 9af2398 | 2018-02-11 10:36:01 +0100 | [diff] [blame] | 28 | #include "qapi/qapi-visit-sockets.h" |
Paolo Bonzini | 1de7afc | 2012-12-17 18:20:00 +0100 | [diff] [blame] | 29 | #include "qemu/sockets.h" |
Paolo Bonzini | 1de7afc | 2012-12-17 18:20:00 +0100 | [diff] [blame] | 30 | #include "qemu/main-loop.h" |
Daniel P. Berrange | b3db211 | 2016-09-30 15:45:27 +0100 | [diff] [blame] | 31 | #include "qapi/qobject-input-visitor.h" |
| 32 | #include "qapi/qobject-output-visitor.h" |
Veronia Bahaa | f348b6d | 2016-03-20 19:16:19 +0200 | [diff] [blame] | 33 | #include "qemu/cutils.h" |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 34 | #include "trace.h" |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 35 | |
| 36 | #ifndef AI_ADDRCONFIG |
| 37 | # define AI_ADDRCONFIG 0 |
| 38 | #endif |
Daniel P. Berrange | 340849a | 2016-04-04 17:22:00 +0100 | [diff] [blame] | 39 | |
Wolfgang Bumiller | 3de3d69 | 2015-05-21 14:33:29 +0200 | [diff] [blame] | 40 | #ifndef AI_V4MAPPED |
| 41 | # define AI_V4MAPPED 0 |
| 42 | #endif |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 43 | |
Daniel P. Berrange | 6979a81 | 2016-07-19 12:58:52 +0100 | [diff] [blame] | 44 | #ifndef AI_NUMERICSERV |
| 45 | # define AI_NUMERICSERV 0 |
| 46 | #endif |
| 47 | |
Gerd Hoffmann | 2af2bf6 | 2009-09-10 10:58:37 +0200 | [diff] [blame] | 48 | |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 49 | static int inet_getport(struct addrinfo *e) |
| 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 | return ntohs(i6->sin6_port); |
| 58 | case PF_INET: |
| 59 | i4 = (void*)e->ai_addr; |
| 60 | return ntohs(i4->sin_port); |
| 61 | default: |
| 62 | return 0; |
| 63 | } |
| 64 | } |
| 65 | |
| 66 | static void inet_setport(struct addrinfo *e, int port) |
| 67 | { |
| 68 | struct sockaddr_in *i4; |
| 69 | struct sockaddr_in6 *i6; |
| 70 | |
| 71 | switch (e->ai_family) { |
| 72 | case PF_INET6: |
| 73 | i6 = (void*)e->ai_addr; |
| 74 | i6->sin6_port = htons(port); |
| 75 | break; |
| 76 | case PF_INET: |
| 77 | i4 = (void*)e->ai_addr; |
| 78 | i4->sin_port = htons(port); |
| 79 | break; |
| 80 | } |
| 81 | } |
| 82 | |
Wenchao Xia | a589569 | 2014-06-18 08:43:30 +0200 | [diff] [blame] | 83 | NetworkAddressFamily inet_netfamily(int family) |
| 84 | { |
| 85 | switch (family) { |
| 86 | case PF_INET6: return NETWORK_ADDRESS_FAMILY_IPV6; |
| 87 | case PF_INET: return NETWORK_ADDRESS_FAMILY_IPV4; |
| 88 | case PF_UNIX: return NETWORK_ADDRESS_FAMILY_UNIX; |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 89 | #ifdef CONFIG_AF_VSOCK |
| 90 | case PF_VSOCK: return NETWORK_ADDRESS_FAMILY_VSOCK; |
| 91 | #endif /* CONFIG_AF_VSOCK */ |
Wenchao Xia | a589569 | 2014-06-18 08:43:30 +0200 | [diff] [blame] | 92 | } |
| 93 | return NETWORK_ADDRESS_FAMILY_UNKNOWN; |
| 94 | } |
| 95 | |
Daniel P. Berrange | 58dc31f | 2017-12-21 12:55:20 +0000 | [diff] [blame] | 96 | bool fd_is_socket(int fd) |
| 97 | { |
| 98 | int optval; |
| 99 | socklen_t optlen = sizeof(optval); |
| 100 | return !qemu_getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen); |
| 101 | } |
| 102 | |
| 103 | |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 104 | /* |
| 105 | * Matrix we're trying to apply |
| 106 | * |
| 107 | * ipv4 ipv6 family |
| 108 | * - - PF_UNSPEC |
| 109 | * - f PF_INET |
| 110 | * - t PF_INET6 |
| 111 | * f - PF_INET6 |
| 112 | * f f <error> |
| 113 | * f t PF_INET6 |
| 114 | * t - PF_INET |
| 115 | * t f PF_INET |
Daniel P. Berrange | 94bc0d1 | 2017-05-17 14:17:55 +0100 | [diff] [blame] | 116 | * t t PF_INET6/PF_UNSPEC |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 117 | * |
Wei Jiangang | d43eda3 | 2016-03-14 17:58:29 +0800 | [diff] [blame] | 118 | * NB, this matrix is only about getting the necessary results |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 119 | * from getaddrinfo(). Some of the cases require further work |
| 120 | * after reading results from getaddrinfo in order to fully |
Daniel P. Berrange | 94bc0d1 | 2017-05-17 14:17:55 +0100 | [diff] [blame] | 121 | * apply the logic the end user wants. |
| 122 | * |
| 123 | * In the first and last cases, we must set IPV6_V6ONLY=0 |
| 124 | * when binding, to allow a single listener to potentially |
| 125 | * accept both IPv4+6 addresses. |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 126 | */ |
Daniel P. Berrange | c1b412f | 2016-07-19 12:54:47 +0100 | [diff] [blame] | 127 | int inet_ai_family_from_address(InetSocketAddress *addr, |
| 128 | Error **errp) |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 129 | { |
| 130 | if (addr->has_ipv6 && addr->has_ipv4 && |
| 131 | !addr->ipv6 && !addr->ipv4) { |
| 132 | error_setg(errp, "Cannot disable IPv4 and IPv6 at same time"); |
| 133 | return PF_UNSPEC; |
| 134 | } |
Daniel P. Berrange | 94bc0d1 | 2017-05-17 14:17:55 +0100 | [diff] [blame] | 135 | if ((addr->has_ipv6 && addr->ipv6) && (addr->has_ipv4 && addr->ipv4)) { |
| 136 | /* |
| 137 | * Some backends can only do a single listener. In that case |
| 138 | * we want empty hostname to resolve to "::" and then use the |
| 139 | * flag IPV6_V6ONLY==0 to get both protocols on 1 socket. This |
| 140 | * doesn't work for addresses other than "", so they're just |
| 141 | * inevitably broken until multiple listeners can be used, |
| 142 | * and thus we honour getaddrinfo automatic protocol detection |
| 143 | * Once all backends do multi-listener, remove the PF_INET6 |
| 144 | * branch entirely. |
| 145 | */ |
| 146 | if (!addr->host || g_str_equal(addr->host, "")) { |
| 147 | return PF_INET6; |
| 148 | } else { |
| 149 | return PF_UNSPEC; |
| 150 | } |
| 151 | } |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 152 | if ((addr->has_ipv6 && addr->ipv6) || (addr->has_ipv4 && !addr->ipv4)) { |
| 153 | return PF_INET6; |
| 154 | } |
| 155 | if ((addr->has_ipv4 && addr->ipv4) || (addr->has_ipv6 && !addr->ipv6)) { |
| 156 | return PF_INET; |
| 157 | } |
| 158 | return PF_UNSPEC; |
| 159 | } |
| 160 | |
Knut Omang | 39f8052 | 2017-08-07 12:58:41 +0200 | [diff] [blame] | 161 | static int create_fast_reuse_socket(struct addrinfo *e) |
| 162 | { |
| 163 | int slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); |
| 164 | if (slisten < 0) { |
| 165 | return -1; |
| 166 | } |
| 167 | socket_set_fast_reuse(slisten); |
| 168 | return slisten; |
| 169 | } |
| 170 | |
Knut Omang | 89382c3 | 2017-08-07 12:58:40 +0200 | [diff] [blame] | 171 | static int try_bind(int socket, InetSocketAddress *saddr, struct addrinfo *e) |
| 172 | { |
| 173 | #ifndef IPV6_V6ONLY |
| 174 | return bind(socket, e->ai_addr, e->ai_addrlen); |
| 175 | #else |
| 176 | /* |
| 177 | * Deals with first & last cases in matrix in comment |
| 178 | * for inet_ai_family_from_address(). |
| 179 | */ |
| 180 | int v6only = |
| 181 | ((!saddr->has_ipv4 && !saddr->has_ipv6) || |
| 182 | (saddr->has_ipv4 && saddr->ipv4 && |
| 183 | saddr->has_ipv6 && saddr->ipv6)) ? 0 : 1; |
| 184 | int stat; |
| 185 | |
| 186 | rebind: |
| 187 | if (e->ai_family == PF_INET6) { |
| 188 | qemu_setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, |
| 189 | sizeof(v6only)); |
| 190 | } |
| 191 | |
| 192 | stat = bind(socket, e->ai_addr, e->ai_addrlen); |
| 193 | if (!stat) { |
| 194 | return 0; |
| 195 | } |
| 196 | |
| 197 | /* If we got EADDRINUSE from an IPv6 bind & v6only is unset, |
| 198 | * it could be that the IPv4 port is already claimed, so retry |
| 199 | * with v6only set |
| 200 | */ |
| 201 | if (e->ai_family == PF_INET6 && errno == EADDRINUSE && !v6only) { |
| 202 | v6only = 1; |
| 203 | goto rebind; |
| 204 | } |
| 205 | return stat; |
| 206 | #endif |
| 207 | } |
| 208 | |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 209 | static int inet_listen_saddr(InetSocketAddress *saddr, |
| 210 | int port_offset, |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 211 | int num, |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 212 | Error **errp) |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 213 | { |
| 214 | struct addrinfo ai,*res,*e; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 215 | char port[33]; |
| 216 | char uaddr[INET6_ADDRSTRLEN+1]; |
| 217 | char uport[33]; |
Knut Omang | 9cf961b | 2017-08-07 12:58:42 +0200 | [diff] [blame] | 218 | int rc, port_min, port_max, p; |
Daniel P. Berrange | 10a7b7e | 2017-10-20 10:18:39 +0100 | [diff] [blame] | 219 | int slisten = -1; |
Knut Omang | 9cf961b | 2017-08-07 12:58:42 +0200 | [diff] [blame] | 220 | int saved_errno = 0; |
| 221 | bool socket_created = false; |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 222 | Error *err = NULL; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 223 | |
Vladimir Sementsov-Ogievskiy | aec21d3 | 2019-07-25 12:49:37 +0300 | [diff] [blame] | 224 | if (saddr->keep_alive) { |
| 225 | error_setg(errp, "keep-alive option is not supported for passive " |
| 226 | "sockets"); |
| 227 | return -1; |
| 228 | } |
| 229 | |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 230 | memset(&ai,0, sizeof(ai)); |
Wolfgang Bumiller | 3de3d69 | 2015-05-21 14:33:29 +0200 | [diff] [blame] | 231 | ai.ai_flags = AI_PASSIVE; |
Daniel P. Berrange | 6979a81 | 2016-07-19 12:58:52 +0100 | [diff] [blame] | 232 | if (saddr->has_numeric && saddr->numeric) { |
| 233 | ai.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV; |
| 234 | } |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 235 | ai.ai_family = inet_ai_family_from_address(saddr, &err); |
Gerd Hoffmann | e5bc776 | 2009-09-10 10:58:41 +0200 | [diff] [blame] | 236 | ai.ai_socktype = SOCK_STREAM; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 237 | |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 238 | if (err) { |
| 239 | error_propagate(errp, err); |
| 240 | return -1; |
| 241 | } |
| 242 | |
| 243 | if (saddr->host == NULL) { |
Daniel P. Berrange | 0983f5e | 2015-09-01 14:46:50 +0100 | [diff] [blame] | 244 | error_setg(errp, "host not specified"); |
Gerd Hoffmann | e5bc776 | 2009-09-10 10:58:41 +0200 | [diff] [blame] | 245 | return -1; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 246 | } |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 247 | if (saddr->port != NULL) { |
| 248 | pstrcpy(port, sizeof(port), saddr->port); |
Daniel P. Berrange | 0983f5e | 2015-09-01 14:46:50 +0100 | [diff] [blame] | 249 | } else { |
| 250 | port[0] = '\0'; |
| 251 | } |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 252 | |
| 253 | /* lookup */ |
Gerd Hoffmann | 8bc8912 | 2013-12-11 12:58:41 +0100 | [diff] [blame] | 254 | if (port_offset) { |
| 255 | unsigned long long baseport; |
Daniel P. Berrange | 0983f5e | 2015-09-01 14:46:50 +0100 | [diff] [blame] | 256 | if (strlen(port) == 0) { |
| 257 | error_setg(errp, "port not specified"); |
| 258 | return -1; |
| 259 | } |
Gerd Hoffmann | 8bc8912 | 2013-12-11 12:58:41 +0100 | [diff] [blame] | 260 | if (parse_uint_full(port, &baseport, 10) < 0) { |
| 261 | error_setg(errp, "can't convert to a number: %s", port); |
| 262 | return -1; |
| 263 | } |
| 264 | if (baseport > 65535 || |
| 265 | baseport + port_offset > 65535) { |
| 266 | error_setg(errp, "port %s out of range", port); |
| 267 | return -1; |
| 268 | } |
| 269 | snprintf(port, sizeof(port), "%d", (int)baseport + port_offset); |
| 270 | } |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 271 | rc = getaddrinfo(strlen(saddr->host) ? saddr->host : NULL, |
Daniel P. Berrange | 0983f5e | 2015-09-01 14:46:50 +0100 | [diff] [blame] | 272 | strlen(port) ? port : NULL, &ai, &res); |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 273 | if (rc != 0) { |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 274 | error_setg(errp, "address resolution failed for %s:%s: %s", |
| 275 | saddr->host, port, gai_strerror(rc)); |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 276 | return -1; |
| 277 | } |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 278 | |
Knut Omang | 9cf961b | 2017-08-07 12:58:42 +0200 | [diff] [blame] | 279 | /* create socket + bind/listen */ |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 280 | for (e = res; e != NULL; e = e->ai_next) { |
vibi | 39b6efc | 2009-05-06 15:27:03 +0530 | [diff] [blame] | 281 | getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, |
Paolo Bonzini | 7d37435 | 2018-12-13 23:37:37 +0100 | [diff] [blame] | 282 | uaddr,INET6_ADDRSTRLEN,uport,32, |
| 283 | NI_NUMERICHOST | NI_NUMERICSERV); |
Knut Omang | 39f8052 | 2017-08-07 12:58:41 +0200 | [diff] [blame] | 284 | |
Markus Armbruster | 877691f | 2012-02-07 15:09:15 +0100 | [diff] [blame] | 285 | port_min = inet_getport(e); |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 286 | port_max = saddr->has_to ? saddr->to + port_offset : port_min; |
Markus Armbruster | 877691f | 2012-02-07 15:09:15 +0100 | [diff] [blame] | 287 | for (p = port_min; p <= port_max; p++) { |
| 288 | inet_setport(e, p); |
Daniel P. Berrange | 10a7b7e | 2017-10-20 10:18:39 +0100 | [diff] [blame] | 289 | |
| 290 | slisten = create_fast_reuse_socket(e); |
| 291 | if (slisten < 0) { |
| 292 | /* First time we expect we might fail to create the socket |
| 293 | * eg if 'e' has AF_INET6 but ipv6 kmod is not loaded. |
| 294 | * Later iterations should always succeed if first iteration |
| 295 | * worked though, so treat that as fatal. |
| 296 | */ |
| 297 | if (p == port_min) { |
Knut Omang | 9cf961b | 2017-08-07 12:58:42 +0200 | [diff] [blame] | 298 | continue; |
| 299 | } else { |
Daniel P. Berrange | 10a7b7e | 2017-10-20 10:18:39 +0100 | [diff] [blame] | 300 | error_setg_errno(errp, errno, |
| 301 | "Failed to recreate failed listening socket"); |
Knut Omang | 9cf961b | 2017-08-07 12:58:42 +0200 | [diff] [blame] | 302 | goto listen_failed; |
Amos Kong | 029409e | 2012-05-11 00:28:26 +0800 | [diff] [blame] | 303 | } |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 304 | } |
Daniel P. Berrange | 10a7b7e | 2017-10-20 10:18:39 +0100 | [diff] [blame] | 305 | socket_created = true; |
| 306 | |
| 307 | rc = try_bind(slisten, saddr, e); |
| 308 | if (rc < 0) { |
| 309 | if (errno != EADDRINUSE) { |
| 310 | error_setg_errno(errp, errno, "Failed to bind socket"); |
| 311 | goto listen_failed; |
| 312 | } |
| 313 | } else { |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 314 | if (!listen(slisten, num)) { |
Daniel P. Berrange | 10a7b7e | 2017-10-20 10:18:39 +0100 | [diff] [blame] | 315 | goto listen_ok; |
| 316 | } |
| 317 | if (errno != EADDRINUSE) { |
| 318 | error_setg_errno(errp, errno, "Failed to listen on socket"); |
| 319 | goto listen_failed; |
| 320 | } |
Knut Omang | 9cf961b | 2017-08-07 12:58:42 +0200 | [diff] [blame] | 321 | } |
| 322 | /* Someone else managed to bind to the same port and beat us |
| 323 | * to listen on it! Socket semantics does not allow us to |
| 324 | * recover from this situation, so we need to recreate the |
| 325 | * socket to allow bind attempts for subsequent ports: |
| 326 | */ |
| 327 | closesocket(slisten); |
Daniel P. Berrange | 10a7b7e | 2017-10-20 10:18:39 +0100 | [diff] [blame] | 328 | slisten = -1; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 329 | } |
Knut Omang | 9cf961b | 2017-08-07 12:58:42 +0200 | [diff] [blame] | 330 | } |
| 331 | error_setg_errno(errp, errno, |
| 332 | socket_created ? |
| 333 | "Failed to find an available port" : |
| 334 | "Failed to create a socket"); |
| 335 | listen_failed: |
| 336 | saved_errno = errno; |
| 337 | if (slisten >= 0) { |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 338 | closesocket(slisten); |
| 339 | } |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 340 | freeaddrinfo(res); |
Knut Omang | 9cf961b | 2017-08-07 12:58:42 +0200 | [diff] [blame] | 341 | errno = saved_errno; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 342 | return -1; |
| 343 | |
Knut Omang | 9cf961b | 2017-08-07 12:58:42 +0200 | [diff] [blame] | 344 | listen_ok: |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 345 | freeaddrinfo(res); |
| 346 | return slisten; |
| 347 | } |
| 348 | |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 349 | #ifdef _WIN32 |
| 350 | #define QEMU_SOCKET_RC_INPROGRESS(rc) \ |
| 351 | ((rc) == -EINPROGRESS || (rc) == -EWOULDBLOCK || (rc) == -WSAEALREADY) |
| 352 | #else |
| 353 | #define QEMU_SOCKET_RC_INPROGRESS(rc) \ |
| 354 | ((rc) == -EINPROGRESS) |
| 355 | #endif |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 356 | |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 357 | static int inet_connect_addr(struct addrinfo *addr, Error **errp); |
Orit Wasserman | 233aa5c | 2012-09-24 13:11:09 +0200 | [diff] [blame] | 358 | |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 359 | static int inet_connect_addr(struct addrinfo *addr, Error **errp) |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 360 | { |
| 361 | int sock, rc; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 362 | |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 363 | sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); |
| 364 | if (sock < 0) { |
Markus Armbruster | 235256a | 2014-09-25 08:49:31 +0200 | [diff] [blame] | 365 | error_setg_errno(errp, errno, "Failed to create socket"); |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 366 | return -1; |
| 367 | } |
Sebastian Ottlik | 04fd1c7 | 2013-10-02 12:23:16 +0200 | [diff] [blame] | 368 | socket_set_fast_reuse(sock); |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 369 | |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 370 | /* connect to peer */ |
| 371 | do { |
| 372 | rc = 0; |
| 373 | if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) { |
Daniel P. Berrange | b16a44e | 2016-03-07 20:36:03 +0000 | [diff] [blame] | 374 | rc = -errno; |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 375 | } |
| 376 | } while (rc == -EINTR); |
| 377 | |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 378 | if (rc < 0) { |
Markus Armbruster | 235256a | 2014-09-25 08:49:31 +0200 | [diff] [blame] | 379 | error_setg_errno(errp, errno, "Failed to connect socket"); |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 380 | closesocket(sock); |
| 381 | return -1; |
| 382 | } |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 383 | |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 384 | return sock; |
| 385 | } |
| 386 | |
Daniel P. Berrange | 2942e42 | 2016-01-11 13:17:03 +0000 | [diff] [blame] | 387 | static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr, |
| 388 | Error **errp) |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 389 | { |
| 390 | struct addrinfo ai, *res; |
| 391 | int rc; |
Daniel P. Berrange | 2942e42 | 2016-01-11 13:17:03 +0000 | [diff] [blame] | 392 | Error *err = NULL; |
Daniel P. Berrange | 340849a | 2016-04-04 17:22:00 +0100 | [diff] [blame] | 393 | static int useV4Mapped = 1; |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 394 | |
| 395 | memset(&ai, 0, sizeof(ai)); |
Orit Wasserman | 233aa5c | 2012-09-24 13:11:09 +0200 | [diff] [blame] | 396 | |
Daniel P. Berrange | 340849a | 2016-04-04 17:22:00 +0100 | [diff] [blame] | 397 | ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; |
Stefan Hajnoczi | d73415a | 2020-09-23 11:56:46 +0100 | [diff] [blame] | 398 | if (qatomic_read(&useV4Mapped)) { |
Daniel P. Berrange | 340849a | 2016-04-04 17:22:00 +0100 | [diff] [blame] | 399 | ai.ai_flags |= AI_V4MAPPED; |
| 400 | } |
Daniel P. Berrange | 2942e42 | 2016-01-11 13:17:03 +0000 | [diff] [blame] | 401 | ai.ai_family = inet_ai_family_from_address(saddr, &err); |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 402 | ai.ai_socktype = SOCK_STREAM; |
| 403 | |
Daniel P. Berrange | 2942e42 | 2016-01-11 13:17:03 +0000 | [diff] [blame] | 404 | if (err) { |
| 405 | error_propagate(errp, err); |
| 406 | return NULL; |
| 407 | } |
| 408 | |
| 409 | if (saddr->host == NULL || saddr->port == NULL) { |
Paolo Bonzini | a12fb8a | 2012-10-02 09:18:02 +0200 | [diff] [blame] | 410 | error_setg(errp, "host and/or port not specified"); |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 411 | return NULL; |
| 412 | } |
| 413 | |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 414 | /* lookup */ |
Daniel P. Berrange | 2942e42 | 2016-01-11 13:17:03 +0000 | [diff] [blame] | 415 | rc = getaddrinfo(saddr->host, saddr->port, &ai, &res); |
Daniel P. Berrange | 340849a | 2016-04-04 17:22:00 +0100 | [diff] [blame] | 416 | |
| 417 | /* At least FreeBSD and OS-X 10.6 declare AI_V4MAPPED but |
| 418 | * then don't implement it in their getaddrinfo(). Detect |
zhaolichang | 8cc360b | 2020-09-17 15:50:24 +0800 | [diff] [blame] | 419 | * this and retry without the flag since that's preferable |
Daniel P. Berrange | 340849a | 2016-04-04 17:22:00 +0100 | [diff] [blame] | 420 | * to a fatal error |
| 421 | */ |
| 422 | if (rc == EAI_BADFLAGS && |
| 423 | (ai.ai_flags & AI_V4MAPPED)) { |
Stefan Hajnoczi | d73415a | 2020-09-23 11:56:46 +0100 | [diff] [blame] | 424 | qatomic_set(&useV4Mapped, 0); |
Daniel P. Berrange | 340849a | 2016-04-04 17:22:00 +0100 | [diff] [blame] | 425 | ai.ai_flags &= ~AI_V4MAPPED; |
| 426 | rc = getaddrinfo(saddr->host, saddr->port, &ai, &res); |
| 427 | } |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 428 | if (rc != 0) { |
Daniel P. Berrange | 2942e42 | 2016-01-11 13:17:03 +0000 | [diff] [blame] | 429 | error_setg(errp, "address resolution failed for %s:%s: %s", |
| 430 | saddr->host, saddr->port, gai_strerror(rc)); |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 431 | return NULL; |
| 432 | } |
| 433 | return res; |
| 434 | } |
| 435 | |
Orit Wasserman | 5db5f44 | 2012-09-24 13:11:08 +0200 | [diff] [blame] | 436 | /** |
| 437 | * Create a socket and connect it to an address. |
| 438 | * |
Daniel P. Berrange | 2942e42 | 2016-01-11 13:17:03 +0000 | [diff] [blame] | 439 | * @saddr: Inet socket address specification |
Orit Wasserman | 5db5f44 | 2012-09-24 13:11:08 +0200 | [diff] [blame] | 440 | * @errp: set on error |
| 441 | * |
| 442 | * Returns: -1 on error, file descriptor on success. |
| 443 | */ |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 444 | int inet_connect_saddr(InetSocketAddress *saddr, Error **errp) |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 445 | { |
Markus Armbruster | 3f9286b | 2014-05-19 18:57:37 +0200 | [diff] [blame] | 446 | Error *local_err = NULL; |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 447 | struct addrinfo *res, *e; |
| 448 | int sock = -1; |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 449 | |
Daniel P. Berrange | 2942e42 | 2016-01-11 13:17:03 +0000 | [diff] [blame] | 450 | res = inet_parse_connect_saddr(saddr, errp); |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 451 | if (!res) { |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 452 | return -1; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 453 | } |
| 454 | |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 455 | for (e = res; e != NULL; e = e->ai_next) { |
Markus Armbruster | 3f9286b | 2014-05-19 18:57:37 +0200 | [diff] [blame] | 456 | error_free(local_err); |
| 457 | local_err = NULL; |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 458 | sock = inet_connect_addr(e, &local_err); |
Markus Armbruster | 3f9286b | 2014-05-19 18:57:37 +0200 | [diff] [blame] | 459 | if (sock >= 0) { |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 460 | break; |
vibi | 39b6efc | 2009-05-06 15:27:03 +0530 | [diff] [blame] | 461 | } |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 462 | } |
Markus Armbruster | 3f9286b | 2014-05-19 18:57:37 +0200 | [diff] [blame] | 463 | |
Vladimir Sementsov-Ogievskiy | da5e116 | 2019-09-10 10:59:43 +0300 | [diff] [blame] | 464 | freeaddrinfo(res); |
| 465 | |
Markus Armbruster | 3f9286b | 2014-05-19 18:57:37 +0200 | [diff] [blame] | 466 | if (sock < 0) { |
| 467 | error_propagate(errp, local_err); |
Vladimir Sementsov-Ogievskiy | da5e116 | 2019-09-10 10:59:43 +0300 | [diff] [blame] | 468 | return sock; |
Markus Armbruster | 3f9286b | 2014-05-19 18:57:37 +0200 | [diff] [blame] | 469 | } |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 470 | |
Vladimir Sementsov-Ogievskiy | aec21d3 | 2019-07-25 12:49:37 +0300 | [diff] [blame] | 471 | if (saddr->keep_alive) { |
| 472 | int val = 1; |
| 473 | int ret = qemu_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, |
| 474 | &val, sizeof(val)); |
| 475 | |
| 476 | if (ret < 0) { |
| 477 | error_setg_errno(errp, errno, "Unable to set KEEPALIVE"); |
| 478 | close(sock); |
| 479 | return -1; |
| 480 | } |
| 481 | } |
| 482 | |
Michael S. Tsirkin | 05bc1d8 | 2012-09-24 13:11:07 +0200 | [diff] [blame] | 483 | return sock; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 484 | } |
| 485 | |
Daniel P. Berrange | 8b39910 | 2016-01-11 13:17:04 +0000 | [diff] [blame] | 486 | static int inet_dgram_saddr(InetSocketAddress *sraddr, |
| 487 | InetSocketAddress *sladdr, |
| 488 | Error **errp) |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 489 | { |
| 490 | struct addrinfo ai, *peer = NULL, *local = NULL; |
| 491 | const char *addr; |
| 492 | const char *port; |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 493 | int sock = -1, rc; |
Daniel P. Berrange | 8b39910 | 2016-01-11 13:17:04 +0000 | [diff] [blame] | 494 | Error *err = NULL; |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 495 | |
| 496 | /* lookup peer addr */ |
| 497 | memset(&ai,0, sizeof(ai)); |
Wolfgang Bumiller | 3de3d69 | 2015-05-21 14:33:29 +0200 | [diff] [blame] | 498 | ai.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ADDRCONFIG; |
Daniel P. Berrange | 8b39910 | 2016-01-11 13:17:04 +0000 | [diff] [blame] | 499 | ai.ai_family = inet_ai_family_from_address(sraddr, &err); |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 500 | ai.ai_socktype = SOCK_DGRAM; |
| 501 | |
Daniel P. Berrange | 8b39910 | 2016-01-11 13:17:04 +0000 | [diff] [blame] | 502 | if (err) { |
| 503 | error_propagate(errp, err); |
Paolo Bonzini | 58c652c | 2016-01-22 12:28:33 +0100 | [diff] [blame] | 504 | goto err; |
Daniel P. Berrange | 8b39910 | 2016-01-11 13:17:04 +0000 | [diff] [blame] | 505 | } |
| 506 | |
| 507 | addr = sraddr->host; |
| 508 | port = sraddr->port; |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 509 | if (addr == NULL || strlen(addr) == 0) { |
| 510 | addr = "localhost"; |
| 511 | } |
| 512 | if (port == NULL || strlen(port) == 0) { |
Paolo Bonzini | 4f085c8 | 2012-10-02 09:25:14 +0200 | [diff] [blame] | 513 | error_setg(errp, "remote port not specified"); |
Paolo Bonzini | 58c652c | 2016-01-22 12:28:33 +0100 | [diff] [blame] | 514 | goto err; |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 515 | } |
| 516 | |
Cao jin | 9cd1883 | 2016-07-28 18:50:04 +0800 | [diff] [blame] | 517 | if ((rc = getaddrinfo(addr, port, &ai, &peer)) != 0) { |
Paolo Bonzini | 4f085c8 | 2012-10-02 09:25:14 +0200 | [diff] [blame] | 518 | error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, |
| 519 | gai_strerror(rc)); |
Cao jin | 2601505 | 2016-07-28 16:54:33 +0800 | [diff] [blame] | 520 | goto err; |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 521 | } |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 522 | |
| 523 | /* lookup local addr */ |
| 524 | memset(&ai,0, sizeof(ai)); |
| 525 | ai.ai_flags = AI_PASSIVE; |
| 526 | ai.ai_family = peer->ai_family; |
| 527 | ai.ai_socktype = SOCK_DGRAM; |
| 528 | |
Daniel P. Berrange | 8b39910 | 2016-01-11 13:17:04 +0000 | [diff] [blame] | 529 | if (sladdr) { |
| 530 | addr = sladdr->host; |
| 531 | port = sladdr->port; |
| 532 | if (addr == NULL || strlen(addr) == 0) { |
| 533 | addr = NULL; |
| 534 | } |
| 535 | if (!port || strlen(port) == 0) { |
| 536 | port = "0"; |
| 537 | } |
| 538 | } else { |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 539 | addr = NULL; |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 540 | port = "0"; |
Daniel P. Berrange | 8b39910 | 2016-01-11 13:17:04 +0000 | [diff] [blame] | 541 | } |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 542 | |
Cao jin | 9cd1883 | 2016-07-28 18:50:04 +0800 | [diff] [blame] | 543 | if ((rc = getaddrinfo(addr, port, &ai, &local)) != 0) { |
Paolo Bonzini | 4f085c8 | 2012-10-02 09:25:14 +0200 | [diff] [blame] | 544 | error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, |
| 545 | gai_strerror(rc)); |
Stefan Weil | 39b3845 | 2012-09-01 09:40:26 +0200 | [diff] [blame] | 546 | goto err; |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 547 | } |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 548 | |
| 549 | /* create socket */ |
Kevin Wolf | 40ff6d7 | 2009-12-02 12:24:42 +0100 | [diff] [blame] | 550 | sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 551 | if (sock < 0) { |
Markus Armbruster | 235256a | 2014-09-25 08:49:31 +0200 | [diff] [blame] | 552 | error_setg_errno(errp, errno, "Failed to create socket"); |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 553 | goto err; |
| 554 | } |
Sebastian Ottlik | 04fd1c7 | 2013-10-02 12:23:16 +0200 | [diff] [blame] | 555 | socket_set_fast_reuse(sock); |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 556 | |
| 557 | /* bind socket */ |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 558 | if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) { |
Markus Armbruster | 235256a | 2014-09-25 08:49:31 +0200 | [diff] [blame] | 559 | error_setg_errno(errp, errno, "Failed to bind socket"); |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 560 | goto err; |
| 561 | } |
| 562 | |
| 563 | /* connect to peer */ |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 564 | if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) { |
Markus Armbruster | 235256a | 2014-09-25 08:49:31 +0200 | [diff] [blame] | 565 | error_setg_errno(errp, errno, "Failed to connect socket"); |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 566 | goto err; |
| 567 | } |
| 568 | |
| 569 | freeaddrinfo(local); |
| 570 | freeaddrinfo(peer); |
| 571 | return sock; |
| 572 | |
| 573 | err: |
Cao jin | 2601505 | 2016-07-28 16:54:33 +0800 | [diff] [blame] | 574 | if (sock != -1) { |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 575 | closesocket(sock); |
Cao jin | 2601505 | 2016-07-28 16:54:33 +0800 | [diff] [blame] | 576 | } |
| 577 | if (local) { |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 578 | freeaddrinfo(local); |
Cao jin | 2601505 | 2016-07-28 16:54:33 +0800 | [diff] [blame] | 579 | } |
| 580 | if (peer) { |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 581 | freeaddrinfo(peer); |
Cao jin | 2601505 | 2016-07-28 16:54:33 +0800 | [diff] [blame] | 582 | } |
| 583 | |
Gerd Hoffmann | 7e1b35b | 2009-09-10 10:58:51 +0200 | [diff] [blame] | 584 | return -1; |
| 585 | } |
| 586 | |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 587 | /* compatibility wrapper */ |
Daniel P. Berrange | 3e32370 | 2018-01-25 17:14:12 +0000 | [diff] [blame] | 588 | static int inet_parse_flag(const char *flagname, const char *optstr, bool *val, |
| 589 | Error **errp) |
| 590 | { |
| 591 | char *end; |
| 592 | size_t len; |
| 593 | |
| 594 | end = strstr(optstr, ","); |
| 595 | if (end) { |
| 596 | if (end[1] == ',') { /* Reject 'ipv6=on,,foo' */ |
| 597 | error_setg(errp, "error parsing '%s' flag '%s'", flagname, optstr); |
| 598 | return -1; |
| 599 | } |
| 600 | len = end - optstr; |
| 601 | } else { |
| 602 | len = strlen(optstr); |
| 603 | } |
| 604 | if (len == 0 || (len == 3 && strncmp(optstr, "=on", len) == 0)) { |
| 605 | *val = true; |
| 606 | } else if (len == 4 && strncmp(optstr, "=off", len) == 0) { |
| 607 | *val = false; |
| 608 | } else { |
| 609 | error_setg(errp, "error parsing '%s' flag '%s'", flagname, optstr); |
| 610 | return -1; |
| 611 | } |
| 612 | return 0; |
| 613 | } |
| 614 | |
Markus Armbruster | 0785bd7 | 2017-04-26 09:36:37 +0200 | [diff] [blame] | 615 | int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 616 | { |
| 617 | const char *optstr, *h; |
Kevin Wolf | 55a1099 | 2015-01-30 20:37:55 +0100 | [diff] [blame] | 618 | char host[65]; |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 619 | char port[33]; |
Paolo Bonzini | 879e45c | 2012-09-19 13:51:46 +0200 | [diff] [blame] | 620 | int to; |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 621 | int pos; |
Daniel P. Berrange | 3e32370 | 2018-01-25 17:14:12 +0000 | [diff] [blame] | 622 | char *begin; |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 623 | |
Markus Armbruster | 0785bd7 | 2017-04-26 09:36:37 +0200 | [diff] [blame] | 624 | memset(addr, 0, sizeof(*addr)); |
Paolo Bonzini | 879e45c | 2012-09-19 13:51:46 +0200 | [diff] [blame] | 625 | |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 626 | /* parse address */ |
| 627 | if (str[0] == ':') { |
| 628 | /* no host given */ |
Paolo Bonzini | 879e45c | 2012-09-19 13:51:46 +0200 | [diff] [blame] | 629 | host[0] = '\0'; |
Cao jin | 9cd1883 | 2016-07-28 18:50:04 +0800 | [diff] [blame] | 630 | if (sscanf(str, ":%32[^,]%n", port, &pos) != 1) { |
Paolo Bonzini | 2f002c4 | 2012-09-19 13:22:21 +0200 | [diff] [blame] | 631 | error_setg(errp, "error parsing port in address '%s'", str); |
Markus Armbruster | 0785bd7 | 2017-04-26 09:36:37 +0200 | [diff] [blame] | 632 | return -1; |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 633 | } |
| 634 | } else if (str[0] == '[') { |
| 635 | /* IPv6 addr */ |
Cao jin | 9cd1883 | 2016-07-28 18:50:04 +0800 | [diff] [blame] | 636 | if (sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos) != 2) { |
Paolo Bonzini | 2f002c4 | 2012-09-19 13:22:21 +0200 | [diff] [blame] | 637 | error_setg(errp, "error parsing IPv6 address '%s'", str); |
Markus Armbruster | 0785bd7 | 2017-04-26 09:36:37 +0200 | [diff] [blame] | 638 | return -1; |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 639 | } |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 640 | } else { |
Ján Tomko | 391b7b9 | 2013-06-03 17:54:55 +0200 | [diff] [blame] | 641 | /* hostname or IPv4 addr */ |
Cao jin | 9cd1883 | 2016-07-28 18:50:04 +0800 | [diff] [blame] | 642 | if (sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos) != 2) { |
Paolo Bonzini | 2f002c4 | 2012-09-19 13:22:21 +0200 | [diff] [blame] | 643 | error_setg(errp, "error parsing address '%s'", str); |
Markus Armbruster | 0785bd7 | 2017-04-26 09:36:37 +0200 | [diff] [blame] | 644 | return -1; |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 645 | } |
| 646 | } |
Paolo Bonzini | 879e45c | 2012-09-19 13:51:46 +0200 | [diff] [blame] | 647 | |
| 648 | addr->host = g_strdup(host); |
| 649 | addr->port = g_strdup(port); |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 650 | |
| 651 | /* parse options */ |
| 652 | optstr = str + pos; |
| 653 | h = strstr(optstr, ",to="); |
Paolo Bonzini | 879e45c | 2012-09-19 13:51:46 +0200 | [diff] [blame] | 654 | if (h) { |
Anthony PERARD | 1ccbc28 | 2012-11-16 04:08:14 +0000 | [diff] [blame] | 655 | h += 4; |
| 656 | if (sscanf(h, "%d%n", &to, &pos) != 1 || |
| 657 | (h[pos] != '\0' && h[pos] != ',')) { |
Paolo Bonzini | 879e45c | 2012-09-19 13:51:46 +0200 | [diff] [blame] | 658 | error_setg(errp, "error parsing to= argument"); |
Markus Armbruster | 0785bd7 | 2017-04-26 09:36:37 +0200 | [diff] [blame] | 659 | return -1; |
Paolo Bonzini | 879e45c | 2012-09-19 13:51:46 +0200 | [diff] [blame] | 660 | } |
| 661 | addr->has_to = true; |
| 662 | addr->to = to; |
| 663 | } |
Daniel P. Berrange | 3e32370 | 2018-01-25 17:14:12 +0000 | [diff] [blame] | 664 | begin = strstr(optstr, ",ipv4"); |
| 665 | if (begin) { |
| 666 | if (inet_parse_flag("ipv4", begin + 5, &addr->ipv4, errp) < 0) { |
| 667 | return -1; |
| 668 | } |
| 669 | addr->has_ipv4 = true; |
Paolo Bonzini | 879e45c | 2012-09-19 13:51:46 +0200 | [diff] [blame] | 670 | } |
Daniel P. Berrange | 3e32370 | 2018-01-25 17:14:12 +0000 | [diff] [blame] | 671 | begin = strstr(optstr, ",ipv6"); |
| 672 | if (begin) { |
| 673 | if (inet_parse_flag("ipv6", begin + 5, &addr->ipv6, errp) < 0) { |
| 674 | return -1; |
| 675 | } |
| 676 | addr->has_ipv6 = true; |
Paolo Bonzini | 879e45c | 2012-09-19 13:51:46 +0200 | [diff] [blame] | 677 | } |
Vladimir Sementsov-Ogievskiy | aec21d3 | 2019-07-25 12:49:37 +0300 | [diff] [blame] | 678 | begin = strstr(optstr, ",keep-alive"); |
| 679 | if (begin) { |
| 680 | if (inet_parse_flag("keep-alive", begin + strlen(",keep-alive"), |
| 681 | &addr->keep_alive, errp) < 0) |
| 682 | { |
| 683 | return -1; |
| 684 | } |
| 685 | addr->has_keep_alive = true; |
| 686 | } |
Markus Armbruster | 0785bd7 | 2017-04-26 09:36:37 +0200 | [diff] [blame] | 687 | return 0; |
Paolo Bonzini | 879e45c | 2012-09-19 13:51:46 +0200 | [diff] [blame] | 688 | } |
| 689 | |
Gerd Hoffmann | e5bc776 | 2009-09-10 10:58:41 +0200 | [diff] [blame] | 690 | |
Orit Wasserman | 5db5f44 | 2012-09-24 13:11:08 +0200 | [diff] [blame] | 691 | /** |
| 692 | * Create a blocking socket and connect it to an address. |
| 693 | * |
| 694 | * @str: address string |
| 695 | * @errp: set in case of an error |
| 696 | * |
| 697 | * Returns -1 in case of error, file descriptor on success |
| 698 | **/ |
| 699 | int inet_connect(const char *str, Error **errp) |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 700 | { |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 701 | int sock = -1; |
Markus Armbruster | 0785bd7 | 2017-04-26 09:36:37 +0200 | [diff] [blame] | 702 | InetSocketAddress *addr = g_new(InetSocketAddress, 1); |
Gerd Hoffmann | f4c94c7 | 2009-09-10 10:58:40 +0200 | [diff] [blame] | 703 | |
Markus Armbruster | 0785bd7 | 2017-04-26 09:36:37 +0200 | [diff] [blame] | 704 | if (!inet_parse(addr, str, errp)) { |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 705 | sock = inet_connect_saddr(addr, errp); |
Orit Wasserman | 5db5f44 | 2012-09-24 13:11:08 +0200 | [diff] [blame] | 706 | } |
Markus Armbruster | 0785bd7 | 2017-04-26 09:36:37 +0200 | [diff] [blame] | 707 | qapi_free_InetSocketAddress(addr); |
Orit Wasserman | 5db5f44 | 2012-09-24 13:11:08 +0200 | [diff] [blame] | 708 | return sock; |
| 709 | } |
| 710 | |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 711 | #ifdef CONFIG_AF_VSOCK |
| 712 | static bool vsock_parse_vaddr_to_sockaddr(const VsockSocketAddress *vaddr, |
| 713 | struct sockaddr_vm *svm, |
| 714 | Error **errp) |
| 715 | { |
| 716 | unsigned long long val; |
| 717 | |
| 718 | memset(svm, 0, sizeof(*svm)); |
| 719 | svm->svm_family = AF_VSOCK; |
| 720 | |
| 721 | if (parse_uint_full(vaddr->cid, &val, 10) < 0 || |
| 722 | val > UINT32_MAX) { |
| 723 | error_setg(errp, "Failed to parse cid '%s'", vaddr->cid); |
| 724 | return false; |
| 725 | } |
| 726 | svm->svm_cid = val; |
| 727 | |
| 728 | if (parse_uint_full(vaddr->port, &val, 10) < 0 || |
| 729 | val > UINT32_MAX) { |
| 730 | error_setg(errp, "Failed to parse port '%s'", vaddr->port); |
| 731 | return false; |
| 732 | } |
| 733 | svm->svm_port = val; |
| 734 | |
| 735 | return true; |
| 736 | } |
| 737 | |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 738 | static int vsock_connect_addr(const struct sockaddr_vm *svm, Error **errp) |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 739 | { |
| 740 | int sock, rc; |
| 741 | |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 742 | sock = qemu_socket(AF_VSOCK, SOCK_STREAM, 0); |
| 743 | if (sock < 0) { |
| 744 | error_setg_errno(errp, errno, "Failed to create socket"); |
| 745 | return -1; |
| 746 | } |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 747 | |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 748 | /* connect to peer */ |
| 749 | do { |
| 750 | rc = 0; |
| 751 | if (connect(sock, (const struct sockaddr *)svm, sizeof(*svm)) < 0) { |
| 752 | rc = -errno; |
| 753 | } |
| 754 | } while (rc == -EINTR); |
| 755 | |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 756 | if (rc < 0) { |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 757 | error_setg_errno(errp, errno, "Failed to connect socket"); |
| 758 | closesocket(sock); |
| 759 | return -1; |
| 760 | } |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 761 | |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 762 | return sock; |
| 763 | } |
| 764 | |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 765 | static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp) |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 766 | { |
| 767 | struct sockaddr_vm svm; |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 768 | |
| 769 | if (!vsock_parse_vaddr_to_sockaddr(vaddr, &svm, errp)) { |
| 770 | return -1; |
| 771 | } |
| 772 | |
Simran Singhal | b3ac2b9 | 2020-04-01 22:23:14 +0530 | [diff] [blame] | 773 | return vsock_connect_addr(&svm, errp); |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 774 | } |
| 775 | |
| 776 | static int vsock_listen_saddr(VsockSocketAddress *vaddr, |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 777 | int num, |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 778 | Error **errp) |
| 779 | { |
| 780 | struct sockaddr_vm svm; |
| 781 | int slisten; |
| 782 | |
| 783 | if (!vsock_parse_vaddr_to_sockaddr(vaddr, &svm, errp)) { |
| 784 | return -1; |
| 785 | } |
| 786 | |
| 787 | slisten = qemu_socket(AF_VSOCK, SOCK_STREAM, 0); |
| 788 | if (slisten < 0) { |
| 789 | error_setg_errno(errp, errno, "Failed to create socket"); |
| 790 | return -1; |
| 791 | } |
| 792 | |
| 793 | if (bind(slisten, (const struct sockaddr *)&svm, sizeof(svm)) != 0) { |
| 794 | error_setg_errno(errp, errno, "Failed to bind socket"); |
| 795 | closesocket(slisten); |
| 796 | return -1; |
| 797 | } |
| 798 | |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 799 | if (listen(slisten, num) != 0) { |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 800 | error_setg_errno(errp, errno, "Failed to listen on socket"); |
| 801 | closesocket(slisten); |
| 802 | return -1; |
| 803 | } |
| 804 | return slisten; |
| 805 | } |
| 806 | |
Markus Armbruster | 4db5c61 | 2017-04-26 09:36:36 +0200 | [diff] [blame] | 807 | static int vsock_parse(VsockSocketAddress *addr, const char *str, |
| 808 | Error **errp) |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 809 | { |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 810 | char cid[33]; |
| 811 | char port[33]; |
| 812 | int n; |
| 813 | |
| 814 | if (sscanf(str, "%32[^:]:%32[^,]%n", cid, port, &n) != 2) { |
| 815 | error_setg(errp, "error parsing address '%s'", str); |
Markus Armbruster | 4db5c61 | 2017-04-26 09:36:36 +0200 | [diff] [blame] | 816 | return -1; |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 817 | } |
| 818 | if (str[n] != '\0') { |
| 819 | error_setg(errp, "trailing characters in address '%s'", str); |
Markus Armbruster | 4db5c61 | 2017-04-26 09:36:36 +0200 | [diff] [blame] | 820 | return -1; |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 821 | } |
| 822 | |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 823 | addr->cid = g_strdup(cid); |
| 824 | addr->port = g_strdup(port); |
Markus Armbruster | 4db5c61 | 2017-04-26 09:36:36 +0200 | [diff] [blame] | 825 | return 0; |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 826 | } |
| 827 | #else |
| 828 | static void vsock_unsupported(Error **errp) |
| 829 | { |
| 830 | error_setg(errp, "socket family AF_VSOCK unsupported"); |
| 831 | } |
| 832 | |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 833 | static int vsock_connect_saddr(VsockSocketAddress *vaddr, Error **errp) |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 834 | { |
| 835 | vsock_unsupported(errp); |
| 836 | return -1; |
| 837 | } |
| 838 | |
| 839 | static int vsock_listen_saddr(VsockSocketAddress *vaddr, |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 840 | int num, |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 841 | Error **errp) |
| 842 | { |
| 843 | vsock_unsupported(errp); |
| 844 | return -1; |
| 845 | } |
| 846 | |
Markus Armbruster | 4db5c61 | 2017-04-26 09:36:36 +0200 | [diff] [blame] | 847 | static int vsock_parse(VsockSocketAddress *addr, const char *str, |
| 848 | Error **errp) |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 849 | { |
| 850 | vsock_unsupported(errp); |
Markus Armbruster | 4db5c61 | 2017-04-26 09:36:36 +0200 | [diff] [blame] | 851 | return -1; |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 852 | } |
| 853 | #endif /* CONFIG_AF_VSOCK */ |
| 854 | |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 855 | #ifndef _WIN32 |
| 856 | |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 857 | static int unix_listen_saddr(UnixSocketAddress *saddr, |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 858 | int num, |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 859 | Error **errp) |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 860 | { |
| 861 | struct sockaddr_un un; |
Gerd Hoffmann | 62b6adf | 2009-09-10 10:58:38 +0200 | [diff] [blame] | 862 | int sock, fd; |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 863 | char *pathbuf = NULL; |
| 864 | const char *path; |
Daniel P. Berrangé | 2d2023c | 2019-05-01 15:50:52 +0100 | [diff] [blame] | 865 | size_t pathlen; |
xiaoqiang zhao | 776b97d | 2020-05-16 11:13:25 +0800 | [diff] [blame] | 866 | size_t addrlen; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 867 | |
Kevin Wolf | 40ff6d7 | 2009-12-02 12:24:42 +0100 | [diff] [blame] | 868 | sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 869 | if (sock < 0) { |
Paolo Bonzini | b658c53 | 2015-01-26 12:12:24 +0100 | [diff] [blame] | 870 | error_setg_errno(errp, errno, "Failed to create Unix socket"); |
vibi | 39b6efc | 2009-05-06 15:27:03 +0530 | [diff] [blame] | 871 | return -1; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 872 | } |
| 873 | |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 874 | if (saddr->path && saddr->path[0]) { |
| 875 | path = saddr->path; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 876 | } else { |
Paolo Bonzini | b658c53 | 2015-01-26 12:12:24 +0100 | [diff] [blame] | 877 | const char *tmpdir = getenv("TMPDIR"); |
| 878 | tmpdir = tmpdir ? tmpdir : "/tmp"; |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 879 | path = pathbuf = g_strdup_printf("%s/qemu-socket-XXXXXX", tmpdir); |
| 880 | } |
Paolo Bonzini | b658c53 | 2015-01-26 12:12:24 +0100 | [diff] [blame] | 881 | |
Daniel P. Berrangé | 2d2023c | 2019-05-01 15:50:52 +0100 | [diff] [blame] | 882 | pathlen = strlen(path); |
xiaoqiang zhao | 776b97d | 2020-05-16 11:13:25 +0800 | [diff] [blame] | 883 | if (pathlen > sizeof(un.sun_path) || |
| 884 | (saddr->abstract && pathlen > (sizeof(un.sun_path) - 1))) { |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 885 | error_setg(errp, "UNIX socket path '%s' is too long", path); |
| 886 | error_append_hint(errp, "Path must be less than %zu bytes\n", |
xiaoqiang zhao | 776b97d | 2020-05-16 11:13:25 +0800 | [diff] [blame] | 887 | saddr->abstract ? sizeof(un.sun_path) - 1 : |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 888 | sizeof(un.sun_path)); |
| 889 | goto err; |
| 890 | } |
| 891 | |
| 892 | if (pathbuf != NULL) { |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 893 | /* |
| 894 | * This dummy fd usage silences the mktemp() unsecure warning. |
| 895 | * Using mkstemp() doesn't make things more secure here |
| 896 | * though. bind() complains about existing files, so we have |
| 897 | * to unlink first and thus re-open the race window. The |
| 898 | * worst case possible is bind() failing, i.e. a DoS attack. |
| 899 | */ |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 900 | fd = mkstemp(pathbuf); |
Paolo Bonzini | b658c53 | 2015-01-26 12:12:24 +0100 | [diff] [blame] | 901 | if (fd < 0) { |
| 902 | error_setg_errno(errp, errno, |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 903 | "Failed to make a temporary socket %s", pathbuf); |
Paolo Bonzini | b658c53 | 2015-01-26 12:12:24 +0100 | [diff] [blame] | 904 | goto err; |
| 905 | } |
| 906 | close(fd); |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 907 | } |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 908 | |
xiaoqiang zhao | 776b97d | 2020-05-16 11:13:25 +0800 | [diff] [blame] | 909 | if (!saddr->abstract && unlink(path) < 0 && errno != ENOENT) { |
Cole Robinson | 0ef705a | 2015-05-05 11:07:19 -0400 | [diff] [blame] | 910 | error_setg_errno(errp, errno, |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 911 | "Failed to unlink socket %s", path); |
Cole Robinson | 0ef705a | 2015-05-05 11:07:19 -0400 | [diff] [blame] | 912 | goto err; |
| 913 | } |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 914 | |
| 915 | memset(&un, 0, sizeof(un)); |
| 916 | un.sun_family = AF_UNIX; |
xiaoqiang zhao | 776b97d | 2020-05-16 11:13:25 +0800 | [diff] [blame] | 917 | addrlen = sizeof(un); |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 918 | |
xiaoqiang zhao | 776b97d | 2020-05-16 11:13:25 +0800 | [diff] [blame] | 919 | if (saddr->abstract) { |
| 920 | un.sun_path[0] = '\0'; |
| 921 | memcpy(&un.sun_path[1], path, pathlen); |
| 922 | if (saddr->tight) { |
| 923 | addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + pathlen; |
| 924 | } |
| 925 | } else { |
| 926 | memcpy(un.sun_path, path, pathlen); |
| 927 | } |
| 928 | |
| 929 | if (bind(sock, (struct sockaddr *) &un, addrlen) < 0) { |
Daniel P. Berrange | 56382bd | 2017-06-26 11:37:56 +0100 | [diff] [blame] | 930 | error_setg_errno(errp, errno, "Failed to bind socket to %s", path); |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 931 | goto err; |
| 932 | } |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 933 | if (listen(sock, num) < 0) { |
Markus Armbruster | 235256a | 2014-09-25 08:49:31 +0200 | [diff] [blame] | 934 | error_setg_errno(errp, errno, "Failed to listen on socket"); |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 935 | goto err; |
| 936 | } |
| 937 | |
Daniel P. Berrange | 6247351 | 2017-12-12 11:12:19 +0000 | [diff] [blame] | 938 | g_free(pathbuf); |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 939 | return sock; |
| 940 | |
| 941 | err: |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 942 | g_free(pathbuf); |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 943 | closesocket(sock); |
| 944 | return -1; |
| 945 | } |
| 946 | |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 947 | static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 948 | { |
| 949 | struct sockaddr_un un; |
Paolo Bonzini | 1fc05ad | 2012-10-03 13:37:46 +0200 | [diff] [blame] | 950 | int sock, rc; |
Daniel P. Berrangé | 2d2023c | 2019-05-01 15:50:52 +0100 | [diff] [blame] | 951 | size_t pathlen; |
xiaoqiang zhao | 776b97d | 2020-05-16 11:13:25 +0800 | [diff] [blame] | 952 | size_t addrlen; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 953 | |
Daniel P. Berrange | 2942e42 | 2016-01-11 13:17:03 +0000 | [diff] [blame] | 954 | if (saddr->path == NULL) { |
Markus Armbruster | 312fd5f | 2013-02-08 21:22:16 +0100 | [diff] [blame] | 955 | error_setg(errp, "unix connect: no path specified"); |
Gerd Hoffmann | 2af2bf6 | 2009-09-10 10:58:37 +0200 | [diff] [blame] | 956 | return -1; |
| 957 | } |
| 958 | |
Kevin Wolf | 40ff6d7 | 2009-12-02 12:24:42 +0100 | [diff] [blame] | 959 | sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0); |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 960 | if (sock < 0) { |
Markus Armbruster | 235256a | 2014-09-25 08:49:31 +0200 | [diff] [blame] | 961 | error_setg_errno(errp, errno, "Failed to create socket"); |
vibi | 39b6efc | 2009-05-06 15:27:03 +0530 | [diff] [blame] | 962 | return -1; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 963 | } |
| 964 | |
Daniel P. Berrangé | 2d2023c | 2019-05-01 15:50:52 +0100 | [diff] [blame] | 965 | pathlen = strlen(saddr->path); |
xiaoqiang zhao | 776b97d | 2020-05-16 11:13:25 +0800 | [diff] [blame] | 966 | if (pathlen > sizeof(un.sun_path) || |
| 967 | (saddr->abstract && pathlen > (sizeof(un.sun_path) - 1))) { |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 968 | error_setg(errp, "UNIX socket path '%s' is too long", saddr->path); |
| 969 | error_append_hint(errp, "Path must be less than %zu bytes\n", |
xiaoqiang zhao | 776b97d | 2020-05-16 11:13:25 +0800 | [diff] [blame] | 970 | saddr->abstract ? sizeof(un.sun_path) - 1 : |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 971 | sizeof(un.sun_path)); |
| 972 | goto err; |
| 973 | } |
| 974 | |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 975 | memset(&un, 0, sizeof(un)); |
| 976 | un.sun_family = AF_UNIX; |
xiaoqiang zhao | 776b97d | 2020-05-16 11:13:25 +0800 | [diff] [blame] | 977 | addrlen = sizeof(un); |
Paolo Bonzini | 1fc05ad | 2012-10-03 13:37:46 +0200 | [diff] [blame] | 978 | |
xiaoqiang zhao | 776b97d | 2020-05-16 11:13:25 +0800 | [diff] [blame] | 979 | if (saddr->abstract) { |
| 980 | un.sun_path[0] = '\0'; |
| 981 | memcpy(&un.sun_path[1], saddr->path, pathlen); |
| 982 | if (saddr->tight) { |
| 983 | addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + pathlen; |
| 984 | } |
| 985 | } else { |
| 986 | memcpy(un.sun_path, saddr->path, pathlen); |
| 987 | } |
Paolo Bonzini | 1fc05ad | 2012-10-03 13:37:46 +0200 | [diff] [blame] | 988 | /* connect to peer */ |
| 989 | do { |
| 990 | rc = 0; |
xiaoqiang zhao | 776b97d | 2020-05-16 11:13:25 +0800 | [diff] [blame] | 991 | if (connect(sock, (struct sockaddr *) &un, addrlen) < 0) { |
Daniel P. Berrange | b16a44e | 2016-03-07 20:36:03 +0000 | [diff] [blame] | 992 | rc = -errno; |
Paolo Bonzini | 1fc05ad | 2012-10-03 13:37:46 +0200 | [diff] [blame] | 993 | } |
| 994 | } while (rc == -EINTR); |
| 995 | |
Paolo Bonzini | 1fc05ad | 2012-10-03 13:37:46 +0200 | [diff] [blame] | 996 | if (rc < 0) { |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 997 | error_setg_errno(errp, -rc, "Failed to connect socket %s", |
| 998 | saddr->path); |
| 999 | goto err; |
Paolo Bonzini | 1fc05ad | 2012-10-03 13:37:46 +0200 | [diff] [blame] | 1000 | } |
| 1001 | |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 1002 | return sock; |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 1003 | |
| 1004 | err: |
| 1005 | close(sock); |
Daniel P. Berrange | ad9579a | 2017-05-25 16:53:00 +0100 | [diff] [blame] | 1006 | return -1; |
aliguori | d247d25 | 2008-11-11 20:46:40 +0000 | [diff] [blame] | 1007 | } |
| 1008 | |
Paolo Bonzini | 0c81470 | 2012-10-18 08:44:00 +0200 | [diff] [blame] | 1009 | #else |
| 1010 | |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 1011 | static int unix_listen_saddr(UnixSocketAddress *saddr, |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 1012 | int num, |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 1013 | Error **errp) |
Paolo Bonzini | 0c81470 | 2012-10-18 08:44:00 +0200 | [diff] [blame] | 1014 | { |
Paolo Bonzini | 5889966 | 2012-09-19 13:54:39 +0200 | [diff] [blame] | 1015 | error_setg(errp, "unix sockets are not available on windows"); |
Paolo Bonzini | 0c81470 | 2012-10-18 08:44:00 +0200 | [diff] [blame] | 1016 | errno = ENOTSUP; |
| 1017 | return -1; |
| 1018 | } |
| 1019 | |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 1020 | static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp) |
Paolo Bonzini | 0c81470 | 2012-10-18 08:44:00 +0200 | [diff] [blame] | 1021 | { |
Paolo Bonzini | 5889966 | 2012-09-19 13:54:39 +0200 | [diff] [blame] | 1022 | error_setg(errp, "unix sockets are not available on windows"); |
Paolo Bonzini | 0c81470 | 2012-10-18 08:44:00 +0200 | [diff] [blame] | 1023 | errno = ENOTSUP; |
| 1024 | return -1; |
| 1025 | } |
| 1026 | #endif |
| 1027 | |
Gerd Hoffmann | 2af2bf6 | 2009-09-10 10:58:37 +0200 | [diff] [blame] | 1028 | /* compatibility wrapper */ |
Daniel P. Berrange | 6247351 | 2017-12-12 11:12:19 +0000 | [diff] [blame] | 1029 | int unix_listen(const char *str, Error **errp) |
Gerd Hoffmann | 62b6adf | 2009-09-10 10:58:38 +0200 | [diff] [blame] | 1030 | { |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 1031 | UnixSocketAddress *saddr; |
Marc-André Lureau | caf88d7 | 2019-05-03 15:00:33 +0200 | [diff] [blame] | 1032 | int sock; |
Gerd Hoffmann | 62b6adf | 2009-09-10 10:58:38 +0200 | [diff] [blame] | 1033 | |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 1034 | saddr = g_new0(UnixSocketAddress, 1); |
Marc-André Lureau | caf88d7 | 2019-05-03 15:00:33 +0200 | [diff] [blame] | 1035 | saddr->path = g_strdup(str); |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 1036 | sock = unix_listen_saddr(saddr, 1, errp); |
Daniel P. Berrange | 1856835 | 2016-01-11 13:17:02 +0000 | [diff] [blame] | 1037 | qapi_free_UnixSocketAddress(saddr); |
Gerd Hoffmann | 62b6adf | 2009-09-10 10:58:38 +0200 | [diff] [blame] | 1038 | return sock; |
| 1039 | } |
| 1040 | |
Paolo Bonzini | 7fc4e63 | 2012-10-02 09:35:32 +0200 | [diff] [blame] | 1041 | int unix_connect(const char *path, Error **errp) |
Gerd Hoffmann | 2af2bf6 | 2009-09-10 10:58:37 +0200 | [diff] [blame] | 1042 | { |
Daniel P. Berrange | 2942e42 | 2016-01-11 13:17:03 +0000 | [diff] [blame] | 1043 | UnixSocketAddress *saddr; |
Gerd Hoffmann | 2af2bf6 | 2009-09-10 10:58:37 +0200 | [diff] [blame] | 1044 | int sock; |
| 1045 | |
Daniel P. Berrange | 2942e42 | 2016-01-11 13:17:03 +0000 | [diff] [blame] | 1046 | saddr = g_new0(UnixSocketAddress, 1); |
| 1047 | saddr->path = g_strdup(path); |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 1048 | sock = unix_connect_saddr(saddr, errp); |
Daniel P. Berrange | 2942e42 | 2016-01-11 13:17:03 +0000 | [diff] [blame] | 1049 | qapi_free_UnixSocketAddress(saddr); |
Paolo Bonzini | 1fc05ad | 2012-10-03 13:37:46 +0200 | [diff] [blame] | 1050 | return sock; |
| 1051 | } |
| 1052 | |
| 1053 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1054 | SocketAddress *socket_parse(const char *str, Error **errp) |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1055 | { |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1056 | SocketAddress *addr; |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1057 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1058 | addr = g_new0(SocketAddress, 1); |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1059 | if (strstart(str, "unix:", NULL)) { |
| 1060 | if (str[5] == '\0') { |
Markus Armbruster | 312fd5f | 2013-02-08 21:22:16 +0100 | [diff] [blame] | 1061 | error_setg(errp, "invalid Unix socket address"); |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1062 | goto fail; |
| 1063 | } else { |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1064 | addr->type = SOCKET_ADDRESS_TYPE_UNIX; |
| 1065 | addr->u.q_unix.path = g_strdup(str + 5); |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1066 | } |
| 1067 | } else if (strstart(str, "fd:", NULL)) { |
| 1068 | if (str[3] == '\0') { |
Markus Armbruster | 312fd5f | 2013-02-08 21:22:16 +0100 | [diff] [blame] | 1069 | error_setg(errp, "invalid file descriptor address"); |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1070 | goto fail; |
| 1071 | } else { |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1072 | addr->type = SOCKET_ADDRESS_TYPE_FD; |
| 1073 | addr->u.fd.str = g_strdup(str + 3); |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1074 | } |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 1075 | } else if (strstart(str, "vsock:", NULL)) { |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1076 | addr->type = SOCKET_ADDRESS_TYPE_VSOCK; |
| 1077 | if (vsock_parse(&addr->u.vsock, str + strlen("vsock:"), errp)) { |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 1078 | goto fail; |
| 1079 | } |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1080 | } else { |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1081 | addr->type = SOCKET_ADDRESS_TYPE_INET; |
| 1082 | if (inet_parse(&addr->u.inet, str, errp)) { |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1083 | goto fail; |
| 1084 | } |
| 1085 | } |
| 1086 | return addr; |
| 1087 | |
| 1088 | fail: |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1089 | qapi_free_SocketAddress(addr); |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1090 | return NULL; |
| 1091 | } |
| 1092 | |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 1093 | static int socket_get_fd(const char *fdstr, int num, Error **errp) |
Daniel P. Berrange | 30bdb3c | 2017-12-22 11:08:49 +0000 | [diff] [blame] | 1094 | { |
Daniel P. Berrange | 1723d6b | 2017-12-22 11:04:30 +0000 | [diff] [blame] | 1095 | int fd; |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 1096 | if (num != 1) { |
| 1097 | error_setg_errno(errp, EINVAL, "socket_get_fd: too many connections"); |
| 1098 | return -1; |
| 1099 | } |
Daniel P. Berrange | 1723d6b | 2017-12-22 11:04:30 +0000 | [diff] [blame] | 1100 | if (cur_mon) { |
| 1101 | fd = monitor_get_fd(cur_mon, fdstr, errp); |
| 1102 | if (fd < 0) { |
| 1103 | return -1; |
| 1104 | } |
| 1105 | } else { |
| 1106 | if (qemu_strtoi(fdstr, NULL, 10, &fd) < 0) { |
| 1107 | error_setg_errno(errp, errno, |
| 1108 | "Unable to parse FD number %s", |
| 1109 | fdstr); |
| 1110 | return -1; |
| 1111 | } |
Daniel P. Berrange | 30bdb3c | 2017-12-22 11:08:49 +0000 | [diff] [blame] | 1112 | } |
| 1113 | if (!fd_is_socket(fd)) { |
| 1114 | error_setg(errp, "File descriptor '%s' is not a socket", fdstr); |
| 1115 | close(fd); |
| 1116 | return -1; |
| 1117 | } |
| 1118 | return fd; |
| 1119 | } |
| 1120 | |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 1121 | int socket_connect(SocketAddress *addr, Error **errp) |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1122 | { |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1123 | int fd; |
| 1124 | |
Eric Blake | 2d32add | 2015-10-26 16:34:55 -0600 | [diff] [blame] | 1125 | switch (addr->type) { |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1126 | case SOCKET_ADDRESS_TYPE_INET: |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 1127 | fd = inet_connect_saddr(&addr->u.inet, errp); |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1128 | break; |
| 1129 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1130 | case SOCKET_ADDRESS_TYPE_UNIX: |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 1131 | fd = unix_connect_saddr(&addr->u.q_unix, errp); |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1132 | break; |
| 1133 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1134 | case SOCKET_ADDRESS_TYPE_FD: |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 1135 | fd = socket_get_fd(addr->u.fd.str, 1, errp); |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1136 | break; |
| 1137 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1138 | case SOCKET_ADDRESS_TYPE_VSOCK: |
Cao jin | b258793 | 2017-06-16 16:54:45 +0800 | [diff] [blame] | 1139 | fd = vsock_connect_saddr(&addr->u.vsock, errp); |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 1140 | break; |
| 1141 | |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1142 | default: |
| 1143 | abort(); |
| 1144 | } |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1145 | return fd; |
| 1146 | } |
| 1147 | |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 1148 | int socket_listen(SocketAddress *addr, int num, Error **errp) |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1149 | { |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1150 | int fd; |
| 1151 | |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 1152 | trace_socket_listen(num); |
Eric Blake | 2d32add | 2015-10-26 16:34:55 -0600 | [diff] [blame] | 1153 | switch (addr->type) { |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1154 | case SOCKET_ADDRESS_TYPE_INET: |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 1155 | fd = inet_listen_saddr(&addr->u.inet, 0, num, errp); |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1156 | break; |
| 1157 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1158 | case SOCKET_ADDRESS_TYPE_UNIX: |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 1159 | fd = unix_listen_saddr(&addr->u.q_unix, num, errp); |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1160 | break; |
| 1161 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1162 | case SOCKET_ADDRESS_TYPE_FD: |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 1163 | fd = socket_get_fd(addr->u.fd.str, num, errp); |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1164 | break; |
| 1165 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1166 | case SOCKET_ADDRESS_TYPE_VSOCK: |
Juan Quintela | e5b6353 | 2019-08-19 14:48:21 +0200 | [diff] [blame] | 1167 | fd = vsock_listen_saddr(&addr->u.vsock, num, errp); |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 1168 | break; |
| 1169 | |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1170 | default: |
| 1171 | abort(); |
| 1172 | } |
Paolo Bonzini | 101f9cb | 2012-10-23 21:31:53 +0200 | [diff] [blame] | 1173 | return fd; |
| 1174 | } |
| 1175 | |
Marc-André Lureau | 74b6ce4 | 2016-06-16 21:28:52 +0200 | [diff] [blame] | 1176 | void socket_listen_cleanup(int fd, Error **errp) |
| 1177 | { |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1178 | SocketAddress *addr; |
Marc-André Lureau | 74b6ce4 | 2016-06-16 21:28:52 +0200 | [diff] [blame] | 1179 | |
| 1180 | addr = socket_local_address(fd, errp); |
Daniel P. Berrange | 2d7ad7c | 2017-10-27 08:51:59 +0100 | [diff] [blame] | 1181 | if (!addr) { |
| 1182 | return; |
| 1183 | } |
Marc-André Lureau | 74b6ce4 | 2016-06-16 21:28:52 +0200 | [diff] [blame] | 1184 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1185 | if (addr->type == SOCKET_ADDRESS_TYPE_UNIX |
| 1186 | && addr->u.q_unix.path) { |
| 1187 | if (unlink(addr->u.q_unix.path) < 0 && errno != ENOENT) { |
Marc-André Lureau | 74b6ce4 | 2016-06-16 21:28:52 +0200 | [diff] [blame] | 1188 | error_setg_errno(errp, errno, |
| 1189 | "Failed to unlink socket %s", |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1190 | addr->u.q_unix.path); |
Marc-André Lureau | 74b6ce4 | 2016-06-16 21:28:52 +0200 | [diff] [blame] | 1191 | } |
| 1192 | } |
| 1193 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1194 | qapi_free_SocketAddress(addr); |
Marc-André Lureau | 74b6ce4 | 2016-06-16 21:28:52 +0200 | [diff] [blame] | 1195 | } |
| 1196 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1197 | int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp) |
Gerd Hoffmann | 3ecc059 | 2013-02-27 14:10:47 +0100 | [diff] [blame] | 1198 | { |
Gerd Hoffmann | 3ecc059 | 2013-02-27 14:10:47 +0100 | [diff] [blame] | 1199 | int fd; |
| 1200 | |
Markus Armbruster | ca0b64e | 2017-03-30 19:43:09 +0200 | [diff] [blame] | 1201 | /* |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1202 | * TODO SOCKET_ADDRESS_TYPE_FD when fd is AF_INET or AF_INET6 |
Markus Armbruster | ca0b64e | 2017-03-30 19:43:09 +0200 | [diff] [blame] | 1203 | * (although other address families can do SOCK_DGRAM, too) |
| 1204 | */ |
Eric Blake | 2d32add | 2015-10-26 16:34:55 -0600 | [diff] [blame] | 1205 | switch (remote->type) { |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1206 | case SOCKET_ADDRESS_TYPE_INET: |
| 1207 | fd = inet_dgram_saddr(&remote->u.inet, |
| 1208 | local ? &local->u.inet : NULL, errp); |
Gerd Hoffmann | 3ecc059 | 2013-02-27 14:10:47 +0100 | [diff] [blame] | 1209 | break; |
| 1210 | |
| 1211 | default: |
| 1212 | error_setg(errp, "socket type unsupported for datagram"); |
Gerd Hoffmann | 7a5b6af | 2013-06-24 08:39:56 +0200 | [diff] [blame] | 1213 | fd = -1; |
Gerd Hoffmann | 3ecc059 | 2013-02-27 14:10:47 +0100 | [diff] [blame] | 1214 | } |
Gerd Hoffmann | 3ecc059 | 2013-02-27 14:10:47 +0100 | [diff] [blame] | 1215 | return fd; |
| 1216 | } |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1217 | |
| 1218 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1219 | static SocketAddress * |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1220 | socket_sockaddr_to_address_inet(struct sockaddr_storage *sa, |
| 1221 | socklen_t salen, |
| 1222 | Error **errp) |
| 1223 | { |
| 1224 | char host[NI_MAXHOST]; |
| 1225 | char serv[NI_MAXSERV]; |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1226 | SocketAddress *addr; |
Eric Blake | 0399293 | 2016-03-03 09:16:48 -0700 | [diff] [blame] | 1227 | InetSocketAddress *inet; |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1228 | int ret; |
| 1229 | |
| 1230 | ret = getnameinfo((struct sockaddr *)sa, salen, |
| 1231 | host, sizeof(host), |
| 1232 | serv, sizeof(serv), |
| 1233 | NI_NUMERICHOST | NI_NUMERICSERV); |
| 1234 | if (ret != 0) { |
| 1235 | error_setg(errp, "Cannot format numeric socket address: %s", |
| 1236 | gai_strerror(ret)); |
| 1237 | return NULL; |
| 1238 | } |
| 1239 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1240 | addr = g_new0(SocketAddress, 1); |
| 1241 | addr->type = SOCKET_ADDRESS_TYPE_INET; |
| 1242 | inet = &addr->u.inet; |
Eric Blake | 0399293 | 2016-03-03 09:16:48 -0700 | [diff] [blame] | 1243 | inet->host = g_strdup(host); |
| 1244 | inet->port = g_strdup(serv); |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1245 | if (sa->ss_family == AF_INET) { |
Eric Blake | 0399293 | 2016-03-03 09:16:48 -0700 | [diff] [blame] | 1246 | inet->has_ipv4 = inet->ipv4 = true; |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1247 | } else { |
Eric Blake | 0399293 | 2016-03-03 09:16:48 -0700 | [diff] [blame] | 1248 | inet->has_ipv6 = inet->ipv6 = true; |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1249 | } |
| 1250 | |
| 1251 | return addr; |
| 1252 | } |
| 1253 | |
| 1254 | |
| 1255 | #ifndef WIN32 |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1256 | static SocketAddress * |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1257 | socket_sockaddr_to_address_unix(struct sockaddr_storage *sa, |
| 1258 | socklen_t salen, |
| 1259 | Error **errp) |
| 1260 | { |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1261 | SocketAddress *addr; |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1262 | struct sockaddr_un *su = (struct sockaddr_un *)sa; |
| 1263 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1264 | addr = g_new0(SocketAddress, 1); |
| 1265 | addr->type = SOCKET_ADDRESS_TYPE_UNIX; |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1266 | if (su->sun_path[0]) { |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1267 | addr->u.q_unix.path = g_strndup(su->sun_path, sizeof(su->sun_path)); |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1268 | } |
| 1269 | |
| 1270 | return addr; |
| 1271 | } |
| 1272 | #endif /* WIN32 */ |
| 1273 | |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 1274 | #ifdef CONFIG_AF_VSOCK |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1275 | static SocketAddress * |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 1276 | socket_sockaddr_to_address_vsock(struct sockaddr_storage *sa, |
| 1277 | socklen_t salen, |
| 1278 | Error **errp) |
| 1279 | { |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1280 | SocketAddress *addr; |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 1281 | VsockSocketAddress *vaddr; |
| 1282 | struct sockaddr_vm *svm = (struct sockaddr_vm *)sa; |
| 1283 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1284 | addr = g_new0(SocketAddress, 1); |
| 1285 | addr->type = SOCKET_ADDRESS_TYPE_VSOCK; |
| 1286 | vaddr = &addr->u.vsock; |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 1287 | vaddr->cid = g_strdup_printf("%u", svm->svm_cid); |
| 1288 | vaddr->port = g_strdup_printf("%u", svm->svm_port); |
| 1289 | |
| 1290 | return addr; |
| 1291 | } |
| 1292 | #endif /* CONFIG_AF_VSOCK */ |
| 1293 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1294 | SocketAddress * |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1295 | socket_sockaddr_to_address(struct sockaddr_storage *sa, |
| 1296 | socklen_t salen, |
| 1297 | Error **errp) |
| 1298 | { |
| 1299 | switch (sa->ss_family) { |
| 1300 | case AF_INET: |
| 1301 | case AF_INET6: |
| 1302 | return socket_sockaddr_to_address_inet(sa, salen, errp); |
| 1303 | |
| 1304 | #ifndef WIN32 |
| 1305 | case AF_UNIX: |
| 1306 | return socket_sockaddr_to_address_unix(sa, salen, errp); |
| 1307 | #endif /* WIN32 */ |
| 1308 | |
Stefan Hajnoczi | 6a02c80 | 2016-10-14 10:00:55 +0100 | [diff] [blame] | 1309 | #ifdef CONFIG_AF_VSOCK |
| 1310 | case AF_VSOCK: |
| 1311 | return socket_sockaddr_to_address_vsock(sa, salen, errp); |
| 1312 | #endif |
| 1313 | |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1314 | default: |
| 1315 | error_setg(errp, "socket family %d unsupported", |
| 1316 | sa->ss_family); |
| 1317 | return NULL; |
| 1318 | } |
| 1319 | return 0; |
| 1320 | } |
| 1321 | |
| 1322 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1323 | SocketAddress *socket_local_address(int fd, Error **errp) |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1324 | { |
| 1325 | struct sockaddr_storage ss; |
| 1326 | socklen_t sslen = sizeof(ss); |
| 1327 | |
| 1328 | if (getsockname(fd, (struct sockaddr *)&ss, &sslen) < 0) { |
Daniel P. Berrange | b16a44e | 2016-03-07 20:36:03 +0000 | [diff] [blame] | 1329 | error_setg_errno(errp, errno, "%s", |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1330 | "Unable to query local socket address"); |
| 1331 | return NULL; |
| 1332 | } |
| 1333 | |
| 1334 | return socket_sockaddr_to_address(&ss, sslen, errp); |
| 1335 | } |
| 1336 | |
| 1337 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1338 | SocketAddress *socket_remote_address(int fd, Error **errp) |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1339 | { |
| 1340 | struct sockaddr_storage ss; |
| 1341 | socklen_t sslen = sizeof(ss); |
| 1342 | |
| 1343 | if (getpeername(fd, (struct sockaddr *)&ss, &sslen) < 0) { |
Daniel P. Berrange | b16a44e | 2016-03-07 20:36:03 +0000 | [diff] [blame] | 1344 | error_setg_errno(errp, errno, "%s", |
Daniel P. Berrange | 17c55de | 2015-05-01 17:36:20 +0100 | [diff] [blame] | 1345 | "Unable to query remote socket address"); |
| 1346 | return NULL; |
| 1347 | } |
| 1348 | |
| 1349 | return socket_sockaddr_to_address(&ss, sslen, errp); |
| 1350 | } |
Daniel P. Berrange | 2a8e21c | 2015-08-14 18:18:41 +0100 | [diff] [blame] | 1351 | |
Markus Armbruster | 216411b | 2017-03-30 19:43:15 +0200 | [diff] [blame] | 1352 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1353 | SocketAddress *socket_address_flatten(SocketAddressLegacy *addr_legacy) |
| 1354 | { |
Markus Armbruster | fc0f005 | 2017-05-15 18:39:04 +0200 | [diff] [blame] | 1355 | SocketAddress *addr; |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1356 | |
| 1357 | if (!addr_legacy) { |
| 1358 | return NULL; |
| 1359 | } |
| 1360 | |
Markus Armbruster | fc0f005 | 2017-05-15 18:39:04 +0200 | [diff] [blame] | 1361 | addr = g_new(SocketAddress, 1); |
| 1362 | |
Markus Armbruster | bd269eb | 2017-04-26 09:36:41 +0200 | [diff] [blame] | 1363 | switch (addr_legacy->type) { |
| 1364 | case SOCKET_ADDRESS_LEGACY_KIND_INET: |
| 1365 | addr->type = SOCKET_ADDRESS_TYPE_INET; |
| 1366 | QAPI_CLONE_MEMBERS(InetSocketAddress, &addr->u.inet, |
| 1367 | addr_legacy->u.inet.data); |
| 1368 | break; |
| 1369 | case SOCKET_ADDRESS_LEGACY_KIND_UNIX: |
| 1370 | addr->type = SOCKET_ADDRESS_TYPE_UNIX; |
| 1371 | QAPI_CLONE_MEMBERS(UnixSocketAddress, &addr->u.q_unix, |
| 1372 | addr_legacy->u.q_unix.data); |
| 1373 | break; |
| 1374 | case SOCKET_ADDRESS_LEGACY_KIND_VSOCK: |
| 1375 | addr->type = SOCKET_ADDRESS_TYPE_VSOCK; |
| 1376 | QAPI_CLONE_MEMBERS(VsockSocketAddress, &addr->u.vsock, |
| 1377 | addr_legacy->u.vsock.data); |
| 1378 | break; |
| 1379 | case SOCKET_ADDRESS_LEGACY_KIND_FD: |
| 1380 | addr->type = SOCKET_ADDRESS_TYPE_FD; |
| 1381 | QAPI_CLONE_MEMBERS(String, &addr->u.fd, addr_legacy->u.fd.data); |
| 1382 | break; |
| 1383 | default: |
| 1384 | abort(); |
| 1385 | } |
| 1386 | |
| 1387 | return addr; |
| 1388 | } |