2012-02-23 02:52:01 +00:00
# Copyright (C) 2012 Aldo Cortesi
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2011-03-12 01:30:12 +00:00
import proxy
2012-08-17 17:04:39 +00:00
import re , filt
2012-12-30 09:41:58 +00:00
import argparse
2012-03-17 04:20:34 +00:00
2012-08-18 12:14:16 +00:00
class ParseException ( Exception ) : pass
2012-03-17 04:20:34 +00:00
class OptionException ( Exception ) : pass
2012-08-18 12:14:16 +00:00
def _parse_hook ( s ) :
sep , rem = s [ 0 ] , s [ 1 : ]
parts = rem . split ( sep , 2 )
if len ( parts ) == 2 :
patt = " .* "
a , b = parts
elif len ( parts ) == 3 :
patt , a , b = parts
else :
raise ParseException ( " Malformed hook specifier - too few clauses: %s " % s )
if not a :
raise ParseException ( " Empty clause: %s " % str ( patt ) )
if not filt . parse ( patt ) :
raise ParseException ( " Malformed filter pattern: %s " % patt )
return patt , a , b
2012-03-17 04:20:34 +00:00
def parse_replace_hook ( s ) :
"""
Returns a ( pattern , regex , replacement ) tuple .
The general form for a replacement hook is as follows :
/ patt / regex / replacement
The first character specifies the separator . Example :
: ~ q : foo : bar
If only two clauses are specified , the pattern is set to match
universally ( i . e . " .* " ) . Example :
/ foo / bar /
Clauses are parsed from left to right . Extra separators are taken to be
part of the final clause . For instance , the replacement clause below is
" foo/bar/ " :
/ one / two / foo / bar /
Checks that pattern and regex are both well - formed . Raises
2012-08-18 12:14:16 +00:00
ParseException on error .
2012-03-17 04:20:34 +00:00
"""
2012-08-18 12:14:16 +00:00
patt , regex , replacement = _parse_hook ( s )
2012-03-17 04:20:34 +00:00
try :
re . compile ( regex )
except re . error , e :
2012-08-18 12:14:16 +00:00
raise ParseException ( " Malformed replacement regex: %s " % str ( e . message ) )
return patt , regex , replacement
2012-03-17 04:20:34 +00:00
2012-08-18 12:14:16 +00:00
def parse_setheader ( s ) :
"""
Returns a ( pattern , header , value ) tuple .
The general form for a replacement hook is as follows :
/ patt / header / value
The first character specifies the separator . Example :
: ~ q : foo : bar
If only two clauses are specified , the pattern is set to match
universally ( i . e . " .* " ) . Example :
/ foo / bar /
Clauses are parsed from left to right . Extra separators are taken to be
part of the final clause . For instance , the value clause below is
" foo/bar/ " :
/ one / two / foo / bar /
Checks that pattern and regex are both well - formed . Raises
ParseException on error .
"""
return _parse_hook ( s )
2011-03-12 01:30:12 +00:00
def get_common_options ( options ) :
2011-03-20 04:31:54 +00:00
stickycookie , stickyauth = None , None
2012-06-26 07:56:47 +00:00
if options . stickycookie_filt :
2011-03-12 02:14:25 +00:00
stickycookie = options . stickycookie_filt
2011-03-20 04:31:54 +00:00
2012-06-26 07:56:47 +00:00
if options . stickyauth_filt :
2011-03-20 04:31:54 +00:00
stickyauth = options . stickyauth_filt
2012-03-17 04:20:34 +00:00
reps = [ ]
for i in options . replace :
try :
p = parse_replace_hook ( i )
2012-08-18 12:14:16 +00:00
except ParseException , e :
2012-03-17 04:20:34 +00:00
raise OptionException ( e . message )
reps . append ( p )
for i in options . replace_file :
try :
patt , rex , path = parse_replace_hook ( i )
2012-08-18 12:14:16 +00:00
except ParseException , e :
2012-03-17 04:20:34 +00:00
raise OptionException ( e . message )
try :
v = open ( path , " r " ) . read ( )
except IOError , e :
raise OptionException ( " Could not read replace file: %s " % path )
reps . append ( ( patt , rex , v ) )
2012-08-18 12:14:16 +00:00
setheaders = [ ]
for i in options . setheader :
try :
p = parse_setheader ( i )
except ParseException , e :
raise OptionException ( e . message )
setheaders . append ( p )
2011-03-12 01:30:12 +00:00
return dict (
2011-05-13 22:44:25 +00:00
anticache = options . anticache ,
2011-07-15 03:21:04 +00:00
anticomp = options . anticomp ,
2011-05-13 22:44:25 +00:00
client_replay = options . client_replay ,
2011-07-23 00:57:54 +00:00
eventlog = options . eventlog ,
2011-05-13 22:44:25 +00:00
kill = options . kill ,
no_server = options . no_server ,
refresh_server_playback = not options . norefresh ,
rheaders = options . rheaders ,
2011-05-14 23:54:12 +00:00
rfile = options . rfile ,
2012-03-17 04:20:34 +00:00
replacements = reps ,
2012-08-18 12:14:16 +00:00
setheaders = setheaders ,
2011-03-12 01:30:12 +00:00
server_replay = options . server_replay ,
2011-08-03 01:20:36 +00:00
script = options . script ,
2011-03-12 01:30:12 +00:00
stickycookie = stickycookie ,
2011-03-20 04:31:54 +00:00
stickyauth = stickyauth ,
2011-05-13 22:44:25 +00:00
wfile = options . wfile ,
verbosity = options . verbose ,
2012-03-05 09:05:11 +00:00
nopop = options . nopop ,
2011-03-12 01:30:12 +00:00
)
def common_options ( parser ) :
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-03-12 01:30:12 +00:00
" -a " ,
2012-08-17 17:04:39 +00:00
action = " store " , type = str , dest = " addr " , default = ' ' ,
2011-03-12 01:30:12 +00:00
help = " Address to bind proxy to (defaults to all interfaces) "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-08-03 01:20:36 +00:00
" --anticache " ,
action = " store_true " , dest = " anticache " , default = False ,
help = " Strip out request headers that might cause the server to return 304-not-modified. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-08-03 01:20:36 +00:00
" --confdir " ,
2012-08-17 17:04:39 +00:00
action = " store " , type = str , dest = " confdir " , default = ' ~/.mitmproxy ' ,
2011-08-03 01:20:36 +00:00
help = " Configuration directory. (~/.mitmproxy) "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-07-23 00:57:54 +00:00
" -e " ,
action = " store_true " , dest = " eventlog " ,
help = " Show event log. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-05-13 22:44:25 +00:00
" -n " ,
action = " store_true " , dest = " no_server " ,
help = " Don ' t start a proxy server. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-03-12 01:30:12 +00:00
" -p " ,
2012-08-17 17:04:39 +00:00
action = " store " , type = int , dest = " port " , default = 8080 ,
2011-03-12 01:30:12 +00:00
help = " Proxy service port. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2012-04-04 02:17:26 +00:00
" -P " ,
2012-02-18 01:45:22 +00:00
action = " store " , dest = " reverse_proxy " , default = None ,
2012-02-18 03:27:09 +00:00
help = " Reverse proxy to upstream server: http[s]://host[:port] "
2012-02-16 14:33:27 +00:00
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-03-12 01:30:12 +00:00
" -q " ,
action = " store_true " , dest = " quiet " ,
help = " Quiet. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-05-14 23:54:12 +00:00
" -r " ,
action = " store " , dest = " rfile " , default = None ,
help = " Read flows from file. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-08-03 01:20:36 +00:00
" -s " ,
action = " store " , dest = " script " , default = None ,
help = " Run a script. "
2011-03-12 01:30:12 +00:00
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-03-12 01:30:12 +00:00
" -t " ,
action = " store " , dest = " stickycookie_filt " , default = None , metavar = " FILTER " ,
help = " Set sticky cookie filter. Matched against requests. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2012-06-26 08:08:24 +00:00
" -T " ,
action = " store_true " , dest = " transparent_proxy " , default = False ,
help = " Set transparent proxy mode. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-03-20 04:31:54 +00:00
" -u " ,
action = " store " , dest = " stickyauth_filt " , default = None , metavar = " FILTER " ,
help = " Set sticky auth filter. Matched against requests. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-03-12 01:30:12 +00:00
" -v " ,
action = " count " , dest = " verbose " , default = 1 ,
help = " Increase verbosity. Can be passed multiple times. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-03-12 01:30:12 +00:00
" -w " ,
action = " store " , dest = " wfile " , default = None ,
help = " Write flows to file. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-07-15 03:21:04 +00:00
" -z " ,
2011-07-17 02:36:38 +00:00
action = " store_true " , dest = " anticomp " , default = False ,
2011-07-15 03:21:04 +00:00
help = " Try to convince servers to send us un-compressed data. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
2011-09-09 05:31:36 +00:00
" -Z " ,
action = " store " , dest = " body_size_limit " , default = None ,
metavar = " SIZE " ,
help = " Byte size limit of HTTP request and response bodies. " \
" Understands k/m/g suffixes, i.e. 3m for 3 megabytes. "
)
2012-08-17 17:04:39 +00:00
parser . add_argument (
" --cert-wait-time " , type = float ,
2012-02-27 02:05:45 +00:00
action = " store " , dest = " cert_wait_time " , default = 0 ,
help = " Wait for specified number of seconds after a new cert is generated. This can smooth over small discrepancies between the client and server times. "
)
2012-08-18 12:14:16 +00:00
2012-08-17 17:04:39 +00:00
parser . add_argument (
2012-07-03 10:56:25 +00:00
" --no-upstream-cert " , default = False ,
action = " store_true " , dest = " no_upstream_cert " ,
help = " Don ' t connect to upstream server to look up certificate details. "
2012-02-27 02:05:45 +00:00
)
2012-08-17 17:04:39 +00:00
group = parser . add_argument_group ( " Client Replay " )
group . add_argument (
2011-03-12 01:30:12 +00:00
" -c " ,
action = " store " , dest = " client_replay " , default = None , metavar = " PATH " ,
help = " Replay client requests from a saved file. "
)
2012-08-17 17:04:39 +00:00
group = parser . add_argument_group ( " Server Replay " )
group . add_argument (
2011-08-03 01:20:36 +00:00
" -S " ,
2011-03-12 01:30:12 +00:00
action = " store " , dest = " server_replay " , default = None , metavar = " PATH " ,
help = " Replay server responses from a saved file. "
)
2012-08-17 17:04:39 +00:00
group . add_argument (
2011-03-12 01:30:12 +00:00
" -k " ,
action = " store_true " , dest = " kill " , default = False ,
help = " Kill extra requests during replay. "
)
2012-08-17 17:04:39 +00:00
group . add_argument (
2011-03-12 01:30:12 +00:00
" --rheader " ,
2012-08-17 17:04:39 +00:00
action = " append " , dest = " rheaders " , type = str ,
2011-03-12 01:30:12 +00:00
help = " Request headers to be considered during replay. "
" Can be passed multiple times. "
)
2012-08-17 17:04:39 +00:00
group . add_argument (
2011-03-12 01:30:12 +00:00
" --norefresh " ,
action = " store_true " , dest = " norefresh " , default = False ,
help = " Disable response refresh, "
" which updates times in cookies and headers for replayed responses. "
)
2012-08-17 17:04:39 +00:00
group . add_argument (
2012-03-05 09:05:11 +00:00
" --no-pop " ,
action = " store_true " , dest = " nopop " , default = False ,
2012-03-05 09:56:03 +00:00
help = " Disable response pop from response flow. "
2012-03-05 09:05:11 +00:00
" This makes it possible to replay same response multiple times. "
)
2012-03-17 04:20:34 +00:00
2012-08-17 17:04:39 +00:00
group = parser . add_argument_group (
2012-03-17 04:20:34 +00:00
" Replacements " ,
"""
Replacements are of the form " /pattern/regex/replacement " , where
the separator can be any character . Please see the documentation
for more information .
""" .strip()
)
2012-08-17 17:04:39 +00:00
group . add_argument (
2012-03-17 04:20:34 +00:00
" --replace " ,
2012-08-17 17:04:39 +00:00
action = " append " , type = str , dest = " replace " , default = [ ] ,
2012-03-17 04:20:34 +00:00
metavar = " PATTERN " ,
help = " Replacement pattern. "
)
2012-08-17 17:04:39 +00:00
group . add_argument (
2012-03-17 04:20:34 +00:00
" --replace-from-file " ,
2012-08-17 17:04:39 +00:00
action = " append " , type = str , dest = " replace_file " , default = [ ] ,
2012-08-18 12:14:16 +00:00
metavar = " PATH " ,
2012-03-17 04:20:34 +00:00
help = " Replacement pattern, where the replacement clause is a path to a file. "
)
2011-03-12 01:30:12 +00:00
2012-08-18 12:14:16 +00:00
group = parser . add_argument_group (
" Set Headers " ,
"""
Header specifications are of the form " /pattern/header/value " ,
where the separator can be any character . Please see the
documentation for more information .
""" .strip()
)
2012-08-17 17:13:56 +00:00
group . add_argument (
2012-08-18 12:14:16 +00:00
" --setheader " ,
action = " append " , type = str , dest = " setheader " , default = [ ] ,
metavar = " PATTERN " ,
help = " Header set pattern. "
2012-08-06 21:09:35 +00:00
)
2012-12-30 09:41:58 +00:00
group = parser . add_argument_group (
" Proxy Authentication " ,
"""
2013-01-02 04:35:44 +00:00
Specify which users are allowed to access the proxy and the method
used for authenticating them . These options are ignored if the
proxy is in transparent or reverse proxy mode .
"""
2012-12-30 09:41:58 +00:00
)
user_specification_group = group . add_mutually_exclusive_group ( )
user_specification_group . add_argument (
" --nonanonymous " ,
action = " store_true " , dest = " auth_nonanonymous " ,
2013-01-02 04:35:44 +00:00
help = " Allow access to any user long as a credentials are specified. "
2012-12-30 09:41:58 +00:00
)
user_specification_group . add_argument (
" --singleuser " ,
action = " store " , dest = " auth_singleuser " , type = str ,
2013-01-02 04:35:44 +00:00
metavar = " USER " ,
help = " Allows access to a a single user, specified in the form username:password. "
2012-12-30 09:41:58 +00:00
)
user_specification_group . add_argument (
" --htpasswd " ,
action = " store " , dest = " auth_htpasswd " , type = argparse . FileType ( ' r ' ) ,
2013-01-02 04:35:44 +00:00
metavar = " PATH " ,
2012-12-30 09:41:58 +00:00
help = " Allow access to users specified in an Apache htpasswd file. "
)
2011-03-12 01:30:12 +00:00
proxy . certificate_option_group ( parser )