update hotspot_proxy, update map template

This commit is contained in:
KF7EEL 2021-10-29 17:06:32 -07:00
parent 5dbca3aca7
commit a5d9fb5d5c
5 changed files with 218 additions and 76 deletions

View File

@ -72,6 +72,9 @@ from datetime import datetime
import re import re
from socket import gethostbyname from socket import gethostbyname
from setproctitle import setproctitle
# Does anybody read this stuff? There's a PEP somewhere that says I should do this. # Does anybody read this stuff? There's a PEP somewhere that says I should do this.
@ -285,26 +288,94 @@ def download_config(L_CONFIG_FILE, cli_file):
# From hotspot_proxy2, FreeDMR # From hotspot_proxy2, FreeDMR
def hotspot_proxy(listen_port, port_start, port_stop): def hotspot_proxy(listen_port, port_start, port_stop):
## Master = "127.0.0.1"
## ListenPort = listen_port
## DestportStart = port_start
## DestPortEnd = port_stop
## Timeout = 30
## Stats = True
## Debug = False
## BlackList = [1234567]
##
##
## CONNTRACK = {}
##
## for port in range(DestportStart,DestPortEnd+1,1):
## CONNTRACK[port] = False
##
##
## reactor.listenUDP(ListenPort,Proxy(Master,ListenPort,CONNTRACK,BlackList,Timeout,Debug,DestportStart,DestPortEnd))
##
## def loopingErrHandle(failure):
## logger.error('(GLOBAL) STOPPING REACTOR TO AVOID MEMORY LEAK: Unhandled error innowtimed loop.\n {}'.format(failure))
## reactor.stop()
##
## def stats():
## count = 0
## nowtime = time()
## for port in CONNTRACK:
## if CONNTRACK[port]:
## count = count+1
##
## totalPorts = DestPortEnd - DestportStart
## freePorts = totalPorts - count
##
## logger.info("{} ports out of {} in use ({} free)".format(count,totalPorts,freePorts))
##
##
##
## if Stats == True:
## stats_task = task.LoopingCall(stats)
## statsa = stats_task.start(30)
## statsa.addErrback(loopingErrHandle)
Master = "127.0.0.1" Master = "127.0.0.1"
ListenPort = listen_port ListenPort = listen_port
# '' = all IPv4, '::' = all IPv4 and IPv6 (Dual Stack)
ListenIP = ''
DestportStart = port_start DestportStart = port_start
DestPortEnd = port_stop DestPortEnd = port_stop
Timeout = 30 Timeout = 30
Stats = True Stats = False
Debug = False Debug = False
ClientInfo = True
BlackList = [1234567] BlackList = [1234567]
#*******************
#Set process title early
setproctitle(__file__)
#If IPv6 is enabled by enivornment variable...
if ListenIP == '' and 'FDPROXY_IPV6' in os.environ and bool(os.environ['FDPROXY_IPV6']):
ListenIP = '::'
#Override static config from Environment
if 'FDPROXY_STATS' in os.environ:
Stats = bool(os.environ['FDPROXY_STATS'])
if 'FDPROXY_DEBUG' in os.environ:
Debug = bool(os.environ['FDPROXY_DEBUG'])
if 'FDPROXY_CLIENTINFO' in os.environ:
ClientInfo = bool(os.environ['FDPROXY_CLIENTINFO'])
if 'FDPROXY_LISTENPORT' in os.environ:
ListenPort = os.environ['FDPROXY_LISTENPORT']
CONNTRACK = {} CONNTRACK = {}
for port in range(DestportStart,DestPortEnd+1,1): for port in range(DestportStart,DestPortEnd+1,1):
CONNTRACK[port] = False CONNTRACK[port] = False
#If we are listening IPv6 and Master is an IPv4 IPv4Address
#IPv6ify the address.
if ListenIP == '::' and IsIPv4Address(Master):
Master = '::ffff:' + Master
reactor.listenUDP(ListenPort,Proxy(Master,ListenPort,CONNTRACK,BlackList,Timeout,Debug,DestportStart,DestPortEnd)) reactor.listenUDP(ListenPort,Proxy(Master,ListenPort,CONNTRACK,BlackList,Timeout,Debug,ClientInfo,DestportStart,DestPortEnd),interface=ListenIP)
def loopingErrHandle(failure): def loopingErrHandle(failure):
logger.error('(GLOBAL) STOPPING REACTOR TO AVOID MEMORY LEAK: Unhandled error innowtimed loop.\n {}'.format(failure)) print('(GLOBAL) STOPPING REACTOR TO AVOID MEMORY LEAK: Unhandled error innowtimed loop.\n {}'.format(failure))
reactor.stop() reactor.stop()
def stats(): def stats():
@ -317,7 +388,7 @@ def hotspot_proxy(listen_port, port_start, port_stop):
totalPorts = DestPortEnd - DestportStart totalPorts = DestPortEnd - DestportStart
freePorts = totalPorts - count freePorts = totalPorts - count
logger.info("{} ports out of {} in use ({} free)".format(count,totalPorts,freePorts)) print("{} ports out of {} in use ({} free)".format(count,totalPorts,freePorts))
@ -326,6 +397,7 @@ def hotspot_proxy(listen_port, port_start, port_stop):
statsa = stats_task.start(30) statsa = stats_task.start(30)
statsa.addErrback(loopingErrHandle) statsa.addErrback(loopingErrHandle)
# Used to track if we have downloaded user custon rules # Used to track if we have downloaded user custon rules
user_rules = {} user_rules = {}
@ -745,7 +817,9 @@ class routerOBP(OPENBRIDGE):
pkt_time = time() pkt_time = time()
dmrpkt = _data[20:53] dmrpkt = _data[20:53]
_bits = _data[15] _bits = _data[15]
print(int_id(_dst_id))
print('Src: ' + str(int_id(_rf_src)))
print('Dst: ' + str(int_id(_dst_id)))
# Make/update this unit in the UNIT_MAP cache # Make/update this unit in the UNIT_MAP cache
UNIT_MAP[_rf_src] = (self.name, pkt_time) UNIT_MAP[_rf_src] = (self.name, pkt_time)

View File

@ -1058,7 +1058,7 @@ def mmdvm_encapsulate(dst_id, src_id, peer_id, _seq, _slot, _call_type, _dtype_v
middle_guts = slot + call_type + frame_type + dtype_vseq middle_guts = slot + call_type + frame_type + dtype_vseq
#print(middle_guts) #print(middle_guts)
dmr_data = str(_dmr_data)[2:-1] #str(re.sub("b'|'", '', str(_dmr_data))) dmr_data = str(_dmr_data)[2:-1] #str(re.sub("b'|'", '', str(_dmr_data)))
complete_packet = signature.encode() + seq + dest_id + source_id + via_id + middle_guts.tobytes() + stream_id + bytes.fromhex((dmr_data))# + bitarray('0000000000101111').tobytes()#bytes.fromhex(dmr_data) complete_packet = signature.encode() + seq + source_id + dest_id + via_id + middle_guts.tobytes() + stream_id + bytes.fromhex((dmr_data))# + bitarray('0000000000101111').tobytes()#bytes.fromhex(dmr_data)
#print('Complete: ' + str(ahex(complete_packet))) #print('Complete: ' + str(ahex(complete_packet)))
return complete_packet return complete_packet
@ -1085,15 +1085,15 @@ def dmr_encode(packet_list, _slot):
l_slot = bitarray('0111011100') l_slot = bitarray('0111011100')
r_slot = bitarray('1101110001') r_slot = bitarray('1101110001')
#Mobile Station #Mobile Station
# D5D7F77FD757 # D5D7F77FD757
#sync_data = bitarray('110101011101011111110111011111111101011101010111') sync_data = bitarray('110101011101011111110111011111111101011101010111')
if _slot == 0: ## if _slot == 0:
# TS1 - F7FDD5DDFD55 ## # TS1 - F7FDD5DDFD55
sync_data = bitarray('111101111111110111010101110111011111110101010101') ## sync_data = bitarray('111101111111110111010101110111011111110101010101')
if _slot == 1: ## if _slot == 1:
#TS2 - D7557F5FF7F5 ## #TS2 - D7557F5FF7F5
sync_data = bitarray('110101110101010101111111010111111111011111110101') ## sync_data = bitarray('110101110101010101111111010111111111011111110101')
##
# Data sync? 110101011101011111110111011111111101011101010111 - D5D7F77FD757 # Data sync? 110101011101011111110111011111111101011101010111 - D5D7F77FD757
new_pkt = ahex(stitched_pkt[:98] + l_slot + sync_data + r_slot + stitched_pkt[98:]) new_pkt = ahex(stitched_pkt[:98] + l_slot + sync_data + r_slot + stitched_pkt[98:])
send_seq.append(new_pkt) send_seq.append(new_pkt)
@ -1130,13 +1130,16 @@ def create_sms_seq(dst_id, src_id, peer_id, _slot, _call_type, dmr_string):
mmdvm_send_seq.append(ahex(the_mmdvm_pkt)) mmdvm_send_seq.append(ahex(the_mmdvm_pkt))
cap_in = cap_in + 1 cap_in = cap_in + 1
print(ahex(the_mmdvm_pkt)) print(ahex(the_mmdvm_pkt))
if bytes.fromhex(dst_id) in UNIT_MAP: if bytes.fromhex(dst_id) in UNIT_MAP:
logger.info('Sending SMS packet to ' + str(UNIT_MAP[bytes.fromhex(dst_id)][0])) logger.info('Sending SMS packet to ' + str(UNIT_MAP[bytes.fromhex(dst_id)][0]))
systems[UNIT_MAP[bytes.fromhex(dst_id)][0]].send_system(the_mmdvm_pkt) systems[UNIT_MAP[bytes.fromhex(dst_id)][0]].send_system(the_mmdvm_pkt)
else: else:
for s in CONFIG['SYSTEMS'].items(): for s in CONFIG['SYSTEMS'].items():
if 'FREEDMR' in s[1]['OTHER_OPTIONS']:
systems[s[0]].send_system(b'SVRDDATA' + the_mmdvm_pkt)
else:
systems[s[0]].send_system(the_mmdvm_pkt) systems[s[0]].send_system(the_mmdvm_pkt)
logger.info('Sending SMS packet to ' + str(s[0])) logger.info('Sending SMS packet to ' + str(s[0]))
if CONFIG['WEB_SERVICE']['REMOTE_CONFIG_ENABLED'] == False: if CONFIG['WEB_SERVICE']['REMOTE_CONFIG_ENABLED'] == False:
with open('/tmp/.hblink_data_que_' + str(CONFIG['DATA_CONFIG']['APRS_LOGIN_CALL']).upper() + '/' + str(random.randint(1000, 9999)) + '.mmdvm_seq', "w") as packet_write_file: with open('/tmp/.hblink_data_que_' + str(CONFIG['DATA_CONFIG']['APRS_LOGIN_CALL']).upper() + '/' + str(random.randint(1000, 9999)) + '.mmdvm_seq', "w") as packet_write_file:
packet_write_file.write(str(mmdvm_send_seq)) packet_write_file.write(str(mmdvm_send_seq))
@ -1230,9 +1233,9 @@ def send_sms(csbk, to_id, from_id, peer_id, call_type, msg):
call_type = 0 call_type = 0
# Send all Group data to TS 2, need to fix later. # Send all Group data to TS 2, need to fix later.
slot = 1 slot = 1
if csbk == 'yes': if csbk == True:
use_csbk = True use_csbk = True
create_sms_seq(to_id, from_id, peer_id, int(slot), new_call_type, csbk_gen(to_id, from_id) + create_crc16(gen_header(to_id, from_id, new_call_type)) + create_crc32(format_sms(msg, to_id, from_id))) create_sms_seq(to_id, from_id, peer_id, int(slot), call_type, csbk_gen(to_id, from_id) + create_crc16(gen_header(to_id, from_id, call_type)) + create_crc32(format_sms(msg, to_id, from_id)))
else: else:
create_sms_seq(to_id, from_id, peer_id, int(slot), call_type, create_crc16(gen_header(to_id, from_id, call_type)) + create_crc32(format_sms(str(msg), to_id, from_id))) create_sms_seq(to_id, from_id, peer_id, int(slot), call_type, create_crc16(gen_header(to_id, from_id, call_type)) + create_crc32(format_sms(str(msg), to_id, from_id)))
@ -1476,6 +1479,7 @@ def data_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _fr
# Use block 0 as trigger. $GPRMC must also be in string to indicate NMEA. # Use block 0 as trigger. $GPRMC must also be in string to indicate NMEA.
# This triggers the APRS upload # This triggers the APRS upload
if btf == 0: if btf == 0:
final_packet = str(bitarray(re.sub("\)|\(|bitarray|'", '', packet_assembly)).tobytes().decode('utf-8', 'ignore')) final_packet = str(bitarray(re.sub("\)|\(|bitarray|'", '', packet_assembly)).tobytes().decode('utf-8', 'ignore'))
sms_hex = str(ba2hx(bitarray(re.sub("\)|\(|bitarray|'", '', packet_assembly)))) sms_hex = str(ba2hx(bitarray(re.sub("\)|\(|bitarray|'", '', packet_assembly))))
sms_hex_string = re.sub("b'|'", '', str(sms_hex)) sms_hex_string = re.sub("b'|'", '', str(sms_hex))
@ -1690,8 +1694,10 @@ class OBP(OPENBRIDGE):
if _mode == b'UNIT': if _mode == b'UNIT':
UNIT_MAP[_data] = (self._system, time()) UNIT_MAP[_data] = (self._system, time())
print(UNIT_MAP) print(UNIT_MAP)
if _mode == b'DATA' or _mode == b'MDATA': if _mode == b'DATA' or _mode == b'MDAT':
## print(ahex(_data))
# DMR Data packet, sent via SVRD # DMR Data packet, sent via SVRD
_peer_id = _data[11:15] _peer_id = _data[11:15]
_seq = _data[4] _seq = _data[4]
_rf_src = _data[5:8] _rf_src = _data[5:8]
@ -1709,6 +1715,14 @@ class OBP(OPENBRIDGE):
_dtype_vseq = (_bits & 0xF) # data, 1=voice header, 2=voice terminator; voice, 0=burst A ... 5=burst F _dtype_vseq = (_bits & 0xF) # data, 1=voice header, 2=voice terminator; voice, 0=burst A ... 5=burst F
_stream_id = _data[16:20] _stream_id = _data[16:20]
print(int_id(_peer_id))
print(int_id(_rf_src))
print(int_id(_dst_id))
print((_dtype_vseq))
print(ahex(bptc_decode(_data)))
## # Record last packet to prevent duplicates, think finger printing. ## # Record last packet to prevent duplicates, think finger printing.
## PACKET_MATCH[_rf_src] = [_data, time()] ## PACKET_MATCH[_rf_src] = [_data, time()]
@ -1724,9 +1738,8 @@ class HBP(HBSYSTEM):
def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data):
UNIT_MAP[_rf_src] = (self._system, time()) UNIT_MAP[_rf_src] = (self._system, time())
print(_dtype_vseq) ## print(ahex(_data))
print('MMDVM RCVD') print('MMDVM RCVD')
print(UNIT_MAP)
if _rf_src not in PACKET_MATCH: if _rf_src not in PACKET_MATCH:
PACKET_MATCH[_rf_src] = [_data, time()] PACKET_MATCH[_rf_src] = [_data, time()]
elif _data == PACKET_MATCH[_rf_src][0] and time() - 1 < PACKET_MATCH[_rf_src][1]: elif _data == PACKET_MATCH[_rf_src][0] and time() - 1 < PACKET_MATCH[_rf_src][1]:

View File

@ -191,6 +191,7 @@ class OPENBRIDGE(DatagramProtocol):
pass pass
def datagramReceived(self, _packet, _sockaddr): def datagramReceived(self, _packet, _sockaddr):
print(_sockaddr)
## print(_packet[:4]) ## print(_packet[:4])
# Keep This Line Commented Unless HEAVILY Debugging! # Keep This Line Commented Unless HEAVILY Debugging!
## logger.debug('(%s) RX packet from %s -- %s', self._system, _sockaddr, ahex(_packet)) ## logger.debug('(%s) RX packet from %s -- %s', self._system, _sockaddr, ahex(_packet))
@ -299,6 +300,7 @@ class OPENBRIDGE(DatagramProtocol):
## else: ## else:
self.svrd_received(_d_pkt[4:8], _d_pkt[8:]) self.svrd_received(_d_pkt[4:8], _d_pkt[8:])
## print(ahex(_d_pkt[8:]))
#************************************************ #************************************************
# HB MASTER CLASS # HB MASTER CLASS

View File

@ -1,26 +1,63 @@
###############################################################################
# Copyright (C) 2020 Simon Adlem, G7RZU <g7rzu@gb7fr.org.uk>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
###############################################################################
from twisted.internet.protocol import DatagramProtocol from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor, task from twisted.internet import reactor, task
from time import time from time import time
from resettabletimer import ResettableTimer
from dmr_utils3.utils import int_id from dmr_utils3.utils import int_id
import random import random
import ipaddress
import os
from setproctitle import setproctitle
from datetime import datetime
# Does anybody read this stuff? There's a PEP somewhere that says I should do this. # Does anybody read this stuff? There's a PEP somewhere that says I should do this.
__author__ = 'Simon Adlem - G7RZU' __author__ = 'Simon Adlem - G7RZU'
__copyright__ = 'Copyright (c) Simon Adlem, G7RZU 2020,2021' __copyright__ = 'Copyright (c) Simon Adlem, G7RZU 2020,2021'
__credits__ = 'Jon Lee, G4TSN; Norman Williams, M6NBP' __credits__ = 'Jon Lee, G4TSN; Norman Williams, M6NBP; Christian, OA4DOA'
__license__ = 'GNU GPLv3' __license__ = 'GNU GPLv3'
__maintainer__ = 'Simon Adlem G7RZU' __maintainer__ = 'Simon Adlem G7RZU'
__email__ = 'simon@gb7fr.org.uk' __email__ = 'simon@gb7fr.org.uk'
def IsIPv4Address(ip):
try:
ipaddress.IPv4Address(ip)
return True
except ValueError as errorCode:
pass
return False
def IsIPv6Address(ip):
try:
ipaddress.IPv6Address(ip)
return True
except ValueError as errorCode:
pass
class Proxy(DatagramProtocol): class Proxy(DatagramProtocol):
def __init__(self,Master,ListenPort,connTrack,blackList,Timeout,Debug,DestportStart,DestPortEnd): def __init__(self,Master,ListenPort,connTrack,blackList,Timeout,Debug,ClientInfo,DestportStart,DestPortEnd):
self.master = Master self.master = Master
self.connTrack = connTrack self.connTrack = connTrack
self.peerTrack = {} self.peerTrack = {}
self.timeout = Timeout self.timeout = Timeout
self.debug = Debug self.debug = Debug
self.clientinfo = ClientInfo
self.blackList = blackList self.blackList = blackList
self.destPortStart = DestportStart self.destPortStart = DestportStart
self.destPortEnd = DestPortEnd self.destPortEnd = DestPortEnd
@ -30,7 +67,9 @@ class Proxy(DatagramProtocol):
def reaper(self,_peer_id): def reaper(self,_peer_id):
if self.debug: if self.debug:
print("dead",_peer_id) print("dead",_peer_id)
self.transport.write(b'RPTCL'+_peer_id, ('127.0.0.1',self.peerTrack[_peer_id]['dport'])) if self.clientinfo and _peer_id != b'\xff\xff\xff\xff':
print(f"{datetime.now().replace(microsecond=0)} Client: ID:{str(int_id(_peer_id)).rjust(9)} IP:{self.peerTrack[_peer_id]['shost'].rjust(15)} Port:{self.peerTrack[_peer_id]['sport']} Removed.")
self.transport.write(b'RPTCL'+_peer_id, (self.master,self.peerTrack[_peer_id]['dport']))
self.connTrack[self.peerTrack[_peer_id]['dport']] = False self.connTrack[self.peerTrack[_peer_id]['dport']] = False
del self.peerTrack[_peer_id] del self.peerTrack[_peer_id]
@ -57,6 +96,8 @@ class Proxy(DatagramProtocol):
RPTA = b'RPTA' RPTA = b'RPTA'
RPTO = b'RPTO' RPTO = b'RPTO'
_peer_id = False
host,port = addr host,port = addr
nowtime = time() nowtime = time()
@ -66,44 +107,31 @@ class Proxy(DatagramProtocol):
#If the packet comes from the master #If the packet comes from the master
if host == self.master: if host == self.master:
_command = data[:4] _command = data[:4]
_lng_command = data[:6]
#### print(_lng_command)
if _command == DMRD: if _command == DMRD:
_peer_id = data[11:15] _peer_id = data[11:15]
## print(self.peerTrack[_peer_id]['timer'])
elif _command == RPTA: elif _command == RPTA:
if data[6:10] in self.peerTrack: if data[6:10] in self.peerTrack:
_peer_id = data[6:10] _peer_id = data[6:10]
else: else:
_peer_id = self.connTrack[port] _peer_id = self.connTrack[port]
elif _lng_command == MSTNAK: elif _command == MSTN:
_peer_id = data[6:10]
elif _command == MSTN and MSTNAK not in _lng_command:
_peer_id = data[6:10] _peer_id = data[6:10]
self.peerTrack[_peer_id]['timer'].cancel()
self.reaper(_peer_id)
return
elif _command == MSTP: elif _command == MSTP:
_peer_id = data[7:11] _peer_id = data[7:11]
## print(self.peerTrack)
elif _command == MSTC: elif _command == MSTC:
_peer_id = data[5:9] _peer_id = data[5:9]
self.peerTrack[_peer_id]['timer'].cancel()
self.reaper(_peer_id)
return
# _peer_id = self.connTrack[port]
if self.debug: if self.debug:
print(data) print(data)
if _peer_id and _peer_id in self.peerTrack: if _peer_id in self.peerTrack:
self.transport.write(data,(self.peerTrack[_peer_id]['shost'],self.peerTrack[_peer_id]['sport'])) self.transport.write(data,(self.peerTrack[_peer_id]['shost'],self.peerTrack[_peer_id]['sport']))
#self.peerTrack[_peer_id]['timer'].reset() # Remove the client after send a MSTN or MSTC packet
return if _command in (MSTN,MSTC):
# Give time to the client for a reply to prevent port reassignment
self.peerTrack[_peer_id]['timer'].reset(15)
return
else: else:
@ -112,16 +140,16 @@ class Proxy(DatagramProtocol):
if _command == DMRD: # DMRData -- encapsulated DMR data frame if _command == DMRD: # DMRData -- encapsulated DMR data frame
_peer_id = data[11:15] _peer_id = data[11:15]
elif _command == DMRA: # DMRAlias -- Talker Alias information elif _command == DMRA: # DMRAlias -- Talker Alias information
_peer_id = _data[4:8] _peer_id = data[4:8]
elif _command == RPTL: # RPTLogin -- a repeater wants to login elif _command == RPTL: # RPTLogin -- a repeater wants to login
_peer_id = data[4:8] _peer_id = data[4:8]
elif _command == RPTK: # Repeater has answered our login challenge elif _command == RPTK: # Repeater has answered our login challenge
_peer_id = data[4:8] _peer_id = data[4:8]
elif _command == RPTC: # Repeater is sending it's configuraiton OR disconnecting elif _command == RPTC: # Repeater is sending it's configuraiton OR disconnecting
if data[:5] == RPTCL: # Disconnect command if data[:5] == RPTCL: # Disconnect command
_peer_id = data[5:9] _peer_id = data[5:9]
else: else:
_peer_id = data[4:8] # Configure Command _peer_id = data[4:8] # Configure Command
elif _command == RPTO: # options elif _command == RPTO: # options
_peer_id = data[4:8] _peer_id = data[4:8]
elif _command == RPTP: # RPTPing -- peer is pinging us elif _command == RPTP: # RPTPing -- peer is pinging us
@ -133,33 +161,33 @@ class Proxy(DatagramProtocol):
_dport = self.peerTrack[_peer_id]['dport'] _dport = self.peerTrack[_peer_id]['dport']
self.peerTrack[_peer_id]['sport'] = port self.peerTrack[_peer_id]['sport'] = port
self.peerTrack[_peer_id]['shost'] = host self.peerTrack[_peer_id]['shost'] = host
self.transport.write(data, ('127.0.0.1',_dport)) self.transport.write(data, (self.master,_dport))
self.peerTrack[_peer_id]['timer'].reset() self.peerTrack[_peer_id]['timer'].reset(self.timeout)
if self.debug: if self.debug:
print(data) print(data)
print(_dport)
return return
else:
else:
if int_id(_peer_id) in self.blackList: if int_id(_peer_id) in self.blackList:
return return
#for _dport in self.connTrack: # Make a list with the available ports
while True: _ports_avail = [port for port in self.connTrack if not self.connTrack[port]]
_dport = random.randint(1,(self.numPorts - 1)) if _ports_avail:
_dport = _dport + self.destPortStart _dport = random.choice(_ports_avail)
if not self.connTrack[_dport]: else:
break return
self.connTrack[_dport] = _peer_id self.connTrack[_dport] = _peer_id
self.peerTrack[_peer_id] = {} self.peerTrack[_peer_id] = {}
self.peerTrack[_peer_id]['dport'] = _dport self.peerTrack[_peer_id]['dport'] = _dport
self.peerTrack[_peer_id]['sport'] = port self.peerTrack[_peer_id]['sport'] = port
self.peerTrack[_peer_id]['shost'] = host self.peerTrack[_peer_id]['shost'] = host
self.peerTrack[_peer_id]['timer'] = ResettableTimer(self.timeout,self.reaper,[_peer_id]) self.peerTrack[_peer_id]['timer'] = reactor.callLater(self.timeout,self.reaper,_peer_id)
self.peerTrack[_peer_id]['timer'].start()
self.transport.write(data, (self.master,_dport)) self.transport.write(data, (self.master,_dport))
if self.clientinfo and _peer_id != b'\xff\xff\xff\xff':
print(f'{datetime.now().replace(microsecond=0)} New client: ID:{str(int_id(_peer_id)).rjust(9)} IP:{host.rjust(15)} Port:{port}, assigned to port:{_dport}.')
if self.debug: if self.debug:
print(data) print(data)
return return
@ -169,23 +197,48 @@ if __name__ == '__main__':
Master = "127.0.0.1" Master = "127.0.0.1"
ListenPort = 62031 ListenPort = 62031
DestportStart = 54100 # '' = all IPv4, '::' = all IPv4 and IPv6 (Dual Stack)
DestPortEnd = 54102 ListenIP = ''
DestportStart = 54000
DestPortEnd = 54100
Timeout = 30 Timeout = 30
Stats = True Stats = False
Debug = True Debug = False
ClientInfo = False
BlackList = [1234567] BlackList = [1234567]
#******************* #*******************
#Set process title early
setproctitle(__file__)
#If IPv6 is enabled by enivornment variable...
if ListenIP == '' and 'FDPROXY_IPV6' in os.environ and bool(os.environ['FDPROXY_IPV6']):
ListenIP = '::'
#Override static config from Environment
if 'FDPROXY_STATS' in os.environ:
Stats = bool(os.environ['FDPROXY_STATS'])
if 'FDPROXY_DEBUG' in os.environ:
Debug = bool(os.environ['FDPROXY_DEBUG'])
if 'FDPROXY_CLIENTINFO' in os.environ:
ClientInfo = bool(os.environ['FDPROXY_CLIENTINFO'])
if 'FDPROXY_LISTENPORT' in os.environ:
ListenPort = os.environ['FDPROXY_LISTENPORT']
CONNTRACK = {} CONNTRACK = {}
for port in range(DestportStart,DestPortEnd+1,1): for port in range(DestportStart,DestPortEnd+1,1):
CONNTRACK[port] = False CONNTRACK[port] = False
#If we are listening IPv6 and Master is an IPv4 IPv4Address
#IPv6ify the address.
if ListenIP == '::' and IsIPv4Address(Master):
Master = '::ffff:' + Master
reactor.listenUDP(ListenPort,Proxy(Master,ListenPort,CONNTRACK,BlackList,Timeout,Debug,DestportStart,DestPortEnd)) reactor.listenUDP(ListenPort,Proxy(Master,ListenPort,CONNTRACK,BlackList,Timeout,Debug,ClientInfo,DestportStart,DestPortEnd),interface=ListenIP)
def loopingErrHandle(failure): def loopingErrHandle(failure):
print('(GLOBAL) STOPPING REACTOR TO AVOID MEMORY LEAK: Unhandled error innowtimed loop.\n {}'.format(failure)) print('(GLOBAL) STOPPING REACTOR TO AVOID MEMORY LEAK: Unhandled error innowtimed loop.\n {}'.format(failure))

View File

@ -11,7 +11,7 @@
<tr> <tr>
<td><span style="color: #ff0000;"><strong>Red</strong></span> = Peer location (no APRS)</td> <td><span style="color: #ff0000;"><strong>Red</strong></span> = Peer location (no APRS)</td>
<td><span style="color: #0000ff;"><strong>Blue</strong></span> = GPS location (APRS)</td> <td><span style="color: #0000ff;"><strong>Blue</strong></span> = GPS location (APRS)</td>
<td><strong><span style="color: #00ff00;">Green</span></strong> = Peer location (APRS)</td> <!-- <td><strong><span style="color: #00ff00;">Green</span></strong> = Peer location (APRS)</td> -->
</tr> </tr>
</tbody> </tbody>
</table> </table>