diff --git a/bridge_master.py b/bridge_master.py index 7d5cfe5..b1aae01 100644 --- a/bridge_master.py +++ b/bridge_master.py @@ -1237,7 +1237,7 @@ class routerOBP(OPENBRIDGE): OPENBRIDGE.__init__(self, _name, _config, _report) self.STATUS = {} - def to_target(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,_noOBP,sysIgnore, _hops = b''): + def to_target(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,_noOBP,sysIgnore, _hops = b'', _source_server = b'\x00\x00\x00\x00', _ber = b'\x00', _rssi = b'\x00'): _sysIgnore = sysIgnore for _target in BRIDGES[_bridge]: if (_target['SYSTEM'] != self._system) and (_target['ACTIVE']): @@ -1406,10 +1406,11 @@ class routerOBP(OPENBRIDGE): elif _dtype_vseq in [1,2,3,4]: dmrbits = dmrbits[0:116] + _target_status[_target['TS']]['TX_EMB_LC'][_dtype_vseq] + dmrbits[148:264] dmrpkt = dmrbits.tobytes() - _tmp_data = b''.join([_tmp_data, dmrpkt, b'\x00\x00']) # Add two bytes of nothing since OBP doesn't include BER & RSSI bytes #_data[53:55] + #_tmp_data = b''.join([_tmp_data, dmrpkt, b'\x00\x00']) # Add two bytes of nothing since OBP doesn't include BER & RSSI bytes #_data[53:55] + _tmp_data = b''.join([_tmp_data, dmrpkt]) # Transmit the packet to the destination system - systems[_target['SYSTEM']].send_system(_tmp_data,_hops) + systems[_target['SYSTEM']].send_system(_tmp_data,_hops,_ber,_rssi,_source_server) #logger.debug('(%s) Packet routed by bridge: %s to system: %s TS: %s, TGID: %s', self._system, _bridge, _target['SYSTEM'], _target['TS'], int_id(_target['TGID'])) #Ignore this system and TS pair if it's called again on this packet return(_sysIgnore) @@ -1424,7 +1425,7 @@ class routerOBP(OPENBRIDGE): if CONFIG['REPORTS']['REPORT']: systems[_d_system]._report.send_bridgeEvent('UNIT DATA,START,TX,{},{},{},{},{},{}'.format(_d_system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), 1, _int_dst_id).encode(encoding='utf-8', errors='ignore')) - def sendDataToOBP(self,_target,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops = b''): + def sendDataToOBP(self,_target,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops = b'',_source_server = b'\x00\x00\x00\x00', _ber = b'\x00', _rssi = b'\x00'): _int_dst_id = int_id(_dst_id) _target_status = systems[_target].STATUS @@ -1458,20 +1459,26 @@ class routerOBP(OPENBRIDGE): #Assemble transmit HBP packet header _tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]]) _tmp_data = b''.join([_tmp_data, dmrpkt]) - systems[_target].send_system(_tmp_data,_hops) + systems[_target].send_system(_tmp_data,_hops,_ber,_rssi, _source_server) logger.info('(%s) UNIT Data Bridged to OBP System: %s DST_ID: %s', self._system, _target,_int_dst_id) if CONFIG['REPORTS']['REPORT']: systems[_target]._report.send_bridgeEvent('UNIT DATA,START,TX,{},{},{},{},{},{}'.format(_target, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), 1, _int_dst_id).encode(encoding='utf-8', errors='ignore')) - def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash, _hops = b''): + def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash, _hops = b'', _source_server = b'\x00\x00\x00\x00', _ber = b'\x00', _rssi = b'\x00'): pkt_time = time() dmrpkt = _data[20:53] _bits = _data[15] #pkt_crc = Crc32.calc(_data[4:53]) #_pkt_crc = Crc32.calc(dmrpkt) - _pkt_crc = _hash + + #Use blake2b hash + _h = blake2b(digest_size=16) + _h.update(_data) + _pkt_crc = _h.digest() + + #_pkt_crc = _hash # Match UNIT data, SMS/GPS, and send it to the dst_id if it is in SUB_MAP if _call_type == 'unit' and (_dtype_vseq == 6 or _dtype_vseq == 7 or _dtype_vseq == 8 or ((_stream_id not in self.STATUS) and _dtype_vseq == 3)): @@ -1569,8 +1576,9 @@ class routerOBP(OPENBRIDGE): if system == self._system: continue #We only want to send data calls to individual IDs via OpenBridge - if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and (_int_dst_id >= 1000000): - self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops) + #Only send if proto ver for bridge is > 1 + if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and CONFIG['SYSTEMS'][system]['VER'] > 1 and (_int_dst_id >= 1000000): + self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops,_source_server,_ber,_rssi) #If destination ID is in the Subscriber Map if _dst_id in SUB_MAP: @@ -1649,8 +1657,8 @@ class routerOBP(OPENBRIDGE): _inthops = 0 if _hops: _inthops = int.from_bytes(_hops,'big') - logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, HOPS %s', \ - self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,_inthops) + logger.info('(%s) *CALL START* STREAM ID: %s SUB: %s (%s) PEER: %s (%s) TGID %s (%s), TS %s, SRC: %s, BER: %s, RSSI %s, HOPS %s', \ + self._system, int_id(_stream_id), get_alias(_rf_src, subscriber_ids), int_id(_rf_src), get_alias(_peer_id, peer_ids), int_id(_peer_id), get_alias(_dst_id, talkgroup_ids), int_id(_dst_id), _slot,int_id(_source_server),int.from_bytes(_ber,'big'),int.from_bytes(_rssi,'big'),_inthops) if CONFIG['REPORTS']['REPORT']: self._report.send_bridgeEvent('GROUP VOICE,START,RX,{},{},{},{},{},{}'.format(self._system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), _slot, int_id(_dst_id)).encode(encoding='utf-8', errors='ignore')) @@ -1722,7 +1730,6 @@ class routerOBP(OPENBRIDGE): logger.warning("(%s) *PacketControl* RATE DROP! Stream ID:, %s TGID: %s",self._system,int_id(_stream_id),int_id(_dst_id)) return - #Duplicate handling# #Handle inbound duplicates #Duplicate complete packet @@ -1769,7 +1776,7 @@ class routerOBP(OPENBRIDGE): for _system in BRIDGES[_bridge]: if _system['SYSTEM'] == self._system and _system['TGID'] == _dst_id and _system['TS'] == _slot and _system['ACTIVE'] == True: - _sysIgnore = self.to_target(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,False,_sysIgnore,_hops) + _sysIgnore = self.to_target(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,False,_sysIgnore,_hops, _source_server, _ber, _rssi) # Final actions - Is this a voice terminator? @@ -1858,7 +1865,7 @@ class routerHBP(HBSYSTEM): } } - def to_target(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,_noOBP,sysIgnore): + def to_target(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,_noOBP,sysIgnore,_source_server, _ber, _rssi): _sysIgnore = sysIgnore for _target in BRIDGES[_bridge]: #if _target['SYSTEM'] != self._system or (_target['SYSTEM'] == self._system and _target['TS'] != _slot): @@ -2025,7 +2032,7 @@ class routerHBP(HBSYSTEM): _tmp_data = b''.join([_tmp_data, dmrpkt, _data[53:55]]) # Transmit the packet to the destination system - systems[_target['SYSTEM']].send_system(_tmp_data,None) + systems[_target['SYSTEM']].send_system(_tmp_data,b'',_ber,_rssi,_source_server) return _sysIgnore @@ -2039,7 +2046,7 @@ class routerHBP(HBSYSTEM): if CONFIG['REPORTS']['REPORT']: systems[_d_system]._report.send_bridgeEvent('UNIT DATA,START,TX,{},{},{},{},{},{}'.format(_d_system, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), 1, _int_dst_id).encode(encoding='utf-8', errors='ignore')) - def sendDataToOBP(self,_target,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops = b''): + def sendDataToOBP(self,_target,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot,_hops = b'',_ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00'): # _sysIgnore = sysIgnore _int_dst_id = int_id(_dst_id) _target_status = systems[_target].STATUS @@ -2048,7 +2055,7 @@ class routerHBP(HBSYSTEM): #We want to ignore this system and TS combination if it's called again for this packet # _sysIgnore.append((_target,_target['TS'])) - #If target has missed 6 (on 1 min) of keepalives, don't send + #If target has missed 6 (in 1 min) of keepalives, don't send if _target_system['ENHANCED_OBP'] and '_bcka' in _target_system and _target_system['_bcka'] < pkt_time - 60: return @@ -2074,7 +2081,7 @@ class routerHBP(HBSYSTEM): #Assemble transmit HBP packet header _tmp_data = b''.join([_data[:15], _tmp_bits.to_bytes(1, 'big'), _data[16:20]]) _tmp_data = b''.join([_tmp_data, dmrpkt]) - systems[_target].send_system(_tmp_data,None) + systems[_target].send_system(_tmp_data,b'',_ber,_rssi,_source_server) logger.info('(%s) UNIT Data Bridged to OBP System: %s DST_ID: %s', self._system, _target,_int_dst_id) if CONFIG['REPORTS']['REPORT']: systems[system]._report.send_bridgeEvent('UNIT DATA,START,TX,{},{},{},{},{},{}'.format(_target, int_id(_stream_id), int_id(_peer_id), int_id(_rf_src), 1, _int_dst_id).encode(encoding='utf-8', errors='ignore')) @@ -2083,8 +2090,14 @@ class routerHBP(HBSYSTEM): def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data): pkt_time = time() dmrpkt = _data[20:53] + + _ber = _data[53:54] + _rssi = _data[54:55] + _bits = _data[15] + _source_server = self._CONFIG['GLOBAL']['SERVER_ID'] + #_pkt_crc = Crc32.calc(_data[4:53]) #_pkt_crc = hash(_data).digest() @@ -2159,7 +2172,7 @@ class routerHBP(HBSYSTEM): if system == self._system: continue #We only want to send data calls to individual IDs via OpenBridge - if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and (_int_dst_id >= 1000000): + if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE' and CONFIG['SYSTEMS'][system]['VER'] > 1 and (_int_dst_id >= 1000000): self.sendDataToOBP(system,_data,dmrpkt,pkt_time,_stream_id,_dst_id,_peer_id,_rf_src,_bits,_slot) @@ -2546,7 +2559,7 @@ class routerHBP(HBSYSTEM): if True: for _system in BRIDGES[_bridge]: if _system['SYSTEM'] == self._system and _system['TGID'] == _dst_id and _system['TS'] == _slot and _system['ACTIVE'] == True: - _sysIgnore = self.to_target(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,False,_sysIgnore) + _sysIgnore = self.to_target(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,False,_sysIgnore,_source_server,_ber,_rssi) #Send to reflector or TG too, if it exists if _bridge[0:1] == '#': @@ -2554,7 +2567,7 @@ class routerHBP(HBSYSTEM): else: _bridge = '#'+_bridge if _bridge in BRIDGES: - _sysIgnore = self.to_target(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,False,_sysIgnore) + _sysIgnore = self.to_target(_peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data, pkt_time, dmrpkt, _bits,_bridge,_system,False,_sysIgnore,_source_server,_ber,_rssi) # Final actions - Is this a voice terminator? if (_frame_type == HBPF_DATA_SYNC) and (_dtype_vseq == HBPF_SLT_VTERM) and (self.STATUS[_slot]['RX_TYPE'] != HBPF_SLT_VTERM): diff --git a/const.py b/const.py index 1da03cb..efa30e9 100755 --- a/const.py +++ b/const.py @@ -81,7 +81,7 @@ BCST = b'BCST' BCVE = b'BCVE' #Protocol version -VER = 2 +VER = 4 # Higheset peer ID permitted by HBP PEER_MAX = 4294967295 diff --git a/doc/FreeDMR FBP Proto v4.ods b/doc/FreeDMR FBP Proto v4.ods new file mode 100644 index 0000000..f2f2a32 Binary files /dev/null and b/doc/FreeDMR FBP Proto v4.ods differ diff --git a/hblink.py b/hblink.py index 42ae6df..46be260 100755 --- a/hblink.py +++ b/hblink.py @@ -144,7 +144,7 @@ class OPENBRIDGE(DatagramProtocol): def dereg(self): logger.info('(%s) is mode OPENBRIDGE. No De-Registration required, continuing shutdown', self._system) - def send_system(self, _packet,_hops = b''): + def send_system(self, _packet, _hops = b'', _ber = b'\x00', _rssi = b'\x00', _source_server = b'\x00\x00\x00\x00'): #Don't do anything if we are STUNned if 'STUN' in self._CONFIG: logger.info('(%s) Bridge STUNned, discarding', self._system) @@ -156,7 +156,25 @@ class OPENBRIDGE(DatagramProtocol): if _packet[:3] == DMR and self._config['TARGET_IP']: - if 'VER' in self._config and self._config['VER'] > 1: + + if 'VER' in self._config and self._config['VER'] > 3: + _ver = VER.to_bytes(1,'big') + _packet = b''.join([DMRE,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:],_ber,_rssi,_ver,time_ns().to_bytes(8,'big'), _source_server, _hops]) + _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) + _h.update(_packet) + _hash = _h.digest() + _packet = b''.join([_packet, _hash]) + self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT'])) + + elif 'VER' in self._config and self._config['VER'] == 3: + _packet = b''.join([DMRF,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:]]) + _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: _packet = b''.join([DMRF,_packet[4:11], self._CONFIG['GLOBAL']['SERVER_ID'],_packet[15:], time_ns().to_bytes(8,'big')]) _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) _h.update(_packet) @@ -215,7 +233,7 @@ class OPENBRIDGE(DatagramProtocol): - def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash,_hops = b''): + def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data,_hash,_hops = b'', _source_server = b'\x00\x00\x00\x00', _ber = b'\x00', _rssi = b'\x00'): pass #print(int_id(_peer_id), int_id(_rf_src), int_id(_dst_id), int_id(_seq), _slot, _call_type, _frame_type, repr(_dtype_vseq), int_id(_stream_id)) @@ -225,11 +243,14 @@ class OPENBRIDGE(DatagramProtocol): if _packet[:3] == DMR: # DMRData -- encapsulated DMR data frame if _packet[:4] == DMRD: + _data = _packet[:53] + _stream_id = _data[16:20] if self._config['VER'] > 1: - logger.warning('(%s) *ProtoControl* Version 1 protocol prohibited by PROTO_VER, Ver: %s',self._system,self._config['VER']) + if _stream_id not in self._laststrid: + logger.warning('(%s) *ProtoControl* Version 1 protocol prohibited by PROTO_VER, Ver: %s',self._system,self._config['VER']) + self._laststrid.append(_stream_id) self.send_bcve() return - _data = _packet[:53] _hash = _packet[53:] _ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest() @@ -252,7 +273,6 @@ class OPENBRIDGE(DatagramProtocol): _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)) @@ -319,6 +339,122 @@ class OPENBRIDGE(DatagramProtocol): elif _packet[:4] == EOBP: logger.warning('(%s) *ProtoControl* KF7EEL EOBP protocol not supported',self._system) return + + elif _packet[:4] == DMRE: + _data = _packet[:53] + _ber = _packet[53:54] + _rssi = _packet[54:55] + _embedded_version = _packet[55] + self._config['VER'] = _embedded_version + _timestamp = _packet[56:64] + _source_server = _packet[64:68] + _hops = _packet[68] + _hash = _packet[69:85] + #_ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest() + _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) + _h.update(_packet[:69]) + + _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: + 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)) + 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: + logger.warning('(%s) Bridge STUNned, discarding', self._system) + self._laststrid.append(_stream_id) + return + + #Discard old packets + if (int.from_bytes(_timestamp,'big')/1000000000) < (time() - 2): + logger.warning('(%s) Packet more than 2s old!, discarding', self._system) + 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._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: + 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)) + self.send_bcsq(_dst_id,_stream_id) + self._laststrid.append(_stream_id) + return + if self._config['USE_ACL']: + if not acl_check(_rf_src, self._config['SUB_ACL']): + 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)) + self.send_bcsq(_dst_id,_stream_id) + self._laststrid.append(_stream_id) + return + if not acl_check(_dst_id, self._config['TG1_ACL']): + 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)) + self.send_bcsq(_dst_id,_stream_id) + self._laststrid.append(_stream_id) + 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:]]) + + _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) + #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] @@ -327,7 +463,11 @@ class OPENBRIDGE(DatagramProtocol): _hash = _packet[62:] #_ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest() _h = blake2b(key=self._config['PASSPHRASE'], digest_size=16) - _h.update(_packet[:61]) + 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']): @@ -598,8 +738,9 @@ class HBSYSTEM(DatagramProtocol): def updateSockaddr_errback(self,failure): logger.info('(%s) hostname resolution error: %s',self._system,failure) - def send_peers(self, _packet, _hops = b''): + def send_peers(self, _packet, _hops = b'', _ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00'): for _peer in self._peers: + _packet =b''.join([_packet,_ber,_rssi]) self.send_peer(_peer, _packet) #logger.debug('(%s) Packet sent to peer %s', self._system, self._peers[_peer]['RADIO_ID']) @@ -610,9 +751,9 @@ class HBSYSTEM(DatagramProtocol): # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! #logger.debug('(%s) TX Packet to %s on port %s: %s', self._peers[_peer]['RADIO_ID'], self._peers[_peer]['IP'], self._peers[_peer]['PORT'], ahex(_packet)) - def send_master(self, _packet, _hops = b''): + def send_master(self, _packet, _hops = b'', _ber = b'\x00', _rssi = b'\x00',_source_server = b'\x00\x00\x00\x00'): if _packet[:4] == DMRD: - _packet = b''.join([_packet[:11], self._config['RADIO_ID'], _packet[15:]]) + _packet = b''.join([_packet[:11], self._config['RADIO_ID'], _packet[15:],_ber,_rssi]) self.transport.write(_packet, self._config['MASTER_SOCKADDR']) # KEEP THE FOLLOWING COMMENTED OUT UNLESS YOU'RE DEBUGGING DEEPLY!!!! #logger.debug('(%s) TX Packet to %s:%s -- %s', self._system, self._config['MASTER_IP'], self._config['MASTER_PORT'], ahex(_packet))