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