fix(syslog_bridge): rewrite both templates with from __future__ annotations, fp socket imports, and start_fp_socket_reader
This commit is contained in:
@@ -16,7 +16,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import base64
|
import base64
|
||||||
import binascii
|
import binascii
|
||||||
|
import json as _json
|
||||||
|
import os as _os
|
||||||
import re
|
import re
|
||||||
|
import socket as _socket
|
||||||
|
import threading as _threading
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
@@ -223,16 +227,12 @@ def extract_form_credentials(
|
|||||||
if "=" not in pair:
|
if "=" not in pair:
|
||||||
continue
|
continue
|
||||||
k, _, v = pair.partition("=")
|
k, _, v = pair.partition("=")
|
||||||
# urllib decode without importing urllib at module scope (the
|
|
||||||
# template emitters are import-cost-sensitive). Inline the
|
|
||||||
# tiny percent-decode + plus-decode.
|
|
||||||
try:
|
try:
|
||||||
from urllib.parse import unquote_plus
|
from urllib.parse import unquote_plus
|
||||||
key = unquote_plus(k).lower()
|
key = unquote_plus(k).lower()
|
||||||
val = unquote_plus(v)
|
val = unquote_plus(v)
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
# First-wins so duplicate-key forms don't get clobbered.
|
|
||||||
fields.setdefault(key, val)
|
fields.setdefault(key, val)
|
||||||
|
|
||||||
principal: Optional[str] = None
|
principal: Optional[str] = None
|
||||||
@@ -262,3 +262,56 @@ def write_syslog_file(line: str) -> None:
|
|||||||
def forward_syslog(line: str, log_target: str) -> None:
|
def forward_syslog(line: str, log_target: str) -> None:
|
||||||
"""No-op stub. TCP forwarding is handled by rsyslog, not by service containers."""
|
"""No-op stub. TCP forwarding is handled by rsyslog, not by service containers."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# ─── Caddy fingerprint socket reader ─────────────────────────────────────────
|
||||||
|
|
||||||
|
_FP_BUF = 65536
|
||||||
|
|
||||||
|
|
||||||
|
def _fp_socket_reader(node_name: str, service_name: str, log_target: str) -> None:
|
||||||
|
sock_path = _os.environ.get("DECNET_FP_SOCK", "/run/decnet/fp.sock")
|
||||||
|
try:
|
||||||
|
sock = _socket.socket(_socket.AF_UNIX, _socket.SOCK_DGRAM)
|
||||||
|
sock.bind(sock_path)
|
||||||
|
except OSError:
|
||||||
|
return
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
data = sock.recv(_FP_BUF)
|
||||||
|
record = _json.loads(data)
|
||||||
|
except (OSError, ValueError):
|
||||||
|
continue
|
||||||
|
kind = record.get("kind", "")
|
||||||
|
remote = record.get("remote_addr", "-")
|
||||||
|
if kind == "h2_settings":
|
||||||
|
ln = syslog_line(
|
||||||
|
service_name, node_name, "http2_settings", SEVERITY_INFO,
|
||||||
|
remote_addr=remote,
|
||||||
|
settings=_json.dumps(record.get("settings", {})),
|
||||||
|
frame_order=_json.dumps(record.get("frame_order", [])),
|
||||||
|
)
|
||||||
|
write_syslog_file(ln)
|
||||||
|
if log_target:
|
||||||
|
forward_syslog(ln, log_target)
|
||||||
|
elif kind == "http_request":
|
||||||
|
ln = syslog_line(
|
||||||
|
service_name, node_name, "http_request_fingerprint", SEVERITY_INFO,
|
||||||
|
remote_addr=remote,
|
||||||
|
proto=record.get("proto_tag", "-"),
|
||||||
|
headers_ordered=_json.dumps(record.get("headers_ordered", [])),
|
||||||
|
cookie=record.get("cookie", ""),
|
||||||
|
accept_language=record.get("accept_language", ""),
|
||||||
|
)
|
||||||
|
write_syslog_file(ln)
|
||||||
|
if log_target:
|
||||||
|
forward_syslog(ln, log_target)
|
||||||
|
|
||||||
|
|
||||||
|
def start_fp_socket_reader(node_name: str, service_name: str, log_target: str) -> None:
|
||||||
|
t = _threading.Thread(
|
||||||
|
target=_fp_socket_reader,
|
||||||
|
args=(node_name, service_name, log_target),
|
||||||
|
daemon=True,
|
||||||
|
)
|
||||||
|
t.start()
|
||||||
|
|||||||
@@ -16,7 +16,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import base64
|
import base64
|
||||||
import binascii
|
import binascii
|
||||||
|
import json as _json
|
||||||
|
import os as _os
|
||||||
import re
|
import re
|
||||||
|
import socket as _socket
|
||||||
|
import threading as _threading
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
@@ -66,7 +70,7 @@ def syslog_line(
|
|||||||
Return a single RFC 5424-compliant syslog line (no trailing newline).
|
Return a single RFC 5424-compliant syslog line (no trailing newline).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
service: APP-NAME (e.g. "http", "mysql")
|
service: APP-NAME (e.g. "http", "ssh")
|
||||||
hostname: HOSTNAME (node name)
|
hostname: HOSTNAME (node name)
|
||||||
event_type: MSGID (e.g. "request", "login_attempt")
|
event_type: MSGID (e.g. "request", "login_attempt")
|
||||||
severity: Syslog severity integer (default: INFO=6)
|
severity: Syslog severity integer (default: INFO=6)
|
||||||
@@ -223,16 +227,12 @@ def extract_form_credentials(
|
|||||||
if "=" not in pair:
|
if "=" not in pair:
|
||||||
continue
|
continue
|
||||||
k, _, v = pair.partition("=")
|
k, _, v = pair.partition("=")
|
||||||
# urllib decode without importing urllib at module scope (the
|
|
||||||
# template emitters are import-cost-sensitive). Inline the
|
|
||||||
# tiny percent-decode + plus-decode.
|
|
||||||
try:
|
try:
|
||||||
from urllib.parse import unquote_plus
|
from urllib.parse import unquote_plus
|
||||||
key = unquote_plus(k).lower()
|
key = unquote_plus(k).lower()
|
||||||
val = unquote_plus(v)
|
val = unquote_plus(v)
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
# First-wins so duplicate-key forms don't get clobbered.
|
|
||||||
fields.setdefault(key, val)
|
fields.setdefault(key, val)
|
||||||
|
|
||||||
principal: Optional[str] = None
|
principal: Optional[str] = None
|
||||||
@@ -262,3 +262,56 @@ def write_syslog_file(line: str) -> None:
|
|||||||
def forward_syslog(line: str, log_target: str) -> None:
|
def forward_syslog(line: str, log_target: str) -> None:
|
||||||
"""No-op stub. TCP forwarding is handled by rsyslog, not by service containers."""
|
"""No-op stub. TCP forwarding is handled by rsyslog, not by service containers."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# ─── Caddy fingerprint socket reader ─────────────────────────────────────────
|
||||||
|
|
||||||
|
_FP_BUF = 65536
|
||||||
|
|
||||||
|
|
||||||
|
def _fp_socket_reader(node_name: str, service_name: str, log_target: str) -> None:
|
||||||
|
sock_path = _os.environ.get("DECNET_FP_SOCK", "/run/decnet/fp.sock")
|
||||||
|
try:
|
||||||
|
sock = _socket.socket(_socket.AF_UNIX, _socket.SOCK_DGRAM)
|
||||||
|
sock.bind(sock_path)
|
||||||
|
except OSError:
|
||||||
|
return
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
data = sock.recv(_FP_BUF)
|
||||||
|
record = _json.loads(data)
|
||||||
|
except (OSError, ValueError):
|
||||||
|
continue
|
||||||
|
kind = record.get("kind", "")
|
||||||
|
remote = record.get("remote_addr", "-")
|
||||||
|
if kind == "h2_settings":
|
||||||
|
ln = syslog_line(
|
||||||
|
service_name, node_name, "http2_settings", SEVERITY_INFO,
|
||||||
|
remote_addr=remote,
|
||||||
|
settings=_json.dumps(record.get("settings", {})),
|
||||||
|
frame_order=_json.dumps(record.get("frame_order", [])),
|
||||||
|
)
|
||||||
|
write_syslog_file(ln)
|
||||||
|
if log_target:
|
||||||
|
forward_syslog(ln, log_target)
|
||||||
|
elif kind == "http_request":
|
||||||
|
ln = syslog_line(
|
||||||
|
service_name, node_name, "http_request_fingerprint", SEVERITY_INFO,
|
||||||
|
remote_addr=remote,
|
||||||
|
proto=record.get("proto_tag", "-"),
|
||||||
|
headers_ordered=_json.dumps(record.get("headers_ordered", [])),
|
||||||
|
cookie=record.get("cookie", ""),
|
||||||
|
accept_language=record.get("accept_language", ""),
|
||||||
|
)
|
||||||
|
write_syslog_file(ln)
|
||||||
|
if log_target:
|
||||||
|
forward_syslog(ln, log_target)
|
||||||
|
|
||||||
|
|
||||||
|
def start_fp_socket_reader(node_name: str, service_name: str, log_target: str) -> None:
|
||||||
|
t = _threading.Thread(
|
||||||
|
target=_fp_socket_reader,
|
||||||
|
args=(node_name, service_name, log_target),
|
||||||
|
daemon=True,
|
||||||
|
)
|
||||||
|
t.start()
|
||||||
|
|||||||
Reference in New Issue
Block a user