CernVM-FS  2.9.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
wpad.cc
Go to the documentation of this file.
1 
5 #include "cvmfs_config.h"
6 #include "wpad.h"
7 
8 #include <fcntl.h>
9 
10 #include <cstdarg>
11 #include <cstdio>
12 #include <cstdlib>
13 
14 #include <string>
15 #include <vector>
16 
17 #include "download.h"
18 #include "logging.h"
19 #include "pacparser.h"
20 #include "statistics.h"
21 #include "util/posix.h"
22 #include "util/string.h"
23 
24 using namespace std; // NOLINT
25 
26 namespace download {
27 
28 const char *kAutoPacLocation = "http://wpad/wpad.dat";
29 
30 static int PrintPacError(const char *fmt, va_list argp) {
31  char *msg = NULL;
32 
33  int retval = vasprintf(&msg, fmt, argp);
34  assert(retval != -1); // else: out of memory
35 
36  LogCvmfs(kLogDownload, kLogDebug | kLogSyslogErr, "(pacparser) %s", msg);
37  free(msg);
38  return retval;
39 }
40 
41 
42 static string PacProxy2Cvmfs(const string &pac_proxy,
43  const bool report_errors)
44 {
45  int log_flags = report_errors ? kLogDebug | kLogSyslogWarn : kLogDebug;
46  if (pac_proxy == "")
47  return "DIRECT";
48 
49  string cvmfs_proxy;
50  vector<string> components = SplitString(pac_proxy, ';');
51  for (unsigned i = 0; i < components.size(); ++i) {
52  // Remove white spaces
53  string next_proxy;
54  for (unsigned j = 0; j < components[i].length(); ++j) {
55  if ((components[i][j] != ' ') && (components[i][j] != '\t'))
56  next_proxy.push_back(components[i][j]);
57  }
58 
59  // No SOCKS support
60  if (HasPrefix(next_proxy, "SOCKS", false)) {
61  LogCvmfs(kLogDownload, log_flags,
62  "no support for SOCKS proxy, skipping %s",
63  next_proxy.substr(5).c_str());
64  continue;
65  }
66 
67  if ((next_proxy != "DIRECT") &&
68  !HasPrefix(next_proxy, "PROXY", false))
69  {
70  LogCvmfs(kLogDownload, log_flags, "invalid proxy definition: %s",
71  next_proxy.c_str());
72  continue;
73  }
74 
75  if (HasPrefix(next_proxy, "PROXY", false))
76  next_proxy = next_proxy.substr(5);
77 
78  if (cvmfs_proxy == "")
79  cvmfs_proxy = next_proxy;
80  else
81  cvmfs_proxy += ";" + next_proxy;
82  }
83 
84  return cvmfs_proxy;
85 }
86 
87 
88 static bool ParsePac(const char *pac_data, const size_t size,
89  DownloadManager *download_manager,
90  string *proxies)
91 {
92  *proxies = "";
93 
94  pacparser_set_error_printer(PrintPacError);
95  bool retval = pacparser_init();
96  if (!retval)
97  return false;
98 
99  const string pac_string(pac_data, size);
100  LogCvmfs(kLogDownload, kLogDebug, "PAC script is:\n%s", pac_string.c_str());
101  retval = pacparser_parse_pac_string(pac_string.c_str());
102  if (!retval) {
103  pacparser_cleanup();
104  return false;
105  }
106 
107  // For every stratum 1: get proxy
108  vector<string> host_list;
109  vector<int> rtt;
110  unsigned current_host;
111  download_manager->GetHostInfo(&host_list, &rtt, &current_host);
112  for (unsigned i = 0; i < host_list.size(); ++i) {
113  size_t hostname_begin = 7; // Strip http:// or file://
114  size_t hostname_end = host_list[i].find_first_of(":/", hostname_begin);
115  size_t hostname_len =
116  (hostname_end == string::npos) ?
117  string::npos : hostname_end-hostname_begin;
118  const string hostname = (hostname_begin > host_list[i].length()) ?
119  "localhost" : host_list[i].substr(hostname_begin, hostname_len);
120  const string url = host_list[i] + "/.cvmfspublished";
121 
122  // pac_proxy is freed by JavaScript GC
123  char *pac_proxy = pacparser_find_proxy(url.c_str(), hostname.c_str());
124  if (pac_proxy == NULL) {
125  pacparser_cleanup();
126  return false;
127  }
128  if (*proxies == "") {
129  *proxies = PacProxy2Cvmfs(pac_proxy, true);
130  if (*proxies == "") {
132  "no valid proxy found (%s returned from pac file)", pac_proxy);
133  pacparser_cleanup();
134  return false;
135  }
136  } else {
137  const string alt_proxies = PacProxy2Cvmfs(pac_proxy, false);
138  if (*proxies != alt_proxies) {
140  "proxy settings for host %s differ from proxy settings for "
141  "other hosts (%s / %s). Not using proxy setting %s.",
142  host_list[i].c_str(), proxies->c_str(), alt_proxies.c_str(),
143  alt_proxies.c_str());
144  }
145  }
146  }
147 
148  pacparser_cleanup();
149  return true;
150 }
151 
152 
153 string AutoProxy(DownloadManager *download_manager) {
154  char *http_env = getenv("http_proxy");
155  if (http_env) {
156  LogCvmfs(kLogDownload, kLogDebug | kLogSyslog, "CernVM-FS: "
157  "using HTTP proxy server(s) %s from http_proxy environment",
158  http_env);
159  return string(http_env);
160  }
161 
162  vector<string> pac_paths;
163  char *pac_env = getenv("CVMFS_PAC_URLS");
164  if (pac_env != NULL)
165  pac_paths = SplitString(pac_env, ';');
166 
167  // Try downloading from each of the PAC URLs
168  for (unsigned i = 0; i < pac_paths.size(); ++i) {
169  if (pac_paths[i] == "auto") {
170  LogCvmfs(kLogDownload, kLogDebug, "resolving auto proxy config to %s",
172  pac_paths[i] = string(kAutoPacLocation);
173  }
174  LogCvmfs(kLogDownload, kLogDebug, "looking for proxy config at %s",
175  pac_paths[i].c_str());
176  download::JobInfo download_pac(&pac_paths[i], false, false, NULL);
177  int retval = download_manager->Fetch(&download_pac);
178  if (retval == download::kFailOk) {
179  string proxies;
180  retval = ParsePac(download_pac.destination_mem.data,
181  download_pac.destination_mem.pos,
182  download_manager,
183  &proxies);
184  free(download_pac.destination_mem.data);
185  if (!retval) {
187  "failed to parse pac file %s", pac_paths[i].c_str());
188  } else {
189  if (proxies != "") {
190  LogCvmfs(kLogDownload, kLogDebug | kLogSyslog, "CernVM-FS: "
191  "using HTTP proxy server(s) %s from pac file %s",
192  proxies.c_str(), pac_paths[i].c_str());
193  return proxies;
194  }
195  }
196 
197  LogCvmfs(kLogDownload, kLogDebug, "no proxy settings found in %s",
198  pac_paths[i].c_str());
199  }
200  }
201 
202  return "";
203 }
204 
205 
207  const string &cvmfs_proxies,
208  const std::string &path_fallback_cache,
209  DownloadManager *download_manager)
210 {
211  if ((cvmfs_proxies == "") || (cvmfs_proxies.find("auto") == string::npos))
212  return cvmfs_proxies;
213 
214  int empty_auto = -1;
215  vector<string> lb_groups = SplitString(cvmfs_proxies, ';');
216  for (unsigned i = 0; i < lb_groups.size(); ++i) {
217  if (lb_groups[i] != "auto")
218  continue;
219 
220  lb_groups[i] = AutoProxy(download_manager);
221  if (lb_groups[i].empty())
222  empty_auto = static_cast<int>(i);
223  }
224 
225  if (empty_auto != -1)
226  lb_groups.erase(lb_groups.begin()+static_cast<unsigned>(empty_auto));
227  string discovered_proxies = JoinStrings(lb_groups, ";");
228 
229  if (!path_fallback_cache.empty()) {
230  if (empty_auto != -1) {
231  string cached_proxies;
232  int fd = open(path_fallback_cache.c_str(), O_RDONLY);
233  if (fd >= 0) {
234  bool retval = SafeReadToString(fd, &cached_proxies);
235  close(fd);
236  if (retval) {
238  "using cached proxy settings from %s",
239  path_fallback_cache.c_str());
240  return cached_proxies;
241  }
242  }
243  } else {
244  bool retval =
245  SafeWriteToFile(discovered_proxies, path_fallback_cache, 0660);
246  if (!retval) {
248  "failed to write proxy settings into %s",
249  path_fallback_cache.c_str());
250  }
251  }
252  }
253 
254  return discovered_proxies;
255 }
256 
257 
258 static void AltCvmfsLogger(const LogSource source, const int mask,
259  const char *msg)
260 {
261  FILE *log_output = NULL;
262  if (mask & kLogStdout)
263  log_output = stdout;
264  else if (mask & kLogStderr || mask & kLogSyslogWarn || mask & kLogSyslogErr)
265  log_output = stderr;
266  if (log_output)
267  fprintf(log_output, "%s\n", msg);
268 }
269 
270 
271 int MainResolveProxyDescription(int argc, char **argv) {
273  if (argc < 4) {
274  LogCvmfs(kLogDownload, kLogStderr, "arguments missing");
275  return 1;
276  }
277  perf::Statistics statistics;
278  string proxy_configuration = argv[2];
279  string host_list = argv[3];
280 
281  DownloadManager download_manager;
282  download_manager.Init(1, false, perf::StatisticsTemplate("pac", &statistics));
283  download_manager.SetHostChain(host_list);
284  string resolved_proxies = ResolveProxyDescription(proxy_configuration, "",
285  &download_manager);
286  download_manager.Fini();
287 
288  LogCvmfs(kLogDownload, kLogStdout, "%s", resolved_proxies.c_str());
289  return resolved_proxies == "";
290 }
291 
292 } // namespace download
#define LogCvmfs(source, mask,...)
Definition: logging.h:20
void SetHostChain(const std::string &host_list)
vector< string > SplitString(const string &str, const char delim, const unsigned max_chunks)
Definition: string.cc:288
string JoinStrings(const vector< string > &strings, const string &joint)
Definition: string.cc:318
int MainResolveProxyDescription(int argc, char **argv)
Definition: wpad.cc:271
assert((mem||(size==0))&&"Out Of Memory")
bool SafeWriteToFile(const std::string &content, const std::string &path, int mode)
Definition: posix.cc:2022
void SetAltLogFunc(void(*fn)(const LogSource source, const int mask, const char *msg))
Definition: logging.cc:350
string AutoProxy(DownloadManager *download_manager)
Definition: wpad.cc:153
LogSource
static void AltCvmfsLogger(const LogSource source, const int mask, const char *msg)
Definition: wpad.cc:258
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:265
bool SafeReadToString(int fd, std::string *final_result)
Definition: posix.cc:2006
const char * kAutoPacLocation
Definition: wpad.cc:28
string ResolveProxyDescription(const string &cvmfs_proxies, const std::string &path_fallback_cache, DownloadManager *download_manager)
Definition: wpad.cc:206
Failures Fetch(JobInfo *info)
Definition: download.cc:1719
struct download::JobInfo::@3 destination_mem
static bool ParsePac(const char *pac_data, const size_t size, DownloadManager *download_manager, string *proxies)
Definition: wpad.cc:88
static int PrintPacError(const char *fmt, va_list argp)
Definition: wpad.cc:30
void Init(const unsigned max_pool_handles, const bool use_system_proxy, perf::StatisticsTemplate statistics)
Definition: download.cc:1594
void GetHostInfo(std::vector< std::string > *host_chain, std::vector< int > *rtt, unsigned *current_host)
Definition: download.cc:1939
static void size_t size
Definition: smalloc.h:47
static string PacProxy2Cvmfs(const string &pac_proxy, const bool report_errors)
Definition: wpad.cc:42