mongo-python-driver icon indicating copy to clipboard operation
mongo-python-driver copied to clipboard

[PYTHON-2943] : Add socks5 proxy support

Open zaif-yuval opened this issue 1 year ago • 10 comments

zaif-yuval avatar Jan 01 '25 12:01 zaif-yuval

The required tests are specified here.

If you'd like to try running everything locally, I'd suggest something like the following:

git clone https://github.com/mongodb-labs/drivers-evergreen-tools
cd drivers-evergreen-tools
bash .evergreen/setup.sh  #  create a standalone cli for https://github.com/mongodb-labs/drivers-evergreen-tools/blob/master/.evergreen/socks5srv.py
make run-server  # start a server on 27017
./evergreen/socks5srv    # run the cli

Once you have the tests working locally, I can either help walk through the Evergreen Configuration portion, or just make commits to your branch if you prefer.

blink1073 avatar Jan 02 '25 13:01 blink1073

The required tests are specified here.

If you'd like to try running everything locally, I'd suggest something like the following:

git clone https://github.com/mongodb-labs/drivers-evergreen-tools
cd drivers-evergreen-tools
bash .evergreen/setup.sh  #  create a standalone cli for https://github.com/mongodb-labs/drivers-evergreen-tools/blob/master/.evergreen/socks5srv.py
make run-server  # start a server on 27017
./evergreen/socks5srv    # run the cli

Once you have the tests working locally, I can either help walk through the Evergreen Configuration portion, or just make commits to your branch if you prefer.

I'm not sure how to add the tests to work with proxy on your environment I will try to look into it but if you will be able to assist and push changes into this branch it will be amazing

zaif-yuval avatar Jan 06 '25 20:01 zaif-yuval

I'm not sure how to add the tests to work with proxy on your environment

I meant for local testing on your machine. If you can get the tests passing locally I can hook up the CI environment part. If you'd rather not, I understand as well.

blink1073 avatar Jan 07 '25 15:01 blink1073

I'm not sure how to add the tests to work with proxy on your environment

I meant for local testing on your machine. If you can get the tests passing locally I can hook up the CI environment part. If you'd rather not, I understand as well.

I would appreciate it, if will be able to hook it into the CI

zaif-yuval avatar Jan 08 '25 09:01 zaif-yuval

Just to clarify, are you going to try writing the tests and getting them to pass locally?

blink1073 avatar Jan 09 '25 15:01 blink1073

Just to clarify, are you going to try writing the tests and getting them to pass locally?

I am not getting to and i would love to get your help to implement the tests I have started to write the cases, I hope you will find it helpful

Let me know if it's working


from __future__ import annotations

import pytest

import pymongo
from pymongo.errors import ConnectionFailure


@pytest.mark.parametrize(
    "conn_str, should_succeed",
    [
        (
            "mongodb://localhost:12345/?proxyHost=localhost&proxyPort=1080&directConnection=true",
            False,
        ),
        (
            "mongodb://localhost:12345/?proxyHost=localhost&proxyPort=1081&directConnection=true",
            True,
        ),
        ("mongodb://replicaset/?proxyHost=localhost&proxyPort=1080", False),
        ("mongodb://replicaset/?proxyHost=localhost&proxyPort=1081", True),
        (
            "mongodb://localhost:12345/?proxyHost=localhost&proxyPort=1080&proxyUsername=nonexistentuser&proxyPassword=badauth&directConnection=true",
            False,
        ),
        (
            "mongodb://localhost:12345/?proxyHost=localhost&proxyPort=1081&proxyUsername=nonexistentuser&proxyPassword=badauth&directConnection=true",
            True,
        ),
        (
            "mongodb://replicaset/?proxyHost=localhost&proxyPort=1081&proxyUsername=nonexistentuser&proxyPassword=badauth",
            True,
        ),
        (
            "mongodb://localhost:12345/?proxyHost=localhost&proxyPort=1080&proxyUsername=username&proxyPassword=p4ssw0rd&directConnection=true",
            True,
        ),
        (
            "mongodb://localhost:12345/?proxyHost=localhost&proxyPort=1081&directConnection=true",
            True,
        ),
        (
            "mongodb://replicaset/?proxyHost=localhost&proxyPort=1080&proxyUsername=username&proxyPassword=p4ssw0rd",
            True,
        ),
        ("mongodb://replicaset/?proxyHost=localhost&proxyPort=1081", True),
    ],
)
def test_socks5_proxy_support(conn_str, should_succeed):
    client = pymongo.MongoClient(conn_str, serverSelectionTimeoutMS=1000)
    try:
        client.admin.command("hello")
        assert should_succeed, f"Connection should have failed: {conn_str}"
    except ConnectionFailure:
        assert not should_succeed, f"Connection should have succeeded: {conn_str}"
    finally:
        client.close()


@pytest.mark.parametrize(
    "conn_str, should_succeed",
    [
        (
            "mongodb://localhost:12345/?proxyHost=localhost&proxyPort=1080&directConnection=true",
            False,
        ),
        (
            "mongodb://localhost:12345/?proxyHost=localhost&proxyPort=1081&directConnection=true",
            True,
        ),
        ("mongodb://replicaset/?proxyHost=localhost&proxyPort=1080", False),
        ("mongodb://replicaset/?proxyHost=localhost&proxyPort=1081", True),
        (
            "mongodb://localhost:12345/?proxyHost=localhost&proxyPort=1080&proxyUsername=nonexistentuser&proxyPassword=badauth&directConnection=true",
            False,
        ),
        (
            "mongodb://localhost:12345/?proxyHost=localhost&proxyPort=1081&proxyUsername=nonexistentuser&proxyPassword=badauth&directConnection=true",
            True,
        ),
        (
            "mongodb://replicaset/?proxyHost=localhost&proxyPort=1081&proxyUsername=nonexistentuser&proxyPassword=badauth",
            True,
        ),
        (
            "mongodb://localhost:12345/?proxyHost=localhost&proxyPort=1080&proxyUsername=username&proxyPassword=p4ssw0rd&directConnection=true",
            True,
        ),
        (
            "mongodb://localhost:12345/?proxyHost=localhost&proxyPort=1081&directConnection=true",
            True,
        ),
        (
            "mongodb://replicaset/?proxyHost=localhost&proxyPort=1080&proxyUsername=username&proxyPassword=p4ssw0rd",
            True,
        ),
        ("mongodb://replicaset/?proxyHost=localhost&proxyPort=1081", True),
    ],
)
def test_socks5_proxy_options(conn_str, should_succeed):
    client = pymongo.MongoClient(conn_str, serverSelectionTimeoutMS=1000)
    try:
        client.admin.command("hello")
        assert should_succeed, f"Connection should have failed: {conn_str}"
    except ConnectionFailure:
        assert not should_succeed, f"Connection should have succeeded: {conn_str}"
    finally:
        client.close()


zaif-yuval avatar Jan 09 '25 15:01 zaif-yuval

Understood, thank you! I won't be able to get to this until at least next week.

blink1073 avatar Jan 09 '25 16:01 blink1073

Understood, thank you! I won't be able to get to this until at least next week.

If you will be able to do it next week it will be amazing :-)

zaif-yuval avatar Jan 09 '25 16:01 zaif-yuval

I had missed the use of the private variable _socket in proxy.connect. That argument is deprecated. It also seems like the from python_socks.sync.v2 import Proxy interface is the preferred way forward, since it is used by httpx_socks. Would you be able to make the necessary changes for the new API?

blink1073 avatar Jan 14 '25 12:01 blink1073

Another option is to switch to PySocks, which is used by requests and supports direct socket access.

blink1073 avatar Jan 14 '25 12:01 blink1073

Hi @zaif-yuval, this PR picked up some merge conflicts over time. I'm going to close it. Please feel free to re-open if you'd like to continue working on it.

blink1073 avatar Apr 07 '25 18:04 blink1073