4

I would like to ask the same question as this one: Proxy that can use a pac file as parent proxy. It's 11 years later now, and there is no accepted answer on that question, so I'm hoping there are better answers.

Here is the content of that other question:

I want to setup a caching proxy that will use a pac (proxy autoconfiguration) file as parent proxy (lookup in a pac proxy file to choose which parent proxy to use). I want to know if anyone knows a proxy server that supports this.

The goal is to be able to use applications that doesn't support pac files with the pac file I normally use.

Related questions:

In my attempts to finding a solution I have found the following:

There are packages to work with PAC files

There have been discussions/attempts to integrate this into proxy servers:

Does anyone have a working solution? Thank you

1 Answer 1

2

Alpaca can do that.

The idea is to run alpaca as a local proxy. Alpaca will fetch the pac file from the network (or use a specified one), as well as your NT credentials. Other programs will use the local proxy and be transparently forwarded to the upstream proxy or a direct connection, as instructed by alpaca.

Running the Alpaca proxy

You will want alpaca to run in the background. Either start it manually, or create a service file to do so. The alpaca-proxy AUR package contains a systemd user unit file, for instance.

Local pac file, no auth

alpaca -C "file:///home/username/proxy.pac.js"

An example pac file is provided at the bottom of this answer.

Configuration in environment, NTLM proxy authentication

$ export LISTEN_ADDRESS=localhost
$ export LISTEN_PORT=3128
$ export NTLM_CREDENTIALS="myusername@MYDOMAIN:00000000000000000000000000000000"
$ export PAC_URL="http://some.url/to/some-file.pac"

$ alpaca
Found credentials for MYDOMAIN\me in environment
pacfetcher.go:100: Attempting to download PAC from http://some.url/to/some-file.pac
main.go:115: Listening on tcp4 localhost:3128
main.go:115: Listening on tcp6 localhost:3128
proxyfinder.go:135: [1] GET http://google.com/ via "PROXY 11.12.13.14:80"

NTLM credentials can be obtained from alpaca:

$ alpaca -d MYDOMAIN -u myusername -H

Using the proxy

Once the proxy is running, instruct programs to use the proxy on the local host.

Explicit proxy configuration

You can do a quick test by instructing a given program to use the proxy. As supported by curl:

curl --proxy "http://127.0.0.1:3128" https://ipinfo.io/ip

Environment variables

Most programs support the lowercase http(s)_proxy environment variable (some programs require them to be upercase, so we use both).

$ export http_proxy='http://localhost:3128'                                                                                                                           
$ export https_proxy="$http_proxy" HTTPS_PROXY="$http_proxy" HTTP_PROXY="$http_proxy"

$ curl google.com
curl -v google.com
* Uses proxy env variable http_proxy == 'http://localhost:3128'
* Host localhost:3128 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:3128...
* Established connection to localhost (::1 port 3128) from ::1 port 58512 
* using HTTP/1.x
> GET http://google.com/ HTTP/1.1
[...]

Example pac file:

// ES5 syntax only https://github.com/robertkrimen/otto#caveat-emptor

var blocked_nhosts_list = [
  // example.com will only match example.com and www.example.com
  'play.google.com',
];

var blocked_sl_tl_hosts_list = [
  // example.com will match example.com and all its subdomains
  'ipinfo.io',
];

var blocked_nhosts = {};
blocked_nhosts_list.forEach(function (v) { blocked_nhosts[v] = true });
var blocked_sl_tl_hosts = {};
blocked_sl_tl_hosts_list.forEach(function (v) { blocked_sl_tl_hosts[v] = true });

var PROXY = 'PROXY 127.0.0.1:1081';
var DIRECT = 'DIRECT';

// extract SLD.TLD from host: sub.example.com -> example.com
var second_level_host_regex = /[^.]+\.[^.]+$/;
// extract THLD.SLD.TLD from host: more.sub.example.com -> sub.example.com
var third_level_host_regex = /[^.]+\.[^.]+\.[^.]+$/;

function FindProxyForURL(url, host) {
  // normalized host
  var nhost = host;
  if (nhost.substring(0, 4) === 'www.') {
    nhost = nhost.substring(4);
  }
  if (nhost.substring(nhost.length - 1) === '.') {
    nhost = nhost.substring(0, nhost.length - 1);
  }

  if (isPlainHostName(nhost)) return DIRECT;

  // second level host
  var slhost = nhost.match(second_level_host_regex)[0];
  // third level host
  var match = nhost.match(third_level_host_regex);
  var tlhost = match ? match[0] : null;

  if (blocked_nhosts[nhost]) return PROXY;
  if (blocked_sl_tl_hosts[slhost]) return PROXY;
  if (tlhost !== null && blocked_sl_tl_hosts[tlhost]) return PROXY;

  if (dnsDomainIs(nhost, '.dev')) return PROXY;

  return DIRECT;
}
2
  • Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center. Commented Apr 4 at 15:35
  • Thank you for this answer. I was so happy with it that I provided it for multiple "duplicates" of this question, at serverfault.com/a/1195791/249301 and stackoverflow.com/a/79811305/3795597 and also the original answer at superuser.com/a/1929827/465683 . I then submitted an edit with the expanded content, as I didn't want to leave the original answer with fewer details, and didn't want to steal your Internet points by submitting a new one :) Commented Nov 6 at 16:22

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.