CernVM-FS  2.12.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 "network/download.h"
18 #include "pacparser.h"
19 #include "statistics.h"
20 #include "util/logging.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  cvmfs::MemSink pac_memsink;
177  download::JobInfo download_pac(&pac_paths[i], false, false, NULL,
178  &pac_memsink);
179  int retval = download_manager->Fetch(&download_pac);
180  if (retval == download::kFailOk) {
181  string proxies;
182  retval = ParsePac(reinterpret_cast<char*>(pac_memsink.data()),
183  pac_memsink.pos(),
184  download_manager,
185  &proxies);
186  if (!retval) {
188  "failed to parse pac file %s", pac_paths[i].c_str());
189  } else {
190  if (proxies != "") {
191  LogCvmfs(kLogDownload, kLogDebug | kLogSyslog, "CernVM-FS: "
192  "using HTTP proxy server(s) %s from pac file %s",
193  proxies.c_str(), pac_paths[i].c_str());
194  return proxies;
195  }
196  }
197 
198  LogCvmfs(kLogDownload, kLogDebug, "no proxy settings found in %s",
199  pac_paths[i].c_str());
200  }
201  }
202 
203  return "";
204 }
205 
206 
208  const string &cvmfs_proxies,
209  const std::string &path_fallback_cache,
210  DownloadManager *download_manager)
211 {
212  if ((cvmfs_proxies == "") || (cvmfs_proxies.find("auto") == string::npos))
213  return cvmfs_proxies;
214 
215  int empty_auto = -1;
216  vector<string> lb_groups = SplitString(cvmfs_proxies, ';');
217  for (unsigned i = 0; i < lb_groups.size(); ++i) {
218  if (lb_groups[i] != "auto")
219  continue;
220 
221  lb_groups[i] = AutoProxy(download_manager);
222  if (lb_groups[i].empty())
223  empty_auto = static_cast<int>(i);
224  }
225 
226  if (empty_auto != -1)
227  lb_groups.erase(lb_groups.begin()+static_cast<unsigned>(empty_auto));
228  string discovered_proxies = JoinStrings(lb_groups, ";");
229 
230  if (!path_fallback_cache.empty()) {
231  if (empty_auto != -1) {
232  string cached_proxies;
233  int fd = open(path_fallback_cache.c_str(), O_RDONLY);
234  if (fd >= 0) {
235  bool retval = SafeReadToString(fd, &cached_proxies);
236  close(fd);
237  if (retval) {
239  "using cached proxy settings from %s",
240  path_fallback_cache.c_str());
241  return cached_proxies;
242  }
243  }
244  } else {
245  bool retval =
246  SafeWriteToFile(discovered_proxies, path_fallback_cache, 0660);
247  if (!retval) {
249  "failed to write proxy settings into %s",
250  path_fallback_cache.c_str());
251  }
252  }
253  }
254 
255  return discovered_proxies;
256 }
257 
258 
259 static void AltCvmfsLogger(const LogSource source, const int mask,
260  const char *msg)
261 {
262  FILE *log_output = NULL;
263  if (mask & kLogStdout)
264  log_output = stdout;
265  else if (mask & kLogStderr || mask & kLogSyslogWarn || mask & kLogSyslogErr)
266  log_output = stderr;
267  if (log_output)
268  fprintf(log_output, "%s\n", msg);
269 }
270 
271 
272 int MainResolveProxyDescription(int argc, char **argv) {
274  if (argc < 4) {
275  LogCvmfs(kLogDownload, kLogStderr, "arguments missing");
276  return 1;
277  }
278  perf::Statistics statistics;
279  string proxy_configuration = argv[2];
280  string host_list = argv[3];
281 
282  DownloadManager download_manager(1,
283  perf::StatisticsTemplate("pac", &statistics));
284  download_manager.SetHostChain(host_list);
285  string resolved_proxies = ResolveProxyDescription(proxy_configuration, "",
286  &download_manager);
287 
288  LogCvmfs(kLogDownload, kLogStdout, "%s", resolved_proxies.c_str());
289  return resolved_proxies == "";
290 }
291 
292 } // namespace download
void SetHostChain(const std::string &host_list)
unsigned char * data()
Definition: sink_mem.h:122
string JoinStrings(const vector< string > &strings, const string &joint)
Definition: string.cc:325
int MainResolveProxyDescription(int argc, char **argv)
Definition: wpad.cc:272
assert((mem||(size==0))&&"Out Of Memory")
bool SafeWriteToFile(const std::string &content, const std::string &path, int mode)
Definition: posix.cc:2084
void SetAltLogFunc(void(*fn)(const LogSource source, const int mask, const char *msg))
Definition: logging.cc:408
vector< string > SplitString(const string &str, char delim)
Definition: string.cc:290
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:259
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:267
bool SafeReadToString(int fd, std::string *final_result)
Definition: posix.cc:2068
const char * kAutoPacLocation
Definition: wpad.cc:28
size_t pos()
Definition: sink_mem.h:121
string ResolveProxyDescription(const string &cvmfs_proxies, const std::string &path_fallback_cache, DownloadManager *download_manager)
Definition: wpad.cc:207
Failures Fetch(JobInfo *info)
Definition: download.cc:1834
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
const int mask
Definition: logging.h:23
void GetHostInfo(std::vector< std::string > *host_chain, std::vector< int > *rtt, unsigned *current_host)
Definition: download.cc:2082
static void size_t size
Definition: smalloc.h:54
static string PacProxy2Cvmfs(const string &pac_proxy, const bool report_errors)
Definition: wpad.cc:42
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:528