91 lines
3.5 KiB
Python
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()
|