Permalink
Browse files

Initial stub for proxy

  • Loading branch information...
0 parents commit 6a74d82362e0ba10397691d21b595e06c93a78c0 @Jc2k Jc2k committed May 11, 2012
@@ -0,0 +1,7 @@
+.installed.cfg
+bin/
+develop-eggs/
+eggs/
+parts/
+*.egg-info
+*.pyc
@@ -0,0 +1,64 @@
+badgerproxy
+===========
+
+This is a HTTP proxy that supports content rewriting of HTTP and HTTPS traffic
+that passes through. Note that rewriting HTTPS obviously means SSL is stripped
+and reapplied. The SSL certificate that is used to reencrypt will be invalid.
+
+There are 2 ways to set up a development environment. You can use buildout::
+
+ $ python bootstrap.py
+ $ bin/buildout
+
+A ``badgerproxy`` and ``badgerproxyctl`` script will be created in the bin/
+directory.
+
+You can also use virtualenv::
+
+ $ virtualenv --no-site-packages .
+ $ source ./bin/active
+ $ python setup.py develop
+
+
+To run a server in foreground::
+
+ $ badgerproxy -c badger-sample start -n
+
+``badger-sample`` is a Yay file in the root of the repository that contains a
+description of which services and triggers to start with the main service. It
+looks something like this::
+
+ socket: /var/local/badgerproxy/var/badgerproxy.sock
+
+ services:
+ - listen: localhost:8084
+ methods:
+ allowed:
+ - HEAD
+ - POST
+ - GET
+ - CONECT
+
+ ports:
+ allowed:
+ - 80
+ - 443
+
+ rewriter:
+ cls: badgerproxy.rewriting.waraningbanner
+ image: https://www.myhost.com/images/banner.gif
+
+ - listen: localhost:8084
+ methods:
+ allowed:
+ - CONNECT
+
+ ports:
+ allowed:
+ - 22
+
+
+To dynamically add an allowed URL::
+
+ $ badgerproxyctl -s /var/local/badgerproxy/var/badgerproxy.sock add-dns www.wibble.com 4.4.4.4 60
+
@@ -0,0 +1,33 @@
+socket: /tmp/badgerproxy.sock
+pidfile: /tmp/badgerpoxy.pid
+resolvercache: /tmp/badgerproxy.resolvercache
+
+services:
+ - listen: localhost:8084
+ methods:
+ allowed:
+ - HEAD
+ - POST
+ - GET
+ - CONECT
+
+ ports:
+ allowed:
+ - 80
+ - 443
+
+ rewriter:
+ cls: badgerproxy.rewriting.waraningbanner
+ height: 20px
+ image: https://www.myhost.com/images/banner.gif
+
+
+ - listen: localhost:8085
+ methods:
+ allowed:
+ - CONNECT
+
+ ports:
+ allowed:
+ - 22
+
No changes.
@@ -0,0 +1,38 @@
+# Copyright 2012 Isotoma Limited
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from twisted.application.service import MultiService
+
+from .pb import PbService
+from .dns import Resolver
+from .proxy import ProxyService
+
+class BadgerProxy(MultiService):
+
+ def __init__(self, config=None):
+ MultiService.__init__(self)
+ self.config = config
+
+ self.pb = PbService(self.config['socket'])
+ self.setServiceParent(self)
+
+ self.resolver = Resolver(self.config['resolver-cache'])
+ self.setServiceParent(self)
+
+ self.services = []
+ for service in self.config['services']:
+ p = ProxyService(service)
+ p.setServiceParent(self)
+ self.services.append(p)
+
@@ -0,0 +1,56 @@
+# Copyright 2012 Isotoma Limited
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import shelve
+import datetime
+
+
+from twisted.application.service import Service
+from twisted.internet import task
+from twisted.python import log
+
+
+class Resolver(Service):
+
+ interval = 60 * 5
+
+ def __init__(self, cachepath):
+ self.domains = shelve.load(cachepath)
+ self._expire_task = task.LoopingCall(self.expire)
+
+ def add_dns(self, domain, ip, ttl):
+ delta = datetime.timedelta(0, 0, ttl)
+ expires = datetime.datetime.now() + delta
+ log.msg("Adding '%s' -> %s, will espire at %s" % (domain, ip, expires))
+ self.domains[domain] = (ip, expires)
+
+ def remove_dns(self, domain):
+ log.msg("Removing domain entry for: '%s'" % domain)
+ del self.domains[domain]
+
+ def expire(self):
+ now = datetime.datetime.now()
+ for k, v in self.domains.items():
+ if v[1] < now:
+ self.remove_dns(domain)
+
+ def startService(self):
+ Service.startService(self):
+ self._expire_task.start(self.interval, now=True)
+
+ def stopService(self):
+ Service.stopService(self)
+ if self._expire_task.running:
+ self._expire_task.stop()
+
@@ -0,0 +1,70 @@
+# Copyright 2012 Isotoma Limited
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from optparse import OptionParser
+
+from zope.interface import implements
+
+from twisted.spread import pb
+from twisted.cred.portal import IRealm, Portal
+from twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse
+from twisted.internet import reactor
+from twisted.cred.credentials import UsernamePassword
+from twisted.application import strports, service
+
+
+class PbPerspective(pb.Avatar):
+
+ def __init__(self, badgerproxy):
+ self.badgerproxy = badgerproxy
+
+ def perspective_add_dns(self, domain, ip, ttl):
+ t = self.badgerproxy.resolver.add_domain(domain, ip, ttl)
+
+ def logout(self):
+ pass
+
+
+class PbRealm(object):
+
+ implements(IRealm)
+
+ def __init__(self, badgerproxy):
+ self.badgerproxy = badgerproxy
+
+ def requestAvatar(self, avatarId, mind, *interfaces):
+ if pb.IPerspective in interfaces:
+ avatar = PbPerspective(self.badgerproxy)
+ return pb.IPerspective, avatar, avatar.logout
+ raise NotImplementedError("no interface")
+
+
+class PbService(service.Service):
+
+ def __init__(self, socket):
+ service.Service.__init__(self)
+ self.socket = socket
+
+ def setServiceParent(self, parent):
+ service.Service.__init__(self, parent)
+
+ portal = Portal(PbRealm(parent))
+
+ checker = InMemoryUsernamePasswordDatabaseDontUse()
+ checker.addUser("guest", "guest")
+ portal.registerChecker(checker)
+
+ service = strports.service("unix:%s" % socket, pb.PBServerFactory(portal))
+ service.setServiceParent(self)
+
Oops, something went wrong.

0 comments on commit 6a74d82

Please sign in to comment.