From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on sa.local.altlinux.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=5.0 tests=ALL_TRUSTED,BAYES_00 autolearn=ham autolearn_force=no version=3.4.1 From: Aleksei Nikiforov To: devel@lists.altlinux.org Date: Tue, 10 Dec 2019 18:23:29 +0300 Message-Id: <20191210152343.33867-25-darktemplar@altlinux.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191210152343.33867-1-darktemplar@altlinux.org> References: <20191210152343.33867-1-darktemplar@altlinux.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Cc: Aleksei Nikiforov Subject: [devel] [PATCH for apt 24/38] Improve ipv6 address handling X-BeenThere: devel@lists.altlinux.org X-Mailman-Version: 2.1.12 Precedence: list Reply-To: ALT Linux Team development discussions List-Id: ALT Linux Team development discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 10 Dec 2019 15:25:22 -0000 Archived-At: List-Archive: List-Post: Introduce new class URIAddress for parsing, storing, and converting back to string various address types, including ipv4-addresses, ipv6-addresses and hostnames. In addition to hostname, address may contain interface name and port number. --- apt/apt-pkg/acquire.cc | 2 +- apt/apt-pkg/contrib/strutl.cc | 282 ++++++++++++++++++++++++-------- apt/apt-pkg/contrib/strutl.h | 35 +++- apt/apt-pkg/rpm/rpmindexfile.cc | 2 +- apt/methods/cdrom.cc | 8 +- apt/methods/connect.cc | 34 ++-- apt/methods/connect.h | 2 +- apt/methods/file.cc | 2 +- apt/methods/ftp.cc | 40 ++--- apt/methods/ftp.h | 2 +- apt/methods/gpg.cc | 2 +- apt/methods/gzip.cc | 2 +- apt/methods/http.cc | 49 ++---- apt/methods/http.h | 2 +- apt/methods/rsh.cc | 4 +- apt/methods/rsh.h | 2 +- apt/methods/rsync.cc | 10 +- apt/test/uri.cc | 14 +- 18 files changed, 319 insertions(+), 175 deletions(-) diff --git a/apt/apt-pkg/acquire.cc b/apt/apt-pkg/acquire.cc index e1e6d7c..79784af 100644 --- a/apt/apt-pkg/acquire.cc +++ b/apt/apt-pkg/acquire.cc @@ -236,7 +236,7 @@ string pkgAcquire::QueueName(const string &Uri,MethodConfig const *&Config) if (Config->SingleInstance == true || QueueMode == QueueAccess) return U.Access; - return U.Access + ':' + U.Host; + return U.Access + ':' + U.Address.to_hostname(); } /*}}}*/ // Acquire::GetConfig - Fetch the configuration information /*{{{*/ diff --git a/apt/apt-pkg/contrib/strutl.cc b/apt/apt-pkg/contrib/strutl.cc index 4d5025a..52d1995 100644 --- a/apt/apt-pkg/contrib/strutl.cc +++ b/apt/apt-pkg/contrib/strutl.cc @@ -35,6 +35,9 @@ #include #include +#include +#include + using namespace std; /*}}}*/ @@ -1058,27 +1061,211 @@ bool CheckDomainList(const string &Host, const string &List) } /*}}}*/ +URIAddress::URIAddress() + : is_ipv6addr(false) +{ +} + +URIAddress::URIAddress(const std::string &host_uri) + : is_ipv6addr(false) +{ + from_string(host_uri); +} + +URIAddress::URIAddress(const URIAddress &other) + : hostname(other.hostname) + , interface(other.interface) + , port(other.port) + , is_ipv6addr(other.is_ipv6addr) +{ +} + +URIAddress::URIAddress(URIAddress &&other) + : hostname(std::move(other.hostname)) + , interface(std::move(other.interface)) + , port(std::move(other.port)) + , is_ipv6addr(std::move(other.is_ipv6addr)) +{ +} + +URIAddress& URIAddress::operator=(const std::string &host_uri) +{ + from_string(host_uri); + + return *this; +} + +URIAddress& URIAddress::operator=(const URIAddress &other) +{ + if (&other != this) + { + this->hostname = other.hostname; + this->interface = other.interface; + this->port = other.port; + this->is_ipv6addr = other.is_ipv6addr; + } + + return *this; +} + +URIAddress& URIAddress::operator=(URIAddress &&other) +{ + if (&other != this) + { + this->hostname = std::move(other.hostname); + this->interface = std::move(other.interface); + this->port = std::move(other.port); + this->is_ipv6addr = std::move(other.is_ipv6addr); + } + + return *this; +} + +bool URIAddress::operator==(const std::string &host_uri) const +{ + URIAddress other(host_uri); + + return (*this == other); +} + +bool URIAddress::operator==(const URIAddress &other) const +{ + return (this->hostname == other.hostname) + && (this->interface == other.interface) + && (this->port == other.port) + && (this->is_ipv6addr == other.is_ipv6addr); +} + +std::string URIAddress::to_string() const +{ + std::string result = to_hostname(); + + if (result.empty()) + { + return result; + } + + if (port) + { + result += ':'; + result += std::to_string(*port); + } + + return result; +} + +std::string URIAddress::to_hostname() const +{ + std::string result = hostname_and_interface(); + + if (result.empty()) + { + return std::string(); + } + + if (!is_ipv6addr) + { + return result; + } + + return std::string("[") + result + std::string("]"); +} + +std::string URIAddress::hostname_and_interface() const +{ + if (hostname.empty()) + { + return std::string(); + } + + if (interface.empty()) + { + return hostname; + } + + return hostname + '%' + interface; +} + +void URIAddress::from_string(const std::string &host_uri) +{ + std::string remainder = host_uri; + + // first look for port delimiter, outside of brackets + size_t index = remainder.size(); + for ( ; (index > 0) && (remainder[index - 1] != ']') && (remainder[index - 1] != ':'); --index) + { + } + + if ((index > 0) && (remainder[index - 1] == ':')) + { + if (index < remainder.size()) + { + port = atoi(remainder.substr(index).c_str()); + } + else + { + port = std::experimental::optional(); + } + + remainder = remainder.substr(0, index > 0 ? index - 1 : 0); + } + else + { + port = std::experimental::optional(); + } + + if ((remainder.front() == '[') && (remainder.back() == ']')) + { + is_ipv6addr = true; + remainder = remainder.substr(1, remainder.size() - 2); + } + else + { + is_ipv6addr = false; + } + + size_t percent_pos = remainder.find_last_of('%'); + if (percent_pos != std::string::npos) + { + hostname = remainder.substr(0, percent_pos); + + if (percent_pos < remainder.size() - 1) + { + interface = remainder.substr(percent_pos + 1); + } + else + { + interface = std::string(); + } + } + else + { + hostname = remainder; + interface = std::string(); + } +} + // URI::CopyFrom - Copy from an object /*{{{*/ // --------------------------------------------------------------------- /* This parses the URI into all of its components */ void URI::CopyFrom(const string &U) { - auto I = U.begin(); + string::const_iterator I = U.begin(); // Locate the first colon, this separates the scheme - for (; I < U.end() && *I != ':' ; I++); - auto FirstColon = I; + for (; I < U.end() && *I != ':' ; ++I); + string::const_iterator FirstColon = I; /* Determine if this is a host type URI with a leading double // and then search for the first single / */ - auto SingleSlash = I; + string::const_iterator SingleSlash = I; if (I + 3 < U.end() && I[1] == '/' && I[2] == '/') SingleSlash += 3; /* Find the / indicating the end of the hostname, ignoring /'s in the square brackets */ bool InBracket = false; - for (; SingleSlash < U.end() && (*SingleSlash != '/' || InBracket == true); SingleSlash++) + for (; SingleSlash < U.end() && (*SingleSlash != '/' || InBracket == true); ++SingleSlash) { if (*SingleSlash == '[') InBracket = true; @@ -1090,9 +1277,9 @@ void URI::CopyFrom(const string &U) SingleSlash = U.end(); // We can now write the access and path specifiers - Access = string(U,0,FirstColon - U.begin()); + Access.assign(U.begin(),FirstColon); if (SingleSlash != U.end()) - Path = string(U,SingleSlash - U.begin()); + Path.assign(SingleSlash,U.end()); if (Path.empty() == true) Path = "/"; @@ -1111,64 +1298,33 @@ void URI::CopyFrom(const string &U) I = FirstColon + 1; if (I > SingleSlash) I = SingleSlash; - for (; I < SingleSlash && *I != ':'; I++); - auto SecondColon = I; - - // Search for the @ after the colon - for (; I < SingleSlash && *I != '@'; I++); - auto At = I; + + // Search for the @ separating user:pass from host + auto const RevAt = std::find( + std::string::const_reverse_iterator(SingleSlash), + std::string::const_reverse_iterator(I), '@'); + string::const_iterator const At = RevAt.base() == I ? SingleSlash : std::prev(RevAt.base()); + // and then look for the colon between user and pass + string::const_iterator const SecondColon = std::find(I, At, ':'); + + std::string Host; // Now write the host and user/pass if (At == SingleSlash) { if (FirstColon < SingleSlash) - Host = string(U,FirstColon - U.begin(),SingleSlash - FirstColon); + Host.assign(FirstColon,SingleSlash); } else { - Host = string(U,At - U.begin() + 1,SingleSlash - At - 1); - User = string(U,FirstColon - U.begin(),SecondColon - FirstColon); + Host.assign(At+1,SingleSlash); + // username and password must be encoded (RFC 3986) + User.assign(DeQuoteString(std::string(FirstColon,SecondColon))); if (SecondColon < At) - Password = string(U,SecondColon - U.begin() + 1,At - SecondColon - 1); + Password.assign(DeQuoteString(std::string(SecondColon+1,At))); } - // Now we parse the RFC 2732 [] hostnames. - unsigned long PortEnd = 0; - InBracket = false; - for (unsigned I = 0; I != Host.length();) - { - if (Host[I] == '[') - { - InBracket = true; - Host.erase(I,1); - continue; - } - - if (InBracket == true && Host[I] == ']') - { - InBracket = false; - Host.erase(I,1); - PortEnd = I; - continue; - } - I++; - } - - // Tsk, weird. - if (InBracket == true) - { - Host = string(); - return; - } - - // Now we parse off a port number from the hostname - Port = 0; - string::size_type Pos = Host.rfind(':'); - if (Pos == string::npos || Pos < PortEnd) - return; - - Port = atoi(string(Host,Pos+1).c_str()); - Host = string(Host,0,Pos); + Address = URIAddress(Host); } /*}}}*/ // URI::operator string - Convert the URI to a string /*{{{*/ @@ -1181,7 +1337,7 @@ URI::operator string() if (Access.empty() == false) Res = Access + ':'; - if (Host.empty() == false) + if (Address.hostname.empty() == false) { if (Access.empty() == false) Res += "//"; @@ -1194,19 +1350,7 @@ URI::operator string() Res += "@"; } - // Add RFC 2732 escaping characters - if (Access.empty() == false && - (Host.find('/') != string::npos || Host.find(':') != string::npos)) - Res += '[' + Host + ']'; - else - Res += Host; - - if (Port != 0) - { - char S[30]; - sprintf(S,":%u",Port); - Res += S; - } + Res += Address.to_string(); } if (Path.empty() == false) @@ -1229,7 +1373,7 @@ string URI::SiteOnly(const string &URI) U.User.clear(); U.Password.clear(); U.Path.clear(); - U.Port = 0; + U.Address.port = std::experimental::optional(); return U; } /*}}}*/ diff --git a/apt/apt-pkg/contrib/strutl.h b/apt/apt-pkg/contrib/strutl.h index 8a063f3..a13b32b 100644 --- a/apt/apt-pkg/contrib/strutl.h +++ b/apt/apt-pkg/contrib/strutl.h @@ -26,6 +26,8 @@ #include #include +#include + using std::string; using std::vector; using std::ostream; @@ -104,6 +106,34 @@ APT_MKSTRCMP2(stringcasecmp,stringcasecmp); inline const char *DeNull(const char *s) {return (s == 0?"(null)":s);}; +class URIAddress +{ +public: + URIAddress(); + URIAddress(const URIAddress &other); + URIAddress(URIAddress &&other); + + explicit URIAddress(const std::string &host_uri); + + URIAddress& operator=(const std::string &host_uri); + URIAddress& operator=(const URIAddress &other); + URIAddress& operator=(URIAddress &&other); + + bool operator==(const std::string &host_uri) const; + bool operator==(const URIAddress &other) const; + + std::string to_string() const; + void from_string(const std::string &host_uri); + + std::string to_hostname() const; + std::string hostname_and_interface() const; + + std::string hostname; + std::string interface; + std::experimental::optional port; + bool is_ipv6addr; +}; + class URI { void CopyFrom(const string &From); @@ -113,9 +143,8 @@ class URI string Access; string User; string Password; - string Host; + URIAddress Address; string Path; - unsigned int Port; operator string(); inline void operator =(const string &From) {CopyFrom(From);}; @@ -123,7 +152,7 @@ class URI static string SiteOnly(const string &URI); URI(const string &Path) {CopyFrom(Path);}; - URI() : Port(0) {}; + URI() {}; }; struct SubstVar diff --git a/apt/apt-pkg/rpm/rpmindexfile.cc b/apt/apt-pkg/rpm/rpmindexfile.cc index b4523b9..ad011a7 100644 --- a/apt/apt-pkg/rpm/rpmindexfile.cc +++ b/apt/apt-pkg/rpm/rpmindexfile.cc @@ -367,7 +367,7 @@ bool rpmPkgListIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const Prog.SubProgress(0,Info(MainType())); ::URI Tmp(URI); - if (Gen.SelectFile(PackageFile,Tmp.Host,*this) == false) + if (Gen.SelectFile(PackageFile,Tmp.Address.to_hostname(),*this) == false) { delete Handler; return _error->Error(_("Problem with SelectFile %s"),PackageFile.c_str()); diff --git a/apt/methods/cdrom.cc b/apt/methods/cdrom.cc index 9e04c3e..cfe0869 100644 --- a/apt/methods/cdrom.cc +++ b/apt/methods/cdrom.cc @@ -198,7 +198,7 @@ bool CDROMMethod::Fetch(FetchItem *Itm) } // All non IMS queries for package files fail. - if (Itm->IndexFile == true || GetID(Get.Host).empty() == true) + if (Itm->IndexFile == true || GetID(Get.Address.to_hostname()).empty() == true) { Fail(_("Please use apt-cdrom to make this media recognized by APT." " apt-get update cannot be used to add new Media")); @@ -206,7 +206,7 @@ bool CDROMMethod::Fetch(FetchItem *Itm) } // We already have a CD inserted, but it is the wrong one - if (CurrentID.empty() == false && Database.Find("CD::" + CurrentID) != Get.Host) + if (CurrentID.empty() == false && Database.Find("CD::" + CurrentID) != Get.Address.to_hostname()) { Fail(_("Wrong CD"),true); return true; @@ -229,7 +229,7 @@ bool CDROMMethod::Fetch(FetchItem *Itm) clog << "ID " << Version << " " << NewID << endl; // A hit - if (Database.Find("CD::" + NewID) == Get.Host) + if (Database.Find("CD::" + NewID) == Get.Address.to_hostname()) { Hit = true; break; @@ -243,7 +243,7 @@ bool CDROMMethod::Fetch(FetchItem *Itm) if (UnmountCdrom(CDROM) == false) return _error->Error(_("Unable to unmount media in %s, it may still be in use."), CDROM.c_str()); - if (MediaFail(Get.Host,CDROM) == false) + if (MediaFail(Get.Address.to_hostname(),CDROM) == false) { CurrentID = "FAIL"; Fail(_("Wrong media"),true); diff --git a/apt/methods/connect.cc b/apt/methods/connect.cc index a25d6b4..a9edd7f 100644 --- a/apt/methods/connect.cc +++ b/apt/methods/connect.cc @@ -42,7 +42,7 @@ /*}}}*/ static string LastHost; -static int LastPort = 0; +static std::string LastPort; static struct addrinfo *LastHostAddr = 0; static struct addrinfo *LastUsed = 0; @@ -153,25 +153,25 @@ static bool DoConnect(struct addrinfo *Addr,const string &Host, // Connect - Connect to a server /*{{{*/ // --------------------------------------------------------------------- /* Performs a connection to the server */ -bool Connect(const string &Host,int Port,const char *Service,int DefPort,std::unique_ptr &Fd, +bool Connect(const URIAddress &address,const char *Service,int DefPort,std::unique_ptr &Fd, unsigned long TimeOut,pkgAcqMethod *Owner) { if (_error->PendingError() == true) return false; // Convert the port name/number - char ServStr[300]; - if (Port != 0) - snprintf(ServStr,sizeof(ServStr),"%u",(unsigned) Port); + std::string ServStr; + if (address.port) + ServStr = std::to_string(*(address.port)); else - snprintf(ServStr,sizeof(ServStr),"%s",Service); + ServStr = Service; /* We used a cached address record.. Yes this is against the spec but the way we have setup our rotating dns suggests that this is more sensible */ - if (LastHost != Host || LastPort != Port) + if (LastHost != address.to_hostname() || LastPort != ServStr) { - Owner->Status(_("Connecting to %s"),Host.c_str()); + Owner->Status(_("Connecting to %s"),address.to_hostname().c_str()); // Free the old address structure if (LastHostAddr != 0) @@ -191,31 +191,31 @@ bool Connect(const string &Host,int Port,const char *Service,int DefPort,std::un while (1) { int Res; - if ((Res = getaddrinfo(Host.c_str(),ServStr,&Hints,&LastHostAddr)) != 0 || + if ((Res = getaddrinfo(address.hostname_and_interface().c_str(),ServStr.c_str(),&Hints,&LastHostAddr)) != 0 || LastHostAddr == 0) { if (Res == EAI_NONAME || Res == EAI_SERVICE) { if (DefPort != 0) { - snprintf(ServStr,sizeof(ServStr),"%u",(unsigned) DefPort); + ServStr = std::to_string((unsigned) DefPort); DefPort = 0; continue; } - return _error->Error(_("Could not resolve '%s'"),Host.c_str()); + return _error->Error(_("Could not resolve '%s'"),address.to_hostname().c_str()); } if (Res == EAI_AGAIN) return _error->Error(_("Temporary failure resolving '%s'"), - Host.c_str()); + address.to_hostname().c_str()); return _error->Error(_("Something wicked happened resolving '%s:%s' (%i)"), - Host.c_str(),ServStr,Res); + address.to_hostname().c_str(),ServStr.c_str(),Res); } break; } - LastHost = Host; - LastPort = Port; + LastHost = address.to_hostname(); + LastPort = ServStr; } // When we have an IP rotation stay with the last IP. @@ -225,7 +225,7 @@ bool Connect(const string &Host,int Port,const char *Service,int DefPort,std::un while (CurHost != 0) { - if (DoConnect(CurHost,Host,TimeOut,Fd,Owner) == true) + if (DoConnect(CurHost,address.to_hostname(),TimeOut,Fd,Owner) == true) { LastUsed = CurHost; return true; @@ -256,7 +256,7 @@ bool Connect(const string &Host,int Port,const char *Service,int DefPort,std::un if (_error->PendingError() == true) return false; - return _error->Error(_("Unable to connect to %s %s:"),Host.c_str(),ServStr); + return _error->Error(_("Unable to connect to %s %s:"),address.to_hostname().c_str(),ServStr.c_str()); } /*}}}*/ diff --git a/apt/methods/connect.h b/apt/methods/connect.h index e0cafba..89b4b8c 100644 --- a/apt/methods/connect.h +++ b/apt/methods/connect.h @@ -36,7 +36,7 @@ struct MethodFd virtual bool HasPending(); }; -bool Connect(const string &To,int Port,const char *Service,int DefPort, +bool Connect(const URIAddress &address,const char *Service,int DefPort, std::unique_ptr &Fd,unsigned long TimeOut,pkgAcqMethod *Owner); void RotateDNS(); diff --git a/apt/methods/file.cc b/apt/methods/file.cc index f3a13d2..d849ca6 100644 --- a/apt/methods/file.cc +++ b/apt/methods/file.cc @@ -42,7 +42,7 @@ bool FileMethod::Fetch(FetchItem *Itm) URI Get = Itm->Uri; string File = Get.Path; FetchResult Res; - if (Get.Host.empty() == false) + if (Get.Address.to_hostname().empty() == false) return _error->Error(_("Invalid URI, local URIS must not start with //")); // See if the file exists diff --git a/apt/methods/ftp.cc b/apt/methods/ftp.cc index 00a5502..e79e70d 100644 --- a/apt/methods/ftp.cc +++ b/apt/methods/ftp.cc @@ -119,7 +119,7 @@ bool FTPConn::Open(pkgAcqMethod *Owner) if (getenv("ftp_proxy") == 0) { string DefProxy = _config->Find("Acquire::ftp::Proxy"); - string SpecificProxy = _config->Find("Acquire::ftp::Proxy::" + ServerName.Host); + string SpecificProxy = _config->Find("Acquire::ftp::Proxy::" + ServerName.Address.to_hostname()); if (SpecificProxy.empty() == false) { if (SpecificProxy == "DIRECT") @@ -136,30 +136,14 @@ bool FTPConn::Open(pkgAcqMethod *Owner) // Parse no_proxy, a , separated list of domains if (getenv("no_proxy") != 0) { - if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true) + if (CheckDomainList(ServerName.Address.to_hostname(),getenv("no_proxy")) == true) Proxy = ""; } - - // Determine what host and port to use based on the proxy settings - int Port = 0; - string Host; - if (Proxy.empty() == true) - { - if (ServerName.Port != 0) - Port = ServerName.Port; - Host = ServerName.Host; - } - else - { - if (Proxy.Port != 0) - Port = Proxy.Port; - Host = Proxy.Host; - } /* Connect to the remote server. Since FTP is connection oriented we want to make sure we get a new server every time we reconnect */ RotateDNS(); - if (Connect(Host,Port,"ftp",21,ServerFd,TimeOut,Owner) == false) + if (Connect(Proxy.empty() ? ServerName.Address : Proxy.Address,"ftp",21,ServerFd,TimeOut,Owner) == false) return false; // Login must be before getpeername otherwise dante won't work. @@ -223,8 +207,8 @@ bool FTPConn::Login() } // Enter passive mode - if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Host) == true) - TryPassive = _config->FindB("Acquire::FTP::Passive::" + ServerName.Host,true); + if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Address.to_hostname()) == true) + TryPassive = _config->FindB("Acquire::FTP::Passive::" + ServerName.Address.to_hostname(),true); else TryPassive = _config->FindB("Acquire::FTP::Passive",true); } @@ -251,8 +235,8 @@ bool FTPConn::Login() // Substitute the variables into the command char SitePort[20]; - if (ServerName.Port != 0) - sprintf(SitePort,"%u",ServerName.Port); + if (ServerName.Address.port) + sprintf(SitePort,"%u",*(ServerName.Address.port)); else strcpy(SitePort,"21"); string Tmp = Opts->Value; @@ -261,7 +245,7 @@ bool FTPConn::Login() Tmp = SubstVar(Tmp,"$(SITE_USER)",User); Tmp = SubstVar(Tmp,"$(SITE_PASS)",Pass); Tmp = SubstVar(Tmp,"$(SITE_PORT)",SitePort); - Tmp = SubstVar(Tmp,"$(SITE)",ServerName.Host); + Tmp = SubstVar(Tmp,"$(SITE)",ServerName.Address.to_hostname()); // Send the command if (WriteMsg(Tag,Msg,"%s",Tmp.c_str()) == false) @@ -272,8 +256,8 @@ bool FTPConn::Login() // Enter passive mode TryPassive = false; - if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Host) == true) - TryPassive = _config->FindB("Acquire::FTP::Passive::" + ServerName.Host,true); + if (_config->Exists("Acquire::FTP::Passive::" + ServerName.Address.to_hostname()) == true) + TryPassive = _config->FindB("Acquire::FTP::Passive::" + ServerName.Address.to_hostname(),true); else { if (_config->Exists("Acquire::FTP::Proxy::Passive") == true) @@ -284,8 +268,8 @@ bool FTPConn::Login() } // Force the use of extended commands - if (_config->Exists("Acquire::FTP::ForceExtended::" + ServerName.Host) == true) - ForceExtended = _config->FindB("Acquire::FTP::ForceExtended::" + ServerName.Host,true); + if (_config->Exists("Acquire::FTP::ForceExtended::" + ServerName.Address.to_hostname()) == true) + ForceExtended = _config->FindB("Acquire::FTP::ForceExtended::" + ServerName.Address.to_hostname(),true); else ForceExtended = _config->FindB("Acquire::FTP::ForceExtended",false); diff --git a/apt/methods/ftp.h b/apt/methods/ftp.h index b4a30fe..5828eea 100644 --- a/apt/methods/ftp.h +++ b/apt/methods/ftp.h @@ -41,7 +41,7 @@ class FTPConn public: - bool Comp(URI Other) {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;}; + bool Comp(URI Other) {return Other.Address == ServerName.Address;}; // Raw connection IO bool ReadResp(unsigned int &Ret,string &Text); diff --git a/apt/methods/gpg.cc b/apt/methods/gpg.cc index 2925908..7179cef 100644 --- a/apt/methods/gpg.cc +++ b/apt/methods/gpg.cc @@ -337,7 +337,7 @@ void removeTmpDir(const string &path, int sigCount) bool GPGMethod::Fetch(FetchItem *Itm) { URI Get = Itm->Uri; - string Path = Get.Host + Get.Path; // To account for relative paths + string Path = Get.Address.to_hostname() + Get.Path; // To account for relative paths string KeyList; FetchResult Res; diff --git a/apt/methods/gzip.cc b/apt/methods/gzip.cc index db61e69..9ecc368 100644 --- a/apt/methods/gzip.cc +++ b/apt/methods/gzip.cc @@ -45,7 +45,7 @@ class GzipMethod : public pkgAcqMethod bool GzipMethod::Fetch(FetchItem *Itm) { URI Get = Itm->Uri; - string Path = Get.Host + Get.Path; // To account for relative paths + string Path = Get.Address.to_hostname() + Get.Path; // To account for relative paths string GzPathOption = "Dir::bin::"+string(Prog); diff --git a/apt/methods/http.cc b/apt/methods/http.cc index c9a37de..9302495 100644 --- a/apt/methods/http.cc +++ b/apt/methods/http.cc @@ -293,7 +293,7 @@ bool ServerState::Open() if (getenv("http_proxy") == 0) { string DefProxy = _config->Find("Acquire::http::Proxy"); - string SpecificProxy = _config->Find("Acquire::http::Proxy::" + ServerName.Host); + string SpecificProxy = _config->Find("Acquire::http::Proxy::" + ServerName.Address.to_hostname()); if (SpecificProxy.empty() == false) { if (SpecificProxy == "DIRECT") @@ -310,37 +310,23 @@ bool ServerState::Open() // Parse no_proxy, a , separated list of domains if (getenv("no_proxy") != 0) { - if (CheckDomainList(ServerName.Host,getenv("no_proxy")) == true) + if (CheckDomainList(ServerName.Address.to_hostname(),getenv("no_proxy")) == true) Proxy = ""; } #endif /* !USE_TLS */ - - // Determine what host and port to use based on the proxy settings - int Port = 0; - string Host; -#ifndef USE_TLS - if (Proxy.empty() == true || Proxy.Host.empty() == true) - { -#endif /* !USE_TLS */ - if (ServerName.Port != 0) - Port = ServerName.Port; - Host = ServerName.Host; -#ifndef USE_TLS - } - else - { - if (Proxy.Port != 0) - Port = Proxy.Port; - Host = Proxy.Host; - } -#endif /* !USE_TLS */ // Connect to the remote server - if (Connect(Host,Port,service_name,default_port,ServerFd,TimeOut,Owner) == false) + if (Connect( +#ifndef USE_TLS + Proxy.empty() ? ServerName.Address : Proxy.Address, +#else /* USE_TLS */ + ServerName.Address, +#endif /* USE_TLS */ + service_name,default_port,ServerFd,TimeOut,Owner) == false) return false; #ifdef USE_TLS - if (!UnwrapTLS(ServerName.Host, ServerFd, TimeOut, Owner)) + if (!UnwrapTLS(ServerName.Address.to_hostname(), ServerFd, TimeOut, Owner)) return false; #endif /* USE_TLS */ @@ -639,12 +625,7 @@ void HttpMethod::SendReq(FetchItem *Itm,CircleBuf &Out) // The HTTP server expects a hostname with a trailing :port char Buf[1000]; - string ProperHost = Uri.Host; - if (Uri.Port != 0) - { - sprintf(Buf,":%u",Uri.Port); - ProperHost += Buf; - } + string ProperHost = Uri.Address.to_string(); // Just in case. if (Itm->Uri.length() >= sizeof(Buf)) @@ -944,7 +925,7 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv) { for (CurrentAuth = AuthList.begin(); CurrentAuth != AuthList.end(); ++CurrentAuth) - if (CurrentAuth->Host == Srv->ServerName.Host) + if (CurrentAuth->Host == Srv->ServerName.Address.to_hostname()) { AuthUser = CurrentAuth->User; AuthPass = CurrentAuth->Password; @@ -957,7 +938,7 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv) // Nope - get username and password if (CurrentAuth == AuthList.end()) { - Description = ParsedURI.Host; + Description = ParsedURI.Address.to_hostname(); #ifdef USE_TLS if (ParsedURI.Access == "https") @@ -969,13 +950,13 @@ int HttpMethod::DealWithHeaders(FetchResult &Res,ServerState *Srv) // Got new credentials; save them AuthRec NewAuthInfo; - NewAuthInfo.Host = Srv->ServerName.Host; + NewAuthInfo.Host = Srv->ServerName.Address.to_hostname(); NewAuthInfo.User = AuthUser; NewAuthInfo.Password = AuthPass; for (CurrentAuth = AuthList.begin(); CurrentAuth != AuthList.end(); ++CurrentAuth) - if (CurrentAuth->Host == Srv->ServerName.Host) + if (CurrentAuth->Host == Srv->ServerName.Address.to_hostname()) { *CurrentAuth = NewAuthInfo; break; diff --git a/apt/methods/http.h b/apt/methods/http.h index 9e4d2be..0a8362a 100644 --- a/apt/methods/http.h +++ b/apt/methods/http.h @@ -110,7 +110,7 @@ struct ServerState URI ServerName; bool HeaderLine(const string &Line); - bool Comp(URI Other) {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;}; + bool Comp(URI Other) {return Other.Address == ServerName.Address;}; void Reset() {Major = 0; Minor = 0; Result = 0; Size = 0; StartPos = 0; Encoding = Closes; time(&Date); ServerFd.reset(); Pipeline = true; }; diff --git a/apt/methods/rsh.cc b/apt/methods/rsh.cc index 8bc47b0..2371e4a 100644 --- a/apt/methods/rsh.cc +++ b/apt/methods/rsh.cc @@ -77,7 +77,7 @@ bool RSHConn::Open() if (Process != -1) return true; - if (Connect(ServerName.Host,ServerName.User) == false) + if (Connect(ServerName.Address.to_hostname(),ServerName.User) == false) return false; return true; @@ -428,7 +428,7 @@ bool RSHMethod::Fetch(FetchItem *Itm) // We say this mainly because the pause here is for the // ssh connection that is still going - Status(_("Connecting to %s"), Get.Host.c_str()); + Status(_("Connecting to %s"), Get.Address.to_hostname().c_str()); // Get the files information unsigned long long Size; diff --git a/apt/methods/rsh.h b/apt/methods/rsh.h index e99c59c..010a28f 100644 --- a/apt/methods/rsh.h +++ b/apt/methods/rsh.h @@ -33,7 +33,7 @@ class RSHConn // Raw connection IO bool WriteMsg(string &Text,bool Sync,const char *Fmt,...); bool Connect(const string &Host, const string &User); - bool Comp(URI Other) {return Other.Host == ServerName.Host && Other.Port == ServerName.Port;}; + bool Comp(URI Other) {return Other.Address == ServerName.Address;}; // Connection control bool Open(); diff --git a/apt/methods/rsync.cc b/apt/methods/rsync.cc index efc1c0e..f28bb5a 100644 --- a/apt/methods/rsync.cc +++ b/apt/methods/rsync.cc @@ -353,11 +353,7 @@ bool RsyncMethod::RsyncConnExec::Get(pkgAcqMethod *Owner, FetchResult &FRes, con } } - char port[12]; - if (srv.Port!=0) - snprintf(port, sizeof(port), ":%u", srv.Port); - else port[0] = 0; - argv.add( "rsync://" + srv.Host + port + From); + argv.add( "rsync://" + srv.Address.to_string() + From); argv.add(To); if ( pipe(p) ) { @@ -519,12 +515,12 @@ bool RsyncMethod::Fetch(FetchItem *Itm) Res.ResumePoint = st.st_size; } - string proxy = _config->Find(string("Acquire::rsync::proxy::")+Get.Host); + string proxy = _config->Find(string("Acquire::rsync::proxy::")+Get.Address.to_hostname()); if ( proxy.empty() ) proxy = _config->Find("Acquire::rsync::proxy"); if (Debug) - cerr << endl << "RSYNC: Proxy(" << Get.Host << "): " << proxy << endl; + cerr << endl << "RSYNC: Proxy(" << Get.Address.to_hostname() << "): " << proxy << endl; // Don't compare now for the same server uri delete server; diff --git a/apt/test/uri.cc b/apt/test/uri.cc index ec652de..535aedb 100644 --- a/apt/test/uri.cc +++ b/apt/test/uri.cc @@ -7,9 +7,12 @@ void Test(const char *Foo) { URI U(Foo); - printf("%s a='%s' u='%s' p='%s' port='%u'\n h='%s' p='%s'\n", + printf("%s a='%s' u='%s' p='%s'\n h='%s' i='%s' port='%s' ipv6='%s'\n p='%s'\n", Foo,U.Access.c_str(),U.User.c_str(),U.Password.c_str(), - U.Port,U.Host.c_str(),U.Path.c_str()); + U.Address.hostname.c_str(), U.Address.interface.c_str(), + U.Address.port ? std::to_string(*(U.Address.port)).c_str() : "(nil)", + U.Address.is_ipv6addr ? "true" : "false", + U.Path.c_str()); } int main() @@ -22,10 +25,17 @@ int main() Test("gzip:./bar/cow"); // RFC 2732 stuff + Test("http://127.0.0.1/foo"); + Test("http://127.0.0.1:80/foo"); Test("http://[1080::8:800:200C:417A]/foo"); Test("http://[::FFFF:129.144.52.38]:80/index.html"); Test("http://[::FFFF:129.144.52.38:]:80/index.html"); Test("http://[::FFFF:129.144.52.38:]/index.html"); + Test("http://[::FFFF:129.144.52.38%eth0]/index.html"); + Test("http://[::FFFF:129.144.52.38%]/index.html"); + Test("http://[::FFFF:129.144.52.38%l]/index.html"); + Test("http://[::FFFF:129.144.52.38]:/index.html"); + Test("http://[::FFFF:129.144.52.38]:8/index.html"); /* My Evil Corruption of RFC 2732 to handle CDROM names! Fun for the whole family! */ -- 2.24.0