Commit 72944400 authored by Vitaly Lipatov's avatar Vitaly Lipatov

gateway: package internal redirect service

parent e9b31e5c
...@@ -2,11 +2,11 @@ import socket ...@@ -2,11 +2,11 @@ import socket
import struct import struct
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from html import escape from html import escape
from urllib.parse import quote, parse_qs, urlparse from urllib.parse import quote
import redis import redis
import configparser import configparser
import os import ipaddress
# Чтение настроек из INI-файла # Чтение настроек из INI-файла
...@@ -19,13 +19,14 @@ def read_settings(settings_file): ...@@ -19,13 +19,14 @@ def read_settings(settings_file):
# Функция для получения оригинального адреса назначения # Функция для получения оригинального адреса назначения
def get_original_dst(sock): def get_original_dst(sock):
try: try:
# Используем SO_ORIGINAL_DST для получения оригинального адреса назначения dst = sock.getsockopt(socket.SOL_IP, 80, 16) # SO_ORIGINAL_DST
# SO_ORIGINAL_DST = 80 (для Linux) return str(ipaddress.IPv4Address(dst[4:8])), struct.unpack('!H', dst[2:4])[0]
dst = sock.getsockopt(socket.SOL_IP, 80, 16) except OSError:
ip, port = struct.unpack("!IH", dst[4:10]) try:
return f"{socket.inet_ntoa(struct.pack('!I', ip))}:{port}" dst = sock.getsockopt(socket.IPPROTO_IPV6, 80, 28) # IP6T_SO_ORIGINAL_DST
except Exception as e: return str(ipaddress.IPv6Address(dst[8:24])), struct.unpack('!H', dst[2:4])[0]
return f"Error: {e}" except OSError:
return None, None
# Кастомный обработчик HTTP-запросов # Кастомный обработчик HTTP-запросов
...@@ -34,36 +35,15 @@ class OriginalDstHandler(BaseHTTPRequestHandler): ...@@ -34,36 +35,15 @@ class OriginalDstHandler(BaseHTTPRequestHandler):
def do_GET(self): def do_GET(self):
# Получаем оригинальный адрес назначения # Получаем оригинальный адрес назначения
original_dst = get_original_dst(self.request) ip, port = get_original_dst(self.request)
if ":" in original_dst: if not ip:
ip, port = original_dst.split(":", 1) self.send_error(502, 'Original destination is unavailable')
else: return
ip, port = original_dst, "0" client_ip = self.client_address[0]
client_ip = self.headers.get('X-Forwarded-For', self.client_address[0])
# Обработка запроса на разблокировку # Обработка запроса на разблокировку
if self.path.startswith("/unban"): 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_file = '/etc/eterban/settings.ini'
settings = read_settings(settings_file) settings = read_settings(settings_file)
...@@ -73,7 +53,8 @@ class OriginalDstHandler(BaseHTTPRequestHandler): ...@@ -73,7 +53,8 @@ class OriginalDstHandler(BaseHTTPRequestHandler):
try: try:
r = redis.Redis(host=host_redis, port=6379, socket_timeout=5) 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.publish('by', f"{ip} was unblocked by {client_ip}")
r.close() r.close()
except Exception as e: except Exception as e:
...@@ -129,12 +110,20 @@ class OriginalDstHandler(BaseHTTPRequestHandler): ...@@ -129,12 +110,20 @@ class OriginalDstHandler(BaseHTTPRequestHandler):
self.wfile.write(response.encode("utf-8")) self.wfile.write(response.encode("utf-8"))
# Запуск HTTP-сервера # Запуск HTTP-сервера
def run_server(port=82): def run_server(host, port=82):
server_address = ("91.232.225.67", port) address = ipaddress.ip_address(host)
httpd = ThreadingHTTPServer(server_address, OriginalDstHandler) 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 httpd.timeout = 5
print(f"Starting server on port {port}...") print(f"Starting server on port {port}...")
httpd.serve_forever() httpd.serve_forever()
if __name__ == "__main__": 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/ ...@@ -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 755 -D gateway/usr/bin/eterban.sh %buildroot%_bindir/%name
install -m 644 gateway/usr/share/%name/*.py %buildroot%_datadir/%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/ install -m 644 common/etc/eterban/* %buildroot/etc/%name/
...@@ -88,11 +89,6 @@ install -m 644 gateway/etc/cron.hourly/* %buildroot/etc/cron.hourly/ ...@@ -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/data/www/* %buildroot%webserver_htdocsdir/%name/
install -m 644 ban-server/etc/nginx/sites-enabled.d/* %buildroot/etc/nginx/sites-enabled.d/ 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/ install -m 644 prod-server/etc/fail2ban/action.d/* %buildroot/etc/fail2ban/action.d/
cp -a prod-server/usr/share/%name/* %buildroot%_datadir/%name/ cp -a prod-server/usr/share/%name/* %buildroot%_datadir/%name/
...@@ -100,11 +96,12 @@ 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 gateway
%post_service %name %post_service %name
%post_service %name-api %post_service %name-api
%post_service %name-internal
%preun gateway %preun gateway
%preun_service %name %preun_service %name
%preun_service %name-api %preun_service %name-api
%preun_service %name-internal
%files common %files common
%config(noreplace) /etc/%name/settings.ini %config(noreplace) /etc/%name/settings.ini
...@@ -121,13 +118,13 @@ cp -a prod-server/usr/share/%name/* %buildroot%_datadir/%name/ ...@@ -121,13 +118,13 @@ cp -a prod-server/usr/share/%name/* %buildroot%_datadir/%name/
%_datadir/%name/autoban_manager.py %_datadir/%name/autoban_manager.py
%_datadir/%name/autoban_cli.py %_datadir/%name/autoban_cli.py
%_datadir/%name/eterban_api.py %_datadir/%name/eterban_api.py
%_datadir/%name/eterban_internal.py
%systemd_unitdir/eterban-api.service %systemd_unitdir/eterban-api.service
%systemd_unitdir/eterban-internal.service
%files web %files web
%webserver_htdocsdir/%name/ %webserver_htdocsdir/%name/
%webserver_htdocsdir/%name-internal/
%config(noreplace) /etc/nginx/sites-enabled.d/eterban.conf %config(noreplace) /etc/nginx/sites-enabled.d/eterban.conf
%config(noreplace) /etc/nginx/sites-available.d/eterban-internal.conf
%files fail2ban %files fail2ban
%_datadir/%name/ban.py %_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