OpenBridge initial commit
The beginning of OpenBridge support. It does not yet do anything, so downloading this is worthless for all but selected alpha testers.
This commit is contained in:
parent
24d1e9f198
commit
5511a3b25a
13
hb_config.py
13
hb_config.py
@ -152,6 +152,19 @@ def build_config(_config_file):
|
|||||||
}})
|
}})
|
||||||
CONFIG['SYSTEMS'][section].update({'PEERS': {}})
|
CONFIG['SYSTEMS'][section].update({'PEERS': {}})
|
||||||
|
|
||||||
|
elif config.get(section, 'MODE') == 'OPENBRIDGE':
|
||||||
|
CONFIG['SYSTEMS'].update({section: {
|
||||||
|
'MODE': config.get(section, 'MODE'),
|
||||||
|
'ENABLED': config.getboolean(section, 'ENABLED'),
|
||||||
|
'NETWORK_ID': config.getint(section, 'NETWORK_ID'),
|
||||||
|
'IP': gethostbyname(config.get(section, 'IP')),
|
||||||
|
'PORT': config.getint(section, 'PORT'),
|
||||||
|
'PASSPHRASE': config.get(section, 'PASSPHRASE').ljust(20,'\x00')[:20],
|
||||||
|
'TARGET_IP': gethostbyname(config.get(section, 'TARGET_IP')),
|
||||||
|
'TARGET_PORT': config.getint(section, 'TARGET_PORT'),
|
||||||
|
}})
|
||||||
|
|
||||||
|
|
||||||
except ConfigParser.Error, err:
|
except ConfigParser.Error, err:
|
||||||
print "Cannot parse configuration file. %s" %err
|
print "Cannot parse configuration file. %s" %err
|
||||||
sys.exit('Could not parse configuration file, exiting...')
|
sys.exit('Could not parse configuration file, exiting...')
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
#
|
#
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Copyright (C) 2016 Cortney T. Buffington, N0MJS <n0mjs@me.com>
|
# Copyright (C) 2016-2018 Cortney T. Buffington, N0MJS <n0mjs@me.com>
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -75,6 +75,28 @@ STALE_DAYS: 7
|
|||||||
EXPORT_IP: 127.0.0.1
|
EXPORT_IP: 127.0.0.1
|
||||||
EXPORT_PORT: 1234
|
EXPORT_PORT: 1234
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
[3102]
|
||||||
|
MODE: OPENBRIDGE
|
||||||
|
ENABLED: True
|
||||||
|
IP:
|
||||||
|
PORT: 62035
|
||||||
|
NETWORK_ID: 3120101
|
||||||
|
PASSPHRASE: c0edbabe
|
||||||
|
TARGET_IP: 74.91.114.19
|
||||||
|
TARGET_PORT: 62035
|
||||||
|
|
||||||
# MASTER INSTANCES - DUPLICATE SECTION FOR MULTIPLE MASTERS
|
# MASTER INSTANCES - DUPLICATE SECTION FOR MULTIPLE MASTERS
|
||||||
# HomeBrew Protocol Master instances go here.
|
# HomeBrew Protocol Master instances go here.
|
||||||
# IP may be left blank if there's one interface on your system.
|
# IP may be left blank if there's one interface on your system.
|
||||||
|
72
hblink.py
72
hblink.py
@ -33,7 +33,8 @@ from __future__ import print_function
|
|||||||
from binascii import b2a_hex as ahex
|
from binascii import b2a_hex as ahex
|
||||||
from binascii import a2b_hex as bhex
|
from binascii import a2b_hex as bhex
|
||||||
from random import randint
|
from random import randint
|
||||||
from hashlib import sha256
|
from hashlib import sha256, sha1
|
||||||
|
from hmac import new as hmac_new, compare_digest
|
||||||
from time import time
|
from time import time
|
||||||
from bitstring import BitArray
|
from bitstring import BitArray
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
@ -181,6 +182,68 @@ class AMBE:
|
|||||||
self._sock.sendto(ambeBytes[18:27], (self._exp_ip, self._exp_port))
|
self._sock.sendto(ambeBytes[18:27], (self._exp_ip, self._exp_port))
|
||||||
|
|
||||||
|
|
||||||
|
#************************************************
|
||||||
|
# OPENBRIDGE CLASS
|
||||||
|
#************************************************
|
||||||
|
|
||||||
|
class OPENBRIDGE(DatagramProtocol):
|
||||||
|
def __init__(self, _name, _config, _logger, _report):
|
||||||
|
# Define a few shortcuts to make the rest of the class more readable
|
||||||
|
self._CONFIG = _config
|
||||||
|
self._system = _name
|
||||||
|
self._logger = _logger
|
||||||
|
self._report = _report
|
||||||
|
self._config = self._CONFIG['SYSTEMS'][self._system]
|
||||||
|
self._localsock = (self._config['IP'], self._config['PORT'])
|
||||||
|
self._targetsock = (self._config['TARGET_IP'], self._config['TARGET_PORT'])
|
||||||
|
print(self._config['NETWORK_ID'])
|
||||||
|
|
||||||
|
def dereg(self):
|
||||||
|
self._logger.info('(%s) is mode OPENBRIDGE. No De-Registration required, continuing shutdown', self._system)
|
||||||
|
|
||||||
|
def send_system(self, _packet):
|
||||||
|
if _packet[:4] == 'DMRD':
|
||||||
|
self.transport.write(_packet, (self._config['TARGET_IP'], self._config['TARGET_PORT']))
|
||||||
|
|
||||||
|
def dmrd_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data):
|
||||||
|
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))
|
||||||
|
|
||||||
|
_dmrd = _data[:53]
|
||||||
|
_hash = _data[53:]
|
||||||
|
|
||||||
|
_ckhs = hmac_new(self._config['PASSPHRASE'],_dmrd,sha1).digest()
|
||||||
|
if compare_digest(_hash, _ckhs):
|
||||||
|
print('PEER:', int_id(_peer_id), 'RF SOURCE:', int_id(_rf_src), 'DESTINATION:', int_id(_dst_id), 'SLOT', _slot, 'SEQ:', int_id(_seq), 'STREAM:', int_id(_stream_id))
|
||||||
|
else:
|
||||||
|
self._logger.info('(%s) OpenBridge HMAC failed, packet discarded', self._system)
|
||||||
|
|
||||||
|
# Aliased in __init__ to datagramReceived if system is a master
|
||||||
|
def datagramReceived(self, _data, _sockaddr):
|
||||||
|
# Keep This Line Commented Unless HEAVILY Debugging!
|
||||||
|
# self._logger.debug('(%s) RX packet from %s -- %s', self._system, _sockaddr, ahex(_data))
|
||||||
|
|
||||||
|
# Extract the command, which is various length, all but one 4 significant characters -- RPTCL
|
||||||
|
_command = _data[:4]
|
||||||
|
|
||||||
|
if _command == 'DMRD': # DMRData -- encapsulated DMR data frame
|
||||||
|
_peer_id = _data[11:15]
|
||||||
|
if _sockaddr == self._targetsock:
|
||||||
|
_seq = _data[4]
|
||||||
|
_rf_src = _data[5:8]
|
||||||
|
_dst_id = _data[8:11]
|
||||||
|
_bits = int_id(_data[15])
|
||||||
|
_slot = 2 if (_bits & 0x80) else 1
|
||||||
|
_call_type = 'unit' if (_bits & 0x40) else '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]
|
||||||
|
#self._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))
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
|
||||||
#************************************************
|
#************************************************
|
||||||
# HB MASTER CLASS
|
# HB MASTER CLASS
|
||||||
#************************************************
|
#************************************************
|
||||||
@ -649,10 +712,13 @@ if __name__ == '__main__':
|
|||||||
report_server = config_reports(CONFIG, logger, reportFactory)
|
report_server = config_reports(CONFIG, logger, reportFactory)
|
||||||
|
|
||||||
# HBlink instance creation
|
# HBlink instance creation
|
||||||
logger.info('HBlink \'HBlink.py\' (c) 2016 N0MJS & the K0USY Group - SYSTEM STARTING...')
|
logger.info('HBlink \'HBlink.py\' (c) 2016-2018 N0MJS & the K0USY Group - SYSTEM STARTING...')
|
||||||
for system in CONFIG['SYSTEMS']:
|
for system in CONFIG['SYSTEMS']:
|
||||||
if CONFIG['SYSTEMS'][system]['ENABLED']:
|
if CONFIG['SYSTEMS'][system]['ENABLED']:
|
||||||
systems[system] = HBSYSTEM(system, CONFIG, logger, report_server)
|
if CONFIG['SYSTEMS'][system]['MODE'] == 'OPENBRIDGE':
|
||||||
|
systems[system] = OPENBRIDGE(system, CONFIG, logger, report_server)
|
||||||
|
else:
|
||||||
|
systems[system] = HBSYSTEM(system, CONFIG, logger, report_server)
|
||||||
reactor.listenUDP(CONFIG['SYSTEMS'][system]['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['IP'])
|
reactor.listenUDP(CONFIG['SYSTEMS'][system]['PORT'], systems[system], interface=CONFIG['SYSTEMS'][system]['IP'])
|
||||||
logger.debug('%s instance created: %s, %s', CONFIG['SYSTEMS'][system]['MODE'], system, systems[system])
|
logger.debug('%s instance created: %s, %s', CONFIG['SYSTEMS'][system]['MODE'], system, systems[system])
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user