win-test-relay/udp_relay.py

91 lines
3.5 KiB
Python

#Copyright (C) © 2024 Philipp Wagner
#This program comes with ABSOLUTELY NO WARRANTY.
#This is free software, and you are welcome to redistribute it
#under certain conditions; type 'show c' for details.
import socket
import threading
import time
import argparse
import hashlib
# Konfigurationsparameter
LOOPBACK_TIMEOUT = 1 # Zeit in Sekunden, um Loopback zu verhindern
# Speichert gesendete Nachrichten-Hashes für eine kurze Zeit, um Loopback zu verhindern
recent_messages = {}
def create_socket(port, bind_ip=''):
"""Erstellt und konfiguriert den UDP-Socket zum Lauschen auf Broadcast-Nachrichten."""
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.bind((bind_ip, port))
return sock
def hash_message(message):
"""Erzeugt einen Hash-Wert für eine Nachricht."""
return hashlib.sha256(message).hexdigest()
def should_forward_message(message):
"""Überprüft, ob eine Nachricht innerhalb des Zeitlimits bereits gesendet wurde."""
current_time = time.time()
message_hash = hash_message(message)
# Entferne alte Nachrichten
for msg_hash in list(recent_messages):
if current_time - recent_messages[msg_hash] > LOOPBACK_TIMEOUT:
del recent_messages[msg_hash]
if message_hash in recent_messages:
print(f"Message already forwarded recently: {message}")
return False
recent_messages[message_hash] = current_time
return True
def relay_messages(listen_ip, listen_port, relay_ip, relay_port):
sock = create_socket(listen_port, listen_ip)
print(f"Listening for UDP broadcasts on {listen_ip}:{listen_port}...")
while True:
data, addr = sock.recvfrom(1024) # Puffergröße 1024 Bytes
print(f"Received message on {listen_ip}:{listen_port} from {addr}: {data}")
# Prüfen, ob die Nachricht mit "RCVDPKT: \"TELNET\" \"\" \"DX de", "GAB:" oder "SpotUdp" beginnt
if (data.startswith(b'RCVDPKT: "TELNET" "" "DX de') or data.startswith(b'GAB:') or data.startswith(b'SpotUdp')):
if should_forward_message(data):
print(f"Forwarding message to {relay_ip}:{relay_port}")
relay_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
relay_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
relay_socket.sendto(data, (relay_ip, relay_port))
relay_socket.close()
else:
print(f"Skipped forwarding message due to recent forwarding: {data}")
def main():
parser = argparse.ArgumentParser(description="Bidirektionales UDP-Relay mit zeitbasierter Loopback-Prüfung")
parser.add_argument('--ip1', type=str, required=True, help='Erste IP-Adresse')
parser.add_argument('--port1', type=int, required=True, help='Erster Port')
parser.add_argument('--ip2', type=str, required=True, help='Zweite IP-Adresse')
parser.add_argument('--port2', type=int, required=True, help='Zweiter Port')
args = parser.parse_args()
ip1 = args.ip1
port1 = args.port1
ip2 = args.ip2
port2 = args.port2
# Starten von zwei Threads für bidirektionales Relay mit zeitbasierter Loopback-Prüfung
thread1 = threading.Thread(target=relay_messages, args=(ip1, port1, ip2, port2))
thread2 = threading.Thread(target=relay_messages, args=(ip2, port2, ip1, port1))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
if __name__ == "__main__":
main()