HDStack docker

This commit is contained in:
Simon 2021-03-07 12:23:30 +00:00
parent 40963656f1
commit e41eb7bfc5
7 changed files with 467 additions and 2 deletions

View File

@ -0,0 +1,17 @@
FROM python:3.7-alpine
COPY entrypoint-proxy /entrypoint
RUN adduser -D -u 54000 radio && \
apk update && \
apk add git gcc musl-dev && \
cd /opt && \
git clone https://github.com/hacknix/freedmr && \
cd /opt/freedmr && \
pip install --no-cache-dir -r requirements.txt && \
apk del git gcc musl-dev && \
chown -R radio: /opt/freedmr
USER radio
ENTRYPOINT [ "/entrypoint" ]

View File

@ -0,0 +1,7 @@
#!/bin/sh
cd /opt/freedmr
python /opt/freedmr/hdstack/hotspot_proxy_v2.py &
python /opt/freedmr/bridge_master.py -c freedmr.cfg -r rules.py &
python /opt/freedmr/bridge_master.py -c hdstack/stack1.cfg -r rules.py &
python /opt/freedmr/bridge_master.py -c hdstack/stack2.cfg -r rules.py &

86
hdstack/freebridge.cfg Normal file
View File

@ -0,0 +1,86 @@
[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
GEN_STAT_BRIDGES: False
ALLOW_NULL_PASSPHRASE: True
ANNOUNCEMENT_LANGUAGE: en_GB
[REPORTS]
REPORT: True
REPORT_INTERVAL: 60
REPORT_PORT: 4321
REPORT_CLIENTS: *
[LOGGER]
LOG_FILE: freedmr.log
LOG_HANDLERS: file-timed
LOG_LEVEL: INFO
LOG_NAME: FreeDMR
[ALIASES]
TRY_DOWNLOAD: False
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
[MYSQL]
USE_MYSQL: False
USER: hblink
PASS: mypassword
DB: hblink
SERVER: 127.0.0.1
PORT: 3306
TABLE: repeaters
[OBP-HDSTACK1]
MODE: OPENBRIDGE
ENABLED: True
IP: 127.0.0.1
PORT: 70001
NETWORK_ID: 3
PASSPHRASE: internal
TARGET_IP: 127.0.0.1
TARGET_PORT: 70001
USE_ACL: True
SUB_ACL: DENY:1
TGID_ACL: PERMIT:ALL
RELAX_CHECKS: True
[OBP-HDSTACK2]
MODE: OPENBRIDGE
ENABLED: True
IP: 127.0.0.1
PORT: 70002
NETWORK_ID: 4
PASSPHRASE: internal
TARGET_IP: 127.0.0.1
TARGET_PORT: 70002
USE_ACL: True
SUB_ACL: DENY:1
TGID_ACL: PERMIT:ALL
RELAX_CHECKS: True
[OBP-FREEDMR]
MODE: OPENBRIDGE
ENABLED: False
IP:
PORT:
NETWORK_ID:
PASSPHRASE:
TARGET_IP:
TARGET_PORT:
USE_ACL: True
SUB_ACL: DENY:1
TGID_ACL: PERMIT:ALL
RELAX_CHECKS: True

80
hdstack/hdstack1.cfg Normal file
View File

@ -0,0 +1,80 @@
[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
GEN_STAT_BRIDGES: False
ALLOW_NULL_PASSPHRASE: True
ANNOUNCEMENT_LANGUAGE: en_GB
[REPORTS]
REPORT: True
REPORT_INTERVAL: 60
REPORT_PORT: 4322
REPORT_CLIENTS: *
[LOGGER]
LOG_FILE: hdstack1.log
LOG_HANDLERS: file-timed
LOG_LEVEL: INFO
LOG_NAME: FreeDMR-hdstack1
[ALIASES]
TRY_DOWNLOAD: False
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
[MYSQL]
USE_MYSQL: False
USER: hblink
PASS: mypassword
DB: hblink
SERVER: 127.0.0.1
PORT: 3306
TABLE: repeaters
[OBP-MAIN]
MODE: OPENBRIDGE
ENABLED: True
IP: 127.0.0.1
PORT: 70001
NETWORK_ID: 1
PASSPHRASE: internal
TARGET_IP: 127.0.0.1
TARGET_PORT: 70001
USE_ACL: True
SUB_ACL: DENY:1
TGID_ACL: PERMIT:ALL
RELAX_CHECKS: True
[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: 999
SINGLE_MODE: True
VOICE_IDENT: True
TS1_STATIC:
TS2_STATIC:
DEFAULT_REFLECTOR: 0
GENERATOR: 150

80
hdstack/hdstack2.cfg Normal file
View File

@ -0,0 +1,80 @@
[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
GEN_STAT_BRIDGES: False
ALLOW_NULL_PASSPHRASE: True
ANNOUNCEMENT_LANGUAGE: en_GB
[REPORTS]
REPORT: True
REPORT_INTERVAL: 60
REPORT_PORT: 4323
REPORT_CLIENTS: *
[LOGGER]
LOG_FILE: hdstack2.log
LOG_HANDLERS: file-timed
LOG_LEVEL: INFO
LOG_NAME: FreeDMR-hdstack2
[ALIASES]
TRY_DOWNLOAD: False
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
[MYSQL]
USE_MYSQL: False
USER: hblink
PASS: mypassword
DB: hblink
SERVER: 127.0.0.1
PORT: 3306
TABLE: repeaters
[OBP-MAIN]
MODE: OPENBRIDGE
ENABLED: True
IP: 127.0.0.1
PORT: 70002
NETWORK_ID: 2
PASSPHRASE: internal
TARGET_IP: 127.0.0.1
TARGET_PORT: 70002
USE_ACL: True
SUB_ACL: DENY:1
TGID_ACL: PERMIT:ALL
RELAX_CHECKS: True
[SYSTEM]
MODE: MASTER
ENABLED: True
REPEAT: True
MAX_PEERS: 1
EXPORT_AMBE: False
IP: 127.0.0.1
PORT: 54150
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: 999
SINGLE_MODE: True
VOICE_IDENT: True
TS1_STATIC:
TS2_STATIC:
DEFAULT_REFLECTOR: 0
GENERATOR: 150

195
hdstack/hotspot_proxy_v2.py Normal file
View File

@ -0,0 +1,195 @@
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor, task
from time import time
from resettabletimer import ResettableTimer
from dmr_utils3.utils import int_id
import random
class Proxy(DatagramProtocol):
def __init__(self,Master,ListenPort,connTrack,blackList,Timeout,Debug,DestportStart,DestPortEnd):
self.master = Master
self.connTrack = connTrack
self.peerTrack = {}
self.timeout = Timeout
self.debug = Debug
self.blackList = blackList
self.destPortStart = DestportStart
self.destPortEnd = DestPortEnd
self.numPorts = DestPortEnd - DestportStart
def reaper(self,_peer_id):
if self.debug:
print("dead",_peer_id)
self.transport.write(b'RPTCL'+_peer_id, ('127.0.0.1',self.peerTrack[_peer_id]['dport']))
self.connTrack[self.peerTrack[_peer_id]['dport']] = False
del self.peerTrack[_peer_id]
def datagramReceived(self, data, addr):
# HomeBrew Protocol Commands
DMRD = b'DMRD'
DMRA = b'DMRA'
MSTCL = b'MSTCL'
MSTNAK = b'MSTNAK'
MSTPONG = b'MSTPONG'
MSTN = b'MSTN'
MSTP = b'MSTP'
MSTC = b'MSTC'
RPTL = b'RPTL'
RPTPING = b'RPTPING'
RPTCL = b'RPTCL'
RPTL = b'RPTL'
RPTACK = b'RPTACK'
RPTK = b'RPTK'
RPTC = b'RPTC'
RPTP = b'RPTP'
RPTA = b'RPTA'
RPTO = b'RPTO'
host,port = addr
nowtime = time()
Debug = self.debug
#If the packet comes from the master
if host == self.master:
_command = data[:4]
if _command == DMRD:
_peer_id = data[11:15]
elif _command == RPTA:
if data[6:10] in self.peerTrack:
_peer_id = data[6:10]
else:
_peer_id = self.connTrack[port]
elif _command == MSTN:
_peer_id = data[6:10]
self.peerTrack[_peer_id]['timer'].cancel()
self.reaper(_peer_id)
return
elif _command == MSTP:
_peer_id = data[7:11]
elif _command == MSTC:
_peer_id = data[5:9]
self.peerTrack[_peer_id]['timer'].cancel()
self.reaper(_peer_id)
return
# _peer_id = self.connTrack[port]
if self.debug:
print(data)
if _peer_id and _peer_id in self.peerTrack:
self.transport.write(data,(self.peerTrack[_peer_id]['shost'],self.peerTrack[_peer_id]['sport']))
#self.peerTrack[_peer_id]['timer'].reset()
return
else:
_command = data[:4]
if _command == DMRD: # DMRData -- encapsulated DMR data frame
_peer_id = data[11:15]
elif _command == DMRA: # DMRAlias -- Talker Alias information
_peer_id = _data[4:8]
elif _command == RPTL: # RPTLogin -- a repeater wants to login
_peer_id = data[4:8]
elif _command == RPTK: # Repeater has answered our login challenge
_peer_id = data[4:8]
elif _command == RPTC: # Repeater is sending it's configuraiton OR disconnecting
if data[:5] == RPTCL: # Disconnect command
_peer_id = data[5:9]
else:
_peer_id = data[4:8] # Configure Command
elif _command == RPTO: # options
_peer_id = data[4:8]
elif _command == RPTP: # RPTPing -- peer is pinging us
_peer_id = data[7:11]
else:
return
if _peer_id in self.peerTrack:
_dport = self.peerTrack[_peer_id]['dport']
self.peerTrack[_peer_id]['sport'] = port
self.peerTrack[_peer_id]['shost'] = host
self.transport.write(data, ('127.0.0.1',_dport))
self.peerTrack[_peer_id]['timer'].reset()
if self.debug:
print(data)
return
else:
if int_id(_peer_id) in self.blackList:
return
#for _dport in self.connTrack:
while True:
_dport = random.randint(1,(self.numPorts - 1))
_dport = _dport + self.destPortStart
if not self.connTrack[_dport]:
break
self.connTrack[_dport] = _peer_id
self.peerTrack[_peer_id] = {}
self.peerTrack[_peer_id]['dport'] = _dport
self.peerTrack[_peer_id]['sport'] = port
self.peerTrack[_peer_id]['shost'] = host
self.peerTrack[_peer_id]['timer'] = ResettableTimer(self.timeout,self.reaper,[_peer_id])
self.peerTrack[_peer_id]['timer'].start()
self.transport.write(data, (self.master,_dport))
if self.debug:
print(data)
return
if __name__ == '__main__':
#*** CONFIG HERE ***
Master = "127.0.0.1"
ListenPort = 62031
DestportStart = 54000
DestPortEnd = 54300
Timeout = 30
Stats = False
Debug = False
BlackList = [1234567]
#*******************
CONNTRACK = {}
for port in range(DestportStart,DestPortEnd+1,1):
CONNTRACK[port] = False
reactor.listenUDP(ListenPort,Proxy(Master,ListenPort,CONNTRACK,BlackList,Timeout,Debug,DestportStart,DestPortEnd))
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 CONNTRACK[port]:
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()

View File

@ -153,8 +153,8 @@ if __name__ == '__main__':
DestportStart = 54000
DestPortEnd = 54100
Timeout = 30
Stats = True
Debug = True
Stats = False
Debug = False
BlackList = [1234567]
#*******************