diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cdcb2ae..ac941da 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -54,8 +54,7 @@ build-testing: # This job runs in the build stage, which runs first. script: - echo "Compiling the code..." - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - - docker buildx build --no-cache -f docker-configs/Dockerfile-ci -t gitlab.hacknix.net:5050/hacknix/freedmr:testing --platform linux/amd64 --push . - - docker logut + - docker buildx build --no-cache -f docker-configs/Dockerfile-ci -t $CI_REGISTRY/hacknix/freedmr:testing --platform linux/amd64 --push . only: - testing diff --git a/docker-configs/Dockerfile-ci b/docker-configs/Dockerfile-ci index a7389f3..9796126 100644 --- a/docker-configs/Dockerfile-ci +++ b/docker-configs/Dockerfile-ci @@ -29,7 +29,9 @@ RUN adduser -D -u 54000 radio && \ ls -lah && \ pip install --no-cache-dir -r requirements.txt && \ apk del git gcc musl-dev && \ - chown -R radio: /opt/freedmr + chown -R radio: /opt/freedmr && \ + mkdir /run/priv_control/ && \ + chown -R radio: /run/priv_control COPY docker-configs/entrypoint-proxy /entrypoint USER radio diff --git a/hotspot_proxy_v2.py b/hotspot_proxy_v2.py index bad2ba2..1e6a494 100644 --- a/hotspot_proxy_v2.py +++ b/hotspot_proxy_v2.py @@ -25,10 +25,11 @@ import ipaddress import os from setproctitle import setproctitle from datetime import datetime +import Pyro5.api # Does anybody read this stuff? There's a PEP somewhere that says I should do this. __author__ = 'Simon Adlem - G7RZU' -__copyright__ = 'Copyright (c) Simon Adlem, G7RZU 2020,2021,2022' +__copyright__ = 'Copyright (c) Simon Adlem, G7RZU 2020,2021,2022,2023' __credits__ = 'Jon Lee, G4TSN; Norman Williams, M6NBP; Christian, OA4DOA' __license__ = 'GNU GPLv3' __maintainer__ = 'Simon Adlem G7RZU' @@ -49,10 +50,40 @@ def IsIPv6Address(ip): except ValueError as errorCode: pass +class privHelper(): + def __init__(self): + self._netfilterURI = 'PYRO:netfilterControl@./u:/run/priv_control/priv_control.unixsocket' + self._conntrackURI = 'PYRO:conntrackControl@./u:/run/priv_control/priv_control.unixsocket' + + def addBL(self,dport,ip): + try: + with Pyro5.api.Proxy(self._netfilterURI) as nf: + nf.blocklistAdd(dport,ip) + except Exception as e: + print('(PrivError) {}'.format(e)) + + def delBL(self,dport,ip): + try: + with Pyro5.api.Proxy(self._netfilterURI) as nf: + nf.blocklistDel(dport,ip) + except Exception as e: + print('(PrivError) {}'.format(e)) + + def flushCT(self): + try: + with Pyro5.api.Proxy(self._conntrackURI) as ct: + ct.flushUDPTarget(62031) + except Exception as e: + print('(PrivError) {}'.format(e)) + + + + class Proxy(DatagramProtocol): - def __init__(self,Master,ListenPort,connTrack,peerTrack,blackList,IPBlackList,Timeout,Debug,ClientInfo,DestportStart,DestPortEnd): + def __init__(self,Master,ListenPort,connTrack,peerTrack,blackList,IPBlackList,Timeout,Debug,ClientInfo,DestportStart,DestPortEnd,privHelper): self.master = Master + self.ListenPort = ListenPort self.connTrack = connTrack self.peerTrack = peerTrack self.timeout = Timeout @@ -63,6 +94,8 @@ class Proxy(DatagramProtocol): self.destPortStart = DestportStart self.destPortEnd = DestPortEnd self.numPorts = DestPortEnd - DestportStart + self.privHelper = privHelper + def reaper(self,_peer_id): @@ -131,6 +164,9 @@ class Proxy(DatagramProtocol): return if self.clientinfo: print('Add to blacklist: host {}. Expire time {}'.format(self.peerTrack[_peer_id]['shost'],_bltime)) + if self.privHelper: + print('Ask priv_helper to add to iptables: host {}, port {}.'.format(self.peerTrack[_peer_id]['shost'],self.ListenPort)) + reactor.callInThread(self.privHelper.addBL,self.ListenPort,self.peerTrack[_peer_id]['shost']) return if _command == DMRD: @@ -226,6 +262,10 @@ if __name__ == '__main__': import argparse import sys import json + import stat + import functools + + print = functools.partial(print, flush=True) #Set process title early setproctitle(__file__) @@ -283,12 +323,12 @@ if __name__ == '__main__': BlackList = [1234567] #e.g. {10.0.0.1: 0, 10.0.0.2: 0} IPBlackList = {} - UsePrivilegedHelper = False #******************* CONNTRACK = {} PEERTRACK = {} + PRIV_HELPER = None # Set up the signal handler def sig_handler(_signal, _frame): @@ -314,12 +354,15 @@ if __name__ == '__main__': ClientInfo = bool(os.environ['FDPROXY_CLIENTINFO']) if 'FDPROXY_LISTENPORT' in os.environ: ListenPort = int(os.environ['FDPROXY_LISTENPORT']) - if 'USE_PRIV_HELPER' in os.environ: - UsePrivilegedHelper = os.environ['USE_PRIV_HELPER'] - if UsePrivilegedHelper: + unixSocket = '/run/priv_control/priv_control.unixsocket' + + if os.path.exists(unixSocket) and stat.S_ISSOCK(os.stat(unixSocket).st_mode): + print('(PRIV) Found UNIX socket. Enabling priv helper') + PRIV_HELPER = privHelper() + print('(PRIV) flush conntrack') + PRIV_HELPER.flushCT() - for port in range(DestportStart,DestPortEnd+1,1): CONNTRACK[port] = False @@ -328,7 +371,7 @@ if __name__ == '__main__': if ListenIP == '::' and IsIPv4Address(Master): Master = '::ffff:' + Master - reactor.listenUDP(ListenPort,Proxy(Master,ListenPort,CONNTRACK,PEERTRACK,BlackList,IPBlackList,Timeout,Debug,ClientInfo,DestportStart,DestPortEnd),interface=ListenIP) + reactor.listenUDP(ListenPort,Proxy(Master,ListenPort,CONNTRACK,PEERTRACK,BlackList,IPBlackList,Timeout,Debug,ClientInfo,DestportStart,DestPortEnd,PRIV_HELPER),interface=ListenIP) def loopingErrHandle(failure): print('(GLOBAL) STOPPING REACTOR TO AVOID MEMORY LEAK: Unhandled error innowtimed loop.\n {}'.format(failure)) @@ -358,6 +401,9 @@ if __name__ == '__main__': IPBlackList.pop(delete) if ClientInfo: print('Remove dynamic blacklist entry for {}'.format(delete)) + if PRIV_HELPER: + print('Ask priv helper to remove blacklist entry for {} from iptables'.format(delete)) + reactor.callInThread(PRIV_HELPER.delBL,ListenPort,delete) if Stats == True: diff --git a/requirements.txt b/requirements.txt index 98a1d9e..69123e4 100755 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ dmr_utils3>=0.1.19 configparser>=3.0.0 resettabletimer>=0.7.0 setproctitle +Pyro5