GithubHelp home page GithubHelp logo

genotrance / px Goto Github PK

View Code? Open in Web Editor NEW
921.0 25.0 97.0 985 KB

An HTTP proxy server to automatically authenticate through an NTLM proxy

License: MIT License

Python 94.70% Shell 4.25% PowerShell 0.79% Dockerfile 0.25%

px's Introduction

Chat on Gitter Chat on Matrix

Px

What is Px?

Px is a HTTP(s) proxy server that allows applications to authenticate through an NTLM or Kerberos proxy server, typically used in corporate deployments, without having to deal with the actual handshake. Px leverages Windows SSPI or single sign-on and automatically authenticates using the currently logged in Windows user account. It is also possible to run Px on Windows, Linux and MacOS without single sign-on by configuring the domain, username and password to authenticate with.

Px uses libcurl and as a result supports all the authentication mechanisms supported by libcurl.

Installation

The whole point of Px is to help tools get through a typical corporate proxy. This means using a package manager to install Px might not always be feasible which is why Px offers two binary options:

  • If Python is already available, Px and all its dependencies can be easily installed by downloading the wheels package for the target OS from the releases page. After extraction, Px and all dependencies can be installed with pip:

    python -m pip install px-proxy --no-index -f /path/to/wheels

  • If Python is not available, get the latest compiled binary from the releases page instead. The Windows binary is built using Python Embedded and the Linux and OSX binaries are compiled with Nuitka and contain everything needed to run standalone.

If direct internet access is available along with Python, Px can be easily installed using the Python package manager pip. This will download and install Px as a Python module along with all dependencies:

python -m pip install px-proxy

On Windows, scoop can also be used to install Px:

scoop install px

Once installed, Px can be run as follows:

  • Running px directly
  • In the background: pythonw -m px
  • In the foreground in a console window: python -m px

Px requires libcurl and the Windows builds ship with a copy. On Linux, it is required to install libcurl using the package manager:

  • RHEL: yum install libcurl
  • Ubuntu: apt install libcurl4
  • Alpine: apk add libcurl

Source install

The latest Px version can be downloaded and installed from source via pip:

python -m pip install https://github.com/genotrance/px/archive/master.zip

Source can also be downloaded and installed:

  • Via git:

    git clone https://github.com/genotrance/px

  • Download ZIP:

    https://github.com/genotrance/px/archive/master.zip

Once downloaded, Px can be installed as a standard Python module along with all dependencies :

python -m pip install .

NOTE: Source install methods will require internet access since Python will try to install Px dependencies from the internet. The binaries mentioned in the previous section could be used to bootstrap a source install.

NOTE: libcurl will need to be installed on Linux, as described earlier, using the package manager. For Windows, download and extract libcurl.dll and libcurl-x64.dll to $PATH.

Without installation

Px can be run as a local Python script without installation. Download the source as described above, install all dependencies and then run Px:

pip install keyring netaddr psutil python-dotenv pyspnego quickjs

# Download/install libcurl

pythonw px.py # run in the background
python px.py # run in a console window

Uninstallation

If Px has been installed to the Windows registry to start on boot, it should be uninstalled before removal:

python -m px --uninstall

Px can then be uninstalled using pip as follows:

python -m pip uninstall px-proxy

Docker

Px is available as a prebuilt Docker image.

Two images are posted - the default includes keyring and associated dependencies whereas the mini version is smaller but will have to depend on PX_PASSWORD and PX_CLIENT_PASSWORD for credentials.

The following Docker flags will be useful to configure and run Px:

--name px       name container so it is easy to stop it
-d              run in the background
--rm            remove container on exit

Networking

--network host  make Px directly accessible from host network
  OR
-p 3128:3128    publish the port - Px needs to run in --gateway mode

Configuration

-e PX_LOG=4     set environment variables to configure Px

-v /dir:/px     mount a host directory with a px.ini or .env file to configure Px
  OR
--mount source=/dir,target=/px
                mount a volume if preferred

docker run ... genotrance/px --gateway --verbose
                configure directly from the command line

Credentials

Keyring credentials can be stored in a host folder and mounted into the container as follows:

-v /keyrings:/root/.local/share/keyrings
                mount a local dir to store keyring info
  OR
--mount source=/keyrings,target=/root/.local/share/keyrings
                mount a volume if preferred

Credentials can be saved using the command line:

docker run ... genotrance/px --username=... --password
                configure keyring directly from the command line

The mini version does not have keyring so credentials need to be set using environment variables:

-e PX_PASSWORD=... -e PX_CLIENT_PASSWORD=...
                set environment variables to configure credentials

Configuration

Px requires only one piece of information in order to function - the server name and port of the proxy server. If not specified, Px will check Internet Options or environment variables for any proxy definitions. Without this, Px will try to connect to sites directly.

The noproxy capability allows Px to connect to configured hosts directly, bypassing the proxy altogether. This allows clients to connect to hosts within the intranet without requiring additional configuration for each client or at the proxy.

Configuration can be specified in multiple ways, listed in order of precedence:

  • Command line flags
  • Environment variables
  • Variables in a dotenv file (.env)
    • In the working directory
    • In the Px directory
  • Configuration file px.ini
    • In the working directory
    • In the Px directory

There are many configuration options to tweak - refer to the Usage section or --help for details and syntax.

Credentials

If SSPI is not available or not preferred, providing --username in domain\username format allows Px to authenticate as that user. The corresponding password is retrieved using Python keyring and needs to be setup in the appropriate OS specific backend.

Credentials can be setup with the command line:

px --username=domain\username --password

If username is already defined with PX_USERNAME or in px.ini:

px --password

Information on keyring backends can be found here.

As an alternative, Px can also load credentials from the environment variable PX_PASSWORD or a dotenv file. This is only recommended when keyring is not available.

Windows

Credential Manager is the recommended backend for Windows and the password is stored as a 'Generic Credential' type with 'Px' as the network address name. Credential Manager can be accessed as follows:

Control Panel > User Accounts > Credential Manager > Windows Credentials

Or on the command line: `rundll32.exe keymgr.dll, KRShowKeyMgr`

Linux

Gnome Keyring or KWallet is used to store passwords on Linux.

For systems without a GUI (headless, docker), D-Bus can be started interactively:

dbus-run-session -- sh

If this needs to be done in a script:

export DBUS_SESSION_BUS_ADDRESS=`dbus-daemon --fork --config-file=/usr/share/dbus-1/session.conf --print-address`

Gnome Keyring can then be unlocked as follows:

echo 'somecredstorepass' | gnome-keyring-daemon --unlock

If the default SecretService keyring backend does not work, a third-party backend might be required. Simply install and configure one and keyring will use it. Remember to specify the environment variables they require before starting Px.

This will not work for the Nuitka binaries so as a fallback, PX_PASSWORD can be used instead to set credentials.

Client authentication

Px is useful to authenticate with the upstream proxy server on behalf of clients but it can also authenticate the client that connects to it if needed. This can be useful in gateway mode where remote clients should log in before accessing the upstream proxy via Px. BASIC and DIGEST auth are supported, along with NTLM and NEGOTIATE.

The client credentials can be different from the upstream proxy credentials or the same if preferred. SSPI is also supported on Windows and can be leveraged for only the client or upstream or both.

Client authentication is turned off by default and can be enabled using --client-auth, PX_CLIENT_AUTH or px.ini. Setting the value to ANYSAFE is recommended.

Similar to the upstream proxy, the client username can be configured with --client-username, PX_CLIENT_USERNAME or px.ini The password can be setup in keyring using PxClient as the network address name. PX_CLIENT_PASSWORD is available for cases where keyring is not available.

SSPI is enabled by default on Windows and can be disabled with --client-nosspi, PX_CLIENT_NOSSPI or in px.ini.

Client credentials can be setup in keyring with the command line:

px --client-username=domain\username --client-password

Px only supports one credential for the upstream proxy but can be configured to support multiple client users when keyring is used. Each user should be added to keyring with the PxClient network address.

Using an upstream proxy is not required so Px can also be used simply as an authenticating proxy for smaller setups.

Misc

The configuration file px.ini can be created or updated from the command line using --save.

The binary distribution of Px runs in the background once started and can be quit by running px --quit. When running in the foreground, use CTRL-C.

Px can also be setup to automatically run on startup on Windows with the --install flag. This is done by adding an entry into the Window registry which can be removed with --uninstall.

NOTE: Command line parameters passed with --install are not saved for use on startup. The --save flag or manual editing of px.ini is required to provide configuration to Px on startup.

NOTE: When using the Px binary distribution on Windows, run .\pythonw -m px --install instead of using px.exe. This will avoid the popup console window on startup.

Usage

px [FLAGS]
python px.py [FLAGS]
python -m px [FLAGS]

Actions:
  --save
  Save configuration to file specified with --config or px.ini in working directory
    Allows setting up Px config directly from command line
    Values specified on CLI override any values in existing config file
    Values not specified on CLI or config file are set to defaults

  --install
  Add Px to the Windows registry to run on startup

  --uninstall
  Remove Px from the Windows registry

  --quit
  Quit a running instance of Px

  --restart
  Quit a running instance of Px and start a new instance

  --password | PX_PASSWORD
  Collect and save password to default keyring. Username needs to be provided
  via --username, PX_USERNAME or in the config file.
  As an alternative, Px can also load credentials from the environment variable
  `PX_PASSWORD` or a dotenv file.

  --client-password | PX_CLIENT_PASSWORD
  Collect and save password to default keyring. Username needs to be provided
  via --client-username, PX_CLIENT_USERNAME or in the config file.
  As an alternative, Px can also load credentials from the environment variable
  `PX_CLIENT_PASSWORD` or a dotenv file.

  --test=URL | --test
  Test Px as configured with the URL specified. This can be used to confirm that
  Px is configured correctly and is able to connect and authenticate with the
  upstream proxy. If URL is skipped, Px runs multiple tests against httpbin.org.

Configuration:
  --config= | PX_CONFIG=
  Specify config file. Valid file path, default: px.ini in working directory
  or script directory

  --proxy=  --server= | PX_SERVER= | proxy:server=
  NTLM server(s) to connect through. IP:port, hostname:port
    Multiple proxies can be specified comma separated. Px will iterate through
    and use the one that works

  --pac= | PX_PAC= | proxy:pac=
  PAC file to use to connect
    Use in place of --server if PAC file should be loaded from a URL or local
    file. Relative paths will be relative to the Px script or binary

  --pac_encoding= | PX_PAC_ENCODING= | proxy:pac_encoding=
  PAC file encoding
    Specify in case default 'utf-8' encoding does not work

  --listen= | PX_LISTEN= | proxy:listen=
  Network interface(s) to listen on. Comma separated, default: 127.0.0.1
    --gateway and --hostonly override this to bind to all interfaces

  --port= | PX_PORT= | proxy:port=
  Port to run this proxy on - default: 3128

  --gateway | PX_GATEWAY= | proxy:gateway=
  Allow remote machines to use proxy. 0 or 1, default: 0
    Overrides --listen and binds to all interfaces

  --hostonly | PX_HOSTONLY= | proxy:hostonly=
  Allow only local interfaces to use proxy. 0 or 1, default: 0
    Px allows all IP addresses assigned to local interfaces to use the service.
    This allows local apps as well as VM or container apps to use Px when in a
    NAT config. Overrides --listen and binds to all interfaces, overrides the
    default --allow rules

  --allow= | PX_ALLOW= | proxy:allow=
  Allow connection from specific subnets. Comma separated, default: *.*.*.*
    Whitelist which IPs can use the proxy. --hostonly overrides any definitions
    unless --gateway mode is also specified
    127.0.0.1 - specific ip
    192.168.0.* - wildcards
    192.168.0.1-192.168.0.255 - ranges
    192.168.0.1/24 - CIDR

  --noproxy= | PX_NOPROXY= | proxy:noproxy=
  Direct connect to specific subnets or domains like a regular proxy. Comma separated
    Skip the NTLM proxy for connections to these hosts
    127.0.0.1 - specific ip
    192.168.0.* - wildcards
    192.168.0.1-192.168.0.255 - ranges
    192.168.0.1/24 - CIDR
    example.com - domains

  --useragent= | PX_USERAGENT= | proxy:useragent=
  Override or send User-Agent header on client's behalf

  --username= | PX_USERNAME= | proxy:username=
  Authentication to use when SSPI is unavailable. Format is domain\username
  Service name "Px" and this username are used to retrieve the password using
  Python keyring if available.

  --auth= | PX_AUTH= | proxy:auth=
  Force instead of discovering upstream proxy type
    By default, Px will attempt to discover the upstream proxy type. This
    option can be used to force either NEGOTIATE, NTLM, DIGEST, BASIC or the
    other libcurl supported upstream proxy types. See:
      https://curl.se/libcurl/c/CURLOPT_HTTPAUTH.html
    To control which methods are available during proxy detection:
      Prefix NO to avoid method - e.g. NONTLM => ANY - NTLM
      Prefix SAFENO to avoid method - e.g. SAFENONTLM => ANYSAFE - NTLM
      Prefix ONLY to support only that method - e.g ONLYNTLM => ONLY + NTLM
    Set to NONE to defer all authentication to the client. This allows multiple
    instances of Px to be chained together to access an upstream proxy that is not
    directly connected:
      Client -> Auth Px -> no-Auth Px -> Upstream proxy
        'Auth Px' cannot directly access upstream proxy but 'no-Auth Px' can

  --client-username= | PX_CLIENT_USERNAME= | client:client_username=
  Client authentication to use when SSPI is unavailable. Format is domain\username
  Service name "PxClient" and this username are used to retrieve the password using
  Python keyring if available.

  --client-auth= | PX_CLIENT_AUTH= | client:client_auth=
  Enable authentication for client connections. Comma separated, default: NONE
  Mechanisms supported: NEGOTIATE, NTLM, DIGEST, BASIC
    ANY     = enable all supported mechanisms
    ANYSAFE = enable all supported mechanisms except BASIC
    NTLM    = enable only NTLM, etc.
    NONE    = disable client authentication altogether (default)

  --client-nosspi= | PX_CLIENT_NOSSPI= | client:client_nosspi=
  Disable SSPI for client authentication on Windows. default: 0
    Set to 1 to disable SSPI and use the configured username and password

  --workers= | PX_WORKERS= | settings:workers=
  Number of parallel workers (processes). Valid integer, default: 2

  --threads= | PX_THREADS= | settings:threads=
  Number of parallel threads per worker (process). Valid integer, default: 32

  --idle= | PX_IDLE= | settings:idle=
  Idle timeout in seconds for HTTP connect sessions. Valid integer, default: 30

  --socktimeout= | PX_SOCKTIMEOUT= | settings:socktimeout=
  Timeout in seconds for connections before giving up. Valid float, default: 20

  --proxyreload= | PX_PROXYRELOAD= | settings:proxyreload=
  Time interval in seconds before refreshing proxy info. Valid int, default: 60
    Proxy info reloaded from manual proxy info defined in Internet Options

  --foreground | PX_FOREGROUND= | settings:foreground=
  Run in foreground when compiled or run with pythonw.exe. 0 or 1, default: 0
    Px will attach to the console and write to it even though the prompt is
    available for further commands. CTRL-C in the console will exit Px

  --log= | PX_LOG= | settings:log=
  Enable debug logging. default: 0
    1 = Log to script dir [--debug]
    2 = Log to working dir
    3 = Log to working dir with unique filename [--uniqlog]
    4 = Log to stdout [--verbose]. Implies --foreground
    If Px crashes without logging, traceback is written to the working dir

Examples

Use proxyserver.com:80 and allow requests from localhost only:

px --proxy=proxyserver.com:80

Don't use any forward proxy at all, just log what's going on:

px --noproxy=0.0.0.0/0 --debug

Allow requests from localhost and all locally assigned IP addresses. This is very useful for Docker for Windows and VMs in a NAT configuration because all requests originate from the host's IP:

px --proxy=proxyserver.com:80 --hostonly

Allow requests from localhost, locally assigned IP addresses and the IPs specified in the allow list outside the host:

px --proxy=proxyserver:80 --hostonly --gateway --allow=172.*.*.*

Allow requests from everywhere. Be careful, every client will use your login:

px --proxy=proxyserver.com:80 --gateway

NOTE: In Docker for Windows you need to set your proxy to http://host.docker.internal:3128 or http://<your_ip>:3128 (or actual port Px is listening to) in your containers and be aware of docker/for-win#1380.

Workaround:

docker build --build-arg http_proxy=http://<your ip>:3128 --build-arg https_proxy=http://<your ip>:3128 -t containername ../dir/with/Dockerfile

NOTE: In WSL2 you can setup your proxy in /etc/profile as follows:

export http_proxy="http://$(tail -1 /etc/resolv.conf | cut -d' ' -f2):3128"
export https_proxy="http://$(tail -1 /etc/resolv.conf | cut -d' ' -f2):3128"

NOTE: When running MQTT over websockets, it will help to increase the idle timeout to 120 seconds: --idle=120. The default value of 30 will cause the websocket connection to disconnect since the default MQTT keepalive period is 60 seconds.

Dependencies

Px doesn't have any GUI and runs completely in the background. It depends on the following Python packages:

Px also depends on libcurl for all outbound HTTP connections and proxy authentication.

Limitations

Windows multiprocessing only works on Python 3.3+ since that's when support was added to share sockets across processes. On older versions of Python, Px will run multi-threaded but in a single process.

MacOSX socket sharing is not implemented at this time and is limited to running in a single process.

While it should mostly work, Px is not tested on MacOSX since there's no test environment available at this time to verify functionality. PRs are welcome to help fix any issues.

Building

To build a self-sufficient executable that does not depend on the presence of Python and dependency modules, both Nuitka and PyInstaller scripts are provided. There is also a Python Embedded build that is preferable on Windows. Check out python tools.py for more details.

Feedback

Px is definitely a work in progress and any feedback or suggestions are welcome. It is hosted on GitHub with an MIT license so issues, forks and PRs are most appreciated. Join us on the discussion board, Gitter or Matrix to chat about Px.

Credits

Thank you to all contributors for their PRs and all issue submitters.

Px is based on code from all over the internet and acknowledges innumerable sources.

px's People

Contributors

bedla avatar eitsupi avatar f11018 avatar fty4 avatar genotrance avatar horsteff avatar jke96 avatar johnadders avatar k0l0nell avatar mindsolve avatar qichaozhao avatar wheelerlaw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

px's Issues

Add a license

Can you add a license to this repo because "no license" means strong copyright. My company has strong OSS policies that prevent me to use your tool.
Please, see this article from Github for more info: https://choosealicense.com/no-license/

Exception happened during reading response code

debug-Process-2.log

Px started manuallัƒ with admin rights.
After the first connect attempt I always get the exception "list index out of range":

Exception happened during processing of request from ('127.0.0.1', 55607)
Traceback (most recent call last):
File "socketserver.py", line 639, in process_request_thread
File "socketserver.py", line 361, in finish_request
File "socketserver.py", line 696, in init
File "http\server.py", line 418, in handle
File "px.py", line 288, in handle_one_request
File "http\server.py", line 406, in handle_one_request
File "px.py", line 677, in do_CONNECT
File "px.py", line 563, in do_transaction
File "px.py", line 416, in do_socket
IndexError: list index out of range

The second attempt is always ok.

A way to noproxy based on domain names

It'd be pretty neat if we could do a no proxy config based on domain names. The use case I have is that I don't want to go via PX for my intranet sites but I can't wildcard domain entries

Version after 4a07056 do not work on windows

Hi,

Using latest release, on windows, got the error in every request:

MainProcess: Thread_0: 1520419833: do_socket: Reading response code
MainProcess: Thread_0: 1520419833: do_socket: Response code: 407 False
MainProcess: Thread_0: 1520419833: do_socket: Reading response headers
MainProcess: Thread_0: 1520419833: do_socket: Received header Via = 1.1 10.0.3.5 (McAfee Web Gateway 7.7.2.7.0.24770)
MainProcess: Thread_0: 1520419833: do_socket: Received header Date = Wed, 07 Mar 2018 10:50:34 GMT
MainProcess: Thread_0: 1520419833: do_socket: Received header Content-Type = text/html
MainProcess: Thread_0: 1520419833: do_socket: Received header Cache-Control = no-cache
MainProcess: Thread_0: 1520419833: do_socket: Received header Content-Length = 3887
MainProcess: Thread_0: 1520419833: do_socket: Received header Proxy-Connection = Keep-Alive
MainProcess: Thread_0: 1520419833: do_socket: Received header Proxy-Authenticate = Negotiate
MainProcess: Thread_0: 1520419833: do_socket: Received header Proxy-Authenticate = NTLM
MainProcess: Thread_0: 1520419833: do_socket: Received header Proxy-Authenticate = Basic realm="Proxy Authentication"
MainProcess: Thread_0: 1520419833: do_socket: Reading response data
MainProcess: Thread_0: 1520419833: do_socket: Content length 3887
MainProcess: Thread_0: 1520419833: do_transaction: Auth required
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 59105)
Traceback (most recent call last):
  File "socketserver.py", line 639, in process_request_thread
  File "socketserver.py", line 361, in finish_request
  File "socketserver.py", line 696, in __init__
  File "http\server.py", line 418, in handle
  File "px.py", line 275, in handle_one_request
  File "http\server.py", line 406, in handle_one_request
  File "px.py", line 614, in do_GET
  File "px.py", line 551, in do_transaction
IndexError: list index out of range

Provide an installer

Hi,

In order to be able to ease the use in a work environnement, providing an installer that can install a windows service directly would be really useful.

Ton of thanks for Px :)

Support for NTLM V2

Currently while using px with ntlmv2 proxy server we get error from curl commands that "Your credentials could not be authenticated: "Another round of authentication required.". You will not be permitted access until your credentials can be verified.
Does it support NTLMV2 auth for proxy server?

Certificates

It seems that px, cntlm and ntlmaps don't work when the requested URL is HTTPS and has a certificate.
If in IntelliJ IDEA I set the proxy to the one of px and want to update IntelliJ then IntelliJ displays a window with the details of the certificate which I can then accept. But other tools for which I used px don't display any window with the certificate but an error message, like ConEmu. There should be a solution for this in px. The easiest would be an option to trust all certificates. I am no expert, I hope you understand what the problem is and can provide a solution.

Not recognizing netaddr

I have installed netaddr 0.7.19 per directions, but whenever I try to run px.py, I get the message "Requires modules netaddr". I am running python 27 on Windows 7.

Crash when installed with admin rights

I'm running into a similar kind of issue like #31. I have px "installed", but after every reboot px crashs with a popup window Failed to execute script px.

I have the feeling that the reasons are missing file permissions. When I "install" px, this is done with administrator rights, so the folder where px is installed is writable only for an administrator. But when px is started, this happens without admin rights. The strange thing is that px also crashes when installed without debug setting active, so nothing should be written in the folder. I checked the created px.ini and it's log=0 there.

When I start px.exe manually in an unelevated cmd.exe, it's all fine, no crash. But during boot, always a crash (without a log file, of course).

@genotrance: Any idea how to further debug this?

Add Proxy-Connection: Keepalive Header for HTTP/1.0 requests

While testing against squid 3.5.27 (latest stable) I observed the following behaviour:
A client using HTTP/1.0 w/o a Proxy-Connection: Keepalive header cannot be authenticated with NTLM; a HTTP/1.0 with Proxy-Connection: Keepalive header is authenticated as well as a HTTP/1.1 client regardless of the header.

As far as my research indicates, this is a valid behaviour: HTTP/1.1 implies a connection keep alive and NTLM auth may require connection keep alive (esp. in order to keep challenge and response together if going through a load balancer).

A possible solution would be to add an option for px to send a Proxy-Connection: keepalive header regardless of client's request (or at least for HTTP/1.0 connections).

Here are the test cases (latest stable curl 7.55.1):

# HTTP/1.0 w/ Proxy-Connection Header // working
curl --proxy 127.0.0.1:3128  -v -0 http://some.server.de 
# HTTP/1.1 w/o Proxy-Connection Header // working
curl --proxy 127.0.0.1:3128 --proxy-header Proxy-Connection: -v  http://some.server.de
# HTTP/1.0 w/o Proxy-Connection Header // failing
curl --proxy 127.0.0.1:3128 --proxy-header Proxy-Connection: -v -0 http://some.server.de

Year 30828 out of range

Hi,

I've used pyinstaller to build px on Windows 7, using Python 3.6, I'm getting the following error while trying to connect to the proxy: ValueError year 3083 is out of range in sspi.py line 111.

image

Any ideas?

Little enhancement and bugfix

2 Bugfixes:

  • In my environment, configparser does not know "default_section", not sure if it's in general like this. I disbaled this line via comment.
  • When using "noproxy" and "get_destination" trys to resolv the ip address, I'm running into a timeout (exception) because of "handle_one_request". This behaviour makes px to timeout all internet requests, because my local DNS isn't able to resolv internet addresses. In my environment resolving internet addresses is done on proxy side. That's why I added an own expception there.

1 Enhancement:

  • Added possibility to set "--listen", "--port" and "--config" via commandline/arguments
--- px.py	2018-01-17 17:14:16.692200100 +0100
+++ px.py	2018-01-17 17:20:24.890200100 +0100
@@ -495,7 +495,10 @@
 
             dprint(netloc)
             spl = netloc.split(":", 1)
-            addr = socket.getaddrinfo(spl[0], int(spl[1]))
+            try:
+		addr = socket.getaddrinfo(spl[0], int(spl[1]))
+            except:
+		addr = ""
             if len(addr) and len(addr[0]) == 5:
                 ipport = addr[0][4]
                 dprint("%s => %s + %s" % (self.path, ipport, path))
@@ -622,9 +625,13 @@
     global MAX_WORKERS
     global PORT
 
+    for i in range(len(sys.argv)):
+        if "--config=" in sys.argv[i]:
+            INI = sys.argv[i].split("=")[1]
+    
     if os.path.exists(INI):
         config = configparser.ConfigParser()
-        config.set(config.default_section, "allow", "*.*.*.*")
+        #config.set(config.default_section, "allow", "*.*.*.*")	//Produces Error
         config.read(INI)
 
         if "proxy" in config.sections():
@@ -689,6 +696,13 @@
             parsenoproxy(sys.argv[i].split("=")[1])
         elif "--allow=" in sys.argv[i]:
             parseallow(sys.argv[i].split("=")[1])
+        elif "--listen=" in sys.argv[i]:
+            LISTEN = sys.argv[i].split("=")[1]
+        elif "--port=" in sys.argv[i]:
+            try:
+		PORT = int((sys.argv[i].split("=")[1]))
+            except:
+		pass
 
     if "--gateway" in sys.argv:
         LISTEN = ''

Missing debug log!?

I have a rather strange issue currently.

If I'm using a compiled px.exe (with or without shim, latest version) no useful logs are generated any more. Some initial lines are in the console, but nothing about request, socket and proxy authentication stuff.

The generated log files debug-MainProcess.log and debug-Process-1.log stay at 0 Bytes, no matter what I do.

This is my log in the shell:

px.exe --proxy=proxy.rwe.com:8080 --hostonly --debug

MainProcess: MainThread: 1520585210: parse_proxy: [('proxy.rwe.com', 8080)]
MainProcess: MainThread: 1520585210: parse_proxy: [('proxy.rwe.com', 8080)]
MainProcess: MainThread: 1520585210: parse_config: Turning allow off
Serving at :3128 proc MainProcess
MainProcess: MainThread: 1520585210: parse_config: proxy:server = proxy.rwe.com:8080
MainProcess: MainThread: 1520585210: parse_config: proxy:listen =
MainProcess: MainThread: 1520585210: parse_config: proxy:port = 3128
MainProcess: MainThread: 1520585210: parse_config: proxy:gateway = 0
MainProcess: MainThread: 1520585210: parse_config: proxy:hostonly = 1
MainProcess: MainThread: 1520585210: parse_config: proxy:allow =
MainProcess: MainThread: 1520585210: parse_config: proxy:noproxy =
MainProcess: MainThread: 1520585210: parse_config: proxy:useragent =
MainProcess: MainThread: 1520585210: parse_config: settings:workers = 2
MainProcess: MainThread: 1520585210: parse_config: settings:threads = 5
MainProcess: MainThread: 1520585210: parse_config: settings:idle = 30
MainProcess: MainThread: 1520585210: parse_config: settings:socktimeout = 5.0
MainProcess: MainThread: 1520585210: parse_config: settings:proxyreload = 60
MainProcess: MainThread: 1520585210: parse_config: settings:foreground = 0
MainProcess: MainThread: 1520585210: parse_config: settings:log = 0
Process-1: MainThread: 1520585211: parse_proxy: [('proxy.rwe.com', 8080)]
Process-1: MainThread: 1520585211: parse_proxy: [('proxy.rwe.com', 8080)]
Process-1: MainThread: 1520585211: parse_config: Turning allow off
Serving at :3128 proc Process-1
Process-1: MainThread: 1520585211: parse_config: proxy:server = proxy.rwe.com:8080
Process-1: MainThread: 1520585211: parse_config: proxy:listen =
Process-1: MainThread: 1520585211: parse_config: proxy:port = 3128
Process-1: MainThread: 1520585211: parse_config: proxy:gateway = 0
Process-1: MainThread: 1520585211: parse_config: proxy:hostonly = 1
Process-1: MainThread: 1520585211: parse_config: proxy:allow =
Process-1: MainThread: 1520585211: parse_config: proxy:noproxy =
Process-1: MainThread: 1520585211: parse_config: proxy:useragent =
Process-1: MainThread: 1520585211: parse_config: settings:workers = 2
Process-1: MainThread: 1520585211: parse_config: settings:threads = 5
Process-1: MainThread: 1520585211: parse_config: settings:idle = 30
Process-1: MainThread: 1520585211: parse_config: settings:socktimeout = 5.0
Process-1: MainThread: 1520585211: parse_config: settings:proxyreload = 60
Process-1: MainThread: 1520585211: parse_config: settings:foreground = 0
Process-1: MainThread: 1520585211: parse_config: settings:log = 0

px seems to work fine as a proxy.

I've seen the commit 4a07056, but I've no idea what could cause this behaviour.

How to use PX with Windows 10

Hello,

can you explain in detail how to make PX work for Windows 10? I did the following:

Open px.ini and add my proxy under server=
Added allow = 127.0.0.1 + my own ip from ipconfig /all
Save px.ini
Run build.bat

I see a terminal for a blink of an eye and then it disappears. What am I doing wrong?

WPAD not working for us!?

I'm currently trying to use WPAD/PAC support on Win10 clients and I get the following log:

MainProcess: MainThread: 1523945168: attach_console: No parent console to attach to
MainProcess: MainThread: 1523945168: parse_config: Turning allow off
MainProcess: MainThread: 1523945168: load_proxy: AutoConfigURL = http://info-pac.rwe.com/innogy.pac
MainProcess: MainThread: 1523945168: load_proxy: Proxy mode = 3
Serving at :3128 proc MainProcess
MainProcess: MainThread: 1523945168: parse_config: proxy:server = 
MainProcess: MainThread: 1523945168: parse_config: proxy:listen = 
MainProcess: MainThread: 1523945168: parse_config: proxy:port = 3128
MainProcess: MainThread: 1523945168: parse_config: proxy:gateway = 0
MainProcess: MainThread: 1523945168: parse_config: proxy:hostonly = 1
MainProcess: MainThread: 1523945168: parse_config: proxy:allow = 
MainProcess: MainThread: 1523945168: parse_config: proxy:noproxy = 
MainProcess: MainThread: 1523945168: parse_config: proxy:useragent = 
MainProcess: MainThread: 1523945168: parse_config: settings:workers = 2
MainProcess: MainThread: 1523945168: parse_config: settings:threads = 5
MainProcess: MainThread: 1523945168: parse_config: settings:idle = 30
MainProcess: MainThread: 1523945168: parse_config: settings:socktimeout = 5.0
MainProcess: MainThread: 1523945168: parse_config: settings:proxyreload = 60
MainProcess: MainThread: 1523945168: parse_config: settings:foreground = 0
MainProcess: MainThread: 1523945168: parse_config: settings:log = 0
MainProcess: MainThread: 1523945204: verify_request: Client address: 127.0.0.1
MainProcess: MainThread: 1523945204: verify_request: Host-only IP allowed
MainProcess: Thread_0: 1523945204: do_CONNECT: Entering
MainProcess: Thread_0: 1523945204: do_transaction: Entering
MainProcess: Thread_0: 1523945204: get_destination: chocolatey.org:443
MainProcess: Thread_0: 1523945204: load_proxy: Skip proxy refresh
MainProcess: Thread_0: 1523945204: winhttp_find_proxy_for_url: WinHttpGetProxyForUrl error 6
MainProcess: Thread_0: 1523945204: find_proxy_for_url: Proxy found: 
MainProcess: Thread_0: 1523945204: do_transaction: No proxy server specified and not in noproxy list
MainProcess: Thread_0: 1523945204: do_CONNECT: Error 501
MainProcess: Thread_0: 1523945204: log_message: code 501, message Not Implemented
MainProcess: Thread_0: 1523945204: log_message: "CONNECT chocolatey.org:443 HTTP/1.1" 501 -
MainProcess: Thread_0: 1523945204: do_CONNECT: Transferred 0 bytes
MainProcess: Thread_0: 1523945204: do_CONNECT: Done

I tried to debug myself, but was not able to figure out why WinHttpGetProxyForUrl() fails with a ERROR_INVALID_HANDLE (6). The function WinHttpOpen() returns a valid handle! What other handle could be invalid?

I googled for other winhttp+ctypes examples on the web and they fail also! Same error at the same location. Any idea what could be different at our setup!? I can reproduce this on multiple Win10 clients.

I'm a little bit lost now... :-(

Add a little more documentation

I propose as background information to add a link to https://msdn.microsoft.com/en-us/library/dd925287.aspx which explains the sequence of the NTLM authentication.

Furthermore you should mention (e.g. as an ini file comment), that the log files are written in to the directory where px got started and that previous logs get overwritten at every start of the tool.

Otherwise thanks fot the cool piece of Software!

Add ftp support

In "get_destination" please add ftp like this:

if not port:
    if parse.scheme == "http":
        port = 80
    elif parse.scheme == "https":
        port = 443
    elif parse.scheme == "ftp":
        port = 21

[Feature Request] Mapping local ports to remote machine ports like CNTLM

Hello,

I would like to request the same feature as the one described in the cntlm.ini file of CNTLM :


Tunnels mapping local port to a machine behind the proxy.
The format is <local_port>:<remote_host>:<remote_port>
Tunnel 7777:machine.foobar.net:443


I'm heavily using this feature and it would be great to have it on px.

Any advice on that matter would be much appreciated.

Cheers.

OverflowError: cannot fit 'int' into an index-sized integer

I'm having issues with large files

Process-1: Thread_1: 1524733960: do_socket: Reading response headers
Process-1: Thread_1: 1524733960: do_socket: Received Server: Apache
Process-1: Thread_1: 1524733960: do_socket: Received Accept-Ranges: bytes
Process-1: Thread_1: 1524733960: do_socket: Received Content-Type: application/zip
Process-1: Thread_1: 1524733960: do_socket: Received Last-Modified: Fri, 26 Jan 2018 07:39:56 GMT
Process-1: Thread_1: 1524733960: do_socket: Received Content-Length: 3814407425
Process-1: Thread_1: 1524733960: do_socket: Received Date: Thu, 26 Apr 2018 09:12:40 GMT
Process-1: Thread_1: 1524733960: do_socket: Received Connection: close
Process-1: Thread_1: 1524733961: do_socket: Received Age: 0
Process-1: Thread_1: 1524733961: do_socket: Reading response data
Process-1: Thread_1: 1524733961: do_socket: Content length 3814407425

Exception happened during processing of request from ('10.0.0.3', 52351)
Traceback (most recent call last):
File "socketserver.py", line 639, in process_request_thread
File "socketserver.py", line 361, in finish_request
File "socketserver.py", line 696, in init
File "http\server.py", line 418, in handle
File "px.py", line 288, in handle_one_request
File "http\server.py", line 406, in handle_one_request
File "px.py", line 635, in do_GET
File "px.py", line 584, in do_transaction
File "px.py", line 471, in do_socket
OverflowError: cannot fit 'int' into an index-sized integer

Add ability to run Px in foreground in frozen mode

Binary version of Px runs in the background already but a flag or config option should allow the script version to run in the background too. This will be useful if Px is run from source or installed via pip or other methods.

As a complement, the --quit flag should also be enhanced to work as expected in this mode.

[Feature Request] Support Kerberos Authentication

Hi genotrance,

Firstly thanks for building this awesome tool.

At my corp offices it seems by default Kerberos authentication is used and NTLM does not work for authenticating through the corporate proxy, is there any possibility you could work at adding authentication via using a Kerberos ticket cache?

I am happy to contribute if you can give me some guidance as to what needs to be done - I am familiar with Python but have no idea how these authentication mechanisms work.

Capturing Error Responses

Is there any reason why you are capturing the error response and sending back an error from SimpleHttp? This has been causing some issues in certain programs that are expecting a specific error to come back from a service. Would it be possible to make this a toggleable configuration?

winhttp_find_proxy_for_url: WinHttpOpen failed: 87

Hi, is there something wrong i'm doing or it's not working?
image

Below my config:

[proxy]
#server =
port = 3128
listen = 127.0.0.1
allow = *.*.*.*
gateway = 0
hostonly = 0
#noproxy = 127.0.0.1
#useragent = 

[settings]
workers = 2
threads = 5
idle = 30
socktimeout = 5.0
proxyreload = 60
foreground = 0
log = 1

And IE settings:
image

Is the PUT method supported?

Hi, geno. I am using a continuous integration tool called Concourse that has a command line application known as Fly. Fly is a Linux tool, so it reads proxy settings from the HTTP_PROXY, HTTPS_PROXY and NO_PROXY environment variables. I am running Fly from within a Windows 10 VM running on my workstation.

Settings:

Setting Value
VM Host IP 192.168.95.1
VM Host px port 3128
VM Host px gateway 1
VM Host px noproxy 127.0.0.0/24,192.168.95.0/24,10.<redacted>
VM Guest HTTP_PROXY environment variable http://192.168.95.1:3128
VM Guest HTTPS_PROXY environment variable http://192.168.95.1:3128
VM Guest NO_PROXY environment variable 127.0.0.0/24,localhost,.corporatenetwork.com
Remote Concourse URL 10.<redacted>

Note that 10.<redacted> in both cases is the single IP address of the Concourse server on my corporate network.

When I run Fly in this manner, I receive the following strange HTTP response:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
        <title>Error response</title>
    </head>
    <body>
        <h1>Error response</h1>
        <p>Error code: 501</p>
        <p>Message: Unsupported method ('PUT').</p>
        <p>Error code explanation: HTTPStatus.NOT_IMPLEMENTED - Server does not support this operation.</p>
    </body>
</html>

However, if I simply add 10.<redacted> to the NO_PROXY environment variable and try again, Fly works without issue. It seems like the only difference between my two attempts is that the first goes through px and the second doesn't.

Partial log output demonstrating that GET works fine but PUT doesn't:

192.168.95.129 - - [14/Mar/2017 08:40:33] "GET http://10.<redacted>:8080/api/v1/info HTTP/1.1" 200 -
...
192.168.95.129 - - [14/Mar/2017 08:40:35] code 501, message Unsupported method ('PUT')
192.168.95.129 - - [14/Mar/2017 08:40:35] "PUT http://10.<redacted>:8080/api/v1/<redacted> HTTP/1.1" 501 -

Does px support PUT? Do I need to configure something somewhere?

"px --quit" does not terminate the executable

steps to reproduce

  • start the px executable directly in Windows 7
  • enter px --quit in cmd
  • Px is not running

expected behaviour

  • start the px executable directly in Windows 7
  • enter px --quit in cmd
  • Px is terminated

Nevertheless, thank you very much for sharing this AWESOME tool!

An attempt was made to access a socket in a way forbidden by its access permissions

Got this error :

Traceback (most recent call last):
  File "px.py", line 606, in <module>
    runpool()
  File "px.py", line 451, in runpool
    httpd = ThreadedTCPServer((GATEWAY, PORT), Proxy)
  File "c:\PORT-STC\opt\python3\lib\socketserver.py", line 430, in __init__
    self.server_bind()
  File "c:\PORT-STC\opt\python3\lib\socketserver.py", line 444, in server_bind
    self.socket.bind(self.server_address)
OSError: [WinError 10013] An attempt was made to access a socket in a way forbidden by its access permissions

I'd say it's because I'm not Administrator my my PC but I'm not sure...

I run in a corporate environment and I have set up the px.ini file correctly (I hope!). The error shows up right at the start of px execution.

Installation from PyPI fails on win_amd64

Hi. I'm using a 64-bit distribution of Python. Installing px from PyPI fails:

>pip install px-proxy
Collecting px-proxy
  Could not find a version that satisfies the requirement px-proxy (from versions: )
No matching distribution found for px-proxy

I think the solution will be to publish a 64-bit wheel -win32_amd64.whl or a source distribution https://pypi.org/project/px-proxy/#files

Function requested not supported in SSPI

I am trying to get this working on Phyton 2.7 64 bit. 64 bit versions of pyutils and pywin32 are installed. The program runs but when I actually get to using the proxy, I get the following error message and a subsequent 407 response from the proxy.

Traceback (most recent call last):
File "px.py", line 96, in create_challenge_response
error_msg, output_buffer = self.sspi_client.authorize(input_buffer)
File "C:\Python27\lib\site-packages\win32\lib\sspi.py", line 139, in authorize
sec_buffer_out)
error: (-2146893054, 'InitializeSecurityContext', 'The function requested is not supported')
127.0.0.1 - - [05/Jan/2017 12:02:28] code 407, message Proxy Authentication Required

Failed to execute script px

Hello, I opened the px.ini in notepad++ with admin rights and entered my server info. When I try to run px.exe, i am getting Failed to execute script px. My co-worker, however was able to complete the same steps with no issue.

Are there any troubleshooting steps I can take?

Thank you,
Teresa

build.bat does not work anymore

Executing build.bat in HEAD gives me:

Unable to find "c:\Miniconda\Lib\site-packages\tld\res\effective_tld_names.dat.txt" when adding binary and data files.

And no px.exe is generated.

When I remove this dependency to miniconda, build.bat works as expected.

Is this file really needed?

Installation via apt on Vagrant machine is very slow

I want to install a package via apt on my Ubuntu 18.04 Vagrant machine. It takes very long until [Waiting for headers] disappears and the installation begins. I'm running Windows 7 and the version 2018-05-19 of px. Sometimes apt prints the error message Connection failed [IP: 10.0.2.2 3129]. The log then says:

MainProcess: Thread_4: 1526995974: handle_one_request: Host disconnected
MainProcess: Thread_4: 1526995974: handle_one_request: Host disconnected: 2
MainProcess: Thread_4: 1526995974: handle_one_request: Host disconnected: 3
MainProcess: Thread_4: 1526995974: handle_one_request: Closed connection to avoid infinite loop

If I switch back to Cntlm everything works normal.

MainProcess: MainThread: 1526995125: attach_console: Attaching to console 8952
MainProcess: MainThread: 1526995125: parse_proxy: [('proxy01.example.com', 8080)]
Serving at :3129 proc MainProcess
MainProcess: MainThread: 1526995125: parse_config: proxy:server = proxy01.example.com:8080
MainProcess: MainThread: 1526995125: parse_config: proxy:listen = 
MainProcess: MainThread: 1526995125: parse_config: proxy:port = 3129
MainProcess: MainThread: 1526995125: parse_config: proxy:gateway = 1
MainProcess: MainThread: 1526995125: parse_config: proxy:hostonly = 0
MainProcess: MainThread: 1526995125: parse_config: proxy:allow = 127.0.0.1,10.0.2.0/24,192.168.56.0/24
MainProcess: MainThread: 1526995125: parse_config: proxy:noproxy = 127.0.0.1,10.0.0.0/8,192.168.0.0/16
MainProcess: MainThread: 1526995125: parse_config: proxy:useragent = 
MainProcess: MainThread: 1526995125: parse_config: settings:workers = 1
MainProcess: MainThread: 1526995125: parse_config: settings:threads = 5
MainProcess: MainThread: 1526995125: parse_config: settings:idle = 30
MainProcess: MainThread: 1526995125: parse_config: settings:socktimeout = 5.0
MainProcess: MainThread: 1526995125: parse_config: settings:proxyreload = 60
MainProcess: MainThread: 1526995125: parse_config: settings:foreground = 0
MainProcess: MainThread: 1526995125: parse_config: settings:log = 0
MainProcess: MainThread: 1526995125: detach_console: Freed console successfully
MainProcess: MainThread: 1526995163: verify_request: Client address: 127.0.0.1
MainProcess: Thread_0: 1526995163: do_GET: Entering
MainProcess: Thread_0: 1526995163: do_GET: Path = http://archive.ubuntu.com/ubuntu/pool/universe/0/0ad-data/0ad-data_0.0.22-1_all.deb
MainProcess: Thread_0: 1526995163: do_transaction: Entering
MainProcess: Thread_0: 1526995163: get_destination: archive.ubuntu.com:80
MainProcess: Thread_0: 1526995163: get_destination: http://archive.ubuntu.com/ubuntu/pool/universe/0/0ad-data/0ad-data_0.0.22-1_all.deb => ('91.189.88.149', 80) + /ubuntu/pool/universe/0/0ad-data/0ad-data_0.0.22-1_all.deb
MainProcess: Thread_0: 1526995163: do_socket_connect: New connection: ('proxy01.example.com', 8080)
MainProcess: Thread_0: 1526995163: do_proxy_type: Searching proxy type
MainProcess: Thread_0: 1526995163: do_socket: Entering
MainProcess: Thread_0: 1526995163: do_socket: GET http://archive.ubuntu.com/ubuntu/pool/universe/0/0ad-data/0ad-data_0.0.22-1_all.deb HTTP/1.1
MainProcess: Thread_0: 1526995163: do_socket: Sending Host: archive.ubuntu.com
MainProcess: Thread_0: 1526995163: do_socket: Sending Range: bytes=27852430-
MainProcess: Thread_0: 1526995163: do_socket: Sending If-Range: Sat, 28 Oct 2017 18:04:50 GMT
MainProcess: Thread_0: 1526995163: do_socket: Sending User-Agent: Debian APT-HTTP/1.3 (1.6.1)
MainProcess: Thread_0: 1526995163: do_socket: Reading response code
MainProcess: Thread_0: 1526995163: do_socket: Response code: 407 False
MainProcess: Thread_0: 1526995163: do_socket: Reading response headers
MainProcess: Thread_0: 1526995163: do_socket: Received Proxy-Authenticate: sanitized (9)
MainProcess: Thread_0: 1526995163: do_socket: Received Proxy-Authenticate: sanitized (4)
MainProcess: Thread_0: 1526995163: do_socket: Received Date: Tue, 22 May 2018 13:19:23 GMT
MainProcess: Thread_0: 1526995163: do_socket: Received Cache-Control: no-cache
MainProcess: Thread_0: 1526995163: do_socket: Received Pragma: no-cache
MainProcess: Thread_0: 1526995163: do_socket: Received Content-Type: text/html; charset="UTF-8"
MainProcess: Thread_0: 1526995163: do_socket: Received Content-Length: 2528
MainProcess: Thread_0: 1526995164: do_socket: Received Accept-Ranges: none
MainProcess: Thread_0: 1526995164: do_socket: Received Proxy-Connection: keep-alive
MainProcess: Thread_0: 1526995164: do_socket: Reading response data
MainProcess: Thread_0: 1526995164: do_socket: Content length 2528
MainProcess: Thread_0: 1526995164: do_proxy_type: Auth mechanisms: Negotiate NTLM 
MainProcess: Thread_0: 1526995164: do_proxy_type: Selected: {('proxy01.example.com', 8080): 'NTLM'}
MainProcess: Thread_0: 1526995164: get_response_sspi: pywin32 SSPI
MainProcess: Thread_0: 1526995164: do_socket: Entering
MainProcess: Thread_0: 1526995164: do_socket: GET http://archive.ubuntu.com/ubuntu/pool/universe/0/0ad-data/0ad-data_0.0.22-1_all.deb HTTP/1.1
MainProcess: Thread_0: 1526995164: do_socket: Sending Host: archive.ubuntu.com
MainProcess: Thread_0: 1526995164: do_socket: Sending Range: bytes=27852430-
MainProcess: Thread_0: 1526995164: do_socket: Sending If-Range: Sat, 28 Oct 2017 18:04:50 GMT
MainProcess: Thread_0: 1526995164: do_socket: Sending User-Agent: Debian APT-HTTP/1.3 (1.6.1)
MainProcess: Thread_0: 1526995164: do_socket: Sending extra Proxy-Authorization: sanitized len(85)
MainProcess: Thread_0: 1526995164: do_socket: Reading response code
MainProcess: Thread_0: 1526995164: do_socket: Response code: 407 False
MainProcess: Thread_0: 1526995164: do_socket: Reading response headers
MainProcess: Thread_0: 1526995164: do_socket: Received Proxy-Authenticate: sanitized (301)
MainProcess: Thread_0: 1526995164: do_socket: Received Date: Tue, 22 May 2018 13:19:24 GMT
MainProcess: Thread_0: 1526995164: do_socket: Received Cache-Control: no-cache
MainProcess: Thread_0: 1526995164: do_socket: Received Pragma: no-cache
MainProcess: Thread_0: 1526995164: do_socket: Received Content-Type: text/html; charset="UTF-8"
MainProcess: Thread_0: 1526995164: do_socket: Received Content-Length: 2528
MainProcess: Thread_0: 1526995164: do_socket: Received Accept-Ranges: none
MainProcess: Thread_0: 1526995164: do_socket: Received Proxy-Connection: keep-alive
MainProcess: Thread_0: 1526995164: do_socket: Reading response data
MainProcess: Thread_0: 1526995164: do_socket: Content length 2528
MainProcess: Thread_0: 1526995164: do_transaction: Auth required
MainProcess: Thread_0: 1526995164: do_transaction: Challenged
MainProcess: Thread_0: 1526995164: get_response_sspi: pywin32 SSPI
MainProcess: Thread_0: 1526995164: do_socket: Entering
MainProcess: Thread_0: 1526995164: do_socket: GET http://archive.ubuntu.com/ubuntu/pool/universe/0/0ad-data/0ad-data_0.0.22-1_all.deb HTTP/1.1
MainProcess: Thread_0: 1526995164: do_socket: Sending Host: archive.ubuntu.com
MainProcess: Thread_0: 1526995164: do_socket: Sending Range: bytes=27852430-
MainProcess: Thread_0: 1526995164: do_socket: Sending If-Range: Sat, 28 Oct 2017 18:04:50 GMT
MainProcess: Thread_0: 1526995164: do_socket: Sending User-Agent: Debian APT-HTTP/1.3 (1.6.1)
MainProcess: Thread_0: 1526995164: do_socket: Sending extra Proxy-Authorization: sanitized len(577)
MainProcess: Thread_0: 1526995164: do_socket: Reading response code
MainProcess: Thread_0: 1526995164: do_socket: Response code: 200 False
MainProcess: Thread_0: 1526995164: do_socket: Reading response headers
MainProcess: Thread_0: 1526995164: do_socket: Received Date: Tue, 22 May 2018 13:19:24 GMT
MainProcess: Thread_0: 1526995164: do_socket: Received Server: Apache/2.4.18 (Ubuntu)
MainProcess: Thread_0: 1526995164: do_socket: Received Last-Modified: Sat, 28 Oct 2017 18:04:50 GMT
MainProcess: Thread_0: 1526995164: do_socket: Received ETag: "26273504-55c9f3dcdb480"
MainProcess: Thread_0: 1526995164: do_socket: Received Accept-Ranges: bytes
MainProcess: Thread_0: 1526995164: do_socket: Received Content-Length: 640103684
MainProcess: Thread_0: 1526995164: do_socket: Received Cache-Control: max-age=86400
MainProcess: Thread_0: 1526995164: do_socket: Received Keep-Alive: timeout=5, max=100
MainProcess: Thread_0: 1526995164: do_socket: Received Content-Type: application/x-debian-package
MainProcess: Thread_0: 1526995164: do_socket: Received Proxy-Connection: keep-alive
MainProcess: Thread_0: 1526995164: do_socket: Reading response data
MainProcess: Thread_0: 1526995164: do_socket: Content length 640103684

Installation through setup.py requires README.txt file

During the installation, following the instructions from README

# download master
python setup.py install

the installation breaks as it requires README.txt file which is not included in the repository.

When replacing both occurrences of the README.txt with README.md in the setup.py file, the installation was successful.

If this is the intended use, I can create the pull request.

PAC File fixes

I've just tried to use your pac file imlementation the first time, but got an Error 87 (ERROR_INVALID_PARAMETER) from WinHttpOpen (maybe related to #49 ). After some reading in the documentation, I saw that WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY is only supported on Win 8.1 and newer, but I'm using Win 7 and that's why I need WINHTTP_ACCESS_TYPE_DEFAULT_PROXY.

Also the proxies inside the pac file could also be devided by a ;, that's why I added a second replace.

--- px.py       2018-05-17 14:42:04.655400100 +0200
+++ px.py       2018-05-17 14:44:08.161400100 +0200
@@ -169,6 +169,13 @@
     Prevents logs from being overwritten on subsequent runs. Also useful if
     running multiple instances of Px""" % __version__
 
+# Windows Version
+#  6.1 = Windows 7
+#  6.2 = Windows 8
+#  6.3 = Windows 8.1
+# 10.0 = Windows 10
+WIN_VERSION = float(str(sys.getwindowsversion().major) + '.' + str(sys.getwindowsversion().minor))
+    
 # Proxy modes - source of proxy info
 MODE_NONE = 0
 MODE_CONFIG = 1
@@ -917,14 +924,20 @@
 WINHTTP_AUTO_DETECT_TYPE_DNS_A = 0x00000002
 
 # dwAccessType values
+WINHTTP_ACCESS_TYPE_DEFAULT_PROXY = 0
 WINHTTP_ACCESS_TYPE_NO_PROXY = 1
 WINHTTP_ACCESS_TYPE_NAMED_PROXY = 3
 WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY = 4
 
 def winhttp_find_proxy_for_url(url, autodetect=False, pac_url=None, autologon=True):
+    if WIN_VERSION >= 6.3:
+        ACCESS_TYPE = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY
+    else:
+        ACCESS_TYPE = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
+    
     hInternet = ctypes.windll.winhttp.WinHttpOpen(
         ctypes.wintypes.LPCWSTR("Px"),
-        WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY, WINHTTP_NO_PROXY_NAME,
+        ACCESS_TYPE, WINHTTP_NO_PROXY_NAME,
         WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC)
     if not hInternet:
         dprint("WinHttpOpen failed: " + str(ctypes.GetLastError()))
@@ -957,7 +970,7 @@
         if not proxy_info.lpszProxy:
             dprint('WinHttpGetProxyForUrl named proxy without name')
             return ""
-        return proxy_info.lpszProxy.replace(' ', ',') # Note: We only see the first!
+        return proxy_info.lpszProxy.replace(' ', ',').replace(';', ',') # Note: We only see the first!
     if proxy_info.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY:
         return "DIRECT"

NTLM authentication no longer possible

Hi,

I think the latest pre-release is no longer able to authenticate against our proxy.

This is the current log:

Process-1: MainThread: 1519632465: verify_request: Client address: 127.0.0.1
Process-1: Thread_0: 1519632465: do_CONNECT: Entering
Process-1: Thread_0: 1519632465: do_transaction: Entering
Process-1: Thread_0: 1519632465: get_response: winkerberos SSPI
Process-1: Thread_0: 1519632465: do_socket: Entering
Process-1: Thread_0: 1519632465: do_socket_connect: New connection: ('proxy.rwe.com', 8080)
Process-1: Thread_0: 1519632465: do_socket: b'CONNECT github.com:443 HTTP/1.1\r\n'
Process-1: Thread_0: 1519632465: do_socket: Sending b'Host: github.com:443\r\n'
Process-1: Thread_0: 1519632465: do_socket: Sending b'User-Agent: git/2.15.0.windows.1\r\n'
Process-1: Thread_0: 1519632465: do_socket: Sending b'Proxy-Connection: Keep-Alive\r\n'
Process-1: Thread_0: 1519632465: do_socket: Sending extra b'Proxy-Authorization: Negotiate YIGeBgYrBgEFBQKggZM... and much more... olAmCpGQrZA=\r\n'
Process-1: Thread_0: 1519632465: do_socket: Reading response code
Process-1: Thread_0: 1519632466: do_socket: Response code: 407 False
Process-1: Thread_0: 1519632466: do_socket: Reading response headers
Process-1: Thread_0: 1519632466: do_socket: Received header Proxy-Authenticate = NEGOTIATE oRUwE6AD... and much more... BgjcCAgo=
Process-1: Thread_0: 1519632466: do_socket: Received header Cache-Control = no-cache
Process-1: Thread_0: 1519632466: do_socket: Received header Pragma = no-cache
Process-1: Thread_0: 1519632466: do_socket: Received header Content-Type = text/html; charset=utf-8
Process-1: Thread_0: 1519632466: do_socket: Received header Proxy-Connection = Keep-Alive
Process-1: Thread_0: 1519632466: do_socket: Received header Connection = Keep-Alive
Process-1: Thread_0: 1519632466: do_socket: Received header Content-Length = 2549
Process-1: Thread_0: 1519632466: do_socket: Reading response data
Process-1: Thread_0: 1519632466: do_socket: Content length 2549
Process-1: Thread_0: 1519632466: do_transaction: Auth required
Process-1: Thread_0: 1519632466: do_transaction: Didn't get challenge, not NTLM proxy
Process-1: Thread_0: 1519632466: do_CONNECT: Error 407
Process-1: Thread_0: 1519632466: log_message: code 407, message Proxy Authentication Required
Process-1: Thread_0: 1519632466: log_message: "CONNECT github.com:443 HTTP/1.1" 407 -
Process-1: Thread_0: 1519632466: do_CONNECT: Transferred 0 bytes
Process-1: Thread_0: 1519632466: do_CONNECT: Done

And this is from an older 0.2 release:

Process-1: MainThread: 1519632294: verify_request: Client address: 127.0.0.1
Process-1: Thread_0: 1519632294: do_CONNECT: Entering
Process-1: Thread_0: 1519632294: do_transaction: Entering
Process-1: Thread_0: 1519632294: get_response_wkb: winkerberos SSPI
Process-1: Thread_0: 1519632294: do_socket: Entering
Process-1: Thread_0: 1519632294: do_socket: New connection
Process-1: Thread_0: 1519632294: do_socket: b'CONNECT github.com:443 HTTP/1.1\r\n'
Process-1: Thread_0: 1519632294: do_socket: Sending b'Host: github.com:443\r\n'
Process-1: Thread_0: 1519632294: do_socket: Sending b'User-Agent: git/2.15.0.windows.1\r\n'
Process-1: Thread_0: 1519632294: do_socket: Sending b'Proxy-Connection: Keep-Alive\r\n'
Process-1: Thread_0: 1519632294: do_socket: Sending extra b'Proxy-Authorization: NTLM TlRMTVNTUAABAAAAl7II4gUA... and much more... BMDY1M0dST1VQ\r\n'
Process-1: Thread_0: 1519632294: do_socket: Reading response code
Process-1: Thread_0: 1519632294: do_socket: Response code: 407 False
Process-1: Thread_0: 1519632294: do_socket: Reading response headers
Process-1: Thread_0: 1519632294: do_socket: Received header Proxy-Authenticate = NTLM TlRMTVNTUAACAAAACgAKADgAAAAV... and much more... ABwAIAPmST3zYrtMBAAAAAA==
Process-1: Thread_0: 1519632294: do_socket: Received header Cache-Control = no-cache
Process-1: Thread_0: 1519632294: do_socket: Received header Pragma = no-cache
Process-1: Thread_0: 1519632294: do_socket: Received header Content-Type = text/html; charset=utf-8
Process-1: Thread_0: 1519632294: do_socket: Received header Proxy-Connection = Keep-Alive
Process-1: Thread_0: 1519632294: do_socket: Received header Connection = Keep-Alive
Process-1: Thread_0: 1519632294: do_socket: Received header Content-Length = 2549
Process-1: Thread_0: 1519632294: do_socket: Reading response data (nobody: False)
Process-1: Thread_0: 1519632294: do_socket: Content length 2549
Process-1: Thread_0: 1519632294: do_transaction: Auth required
Process-1: Thread_0: 1519632294: do_transaction: Challenged
Process-1: Thread_0: 1519632294: get_response_wkb: winkerberos SSPI
Process-1: Thread_0: 1519632294: do_socket: Entering
Process-1: Thread_0: 1519632294: do_socket: b'CONNECT github.com:443 HTTP/1.1\r\n'
Process-1: Thread_0: 1519632294: do_socket: Sending b'Host: github.com:443\r\n'
Process-1: Thread_0: 1519632294: do_socket: Sending b'User-Agent: git/2.15.0.windows.1\r\n'
Process-1: Thread_0: 1519632294: do_socket: Sending b'Proxy-Connection: Keep-Alive\r\n'
Process-1: Thread_0: 1519632294: do_socket: Sending extra b'Proxy-Authorization: NTLM TlRMTVNTUAADAAAAGAAYAIIAAA... and much more... J2HBxQa\r\n'
Process-1: Thread_0: 1519632294: do_socket: Reading response code
Process-1: Thread_0: 1519632294: do_socket: Response code: 200 True
Process-1: Thread_0: 1519632294: do_socket: Reading response headers
Process-1: Thread_0: 1519632294: do_socket: Reading response data (nobody: True)
Process-1: Thread_0: 1519632294: do_CONNECT: Tunneling through proxy
127.0.0.1 - - [26/Feb/2018 09:04:54] "CONNECT github.com:443 HTTP/1.1" 200 -
Process-1: Thread_0: 1519632295: do_CONNECT: Transferred 6094 bytes
Process-1: Thread_0: 1519632295: do_CONNECT: Done

Any idea!? This might be related to #22.

Is there "no proxy" configuration support?

One cool feature of Cntlm (and most other proxies) is the ability to ignore certain IP addresses/ranges and hostnames/ranges. e.g., in Cntlm, I could do this:

NoProxy localhost,127.0.0.*,*.corporatenetwork.com

This is a critical feature because without it, I can't force certain IPs and hostnames to resolve locally.

winkerberos.GSSError: SSPI: InitializeSecurityContext: The token supplied to the function is invalid

I get the following error for both ca5d1fb and 26a98ba builds:

Process-1: MainThread: 1526291786: attach_console: Attaching to console 3684
Process-1: MainThread: 1526291786: parse_proxy: [('wwsgwy', 8080)]
Serving at 127.0.0.1:3128 proc Process-1
Process-1: MainThread: 1526291786: parse_config: proxy:server = wwsgwy:8080
Process-1: MainThread: 1526291786: parse_config: proxy:listen = 127.0.0.1
Process-1: MainThread: 1526291786: parse_config: proxy:port = 3128
Process-1: MainThread: 1526291786: parse_config: proxy:gateway = 0
Process-1: MainThread: 1526291786: parse_config: proxy:allow = ...
Process-1: MainThread: 1526291786: parse_config: proxy:noproxy =
Process-1: MainThread: 1526291786: parse_config: proxy:useragent =
Process-1: MainThread: 1526291786: parse_config: proxy:hostonly = 0
Process-1: MainThread: 1526291786: parse_config: settings:workers = 2
Process-1: MainThread: 1526291786: parse_config: settings:threads = 5
Process-1: MainThread: 1526291786: parse_config: settings:idle = 30
Process-1: MainThread: 1526291786: parse_config: settings:log = 0
Process-1: MainThread: 1526291786: parse_config: settings:socktimeout = 5.0
Process-1: MainThread: 1526291786: parse_config: settings:proxyreload = 60
Process-1: MainThread: 1526291786: parse_config: settings:foreground = 1
Process-1: MainThread: 1526291809: verify_request: Client address: 127.0.0.1
Process-1: Thread_0: 1526291809: do_GET: Entering
Process-1: Thread_0: 1526291809: do_GET: Path = http://hackage.haskell.org/package/ghcid-0.6.6.tar.gz
Process-1: Thread_0: 1526291809: do_transaction: Entering
Process-1: Thread_0: 1526291809: get_destination: hackage.haskell.org:80
Process-1: Thread_0: 1526291809: do_socket_connect: New connection: ('wwsgwy', 8080)
Process-1: Thread_0: 1526291809: do_proxy_type: Searching proxy type
Process-1: Thread_0: 1526291809: do_socket: Entering
Process-1: Thread_0: 1526291809: do_socket: GET http://hackage.haskell.org/package/ghcid-0.6.6.tar.gz HTTP/1.1
Process-1: Thread_0: 1526291809: do_socket: Sending User-Agent: cabal-install/1.24.0.0 (windows; i386)
Process-1: Thread_0: 1526291809: do_socket: Sending Host: hackage.haskell.org
Process-1: Thread_0: 1526291809: do_socket: Reading response code
Process-1: Thread_0: 1526291809: do_socket: Response code: 407 False
Process-1: Thread_0: 1526291809: do_socket: Reading response headers
Process-1: Thread_0: 1526291809: do_socket: Received Date: Mon, 14 May 2018 09:56:58 GMT
Process-1: Thread_0: 1526291809: do_socket: Received Content-Type: text/html
Process-1: Thread_0: 1526291809: do_socket: Received Cache-Control: no-cache
Process-1: Thread_0: 1526291809: do_socket: Received Content-Length: 3806
Process-1: Thread_0: 1526291809: do_socket: Received Proxy-Connection: Keep-Alive
Process-1: Thread_0: 1526291809: do_socket: Received Proxy-Authenticate: sanitized (4)
Process-1: Thread_0: 1526291809: do_socket: Received Proxy-Authenticate: sanitized (27)
Process-1: Thread_0: 1526291809: do_socket: Reading response data
Process-1: Thread_0: 1526291809: do_socket: Content length 3806
Process-1: Thread_0: 1526291809: do_proxy_type: Auth mechanisms: NTLM Basic realm="MWG NTLM Auth"
Process-1: Thread_0: 1526291809: do_proxy_type: Selected: {('wwsgwy', 8080): 'NTLM'}
Process-1: Thread_0: 1526291809: get_response: winkerberos SSPI
Process-1: Thread_0: 1526291809: do_socket: Entering
Process-1: Thread_0: 1526291809: do_socket: GET http://hackage.haskell.org/package/ghcid-0.6.6.tar.gz HTTP/1.1
Process-1: Thread_0: 1526291809: do_socket: Sending User-Agent: cabal-install/1.24.0.0 (windows; i386)
Process-1: Thread_0: 1526291809: do_socket: Sending Host: hackage.haskell.org
Process-1: Thread_0: 1526291809: do_socket: Sending extra Proxy-Authorization: sanitized len(77)
Process-1: Thread_0: 1526291809: do_socket: Reading response code
Process-1: Thread_0: 1526291809: do_socket: Response code: 407 False
Process-1: Thread_0: 1526291809: do_socket: Reading response headers
Process-1: Thread_0: 1526291809: do_socket: Received Date: Mon, 14 May 2018 09:56:59 GMT
Process-1: Thread_0: 1526291809: do_socket: Received Content-Type: text/html
Process-1: Thread_0: 1526291809: do_socket: Received Cache-Control: no-cache
Process-1: Thread_0: 1526291809: do_socket: Received Content-Length: 0
Process-1: Thread_0: 1526291809: do_socket: Received Proxy-Connection: Keep-Alive
Process-1: Thread_0: 1526291809: do_socket: Received Proxy-Authenticate: sanitized (69)
Process-1: Thread_0: 1526291809: do_socket: Reading response data
Process-1: Thread_0: 1526291809: do_transaction: Auth required
Process-1: Thread_0: 1526291809: do_transaction: Challenged
Process-1: Thread_0: 1526291809: get_response: winkerberos SSPI
Traceback (most recent call last):
File "px.py", line 272, in get_response
winkerberos.GSSError: SSPI: InitializeSecurityContext: The token supplied to the function is invalid

Process-1: Thread_0: 1526291809: do_transaction: Bad NTLM response
Process-1: Thread_0: 1526291809: do_GET: Error 503
Process-1: Thread_0: 1526291809: log_message: code 503, message Service Unavailable
Process-1: Thread_0: 1526291809: log_message: "GET http://hackage.haskell.org/package/ghcid-0.6.6.tar.gz HTTP/1.1" 503 -
Process-1: Thread_0: 1526291809: do_GET: Done

Px not running on startup because the wrong command is being added to windows registry

After noticing that px was not running on startup I checked the registry and found that the following command was added:

c:\users\current_user\appdata\local\programs\python\python37-32\python.exe "C:\Users\current_user\AppData\Local\Programs\Python\Python37-32\Scripts\px"

This command, however, fails when executed because the px file is an executable (not a script). It probably should be executed with the following command:

C:\Users\current_user\AppData\Local\Programs\Python\Python37-32\Scripts\px

I installed Px using pip and Python 3.7 on a Windows 7 machine.

Need ability to bind px to specific IP addresses

I run px on my laptop and connect to it from VMs running in VMware Workstation on my laptop. This works by setting gateway = 1 in px.ini. Unfortunately, I think what happens when gateway = 1 is that it binds to 0.0.0.0. Unfortunately, this is triggering Windows Firewall to block communication to the TCP listening socket when I am connected to our corporate VPN, since the VPN adapter is considered a "private" network according to domain policy.

If I could tell px to listen just on my VMware Workstation's host-only network (192.168.95.1), then I think I could avoid these Windows Firewall issues. I don't need px to act as a proxy for my laptop's host OS, just for all the VMs.

Something like a bind_ips = 192.168.95.1,127.0.0.1 setting would be perfect.

No --help output in shimed .exe (Chocolatey)

I'm currently building an internal Chocolatey environment. During creation of a px-0.3.0 package I realized that I cannot see any ouput from my shimed px.exe. Shiming is the chocolated way of putting installed programs in the PATH. To avoid cluttering of the PATH a new small .exe-File with the same name (px.exe) is generated at a location within the PATH. This exe redirects any console input/output to the original installed application outside of the PATH. Normally this works quite well, but not for px.

I think the reason is how attachConsole works!? It looks for an parant cmd/cmd.exe and attaches to this console. It will never find a parent powershell.exe, git-cmd.exe or the shimed px.exe.

Maybe the first parsecli()-Call should stick to the old fashioned way of using the console!?

Please enhance documentation regarding --install

Hi,

I wonder how Px is configured if it has been installed using "--install". Does it use the CLI parameters which have been specified together with --install or is Px expecting a config file in a certain location?

Can you please describe that in the README?

Great tool, anyway!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.