apt  2.2.4
About: Apt (Advanced Package Tool) is a management system for software packages (Debian/Ubuntu). Release series 2.2.
  Fossies Dox: apt-2.2.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

connect.cc
Go to the documentation of this file.
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 /* ######################################################################
4 
5  Connect - Replacement connect call
6 
7  This was originally authored by Jason Gunthorpe <jgg@debian.org>
8  and is placed in the Public Domain, do with it what you will.
9 
10  ##################################################################### */
11  /*}}}*/
12 // Include Files /*{{{*/
13 #include <config.h>
14 
15 #include <apt-pkg/acquire-method.h>
16 #include <apt-pkg/configuration.h>
17 #include <apt-pkg/error.h>
18 #include <apt-pkg/fileutl.h>
19 #include <apt-pkg/srvrec.h>
20 #include <apt-pkg/strutl.h>
21 
22 #include <gnutls/gnutls.h>
23 #include <gnutls/x509.h>
24 
25 #include <list>
26 #include <set>
27 #include <sstream>
28 #include <string>
29 #include <errno.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 // Internet stuff
35 #include <netdb.h>
36 #include <arpa/inet.h>
37 #include <netinet/in.h>
38 #include <sys/select.h>
39 #include <sys/socket.h>
40 
41 #include "aptmethod.h"
42 #include "connect.h"
43 #include "rfc2553emu.h"
44 #include <apti18n.h>
45  /*}}}*/
46 
47 static std::string LastHost;
48 static std::string LastService;
49 static struct addrinfo *LastHostAddr = 0;
50 static struct addrinfo *LastUsed = 0;
51 
52 static std::vector<SrvRec> SrvRecords;
53 
54 // Set of IP/hostnames that we timed out before or couldn't resolve
55 static std::set<std::string> bad_addr;
56 
57 // RotateDNS - Select a new server from a DNS rotation /*{{{*/
58 // ---------------------------------------------------------------------
59 /* This is called during certain errors in order to recover by selecting a
60  new server */
61 void RotateDNS()
62 {
63  if (LastUsed != 0 && LastUsed->ai_next != 0)
65  else
67 }
68  /*}}}*/
69 static bool ConnectionAllowed(char const * const Service, std::string const &Host)/*{{{*/
70 {
71  if (unlikely(Host.empty())) // the only legal empty host (RFC2782 '.' target) is detected by caller
72  return false;
73  if (APT::String::Endswith(Host, ".onion") && _config->FindB("Acquire::BlockDotOnion", true))
74  {
75  // TRANSLATOR: %s is e.g. Tor's ".onion" which would likely fail or leak info (RFC7686)
76  _error->Error(_("Direct connection to %s domains is blocked by default."), ".onion");
77  if (strcmp(Service, "http") == 0)
78  _error->Error(_("If you meant to use Tor remember to use %s instead of %s."), "tor+http", "http");
79  return false;
80  }
81  return true;
82 }
83  /*}}}*/
84 
85 // File Descriptor based Fd /*{{{*/
86 struct FdFd : public MethodFd
87 {
88  int fd = -1;
89  int Fd() APT_OVERRIDE { return fd; }
90  ssize_t Read(void *buf, size_t count) APT_OVERRIDE { return ::read(fd, buf, count); }
91  ssize_t Write(void *buf, size_t count) APT_OVERRIDE { return ::write(fd, buf, count); }
93  {
94  int result = 0;
95  if (fd != -1)
96  result = ::close(fd);
97  fd = -1;
98  return result;
99  }
100 };
101 
103 {
104  return false;
105 }
106 std::unique_ptr<MethodFd> MethodFd::FromFd(int iFd)
107 {
108  FdFd *fd = new FdFd();
109  fd->fd = iFd;
110  return std::unique_ptr<MethodFd>(fd);
111 }
112  /*}}}*/
113 // DoConnect - Attempt a connect operation /*{{{*/
114 // ---------------------------------------------------------------------
115 /* This helper function attempts a connection to a single address. */
117 {
118  struct addrinfo *Addr;
119  std::string Host;
121  std::unique_ptr<FdFd> Fd;
124 
125  Connection(struct addrinfo *Addr, std::string const &Host, aptMethod *Owner) : Addr(Addr), Host(Host), Owner(Owner), Fd(new FdFd()), Name{0}, Service{0}
126  {
127  }
128 
129  // Allow moving values, but not connections.
130  Connection(Connection &&Conn) = default;
131  Connection(const Connection &Conn) = delete;
132  Connection &operator=(const Connection &) = delete;
133  Connection &operator=(Connection &&Conn) = default;
134 
136  {
137  if (Fd != nullptr)
138  {
139  Fd->Close();
140  }
141  }
142 
143  std::unique_ptr<MethodFd> Take()
144  {
145  /* Store the IP we are using.. If something goes
146  wrong this will get tacked onto the end of the error message */
147  std::stringstream ss;
148  ioprintf(ss, _("[IP: %s %s]"), Name, Service);
149  Owner->SetIP(ss.str());
150  Owner->Status(_("Connected to %s (%s)"), Host.c_str(), Name);
151  _error->Discard();
152  Owner->SetFailReason("");
153  LastUsed = Addr;
154  return std::move(Fd);
155  }
156 
158 
160 };
161 
163 {
165  Name,sizeof(Name),Service,sizeof(Service),
167  Owner->Status(_("Connecting to %s (%s)"),Host.c_str(),Name);
168 
169  // if that addr did timeout before, we do not try it again
170  if(bad_addr.find(std::string(Name)) != bad_addr.end())
172 
173  // Get a socket
174  if ((static_cast<FdFd *>(Fd.get())->fd = socket(Addr->ai_family, Addr->ai_socktype,
175  Addr->ai_protocol)) < 0)
176  {
177  _error->Errno("socket", _("Could not create a socket for %s (f=%u t=%u p=%u)"),
180  }
181 
182  SetNonBlock(Fd->Fd(), true);
183  if (connect(Fd->Fd(), Addr->ai_addr, Addr->ai_addrlen) < 0 &&
184  errno != EINPROGRESS)
185  {
186  _error->Errno("connect", _("Cannot initiate the connection "
187  "to %s:%s (%s)."),
188  Host.c_str(), Service, Name);
190  }
191 
193 }
194 
196 {
197  // Check the socket for an error condition
198  unsigned int Err;
199  unsigned int Len = sizeof(Err);
200  if (getsockopt(Fd->Fd(), SOL_SOCKET, SO_ERROR, &Err, &Len) != 0)
201  {
202  _error->Errno("getsockopt", _("Failed"));
204  }
205 
206  if (Err != 0)
207  {
208  errno = Err;
209  if(errno == ECONNREFUSED)
210  Owner->SetFailReason("ConnectionRefused");
211  else if (errno == ETIMEDOUT)
212  Owner->SetFailReason("ConnectionTimedOut");
213  bad_addr.insert(bad_addr.begin(), std::string(Name));
214  _error->Errno("connect", _("Could not connect to %s:%s (%s)."), Host.c_str(),
215  Service, Name);
217  }
218 
219  Owner->SetFailReason("");
220 
222 }
223  /*}}}*/
224 // Order the given host names returned by getaddrinfo() /*{{{*/
225 static std::vector<struct addrinfo *> OrderAddresses(struct addrinfo *CurHost)
226 {
227  std::vector<struct addrinfo *> preferredAddrs;
228  std::vector<struct addrinfo *> otherAddrs;
229  std::vector<struct addrinfo *> allAddrs;
230 
231  // Partition addresses into preferred and other address families
232  while (CurHost != 0)
233  {
234  if (preferredAddrs.empty() || CurHost->ai_family == preferredAddrs[0]->ai_family)
235  preferredAddrs.push_back(CurHost);
236  else
237  otherAddrs.push_back(CurHost);
238 
239  // Ignore UNIX domain sockets
240  do
241  {
242  CurHost = CurHost->ai_next;
243  } while (CurHost != 0 && CurHost->ai_family == AF_UNIX);
244 
245  /* If we reached the end of the search list then wrap around to the
246  start */
247  if (CurHost == 0 && LastUsed != 0)
248  CurHost = LastHostAddr;
249 
250  // Reached the end of the search cycle
251  if (CurHost == LastUsed)
252  break;
253  }
254 
255  // Build a new address vector alternating between preferred and other
256  for (auto prefIter = preferredAddrs.cbegin(), otherIter = otherAddrs.cbegin();
257  prefIter != preferredAddrs.end() || otherIter != otherAddrs.end();)
258  {
259  if (prefIter != preferredAddrs.end())
260  allAddrs.push_back(*prefIter++);
261  if (otherIter != otherAddrs.end())
262  allAddrs.push_back(*otherIter++);
263  }
264 
265  return allAddrs;
266 }
267  /*}}}*/
268 // Check for errors and report them /*{{{*/
269 static ResultState WaitAndCheckErrors(std::list<Connection> &Conns, std::unique_ptr<MethodFd> &Fd, long TimeoutMsec, bool ReportTimeout)
270 {
271  // The last error detected
273 
274  struct timeval tv = {
275  // Split our millisecond timeout into seconds and microseconds
276  .tv_sec = TimeoutMsec / 1000,
277  .tv_usec = (TimeoutMsec % 1000) * 1000,
278  };
279 
280  // We will return once we have no more connections, a time out, or
281  // a success.
282  while (!Conns.empty())
283  {
284  fd_set Set;
285  int nfds = -1;
286 
287  FD_ZERO(&Set);
288 
289  for (auto &Conn : Conns)
290  {
291  int fd = Conn.Fd->Fd();
292  FD_SET(fd, &Set);
293  nfds = std::max(nfds, fd);
294  }
295 
296  {
297  int Res;
298  do
299  {
300  Res = select(nfds + 1, 0, &Set, 0, (TimeoutMsec != 0 ? &tv : 0));
301  } while (Res < 0 && errno == EINTR);
302 
303  if (Res == 0)
304  {
305  if (ReportTimeout)
306  {
307  for (auto &Conn : Conns)
308  {
309  Conn.Owner->SetFailReason("Timeout");
310  bad_addr.insert(bad_addr.begin(), Conn.Name);
311  _error->Error(_("Could not connect to %s:%s (%s), "
312  "connection timed out"),
313  Conn.Host.c_str(), Conn.Service, Conn.Name);
314  }
315  }
317  }
318  }
319 
320  // iterate over connections, remove failed ones, and return if
321  // there was a successful one.
322  for (auto ConnI = Conns.begin(); ConnI != Conns.end();)
323  {
324  if (!FD_ISSET(ConnI->Fd->Fd(), &Set))
325  {
326  ConnI++;
327  continue;
328  }
329 
330  Result = ConnI->CheckError();
331  if (Result == ResultState::SUCCESSFUL)
332  {
333  Fd = ConnI->Take();
334  return Result;
335  }
336 
337  // Connection failed. Erase it and continue to next position
338  ConnI = Conns.erase(ConnI);
339  }
340  }
341 
342  return Result;
343 }
344  /*}}}*/
345 // Connect to a given Hostname /*{{{*/
346 static ResultState ConnectToHostname(std::string const &Host, int const Port,
347  const char *const Service, int DefPort, std::unique_ptr<MethodFd> &Fd,
348  unsigned long const TimeOut, aptMethod *const Owner)
349 {
350  if (ConnectionAllowed(Service, Host) == false)
352 
353  // Used by getaddrinfo(); prefer port if given, else fallback to service
354  std::string ServiceNameOrPort = Port != 0 ? std::to_string(Port) : Service;
355 
356  /* We used a cached address record.. Yes this is against the spec but
357  the way we have setup our rotating dns suggests that this is more
358  sensible */
359  if (LastHost != Host || LastService != ServiceNameOrPort)
360  {
361  Owner->Status(_("Connecting to %s"),Host.c_str());
362 
363  // Free the old address structure
364  if (LastHostAddr != 0)
365  {
367  LastHostAddr = 0;
368  LastUsed = 0;
369  }
370 
371  // We only understand SOCK_STREAM sockets.
372  struct addrinfo Hints;
373  memset(&Hints,0,sizeof(Hints));
374  Hints.ai_socktype = SOCK_STREAM;
375  Hints.ai_flags = 0;
376 #ifdef AI_IDN
377  if (_config->FindB("Acquire::Connect::IDN", true) == true)
378  Hints.ai_flags |= AI_IDN;
379 #endif
380  // see getaddrinfo(3): only return address if system has such a address configured
381  // useful if system is ipv4 only, to not get ipv6, but that fails if the system has
382  // no address configured: e.g. offline and trying to connect to localhost.
383  if (_config->FindB("Acquire::Connect::AddrConfig", true) == true)
384  Hints.ai_flags |= AI_ADDRCONFIG;
385  Hints.ai_protocol = 0;
386 
387  if(_config->FindB("Acquire::ForceIPv4", false) == true)
388  Hints.ai_family = AF_INET;
389  else if(_config->FindB("Acquire::ForceIPv6", false) == true)
390  Hints.ai_family = AF_INET6;
391  else
392  Hints.ai_family = AF_UNSPEC;
393 
394  // if we couldn't resolve the host before, we don't try now
395  if (bad_addr.find(Host) != bad_addr.end())
396  {
397  _error->Error(_("Could not resolve '%s'"), Host.c_str());
399  }
400 
401  // Resolve both the host and service simultaneously
402  while (1)
403  {
404  int Res;
405  if ((Res = getaddrinfo(Host.c_str(), ServiceNameOrPort.c_str(), &Hints, &LastHostAddr)) != 0 ||
406  LastHostAddr == 0)
407  {
408  if (Res == EAI_NONAME || Res == EAI_SERVICE)
409  {
410  if (DefPort != 0)
411  {
412  ServiceNameOrPort = std::to_string(DefPort);
413  DefPort = 0;
414  continue;
415  }
416  bad_addr.insert(bad_addr.begin(), Host);
417  Owner->SetFailReason("ResolveFailure");
418  _error->Error(_("Could not resolve '%s'"), Host.c_str());
420  }
421 
422  if (Res == EAI_AGAIN)
423  {
424  Owner->SetFailReason("TmpResolveFailure");
425  _error->Error(_("Temporary failure resolving '%s'"),
426  Host.c_str());
428  }
429  if (Res == EAI_SYSTEM)
430  _error->Errno("getaddrinfo", _("System error resolving '%s:%s'"),
431  Host.c_str(), ServiceNameOrPort.c_str());
432  else
433  _error->Error(_("Something wicked happened resolving '%s:%s' (%i - %s)"),
434  Host.c_str(), ServiceNameOrPort.c_str(), Res, gai_strerror(Res));
436  }
437  break;
438  }
439 
440  LastHost = Host;
441  LastService = ServiceNameOrPort;
442  }
443 
444  // When we have an IP rotation stay with the last IP.
445  auto Addresses = OrderAddresses(LastUsed != nullptr ? LastUsed : LastHostAddr);
446  std::list<Connection> Conns;
448 
449  for (auto Addr : Addresses)
450  {
451  Connection Conn(Addr, Host, Owner);
452  if (Conn.DoConnect() != ResultState::SUCCESSFUL)
453  continue;
454 
455  Conns.push_back(std::move(Conn));
456 
457  Result = WaitAndCheckErrors(Conns, Fd, Owner->ConfigFindI("ConnectionAttemptDelayMsec", 250), false);
458 
459  if (Result == ResultState::SUCCESSFUL)
461  }
462 
463  if (!Conns.empty())
464  return WaitAndCheckErrors(Conns, Fd, TimeOut * 1000, true);
465  if (Result != ResultState::SUCCESSFUL)
466  return Result;
467  if (_error->PendingError() == true)
469  _error->Error(_("Unable to connect to %s:%s:"), Host.c_str(), ServiceNameOrPort.c_str());
471 }
472  /*}}}*/
473 // Connect - Connect to a server /*{{{*/
474 // ---------------------------------------------------------------------
475 /* Performs a connection to the server (including SRV record lookup) */
476 ResultState Connect(std::string Host, int Port, const char *Service,
477  int DefPort, std::unique_ptr<MethodFd> &Fd,
478  unsigned long TimeOut, aptMethod *Owner)
479 {
480  if (_error->PendingError() == true)
482 
483  if (ConnectionAllowed(Service, Host) == false)
485 
486  // Used by getaddrinfo(); prefer port if given, else fallback to service
487  std::string ServiceNameOrPort = Port != 0 ? std::to_string(Port) : Service;
488 
489  if(LastHost != Host || LastService != ServiceNameOrPort)
490  {
491  SrvRecords.clear();
492  if (_config->FindB("Acquire::EnableSrvRecords", true) == true)
493  {
494  GetSrvRecords(Host, DefPort, SrvRecords);
495  // RFC2782 defines that a lonely '.' target is an abort reason
496  if (SrvRecords.size() == 1 && SrvRecords[0].target.empty())
497  {
498  _error->Error("SRV records for %s indicate that "
499  "%s service is not available at this domain",
500  Host.c_str(), Service);
502  }
503  }
504  }
505 
506  size_t stackSize = 0;
507  // try to connect in the priority order of the srv records
508  std::string initialHost{std::move(Host)};
509  auto const initialPort = Port;
510  while(SrvRecords.empty() == false)
511  {
512  _error->PushToStack();
513  ++stackSize;
514  // PopFromSrvRecs will also remove the server
515  auto Srv = PopFromSrvRecs(SrvRecords);
516  Host = Srv.target;
517  Port = Srv.port;
518  auto const ret = ConnectToHostname(Host, Port, Service, DefPort, Fd, TimeOut, Owner);
519  if (ret == ResultState::SUCCESSFUL)
520  {
521  while(stackSize--)
522  _error->RevertToStack();
523  return ret;
524  }
525  }
526  Host = std::move(initialHost);
527  Port = initialPort;
528 
529  // we have no (good) SrvRecords for this host, connect right away
530  _error->PushToStack();
531  ++stackSize;
532  auto const ret = ConnectToHostname(Host, Port, Service, DefPort, Fd,
533  TimeOut, Owner);
534  while(stackSize--)
535  if (ret == ResultState::SUCCESSFUL)
536  _error->RevertToStack();
537  else
538  _error->MergeWithStack();
539  return ret;
540 }
541  /*}}}*/
542 // UnwrapSocks - Handle SOCKS setup /*{{{*/
543 // ---------------------------------------------------------------------
544 /* This does socks magic */
545 static bool TalkToSocksProxy(int const ServerFd, std::string const &Proxy,
546  char const *const type, bool const ReadWrite, uint8_t *const ToFrom,
547  unsigned int const Size, unsigned int const Timeout)
548 {
549  if (WaitFd(ServerFd, ReadWrite, Timeout) == false)
550  {
551  if (ReadWrite)
552  return _error->Error("Timed out while waiting to write '%s' to proxy %s", type, URI::SiteOnly(Proxy).c_str());
553  else
554  return _error->Error("Timed out while waiting to read '%s' from proxy %s", type, URI::SiteOnly(Proxy).c_str());
555  }
556  if (ReadWrite == false)
557  {
558  if (FileFd::Read(ServerFd, ToFrom, Size) == false)
559  return _error->Error("Reading the %s from SOCKS proxy %s failed", type, URI::SiteOnly(Proxy).c_str());
560  }
561  else
562  {
563  if (FileFd::Write(ServerFd, ToFrom, Size) == false)
564  return _error->Error("Writing the %s to SOCKS proxy %s failed", type, URI::SiteOnly(Proxy).c_str());
565  }
566  return true;
567 }
568 
569 ResultState UnwrapSocks(std::string Host, int Port, URI Proxy, std::unique_ptr<MethodFd> &Fd,
570  unsigned long Timeout, aptMethod *Owner)
571 {
572  /* We implement a very basic SOCKS5 client here complying mostly to RFC1928 expect
573  * for not offering GSSAPI auth which is a must (we only do no or user/pass auth).
574  * We also expect the SOCKS5 server to do hostname lookup (aka socks5h) */
575  std::string const ProxyInfo = URI::SiteOnly(Proxy);
576  Owner->Status(_("Connecting to %s (%s)"), "SOCKS5h proxy", ProxyInfo.c_str());
577 #define APT_WriteOrFail(TYPE, DATA, LENGTH) \
578  if (TalkToSocksProxy(Fd->Fd(), ProxyInfo, TYPE, true, DATA, LENGTH, Timeout) == false) \
579  return ResultState::TRANSIENT_ERROR
580 #define APT_ReadOrFail(TYPE, DATA, LENGTH) \
581  if (TalkToSocksProxy(Fd->Fd(), ProxyInfo, TYPE, false, DATA, LENGTH, Timeout) == false) \
582  return ResultState::TRANSIENT_ERROR
583  if (Host.length() > 255)
584  {
585  _error->Error("Can't use SOCKS5h as hostname %s is too long!", Host.c_str());
587  }
588  if (Proxy.User.length() > 255 || Proxy.Password.length() > 255)
589  {
590  _error->Error("Can't use user&pass auth as they are too long (%lu and %lu) for the SOCKS5!", Proxy.User.length(), Proxy.Password.length());
592  }
593  if (Proxy.User.empty())
594  {
595  uint8_t greeting[] = {0x05, 0x01, 0x00};
596  APT_WriteOrFail("greet-1", greeting, sizeof(greeting));
597  }
598  else
599  {
600  uint8_t greeting[] = {0x05, 0x02, 0x00, 0x02};
601  APT_WriteOrFail("greet-2", greeting, sizeof(greeting));
602  }
603  uint8_t greeting[2];
604  APT_ReadOrFail("greet back", greeting, sizeof(greeting));
605  if (greeting[0] != 0x05)
606  {
607  _error->Error("SOCKS proxy %s greets back with wrong version: %d", ProxyInfo.c_str(), greeting[0]);
609  }
610  if (greeting[1] == 0x00)
611  ; // no auth has no method-dependent sub-negotiations
612  else if (greeting[1] == 0x02)
613  {
614  if (Proxy.User.empty())
615  {
616  _error->Error("SOCKS proxy %s negotiated user&pass auth, but we had not offered it!", ProxyInfo.c_str());
618  }
619  // user&pass auth sub-negotiations are defined by RFC1929
620  std::vector<uint8_t> auth = {{0x01, static_cast<uint8_t>(Proxy.User.length())}};
621  std::copy(Proxy.User.begin(), Proxy.User.end(), std::back_inserter(auth));
622  auth.push_back(static_cast<uint8_t>(Proxy.Password.length()));
623  std::copy(Proxy.Password.begin(), Proxy.Password.end(), std::back_inserter(auth));
624  APT_WriteOrFail("user&pass auth", auth.data(), auth.size());
625  uint8_t authstatus[2];
626  APT_ReadOrFail("auth report", authstatus, sizeof(authstatus));
627  if (authstatus[0] != 0x01)
628  {
629  _error->Error("SOCKS proxy %s auth status response with wrong version: %d", ProxyInfo.c_str(), authstatus[0]);
631  }
632  if (authstatus[1] != 0x00)
633  {
634  _error->Error("SOCKS proxy %s reported authorization failure: username or password incorrect? (%d)", ProxyInfo.c_str(), authstatus[1]);
636  }
637  }
638  else
639  {
640  _error->Error("SOCKS proxy %s greets back having not found a common authorization method: %d", ProxyInfo.c_str(), greeting[1]);
642  }
643  union {
644  uint16_t *i;
645  uint8_t *b;
646  } portu;
647  uint16_t port = htons(static_cast<uint16_t>(Port));
648  portu.i = &port;
649  std::vector<uint8_t> request = {{0x05, 0x01, 0x00, 0x03, static_cast<uint8_t>(Host.length())}};
650  std::copy(Host.begin(), Host.end(), std::back_inserter(request));
651  request.push_back(portu.b[0]);
652  request.push_back(portu.b[1]);
653  APT_WriteOrFail("request", request.data(), request.size());
654  uint8_t response[4];
655  APT_ReadOrFail("first part of response", response, sizeof(response));
656  if (response[0] != 0x05)
657  {
658  _error->Error("SOCKS proxy %s response with wrong version: %d", ProxyInfo.c_str(), response[0]);
660  }
661  if (response[2] != 0x00)
662  {
663  _error->Error("SOCKS proxy %s has unexpected non-zero reserved field value: %d", ProxyInfo.c_str(), response[2]);
665  }
666  std::string bindaddr;
667  if (response[3] == 0x01) // IPv4 address
668  {
669  uint8_t ip4port[6];
670  APT_ReadOrFail("IPv4+Port of response", ip4port, sizeof(ip4port));
671  portu.b[0] = ip4port[4];
672  portu.b[1] = ip4port[5];
673  port = ntohs(*portu.i);
674  strprintf(bindaddr, "%d.%d.%d.%d:%d", ip4port[0], ip4port[1], ip4port[2], ip4port[3], port);
675  }
676  else if (response[3] == 0x03) // hostname
677  {
678  uint8_t namelength;
679  APT_ReadOrFail("hostname length of response", &namelength, 1);
680  uint8_t hostname[namelength + 2];
681  APT_ReadOrFail("hostname of response", hostname, sizeof(hostname));
682  portu.b[0] = hostname[namelength];
683  portu.b[1] = hostname[namelength + 1];
684  port = ntohs(*portu.i);
685  hostname[namelength] = '\0';
686  strprintf(bindaddr, "%s:%d", hostname, port);
687  }
688  else if (response[3] == 0x04) // IPv6 address
689  {
690  uint8_t ip6port[18];
691  APT_ReadOrFail("IPv6+port of response", ip6port, sizeof(ip6port));
692  portu.b[0] = ip6port[16];
693  portu.b[1] = ip6port[17];
694  port = ntohs(*portu.i);
695  strprintf(bindaddr, "[%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X]:%d",
696  ip6port[0], ip6port[1], ip6port[2], ip6port[3], ip6port[4], ip6port[5], ip6port[6], ip6port[7],
697  ip6port[8], ip6port[9], ip6port[10], ip6port[11], ip6port[12], ip6port[13], ip6port[14], ip6port[15],
698  port);
699  }
700  else
701  {
702  _error->Error("SOCKS proxy %s destination address is of unknown type: %d",
703  ProxyInfo.c_str(), response[3]);
705  }
706  if (response[1] != 0x00)
707  {
708  char const *errstr = nullptr;
709  auto errcode = response[1];
710  bool Transient = false;
711  // Tor error reporting can be a bit arcane, lets try to detect & fix it up
712  if (bindaddr == "0.0.0.0:0")
713  {
714  auto const lastdot = Host.rfind('.');
715  if (lastdot == std::string::npos || Host.substr(lastdot) != ".onion")
716  ;
717  else if (errcode == 0x01)
718  {
719  auto const prevdot = Host.rfind('.', lastdot - 1);
720  if (prevdot == std::string::npos && (lastdot == 16 || lastdot == 56))
721  ; // valid .onion address
722  else if (prevdot != std::string::npos && ((lastdot - prevdot) == 17 || (lastdot - prevdot) == 57))
723  ; // valid .onion address with subdomain(s)
724  else
725  {
726  errstr = "Invalid hostname: onion service name must be either 16 or 56 characters long";
727  Owner->SetFailReason("SOCKS");
728  }
729  }
730  // in all likelihood the service is either down or the address has
731  // a typo and so "Host unreachable" is the better understood error
732  // compared to the technically correct "TLL expired".
733  else if (errcode == 0x06)
734  errcode = 0x04;
735  }
736  if (errstr == nullptr)
737  {
738  switch (errcode)
739  {
740  case 0x01:
741  errstr = "general SOCKS server failure";
742  Owner->SetFailReason("SOCKS");
743  break;
744  case 0x02:
745  errstr = "connection not allowed by ruleset";
746  Owner->SetFailReason("SOCKS");
747  break;
748  case 0x03:
749  errstr = "Network unreachable";
750  Owner->SetFailReason("ConnectionTimedOut");
751  Transient = true;
752  break;
753  case 0x04:
754  errstr = "Host unreachable";
755  Owner->SetFailReason("ConnectionTimedOut");
756  Transient = true;
757  break;
758  case 0x05:
759  errstr = "Connection refused";
760  Owner->SetFailReason("ConnectionRefused");
761  Transient = true;
762  break;
763  case 0x06:
764  errstr = "TTL expired";
765  Owner->SetFailReason("Timeout");
766  Transient = true;
767  break;
768  case 0x07:
769  errstr = "Command not supported";
770  Owner->SetFailReason("SOCKS");
771  break;
772  case 0x08:
773  errstr = "Address type not supported";
774  Owner->SetFailReason("SOCKS");
775  break;
776  default:
777  errstr = "Unknown error";
778  Owner->SetFailReason("SOCKS");
779  break;
780  }
781  }
782  _error->Error("SOCKS proxy %s could not connect to %s (%s) due to: %s (%d)",
783  ProxyInfo.c_str(), Host.c_str(), bindaddr.c_str(), errstr, response[1]);
785  }
786  else if (Owner->DebugEnabled())
787  ioprintf(std::clog, "http: SOCKS proxy %s connection established to %s (%s)\n",
788  ProxyInfo.c_str(), Host.c_str(), bindaddr.c_str());
789 
790  if (WaitFd(Fd->Fd(), true, Timeout) == false)
791  {
792  _error->Error("SOCKS proxy %s reported connection to %s (%s), but timed out",
793  ProxyInfo.c_str(), Host.c_str(), bindaddr.c_str());
795  }
796 #undef APT_ReadOrFail
797 #undef APT_WriteOrFail
798 
800 }
801  /*}}}*/
802 // UnwrapTLS - Handle TLS connections /*{{{*/
803 // ---------------------------------------------------------------------
804 /* Performs a TLS handshake on the socket */
805 struct TlsFd : public MethodFd
806 {
807  std::unique_ptr<MethodFd> UnderlyingFd;
808  gnutls_session_t session;
809  gnutls_certificate_credentials_t credentials;
810  std::string hostname;
811  unsigned long Timeout;
812 
813  int Fd() APT_OVERRIDE { return UnderlyingFd->Fd(); }
814 
815  ssize_t Read(void *buf, size_t count) APT_OVERRIDE
816  {
817  return HandleError(gnutls_record_recv(session, buf, count));
818  }
819  ssize_t Write(void *buf, size_t count) APT_OVERRIDE
820  {
821  return HandleError(gnutls_record_send(session, buf, count));
822  }
823 
824  ssize_t DoTLSHandshake()
825  {
826  int err;
827  // Do the handshake. Our socket is non-blocking, so we need to call WaitFd()
828  // accordingly.
829  do
830  {
831  err = gnutls_handshake(session);
832  if ((err == GNUTLS_E_INTERRUPTED || err == GNUTLS_E_AGAIN) &&
833  WaitFd(this->Fd(), gnutls_record_get_direction(session) == 1, Timeout) == false)
834  {
835  _error->Errno("select", "Could not wait for server fd");
836  return err;
837  }
838  } while (err < 0 && gnutls_error_is_fatal(err) == 0);
839 
840  if (err < 0)
841  {
842  // Print reason why validation failed.
843  if (err == GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR)
844  {
845  gnutls_datum_t txt;
846  auto type = gnutls_certificate_type_get(session);
847  auto status = gnutls_session_get_verify_cert_status(session);
848  if (gnutls_certificate_verification_status_print(status, type, &txt, 0) == 0)
849  {
850  _error->Error("Certificate verification failed: %s", txt.data);
851  }
852  gnutls_free(txt.data);
853  }
854  _error->Error("Could not handshake: %s", gnutls_strerror(err));
855  }
856  return err;
857  }
858 
859  template <typename T>
860  T HandleError(T err)
861  {
862  // Server may request re-handshake if client certificates need to be provided
863  // based on resource requested
864  if (err == GNUTLS_E_REHANDSHAKE)
865  {
866  int rc = DoTLSHandshake();
867  // Only reset err if DoTLSHandshake() fails.
868  // Otherwise, we want to follow the original error path and set errno to EAGAIN
869  // so that the request is retried.
870  if (rc < 0)
871  err = rc;
872  }
873 
874  if (err < 0 && gnutls_error_is_fatal(err))
875  errno = EIO;
876  else if (err < 0)
877  errno = EAGAIN;
878  else
879  errno = 0;
880  return err;
881  }
882 
884  {
885  auto err = HandleError(gnutls_bye(session, GNUTLS_SHUT_RDWR));
886  auto lower = UnderlyingFd->Close();
887  return err < 0 ? HandleError(err) : lower;
888  }
889 
891  {
892  return gnutls_record_check_pending(session) > 0;
893  }
894 };
895 
896 ResultState UnwrapTLS(std::string const &Host, std::unique_ptr<MethodFd> &Fd,
897  unsigned long Timeout, aptMethod *Owner)
898 {
899  if (_config->FindB("Acquire::AllowTLS", true) == false)
900  {
901  _error->Error("TLS support has been disabled: Acquire::AllowTLS is false.");
903  }
904 
905  int err;
906  TlsFd *tlsFd = new TlsFd();
907 
908  tlsFd->hostname = Host;
909  tlsFd->UnderlyingFd = MethodFd::FromFd(-1); // For now
910  tlsFd->Timeout = Timeout;
911 
912  if ((err = gnutls_init(&tlsFd->session, GNUTLS_CLIENT | GNUTLS_NONBLOCK)) < 0)
913  {
914  _error->Error("Internal error: could not allocate credentials: %s", gnutls_strerror(err));
916  }
917 
918  FdFd *fdfd = dynamic_cast<FdFd *>(Fd.get());
919  if (fdfd != nullptr)
920  {
921  gnutls_transport_set_int(tlsFd->session, fdfd->fd);
922  }
923  else
924  {
925  gnutls_transport_set_ptr(tlsFd->session, Fd.get());
926  gnutls_transport_set_pull_function(tlsFd->session,
927  [](gnutls_transport_ptr_t p, void *buf, size_t size) -> ssize_t {
928  return reinterpret_cast<MethodFd *>(p)->Read(buf, size);
929  });
930  gnutls_transport_set_push_function(tlsFd->session,
931  [](gnutls_transport_ptr_t p, const void *buf, size_t size) -> ssize_t {
932  return reinterpret_cast<MethodFd *>(p)->Write((void *)buf, size);
933  });
934  }
935 
936  if ((err = gnutls_certificate_allocate_credentials(&tlsFd->credentials)) < 0)
937  {
938  _error->Error("Internal error: could not allocate credentials: %s", gnutls_strerror(err));
940  }
941 
942  // Credential setup
943  std::string fileinfo = Owner->ConfigFind("CaInfo", "");
944  if (fileinfo.empty())
945  {
946  // No CaInfo specified, use system trust store.
947  err = gnutls_certificate_set_x509_system_trust(tlsFd->credentials);
948  if (err == 0)
949  Owner->Warning("No system certificates available. Try installing ca-certificates.");
950  else if (err < 0)
951  {
952  _error->Error("Could not load system TLS certificates: %s", gnutls_strerror(err));
954  }
955  }
956  else
957  {
958  // CA location has been set, use the specified one instead
959  gnutls_certificate_set_verify_flags(tlsFd->credentials, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
960  err = gnutls_certificate_set_x509_trust_file(tlsFd->credentials, fileinfo.c_str(), GNUTLS_X509_FMT_PEM);
961  if (err < 0)
962  {
963  _error->Error("Could not load certificates from %s (CaInfo option): %s", fileinfo.c_str(), gnutls_strerror(err));
965  }
966  }
967 
968  if (!Owner->ConfigFind("IssuerCert", "").empty())
969  {
970  _error->Error("The option '%s' is not supported anymore", "IssuerCert");
972  }
973  if (!Owner->ConfigFind("SslForceVersion", "").empty())
974  {
975  _error->Error("The option '%s' is not supported anymore", "SslForceVersion");
977  }
978 
979  // For client authentication, certificate file ...
980  std::string const cert = Owner->ConfigFind("SslCert", "");
981  std::string const key = Owner->ConfigFind("SslKey", "");
982  if (cert.empty() == false)
983  {
984  if ((err = gnutls_certificate_set_x509_key_file(
985  tlsFd->credentials,
986  cert.c_str(),
987  key.empty() ? cert.c_str() : key.c_str(),
988  GNUTLS_X509_FMT_PEM)) < 0)
989  {
990  _error->Error("Could not load client certificate (%s, SslCert option) or key (%s, SslKey option): %s", cert.c_str(), key.c_str(), gnutls_strerror(err));
992  }
993  }
994 
995  // CRL file
996  std::string const crlfile = Owner->ConfigFind("CrlFile", "");
997  if (crlfile.empty() == false)
998  {
999  if ((err = gnutls_certificate_set_x509_crl_file(tlsFd->credentials,
1000  crlfile.c_str(),
1001  GNUTLS_X509_FMT_PEM)) < 0)
1002  {
1003  _error->Error("Could not load custom certificate revocation list %s (CrlFile option): %s", crlfile.c_str(), gnutls_strerror(err));
1004  return ResultState::FATAL_ERROR;
1005  }
1006  }
1007 
1008  if ((err = gnutls_credentials_set(tlsFd->session, GNUTLS_CRD_CERTIFICATE, tlsFd->credentials)) < 0)
1009  {
1010  _error->Error("Internal error: Could not add certificates to session: %s", gnutls_strerror(err));
1011  return ResultState::FATAL_ERROR;
1012  }
1013 
1014  if ((err = gnutls_set_default_priority(tlsFd->session)) < 0)
1015  {
1016  _error->Error("Internal error: Could not set algorithm preferences: %s", gnutls_strerror(err));
1017  return ResultState::FATAL_ERROR;
1018  }
1019 
1020  if (Owner->ConfigFindB("Verify-Peer", true))
1021  {
1022  gnutls_session_set_verify_cert(tlsFd->session, Owner->ConfigFindB("Verify-Host", true) ? tlsFd->hostname.c_str() : nullptr, 0);
1023  }
1024 
1025  // set SNI only if the hostname is really a name and not an address
1026  {
1027  struct in_addr addr4;
1028  struct in6_addr addr6;
1029 
1030  if (inet_pton(AF_INET, tlsFd->hostname.c_str(), &addr4) == 1 ||
1031  inet_pton(AF_INET6, tlsFd->hostname.c_str(), &addr6) == 1)
1032  /* not a host name */;
1033  else if ((err = gnutls_server_name_set(tlsFd->session, GNUTLS_NAME_DNS, tlsFd->hostname.c_str(), tlsFd->hostname.length())) < 0)
1034  {
1035  _error->Error("Could not set host name %s to indicate to server: %s", tlsFd->hostname.c_str(), gnutls_strerror(err));
1036  return ResultState::FATAL_ERROR;
1037  }
1038  }
1039 
1040  // Set the FD now, so closing it works reliably.
1041  tlsFd->UnderlyingFd = std::move(Fd);
1042  Fd.reset(tlsFd);
1043 
1044  // Do the handshake.
1045  err = tlsFd->DoTLSHandshake();
1046 
1047  if (err < 0)
1049 
1050  return ResultState::SUCCESSFUL;
1051 }
1052  /*}}}*/
strprintf(m, msg, repo.c_str())
ResultState
Definition: aptmethod.h:35
bool FindB(const char *Name, bool const &Default=false) const
bool Write(const void *From, unsigned long long Size)
Definition: fileutl.cc:2819
bool Read(void *To, unsigned long long Size, bool AllowEof)
Definition: fileutl.h:89
Definition: strutl.h:193
std::string User
Definition: strutl.h:199
std::string Password
Definition: strutl.h:200
static std::string SiteOnly(const std::string &URI)
Definition: strutl.cc:1788
void Warning(std::string &&msg)
Definition: aptmethod.h:387
std::string ConfigFind(char const *const postfix, std::string const &defValue) const APT_NONNULL(2)
Definition: aptmethod.h:425
bool DebugEnabled() const
Definition: aptmethod.h:409
bool ConfigFindB(char const *const postfix, bool const defValue) const APT_NONNULL(2)
Definition: aptmethod.h:441
int ConfigFindI(char const *const postfix, int const defValue) const APT_NONNULL(2)
Definition: aptmethod.h:445
void SetIP(std::string aIP)
void Status(const char *Format,...)
void SetFailReason(std::string Msg)
Configuration * _config
static bool ConnectionAllowed(char const *const Service, std::string const &Host)
Definition: connect.cc:69
static ResultState ConnectToHostname(std::string const &Host, int const Port, const char *const Service, int DefPort, std::unique_ptr< MethodFd > &Fd, unsigned long const TimeOut, aptMethod *const Owner)
Definition: connect.cc:346
static std::vector< struct addrinfo_emu * > OrderAddresses(struct addrinfo_emu *CurHost)
Definition: connect.cc:225
static std::vector< SrvRec > SrvRecords
Definition: connect.cc:52
static bool TalkToSocksProxy(int const ServerFd, std::string const &Proxy, char const *const type, bool const ReadWrite, uint8_t *const ToFrom, unsigned int const Size, unsigned int const Timeout)
Definition: connect.cc:545
static std::string LastService
Definition: connect.cc:48
ResultState UnwrapSocks(std::string Host, int Port, URI Proxy, std::unique_ptr< MethodFd > &Fd, unsigned long Timeout, aptMethod *Owner)
Definition: connect.cc:569
#define APT_ReadOrFail(TYPE, DATA, LENGTH)
static struct addrinfo_emu * LastHostAddr
Definition: connect.cc:49
static std::string LastHost
Definition: connect.cc:47
static struct addrinfo_emu * LastUsed
Definition: connect.cc:50
void RotateDNS()
Definition: connect.cc:61
static ResultState WaitAndCheckErrors(std::list< Connection > &Conns, std::unique_ptr< MethodFd > &Fd, long TimeoutMsec, bool ReportTimeout)
Definition: connect.cc:269
ResultState Connect(std::string Host, int Port, const char *Service, int DefPort, std::unique_ptr< MethodFd > &Fd, unsigned long TimeOut, aptMethod *Owner)
Definition: connect.cc:476
static std::set< std::string > bad_addr
Definition: connect.cc:55
ResultState UnwrapTLS(std::string const &Host, std::unique_ptr< MethodFd > &Fd, unsigned long Timeout, aptMethod *Owner)
Definition: connect.cc:896
#define APT_WriteOrFail(TYPE, DATA, LENGTH)
void SetNonBlock(int Fd, bool Block)
Definition: fileutl.cc:804
bool WaitFd(int Fd, bool write, unsigned long timeout)
Definition: fileutl.cc:819
unsigned long TimeOut
Definition: ftp.cc:65
URI Proxy
Definition: ftp.cc:66
#define APT_OVERRIDE
Definition: macros.h:111
bool Endswith(const std::string &s, const std::string &end)
Definition: strutl.cc:77
int getaddrinfo(const char *nodename, const char *servname, const struct addrinfo_emu *hints, struct addrinfo_emu **res)
Definition: rfc2553emu.cc:29
int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags)
Definition: rfc2553emu.cc:170
void freeaddrinfo(struct addrinfo_emu *ai)
Definition: rfc2553emu.cc:154
#define EAI_NONAME
Definition: rfc2553emu.h:64
#define NI_NUMERICHOST
Definition: rfc2553emu.h:97
#define EAI_AGAIN
Definition: rfc2553emu.h:65
#define EAI_SYSTEM
Definition: rfc2553emu.h:72
#define EAI_SERVICE
Definition: rfc2553emu.h:70
#define NI_MAXHOST
Definition: rfc2553emu.h:92
#define NI_MAXSERV
Definition: rfc2553emu.h:93
#define addrinfo
Definition: rfc2553emu.h:52
#define NI_NUMERICSERV
Definition: rfc2553emu.h:98
bool GetSrvRecords(std::string host, int port, std::vector< SrvRec > &Result)
Get SRV records for query string like: _http._tcp.example.com.
Definition: srvrec.cc:35
SrvRec PopFromSrvRecs(std::vector< SrvRec > &Recs)
Pop a single SRV record from the vector of SrvRec taking priority and weight into account.
Definition: srvrec.cc:150
aptMethod * Owner
Definition: connect.cc:120
std::unique_ptr< FdFd > Fd
Definition: connect.cc:121
Connection(Connection &&Conn)=default
char Name[1025]
Definition: connect.cc:122
~Connection()
Definition: connect.cc:135
ResultState CheckError()
Definition: connect.cc:195
std::string Host
Definition: connect.cc:119
ResultState DoConnect()
Definition: connect.cc:162
Connection & operator=(Connection &&Conn)=default
Connection(struct addrinfo_emu *Addr, std::string const &Host, aptMethod *Owner)
Definition: connect.cc:125
std::unique_ptr< MethodFd > Take()
Definition: connect.cc:143
Connection(const Connection &Conn)=delete
struct addrinfo_emu * Addr
Definition: connect.cc:118
Connection & operator=(const Connection &)=delete
char Service[32]
Definition: connect.cc:123
Definition: connect.cc:87
ssize_t Write(void *buf, size_t count) APT_OVERRIDE
Should behave like write(2)
Definition: connect.cc:91
int Fd() APT_OVERRIDE
Returns -1 for unusable, or an fd to select() on otherwise.
Definition: connect.cc:89
int fd
Definition: connect.cc:88
int Close() APT_OVERRIDE
Closes the file descriptor. Can be called multiple times.
Definition: connect.cc:92
ssize_t Read(void *buf, size_t count) APT_OVERRIDE
Should behave like read(2)
Definition: connect.cc:90
Small representation of a file descriptor for network traffic.
Definition: connect.h:24
virtual bool HasPending()
If there is pending data.
Definition: connect.cc:102
static std::unique_ptr< MethodFd > FromFd(int iFd)
Construct a MethodFd from a UNIX file descriptor.
Definition: connect.cc:106
ssize_t DoTLSHandshake()
Definition: connect.cc:824
ssize_t Write(void *buf, size_t count) APT_OVERRIDE
Should behave like write(2)
Definition: connect.cc:819
gnutls_session_t session
Definition: connect.cc:808
int Fd() APT_OVERRIDE
Returns -1 for unusable, or an fd to select() on otherwise.
Definition: connect.cc:813
int Close() APT_OVERRIDE
Closes the file descriptor. Can be called multiple times.
Definition: connect.cc:883
bool HasPending() APT_OVERRIDE
If there is pending data.
Definition: connect.cc:890
std::unique_ptr< MethodFd > UnderlyingFd
Definition: connect.cc:807
T HandleError(T err)
Definition: connect.cc:860
unsigned long Timeout
Definition: connect.cc:811
std::string hostname
Definition: connect.cc:810
ssize_t Read(void *buf, size_t count) APT_OVERRIDE
Should behave like read(2)
Definition: connect.cc:815
gnutls_certificate_credentials_t credentials
Definition: connect.cc:809
struct sockaddr * ai_addr
Definition: rfc2553emu.h:49
int ai_socktype
Definition: rfc2553emu.h:45
int ai_protocol
Definition: rfc2553emu.h:46
size_t ai_addrlen
Definition: rfc2553emu.h:47
struct addrinfo_emu * ai_next
Definition: rfc2553emu.h:50
void ioprintf(ostream &out, const char *format,...)
Definition: strutl.cc:1433