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:
Cort Buffington 2018-09-25 20:17:55 -05:00
parent 24d1e9f198
commit 5511a3b25a
4 changed files with 105 additions and 4 deletions

View File

@ -151,6 +151,19 @@ def build_config(_config_file):
'GROUP_HANGTIME': config.getint(section, 'GROUP_HANGTIME')
}})
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:
print "Cannot parse configuration file. %s" %err

View File

@ -1,7 +1,7 @@
#!/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
# it under the terms of the GNU General Public License as published by

View File

@ -75,6 +75,28 @@ STALE_DAYS: 7
EXPORT_IP: 127.0.0.1
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
# HomeBrew Protocol Master instances go here.
# IP may be left blank if there's one interface on your system.

View File

@ -33,7 +33,8 @@ from __future__ import print_function
from binascii import b2a_hex as ahex
from binascii import a2b_hex as bhex
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 bitstring import BitArray
from importlib import import_module
@ -181,6 +182,68 @@ class AMBE:
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
#************************************************
@ -649,10 +712,13 @@ if __name__ == '__main__':
report_server = config_reports(CONFIG, logger, reportFactory)
# 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']:
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'])
logger.debug('%s instance created: %s, %s', CONFIG['SYSTEMS'][system]['MODE'], system, systems[system])