Skip to content

Commit

Permalink
Merge ba6ed17 into 26292fb
Browse files Browse the repository at this point in the history
  • Loading branch information
david415 committed Jun 1, 2016
2 parents 26292fb + ba6ed17 commit 330e9d6
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 6 deletions.
7 changes: 5 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,18 @@ def run(self):
"platforms": ["any"],

"package_dir": {"": "src"},
"packages": ["foolscap", "foolscap.slicers", "foolscap.logging",
"packages": ["twisted.plugins", "foolscap", "foolscap.slicers", "foolscap.logging",
"foolscap.appserver", "foolscap.test"],
"entry_points": {"console_scripts": [
"flogtool = foolscap.logging.cli:run_flogtool",
"flappserver = foolscap.appserver.cli:run_flappserver",
"flappclient = foolscap.appserver.client:run_flappclient",
] },
"cmdclass": commands,
"install_requires": ["twisted[tls] >= 16.0.0", "pyOpenSSL"],
"install_requires": ["twisted[tls] >= 16.0.0", "pyOpenSSL", "txsocksx"],
"extras_require": {
'socks': ['txsocksx',],
}
}

if __name__ == "__main__":
Expand Down
45 changes: 43 additions & 2 deletions src/foolscap/connection_plugins.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@

import re
from zope.interface import implementer
from twisted.internet import endpoints
from twisted.plugin import IPlugin

from foolscap.ipb import IConnectionHintHandler, InvalidHintError


try:
import txsocksx
except ImportError:
txsocksx = None

class PluginDependencyNotLoaded(Exception):
"""
PluginDependencyNotLoaded is raised when a plugin is instantiated
and a dependency is missing.
"""

# This can match IPv4 IP addresses + port numbers *or* host names +
# port numbers.
DOTTED_QUAD_RESTR=r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
Expand All @@ -11,6 +26,8 @@
DNS_NAME_RESTR))
NEW_STYLE_HINT_RE=re.compile(r"^tcp:(%s|%s):(\d+){1,5}$" % (DOTTED_QUAD_RESTR,
DNS_NAME_RESTR))
ANY_HINT_RE=re.compile(r"^[^:]*:(%s|%s):(\d+){1,5}$" % (DOTTED_QUAD_RESTR,
DNS_NAME_RESTR))

# Each location hint must start with "TYPE:" (where TYPE is alphanumeric) and
# then can contain any characters except "," and "/". These are expected to
Expand Down Expand Up @@ -42,8 +59,8 @@ def convert_legacy_hint(location):
return "tcp:%s:%d" % (host, port)
return location

@implementer(IConnectionHintHandler)
class DefaultTCP:
@implementer(IConnectionHintHandler, IPlugin)
class DefaultTCP(object):
def hint_to_endpoint(self, hint, reactor):
# Return (endpoint, hostname), where "hostname" is what we pass to the
# HTTP "Host:" header so a dumb HTTP server can be used to redirect us.
Expand All @@ -52,3 +69,27 @@ def hint_to_endpoint(self, hint, reactor):
raise InvalidHintError("unrecognized TCP hint")
host, port = mo.group(1), int(mo.group(2))
return endpoints.HostnameEndpoint(reactor, host, port), host

@implementer(IConnectionHintHandler, IPlugin)
class SOCKS5(object):
def __init__(self, endpoint=None, proxy_endpoint_factory=None):
if txsocksx is None:
raise PluginDependencyNotLoaded("""SOCKS5 foolscap client transport plugin requires txsocksx.\n
If you are using a Python virtual env you can simply: pip install txsocksx;\n
Debian users can install via the APT repo: apt-get install txsocksx;\n""")
self.proxy_endpoint_factory = proxy_endpoint_factory
self.proxy_endpoint_desc = endpoint
self.proxy_endpoint = None

def hint_to_endpoint(self, hint, reactor):
if self.proxy_endpoint_factory is not None:
self.proxy_endpoint = self.proxy_endpoint_factory()
else:
if self.proxy_endpoint is None:
self.proxy_endpoint = endpoints.clientFromString(reactor, self.proxy_endpoint_desc)

mo = ANY_HINT_RE.search(hint)
if not mo:
raise InvalidHintError("Invalid SOCKS5 client connection hint")
host, port = mo.group(1), int(mo.group(2))
return txsocksx.client.SOCKS5ClientEndpoint(host, port, self.proxy_endpoint), host
38 changes: 36 additions & 2 deletions src/foolscap/test/test_connection.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,49 @@

from txsocksx.client import SOCKS5ClientEndpoint
from txsocksx.test.util import FakeEndpoint

from zope.interface import implementer
from twisted.trial import unittest
from twisted.internet import endpoints
from twisted.internet import endpoints, reactor
from twisted.application import service
from foolscap.api import Tub
from foolscap.connection import get_endpoint
from foolscap.connection_plugins import convert_legacy_hint, DefaultTCP
from foolscap.connection_plugins import convert_legacy_hint, DefaultTCP, SOCKS5
from foolscap.tokens import NoLocationHintsError
from foolscap.test.common import (certData_low, certData_high, Target,
ShouldFailMixin)
from foolscap import ipb, util

class SocksPluginTests(unittest.TestCase):
def test_defaultFactory(self):
def SocksEndpointGenerator():
return FakeEndpoint()
plugin = SOCKS5(endpoint = "tcp:127.0.0.1:9050", proxy_endpoint_factory = SocksEndpointGenerator)
hint = "tor:meowhost:80"
endpoint, host = plugin.hint_to_endpoint(hint, reactor)

self.failUnlessEqual("meowhost", host)
self.failUnless(isinstance(endpoint, SOCKS5ClientEndpoint))

endpoint.connect(None)
# equivalent to the TestSOCKS5ClientEndpoint.test_defaultFactory test-case.
self.assertEqual(endpoint.proxyEndpoint.transport.value(), '\x05\x01\x00')

def test_override(self):
SocksEndpointGenerator = lambda: FakeEndpoint()
ep, host = get_endpoint("tcp:meowhost:80", {"tcp": SOCKS5(
endpoint = "tcp:127.0.0.1:9050", proxy_endpoint_factory=SocksEndpointGenerator)})
self.failUnless(isinstance(ep, SOCKS5ClientEndpoint), ep)
self.failUnlessEqual(host, "meowhost")

def test_invalid(self):
SocksEndpointGenerator = lambda: FakeEndpoint()
hint = "tcp:meowhost80"
self.failUnlessRaises(ipb.InvalidHintError,
get_endpoint, hint, {"tcp": SOCKS5(
endpoint = "tcp:127.0.0.1:9050", proxy_endpoint_factory=SocksEndpointGenerator
)})

class Convert(unittest.TestCase):
def checkTCPEndpoint(self, hint, expected_host, expected_port):
ep, host = get_endpoint(hint, {"tcp": DefaultTCP()})
Expand Down
3 changes: 3 additions & 0 deletions src/twisted/plugins/load_transport_plugins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import foolscap
tcpTransportPlugin = foolscap.DefaultTCP()
socksTransportPlugin = foolscap.SOCKS5()

0 comments on commit 330e9d6

Please sign in to comment.