Commit 72944400 authored by Vitaly Lipatov's avatar Vitaly Lipatov

gateway: package internal redirect service

parent e9b31e5c
......@@ -2,11 +2,11 @@ import socket
import struct
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from html import escape
from urllib.parse import quote, parse_qs, urlparse
from urllib.parse import quote
import redis
import configparser
import os
import ipaddress
# Чтение настроек из INI-файла
......@@ -19,13 +19,14 @@ def read_settings(settings_file):
# Функция для получения оригинального адреса назначения
def get_original_dst(sock):
try:
# Используем SO_ORIGINAL_DST для получения оригинального адреса назначения
# SO_ORIGINAL_DST = 80 (для Linux)
dst = sock.getsockopt(socket.SOL_IP, 80, 16)
ip, port = struct.unpack("!IH", dst[4:10])
return f"{socket.inet_ntoa(struct.pack('!I', ip))}:{port}"
except Exception as e:
return f"Error: {e}"
dst = sock.getsockopt(socket.SOL_IP, 80, 16) # SO_ORIGINAL_DST
return str(ipaddress.IPv4Address(dst[4:8])), struct.unpack('!H', dst[2:4])[0]
except OSError:
try:
dst = sock.getsockopt(socket.IPPROTO_IPV6, 80, 28) # IP6T_SO_ORIGINAL_DST
return str(ipaddress.IPv6Address(dst[8:24])), struct.unpack('!H', dst[2:4])[0]
except OSError:
return None, None
# Кастомный обработчик HTTP-запросов
......@@ -34,36 +35,15 @@ class OriginalDstHandler(BaseHTTPRequestHandler):
def do_GET(self):
# Получаем оригинальный адрес назначения
original_dst = get_original_dst(self.request)
if ":" in original_dst:
ip, port = original_dst.split(":", 1)
else:
ip, port = original_dst, "0"
client_ip = self.headers.get('X-Forwarded-For', self.client_address[0])
ip, port = get_original_dst(self.request)
if not ip:
self.send_error(502, 'Original destination is unavailable')
return
client_ip = self.client_address[0]
# Обработка запроса на разблокировку
if self.path.startswith("/unban"):
# Извлекаем IP из параметра запроса
query = urlparse(self.path).query
params = parse_qs(query)
target_ip = params.get("ip", [None])[0]
# Получаем предыдущий адрес (HTTP_REFERER)
#old_addr = self.headers.get('Referer', '')
if not target_ip:
response_message = "No IP provided for unban."
# Возвращаем ответ
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(response_message.encode("utf-8"))
return
# Читаем настройки из файла
settings_file = '/etc/eterban/settings.ini'
settings = read_settings(settings_file)
......@@ -73,7 +53,8 @@ class OriginalDstHandler(BaseHTTPRequestHandler):
try:
r = redis.Redis(host=host_redis, port=6379, socket_timeout=5)
r.publish('unban', ip)
if r.publish('unban', ip) < 1:
raise redis.RedisError('no Redis subscribers')
r.publish('by', f"{ip} was unblocked by {client_ip}")
r.close()
except Exception as e:
......@@ -129,12 +110,20 @@ class OriginalDstHandler(BaseHTTPRequestHandler):
self.wfile.write(response.encode("utf-8"))
# Запуск HTTP-сервера
def run_server(port=82):
server_address = ("91.232.225.67", port)
httpd = ThreadingHTTPServer(server_address, OriginalDstHandler)
def run_server(host, port=82):
address = ipaddress.ip_address(host)
if isinstance(address, ipaddress.IPv6Address):
class IPv6ThreadingHTTPServer(ThreadingHTTPServer):
address_family = socket.AF_INET6
server_class = IPv6ThreadingHTTPServer
else:
server_class = ThreadingHTTPServer
server_address = (str(address), port)
httpd = server_class(server_address, OriginalDstHandler)
httpd.timeout = 5
print(f"Starting server on port {port}...")
httpd.serve_forever()
if __name__ == "__main__":
run_server()
settings = read_settings('/etc/eterban/settings.ini')
run_server(settings['ban_server'])
......@@ -79,6 +79,7 @@ mkdir -p %buildroot/etc/nginx/sites-enabled.d/
install -m 755 -D gateway/usr/bin/eterban.sh %buildroot%_bindir/%name
install -m 644 gateway/usr/share/%name/*.py %buildroot%_datadir/%name/
install -m 755 ban-internal-server/data/www/int2.py %buildroot%_datadir/%name/eterban_internal.py
install -m 644 common/etc/eterban/* %buildroot/etc/%name/
......@@ -88,11 +89,6 @@ install -m 644 gateway/etc/cron.hourly/* %buildroot/etc/cron.hourly/
install -m 644 ban-server/data/www/* %buildroot%webserver_htdocsdir/%name/
install -m 644 ban-server/etc/nginx/sites-enabled.d/* %buildroot/etc/nginx/sites-enabled.d/
mkdir -p %buildroot%webserver_htdocsdir/%name-internal/
mkdir -p %buildroot/etc/nginx/sites-available.d/
install -m 644 ban-internal-server/data/www/* %buildroot%webserver_htdocsdir/%name-internal/
install -m 644 ban-internal-server/etc/nginx/sites-enabled.d/eterban.conf %buildroot/etc/nginx/sites-available.d/eterban-internal.conf
install -m 644 prod-server/etc/fail2ban/action.d/* %buildroot/etc/fail2ban/action.d/
cp -a prod-server/usr/share/%name/* %buildroot%_datadir/%name/
......@@ -100,11 +96,12 @@ cp -a prod-server/usr/share/%name/* %buildroot%_datadir/%name/
%post gateway
%post_service %name
%post_service %name-api
%post_service %name-internal
%preun gateway
%preun_service %name
%preun_service %name-api
%preun_service %name-internal
%files common
%config(noreplace) /etc/%name/settings.ini
......@@ -121,13 +118,13 @@ cp -a prod-server/usr/share/%name/* %buildroot%_datadir/%name/
%_datadir/%name/autoban_manager.py
%_datadir/%name/autoban_cli.py
%_datadir/%name/eterban_api.py
%_datadir/%name/eterban_internal.py
%systemd_unitdir/eterban-api.service
%systemd_unitdir/eterban-internal.service
%files web
%webserver_htdocsdir/%name/
%webserver_htdocsdir/%name-internal/
%config(noreplace) /etc/nginx/sites-enabled.d/eterban.conf
%config(noreplace) /etc/nginx/sites-available.d/eterban-internal.conf
%files fail2ban
%_datadir/%name/ban.py
......
[Unit]
Description=Eterban internal redirect page
After=network.target redis.service
[Service]
Type=simple
ExecStart=/usr/share/eterban/eterban_internal.py
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment