libzypp  17.37.18
proxyinfolibproxy.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
13 #include <zypp-core/AutoDispose.h>
14 #include <iostream>
15 #include <optional>
16 #include <cstdlib>
17 
18 #include <zypp-core/base/Logger.h>
19 #include <zypp-core/base/String.h>
20 #include <zypp-core/fs/WatchFile>
21 #include <zypp-core/Pathname.h>
22 #include <zypp-core/base/Env.h>
23 
24 #include <zypp-curl/proxyinfo/ProxyInfoLibproxy>
25 
26 #include <dlfcn.h> // for dlload, dlsym, dlclose
27 #include <glib.h> // g_clear_pointer and g_strfreev
28 
29 using std::endl;
30 using namespace zypp::base;
31 
32 namespace zypp {
33  namespace env {
34  inline bool inYAST()
35  {
36  static const bool _inYAST { static_cast<bool>(::getenv("YAST_IS_RUNNING")) };
37  return _inYAST;
38  }
39 
40  inline bool PX_DEBUG()
41  {
42  static const bool _pxdebug { env::getenvBool("PX_DEBUG") };
43  return _pxdebug;
44  }
45  }
46 
47  namespace media {
48 
49  namespace {
50 
51  using CreateFactoryCb = CreateFactorySig<pxProxyFactoryType>;
52  using DelFactoryCb = DelFactorySig<pxProxyFactoryType>;
53  using GetProxiesCb = GetProxiesSig<pxProxyFactoryType>;
54 
55  struct LibProxyAPI
56  {
58  CreateFactoryCb createProxyFactory = nullptr;
59  DelFactoryCb deleteProxyFactory = nullptr;
60  GetProxiesCb getProxies = nullptr;
62 
68  static void fallbackFreeProxies( char **proxies ) {
69  g_clear_pointer (&proxies, g_strfreev);
70  }
71 
72  static std::unique_ptr<LibProxyAPI> create() {
73  MIL << "Detecting libproxy availability" << std::endl;
74  zypp::AutoDispose<void *> handle( dlopen("libproxy.so.1", RTLD_LAZY ), []( void *ptr ){ if ( ptr ) ::dlclose(ptr); });
75  if ( !handle ) {
76  MIL << "No libproxy support detected (could not load library): " << dlerror() << std::endl;
77  return nullptr;
78  }
79 
80  std::unique_ptr<LibProxyAPI> apiInstance = std::make_unique<LibProxyAPI>();
81  apiInstance->libProxyLibHandle = std::move(handle);
82  apiInstance->createProxyFactory = (CreateFactoryCb)::dlsym ( apiInstance->libProxyLibHandle, "px_proxy_factory_new" );
83  if ( !apiInstance->createProxyFactory ){
84  ERR << "Incompatible libproxy detected (could not resolve px_proxy_factory_new): " << dlerror() << std::endl;
85  return nullptr;
86  }
87  apiInstance->deleteProxyFactory = (DelFactoryCb)::dlsym ( apiInstance->libProxyLibHandle, "px_proxy_factory_free" );
88  if ( !apiInstance->deleteProxyFactory ){
89  ERR << "Incompatible libproxy detected (could not resolve px_proxy_factory_free): " << dlerror() << std::endl;
90  return nullptr;
91  }
92  apiInstance->getProxies = (GetProxiesCb)::dlsym ( apiInstance->libProxyLibHandle, "px_proxy_factory_get_proxies" );
93  if ( !apiInstance->getProxies ){
94  ERR << "Incompatible libproxy detected (could not resolve px_proxy_factory_get_proxies): " << dlerror() << std::endl;
95  return nullptr;
96  }
97  apiInstance->freeProxies = (FreeProxiesCb)::dlsym ( apiInstance->libProxyLibHandle, "px_proxy_factory_free_proxies" );
98  if ( !apiInstance->freeProxies ){
99  MIL << "Older version of libproxy detected, using fallback function to free the proxy list (could not resolve px_proxy_factory_free_proxies): " << dlerror() << std::endl;
100  apiInstance->freeProxies = &fallbackFreeProxies;
101  }
102 
103  MIL << "Libproxy is available" << std::endl;
104  return apiInstance;
105  }
106  };
107 
108  LibProxyAPI *proxyApi() {
109  static std::unique_ptr<LibProxyAPI> api = LibProxyAPI::create();
110  return api.get();
111  }
112 
113  LibProxyAPI &assertProxyApi() {
114  auto api = proxyApi();
115  if ( !api )
116  ZYPP_THROW( zypp::Exception("LibProxyAPI is not available.") );
117  return *api;
118  }
119  }
120 
121  struct TmpUnsetEnv : private env::ScopedSet
122  {
123  TmpUnsetEnv( const char * var_r )
124  : env::ScopedSet( var_r, nullptr )
125  {}
126  };
127 
129  {
130  static pxProxyFactoryType * proxyFactory = 0;
131 
132  // Force libproxy into using "/etc/sysconfig/proxy"
133  // if it exists.
134  static WatchFile sysconfigProxy( "/etc/sysconfig/proxy", WatchFile::NO_INIT );
135  if ( sysconfigProxy.hasChanged() )
136  {
137  MIL << "Build Libproxy Factory from /etc/sysconfig/proxy" << endl;
138  if ( proxyFactory )
139  assertProxyApi().deleteProxyFactory( proxyFactory );
140 
141  TmpUnsetEnv envguard[] __attribute__ ((__unused__)) = { "KDE_FULL_SESSION", "GNOME_DESKTOP_SESSION_ID", "DESKTOP_SESSION" };
142  proxyFactory = assertProxyApi().createProxyFactory();
143  }
144  else if ( ! proxyFactory )
145  {
146  MIL << "Build Libproxy Factory" << endl;
147  proxyFactory = assertProxyApi().createProxyFactory();
148  }
149 
150  return proxyFactory;
151  }
152 
153  ProxyInfoLibproxy::ProxyInfoLibproxy()
154  : ProxyInfo::Impl()
155  , _factory( getProxyFactory())
156  {
157  _enabled = !(_factory == NULL);
158  }
159 
161  {}
162 
164  {
165  return ( proxyApi () != nullptr );
166  }
167 
168  std::string ProxyInfoLibproxy::proxy(const Url & url_r) const
169  {
170  if (!_enabled)
171  return "";
172 
173  const url::ViewOption vopt =
174  url::ViewOption::WITH_SCHEME
175  + url::ViewOption::WITH_HOST
176  + url::ViewOption::WITH_PORT
177  + url::ViewOption::WITH_PATH_NAME;
178 
179  auto &api = assertProxyApi ();
180 
182  api.getProxies(_factory, url_r.asString(vopt).c_str())
183  , api.freeProxies
184  );
185  if ( !proxies.value() )
186  return "";
187 
188  // bsc#1244710: libproxy appears to return /etc/sysconfig/proxy
189  // values after $*_proxy environment variables.
190  // In YAST, e.g after changing the proxy settings, we'd like
191  // /etc/sysconfig/proxy changes to take effect immediately.
192  // So we pick the last proxy accessible via http/https.
193  // (sorts out direct:// or other directives returned by libproxy)
194  std::optional<std::string> result;
195  for ( int i = 0; proxies[i]; ++i ) {
196  if ( str::hasPrefix( proxies[i], "http" ) ) { // Filter for http/https
197  result = str::asString( proxies[i] );
198  if ( not env::inYAST() )
199  break;
200  }
201  }
202 
203  if ( env::PX_DEBUG() ) {
204  L_DBG("PX_DEBUG") << "Url " << url_r << endl;
205  for ( int i = 0; proxies[i]; ++i ) {
206  L_DBG("PX_DEBUG") << "got " << proxies[i] << endl;
207  }
208  L_DBG("PX_DEBUG") << "--> " << result.value_or( "" ) << endl;
209  }
210 
211  return result.value_or( "" );
212  }
213 
215  { return _no_proxy.begin(); }
216 
218  { return _no_proxy.end(); }
219 
220  } // namespace media
221 } // namespace zypp
#define MIL
Definition: Logger.h:100
std::string proxy(const Url &url_r) const override
Namespace intended to collect all environment variables we use.
Definition: Env.h:24
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:459
bool hasChanged()
Definition: watchfile.h:80
FreeProxiesCb freeProxies
std::list< std::string >::const_iterator NoProxyIterator
Definition: proxyinfo.h:35
GetProxiesCb getProxies
const std::string & asString(const std::string &t)
Global asString() that works with std::string too.
Definition: String.h:140
Url::asString() view options.
Definition: UrlBase.h:40
#define ERR
Definition: Logger.h:102
Remember a files attributes to detect content changes.
Definition: watchfile.h:49
Temporarily set/unset an environment variable.
Definition: Env.h:44
std::string asString() const
Returns a default string representation of the Url object.
Definition: Url.cc:515
zypp::AutoDispose< void * > libProxyLibHandle
TriBool getenvBool(const C_Str &var_r)
If the environment variable var_r is set to a legal true or false string return bool, else indeterminate.
Definition: Env.h:32
DefaultIntegral< bool, false > _enabled
static pxProxyFactoryType * getProxyFactory()
DelFactoryCb deleteProxyFactory
ProxyInfo::NoProxyList _no_proxy
ProxyInfo::NoProxyIterator noProxyEnd() const override
struct _pxProxyFactory pxProxyFactoryType
#define L_DBG(GROUP)
Definition: Logger.h:108
TmpUnsetEnv(const char *var_r)
struct zypp::media::MediaBlock __attribute__
Base class for Exception.
Definition: Exception.h:152
reference value() const
Reference to the Tp object.
Definition: AutoDispose.h:138
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition: AutoDispose.h:94
ProxyInfo::NoProxyIterator noProxyBegin() const override
CreateFactoryCb createProxyFactory
void(*)(char **proxies) FreeProxiesCb
bool hasPrefix(const C_Str &str_r, const C_Str &prefix_r)
Return whether str_r has prefix prefix_r.
Definition: String.h:1098
Url manipulation class.
Definition: Url.h:92