aboutsummaryrefslogtreecommitdiffstats
path: root/libmproxy
diff options
context:
space:
mode:
Diffstat (limited to 'libmproxy')
-rw-r--r--libmproxy/app.py4
-rw-r--r--libmproxy/cmdline.py4
-rw-r--r--libmproxy/flow.py40
-rw-r--r--libmproxy/protocol/__init__.py2
-rw-r--r--libmproxy/protocol/http.py6
-rw-r--r--libmproxy/protocol/primitives.py2
-rw-r--r--libmproxy/proxy/__init__.py (renamed from libmproxy/prxy/__init__.py)0
-rw-r--r--libmproxy/proxy/config.py124
-rw-r--r--libmproxy/proxy/connection.py (renamed from libmproxy/prxy/connection.py)3
-rw-r--r--libmproxy/proxy/primitives.py40
-rw-r--r--libmproxy/proxy/server.py (renamed from libmproxy/proxy.py)246
-rw-r--r--libmproxy/prxy/exception.py14
-rw-r--r--libmproxy/prxy/server.py18
13 files changed, 247 insertions, 256 deletions
diff --git a/libmproxy/app.py b/libmproxy/app.py
index 24187704..69721031 100644
--- a/libmproxy/app.py
+++ b/libmproxy/app.py
@@ -17,12 +17,12 @@ def index():
@mapp.route("/cert/pem")
def certs_pem():
- p = os.path.join(master().server.config.confdir, proxy.CONF_BASENAME + "-ca-cert.pem")
+ p = os.path.join(master().server.config.confdir, proxy.config.CONF_BASENAME + "-ca-cert.pem")
return flask.Response(open(p, "rb").read(), mimetype='application/x-x509-ca-cert')
@mapp.route("/cert/p12")
def certs_p12():
- p = os.path.join(master().server.config.confdir, proxy.CONF_BASENAME + "-ca-cert.p12")
+ p = os.path.join(master().server.config.confdir, proxy.config.CONF_BASENAME + "-ca-cert.p12")
return flask.Response(open(p, "rb").read(), mimetype='application/x-pkcs12')
diff --git a/libmproxy/cmdline.py b/libmproxy/cmdline.py
index 7950d40b..72c13769 100644
--- a/libmproxy/cmdline.py
+++ b/libmproxy/cmdline.py
@@ -1,4 +1,4 @@
-import proxy
+from . import proxy
import re, filt
import argparse
@@ -387,4 +387,4 @@ def common_options(parser):
help="Allow access to users specified in an Apache htpasswd file."
)
- proxy.ssl_option_group(parser)
+ proxy.config.ssl_option_group(parser)
diff --git a/libmproxy/flow.py b/libmproxy/flow.py
index c362465c..452fd783 100644
--- a/libmproxy/flow.py
+++ b/libmproxy/flow.py
@@ -7,13 +7,15 @@ import hashlib, Cookie, cookielib, re, threading
import os
import flask
import requests
+from . import controller, protocol
+from .protocol import http
+from .proxy.connection import ServerConnection
+from .proxy.primitives import ProxyError
import tnetstring, filt, script
-from netlib import odict, wsgi
-import controller, version, protocol
+from netlib import odict, wsgi, tcp
+import netlib.http
+import version
import app
-from .protocol import KILL
-from .protocol.http import HTTPResponse, CONTENT_MISSING
-from .proxy import RequestReplayThread
ODict = odict.ODict
ODictCaseless = odict.ODictCaseless
@@ -564,7 +566,7 @@ class FlowMaster(controller.Master):
rflow = self.server_playback.next_flow(flow)
if not rflow:
return None
- response = HTTPResponse._from_state(rflow.response._get_state())
+ response = http.HTTPResponse._from_state(rflow.response._get_state())
response.is_replay = True
if self.refresh_server_playback:
response.refresh()
@@ -641,7 +643,7 @@ class FlowMaster(controller.Master):
"""
if f.intercepting:
return "Can't replay while intercepting..."
- if f.request.content == CONTENT_MISSING:
+ if f.request.content == http.CONTENT_MISSING:
return "Can't replay request with missing content..."
if f.request:
f.request.is_replay = True
@@ -692,7 +694,7 @@ class FlowMaster(controller.Master):
err = app.serve(r, r.flow.client_conn.wfile, **{"mitmproxy.master": self})
if err:
self.add_event("Error in wsgi app. %s"%err, "error")
- r.reply(KILL)
+ r.reply(protocol.KILL)
return
f = self.state.add_request(r)
self.replacehooks.run(f)
@@ -784,3 +786,25 @@ class FilteredFlowWriter:
d = f._get_state()
tnetstring.dump(d, self.fo)
+
+class RequestReplayThread(threading.Thread):
+ name="RequestReplayThread"
+
+ def __init__(self, config, flow, masterq):
+ self.config, self.flow, self.channel = config, flow, controller.Channel(masterq)
+ threading.Thread.__init__(self)
+
+ def run(self):
+ try:
+ r = self.flow.request
+ server = ServerConnection(self.flow.server_conn.address(), None)
+ server.connect()
+ if self.flow.server_conn.ssl_established:
+ server.establish_ssl(self.config.clientcerts,
+ self.flow.server_conn.sni)
+ server.send(r._assemble())
+ self.flow.response = http.HTTPResponse.from_stream(server.rfile, r.method, body_size_limit=self.config.body_size_limit)
+ self.channel.ask("response", self.flow.response)
+ except (ProxyError, netlib.http.HttpError, tcp.NetLibError), v:
+ self.flow.error = protocol.primitives.Error(str(v))
+ self.channel.ask("error", self.flow.error) \ No newline at end of file
diff --git a/libmproxy/protocol/__init__.py b/libmproxy/protocol/__init__.py
index 392a8e3d..6200757f 100644
--- a/libmproxy/protocol/__init__.py
+++ b/libmproxy/protocol/__init__.py
@@ -1,4 +1,4 @@
-from ..prxy.server import AddressPriority
+from libmproxy.proxy.primitives import AddressPriority
KILL = 0 # const for killed requests
diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py
index 3f9668ae..77a09e61 100644
--- a/libmproxy/protocol/http.py
+++ b/libmproxy/protocol/http.py
@@ -1,8 +1,8 @@
import Cookie, urllib, urlparse, time, copy
from email.utils import parsedate_tz, formatdate, mktime_tz
-from ..prxy.connection import ServerConnection
-from ..prxy.exception import ProxyError, ConnectionTypeChange
-from ..prxy.server import AddressPriority
+from libmproxy.proxy.primitives import AddressPriority
+from ..proxy.connection import ServerConnection
+from ..proxy.primitives import ProxyError, ConnectionTypeChange
import netlib.utils
from netlib import http, tcp, http_status
from netlib.odict import ODict, ODictCaseless
diff --git a/libmproxy/protocol/primitives.py b/libmproxy/protocol/primitives.py
index 7cee074d..f2701458 100644
--- a/libmproxy/protocol/primitives.py
+++ b/libmproxy/protocol/primitives.py
@@ -1,5 +1,5 @@
from .. import stateobject, utils, version
-from ..prxy.connection import ClientConnection, ServerConnection
+from ..proxy.connection import ClientConnection, ServerConnection
import copy
diff --git a/libmproxy/prxy/__init__.py b/libmproxy/proxy/__init__.py
index e69de29b..e69de29b 100644
--- a/libmproxy/prxy/__init__.py
+++ b/libmproxy/proxy/__init__.py
diff --git a/libmproxy/proxy/config.py b/libmproxy/proxy/config.py
new file mode 100644
index 00000000..38c6ce89
--- /dev/null
+++ b/libmproxy/proxy/config.py
@@ -0,0 +1,124 @@
+import os
+from .. import utils, platform
+from netlib import http_auth, certutils
+
+
+TRANSPARENT_SSL_PORTS = [443, 8443]
+CONF_BASENAME = "mitmproxy"
+CONF_DIR = "~/.mitmproxy"
+
+
+class ProxyConfig:
+ def __init__(self, confdir=CONF_DIR, clientcerts=None,
+ no_upstream_cert=False, body_size_limit=None, reverse_proxy=None,
+ forward_proxy=None, transparent_proxy=None, authenticator=None,
+ ciphers=None, certs=None
+ ):
+ self.ciphers = ciphers
+ self.clientcerts = clientcerts
+ self.no_upstream_cert = no_upstream_cert
+ self.body_size_limit = body_size_limit
+ self.reverse_proxy = reverse_proxy
+ self.forward_proxy = forward_proxy
+ self.transparent_proxy = transparent_proxy
+ self.authenticator = authenticator
+ self.confdir = os.path.expanduser(confdir)
+ self.certstore = certutils.CertStore.from_store(self.confdir, CONF_BASENAME)
+
+
+def process_proxy_options(parser, options):
+ body_size_limit = utils.parse_size(options.body_size_limit)
+ if options.reverse_proxy and options.transparent_proxy:
+ return parser.error("Can't set both reverse proxy and transparent proxy.")
+
+ if options.transparent_proxy:
+ if not platform.resolver:
+ return parser.error("Transparent mode not supported on this platform.")
+ trans = dict(
+ resolver=platform.resolver(),
+ sslports=TRANSPARENT_SSL_PORTS
+ )
+ else:
+ trans = None
+
+ if options.reverse_proxy:
+ rp = utils.parse_proxy_spec(options.reverse_proxy)
+ if not rp:
+ return parser.error("Invalid reverse proxy specification: %s" % options.reverse_proxy)
+ else:
+ rp = None
+
+ if options.forward_proxy:
+ fp = utils.parse_proxy_spec(options.forward_proxy)
+ if not fp:
+ return parser.error("Invalid forward proxy specification: %s" % options.forward_proxy)
+ else:
+ fp = None
+
+ if options.clientcerts:
+ options.clientcerts = os.path.expanduser(options.clientcerts)
+ if not os.path.exists(options.clientcerts) or not os.path.isdir(options.clientcerts):
+ return parser.error(
+ "Client certificate directory does not exist or is not a directory: %s" % options.clientcerts
+ )
+
+ if (options.auth_nonanonymous or options.auth_singleuser or options.auth_htpasswd):
+ if options.auth_singleuser:
+ if len(options.auth_singleuser.split(':')) != 2:
+ return parser.error("Invalid single-user specification. Please use the format username:password")
+ username, password = options.auth_singleuser.split(':')
+ password_manager = http_auth.PassManSingleUser(username, password)
+ elif options.auth_nonanonymous:
+ password_manager = http_auth.PassManNonAnon()
+ elif options.auth_htpasswd:
+ try:
+ password_manager = http_auth.PassManHtpasswd(options.auth_htpasswd)
+ except ValueError, v:
+ return parser.error(v.message)
+ authenticator = http_auth.BasicProxyAuth(password_manager, "mitmproxy")
+ else:
+ authenticator = http_auth.NullProxyAuth(None)
+
+ certs = []
+ for i in options.certs:
+ parts = i.split("=", 1)
+ if len(parts) == 1:
+ parts = ["*", parts[0]]
+ parts[1] = os.path.expanduser(parts[1])
+ if not os.path.exists(parts[1]):
+ parser.error("Certificate file does not exist: %s"%parts[1])
+ certs.append(parts)
+
+ return ProxyConfig(
+ clientcerts=options.clientcerts,
+ body_size_limit=body_size_limit,
+ no_upstream_cert=options.no_upstream_cert,
+ reverse_proxy=rp,
+ forward_proxy=fp,
+ transparent_proxy=trans,
+ authenticator=authenticator,
+ ciphers=options.ciphers,
+ certs = certs,
+ )
+
+
+def ssl_option_group(parser):
+ group = parser.add_argument_group("SSL")
+ group.add_argument(
+ "--cert", dest='certs', default=[], type=str,
+ metavar = "SPEC", action="append",
+ help='Add an SSL certificate. SPEC is of the form "[domain=]path". '\
+ 'The domain may include a wildcard, and is equal to "*" if not specified. '\
+ 'The file at path is a certificate in PEM format. If a private key is included in the PEM, '\
+ 'it is used, else the default key in the conf dir is used. Can be passed multiple times.'
+ )
+ group.add_argument(
+ "--client-certs", action="store",
+ type=str, dest="clientcerts", default=None,
+ help="Client certificate directory."
+ )
+ group.add_argument(
+ "--ciphers", action="store",
+ type=str, dest="ciphers", default=None,
+ help="SSL cipher specification."
+ ) \ No newline at end of file
diff --git a/libmproxy/prxy/connection.py b/libmproxy/proxy/connection.py
index b1040c1c..3a0273af 100644
--- a/libmproxy/prxy/connection.py
+++ b/libmproxy/proxy/connection.py
@@ -1,9 +1,10 @@
import copy
import os
from .. import stateobject, utils
-from .exception import ProxyError
+from .primitives import ProxyError
from netlib import tcp, certutils
+
class ClientConnection(tcp.BaseHandler, stateobject.SimpleStateObject):
def __init__(self, client_connection, address, server):
if client_connection: # Eventually, this object is restored from state. We don't have a connection then.
diff --git a/libmproxy/proxy/primitives.py b/libmproxy/proxy/primitives.py
new file mode 100644
index 00000000..8dd0e16a
--- /dev/null
+++ b/libmproxy/proxy/primitives.py
@@ -0,0 +1,40 @@
+class ProxyError(Exception):
+ def __init__(self, code, msg, headers=None):
+ self.code, self.msg, self.headers = code, msg, headers
+
+ def __str__(self):
+ return "ProxyError(%s, %s)" % (self.code, self.msg)
+
+
+class ConnectionTypeChange(Exception):
+ """
+ Gets raised if the connection type has been changed (e.g. after HTTP/1.1 101 Switching Protocols).
+ It's up to the raising ProtocolHandler to specify the new conntype before raising the exception.
+ """
+ pass
+
+
+class ProxyServerError(Exception):
+ pass
+
+
+class AddressPriority(object):
+ """
+ Enum that signifies the priority of the given address when choosing the destination host.
+ Higher is better (None < i)
+ """
+ FORCE = 5
+ """forward mode"""
+ MANUALLY_CHANGED = 4
+ """user changed the target address in the ui"""
+ FROM_SETTINGS = 3
+ """reverse proxy mode"""
+ FROM_CONNECTION = 2
+ """derived from transparent resolver"""
+ FROM_PROTOCOL = 1
+ """derived from protocol (e.g. absolute-form http requests)"""
+
+
+class Log:
+ def __init__(self, msg):
+ self.msg = msg \ No newline at end of file
diff --git a/libmproxy/proxy.py b/libmproxy/proxy/server.py
index ccb47c26..37ec7758 100644
--- a/libmproxy/proxy.py
+++ b/libmproxy/proxy/server.py
@@ -1,73 +1,51 @@
-import os
import socket
-import threading
+from .. import version, protocol
+from libmproxy.proxy.primitives import Log
+from .primitives import ProxyServerError
+from .connection import ClientConnection, ServerConnection
+from .primitives import ProxyError, ConnectionTypeChange, AddressPriority
+from netlib import tcp
-from OpenSSL import SSL
-from .prxy.connection import ClientConnection, ServerConnection
-from .prxy.exception import ProxyError, ConnectionTypeChange
-from .prxy.server import AddressPriority
-from netlib import tcp, http, certutils, http_auth
-import utils
-import version
-import platform
-import controller
-
-
-TRANSPARENT_SSL_PORTS = [443, 8443]
-CONF_BASENAME = "mitmproxy"
-CONF_DIR = "~/.mitmproxy"
-CA_CERT_NAME = "mitmproxy-ca.pem"
-
-
-class Log:
- def __init__(self, msg):
- self.msg = msg
+class DummyServer:
+ bound = False
+ def __init__(self, config):
+ self.config = config
-class ProxyConfig:
- def __init__(self, confdir=CONF_DIR, clientcerts=None,
- no_upstream_cert=False, body_size_limit=None, reverse_proxy=None,
- forward_proxy=None, transparent_proxy=None, authenticator=None,
- ciphers=None, certs=None
- ):
- self.ciphers = ciphers
- self.clientcerts = clientcerts
- self.no_upstream_cert = no_upstream_cert
- self.body_size_limit = body_size_limit
- self.reverse_proxy = reverse_proxy
- self.forward_proxy = forward_proxy
- self.transparent_proxy = transparent_proxy
- self.authenticator = authenticator
- self.confdir = os.path.expanduser(confdir)
- self.certstore = certutils.CertStore.from_store(self.confdir, CONF_BASENAME)
+ def start_slave(self, *args):
+ pass
+ def shutdown(self):
+ pass
-from . import protocol
-from .protocol.http import HTTPResponse
+class ProxyServer(tcp.TCPServer):
+ allow_reuse_address = True
+ bound = True
+ def __init__(self, config, port, host='', server_version=version.NAMEVERSION):
+ """
+ Raises ProxyServerError if there's a startup problem.
+ """
+ self.config = config
+ self.server_version = server_version
+ try:
+ tcp.TCPServer.__init__(self, (host, port))
+ except socket.error, v:
+ raise ProxyServerError('Error starting proxy server: ' + v.strerror)
+ self.channel = None
-class RequestReplayThread(threading.Thread):
- name="RequestReplayThread"
+ def start_slave(self, klass, channel):
+ slave = klass(channel, self)
+ slave.start()
- def __init__(self, config, flow, masterq):
- self.config, self.flow, self.channel = config, flow, controller.Channel(masterq)
- threading.Thread.__init__(self)
+ def set_channel(self, channel):
+ self.channel = channel
- def run(self):
- try:
- r = self.flow.request
- server = ServerConnection(self.flow.server_conn.address(), None)
- server.connect()
- if self.flow.server_conn.ssl_established:
- server.establish_ssl(self.config.clientcerts,
- self.flow.server_conn.sni)
- server.send(r._assemble())
- self.flow.response = HTTPResponse.from_stream(server.rfile, r.method, body_size_limit=self.config.body_size_limit)
- self.channel.ask("response", self.flow.response)
- except (ProxyError, http.HttpError, tcp.NetLibError), v:
- self.flow.error = protocol.primitives.Error(str(v))
- self.channel.ask("error", self.flow.error)
+ def handle_client_connection(self, conn, client_address):
+ h = ConnectionHandler(self.config, conn, client_address, self, self.channel, self.server_version)
+ h.handle()
+ h.finish()
class ConnectionHandler:
@@ -174,7 +152,7 @@ class ConnectionHandler:
"""
Sets a new server address with the given priority.
Does not re-establish either connection or SSL handshake.
- @type priority: libmproxy.prxy.server.AddressPriority
+ @type priority: libmproxy.proxy.primitives.AddressPriority
"""
address = tcp.Address.wrap(address)
@@ -241,7 +219,7 @@ class ConnectionHandler:
raise ProxyError(502, "SSL to Client already established.")
cert, key = self.find_cert()
self.client_conn.convert_to_ssl(
- cert, key,
+ cert, key,
handle_sni = self.handle_sni,
cipher_list = self.config.ciphers
)
@@ -306,148 +284,4 @@ class ConnectionHandler:
# An unhandled exception in this method will core dump PyOpenSSL, so
# make dang sure it doesn't happen.
except Exception, e: # pragma: no cover
- pass
-
-
-class ProxyServerError(Exception):
- pass
-
-
-class ProxyServer(tcp.TCPServer):
- allow_reuse_address = True
- bound = True
- def __init__(self, config, port, host='', server_version=version.NAMEVERSION):
- """
- Raises ProxyServerError if there's a startup problem.
- """
- self.config = config
- self.server_version = server_version
- try:
- tcp.TCPServer.__init__(self, (host, port))
- except socket.error, v:
- raise ProxyServerError('Error starting proxy server: ' + v.strerror)
- self.channel = None
-
- def start_slave(self, klass, channel):
- slave = klass(channel, self)
- slave.start()
-
- def set_channel(self, channel):
- self.channel = channel
-
- def handle_client_connection(self, conn, client_address):
- h = ConnectionHandler(self.config, conn, client_address, self, self.channel, self.server_version)
- h.handle()
- h.finish()
-
-
-class DummyServer:
- bound = False
-
- def __init__(self, config):
- self.config = config
-
- def start_slave(self, *args):
- pass
-
- def shutdown(self):
- pass
-
-
-# Command-line utils
-def ssl_option_group(parser):
- group = parser.add_argument_group("SSL")
- group.add_argument(
- "--cert", dest='certs', default=[], type=str,
- metavar = "SPEC", action="append",
- help='Add an SSL certificate. SPEC is of the form "[domain=]path". '\
- 'The domain may include a wildcard, and is equal to "*" if not specified. '\
- 'The file at path is a certificate in PEM format. If a private key is included in the PEM, '\
- 'it is used, else the default key in the conf dir is used. Can be passed multiple times.'
- )
- group.add_argument(
- "--client-certs", action="store",
- type=str, dest="clientcerts", default=None,
- help="Client certificate directory."
- )
- group.add_argument(
- "--ciphers", action="store",
- type=str, dest="ciphers", default=None,
- help="SSL cipher specification."
- )
-
-
-def process_proxy_options(parser, options):
- body_size_limit = utils.parse_size(options.body_size_limit)
- if options.reverse_proxy and options.transparent_proxy:
- return parser.error("Can't set both reverse proxy and transparent proxy.")
-
- if options.transparent_proxy:
- if not platform.resolver:
- return parser.error("Transparent mode not supported on this platform.")
- trans = dict(
- resolver=platform.resolver(),
- sslports=TRANSPARENT_SSL_PORTS
- )
- else:
- trans = None
-
- if options.reverse_proxy:
- rp = utils.parse_proxy_spec(options.reverse_proxy)
- if not rp:
- return parser.error("Invalid reverse proxy specification: %s" % options.reverse_proxy)
- else:
- rp = None
-
- if options.forward_proxy:
- fp = utils.parse_proxy_spec(options.forward_proxy)
- if not fp:
- return parser.error("Invalid forward proxy specification: %s" % options.forward_proxy)
- else:
- fp = None
-
- if options.clientcerts:
- options.clientcerts = os.path.expanduser(options.clientcerts)
- if not os.path.exists(options.clientcerts) or not os.path.isdir(options.clientcerts):
- return parser.error(
- "Client certificate directory does not exist or is not a directory: %s" % options.clientcerts
- )
-
- if (options.auth_nonanonymous or options.auth_singleuser or options.auth_htpasswd):
- if options.auth_singleuser:
- if len(options.auth_singleuser.split(':')) != 2:
- return parser.error("Invalid single-user specification. Please use the format username:password")
- username, password = options.auth_singleuser.split(':')
- password_manager = http_auth.PassManSingleUser(username, password)
- elif options.auth_nonanonymous:
- password_manager = http_auth.PassManNonAnon()
- elif options.auth_htpasswd:
- try:
- password_manager = http_auth.PassManHtpasswd(options.auth_htpasswd)
- except ValueError, v:
- return parser.error(v.message)
- authenticator = http_auth.BasicProxyAuth(password_manager, "mitmproxy")
- else:
- authenticator = http_auth.NullProxyAuth(None)
-
- certs = []
- for i in options.certs:
- parts = i.split("=", 1)
- if len(parts) == 1:
- parts = ["*", parts[0]]
- parts[1] = os.path.expanduser(parts[1])
- if not os.path.exists(parts[1]):
- parser.error("Certificate file does not exist: %s"%parts[1])
- certs.append(parts)
-
- return ProxyConfig(
- clientcerts=options.clientcerts,
- body_size_limit=body_size_limit,
- no_upstream_cert=options.no_upstream_cert,
- reverse_proxy=rp,
- forward_proxy=fp,
- transparent_proxy=trans,
- authenticator=authenticator,
- ciphers=options.ciphers,
- certs = certs,
- )
+ pass \ No newline at end of file
diff --git a/libmproxy/prxy/exception.py b/libmproxy/prxy/exception.py
deleted file mode 100644
index c43a5d75..00000000
--- a/libmproxy/prxy/exception.py
+++ /dev/null
@@ -1,14 +0,0 @@
-class ProxyError(Exception):
- def __init__(self, code, msg, headers=None):
- self.code, self.msg, self.headers = code, msg, headers
-
- def __str__(self):
- return "ProxyError(%s, %s)" % (self.code, self.msg)
-
-
-class ConnectionTypeChange(Exception):
- """
- Gets raised if the connection type has been changed (e.g. after HTTP/1.1 101 Switching Protocols).
- It's up to the raising ProtocolHandler to specify the new conntype before raising the exception.
- """
- pass \ No newline at end of file
diff --git a/libmproxy/prxy/server.py b/libmproxy/prxy/server.py
deleted file mode 100644
index 441b29b4..00000000
--- a/libmproxy/prxy/server.py
+++ /dev/null
@@ -1,18 +0,0 @@
-__author__ = 'user'
-
-
-class AddressPriority(object):
- """
- Enum that signifies the priority of the given address when choosing the destination host.
- Higher is better (None < i)
- """
- FORCE = 5
- """forward mode"""
- MANUALLY_CHANGED = 4
- """user changed the target address in the ui"""
- FROM_SETTINGS = 3
- """reverse proxy mode"""
- FROM_CONNECTION = 2
- """derived from transparent resolver"""
- FROM_PROTOCOL = 1
- """derived from protocol (e.g. absolute-form http requests)""" \ No newline at end of file