17d62b00eSchristos /* Operations on network stuff. 2*6881a400Schristos Copyright (C) 2018-2023 Free Software Foundation, Inc. 37d62b00eSchristos 47d62b00eSchristos This file is part of GDB. 57d62b00eSchristos 67d62b00eSchristos This program is free software; you can redistribute it and/or modify 77d62b00eSchristos it under the terms of the GNU General Public License as published by 87d62b00eSchristos the Free Software Foundation; either version 3 of the License, or 97d62b00eSchristos (at your option) any later version. 107d62b00eSchristos 117d62b00eSchristos This program is distributed in the hope that it will be useful, 127d62b00eSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 137d62b00eSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 147d62b00eSchristos GNU General Public License for more details. 157d62b00eSchristos 167d62b00eSchristos You should have received a copy of the GNU General Public License 177d62b00eSchristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 187d62b00eSchristos 197d62b00eSchristos #include "common-defs.h" 207d62b00eSchristos #include "netstuff.h" 217d62b00eSchristos #include <algorithm> 227d62b00eSchristos 237d62b00eSchristos #ifdef USE_WIN32API 247d62b00eSchristos #include <ws2tcpip.h> 257d62b00eSchristos #else 267d62b00eSchristos #include <netinet/in.h> 277d62b00eSchristos #include <arpa/inet.h> 287d62b00eSchristos #include <netdb.h> 297d62b00eSchristos #include <sys/socket.h> 307d62b00eSchristos #include <netinet/tcp.h> 317d62b00eSchristos #endif 327d62b00eSchristos 337d62b00eSchristos /* See gdbsupport/netstuff.h. */ 347d62b00eSchristos 357d62b00eSchristos scoped_free_addrinfo::~scoped_free_addrinfo () 367d62b00eSchristos { 377d62b00eSchristos freeaddrinfo (m_res); 387d62b00eSchristos } 397d62b00eSchristos 407d62b00eSchristos /* See gdbsupport/netstuff.h. */ 417d62b00eSchristos 427d62b00eSchristos parsed_connection_spec 437d62b00eSchristos parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint) 447d62b00eSchristos { 457d62b00eSchristos parsed_connection_spec ret; 467d62b00eSchristos size_t last_colon_pos = 0; 477d62b00eSchristos /* We're dealing with IPv6 if: 487d62b00eSchristos 497d62b00eSchristos - ai_family is AF_INET6, or 507d62b00eSchristos - ai_family is not AF_INET, and 517d62b00eSchristos - spec[0] is '[', or 527d62b00eSchristos - the number of ':' on spec is greater than 1. */ 537d62b00eSchristos bool is_ipv6 = (hint->ai_family == AF_INET6 547d62b00eSchristos || (hint->ai_family != AF_INET 557d62b00eSchristos && (spec[0] == '[' 567d62b00eSchristos || std::count (spec.begin (), 577d62b00eSchristos spec.end (), ':') > 1))); 587d62b00eSchristos 597d62b00eSchristos if (is_ipv6) 607d62b00eSchristos { 617d62b00eSchristos if (spec[0] == '[') 627d62b00eSchristos { 637d62b00eSchristos /* IPv6 addresses can be written as '[ADDR]:PORT', and we 647d62b00eSchristos support this notation. */ 657d62b00eSchristos size_t close_bracket_pos = spec.find_first_of (']'); 667d62b00eSchristos 677d62b00eSchristos if (close_bracket_pos == std::string::npos) 687d62b00eSchristos error (_("Missing close bracket in hostname '%s'"), 697d62b00eSchristos spec.c_str ()); 707d62b00eSchristos 717d62b00eSchristos hint->ai_family = AF_INET6; 727d62b00eSchristos 737d62b00eSchristos const char c = spec[close_bracket_pos + 1]; 747d62b00eSchristos 757d62b00eSchristos if (c == '\0') 767d62b00eSchristos last_colon_pos = std::string::npos; 777d62b00eSchristos else if (c != ':') 787d62b00eSchristos error (_("Invalid cruft after close bracket in '%s'"), 797d62b00eSchristos spec.c_str ()); 807d62b00eSchristos 817d62b00eSchristos /* Erase both '[' and ']'. */ 827d62b00eSchristos spec.erase (0, 1); 837d62b00eSchristos spec.erase (close_bracket_pos - 1, 1); 847d62b00eSchristos } 857d62b00eSchristos else if (spec.find_first_of (']') != std::string::npos) 867d62b00eSchristos error (_("Missing open bracket in hostname '%s'"), 877d62b00eSchristos spec.c_str ()); 887d62b00eSchristos } 897d62b00eSchristos 907d62b00eSchristos if (last_colon_pos == 0) 917d62b00eSchristos last_colon_pos = spec.find_last_of (':'); 927d62b00eSchristos 937d62b00eSchristos /* The length of the hostname part. */ 947d62b00eSchristos size_t host_len; 957d62b00eSchristos 967d62b00eSchristos if (last_colon_pos != std::string::npos) 977d62b00eSchristos { 987d62b00eSchristos /* The user has provided a port. */ 997d62b00eSchristos host_len = last_colon_pos; 1007d62b00eSchristos ret.port_str = spec.substr (last_colon_pos + 1); 1017d62b00eSchristos } 1027d62b00eSchristos else 1037d62b00eSchristos host_len = spec.size (); 1047d62b00eSchristos 1057d62b00eSchristos ret.host_str = spec.substr (0, host_len); 1067d62b00eSchristos 1077d62b00eSchristos /* Default hostname is localhost. */ 1087d62b00eSchristos if (ret.host_str.empty ()) 1097d62b00eSchristos ret.host_str = "localhost"; 1107d62b00eSchristos 1117d62b00eSchristos return ret; 1127d62b00eSchristos } 1137d62b00eSchristos 1147d62b00eSchristos /* See gdbsupport/netstuff.h. */ 1157d62b00eSchristos 1167d62b00eSchristos parsed_connection_spec 1177d62b00eSchristos parse_connection_spec (const char *spec, struct addrinfo *hint) 1187d62b00eSchristos { 1197d62b00eSchristos /* Struct to hold the association between valid prefixes, their 1207d62b00eSchristos family and socktype. */ 1217d62b00eSchristos struct host_prefix 1227d62b00eSchristos { 1237d62b00eSchristos /* The prefix. */ 1247d62b00eSchristos const char *prefix; 1257d62b00eSchristos 1267d62b00eSchristos /* The 'ai_family'. */ 1277d62b00eSchristos int family; 1287d62b00eSchristos 1297d62b00eSchristos /* The 'ai_socktype'. */ 1307d62b00eSchristos int socktype; 1317d62b00eSchristos }; 1327d62b00eSchristos static const struct host_prefix prefixes[] = 1337d62b00eSchristos { 1347d62b00eSchristos { "udp:", AF_UNSPEC, SOCK_DGRAM }, 1357d62b00eSchristos { "tcp:", AF_UNSPEC, SOCK_STREAM }, 1367d62b00eSchristos { "udp4:", AF_INET, SOCK_DGRAM }, 1377d62b00eSchristos { "tcp4:", AF_INET, SOCK_STREAM }, 1387d62b00eSchristos { "udp6:", AF_INET6, SOCK_DGRAM }, 1397d62b00eSchristos { "tcp6:", AF_INET6, SOCK_STREAM }, 1407d62b00eSchristos }; 1417d62b00eSchristos 1427d62b00eSchristos for (const host_prefix prefix : prefixes) 1437d62b00eSchristos if (startswith (spec, prefix.prefix)) 1447d62b00eSchristos { 1457d62b00eSchristos spec += strlen (prefix.prefix); 1467d62b00eSchristos hint->ai_family = prefix.family; 1477d62b00eSchristos hint->ai_socktype = prefix.socktype; 1487d62b00eSchristos hint->ai_protocol 1497d62b00eSchristos = hint->ai_socktype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; 1507d62b00eSchristos break; 1517d62b00eSchristos } 1527d62b00eSchristos 1537d62b00eSchristos return parse_connection_spec_without_prefix (spec, hint); 1547d62b00eSchristos } 155