80 lines
3.7 KiB
Python
80 lines
3.7 KiB
Python
|
#!/usr/bin/env python2
|
||
|
import os.path as path
|
||
|
import time
|
||
|
from distutils.util import strtobool
|
||
|
|
||
|
|
||
|
class Module:
|
||
|
def __init__(self, incoming=False, verbose=False, options=None):
|
||
|
# extract the file name from __file__. __file__ is proxymodules/name.py
|
||
|
self.name = path.splitext(path.basename(__file__))[0]
|
||
|
self.description = 'Change HTTP responses of a certain size to 404.'
|
||
|
self.incoming = incoming # incoming means module is on -im chain
|
||
|
self.size = 2392 # if a response has this value as content-length, it will become a 404
|
||
|
self.verbose = False
|
||
|
self.custom = False
|
||
|
self.rewriteall = False # will we block the first occurence?
|
||
|
self.firstfound = False # have we found the first occurence yet?
|
||
|
self.resetinterval = None # if we haven't found a fitting response in this many seconds, reset the state and set first to False again
|
||
|
self.timer = time.time()
|
||
|
if options is not None:
|
||
|
if 'size' in options.keys():
|
||
|
try:
|
||
|
self.size = int(options['size'])
|
||
|
except ValueError:
|
||
|
pass # use the default if you can't parse the parameter
|
||
|
if 'verbose' in options.keys():
|
||
|
self.verbose = bool(strtobool(options['verbose']))
|
||
|
if 'custom' in options.keys():
|
||
|
try:
|
||
|
with open(options['custom'], 'rb') as handle:
|
||
|
self.custom = handle.read()
|
||
|
except Exception:
|
||
|
print('Can\'t open custom error file, not using it.')
|
||
|
self.custom = False
|
||
|
if 'rewriteall' in options.keys():
|
||
|
self.rewriteall = bool(strtobool(options['rewriteall']))
|
||
|
if 'reset' in options.keys():
|
||
|
try:
|
||
|
self.resetinterval = float(options['reset'])
|
||
|
except ValueError:
|
||
|
pass # use the default if you can't parse the parameter
|
||
|
|
||
|
def execute(self, data):
|
||
|
contentlength = b'content-length: ' + bytes(str(self.size), 'ascii')
|
||
|
if data.startswith(b'HTTP/1.1 200 OK') and contentlength in data.lower():
|
||
|
if self.resetinterval is not None:
|
||
|
t = time.time()
|
||
|
if t - self.timer >= self.resetinterval:
|
||
|
if self.verbose:
|
||
|
print('Timer elapsed')
|
||
|
self.firstfound = False
|
||
|
self.timer = t
|
||
|
if self.rewriteall is False and self.firstfound is False:
|
||
|
# we have seen this response size for the first time and are not blocking the first one
|
||
|
self.firstfound = True
|
||
|
if self.verbose:
|
||
|
print('Letting this response through')
|
||
|
return data
|
||
|
if self.custom is not False:
|
||
|
data = self.custom
|
||
|
if self.verbose:
|
||
|
print('Replaced response with custom response')
|
||
|
else:
|
||
|
data = data.replace(b'200 OK', b'404 Not Found', 1)
|
||
|
if self.verbose:
|
||
|
print('Edited return code')
|
||
|
return data
|
||
|
|
||
|
def help(self):
|
||
|
h = '\tsize: if a response has this value as content-length, it will become a 404\n'
|
||
|
h += ('\tverbose: print a message if a string is replaced\n'
|
||
|
'\tcustom: path to a file containing a custom response, will replace the received response\n'
|
||
|
'\trewriteall: if set, it will rewrite all responses. Default is to let the first on through'
|
||
|
'\treset: number of seconds after which we will reset the state and will let the next response through.')
|
||
|
return h
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
print('This module is not supposed to be executed alone!')
|