From 7c65ec74c5ccba32b6913086d2d101a8569ba51e Mon Sep 17 00:00:00 2001 From: Simon Date: Thu, 7 Jan 2021 18:40:15 +0000 Subject: [PATCH] Preparing for v1 release --- FreeDMR-SAMPLE.cfg | 256 +++++++++++++++++++++++++++++++++++++++++++++ HBlink.png | Bin 43039 -> 0 bytes HBlink.svg | 245 ------------------------------------------- hblink.py | 2 +- hotspot_proxy.py | 106 ------------------- rules_SAMPLE.py | 16 +-- 6 files changed, 261 insertions(+), 364 deletions(-) create mode 100755 FreeDMR-SAMPLE.cfg delete mode 100644 HBlink.png delete mode 100644 HBlink.svg delete mode 100644 hotspot_proxy.py diff --git a/FreeDMR-SAMPLE.cfg b/FreeDMR-SAMPLE.cfg new file mode 100755 index 0000000..7b793ad --- /dev/null +++ b/FreeDMR-SAMPLE.cfg @@ -0,0 +1,256 @@ +# PROGRAM-WIDE PARAMETERS GO HERE +# PATH - working path for files, leave it alone unless you NEED to change it +# PING_TIME - the interval that peers will ping the master, and re-try registraion +# - how often the Master maintenance loop runs +# MAX_MISSED - how many pings are missed before we give up and re-register +# - number of times the master maintenance loop runs before de-registering a peer +# +# ACLs: +# +# Access Control Lists are a very powerful tool for administering your system. +# But they consume packet processing time. Disable them if you are not using them. +# But be aware that, as of now, the configuration stanzas still need the ACL +# sections configured even if you're not using them. +# +# REGISTRATION ACLS ARE ALWAYS USED, ONLY SUBSCRIBER AND TGID MAY BE DISABLED!!! +# +# The 'action' May be PERMIT|DENY +# Each entry may be a single radio id, or a hypenated range (e.g. 1-2999) +# Format: +# ACL = 'action:id|start-end|,id|start-end,....' +# --for example-- +# SUB_ACL: DENY:1,1000-2000,4500-60000,17 +# +# ACL Types: +# REG_ACL: peer radio IDs for registration (only used on HBP master systems) +# SUB_ACL: subscriber IDs for end-users +# TGID_TS1_ACL: destination talkgroup IDs on Timeslot 1 +# TGID_TS2_ACL: destination talkgroup IDs on Timeslot 2 +# +# ACLs may be repeated for individual systems if needed for granularity +# Global ACLs will be processed BEFORE the system level ACLs +# Packets will be matched against all ACLs, GLOBAL first. If a packet 'passes' +# All elements, processing continues. Packets are discarded at the first +# negative match, or 'reject' from an ACL element. +# +# If you do not wish to use ACLs, set them to 'PERMIT:ALL' +# TGID_TS1_ACL in the global stanza is used for OPENBRIDGE systems, since all +# traffic is passed as TS 1 between OpenBridges +[GLOBAL] +PATH: ./ +PING_TIME: 10 +MAX_MISSED: 3 +USE_ACL: True +REG_ACL: PERMIT:ALL +SUB_ACL: DENY:1 +TGID_TS1_ACL: PERMIT:ALL +TGID_TS2_ACL: PERMIT:ALL + + +# NOT YET WORKING: NETWORK REPORTING CONFIGURATION +# Enabling "REPORT" will configure a socket-based reporting +# system that will send the configuration and other items +# to a another process (local or remote) that may process +# the information for some useful purpose, like a web dashboard. +# +# REPORT - True to enable, False to disable +# REPORT_INTERVAL - Seconds between reports +# REPORT_PORT - TCP port to listen on if "REPORT_NETWORKS" = NETWORK +# REPORT_CLIENTS - comma separated list of IPs you will allow clients +# to connect on. Entering a * will allow all. +# +# ****FOR NOW MUST BE TRUE - USE THE LOOPBACK IF YOU DON'T USE THIS!!!**** +[REPORTS] +REPORT: True +REPORT_INTERVAL: 60 +REPORT_PORT: 4321 +REPORT_CLIENTS: 127.0.0.1 + + +# SYSTEM LOGGER CONFIGURAITON +# This allows the logger to be configured without chaning the individual +# python logger stuff. LOG_FILE should be a complete path/filename for *your* +# system -- use /dev/null for non-file handlers. +# LOG_HANDLERS may be any of the following, please, no spaces in the +# list if you use several: +# null +# console +# console-timed +# file +# file-timed +# syslog +# LOG_LEVEL may be any of the standard syslog logging levels, though +# as of now, DEBUG, INFO, WARNING and CRITICAL are the only ones +# used. +# +[LOGGER] +LOG_FILE: /tmp/hblink.log +LOG_HANDLERS: console-timed +LOG_LEVEL: DEBUG +LOG_NAME: HBlink + +# DOWNLOAD AND IMPORT SUBSCRIBER, PEER and TGID ALIASES +# Ok, not the TGID, there's no master list I know of to download +# This is intended as a facility for other applcations built on top of +# HBlink to use, and will NOT be used in HBlink directly. +# STALE_DAYS is the number of days since the last download before we +# download again. Don't be an ass and change this to less than a few days. +[ALIASES] +TRY_DOWNLOAD: True +PATH: ./ +PEER_FILE: peer_ids.json +SUBSCRIBER_FILE: subscriber_ids.json +TGID_FILE: talkgroup_ids.json +PEER_URL: https://www.radioid.net/static/rptrs.json +SUBSCRIBER_URL: https://www.radioid.net/static/users.json +STALE_DAYS: 7 + +#Read further repeater configs from MySQL +[MYSQL] +USE_MYSQL: False +USER: hblink +PASS: mypassword +DB: hblink +SERVER: 127.0.0.1 +PORT: 3306 + +# OPENBRIDGE INSTANCES - DUPLICATE SECTION FOR MULTIPLE CONNECTIONS +# OpenBridge is a protocol originall created by DMR+ for connection between an +# IPSC2 server and Brandmeister. It has been implemented here at the suggestion +# of the Brandmeister team as a way to legitimately connect HBlink to the +# Brandemiester network. +# It is recommended to name the system the ID of the Brandmeister server that +# it connects to, but is not necessary. TARGET_IP and TARGET_PORT are of the +# Brandmeister or IPSC2 server you are connecting to. PASSPHRASE is the password +# that must be agreed upon between you and the operator of the server you are +# connecting to. NETWORK_ID is a number in the format of a DMR Radio ID that +# will be sent to the other server to identify this connection. +# other parameters follow the other system types. +# +# ACLs: +# OpenBridge does not 'register', so registration ACL is meaningless. +# OpenBridge passes all traffic on TS1, so there is only 1 TGID ACL. +# Otherwise ACLs work as described in the global stanza +[OBP-TEST] +MODE: OPENBRIDGE +ENABLED: False +IP: +PORT: 62044 +NETWORK_ID: 1 +PASSPHRASE: mypass +TARGET_IP: +TARGET_PORT: 62044 +USE_ACL: True +SUB_ACL: DENY:1 +TGID_ACL: PERMIT:ALL + +# MASTER INSTANCES - DUPLICATE SECTION FOR MULTIPLE MASTERS +# HomeBrew Protocol Master instances go here. +# IP may be left blank if there's one interface on your system. +# Port should be the port you want this master to listen on. It must be unique +# and unused by anything else. +# Repeat - if True, the master repeats traffic to peers, False, it does nothing. +# +# MAX_PEERS -- maximun number of peers that may be connect to this master +# at any given time. This is very handy if you're allowing hotspots to +# connect, or using a limited computer like a Raspberry Pi. +# +# ACLs: +# See comments in the GLOBAL stanza +[G9XYZ] +MODE: MASTER +ENABLED: False +REPEAT: True +MAX_PEERS: 1 +EXPORT_AMBE: False +IP: +PORT: 54001 +PASSPHRASE: passw0rd +GROUP_HANGTIME: 5 +USE_ACL: True +REG_ACL: DENY:1 +SUB_ACL: DENY:1 +TGID_TS1_ACL: PERMIT:ALL +TGID_TS2_ACL: PERMIT:ALL +DEFAULT_UA_TIMER: 10 +SINGLE_MODE: True +VOICE_IDENT: True +TS1_STATIC: +TS2_STATIC: +DEFAULT_REFLECTOR: 0 + +# PEER INSTANCES - DUPLICATE SECTION FOR MULTIPLE PEERS +# There are a LOT of errors in the HB Protocol specifications on this one! +# MOST of these items are just strings and will be properly dealt with by the program +# The TX & RX Frequencies are 9-digit numbers, and are the frequency in Hz. +# Latitude is an 8-digit unsigned floating point number. +# Longitude is a 9-digit signed floating point number. +# Height is in meters +# Setting Loose to True relaxes the validation on packets received from the master. +# This will allow HBlink to connect to a non-compliant system such as XLXD, DMR+ etc. +# +# ACLs: +# See comments in the GLOBAL stanza +[REPEATER-1] +MODE: PEER +ENABLED: False +LOOSE: False +EXPORT_AMBE: False +IP: +PORT: 54001 +MASTER_IP: 172.16.1.1 +MASTER_PORT: 54000 +PASSPHRASE: homebrew +CALLSIGN: W1ABC +RADIO_ID: 312000 +RX_FREQ: 449000000 +TX_FREQ: 444000000 +TX_POWER: 25 +COLORCODE: 1 +SLOTS: 1 +LATITUDE: 38.0000 +LONGITUDE: -095.0000 +HEIGHT: 75 +LOCATION: Anywhere, USA +DESCRIPTION: This is a cool repeater +URL: www.w1abc.org +SOFTWARE_ID: 20170620 +PACKAGE_ID: MMDVM_HBlink +GROUP_HANGTIME: 5 +OPTIONS: +USE_ACL: True +SUB_ACL: DENY:1 +TGID_TS1_ACL: PERMIT:ALL +TGID_TS2_ACL: PERMIT:ALL + +[XLX-1] +MODE: XLXPEER +ENABLED: False +LOOSE: True +EXPORT_AMBE: False +IP: +PORT: 54002 +MASTER_IP: 172.16.1.1 +MASTER_PORT: 62030 +PASSPHRASE: passw0rd +CALLSIGN: W1ABC +RADIO_ID: 312000 +RX_FREQ: 449000000 +TX_FREQ: 444000000 +TX_POWER: 25 +COLORCODE: 1 +SLOTS: 1 +LATITUDE: 38.0000 +LONGITUDE: -095.0000 +HEIGHT: 75 +LOCATION: Anywhere, USA +DESCRIPTION: This is a cool repeater +URL: www.w1abc.org +SOFTWARE_ID: 20170620 +PACKAGE_ID: MMDVM_HBlink +GROUP_HANGTIME: 5 +XLXMODULE: 4004 +USE_ACL: True +SUB_ACL: DENY:1 +TGID_TS1_ACL: PERMIT:ALL +TGID_TS2_ACL: PERMIT:ALL diff --git a/HBlink.png b/HBlink.png deleted file mode 100644 index 29fa55615dea42d554a25a2fb2d7a18dc8fe1dd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43039 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 em4JTh5=jv~irnJ%c)< - - - - - - - - - - - - - - - Produced by OmniGraffle 7.12.1 - 2018-03-14 13:37:44 +0000 - - - image/svg+xml - - - - - - - Canvas 2 - - Layer 1 - - - path6007 - - - - - - - - - - - - - - - - - - - - - path6381 - - - - - - - - - - - - diff --git a/hblink.py b/hblink.py index e70bc40..eeb5e47 100755 --- a/hblink.py +++ b/hblink.py @@ -551,7 +551,7 @@ class HBSYSTEM(DatagramProtocol): logger.warning('(%s) Ping from Radio ID that is not logged in: %s', self._system, int_id(_peer_id)) else: - logger.error('(%s) Unrecognized command. Raw HBP PDU: %s', self._system, ahex(_data)) + logger.error('(%s) Unrecognized command. Raw HBP PDU: %s', self._system, _data) # Aliased in __init__ to datagramReceived if system is a peer def peer_datagramReceived(self, _data, _sockaddr): diff --git a/hotspot_proxy.py b/hotspot_proxy.py deleted file mode 100644 index 8ce7200..0000000 --- a/hotspot_proxy.py +++ /dev/null @@ -1,106 +0,0 @@ -from twisted.internet.protocol import DatagramProtocol -from twisted.internet import reactor, task -from time import time - - -class Proxy(DatagramProtocol): - - def __init__(self,ListenPort,connTrack,Timeout,Debug): - self.connTrack = connTrack - self.sourceTrack = {} - self.timeout = Timeout - self.debug = Debug - - def datagramReceived(self, data, addr): - host,port = addr - - nowtime = time() - - Debug = self.debug - - #If the packet comes from the master - if host == '127.0.0.1' and port in self.connTrack: - if int(self.connTrack[port]['time'])+self.timeout >nowtime: - self.transport.write(data,(self.connTrack[port]['host'],self.connTrack[port]['sport'])) - if Debug: - print("return path match") - print(data) - elif self.sourceTrack[str(self.connTrack[port]['host'])+":"+str(self.connTrack[port]['sport']) in self.sourceTrack: - del self.sourceTrack[str(self.connTrack[port]['host'])+":"+str(self.connTrack[port]['sport'])] - return - - #If we have a sourcetrack for this connect and thenowtimeout has not expired, forward to tracked port - if host+":"+str(port) in self.sourceTrack and (int(self.sourceTrack[host+":"+str(port)]['time'])+self.timeout >nowtime): - self.transport.write(data, ('127.0.0.1',self.sourceTrack[host+":"+str(port)]['dport'])) - self.connTrack[self.sourceTrack[host+":"+str(port)]['dport']]['time'] =nowtime - self.sourceTrack[host+":"+str(port)]['time'] =nowtime - if Debug: - print("Tracked inbound match") - print(data) - return - elif host+":"+str(port) in self.sourceTrack: - del self.sourceTrack[host+":"+str(port)] - - #Find free port to map for new connection - for dport in self.connTrack: - if (self.connTrack[dport]['time'] == False or (int(self.connTrack[dport]['time'])+self.timeout < nowtime)): - self.connTrack[dport]['sport'] = port - self.connTrack[dport]['host'] = host - self.connTrack[dport]['time'] =nowtime - self.sourceTrack[host+":"+str(port)] = {} - self.sourceTrack[host+":"+str(port)]['dport'] = dport - self.sourceTrack[host+":"+str(port)]['time'] = nowtime - self.transport.write(data, ('127.0.0.1',dport)) - if Debug: - print("New connection") - print(data) - return - - - -if __name__ == '__main__': - -#*** CONFIG HERE *** - - ListenPort = 62031 - DestportStart = 54001 - DestPortEnd = 54002 - Timeout = 35 - Stats = True - Debug = True - -#******************* - - - CONNTRACK = {} - - for port in range(DestportStart,DestPortEnd,1): - CONNTRACK[port] = {'host': False,'time': False,'sport':False, 'nacktime': False} - - reactor.listenUDP(ListenPort,Proxy(ListenPort,CONNTRACK,Timeout,Debug)) - - def loopingErrHandle(failure): - print('(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 int(CONNTRACK[port]['time'])+Timeout > nowtime: - count = count+1 - - totalPorts = DestPortEnd - DestportStart - freePorts = totalPorts - count - - print("{} 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) - - reactor.run() - diff --git a/rules_SAMPLE.py b/rules_SAMPLE.py index a3c3701..6270d72 100755 --- a/rules_SAMPLE.py +++ b/rules_SAMPLE.py @@ -1,6 +1,9 @@ ''' THIS EXAMPLE WILL NOT WORK AS IT IS - YOU MUST SPECIFY YOUR OWN VALUES!!! +In FreeDMR, the rules file should be *empty* unless you have static routing required. Please see the +documentation for more details. + This file is organized around the "Conference Bridges" that you wish to use. If you're a c-Bridge person, think of these as "bridge groups". You might also liken them to a "reflector". If a particular system is "ACTIVE" on a particular conference bridge, any traffid from that system will be sent @@ -33,18 +36,7 @@ configuration file. ''' BRIDGES = { - 'WORLDWIDE': [ - {'SYSTEM': 'MASTER-1', 'TS': 1, 'TGID': 1, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'ON', 'ON': [2,], 'OFF': [9,10], 'RESET': []}, - {'SYSTEM': 'CLIENT-1', 'TS': 1, 'TGID': 3100, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'ON', 'ON': [2,], 'OFF': [9,10], 'RESET': []}, - ], - 'ENGLISH': [ - {'SYSTEM': 'MASTER-1', 'TS': 1, 'TGID': 13, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'NONE', 'ON': [3,], 'OFF': [8,10], 'RESET': []}, - {'SYSTEM': 'CLIENT-2', 'TS': 1, 'TGID': 13, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'NONE', 'ON': [3,], 'OFF': [8,10], 'RESET': []}, - ], - 'STATEWIDE': [ - {'SYSTEM': 'MASTER-1', 'TS': 2, 'TGID': 3129, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'NONE', 'ON': [4,], 'OFF': [7,10], 'RESET': []}, - {'SYSTEM': 'CLIENT-2', 'TS': 2, 'TGID': 3129, 'ACTIVE': True, 'TIMEOUT': 2, 'TO_TYPE': 'NONE', 'ON': [4,], 'OFF': [7,10], 'RESET': []}, - ] + } if __name__ == '__main__':