summaryrefslogtreecommitdiffstats
path: root/iv/orodja/waf/waf.py
blob: 701b4ddf60ae1c0ca6c19f2b8c8bc08e00b3b6c6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/usr/bin/python3
import asyncio
import os
import ssl
import re

def manyregex (string, patterns):
	for pattern in patterns:
		if re.search(pattern, string) != None:
			return True
	return False

async def cevovod (reader, writer, writer2, compiled):
	buffer = b''
	while True:
		prebral = await reader.read(65536)
		buffer += prebral
		if manyregex(buffer, compiled):
			break ## hacker detected
		if len(buffer) > 65536:
			buffer = buffer[-32768:]
		if len(prebral) == 0:
			break
		writer.write(prebral)
	writer.close()
	writer2.close()

async def handle_client (reader, writer):
	try:
		compiled = []
		reflags = re.ASCII | re.MULTILINE | re.DOTALL | re.VERBOSE
		with open(os.getenv("WAF_REGEXES"), "rb") as rulesfile:
			regexes = rulesfile.read().split(b"\n")
			for regex in regexes:
				if len(regex) == 0:
					continue
				compiled.append(re.compile(regex, reflags))
		write_to_backend = b''
		if os.getenv("WAF_HTTP"):
			headers = []
			while True:
				line = (await reader.readuntil(b'\n')).replace(b'\r', b'').replace(b'\n', b'')
				if not line.lower().startswith(b"accept-encoding:"):
					write_to_backend += line + b"\r\n"
				if len(line) == 0:
					break
				headers.append(line)
			if headers[0].startswith(b"GET /waf HTTP/"):
				writer.write(b"HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\nwaf works (: PID " + str(os.getpid()).encode() + b"\r\n")
				writer.close()
				return
		context = None
		if os.getenv("WAF_TLS"):
			context = ssl.create_default_context()
			context.check_hostname = False
			context.verify_mode = ssl.CERT_NONE
		backendr, backendw = await asyncio.open_connection(os.getenv("WAF_BACKEND_HOST"), os.getenv("WAF_BACKEND_PORT"), ssl=context)
		if manyregex(write_to_backend, compiled):
			writer.write(b'HTTP/1.0 469 Hacking\r\nContent-Type: text/plain\r\n\r\nHacking is illegal according to ZEKom-2.\r\n')
			backendw.close() ## hacker
			writer.close()
			return
		backendw.write(write_to_backend)
	except Exception as e:
		writer.write(b"HTTP/1.0 569 Exception\r\nContent-Type: text/plain\r\n\r\n")
		writer.write(str(e).encode())
		writer.write(b"\r\n")
		backendw.close()
		writer.close()
		raise e
	else:
		event_loop = asyncio.get_event_loop()
		event_loop.create_task(cevovod(reader, backendw, writer, compiled))
		event_loop.create_task(cevovod(backendr, writer, backendw, compiled))

async def run_server ():
	context = None
	if os.getenv("WAF_TLS"):
		context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
		context.load_cert_chain(certfile=os.getenv("WAF_TLS"), keyfile=os.getenv("WAF_TLS_KEY"))
	server = await asyncio.start_server(handle_client, os.getenv("WAF_LISTEN_ADDR"), os.getenv("WAF_LISTEN_PORT"), ssl=context)
	async with server:
		await server.serve_forever()

asyncio.run(run_server())