[Twisted-Python] Trying to proxy through multiple IPs

Erik Wickstrom erik at erikwickstrom.com
Tue Nov 4 00:06:50 MST 2008


Hi all,

I'm trying to write a proxy server that accepts connections on
multiple ports, and depending on the port, using a different IP for
the outgoing connection.  My code works except that adding additional
reactor.listenTCP(...)s overwrite the IP of the previous listenTCPs.
So the proxy accepts connections on all the desired ports, but only
uses the last IP address for outgoing connections.

The ip (bindIP) is somehow being overwritten.  Based on advice from
IRC (exarkun --thanks!), I've tried a couple attempts at using
closures to solve the problem, but non of my implementations have done
the trick.

Can anyone see any other changes that might get this working?

# Also pasted at http://dpaste.com/88623/ incase of email garbling...

#from twisted.web import proxy, http

import urlparse
from urllib import quote as urlquote

from twisted.internet import reactor
from twisted.internet.protocol import ClientFactory
from twisted.web.resource import Resource
from twisted.web.server import NOT_DONE_YET
from twisted.web.http import HTTPClient, Request, HTTPChannel
from twisted.web.proxy import ProxyClient, ProxyClientFactory
from twisted.web import http
from twisted.internet import reactor
from twisted.python import log
import sys
log.startLogging(sys.stdout)



class ProxyRequest(Request):
    """
    Used by Proxy to implement a simple web proxy.

    @ivar reactor: the reactor used to create connections.
    @type reactor: object providing L{twisted.internet.interfaces.IReactorTCP}
    """

    protocols = {'http': ProxyClientFactory}
    ports = {'http': 80}

    def __init__(self, channel, queued, reactor=reactor):
        Request.__init__(self, channel, queued)
        self.reactor = reactor


    def process(self):
        parsed = urlparse.urlparse(self.uri)
        protocol = parsed[0]
        host = parsed[1]
        port = self.ports[protocol]
        if ':' in host:
            host, port = host.split(':')
            port = int(port)
        rest = urlparse.urlunparse(('', '') + parsed[2:])
        if not rest:
            rest = rest + '/'
        class_ = self.protocols[protocol]
        headers = self.getAllHeaders().copy()
        if 'host' not in headers:
            headers['host'] = host
        self.content.seek(0, 0)
        s = self.content.read()
        clientFactory = class_(self.method, rest, self.clientproto, headers,
                               s, self)
        self.reactor.connectTCP(host, port, clientFactory,
bindAddress=(self.bindIP,0))

class Proxy(HTTPChannel):
    requestFactory = ProxyRequest

class ProxyFactory(http.HTTPFactory):
    def class_factory(self, bindIP):
        def closure(ip):
            klass2 = ProxyRequest
            setattr(klass2, 'bindIP', ip)
            return klass2
        klass = Proxy
        setattr(klass, 'requestFactory', closure(bindIP))
        return klass

    def __init__(self, ip):
        http.HTTPFactory.__init__(self)
        self.ip = ip
        #self.protocol = proxy.Proxy
        self.protocol = self.class_factory(ip)


reactor.listenTCP(8080, ProxyFactory('192.168.168.101'),
interface="192.168.168.1")

reactor.listenTCP(8081, ProxyFactory('192.168.168.102'),
interface="192.168.168.1")
reactor.run()


##
Thanks!
Erik




More information about the Twisted-Python mailing list