cloudOnFire/main.py
2021-04-04 17:52:01 +02:00

167 lines
5.9 KiB
Python

import os
import re
import time
import requests
from urllib.parse import urlparse, urlsplit
from http.server import HTTPServer, BaseHTTPRequestHandler
from subprocess import Popen, PIPE
import ssl
import threading
class CFProxy(BaseHTTPRequestHandler):
TOKEN_HEADER = 'H-Token'
TOKEN_VALUE = 'agfjkewjkfvasfhgkzuc'
HOST_HEADER = 'H-Host'
IP_HEADER = 'H-IP'
PROXY_HOST = "blue-wind-f1c2.grogu.workers.dev" # "proxy.grogu.ml"
UA = "User Agent"
FAKE_IP = "1.1.1.1"
PROXY = None
cakey = 'ca.key'
cacert = 'ca.crt'
certkey = 'cert.key'
certdir = 'certs/'
lock = threading.Lock()
def __init__(self, *args):
self.session = requests.Session()
self.session.proxies.update({'https': self.PROXY,
'http': self.PROXY})
self.session.headers.update({'User-Agent': self.UA,
self.TOKEN_HEADER: self.TOKEN_VALUE})
self.proxy_host = self.PROXY_HOST
self.fake_ip = self.FAKE_IP
BaseHTTPRequestHandler.__init__(self, *args)
def do_GET_old(self):
url = self.path
print("[GET] "+url)
req = self.get(url)
self.send_response(req.status_code)
self.end_headers()
self.wfile.write(req.text.encode())
def do_CONNECT(self):
hostname = self.path.split(':')[0]
certpath = "%s/%s.crt" % (self.certdir.rstrip('/'), hostname)
with self.lock:
if not os.path.isfile(certpath):
epoch = "%d" % (time.time() * 1000)
p1 = Popen(["openssl", "req", "-new", "-key", self.certkey, "-subj", "/CN=%s" % hostname], stdout=PIPE)
p2 = Popen(["openssl", "x509", "-req", "-days", "3650", "-CA", self.cacert, "-CAkey", self.cakey, "-set_serial", epoch, "-out", certpath], stdin=p1.stdout, stderr=PIPE)
p2.communicate()
#self.wfile.write(("%s %d %s\r\n" % (self.protocol_version, 200, 'Connection Established')).encode())
self.send_response(200, 'Connection Established')
self.end_headers()
self.connection = ssl.wrap_socket(self.connection, keyfile=self.certkey, certfile=certpath, server_side=True)
self.rfile = self.connection.makefile("rb", self.rbufsize)
self.wfile = self.connection.makefile("wb", self.wbufsize)
conntype = self.headers.get('Proxy-Connection', '')
if self.protocol_version == "HTTP/1.1" and conntype.lower() != 'close':
self.close_connection = 0
else:
self.close_connection = 1
print("[CON OK]")
def request_handler(self, req, req_body):
pass
def response_handler(self, req, req_body, res, res_body):
pass
def filter_headers(self, headers):
# http://tools.ietf.org/html/rfc2616#section-13.5.1
hop_by_hop = ('connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization', 'te', 'trailers', 'transfer-encoding', 'upgrade')
for k in hop_by_hop:
del headers[k]
# accept only supported encodings
if 'Accept-Encoding' in headers:
ae = headers['Accept-Encoding']
filtered_encodings = [x for x in re.split(r',\s*', ae) if x in ('identity', 'gzip', 'x-gzip', 'deflate')]
headers['Accept-Encoding'] = ', '.join(filtered_encodings)
return headers
def do_ALL(self):
if self.path == 'http://127.0.0.1/':
self.send_cacert()
return
req = self
content_length = int(req.headers.get('Content-Length', 0))
req_body = self.rfile.read(content_length) if content_length else None
if req.path[0] == '/':
if isinstance(self.connection, ssl.SSLSocket):
req.path = "https://%s%s" % (req.headers['Host'], req.path)
else:
req.path = "http://%s%s" % (req.headers['Host'], req.path)
req_body_modified = self.request_handler(req, req_body)
if req_body_modified is False:
self.send_error(403)
return
elif req_body_modified is not None:
req_body = req_body_modified
req.headers['Content-length'] = str(len(req_body))
u = urlsplit(req.path)
scheme, netloc, path = u.scheme, u.netloc, (u.path + '?' + u.query if u.query else u.path)
assert scheme in ('http', 'https')
if netloc:
req.headers['Host'] = netloc
setattr(req, 'headers', self.filter_headers(req.headers))
res = self.get(req.path)
self.send_response(res.status_code)
self.end_headers()
self.wfile.write(res.text.encode())
do_GET = do_ALL
do_POST = do_ALL # wont work, because we drop the body...
def send_cacert(self):
with open(self.cacert, 'rb') as f:
data = f.read()
self.wfile.write("%s %d %s\r\n" % (self.protocol_version, 200, 'OK'))
self.send_header('Content-Type', 'application/x-x509-ca-cert')
self.send_header('Content-Length', len(data))
self.send_header('Connection', 'close')
self.end_headers()
self.wfile.write(data)
def get(self, url, **kwargs):
return self.handleReq('GET', url, **kwargs)
def post(self, url, **kwargs):
return self.handleReq('POST', url, **kwargs)
def handleReq(self, method, url, **kwargs):
# Gestion des headers
if 'headers' in kwargs:
for k, v in kwargs.get('headers'):
self.session.headers.update({k: v})
kwargs.pop('headers')
parsed_uri = urlparse(url)
self.session.headers.update({self.HOST_HEADER: parsed_uri.hostname})
self.session.headers.update({self.IP_HEADER: self.fake_ip})
proxyfied_url = '{0}://{1}{2}'.format(parsed_uri.scheme, self.proxy_host, parsed_uri.path)
return self.session.request(method, proxyfied_url, **kwargs)
PORT = 9097
httpd = HTTPServer(('', PORT), CFProxy)
print ("[i] Now serving at " + str(PORT))
httpd.serve_forever()