Updates to tidy up handling of low-level TG filter.

Also, remove the obsolete protocol versions 2 and 3

and some further tidying up.

Squashed commit of the following:

commit 7b13b9f046
Author: Simon <simon@gb7fr.org.uk>
Date:   Sun Jan 29 19:01:33 2023 +0000

    SERVER_ID is bytes!

commit cee3bc76fb
Author: Simon <simon@gb7fr.org.uk>
Date:   Sun Jan 29 18:50:06 2023 +0000

    frog

commit 82432b9c2c
Author: Simon <simon@gb7fr.org.uk>
Date:   Sun Jan 29 18:49:53 2023 +0000

    fred

commit 6601573c7f
Author: Simon <simon@gb7fr.org.uk>
Date:   Sun Jan 29 18:39:08 2023 +0000

    Stringly

commit 28fa37f828
Author: Simon <simon@gb7fr.org.uk>
Date:   Sun Jan 29 18:30:37 2023 +0000

    self

commit 3e6d28d4dd
Author: Simon <simon@gb7fr.org.uk>
Date:   Sun Jan 29 18:23:42 2023 +0000

    Fix trace

commit a15901dc79
Author: Simon <simon@gb7fr.org.uk>
Date:   Sun Jan 29 18:21:30 2023 +0000

    Tweak config file used in install script

commit 654ec135ca
Merge: f75ff26 d4e3922
Author: Simon <simon@gb7fr.org.uk>
Date:   Sun Jan 29 17:48:22 2023 +0000

    Merge branch 'master' into testing

commit f75ff26cfa
Merge: c0b5216 48339d3
Author: Simon <simon@gb7fr.org.uk>
Date:   Sun Jan 29 17:46:07 2023 +0000

    Merge branch 'master' into testing

commit c0b5216e5a
Author: Simon <simon@gb7fr.org.uk>
Date:   Sun Jan 29 11:04:45 2023 +0000

    more config work

commit c79ce0551d
Author: Simon <simon@gb7fr.org.uk>
Date:   Sun Jan 29 00:54:56 2023 +0000

    ib

commit 294a09c8f1
Author: Simon <simon@gb7fr.org.uk>
Date:   Sun Jan 29 00:50:36 2023 +0000

    Enable minimal config and tidy up global ACL

commit d1dc58d46f
Author: Simon <simon@gb7fr.org.uk>
Date:   Sat Jan 28 23:12:41 2023 +0000

    Deprecate protocol versions 2 and 3
api
Simon 3 years ago
parent d4e3922dc2
commit 2517d3ac21

@ -0,0 +1,42 @@
#This empty config file will use defaults for everything apart from OBP and HBP config
#This is usually a sensible choice.
[GLOBAL]
SERVER_ID: 0000
[REPORTS]
[LOGGER]
[ALIASES]
[ALLSTAR]
[SYSTEM]
MODE: MASTER
ENABLED: True
REPEAT: True
MAX_PEERS: 1
EXPORT_AMBE: False
IP: 127.0.0.1
PORT: 54000
PASSPHRASE:
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: 60
SINGLE_MODE: True
VOICE_IDENT: True
TS1_STATIC:
TS2_STATIC:
DEFAULT_REFLECTOR: 0
ANNOUNCEMENT_LANGUAGE: en_GB
GENERATOR: 100
ALLOW_UNREG_ID: False
PROXY_CONTROL: True
OVERRIDE_IDENT_TG:

@ -9,7 +9,7 @@ TGID_TS1_ACL: PERMIT:ALL
TGID_TS2_ACL: PERMIT:ALL TGID_TS2_ACL: PERMIT:ALL
GEN_STAT_BRIDGES: True GEN_STAT_BRIDGES: True
ALLOW_NULL_PASSPHRASE: True ALLOW_NULL_PASSPHRASE: True
ANNOUNCEMENT_LANGUAGES: en_GB,en_US,es_ES,fr_FR,de_DE,dk_DK,it_IT,no_NO,pl_PL,se_SE,pt_PT,cy_GB,el_GR,CW ANNOUNCEMENT_LANGUAGES:
SERVER_ID: 0000 SERVER_ID: 0000
DATA_GATEWAY: False DATA_GATEWAY: False
VALIDATE_SERVER_IDS: True VALIDATE_SERVER_IDS: True

@ -2536,7 +2536,7 @@ if __name__ == '__main__':
if cli_args.LOG_LEVEL: if cli_args.LOG_LEVEL:
CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL CONFIG['LOGGER']['LOG_LEVEL'] = cli_args.LOG_LEVEL
logger = log.config_logging(CONFIG['LOGGER']) logger = log.config_logging(CONFIG['LOGGER'])
logger.info('\n\nCopyright (c) 2020, 2021, 2022 Simon G7RZU simon@gb7fr.org.uk') logger.info('\n\nCopyright (c) 2020, 2021, 2022, 2023 Simon G7RZU simon@gb7fr.org.uk')
logger.info('Copyright (c) 2013, 2014, 2015, 2016, 2018, 2019\n\tThe Regents of the K0USY Group. All rights reserved.\n') logger.info('Copyright (c) 2013, 2014, 2015, 2016, 2018, 2019\n\tThe Regents of the K0USY Group. All rights reserved.\n')
logger.debug('(GLOBAL) Logging system started, anything from here on gets logged') logger.debug('(GLOBAL) Logging system started, anything from here on gets logged')

@ -182,7 +182,7 @@ def build_config(_config_file):
'TGID_URL': config.get(section, 'TGID_URL', fallback='https://freedmr-lh.gb7fr.org.uk/json/talkgroup_ids.json'), 'TGID_URL': config.get(section, 'TGID_URL', fallback='https://freedmr-lh.gb7fr.org.uk/json/talkgroup_ids.json'),
'STALE_TIME': config.getint(section, 'STALE_DAYS', fallback=1) * 86400, 'STALE_TIME': config.getint(section, 'STALE_DAYS', fallback=1) * 86400,
'SUB_MAP_FILE': config.get(section, 'SUB_MAP_FILE', fallback='sub_map.pkl'), 'SUB_MAP_FILE': config.get(section, 'SUB_MAP_FILE', fallback='sub_map.pkl'),
'LOCAL_SUBSCRIBER_FILE': config.get(section, 'LOCAL_SUBSCRIBER_FILE', fallback=''), 'LOCAL_SUBSCRIBER_FILE': config.get(section, 'LOCAL_SUBSCRIBER_FILE', fallback='local_subscribers.json'),
'SERVER_ID_URL': config.get(section, 'SERVER_ID_URL', fallback='https://freedmr-lh.gb7fr.org.uk/json/server_ids.tsv'), 'SERVER_ID_URL': config.get(section, 'SERVER_ID_URL', fallback='https://freedmr-lh.gb7fr.org.uk/json/server_ids.tsv'),
'SERVER_ID_FILE': config.get(section, 'SERVER_ID_FILE', fallback='server_ids.tsv'), 'SERVER_ID_FILE': config.get(section, 'SERVER_ID_FILE', fallback='server_ids.tsv'),
'CHECKSUM_URL': config.get(section, 'CHECKSUM_URL', fallback='https://freedmr-lh.gb7fr.org.uk/file_checksums.json'), 'CHECKSUM_URL': config.get(section, 'CHECKSUM_URL', fallback='https://freedmr-lh.gb7fr.org.uk/file_checksums.json'),
@ -304,52 +304,55 @@ def build_config(_config_file):
elif config.get(section, 'MODE') == 'MASTER': elif config.get(section, 'MODE') == 'MASTER':
CONFIG['SYSTEMS'].update({section: { CONFIG['SYSTEMS'].update({section: {
'MODE': config.get(section, 'MODE'), 'MODE': config.get(section, 'MODE'),
'ENABLED': config.getboolean(section, 'ENABLED'), 'ENABLED': config.getboolean(section, 'ENABLED', fallback=True ),
'REPEAT': config.getboolean(section, 'REPEAT'), 'REPEAT': config.getboolean(section, 'REPEAT', fallback=True),
'MAX_PEERS': config.getint(section, 'MAX_PEERS'), 'MAX_PEERS': config.getint(section, 'MAX_PEERS', fallback=1),
'IP': config.get(section, 'IP'), 'IP': config.get(section, 'IP', fallback='127.0.0.1'),
'PORT': config.getint(section, 'PORT'), 'PORT': config.getint(section, 'PORT', fallback=54000),
'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE'), 'utf-8'), 'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE', fallback=''), 'utf-8'),
'GROUP_HANGTIME': config.getint(section, 'GROUP_HANGTIME'), 'GROUP_HANGTIME': config.getint(section, 'GROUP_HANGTIME',fallback=5),
'USE_ACL': config.getboolean(section, 'USE_ACL'), 'USE_ACL': config.getboolean(section, 'USE_ACL', fallback=False),
'REG_ACL': config.get(section, 'REG_ACL'), 'REG_ACL': config.get(section, 'REG_ACL', fallback=''),
'SUB_ACL': config.get(section, 'SUB_ACL'), 'SUB_ACL': config.get(section, 'SUB_ACL', fallback=''),
'TG1_ACL': config.get(section, 'TGID_TS1_ACL'), 'TG1_ACL': config.get(section, 'TGID_TS1_ACL', fallback=''),
'TG2_ACL': config.get(section, 'TGID_TS2_ACL'), 'TG2_ACL': config.get(section, 'TGID_TS2_ACL', fallback=''),
'DEFAULT_UA_TIMER': config.getint(section, 'DEFAULT_UA_TIMER'), 'DEFAULT_UA_TIMER': config.getint(section, 'DEFAULT_UA_TIMER', fallback=10),
'SINGLE_MODE': config.getboolean(section, 'SINGLE_MODE'), 'SINGLE_MODE': config.getboolean(section, 'SINGLE_MODE', fallback=True),
'VOICE_IDENT': config.getboolean(section, 'VOICE_IDENT'), 'VOICE_IDENT': config.getboolean(section, 'VOICE_IDENT', fallback=True),
'TS1_STATIC': config.get(section,'TS1_STATIC'), 'TS1_STATIC': config.get(section,'TS1_STATIC', fallback=''),
'TS2_STATIC': config.get(section,'TS2_STATIC'), 'TS2_STATIC': config.get(section,'TS2_STATIC', fallback=''),
'DEFAULT_REFLECTOR': config.getint(section, 'DEFAULT_REFLECTOR'), 'DEFAULT_REFLECTOR': config.getint(section, 'DEFAULT_REFLECTOR'),
'GENERATOR': config.getint(section, 'GENERATOR'), 'GENERATOR': config.getint(section, 'GENERATOR', fallback=100),
'ANNOUNCEMENT_LANGUAGE': config.get(section, 'ANNOUNCEMENT_LANGUAGE'), 'ANNOUNCEMENT_LANGUAGE': config.get(section, 'ANNOUNCEMENT_LANGUAGE', fallback='en_GB'),
'ALLOW_UNREG_ID': config.getboolean(section,'ALLOW_UNREG_ID'), 'ALLOW_UNREG_ID': config.getboolean(section,'ALLOW_UNREG_ID', fallback=False),
'PROXY_CONTROL' : config.getboolean(section,'PROXY_CONTROL'), 'PROXY_CONTROL' : config.getboolean(section,'PROXY_CONTROL', fallback=True),
'OVERRIDE_IDENT_TG': config.get(section, 'OVERRIDE_IDENT_TG') 'OVERRIDE_IDENT_TG': config.get(section, 'OVERRIDE_IDENT_TG', fallback=False)
}}) }})
CONFIG['SYSTEMS'][section].update({'PEERS': {}}) CONFIG['SYSTEMS'][section].update({'PEERS': {}})
elif config.get(section, 'MODE') == 'OPENBRIDGE': elif config.get(section, 'MODE') == 'OPENBRIDGE':
CONFIG['SYSTEMS'].update({section: { CONFIG['SYSTEMS'].update({section: {
'MODE': config.get(section, 'MODE'), 'MODE': config.get(section, 'MODE'),
'ENABLED': config.getboolean(section, 'ENABLED'), 'ENABLED': config.getboolean(section, 'ENABLED', fallback=True),
'NETWORK_ID': config.getint(section, 'NETWORK_ID').to_bytes(4, 'big'), 'NETWORK_ID': config.getint(section, 'NETWORK_ID').to_bytes(4, 'big'),
#'OVERRIDE_SERVER_ID': config.getint(section, 'OVERRIDE_SERVER_ID').to_bytes(4, 'big'), #'OVERRIDE_SERVER_ID': config.getint(section, 'OVERRIDE_SERVER_ID').to_bytes(4, 'big'),
'IP': config.get(section, 'IP'), 'IP': config.get(section, 'IP', fallback=''),
'PORT': config.getint(section, 'PORT'), 'PORT': config.getint(section, 'PORT'),
'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE').ljust(20,'\x00')[:20], 'utf-8'), 'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE').ljust(20,'\x00')[:20], 'utf-8'),
#'TARGET_SOCK': (gethostbyname(config.get(section, 'TARGET_IP')), config.getint(section, 'TARGET_PORT')), #'TARGET_SOCK': (gethostbyname(config.get(section, 'TARGET_IP')), config.getint(section, 'TARGET_PORT')),
'TARGET_IP': config.get(section, 'TARGET_IP'), 'TARGET_IP': config.get(section, 'TARGET_IP'),
'TARGET_PORT': config.getint(section, 'TARGET_PORT'), 'TARGET_PORT': config.getint(section, 'TARGET_PORT'),
'USE_ACL': config.getboolean(section, 'USE_ACL'), 'USE_ACL': config.getboolean(section, 'USE_ACL', fallback=False),
'SUB_ACL': config.get(section, 'SUB_ACL'), 'SUB_ACL': config.get(section, 'SUB_ACL', fallback=''),
'TG1_ACL': config.get(section, 'TGID_ACL'), 'TG1_ACL': config.get(section, 'TGID_ACL', fallback=''),
'TG2_ACL': 'PERMIT:ALL', 'TG2_ACL': 'PERMIT:ALL',
'RELAX_CHECKS': config.getboolean(section, 'RELAX_CHECKS'), 'RELAX_CHECKS': config.getboolean(section, 'RELAX_CHECKS', fallback=True),
'ENHANCED_OBP': config.getboolean(section, 'ENHANCED_OBP'), 'ENHANCED_OBP': config.getboolean(section, 'ENHANCED_OBP',fallback=True),
'VER' : config.getint(section, 'PROTO_VER') 'VER' : config.getint(section, 'PROTO_VER', fallback=5)
}}) }})
if CONFIG['SYSTEMS'][section]['VER'] in (0,2,3) or CONFIG['SYSTEMS'][section]['VER'] > 5:
sys.exit('(%s) PROTO_VER not valid',section)
try: try:

@ -70,66 +70,32 @@ chown 54000:54000 /etc/freedmr/json &&
echo Install /etc/freedmr/freedmr.cfg ... echo Install /etc/freedmr/freedmr.cfg ...
cat << EOF > /etc/freedmr/freedmr.cfg cat << EOF > /etc/freedmr/freedmr.cfg
#This empty config file will use defaults for everything apart from OBP and HBP config
#This is usually a sensible choice.
#I have moved to a config like this to encourage servers to use the accepted defaults
#unless you really know what you are doing.
[GLOBAL] [GLOBAL]
PATH: ./ #If you join the FreeDMR network, you need to add your ServerID Here.
PING_TIME: 10
MAX_MISSED: 3
USE_ACL: True
REG_ACL: DENY:0-100000
SUB_ACL: DENY:0-100000
TGID_TS1_ACL: PERMIT:ALL
TGID_TS2_ACL: PERMIT:ALL
GEN_STAT_BRIDGES: True
ALLOW_NULL_PASSPHRASE: True
ANNOUNCEMENT_LANGUAGES:
SERVER_ID: 0 SERVER_ID: 0
DATA_GATEWAY: False
VALIDATE_SERVER_IDS: True
[REPORTS] [REPORTS]
REPORT: True
REPORT_INTERVAL: 60
REPORT_PORT: 4321
REPORT_CLIENTS: *
[LOGGER] [LOGGER]
LOG_FILE: /dev/null
LOG_HANDLERS: console-timed
LOG_LEVEL: INFO
LOG_NAME: FreeDMR
[ALIASES] [ALIASES]
TRY_DOWNLOAD: True
PATH: ./json/
PEER_FILE: peer_ids.json
SUBSCRIBER_FILE: subscriber_ids.json
TGID_FILE: talkgroup_ids.json
PEER_URL: https://freedmr-lh.gb7fr.org.uk/json/peer_ids.json
SUBSCRIBER_URL: https://freedmr-lh.gb7fr.org.uk/json/subscriber_ids.json
TGID_URL: https://freedmr-lh.gb7fr.org.uk/json/talkgroup_ids.json
LOCAL_SUBSCRIBER_FILE: local_subcriber_ids.json
STALE_DAYS: 1
SUB_MAP_FILE: sub_map.pkl
SERVER_ID_URL: https://freedmr-lh.gb7fr.org.uk/json/server_ids.tsv
SERVER_ID_FILE: server_ids.tsv
CHECKSUM_URL: https://freedmr-lh.gb7fr.org.uk/file_checksums.json
CHECKSUM_FILE: file_checksums.json
#Control server shared allstar instance via dial / AMI
[ALLSTAR] [ALLSTAR]
ENABLED: false
USER:admin
PASS: password
SERVER: asl.example.com
PORT: 5038
NODE: 11111
#This is an example OpenBridgeProtocol (OBP) or FreeBridgeProtocol (FBP) configuration
#If you joing FreeDMR, you will be given a config like this to paste in
[OBP-TEST] [OBP-TEST]
MODE: OPENBRIDGE MODE: OPENBRIDGE
ENABLED: False ENABLED: False
IP: IP:
PORT: 62044 PORT: 62044
#The ID which you expect to see sent from the other end of the link.
NETWORK_ID: 1 NETWORK_ID: 1
PASSPHRASE: mypass PASSPHRASE: mypass
TARGET_IP: TARGET_IP:
@ -137,11 +103,17 @@ TARGET_PORT: 62044
USE_ACL: True USE_ACL: True
SUB_ACL: DENY:1 SUB_ACL: DENY:1
TGID_ACL: PERMIT:ALL TGID_ACL: PERMIT:ALL
#Should always be true if using docker.
RELAX_CHECKS: True RELAX_CHECKS: True
#True for FBP, False for OBP
ENHANCED_OBP: True ENHANCED_OBP: True
PROTO_VER: 2 #PROTO_VER should be 5 for FreeDMR servers using FBP
#1 for other servers using OBP
PROTO_VER: 5
#This defines parameters for repeater/hotspot connections
#via HomeBrewProtocol (HBP)
#I don't recommend changing most of this unless you know what you are doing
[SYSTEM] [SYSTEM]
MODE: MASTER MODE: MASTER
ENABLED: True ENABLED: True
@ -169,6 +141,7 @@ ALLOW_UNREG_ID: False
PROXY_CONTROL: True PROXY_CONTROL: True
OVERRIDE_IDENT_TG: OVERRIDE_IDENT_TG:
#Echo (Loro / Parrot) server
[ECHO] [ECHO]
MODE: PEER MODE: PEER
ENABLED: True ENABLED: True

@ -201,20 +201,10 @@ class OPENBRIDGE(DatagramProtocol):
self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT'])) self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT']))
elif 'VER' in self._config and self._config['VER'] == 3: elif 'VER' in self._config and self._config['VER'] == 3:
_packet = b''.join([DMRF,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:]]) logger.error('(%s) protocol version 3 no longer supported',self._system)
_h = blake2b(key=self._config['PASSPHRASE'], digest_size=16)
_h.update(_packet)
_hash = _h.digest()
_packet = b''.join([_packet,time_ns().to_bytes(8,'big'), _hops, _hash])
self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT']))
elif 'VER' in self._config and self._config['VER'] == 2: elif 'VER' in self._config and self._config['VER'] == 2:
_packet = b''.join([DMRF,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:], time_ns().to_bytes(8,'big')]) logger.error('(%s) protocol version 2 no longer supported',self._system)
_h = blake2b(key=self._config['PASSPHRASE'], digest_size=16)
_h.update(_packet)
_hash = _h.digest()
_packet = b''.join([_packet,_hops, _hash])
self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT']))
# KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!!
#logger.debug('(%s) TX Packet to OpenBridge %s:%s -- %s %s', self._system, self._config['TARGET_IP'], self._config['TARGET_PORT'], _packet, _hash) #logger.debug('(%s) TX Packet to OpenBridge %s:%s -- %s %s', self._system, self._config['TARGET_IP'], self._config['TARGET_PORT'], _packet, _hash)
else: else:
@ -486,122 +476,39 @@ class OPENBRIDGE(DatagramProtocol):
self.send_bcsq(_dst_id,_stream_id) self.send_bcsq(_dst_id,_stream_id)
return return
#Low-level TG filtering #Low-level TG filtering
if _call_type != 'unit': if _call_type != 'unit':
_int_dst_id = int_id(_dst_id) _int_dst_id = int_id(_dst_id)
if _int_dst_id <= 79 or (_int_dst_id >= 9990 and _int_dst_id <= 9999) or _int_dst_id == 900999:
if _stream_id not in self._laststrid: if _int_dst_id <= 79:
logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL TG FILTER', self._system, int_id(_stream_id), _int_dst_id)
self.send_bcsq(_dst_id,_stream_id)
self._laststrid.append(_stream_id)
return
# ACL Processing
if self._CONFIG['GLOBAL']['USE_ACL']:
if not acl_check(_rf_src, self._CONFIG['GLOBAL']['SUB_ACL']):
if _stream_id not in self._laststrid:
logger.info('(%s) CALL DROPPED WITH STREAM ID %s ON TGID %s BY GLOBAL TS1 ACL', self._system, int_id(_stream_id), int_id(_rf_src))
self.send_bcsq(_dst_id,_stream_id)
self._laststrid.append(_stream_id)
return
if _slot == 1 and not acl_check(_dst_id, self._CONFIG['GLOBAL']['TG1_ACL']):
if _stream_id not in self._laststrid: if _stream_id not in self._laststrid:
logger.info('(%s) CALL DROPPED WITH STREAM ID %s ON TGID %s BY GLOBAL TS1 ACL', self._system, int_id(_stream_id), int_id(_dst_id)) logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL TG FILTER (local to repeater)', self._system, int_id(_stream_id), _int_dst_id)
self.send_bcsq(_dst_id,_stream_id) self.send_bcsq(_dst_id,_stream_id)
self._laststrid.append(_stream_id) self._laststrid.append(_stream_id)
return return
if self._config['USE_ACL']:
if not acl_check(_rf_src, self._config['SUB_ACL']): if (_int_dst_id >= 9990 and _int_dst_id <= 9999) or _int_dst_id == 900999:
if _stream_id not in self._laststrid: if _stream_id not in self._laststrid:
logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY SYSTEM ACL', self._system, int_id(_stream_id), int_id(_rf_src)) logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL TG FILTER (local to server)', self._system, int_id(_stream_id), _int_dst_id)
self.send_bcsq(_dst_id,_stream_id) self.send_bcsq(_dst_id,_stream_id)
self._laststrid.append(_stream_id) self._laststrid.append(_stream_id)
return return
if not acl_check(_dst_id, self._config['TG1_ACL']):
if (_int_dst_id >= 92 and _int_dst_id <= 199) and int(str(int.from_bytes(_source_server,'big'))[:4]) != int(str(int.from_bytes(self._CONFIG['GLOBAL']['SERVER_ID'],'big'))[:4]):
if _stream_id not in self._laststrid: if _stream_id not in self._laststrid:
logger.info('(%s) CALL DROPPED WITH STREAM ID %s ON TGID %s BY SYSTEM ACL', self._system, int_id(_stream_id), int_id(_dst_id)) logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL TG FILTER (local to server main ID)', self._system, int_id(_stream_id), _int_dst_id)
self.send_bcsq(_dst_id,_stream_id) self.send_bcsq(_dst_id,_stream_id)
self._laststrid.append(_stream_id) self._laststrid.append(_stream_id)
return return
_data = b''.join([DMRD,_data[4:]]) if (_int_dst_id >= 80 and _int_dst_id <= 89) or (_int_dst_id >= 800 and _int_dst_id <= 899) and int(str(int.from_bytes(_source_server,'big'))[:3]) != int(str(int.from_bytes(self._CONFIG['GLOBAL']['SERVER_ID'],'big'))[:3]):
_hops = _inthops.to_bytes(1,'big')
# Userland actions -- typically this is the function you subclass for an application
self.dmrd_received(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash,_hops,_source_server,_ber,_rssi,_source_rptr)
#Silently treat a DMRD packet like a keepalive - this is because it's traffic and the
#Other end may not have enabled ENAHNCED_OBP
self._config['_bcka'] = time()
else:
h,p = _sockaddr
logger.warning('(%s) FreeBridge HMAC failed, packet discarded - OPCODE: %s DATA: %s HMAC LENGTH: %s HMAC: %s SRC IP: %s SRC PORT: %s', self._system, _packet[:4], repr(_packet[:69]), len(_packet[69:]), repr(_packet[61:]),h,p)
elif _packet[:4] == DMRF:
_data = _packet[:53]
_timestamp = _packet[53:60]
_hops = _packet[61]
_hash = _packet[62:]
#_ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest()
_h = blake2b(key=self._config['PASSPHRASE'], digest_size=16)
if 'VER' in self._config and self._config['VER'] > 2:
_h.update(_packet[:53])
elif 'VER' in self._config and self._config['VER'] == 2:
_h.update(_packet[:61])
_ckhs = _h.digest()
if compare_digest(_hash, _ckhs) and (_sockaddr == self._config['TARGET_SOCK'] or self._config['RELAX_CHECKS']):
_peer_id = _data[11:15]
if self._config['NETWORK_ID'] != _peer_id:
if _stream_id not in self._laststrid:
logger.error('(%s) OpenBridge packet discarded because NETWORK_ID: %s Does not match sent Peer ID: %s', self._system, int_id(self._config['NETWORK_ID']), int_id(_peer_id))
self._laststrid.append(_stream_id)
return
_seq = _data[4]
_rf_src = _data[5:8]
_dst_id = _data[8:11]
_int_dst_id = int_id(_dst_id)
_bits = _data[15]
_slot = 2 if (_bits & 0x80) else 1
#_call_type = 'unit' if (_bits & 0x40) else 'group'
if _bits & 0x40:
_call_type = 'unit'
elif (_bits & 0x23) == 0x23:
_call_type = 'vcsbk'
else:
_call_type = 'group'
_frame_type = (_bits & 0x30) >> 4
_dtype_vseq = (_bits & 0xF) # data, 1=voice header, 2=voice terminator; voice, 0=burst A ... 5=burst F
_stream_id = _data[16:20]
#logger.debug('(%s) DMRD - Seqence: %s, RF Source: %s, Destination ID: %s', self._system, int_id(_seq), int_id(_rf_src), int_id(_dst_id))
#Don't do anything if we are STUNned
if 'STUN' in self._CONFIG:
if _stream_id not in self._laststrid: if _stream_id not in self._laststrid:
logger.warning('(%s) Bridge STUNned, discarding', self._system) logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL TG FILTER (local to MCC)', self._system, int_id(_stream_id), _int_dst_id)
self._laststrid.append(_stream_id)
return
#Increment max hops
_inthops = _hops +1
if _inthops > 10:
logger.warning('(%s) MAX HOPS exceed, dropping. Hops: %s, DST: %s', self._system, _inthops, _int_dst_id)
self.send_bcsq(_dst_id,_stream_id)
return
#Low-level TG filtering
if _call_type != 'unit':
_int_dst_id = int_id(_dst_id)
if _int_dst_id <= 79 or (_int_dst_id >= 9990 and _int_dst_id <= 9999) or _int_dst_id == 900999:
if _stream_id not in self._laststrid:
logger.info('(%s) CALL DROPPED WITH STREAM ID %s FROM SUBSCRIBER %s BY GLOBAL TG FILTER', self._system, int_id(_stream_id), _int_dst_id)
self.send_bcsq(_dst_id,_stream_id) self.send_bcsq(_dst_id,_stream_id)
self._laststrid.append(_stream_id) self._laststrid.append(_stream_id)
return return
# ACL Processing # ACL Processing
if self._CONFIG['GLOBAL']['USE_ACL']: if self._CONFIG['GLOBAL']['USE_ACL']:
@ -630,23 +537,22 @@ class OPENBRIDGE(DatagramProtocol):
self.send_bcsq(_dst_id,_stream_id) self.send_bcsq(_dst_id,_stream_id)
self._laststrid.append(_stream_id) self._laststrid.append(_stream_id)
return return
#Remove timestamp from data. For now dmrd_received does not expect it
#Leaving it in screws up the AMBE data
#_data = b''.join([_data[:5],_data[12:]])
_data = b''.join([DMRD,_data[4:]]) _data = b''.join([DMRD,_data[4:]])
_hops = _inthops.to_bytes(1,'big') _hops = _inthops.to_bytes(1,'big')
# Userland actions -- typically this is the function you subclass for an application # Userland actions -- typically this is the function you subclass for an application
self.dmrd_received(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash,_hops) self.dmrd_received(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash,_hops,_source_server,_ber,_rssi,_source_rptr)
#Silently treat a DMRD packet like a keepalive - this is because it's traffic and the #Silently treat a DMRD packet like a keepalive - this is because it's traffic and the
#Other end may not have enabled ENAHNCED_OBP #Other end may not have enabled ENAHNCED_OBP
self._config['_bcka'] = time() self._config['_bcka'] = time()
else: else:
h,p = _sockaddr h,p = _sockaddr
logger.warning('(%s) FreeBridge HMAC failed, packet discarded - OPCODE: %s DATA: %s HMAC LENGTH: %s HMAC: %s SRC IP: %s SRC PORT: %s', self._system, _packet[:4], repr(_packet[:61]), len(_packet[61:]), repr(_packet[61:]),h,p) logger.warning('(%s) FreeBridge HMAC failed, packet discarded - OPCODE: %s DATA: %s HMAC LENGTH: %s HMAC: %s SRC IP: %s SRC PORT: %s', self._system, _packet[:4], repr(_packet[:69]), len(_packet[69:]), repr(_packet[61:]),h,p)
elif _packet[:4] == DMRF:
logger.error('(%s) Protocol versions 2 and 3 no longer supported',self._system)
if self._config['ENHANCED_OBP']: if self._config['ENHANCED_OBP']:
if _packet[:2] == BC: # Bridge Control packet (Extended OBP) if _packet[:2] == BC: # Bridge Control packet (Extended OBP)
@ -703,7 +609,9 @@ class OPENBRIDGE(DatagramProtocol):
if compare_digest(_hash, _ckhs): if compare_digest(_hash, _ckhs):
logger.trace('(%s) *ProtoControl* BCVE Version received, Ver: %s',self._system,_ver) logger.trace('(%s) *ProtoControl* BCVE Version received, Ver: %s',self._system,_ver)
if _ver > self._config['VER']: if _ver == 2 or _ver == 3 or _ver > 5:
logger.info('(%s) *ProtoControl* BCVE Version not supported, Ver: %s',self._system,_ver)
elif _ver > self._config['VER']:
logger.info('(%s) *ProtoControl* BCVE Version upgrade, Ver: %s',self._system,_ver) logger.info('(%s) *ProtoControl* BCVE Version upgrade, Ver: %s',self._system,_ver)
self._config['VER'] = _ver self._config['VER'] = _ver
elif _ver == self._config['VER']: elif _ver == self._config['VER']:
@ -927,7 +835,6 @@ class HBSYSTEM(DatagramProtocol):
# Extract the command, which is various length, all but one 4 significant characters -- RPTCL # Extract the command, which is various length, all but one 4 significant characters -- RPTCL
_command = _data[:4] _command = _data[:4]
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]
if _peer_id in self._peers \ if _peer_id in self._peers \

Loading…
Cancel
Save

Powered by TurnKey Linux.