working SMS generation, not correct though
This commit is contained in:
		
							parent
							
								
									73c5ec938f
								
							
						
					
					
						commit
						9690cdf98c
					
				
							
								
								
									
										363
									
								
								data_gateway-SAMPLE.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								data_gateway-SAMPLE.cfg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,363 @@
 | 
				
			|||||||
 | 
					# PROGRAM-WIDE PARAMETERS GO HERE
 | 
				
			||||||
 | 
					# PATH - working path for files, leave it alone unless you NEED to change it
 | 
				
			||||||
 | 
					# PING_TIME - the interval that peers will ping the master, and re-try registraion
 | 
				
			||||||
 | 
					#           - how often the Master maintenance loop runs
 | 
				
			||||||
 | 
					# MAX_MISSED - how many pings are missed before we give up and re-register
 | 
				
			||||||
 | 
					#           - number of times the master maintenance loop runs before de-registering a peer
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# ACLs:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Access Control Lists are a very powerful tool for administering your system.
 | 
				
			||||||
 | 
					# But they consume packet processing time. Disable them if you are not using them.
 | 
				
			||||||
 | 
					# But be aware that, as of now, the configuration stanzas still need the ACL
 | 
				
			||||||
 | 
					# sections configured even if you're not using them.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# REGISTRATION ACLS ARE ALWAYS USED, ONLY SUBSCRIBER AND TGID MAY BE DISABLED!!!
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The 'action' May be PERMIT|DENY
 | 
				
			||||||
 | 
					# Each entry may be a single radio id, or a hypenated range (e.g. 1-2999)
 | 
				
			||||||
 | 
					# Format:
 | 
				
			||||||
 | 
					# 	ACL = 'action:id|start-end|,id|start-end,....'
 | 
				
			||||||
 | 
					#		--for example--
 | 
				
			||||||
 | 
					#	SUB_ACL: DENY:1,1000-2000,4500-60000,17
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# ACL Types:
 | 
				
			||||||
 | 
					# 	REG_ACL: peer radio IDs for registration (only used on HBP master systems)
 | 
				
			||||||
 | 
					# 	SUB_ACL: subscriber IDs for end-users
 | 
				
			||||||
 | 
					# 	TGID_TS1_ACL: destination talkgroup IDs on Timeslot 1
 | 
				
			||||||
 | 
					# 	TGID_TS2_ACL: destination talkgroup IDs on Timeslot 2
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# ACLs may be repeated for individual systems if needed for granularity
 | 
				
			||||||
 | 
					# Global ACLs will be processed BEFORE the system level ACLs
 | 
				
			||||||
 | 
					# Packets will be matched against all ACLs, GLOBAL first. If a packet 'passes'
 | 
				
			||||||
 | 
					# All elements, processing continues. Packets are discarded at the first
 | 
				
			||||||
 | 
					# negative match, or 'reject' from an ACL element.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# If you do not wish to use ACLs, set them to 'PERMIT:ALL'
 | 
				
			||||||
 | 
					# TGID_TS1_ACL in the global stanza is used for OPENBRIDGE systems, since all
 | 
				
			||||||
 | 
					# traffic is passed as TS 1 between OpenBridges
 | 
				
			||||||
 | 
					[GLOBAL]
 | 
				
			||||||
 | 
					PATH: ./
 | 
				
			||||||
 | 
					PING_TIME: 5
 | 
				
			||||||
 | 
					MAX_MISSED: 3
 | 
				
			||||||
 | 
					USE_ACL: True
 | 
				
			||||||
 | 
					REG_ACL: PERMIT:ALL
 | 
				
			||||||
 | 
					SUB_ACL: DENY:1
 | 
				
			||||||
 | 
					TGID_TS1_ACL: PERMIT:ALL
 | 
				
			||||||
 | 
					TGID_TS2_ACL: PERMIT:ALL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# NOT YET WORKING: NETWORK REPORTING CONFIGURATION
 | 
				
			||||||
 | 
					#   Enabling "REPORT" will configure a socket-based reporting
 | 
				
			||||||
 | 
					#   system that will send the configuration and other items
 | 
				
			||||||
 | 
					#   to a another process (local or remote) that may process
 | 
				
			||||||
 | 
					#   the information for some useful purpose, like a web dashboard.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   REPORT - True to enable, False to disable
 | 
				
			||||||
 | 
					#   REPORT_INTERVAL - Seconds between reports
 | 
				
			||||||
 | 
					#   REPORT_PORT - TCP port to listen on if "REPORT_NETWORKS" = NETWORK
 | 
				
			||||||
 | 
					#   REPORT_CLIENTS - comma separated list of IPs you will allow clients
 | 
				
			||||||
 | 
					#       to connect on. Entering a * will allow all.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# ****FOR NOW MUST BE TRUE - USE THE LOOPBACK IF YOU DON'T USE THIS!!!****
 | 
				
			||||||
 | 
					[REPORTS]
 | 
				
			||||||
 | 
					REPORT: True
 | 
				
			||||||
 | 
					REPORT_INTERVAL: 60
 | 
				
			||||||
 | 
					REPORT_PORT: 4329
 | 
				
			||||||
 | 
					REPORT_CLIENTS: 127.0.0.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SYSTEM LOGGER CONFIGURAITON
 | 
				
			||||||
 | 
					#   This allows the logger to be configured without chaning the individual
 | 
				
			||||||
 | 
					#   python logger stuff. LOG_FILE should be a complete path/filename for *your*
 | 
				
			||||||
 | 
					#   system -- use /dev/null for non-file handlers.
 | 
				
			||||||
 | 
					#   LOG_HANDLERS may be any of the following, please, no spaces in the
 | 
				
			||||||
 | 
					#   list if you use several:
 | 
				
			||||||
 | 
					#       null
 | 
				
			||||||
 | 
					#       console
 | 
				
			||||||
 | 
					#       console-timed
 | 
				
			||||||
 | 
					#       file
 | 
				
			||||||
 | 
					#       file-timed
 | 
				
			||||||
 | 
					#       syslog
 | 
				
			||||||
 | 
					#   LOG_LEVEL may be any of the standard syslog logging levels, though
 | 
				
			||||||
 | 
					#   as of now, DEBUG, INFO, WARNING and CRITICAL are the only ones
 | 
				
			||||||
 | 
					#   used.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					[LOGGER]
 | 
				
			||||||
 | 
					LOG_FILE: /tmp/hblink.log
 | 
				
			||||||
 | 
					LOG_HANDLERS: console-timed
 | 
				
			||||||
 | 
					LOG_LEVEL: DEBUG
 | 
				
			||||||
 | 
					LOG_NAME: HBlink
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# DOWNLOAD AND IMPORT SUBSCRIBER, PEER and TGID ALIASES
 | 
				
			||||||
 | 
					# Ok, not the TGID, there's no master list I know of to download
 | 
				
			||||||
 | 
					# This is intended as a facility for other applcations built on top of
 | 
				
			||||||
 | 
					# HBlink to use, and will NOT be used in HBlink directly.
 | 
				
			||||||
 | 
					# STALE_DAYS is the number of days since the last download before we
 | 
				
			||||||
 | 
					# download again. Don't be an ass and change this to less than a few days.
 | 
				
			||||||
 | 
					[ALIASES]
 | 
				
			||||||
 | 
					TRY_DOWNLOAD: True
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# USER MANAGER
 | 
				
			||||||
 | 
					# This is where to configure the details for use with a user managment script
 | 
				
			||||||
 | 
					[WEB_SERVICE]
 | 
				
			||||||
 | 
					THIS_SERVER_NAME: DATA_GATEWAY
 | 
				
			||||||
 | 
					REMOTE_CONFIG_ENABLED: False
 | 
				
			||||||
 | 
					# URL of the user managment server
 | 
				
			||||||
 | 
					URL: http://localhost:8080/svr
 | 
				
			||||||
 | 
					# Integer appended to DMR ID during the generation of a passphrase
 | 
				
			||||||
 | 
					APPEND_INT: 1
 | 
				
			||||||
 | 
					EXTRA_INT_1: 5
 | 
				
			||||||
 | 
					EXTRA_INT_2: 8
 | 
				
			||||||
 | 
					EXTRA_1: TeSt
 | 
				
			||||||
 | 
					EXTRA_2: DmR4
 | 
				
			||||||
 | 
					# Secret used to authenticate with user managment server, before checking if user login is approved
 | 
				
			||||||
 | 
					SHARED_SECRET: test
 | 
				
			||||||
 | 
					# Shorten passphrases
 | 
				
			||||||
 | 
					SHORTEN_PASSPHRASE: True
 | 
				
			||||||
 | 
					SHORTEN_SAMPLE: 4
 | 
				
			||||||
 | 
					SHORTEN_LENGTH: 4
 | 
				
			||||||
 | 
					BURN_FILE: ./burn_ids.txt
 | 
				
			||||||
 | 
					BURN_INT: 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[DATA_CONFIG]
 | 
				
			||||||
 | 
					DATA_DMR_ID: 9099
 | 
				
			||||||
 | 
					CALL_TYPE: both
 | 
				
			||||||
 | 
					UNIT_SMS_TS: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USER_APRS_SSID: 5
 | 
				
			||||||
 | 
					USER_APRS_COMMENT: HBNet APRS Gateway
 | 
				
			||||||
 | 
					APRS_SERVER: hbl.ink
 | 
				
			||||||
 | 
					APRS_PORT: 14580
 | 
				
			||||||
 | 
					APRS_LOGIN_CALL: N0CALL
 | 
				
			||||||
 | 
					APRS_LOGIN_PASSCODE: 12345
 | 
				
			||||||
 | 
					APRS_FILTER: r/47/-120/500 t/m
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The following settings are only applicable if you are using the gps_data_beacon_igate script.
 | 
				
			||||||
 | 
					# They do not affect the operation gps_data itself.
 | 
				
			||||||
 | 
					# Time in minutes.
 | 
				
			||||||
 | 
					IGATE_BEACON_TIME = 45
 | 
				
			||||||
 | 
					IGATE_BEACON_COMMENT = HBLink3 D-APRS Gateway
 | 
				
			||||||
 | 
					IGATE_BEACON_ICON = /I
 | 
				
			||||||
 | 
					IGATE_LATITUDE = 4730.  N
 | 
				
			||||||
 | 
					IGATE_LONGITUDE = 11930.  W
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The following settings are for the static positions only, for hotspots or repeaters connected to MASTER stanzas.
 | 
				
			||||||
 | 
					# Implementation by IU7IGU
 | 
				
			||||||
 | 
					# REPORT_INTERVAL in Minute (ALLOW only > 3 Minutes)
 | 
				
			||||||
 | 
					# MESSAGE: This message will print on APRS description together RX and TX Frequency
 | 
				
			||||||
 | 
					APRS_STATIC_REPORT_INTERVAL: 15
 | 
				
			||||||
 | 
					APRS_STATIC_MESSAGE:Connected to HBLink
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The options below are required for operation of the dashboard and will cause errors in gps_data.py
 | 
				
			||||||
 | 
					# if configured wrong. Leave them as default unless you know what you are doing.
 | 
				
			||||||
 | 
					# If you do change, you must use absolute paths.
 | 
				
			||||||
 | 
					LOCATION_FILE: /tmp/gps_data_user_loc.txt
 | 
				
			||||||
 | 
					BULLETIN_BOARD_FILE: /tmp/gps_data_user_bb.txt
 | 
				
			||||||
 | 
					MAILBOX_FILE: /tmp/gps_data_user_mailbox.txt
 | 
				
			||||||
 | 
					EMERGENCY_SOS_FILE: /tmp/gps_data_user_sos.txt
 | 
				
			||||||
 | 
					SMS_FILE: /tmp/gps_data_user_sms.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# User settings file, MUST configure using absolute path.
 | 
				
			||||||
 | 
					USER_SETTINGS_FILE: /tmp/user_settings.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# API settings
 | 
				
			||||||
 | 
					# Authorized Apps file - data used for the dashboard API
 | 
				
			||||||
 | 
					USE_API: True
 | 
				
			||||||
 | 
					AUTHORIZED_APPS_FILE: /tmp/authorized_apps.txt
 | 
				
			||||||
 | 
					AUTHORIZED_TOKENS_FILE: /tmp/hblink_auth_tokens.txt
 | 
				
			||||||
 | 
					AUTHORIZED_USERS_FILE: /home/eric/Sync/hblink3_sms_dev/authorized_users.txt
 | 
				
			||||||
 | 
					ACCESS_SYSTEMS_FILE: /home/eric/Sync/hblink3_sms_dev/access_systems.txt
 | 
				
			||||||
 | 
					MY_SERVER_SHORTCUT: XYZ
 | 
				
			||||||
 | 
					SERVER_NAME: Test HBLink Network
 | 
				
			||||||
 | 
					USE_PUBLIC_APPS: True
 | 
				
			||||||
 | 
					PUBLIC_APPS_LIST: https://raw.githubusercontent.com/kf7eel/hblink_sms_external_apps/main/public_systems.txt
 | 
				
			||||||
 | 
					RULES_PATH: /home/eric/Sync/hblink3_sms_dev/rules.py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The following options are used for the dashboard. The dashboard is optional.
 | 
				
			||||||
 | 
					# Title of the Dashboard
 | 
				
			||||||
 | 
					DASHBOARD_TITLE: HBNet D-APRS Dashboard
 | 
				
			||||||
 | 
					# Used for API, RSS feed link, etc
 | 
				
			||||||
 | 
					DASHBOARD_URL: http://localhost:8092
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Logo used on dashboard page
 | 
				
			||||||
 | 
					LOGO: https://raw.githubusercontent.com/kf7eel/hblink3/gps/HBlink.png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Port to run server
 | 
				
			||||||
 | 
					DASH_PORT: 8092
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# IP to run server on
 | 
				
			||||||
 | 
					DASH_HOST: 127.0.0.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#Description of dashboard to show on main page
 | 
				
			||||||
 | 
					DESCRIPTION: Welcome to the dashboard.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Gateway contact info displayed on about page.
 | 
				
			||||||
 | 
					CONTACT_NAME: your name
 | 
				
			||||||
 | 
					CONTACT_CALL: N0CALL
 | 
				
			||||||
 | 
					CONTACT_EMAIL: email@example.org
 | 
				
			||||||
 | 
					CONTACT_WEBSITE: https://hbl.ink
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Time format for display
 | 
				
			||||||
 | 
					TIME_FORMAT: %%H:%%M:%%S - %%m/%%d/%%y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Center dashboard map over these coordinates
 | 
				
			||||||
 | 
					MAP_CENTER_LAT: 47.00
 | 
				
			||||||
 | 
					MAP_CENTER_LON: -120.00
 | 
				
			||||||
 | 
					ZOOM_LEVEL: 7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# List and preview of some map themes at http://leaflet-extras.github.io/leaflet-providers/preview/
 | 
				
			||||||
 | 
					# The following are options for map themes and just work, you should use one of these: “OpenStreetMap”, “Stamen” (Terrain, Toner, and Watercolor),
 | 
				
			||||||
 | 
					MAP_THEME: Stamen Toner
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# ACLs:
 | 
				
			||||||
 | 
					# OpenBridge does not 'register', so registration ACL is meaningless.
 | 
				
			||||||
 | 
					# Proper OpenBridge passes all traffic on TS1.
 | 
				
			||||||
 | 
					# HBlink can extend OPB to use both slots for unit calls only.
 | 
				
			||||||
 | 
					# Setting "BOTH_SLOTS" True ONLY affects unit traffic!
 | 
				
			||||||
 | 
					# Otherwise ACLs work as described in the global stanza
 | 
				
			||||||
 | 
					[OBP-1]
 | 
				
			||||||
 | 
					MODE: OPENBRIDGE
 | 
				
			||||||
 | 
					ENABLED: True
 | 
				
			||||||
 | 
					IP:
 | 
				
			||||||
 | 
					PORT: 62036
 | 
				
			||||||
 | 
					NETWORK_ID: 1234
 | 
				
			||||||
 | 
					PASSPHRASE: passw0rd
 | 
				
			||||||
 | 
					TARGET_IP: 127.0.0.1
 | 
				
			||||||
 | 
					TARGET_PORT: 62037
 | 
				
			||||||
 | 
					BOTH_SLOTS: True
 | 
				
			||||||
 | 
					USE_ACL: True
 | 
				
			||||||
 | 
					SUB_ACL: DENY:1
 | 
				
			||||||
 | 
					TGID_ACL: PERMIT:ALL
 | 
				
			||||||
 | 
					USE_ENCRYPTION: False
 | 
				
			||||||
 | 
					ENCRYPTION_KEY: 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# 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.
 | 
				
			||||||
 | 
					# Port should be the port you want this master to listen on. It must be unique
 | 
				
			||||||
 | 
					# and unused by anything else.
 | 
				
			||||||
 | 
					# Repeat - if True, the master repeats traffic to peers, False, it does nothing.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# MAX_PEERS -- maximun number of peers that may be connect to this master
 | 
				
			||||||
 | 
					# at any given time. This is very handy if you're allowing hotspots to
 | 
				
			||||||
 | 
					# connect, or using a limited computer like a Raspberry Pi.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# ACLs:
 | 
				
			||||||
 | 
					# See comments in the GLOBAL stanza
 | 
				
			||||||
 | 
					[MASTER-1]
 | 
				
			||||||
 | 
					MODE: MASTER
 | 
				
			||||||
 | 
					ENABLED: True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Use the user manager? If False, MASTER instance will operate as normal.
 | 
				
			||||||
 | 
					USE_USER_MAN: False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					REPEAT: True
 | 
				
			||||||
 | 
					MAX_PEERS: 3
 | 
				
			||||||
 | 
					EXPORT_AMBE: False
 | 
				
			||||||
 | 
					IP:
 | 
				
			||||||
 | 
					PORT: 62033
 | 
				
			||||||
 | 
					PASSPHRASE: passw0rd
 | 
				
			||||||
 | 
					GROUP_HANGTIME: 5
 | 
				
			||||||
 | 
					USE_ACL: True
 | 
				
			||||||
 | 
					REG_ACL: DENY:1
 | 
				
			||||||
 | 
					SUB_ACL: DENY:1
 | 
				
			||||||
 | 
					TGID_TS1_ACL: PERMIT:ALL
 | 
				
			||||||
 | 
					TGID_TS2_ACL: PERMIT:ALL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# PEER INSTANCES - DUPLICATE SECTION FOR MULTIPLE PEERS
 | 
				
			||||||
 | 
					# There are a LOT of errors in the HB Protocol specifications on this one!
 | 
				
			||||||
 | 
					# MOST of these items are just strings and will be properly dealt with by the program
 | 
				
			||||||
 | 
					# The TX & RX Frequencies are 9-digit numbers, and are the frequency in Hz.
 | 
				
			||||||
 | 
					# Latitude is an 8-digit unsigned floating point number.
 | 
				
			||||||
 | 
					# Longitude is a 9-digit signed floating point number.
 | 
				
			||||||
 | 
					# Height is in meters
 | 
				
			||||||
 | 
					# Setting Loose to True relaxes the validation on packets received from the master.
 | 
				
			||||||
 | 
					# This will allow HBlink to connect to a non-compliant system such as XLXD, DMR+ etc.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# ACLs:
 | 
				
			||||||
 | 
					# See comments in the GLOBAL stanza
 | 
				
			||||||
 | 
					[REPEATER-1]
 | 
				
			||||||
 | 
					MODE: PEER
 | 
				
			||||||
 | 
					ENABLED: False
 | 
				
			||||||
 | 
					LOOSE: False
 | 
				
			||||||
 | 
					EXPORT_AMBE: False
 | 
				
			||||||
 | 
					IP: 
 | 
				
			||||||
 | 
					PORT: 54001
 | 
				
			||||||
 | 
					MASTER_IP: 172.16.1.1
 | 
				
			||||||
 | 
					MASTER_PORT: 54000
 | 
				
			||||||
 | 
					PASSPHRASE: homebrew
 | 
				
			||||||
 | 
					CALLSIGN: W1ABC
 | 
				
			||||||
 | 
					RADIO_ID: 312000
 | 
				
			||||||
 | 
					RX_FREQ: 449000000
 | 
				
			||||||
 | 
					TX_FREQ: 444000000
 | 
				
			||||||
 | 
					TX_POWER: 25
 | 
				
			||||||
 | 
					COLORCODE: 1
 | 
				
			||||||
 | 
					SLOTS: 1
 | 
				
			||||||
 | 
					LATITUDE: 38.0000
 | 
				
			||||||
 | 
					LONGITUDE: -095.0000
 | 
				
			||||||
 | 
					HEIGHT: 75
 | 
				
			||||||
 | 
					LOCATION: Anywhere, USA
 | 
				
			||||||
 | 
					DESCRIPTION: This is a cool repeater
 | 
				
			||||||
 | 
					URL: www.w1abc.org
 | 
				
			||||||
 | 
					SOFTWARE_ID: 20170620
 | 
				
			||||||
 | 
					PACKAGE_ID: MMDVM_HBlink
 | 
				
			||||||
 | 
					GROUP_HANGTIME: 5
 | 
				
			||||||
 | 
					OPTIONS:
 | 
				
			||||||
 | 
					USE_ACL: True
 | 
				
			||||||
 | 
					SUB_ACL: DENY:1
 | 
				
			||||||
 | 
					TGID_TS1_ACL: PERMIT:ALL
 | 
				
			||||||
 | 
					TGID_TS2_ACL: PERMIT:ALL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[XLX-1]
 | 
				
			||||||
 | 
					MODE: XLXPEER
 | 
				
			||||||
 | 
					ENABLED: False
 | 
				
			||||||
 | 
					LOOSE: True
 | 
				
			||||||
 | 
					EXPORT_AMBE: False
 | 
				
			||||||
 | 
					IP: 
 | 
				
			||||||
 | 
					PORT: 54002
 | 
				
			||||||
 | 
					MASTER_IP: 172.16.1.1
 | 
				
			||||||
 | 
					MASTER_PORT: 62030
 | 
				
			||||||
 | 
					PASSPHRASE: passw0rd
 | 
				
			||||||
 | 
					CALLSIGN: W1ABC
 | 
				
			||||||
 | 
					RADIO_ID: 312000
 | 
				
			||||||
 | 
					RX_FREQ: 449000000
 | 
				
			||||||
 | 
					TX_FREQ: 444000000
 | 
				
			||||||
 | 
					TX_POWER: 25
 | 
				
			||||||
 | 
					COLORCODE: 1
 | 
				
			||||||
 | 
					SLOTS: 1
 | 
				
			||||||
 | 
					LATITUDE: 38.0000
 | 
				
			||||||
 | 
					LONGITUDE: -095.0000
 | 
				
			||||||
 | 
					HEIGHT: 75
 | 
				
			||||||
 | 
					LOCATION: Anywhere, USA
 | 
				
			||||||
 | 
					DESCRIPTION: This is a cool repeater
 | 
				
			||||||
 | 
					URL: www.w1abc.org
 | 
				
			||||||
 | 
					SOFTWARE_ID: 20170620
 | 
				
			||||||
 | 
					PACKAGE_ID: MMDVM_HBlink
 | 
				
			||||||
 | 
					GROUP_HANGTIME: 5
 | 
				
			||||||
 | 
					XLXMODULE: 4004
 | 
				
			||||||
 | 
					USE_ACL: True
 | 
				
			||||||
 | 
					SUB_ACL: DENY:1
 | 
				
			||||||
 | 
					TGID_TS1_ACL: PERMIT:ALL
 | 
				
			||||||
 | 
					TGID_TS2_ACL: PERMIT:ALL
 | 
				
			||||||
							
								
								
									
										339
									
								
								data_gateway.py
									
									
									
									
									
								
							
							
						
						
									
										339
									
								
								data_gateway.py
									
									
									
									
									
								
							@ -38,7 +38,7 @@ from twisted.internet import reactor, task
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Things we import from the main hblink module
 | 
					# Things we import from the main hblink module
 | 
				
			||||||
from hblink import HBSYSTEM, OPENBRIDGE, systems, hblink_handler, reportFactory, REPORT_OPCODES, mk_aliases, config_reports
 | 
					from hblink import HBSYSTEM, OPENBRIDGE, systems, hblink_handler, reportFactory, REPORT_OPCODES, mk_aliases, config_reports
 | 
				
			||||||
from dmr_utils3.utils import bytes_3, int_id, get_alias
 | 
					from dmr_utils3.utils import bytes_3, int_id, get_alias, bytes_4
 | 
				
			||||||
from dmr_utils3 import decode, bptc, const
 | 
					from dmr_utils3 import decode, bptc, const
 | 
				
			||||||
import data_gateway_config
 | 
					import data_gateway_config
 | 
				
			||||||
import log
 | 
					import log
 | 
				
			||||||
@ -89,6 +89,8 @@ import threading
 | 
				
			|||||||
import libscrc
 | 
					import libscrc
 | 
				
			||||||
import random
 | 
					import random
 | 
				
			||||||
from bitarray.util import hex2ba as hex2bits
 | 
					from bitarray.util import hex2ba as hex2bits
 | 
				
			||||||
 | 
					import traceback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#################################
 | 
					#################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -567,22 +569,326 @@ def process_sms(_rf_src, sms, call_type):
 | 
				
			|||||||
            if call_type == 'vcsbk':
 | 
					            if call_type == 'vcsbk':
 | 
				
			||||||
                send_sms(False, 9, 0000, 0000, 'group',  'APRS Messaging must be enabled. Send command "@APRS ON" or use dashboard to enable.')
 | 
					                send_sms(False, 9, 0000, 0000, 'group',  'APRS Messaging must be enabled. Send command "@APRS ON" or use dashboard to enable.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					##    try:
 | 
				
			||||||
        if sms in cmd_list:
 | 
					##        if sms in cmd_list:
 | 
				
			||||||
            logger.info('Executing command/script.')
 | 
					##            logger.info('Executing command/script.')
 | 
				
			||||||
            os.popen(cmd_list[sms]).read()
 | 
					##            os.popen(cmd_list[sms]).read()
 | 
				
			||||||
            packet_assembly = ''
 | 
					##            packet_assembly = ''
 | 
				
			||||||
    except Exception as error_exception:
 | 
					##    except Exception as error_exception:
 | 
				
			||||||
        logger.info('Exception. Command possibly not in list, or other error.')
 | 
					##        logger.info('Exception. Command possibly not in list, or other error.')
 | 
				
			||||||
        logger.info(error_exception)
 | 
					##        logger.info(error_exception)
 | 
				
			||||||
        logger.info(str(traceback.extract_tb(error_exception.__traceback__)))
 | 
					##        logger.info(str(traceback.extract_tb(error_exception.__traceback__)))
 | 
				
			||||||
        packet_assembly = ''
 | 
					##        packet_assembly = ''
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Module gobal varaibles
 | 
					##### SMS encode #########
 | 
				
			||||||
 | 
					############## SMS Que and functions ###########
 | 
				
			||||||
 | 
					def create_crc16(fragment_input):
 | 
				
			||||||
 | 
					    crc16 = libscrc.gsm16(bytearray.fromhex(fragment_input))
 | 
				
			||||||
 | 
					    return fragment_input + re.sub('x', '0', str(hex(crc16 ^ 0xcccc))[-4:])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def create_crc32(fragment_input):
 | 
				
			||||||
 | 
					    # Create and append CRC32 to data
 | 
				
			||||||
 | 
					    # Create list of hex
 | 
				
			||||||
 | 
					    word_list = []
 | 
				
			||||||
 | 
					    count_index = 0
 | 
				
			||||||
 | 
					    while count_index < len(fragment_input):
 | 
				
			||||||
 | 
					        word_list.append((fragment_input[count_index:count_index + 2]))
 | 
				
			||||||
 | 
					        count_index = count_index + 2
 | 
				
			||||||
 | 
					    # Create string of rearranged word_list to match ETSI 102 361-1 pg 141
 | 
				
			||||||
 | 
					    lst_index = 0
 | 
				
			||||||
 | 
					    crc_string = ''
 | 
				
			||||||
 | 
					    for i in (word_list):
 | 
				
			||||||
 | 
					        #print(lst_index)
 | 
				
			||||||
 | 
					        if lst_index % 2 == 0:
 | 
				
			||||||
 | 
					            crc_string =  crc_string + word_list[lst_index + 1]
 | 
				
			||||||
 | 
					            #print(crc_string)
 | 
				
			||||||
 | 
					        if lst_index % 2 == 1:
 | 
				
			||||||
 | 
					            crc_string = crc_string + word_list[lst_index - 1]
 | 
				
			||||||
 | 
					            #print(crc_string)
 | 
				
			||||||
 | 
					        lst_index = lst_index + 1
 | 
				
			||||||
 | 
					    # Create bytearray of word_list_string
 | 
				
			||||||
 | 
					   # print(crc_string)
 | 
				
			||||||
 | 
					    word_array = libscrc.posix(bytearray.fromhex(crc_string))
 | 
				
			||||||
 | 
					    # XOR to get almost final CRC
 | 
				
			||||||
 | 
					    pre_crc = str(hex(word_array ^ 0xffffffff))[2:]
 | 
				
			||||||
 | 
					    # Rearrange pre_crc for transmission
 | 
				
			||||||
 | 
					    crc = ''
 | 
				
			||||||
 | 
					    c = 8
 | 
				
			||||||
 | 
					    while c > 0:
 | 
				
			||||||
 | 
					        crc = crc + pre_crc[c-2:c]
 | 
				
			||||||
 | 
					        c = c - 2
 | 
				
			||||||
 | 
					    #crc = crc.zfill(8)
 | 
				
			||||||
 | 
					    crc = crc.ljust(8, '0')
 | 
				
			||||||
 | 
					    # Return original data and append CRC32
 | 
				
			||||||
 | 
					    print('Output: ' + fragment_input + crc)
 | 
				
			||||||
 | 
					    return fragment_input + crc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def create_crc16_csbk(fragment_input):
 | 
				
			||||||
 | 
					    crc16_csbk = libscrc.gsm16(bytearray.fromhex(fragment_input))
 | 
				
			||||||
 | 
					    return fragment_input + re.sub('x', '0', str(hex(crc16_csbk ^ 0xa5a5))[-4:])
 | 
				
			||||||
 | 
					def csbk_gen(to_id, from_id):
 | 
				
			||||||
 | 
					    csbk_lst = ['BD00801a', 'BD008019', 'BD008018', 'BD008017', 'BD008016']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    send_seq_list = ''
 | 
				
			||||||
 | 
					    for block in csbk_lst:
 | 
				
			||||||
 | 
					        block = block + to_id + from_id
 | 
				
			||||||
 | 
					        block  = create_crc16_csbk(block)
 | 
				
			||||||
 | 
					        print(block)
 | 
				
			||||||
 | 
					        send_seq_list = send_seq_list + block
 | 
				
			||||||
 | 
					        print(send_seq_list)
 | 
				
			||||||
 | 
					    return send_seq_list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def mmdvm_encapsulate(dst_id, src_id, peer_id, _seq, _slot, _call_type, _dtype_vseq, _stream_id, _dmr_data):
 | 
				
			||||||
 | 
					    signature = 'DMRD'
 | 
				
			||||||
 | 
					    # needs to be in bytes
 | 
				
			||||||
 | 
					    frame_type = 0x10 #bytes_2(int(10))
 | 
				
			||||||
 | 
					    #print((frame_type))
 | 
				
			||||||
 | 
					    dest_id = bytes_3(int(dst_id, 16))
 | 
				
			||||||
 | 
					    #print(ahex(dest_id))
 | 
				
			||||||
 | 
					    source_id = bytes_3(int(src_id, 16))
 | 
				
			||||||
 | 
					    via_id = bytes_4(int(peer_id, 16))
 | 
				
			||||||
 | 
					    #print(ahex(via_id))
 | 
				
			||||||
 | 
					    seq = int(_seq).to_bytes(1, 'big')
 | 
				
			||||||
 | 
					    #print(ahex(seq))
 | 
				
			||||||
 | 
					    # Binary, 0 for 1, 1 for 2
 | 
				
			||||||
 | 
					    slot = bitarray(str(_slot))
 | 
				
			||||||
 | 
					    #print(slot)
 | 
				
			||||||
 | 
					    # binary, 0 for group, 1 for unit, bin(1)
 | 
				
			||||||
 | 
					    call_type = bitarray(str(_call_type))
 | 
				
			||||||
 | 
					    #print(call_type)
 | 
				
			||||||
 | 
					    #0x00 for voice, 0x01 for voice sync, 0x10 for data 
 | 
				
			||||||
 | 
					    #frame_type = int(16).to_bytes(1, 'big')
 | 
				
			||||||
 | 
					    frame_type = bitarray('10')
 | 
				
			||||||
 | 
					    #print(frame_type)
 | 
				
			||||||
 | 
					    # Observed to be always 7, int. Will be 6 for header
 | 
				
			||||||
 | 
					    #dtype_vseq = hex(int(_dtype_vseq)).encode()
 | 
				
			||||||
 | 
					    if _dtype_vseq == 6:
 | 
				
			||||||
 | 
					        dtype_vseq = bitarray('0110')
 | 
				
			||||||
 | 
					    if _dtype_vseq == 7:
 | 
				
			||||||
 | 
					        dtype_vseq = bitarray('0111')
 | 
				
			||||||
 | 
					    if _dtype_vseq == 3:
 | 
				
			||||||
 | 
					        dtype_vseq = bitarray('0011')
 | 
				
			||||||
 | 
					    # 9 digit integer in hex
 | 
				
			||||||
 | 
					    stream_id = bytes_4(_stream_id)
 | 
				
			||||||
 | 
					    #print(ahex(stream_id))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    middle_guts = slot + call_type + frame_type + dtype_vseq
 | 
				
			||||||
 | 
					    #print(middle_guts)
 | 
				
			||||||
 | 
					    dmr_data = str(_dmr_data)[2:-1] #str(re.sub("b'|'", '', str(_dmr_data)))
 | 
				
			||||||
 | 
					    complete_packet = signature.encode() + seq + dest_id + source_id + via_id + middle_guts.tobytes() + stream_id + bytes.fromhex((dmr_data)) + bitarray('0000000000101111').tobytes()#bytes.fromhex(dmr_data)
 | 
				
			||||||
 | 
					    #print('Complete: ' + str(ahex(complete_packet)))
 | 
				
			||||||
 | 
					    return complete_packet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Break long string into block sequence
 | 
				
			||||||
 | 
					def block_sequence(input_string):
 | 
				
			||||||
 | 
					    seq_blocks = len(input_string)/24
 | 
				
			||||||
 | 
					    n = 0
 | 
				
			||||||
 | 
					    block_seq = []
 | 
				
			||||||
 | 
					    while n < seq_blocks:
 | 
				
			||||||
 | 
					        if n == 0:
 | 
				
			||||||
 | 
					            block_seq.append(bytes.fromhex(input_string[:24].ljust(24,'0')))
 | 
				
			||||||
 | 
					            n = n + 1
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            block_seq.append(bytes.fromhex(input_string[n*24:n*24+24].ljust(24,'0')))
 | 
				
			||||||
 | 
					            n = n + 1
 | 
				
			||||||
 | 
					    return block_seq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Takes list of DMR packets, 12 bytes, then encodes them
 | 
				
			||||||
 | 
					def dmr_encode(packet_list, _slot):
 | 
				
			||||||
 | 
					    send_seq = []
 | 
				
			||||||
 | 
					    for i in packet_list:
 | 
				
			||||||
 | 
					        stitched_pkt = bptc.interleave_19696(bptc.encode_19696(i))
 | 
				
			||||||
 | 
					        l_slot = bitarray('0111011100')
 | 
				
			||||||
 | 
					        r_slot = bitarray('1101110001')
 | 
				
			||||||
 | 
					        #Mobile Station
 | 
				
			||||||
 | 
					        #sync_data = bitarray('110101011101011111110111011111111101011101010111')
 | 
				
			||||||
 | 
					        if _slot == 0:
 | 
				
			||||||
 | 
					            # TS1 - F7FDD5DDFD55
 | 
				
			||||||
 | 
					            sync_data = bitarray('111101111111110111010101110111011111110101010101')
 | 
				
			||||||
 | 
					        if _slot == 1:
 | 
				
			||||||
 | 
					            #TS2 - D7557F5FF7F5
 | 
				
			||||||
 | 
					            sync_data = bitarray('110101110101010101111111010111111111011111110101')
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        # Data sync? 110101011101011111110111011111111101011101010111 - D5D7F77FD757
 | 
				
			||||||
 | 
					        new_pkt = ahex(stitched_pkt[:98] + l_slot + sync_data + r_slot + stitched_pkt[98:])
 | 
				
			||||||
 | 
					        send_seq.append(new_pkt)
 | 
				
			||||||
 | 
					    return send_seq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def create_sms_seq(dst_id, src_id, peer_id, _slot, _call_type, dmr_string):
 | 
				
			||||||
 | 
					    rand_seq = random.randint(1, 999999)
 | 
				
			||||||
 | 
					    block_seq = block_sequence(dmr_string)
 | 
				
			||||||
 | 
					    dmr_list = dmr_encode(block_seq, _slot)
 | 
				
			||||||
 | 
					    cap_in = 0
 | 
				
			||||||
 | 
					    mmdvm_send_seq = []
 | 
				
			||||||
 | 
					    for i in dmr_list:
 | 
				
			||||||
 | 
					        if use_csbk == True:
 | 
				
			||||||
 | 
					            if cap_in < 5:
 | 
				
			||||||
 | 
					                the_mmdvm_pkt = mmdvm_encapsulate(dst_id, src_id, peer_id, cap_in, _slot, _call_type, 3, rand_seq, i)
 | 
				
			||||||
 | 
					                #print(block_seq[cap_in])
 | 
				
			||||||
 | 
					                #print(3)
 | 
				
			||||||
 | 
					            if cap_in == 5:
 | 
				
			||||||
 | 
					                #print(block_seq[cap_in])
 | 
				
			||||||
 | 
					                #print(6)
 | 
				
			||||||
 | 
					                the_mmdvm_pkt = mmdvm_encapsulate(dst_id, src_id, peer_id, cap_in, _slot, _call_type, 6, rand_seq, i) #(bytes.fromhex(re.sub("b'|'", '', str(orig_cap[cap_in][20:-4])))))
 | 
				
			||||||
 | 
					            if cap_in > 5:
 | 
				
			||||||
 | 
					                #print(block_seq[cap_in])
 | 
				
			||||||
 | 
					                #print(7)
 | 
				
			||||||
 | 
					                the_mmdvm_pkt = mmdvm_encapsulate(dst_id, src_id, peer_id, cap_in, _slot, _call_type, 7, rand_seq, i)#(bytes.fromhex(re.sub("b'|'", '', str(orig_cap[cap_in][20:-4])))))
 | 
				
			||||||
 | 
					            mmdvm_send_seq.append(ahex(the_mmdvm_pkt))
 | 
				
			||||||
 | 
					            cap_in = cap_in + 1
 | 
				
			||||||
 | 
					        if use_csbk == False:
 | 
				
			||||||
 | 
					            if cap_in == 0:
 | 
				
			||||||
 | 
					                the_mmdvm_pkt = mmdvm_encapsulate(dst_id, src_id, peer_id, cap_in, _slot, _call_type, 6, rand_seq, i) #(bytes.fromhex(re.sub("b'|'", '', str(orig_cap[cap_in][20:-4])))))
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                the_mmdvm_pkt = mmdvm_encapsulate(dst_id, src_id, peer_id, cap_in, _slot, _call_type, 7, rand_seq, i)#(bytes.fromhex(re.sub("b'|'", '', str(orig_cap[cap_in][20:-4])))))
 | 
				
			||||||
 | 
					            mmdvm_send_seq.append(ahex(the_mmdvm_pkt))
 | 
				
			||||||
 | 
					            cap_in = cap_in + 1
 | 
				
			||||||
 | 
					            print(ahex(the_mmdvm_pkt))
 | 
				
			||||||
 | 
					            systems['OBP-2'].send_system(the_mmdvm_pkt)
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					    with open('/tmp/.hblink_data_que_' + str(CONFIG['DATA_CONFIG']['APRS_LOGIN_CALL']).upper() + '/' + str(random.randint(1000, 9999)) + '.mmdvm_seq', "w") as packet_write_file:
 | 
				
			||||||
 | 
					        packet_write_file.write(str(mmdvm_send_seq))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return mmdvm_send_seq
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Built for max length msg, will improve later
 | 
				
			||||||
 | 
					def sms_headers(to_id, from_id):
 | 
				
			||||||
 | 
					##    #ETSI 102 361-2 uncompressed ipv4
 | 
				
			||||||
 | 
					##    # UDP header, src and dest ports are 4007, 0fa7
 | 
				
			||||||
 | 
					##    udp_ports = '0fa70fa7'
 | 
				
			||||||
 | 
					##    # Length, of what?
 | 
				
			||||||
 | 
					##    udp_length = '00da'
 | 
				
			||||||
 | 
					##    # Checksum
 | 
				
			||||||
 | 
					##    udp_checksum = '4b37'
 | 
				
			||||||
 | 
					##
 | 
				
			||||||
 | 
					##    # IPV4
 | 
				
			||||||
 | 
					##    #IPV4 version and header length, always 45
 | 
				
			||||||
 | 
					##    ipv4_v_l = '45'
 | 
				
			||||||
 | 
					##    #Type of service, always 00
 | 
				
			||||||
 | 
					##    ipv4_svc = '00'
 | 
				
			||||||
 | 
					##    #length, always 00ee
 | 
				
			||||||
 | 
					##    ipv4_len = '00ee'
 | 
				
			||||||
 | 
					##    #ID always 000d
 | 
				
			||||||
 | 
					##    ipv4_id = '000d'
 | 
				
			||||||
 | 
					##    #Flags and offset always0
 | 
				
			||||||
 | 
					##    ipv4_flag_off = '0000'
 | 
				
			||||||
 | 
					##    #TTL and Protocol always 4011, no matter what
 | 
				
			||||||
 | 
					##    ipv4_ttl_proto = '4011'
 | 
				
			||||||
 | 
					    #ipv4 = '450000ee000d0000401100000c' + from_id + '0c' + to_id
 | 
				
			||||||
 | 
					    ipv4 = '450000ee00000000401100000c' + from_id + '0c' + to_id
 | 
				
			||||||
 | 
					    count_index = 0
 | 
				
			||||||
 | 
					    hdr_lst = []
 | 
				
			||||||
 | 
					    while count_index < len(ipv4):
 | 
				
			||||||
 | 
					        hdr_lst.append((ipv4[count_index:count_index + 4]))
 | 
				
			||||||
 | 
					        count_index = count_index + 4
 | 
				
			||||||
 | 
					    sum = 0
 | 
				
			||||||
 | 
					    for i in hdr_lst:
 | 
				
			||||||
 | 
					        sum = sum + int(i, 16)
 | 
				
			||||||
 | 
					    flipped = ''
 | 
				
			||||||
 | 
					    for i in str(bin(sum))[2:]:
 | 
				
			||||||
 | 
					        if i == '1':
 | 
				
			||||||
 | 
					            flipped = flipped + '0'
 | 
				
			||||||
 | 
					        if i == '0':
 | 
				
			||||||
 | 
					            flipped = flipped + '1'
 | 
				
			||||||
 | 
					    ipv4_chk_sum = str(hex(int(flipped, 2)))[2:]
 | 
				
			||||||
 | 
					    # UDP checksum is optional per ETSI, zero for now as Anytone is not affected.
 | 
				
			||||||
 | 
					    header = ipv4[:20] + ipv4_chk_sum + ipv4[24:] + '0fa70fa700da000000d0a00081040d000a'
 | 
				
			||||||
 | 
					    return header
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def format_sms(msg, to_id, from_id):
 | 
				
			||||||
 | 
					    msg_bytes = str.encode(msg)
 | 
				
			||||||
 | 
					    encoded = "".join([str('00' + x) for x in re.findall('..',bytes.hex(msg_bytes))] )
 | 
				
			||||||
 | 
					    final = encoded
 | 
				
			||||||
 | 
					    while len(final) < 400:
 | 
				
			||||||
 | 
					        final = final + '002e'
 | 
				
			||||||
 | 
					    final = final + '0000000000000000000000'
 | 
				
			||||||
 | 
					    headers = sms_headers(to_id, from_id)
 | 
				
			||||||
 | 
					    return headers + final
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def gen_header(to_id, from_id, call_type):
 | 
				
			||||||
 | 
					    if call_type == 1:
 | 
				
			||||||
 | 
					        seq_header = '024A' + to_id + from_id + '9550'
 | 
				
			||||||
 | 
					    if call_type == 0:
 | 
				
			||||||
 | 
					        seq_header = '824A' + to_id + from_id + '9550'
 | 
				
			||||||
 | 
					    return seq_header
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def send_sms(csbk, to_id, from_id, peer_id, call_type, msg):
 | 
				
			||||||
 | 
					    global use_csbk
 | 
				
			||||||
 | 
					    use_csbk = csbk
 | 
				
			||||||
 | 
					    to_id = str(hex(to_id))[2:].zfill(6)
 | 
				
			||||||
 | 
					    from_id = str(hex(from_id))[2:].zfill(6)
 | 
				
			||||||
 | 
					    peer_id = str(hex(peer_id))[2:].zfill(8)
 | 
				
			||||||
 | 
					    if call_type == 'unit':
 | 
				
			||||||
 | 
					        call_type = 1
 | 
				
			||||||
 | 
					        # Try to find slot from UNIT_MAP
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            #Slot 2
 | 
				
			||||||
 | 
					            if UNIT_MAP[bytes.fromhex(to_id)][2] == 2:
 | 
				
			||||||
 | 
					                slot = 1
 | 
				
			||||||
 | 
					            # Slot 1
 | 
				
			||||||
 | 
					            if UNIT_MAP[bytes.fromhex(to_id)][2] == 1:
 | 
				
			||||||
 | 
					                slot = 0
 | 
				
			||||||
 | 
					        except Exception as e:
 | 
				
			||||||
 | 
					            logger.info(e)
 | 
				
			||||||
 | 
					            # Change to config value later
 | 
				
			||||||
 | 
					            slot = 1
 | 
				
			||||||
 | 
					    if call_type == 'group':
 | 
				
			||||||
 | 
					        call_type = 0
 | 
				
			||||||
 | 
					        # Send all Group data to TS 2, need to fix later.
 | 
				
			||||||
 | 
					        slot = 1
 | 
				
			||||||
 | 
					    if csbk == 'yes':
 | 
				
			||||||
 | 
					        use_csbk = True
 | 
				
			||||||
 | 
					        create_sms_seq(to_id, from_id, peer_id, int(slot), new_call_type, csbk_gen(to_id, from_id) + create_crc16(gen_header(to_id, from_id, new_call_type)) + create_crc32(format_sms(msg, to_id, from_id)))
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        create_sms_seq(to_id, from_id, peer_id, int(slot), call_type, create_crc16(gen_header(to_id, from_id, call_type)) + create_crc32(format_sms(str(msg), to_id, from_id)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def data_que_check():
 | 
				
			||||||
 | 
					    l=task.LoopingCall(data_que_send)
 | 
				
			||||||
 | 
					    l.start(1)
 | 
				
			||||||
 | 
					def data_que_send():
 | 
				
			||||||
 | 
					    #logger.info('Check SMS que')
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        #logger.info(UNIT_MAP)
 | 
				
			||||||
 | 
					        for packet_file in os.listdir('/tmp/.hblink_data_que_' + str(CONFIG['DATA_CONFIG']['APRS_LOGIN_CALL']).upper() + '/'):
 | 
				
			||||||
 | 
					            logger.info('Sending SMS')
 | 
				
			||||||
 | 
					            logger.info(os.listdir('/tmp/.hblink_data_que_' + str(CONFIG['DATA_CONFIG']['APRS_LOGIN_CALL']).upper() + '/'))
 | 
				
			||||||
 | 
					            snd_seq = ast.literal_eval(os.popen('cat /tmp/.hblink_data_que_' + str(CONFIG['DATA_CONFIG']['APRS_LOGIN_CALL']).upper() + '/' + packet_file).read())
 | 
				
			||||||
 | 
					            for data in snd_seq:
 | 
				
			||||||
 | 
					                # Get dest id
 | 
				
			||||||
 | 
					                dst_id = bytes.fromhex(str(data[10:16])[2:-1])
 | 
				
			||||||
 | 
					                call_type = hex2bits(data)[121:122]
 | 
				
			||||||
 | 
					                # Handle UNIT calls
 | 
				
			||||||
 | 
					                if call_type[0] == True:
 | 
				
			||||||
 | 
					                # If destination ID in map, route call only there
 | 
				
			||||||
 | 
					                    if dst_id in UNIT_MAP:
 | 
				
			||||||
 | 
					                        data_target = UNIT_MAP[dst_id][0]
 | 
				
			||||||
 | 
					                        reactor.callFromThread(systems[data_target].send_system,bytes.fromhex(re.sub("b'|'", '', str(data))))
 | 
				
			||||||
 | 
					                        logger.info('Sending data to ' + str(data[10:16])[2:-1] + ' on system ' + data_target)
 | 
				
			||||||
 | 
					                    # Flood all systems
 | 
				
			||||||
 | 
					                    elif dst_id not in UNIT_MAP:
 | 
				
			||||||
 | 
					                        for i in UNIT:
 | 
				
			||||||
 | 
					                            reactor.callFromThread(systems[i].send_system,bytes.fromhex(re.sub("b'|'", '', str(data))))
 | 
				
			||||||
 | 
					                            logger.info('Sending data to ' + str(data[10:16])[2:-1] + ' on system ' + i)
 | 
				
			||||||
 | 
					                # Handle group calls
 | 
				
			||||||
 | 
					                elif call_type[0] == False:
 | 
				
			||||||
 | 
					                    for i in BRIDGES.items():
 | 
				
			||||||
 | 
					                        for d in i[1]:
 | 
				
			||||||
 | 
					                            if dst_id == d['TGID']:
 | 
				
			||||||
 | 
					                                data_target = d['SYSTEM']
 | 
				
			||||||
 | 
					                                reactor.callFromThread(systems[data_target].send_system,bytes.fromhex(re.sub("b'|'", '', str(data))))
 | 
				
			||||||
 | 
					                                logger.info('Sending data to ' + str(data[10:16])[2:-1] + ' on system ' + data_target)
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					            os.system('rm /tmp/.hblink_data_que_' + str(CONFIG['DATA_CONFIG']['APRS_LOGIN_CALL']).upper() + '/' + packet_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    #routerHBP.send_peer('MASTER-2', bytes.fromhex(re.sub("b'|'", '', str(data))))
 | 
				
			||||||
 | 
					    ##            os.system('rm /tmp/.hblink_data_que/' + packet_file)
 | 
				
			||||||
 | 
					    except Exception as e:
 | 
				
			||||||
 | 
					        logger.info(e)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
##class DATA():
 | 
					 | 
				
			||||||
##### DMR data function ####
 | 
					##### DMR data function ####
 | 
				
			||||||
def data_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data):
 | 
					def data_received(self, _peer_id, _rf_src, _dst_id, _seq, _slot, _call_type, _frame_type, _dtype_vseq, _stream_id, _data):
 | 
				
			||||||
    # Capture data headers
 | 
					    # Capture data headers
 | 
				
			||||||
@ -951,7 +1257,12 @@ if __name__ == '__main__':
 | 
				
			|||||||
        with open(sms_file, 'w') as user_sms_file:
 | 
					        with open(sms_file, 'w') as user_sms_file:
 | 
				
			||||||
            user_sms_file.write("[]")
 | 
					            user_sms_file.write("[]")
 | 
				
			||||||
            user_sms_file.close()
 | 
					            user_sms_file.close()
 | 
				
			||||||
    
 | 
					    try:
 | 
				
			||||||
 | 
					        Path('/tmp/.hblink_data_que_' + str(CONFIG['DATA_CONFIG']['APRS_LOGIN_CALL']).upper() + '/').mkdir(parents=True, exist_ok=True)
 | 
				
			||||||
 | 
					        logger.info('Created que directory')
 | 
				
			||||||
 | 
					    except:
 | 
				
			||||||
 | 
					        logger.info('Unable to create data que directory')
 | 
				
			||||||
 | 
					        pass    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Start the system logger
 | 
					    # Start the system logger
 | 
				
			||||||
    if cli_args.LOG_LEVEL:
 | 
					    if cli_args.LOG_LEVEL:
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										409
									
								
								data_gateway_config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										409
									
								
								data_gateway_config.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,409 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env python
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					#   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
 | 
				
			||||||
 | 
					#   the Free Software Foundation; either version 3 of the License, or
 | 
				
			||||||
 | 
					#   (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					#   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					#   GNU General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					#   along with this program; if not, write to the Free Software Foundation,
 | 
				
			||||||
 | 
					#   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					This module generates the configuration data structure for hblink.py and
 | 
				
			||||||
 | 
					assoicated programs that use it. It has been seaparated into a different
 | 
				
			||||||
 | 
					module so as to keep hblink.py easeier to navigate. This file only needs
 | 
				
			||||||
 | 
					updated if the items in the main configuraiton file (usually hblink.cfg)
 | 
				
			||||||
 | 
					change.
 | 
				
			||||||
 | 
					'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import configparser
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import const
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from socket import gethostbyname
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Does anybody read this stuff? There's a PEP somewhere that says I should do this.
 | 
				
			||||||
 | 
					__author__     = 'Cortney T. Buffington, N0MJS'
 | 
				
			||||||
 | 
					__copyright__  = 'Copyright (c) 2016-2018 Cortney T. Buffington, N0MJS and the K0USY Group'
 | 
				
			||||||
 | 
					__credits__    = 'Colin Durbridge, G4EML, Steve Zingman, N4IRS; Mike Zingman, N4IRR; Jonathan Naylor, G4KLX; Hans Barthen, DL5DI; Torsten Shultze, DG1HT'
 | 
				
			||||||
 | 
					__license__    = 'GNU GPLv3'
 | 
				
			||||||
 | 
					__maintainer__ = 'Cort Buffington, N0MJS'
 | 
				
			||||||
 | 
					__email__      = 'n0mjs@me.com'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Processing of ALS goes here. It's separated from the acl_build function because this
 | 
				
			||||||
 | 
					# code is hblink config-file format specific, and acl_build is abstracted
 | 
				
			||||||
 | 
					def process_acls(_config):
 | 
				
			||||||
 | 
					    # Global registration ACL
 | 
				
			||||||
 | 
					    _config['GLOBAL']['REG_ACL'] = acl_build(_config['GLOBAL']['REG_ACL'], const.PEER_MAX)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Global subscriber and TGID ACLs
 | 
				
			||||||
 | 
					    for acl in ['SUB_ACL', 'TG1_ACL', 'TG2_ACL']:
 | 
				
			||||||
 | 
					        _config['GLOBAL'][acl] = acl_build(_config['GLOBAL'][acl], const.ID_MAX)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # System level ACLs
 | 
				
			||||||
 | 
					    for system in _config['SYSTEMS']:
 | 
				
			||||||
 | 
					        # Registration ACLs (which make no sense for peer systems)
 | 
				
			||||||
 | 
					        if _config['SYSTEMS'][system]['MODE'] == 'MASTER':
 | 
				
			||||||
 | 
					            _config['SYSTEMS'][system]['REG_ACL'] = acl_build(_config['SYSTEMS'][system]['REG_ACL'], const.PEER_MAX)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Subscriber and TGID ACLs (valid for all system types)
 | 
				
			||||||
 | 
					        for acl in ['SUB_ACL', 'TG1_ACL', 'TG2_ACL']:
 | 
				
			||||||
 | 
					            _config['SYSTEMS'][system][acl] = acl_build(_config['SYSTEMS'][system][acl], const.ID_MAX)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Create an access control list that is programatically useable from human readable:
 | 
				
			||||||
 | 
					# ORIGINAL:  'DENY:1-5,3120101,3120124'
 | 
				
			||||||
 | 
					# PROCESSED: (False, set([(1, 5), (3120124, 3120124), (3120101, 3120101)]))
 | 
				
			||||||
 | 
					def acl_build(_acl, _max):
 | 
				
			||||||
 | 
					    if not _acl:
 | 
				
			||||||
 | 
					        return(True, set((const.ID_MIN, _max)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    acl = [] #set()
 | 
				
			||||||
 | 
					    sections = _acl.split(':')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if sections[0] == 'PERMIT':
 | 
				
			||||||
 | 
					        action = True
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        action = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for entry in sections[1].split(','):
 | 
				
			||||||
 | 
					        if entry == 'ALL':
 | 
				
			||||||
 | 
					            acl.append((const.ID_MIN, _max))
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        elif '-' in entry:
 | 
				
			||||||
 | 
					            start,end = entry.split('-')
 | 
				
			||||||
 | 
					            start,end = int(start), int(end)
 | 
				
			||||||
 | 
					            if (const.ID_MIN <= start <= _max) or (const.ID_MIN <= end <= _max):
 | 
				
			||||||
 | 
					                acl.append((start, end))
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                sys.exit('ACL CREATION ERROR, VALUE OUT OF RANGE ({} - {})IN RANGE-BASED ENTRY: {}'.format(const.ID_MIN, _max, entry))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            id = int(entry)
 | 
				
			||||||
 | 
					            if (const.ID_MIN <= id <= _max):
 | 
				
			||||||
 | 
					                acl.append((id, id))
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                 sys.exit('ACL CREATION ERROR, VALUE OUT OF RANGE ({} - {}) IN SINGLE ID ENTRY: {}'.format(const.ID_MIN, _max, entry))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return (action, acl)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def build_config(_config_file):
 | 
				
			||||||
 | 
					    config = configparser.ConfigParser()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not config.read(_config_file):
 | 
				
			||||||
 | 
					        sys.exit('Configuration file \''+_config_file+'\' is not a valid configuration file! Exiting...')        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CONFIG = {}
 | 
				
			||||||
 | 
					    CONFIG['GLOBAL'] = {}
 | 
				
			||||||
 | 
					    CONFIG['REPORTS'] = {}
 | 
				
			||||||
 | 
					    CONFIG['LOGGER'] = {}
 | 
				
			||||||
 | 
					    CONFIG['ALIASES'] = {}
 | 
				
			||||||
 | 
					    CONFIG['WEB_SERVICE'] = {}
 | 
				
			||||||
 | 
					    CONFIG['DATA_CONFIG'] = {}
 | 
				
			||||||
 | 
					    CONFIG['SYSTEMS'] = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        for section in config.sections():
 | 
				
			||||||
 | 
					            if section == 'GLOBAL':
 | 
				
			||||||
 | 
					                CONFIG['GLOBAL'].update({
 | 
				
			||||||
 | 
					                    'PATH': config.get(section, 'PATH'),
 | 
				
			||||||
 | 
					                    'PING_TIME': config.getint(section, 'PING_TIME'),
 | 
				
			||||||
 | 
					                    'MAX_MISSED': config.getint(section, 'MAX_MISSED'),
 | 
				
			||||||
 | 
					                    'USE_ACL': config.get(section, 'USE_ACL'),
 | 
				
			||||||
 | 
					                    'REG_ACL': config.get(section, 'REG_ACL'),
 | 
				
			||||||
 | 
					                    'SUB_ACL': config.get(section, 'SUB_ACL'),
 | 
				
			||||||
 | 
					                    'TG1_ACL': config.get(section, 'TGID_TS1_ACL'),
 | 
				
			||||||
 | 
					                    'TG2_ACL': config.get(section, 'TGID_TS2_ACL')
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            elif section == 'REPORTS':
 | 
				
			||||||
 | 
					                CONFIG['REPORTS'].update({
 | 
				
			||||||
 | 
					                    'REPORT': config.getboolean(section, 'REPORT'),
 | 
				
			||||||
 | 
					                    'REPORT_INTERVAL': config.getint(section, 'REPORT_INTERVAL'),
 | 
				
			||||||
 | 
					                    'REPORT_PORT': config.getint(section, 'REPORT_PORT'),
 | 
				
			||||||
 | 
					                    'REPORT_CLIENTS': config.get(section, 'REPORT_CLIENTS').split(',')
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            elif section == 'LOGGER':
 | 
				
			||||||
 | 
					                CONFIG['LOGGER'].update({
 | 
				
			||||||
 | 
					                    'LOG_FILE': config.get(section, 'LOG_FILE'),
 | 
				
			||||||
 | 
					                    'LOG_HANDLERS': config.get(section, 'LOG_HANDLERS'),
 | 
				
			||||||
 | 
					                    'LOG_LEVEL': config.get(section, 'LOG_LEVEL'),
 | 
				
			||||||
 | 
					                    'LOG_NAME': config.get(section, 'LOG_NAME')
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                if not CONFIG['LOGGER']['LOG_FILE']:
 | 
				
			||||||
 | 
					                    CONFIG['LOGGER']['LOG_FILE'] = '/dev/null'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            elif section == 'ALIASES':
 | 
				
			||||||
 | 
					                CONFIG['ALIASES'].update({
 | 
				
			||||||
 | 
					                    'TRY_DOWNLOAD': config.getboolean(section, 'TRY_DOWNLOAD'),
 | 
				
			||||||
 | 
					                    'PATH': config.get(section, 'PATH'),
 | 
				
			||||||
 | 
					                    'PEER_FILE': config.get(section, 'PEER_FILE'),
 | 
				
			||||||
 | 
					                    'SUBSCRIBER_FILE': config.get(section, 'SUBSCRIBER_FILE'),
 | 
				
			||||||
 | 
					                    'TGID_FILE': config.get(section, 'TGID_FILE'),
 | 
				
			||||||
 | 
					                    'PEER_URL': config.get(section, 'PEER_URL'),
 | 
				
			||||||
 | 
					                    'SUBSCRIBER_URL': config.get(section, 'SUBSCRIBER_URL'),
 | 
				
			||||||
 | 
					                    'STALE_TIME': config.getint(section, 'STALE_DAYS') * 86400,
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            elif section == 'WEB_SERVICE':
 | 
				
			||||||
 | 
					                CONFIG['WEB_SERVICE'].update({
 | 
				
			||||||
 | 
					                    'THIS_SERVER_NAME': config.get(section, 'THIS_SERVER_NAME'),
 | 
				
			||||||
 | 
					                    'URL': config.get(section, 'URL'),
 | 
				
			||||||
 | 
					                    'REMOTE_CONFIG_ENABLED': config.getboolean(section, 'REMOTE_CONFIG_ENABLED'),
 | 
				
			||||||
 | 
					                    'APPEND_INT': config.getint(section, 'APPEND_INT'),
 | 
				
			||||||
 | 
					                    'EXTRA_INT_1': config.getint(section, 'EXTRA_INT_1'),
 | 
				
			||||||
 | 
					                    'EXTRA_INT_2': config.getint(section, 'EXTRA_INT_2'),
 | 
				
			||||||
 | 
					                    'EXTRA_1': config.get(section, 'EXTRA_1'),
 | 
				
			||||||
 | 
					                    'EXTRA_2': config.get(section, 'EXTRA_2'),
 | 
				
			||||||
 | 
					                    'SHARED_SECRET': config.get(section, 'SHARED_SECRET'),
 | 
				
			||||||
 | 
					                    'SHORTEN_PASSPHRASE': config.getboolean(section, 'SHORTEN_PASSPHRASE'),
 | 
				
			||||||
 | 
					                    'SHORTEN_SAMPLE': config.get(section, 'SHORTEN_SAMPLE'),
 | 
				
			||||||
 | 
					                    'SHORTEN_LENGTH': config.get(section, 'SHORTEN_LENGTH'),
 | 
				
			||||||
 | 
					                    'BURN_FILE': config.get(section, 'BURN_FILE'),
 | 
				
			||||||
 | 
					                    'BURN_INT': config.getint(section, 'BURN_INT'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            elif section == 'DATA_CONFIG':
 | 
				
			||||||
 | 
					                CONFIG['DATA_CONFIG'].update({
 | 
				
			||||||
 | 
					                    'DATA_DMR_ID': config.get(section, 'DATA_DMR_ID'),
 | 
				
			||||||
 | 
					                    'USER_APRS_SSID': config.get(section, 'USER_APRS_SSID'),
 | 
				
			||||||
 | 
					                    'CALL_TYPE': config.get(section, 'CALL_TYPE'),
 | 
				
			||||||
 | 
					##                    'UNIT_SMS_TS': config.get(section, 'UNIT_SMS_TS'),
 | 
				
			||||||
 | 
					                    'USER_APRS_COMMENT': config.get(section, 'USER_APRS_COMMENT'),
 | 
				
			||||||
 | 
					                    'APRS_LOGIN_CALL': config.get(section, 'APRS_LOGIN_CALL'),
 | 
				
			||||||
 | 
					                    'APRS_LOGIN_PASSCODE': config.get(section, 'APRS_LOGIN_PASSCODE'),
 | 
				
			||||||
 | 
					                    'APRS_SERVER': config.get(section, 'APRS_SERVER'),
 | 
				
			||||||
 | 
					                    'APRS_PORT': config.get(section, 'APRS_PORT'),
 | 
				
			||||||
 | 
					                    'APRS_FILTER': config.get(section, 'APRS_FILTER'),
 | 
				
			||||||
 | 
					                    'IGATE_BEACON_TIME': config.get(section, 'IGATE_BEACON_TIME'),
 | 
				
			||||||
 | 
					                    'IGATE_BEACON_ICON': config.get(section, 'IGATE_BEACON_ICON'),
 | 
				
			||||||
 | 
					                    'IGATE_BEACON_COMMENT': config.get(section, 'IGATE_BEACON_COMMENT'),
 | 
				
			||||||
 | 
					                    'IGATE_LATITUDE': config.get(section, 'IGATE_LATITUDE'),
 | 
				
			||||||
 | 
					                    'IGATE_LONGITUDE': config.get(section, 'IGATE_LONGITUDE'),
 | 
				
			||||||
 | 
					                    'APRS_STATIC_REPORT_INTERVAL': config.get(section, 'APRS_STATIC_REPORT_INTERVAL'),
 | 
				
			||||||
 | 
					                    'APRS_STATIC_MESSAGE': config.get(section, 'APRS_STATIC_MESSAGE'),
 | 
				
			||||||
 | 
					##                    'EMAIL_SENDER': config.get(section, 'EMAIL_SENDER'),
 | 
				
			||||||
 | 
					##                    'EMAIL_PASSWORD': config.get(section, 'EMAIL_PASSWORD'),
 | 
				
			||||||
 | 
					##                    'SMTP_SERVER': config.get(section, 'SMTP_SERVER'),
 | 
				
			||||||
 | 
					##                    'SMTP_PORT': config.get(section, 'SMTP_PORT'),
 | 
				
			||||||
 | 
					                    'LOCATION_FILE': config.get(section, 'LOCATION_FILE'),
 | 
				
			||||||
 | 
					                    'BULLETIN_BOARD_FILE': config.get(section, 'BULLETIN_BOARD_FILE'),
 | 
				
			||||||
 | 
					                    'MAILBOX_FILE': config.get(section, 'MAILBOX_FILE'),
 | 
				
			||||||
 | 
					                    'SMS_FILE': config.get(section, 'SMS_FILE'),
 | 
				
			||||||
 | 
					                    'EMERGENCY_SOS_FILE': config.get(section, 'EMERGENCY_SOS_FILE'),
 | 
				
			||||||
 | 
					                    'USER_SETTINGS_FILE': config.get(section, 'USER_SETTINGS_FILE'),
 | 
				
			||||||
 | 
					##                    'USE_API': config.getboolean(section, 'USE_API'),
 | 
				
			||||||
 | 
					##                    'AUTHORIZED_TOKENS_FILE': config.get(section, 'AUTHORIZED_TOKENS_FILE'),
 | 
				
			||||||
 | 
					##                    'USE_PUBLIC_APPS': config.getboolean(section, 'USE_PUBLIC_APPS'),
 | 
				
			||||||
 | 
					##                    'PUBLIC_APPS_LIST': config.get(section, 'PUBLIC_APPS_LIST'),
 | 
				
			||||||
 | 
					##                    'MY_SERVER_SHORTCUT': config.get(section, 'MY_SERVER_SHORTCUT'),
 | 
				
			||||||
 | 
					##                    'DASHBOARD_URL': config.get(section, 'DASHBOARD_URL'),
 | 
				
			||||||
 | 
					##                    'SERVER_NAME': config.get(section, 'SERVER_NAME'),
 | 
				
			||||||
 | 
					##                    'RULES_PATH': config.get(section, 'RULES_PATH'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            elif config.getboolean(section, 'ENABLED'):
 | 
				
			||||||
 | 
					                if config.get(section, 'MODE') == 'PEER':
 | 
				
			||||||
 | 
					                    CONFIG['SYSTEMS'].update({section: {
 | 
				
			||||||
 | 
					                        'MODE': config.get(section, 'MODE'),
 | 
				
			||||||
 | 
					                        'ENABLED': config.getboolean(section, 'ENABLED'),
 | 
				
			||||||
 | 
					                        'LOOSE': config.getboolean(section, 'LOOSE'),
 | 
				
			||||||
 | 
					                        'SOCK_ADDR': (gethostbyname(config.get(section, 'IP')), config.getint(section, 'PORT')),
 | 
				
			||||||
 | 
					                        'IP': gethostbyname(config.get(section, 'IP')),
 | 
				
			||||||
 | 
					                        'PORT': config.getint(section, 'PORT'),
 | 
				
			||||||
 | 
					                        'MASTER_SOCKADDR': (gethostbyname(config.get(section, 'MASTER_IP')), config.getint(section, 'MASTER_PORT')),
 | 
				
			||||||
 | 
					                        'MASTER_IP': gethostbyname(config.get(section, 'MASTER_IP')),
 | 
				
			||||||
 | 
					                        'MASTER_PORT': config.getint(section, 'MASTER_PORT'),
 | 
				
			||||||
 | 
					                        'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE'), 'utf-8'),
 | 
				
			||||||
 | 
					                        'CALLSIGN': bytes(config.get(section, 'CALLSIGN').ljust(8)[:8], 'utf-8'),
 | 
				
			||||||
 | 
					                        'RADIO_ID': config.getint(section, 'RADIO_ID').to_bytes(4, 'big'),
 | 
				
			||||||
 | 
					                        'RX_FREQ': bytes(config.get(section, 'RX_FREQ').ljust(9)[:9], 'utf-8'),
 | 
				
			||||||
 | 
					                        'TX_FREQ': bytes(config.get(section, 'TX_FREQ').ljust(9)[:9], 'utf-8'),
 | 
				
			||||||
 | 
					                        'TX_POWER': bytes(config.get(section, 'TX_POWER').rjust(2,'0'), 'utf-8'),
 | 
				
			||||||
 | 
					                        'COLORCODE': bytes(config.get(section, 'COLORCODE').rjust(2,'0'), 'utf-8'),
 | 
				
			||||||
 | 
					                        'LATITUDE': bytes(config.get(section, 'LATITUDE').ljust(8)[:8], 'utf-8'),
 | 
				
			||||||
 | 
					                        'LONGITUDE': bytes(config.get(section, 'LONGITUDE').ljust(9)[:9], 'utf-8'),
 | 
				
			||||||
 | 
					                        'HEIGHT': bytes(config.get(section, 'HEIGHT').rjust(3,'0'), 'utf-8'),
 | 
				
			||||||
 | 
					                        'LOCATION': bytes(config.get(section, 'LOCATION').ljust(20)[:20], 'utf-8'),
 | 
				
			||||||
 | 
					                        'DESCRIPTION': bytes(config.get(section, 'DESCRIPTION').ljust(19)[:19], 'utf-8'),
 | 
				
			||||||
 | 
					                        'SLOTS': bytes(config.get(section, 'SLOTS'), 'utf-8'),
 | 
				
			||||||
 | 
					                        'URL': bytes(config.get(section, 'URL').ljust(124)[:124], 'utf-8'),
 | 
				
			||||||
 | 
					                        'SOFTWARE_ID': bytes(config.get(section, 'SOFTWARE_ID').ljust(40)[:40], 'utf-8'),
 | 
				
			||||||
 | 
					                        'PACKAGE_ID': bytes(config.get(section, 'PACKAGE_ID').ljust(40)[:40], 'utf-8'),
 | 
				
			||||||
 | 
					                        'GROUP_HANGTIME': config.getint(section, 'GROUP_HANGTIME'),
 | 
				
			||||||
 | 
					                        'OPTIONS': b''.join([b'Type=HBlink;', bytes(config.get(section, 'OPTIONS'), 'utf-8')]),
 | 
				
			||||||
 | 
					                        'USE_ACL': config.getboolean(section, 'USE_ACL'),
 | 
				
			||||||
 | 
					                        'SUB_ACL': config.get(section, 'SUB_ACL'),
 | 
				
			||||||
 | 
					                        'TG1_ACL': config.get(section, 'TGID_TS1_ACL'),
 | 
				
			||||||
 | 
					                        'TG2_ACL': config.get(section, 'TGID_TS2_ACL')
 | 
				
			||||||
 | 
					                    }})
 | 
				
			||||||
 | 
					                    CONFIG['SYSTEMS'][section].update({'STATS': {
 | 
				
			||||||
 | 
					                        'CONNECTION': 'NO',             # NO, RTPL_SENT, AUTHENTICATED, CONFIG-SENT, YES 
 | 
				
			||||||
 | 
					                        'CONNECTED': None,
 | 
				
			||||||
 | 
					                        'PINGS_SENT': 0,
 | 
				
			||||||
 | 
					                        'PINGS_ACKD': 0,
 | 
				
			||||||
 | 
					                        'NUM_OUTSTANDING': 0,
 | 
				
			||||||
 | 
					                        'PING_OUTSTANDING': False,
 | 
				
			||||||
 | 
					                        'LAST_PING_TX_TIME': 0,
 | 
				
			||||||
 | 
					                        'LAST_PING_ACK_TIME': 0,
 | 
				
			||||||
 | 
					                    }})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if config.get(section, 'MODE') == 'XLXPEER':
 | 
				
			||||||
 | 
					                    CONFIG['SYSTEMS'].update({section: {
 | 
				
			||||||
 | 
					                        'MODE': config.get(section, 'MODE'),
 | 
				
			||||||
 | 
					                        'ENABLED': config.getboolean(section, 'ENABLED'),
 | 
				
			||||||
 | 
					                        'LOOSE': config.getboolean(section, 'LOOSE'),
 | 
				
			||||||
 | 
					                        'SOCK_ADDR': (gethostbyname(config.get(section, 'IP')), config.getint(section, 'PORT')),
 | 
				
			||||||
 | 
					                        'IP': gethostbyname(config.get(section, 'IP')),
 | 
				
			||||||
 | 
					                        'PORT': config.getint(section, 'PORT'),
 | 
				
			||||||
 | 
					                        'MASTER_SOCKADDR': (gethostbyname(config.get(section, 'MASTER_IP')), config.getint(section, 'MASTER_PORT')),
 | 
				
			||||||
 | 
					                        'MASTER_IP': gethostbyname(config.get(section, 'MASTER_IP')),
 | 
				
			||||||
 | 
					                        'MASTER_PORT': config.getint(section, 'MASTER_PORT'),
 | 
				
			||||||
 | 
					                        'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE'), 'utf-8'),
 | 
				
			||||||
 | 
					                        'CALLSIGN': bytes(config.get(section, 'CALLSIGN').ljust(8)[:8], 'utf-8'),
 | 
				
			||||||
 | 
					                        'RADIO_ID': config.getint(section, 'RADIO_ID').to_bytes(4, 'big'),
 | 
				
			||||||
 | 
					                        'RX_FREQ': bytes(config.get(section, 'RX_FREQ').ljust(9)[:9], 'utf-8'),
 | 
				
			||||||
 | 
					                        'TX_FREQ': bytes(config.get(section, 'TX_FREQ').ljust(9)[:9], 'utf-8'),
 | 
				
			||||||
 | 
					                        'TX_POWER': bytes(config.get(section, 'TX_POWER').rjust(2,'0'), 'utf-8'),
 | 
				
			||||||
 | 
					                        'COLORCODE': bytes(config.get(section, 'COLORCODE').rjust(2,'0'), 'utf-8'),
 | 
				
			||||||
 | 
					                        'LATITUDE': bytes(config.get(section, 'LATITUDE').ljust(8)[:8], 'utf-8'),
 | 
				
			||||||
 | 
					                        'LONGITUDE': bytes(config.get(section, 'LONGITUDE').ljust(9)[:9], 'utf-8'),
 | 
				
			||||||
 | 
					                        'HEIGHT': bytes(config.get(section, 'HEIGHT').rjust(3,'0'), 'utf-8'),
 | 
				
			||||||
 | 
					                        'LOCATION': bytes(config.get(section, 'LOCATION').ljust(20)[:20], 'utf-8'),
 | 
				
			||||||
 | 
					                        'DESCRIPTION': bytes(config.get(section, 'DESCRIPTION').ljust(19)[:19], 'utf-8'),
 | 
				
			||||||
 | 
					                        'SLOTS': bytes(config.get(section, 'SLOTS'), 'utf-8'),
 | 
				
			||||||
 | 
					                        'URL': bytes(config.get(section, 'URL').ljust(124)[:124], 'utf-8'),
 | 
				
			||||||
 | 
					                        'SOFTWARE_ID': bytes(config.get(section, 'SOFTWARE_ID').ljust(40)[:40], 'utf-8'),
 | 
				
			||||||
 | 
					                        'PACKAGE_ID': bytes(config.get(section, 'PACKAGE_ID').ljust(40)[:40], 'utf-8'),
 | 
				
			||||||
 | 
					                        'GROUP_HANGTIME': config.getint(section, 'GROUP_HANGTIME'),
 | 
				
			||||||
 | 
					                        'XLXMODULE': config.getint(section, 'XLXMODULE'),
 | 
				
			||||||
 | 
					                        'OPTIONS': '',
 | 
				
			||||||
 | 
					                        'USE_ACL': config.getboolean(section, 'USE_ACL'),
 | 
				
			||||||
 | 
					                        'SUB_ACL': config.get(section, 'SUB_ACL'),
 | 
				
			||||||
 | 
					                        'TG1_ACL': config.get(section, 'TGID_TS1_ACL'),
 | 
				
			||||||
 | 
					                        'TG2_ACL': config.get(section, 'TGID_TS2_ACL')
 | 
				
			||||||
 | 
					                    }})
 | 
				
			||||||
 | 
					                    CONFIG['SYSTEMS'][section].update({'XLXSTATS': {
 | 
				
			||||||
 | 
					                        'CONNECTION': 'NO',             # NO, RTPL_SENT, AUTHENTICATED, CONFIG-SENT, YES 
 | 
				
			||||||
 | 
					                        'CONNECTED': None,
 | 
				
			||||||
 | 
					                        'PINGS_SENT': 0,
 | 
				
			||||||
 | 
					                        'PINGS_ACKD': 0,
 | 
				
			||||||
 | 
					                        'NUM_OUTSTANDING': 0,
 | 
				
			||||||
 | 
					                        'PING_OUTSTANDING': False,
 | 
				
			||||||
 | 
					                        'LAST_PING_TX_TIME': 0,
 | 
				
			||||||
 | 
					                        'LAST_PING_ACK_TIME': 0,
 | 
				
			||||||
 | 
					                    }})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                elif config.get(section, 'MODE') == 'MASTER':
 | 
				
			||||||
 | 
					                    CONFIG['SYSTEMS'].update({section: {
 | 
				
			||||||
 | 
					                        'MODE': config.get(section, 'MODE'),
 | 
				
			||||||
 | 
					                        'ENABLED': config.getboolean(section, 'ENABLED'),
 | 
				
			||||||
 | 
					                        'USE_USER_MAN': config.getboolean(section, 'USE_USER_MAN'),
 | 
				
			||||||
 | 
					                        'REPEAT': config.getboolean(section, 'REPEAT'),
 | 
				
			||||||
 | 
					                        'MAX_PEERS': config.getint(section, 'MAX_PEERS'),
 | 
				
			||||||
 | 
					                        'IP': gethostbyname(config.get(section, 'IP')),
 | 
				
			||||||
 | 
					                        'PORT': config.getint(section, 'PORT'),
 | 
				
			||||||
 | 
					                        'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE'), 'utf-8'),
 | 
				
			||||||
 | 
					                        'GROUP_HANGTIME': config.getint(section, 'GROUP_HANGTIME'),
 | 
				
			||||||
 | 
					                        'USE_ACL': config.getboolean(section, 'USE_ACL'),
 | 
				
			||||||
 | 
					                        'REG_ACL': config.get(section, 'REG_ACL'),
 | 
				
			||||||
 | 
					                        'SUB_ACL': config.get(section, 'SUB_ACL'),
 | 
				
			||||||
 | 
					                        'TG1_ACL': config.get(section, 'TGID_TS1_ACL'),
 | 
				
			||||||
 | 
					                        'TG2_ACL': config.get(section, 'TGID_TS2_ACL')
 | 
				
			||||||
 | 
					                    }})
 | 
				
			||||||
 | 
					                    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').to_bytes(4, 'big'),
 | 
				
			||||||
 | 
					                        'IP': gethostbyname(config.get(section, 'IP')),
 | 
				
			||||||
 | 
					                        'PORT': config.getint(section, 'PORT'),
 | 
				
			||||||
 | 
					                        'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE').ljust(20,'\x00')[:20], 'utf-8'),
 | 
				
			||||||
 | 
					                        'TARGET_SOCK': (gethostbyname(config.get(section, 'TARGET_IP')), config.getint(section, 'TARGET_PORT')),
 | 
				
			||||||
 | 
					                        'TARGET_IP': gethostbyname(config.get(section, 'TARGET_IP')),
 | 
				
			||||||
 | 
					                        'TARGET_PORT': config.getint(section, 'TARGET_PORT'),
 | 
				
			||||||
 | 
					                        'BOTH_SLOTS': config.getboolean(section, 'BOTH_SLOTS'),
 | 
				
			||||||
 | 
					                        'USE_ACL': config.getboolean(section, 'USE_ACL'),
 | 
				
			||||||
 | 
					                        'SUB_ACL': config.get(section, 'SUB_ACL'),
 | 
				
			||||||
 | 
					                        'TG1_ACL': config.get(section, 'TGID_ACL'),
 | 
				
			||||||
 | 
					                        'TG2_ACL': 'PERMIT:ALL',
 | 
				
			||||||
 | 
					                        'USE_ENCRYPTION': config.getboolean(section, 'USE_ENCRYPTION'),
 | 
				
			||||||
 | 
					                        'ENCRYPTION_KEY': bytes(config.get(section, 'ENCRYPTION_KEY'), 'utf-8'),
 | 
				
			||||||
 | 
					                    }})
 | 
				
			||||||
 | 
					                elif config.get(section, 'MODE') == 'PROXY':
 | 
				
			||||||
 | 
					                    CONFIG['SYSTEMS'].update({section: {
 | 
				
			||||||
 | 
					                        'MODE': config.get(section, 'MODE'),
 | 
				
			||||||
 | 
					                        'ENABLED': config.getboolean(section, 'ENABLED'),
 | 
				
			||||||
 | 
					                        'EXTERNAL_PROXY_SCRIPT': config.getboolean(section, 'EXTERNAL_PROXY_SCRIPT'),
 | 
				
			||||||
 | 
					                        'STATIC_APRS_POSITION_ENABLED': config.getboolean(section, 'STATIC_APRS_POSITION_ENABLED'),
 | 
				
			||||||
 | 
					                        'REPEAT': config.getboolean(section, 'REPEAT'),
 | 
				
			||||||
 | 
					                        'PASSPHRASE': bytes(config.get(section, 'PASSPHRASE'), 'utf-8'),
 | 
				
			||||||
 | 
					                        'EXTERNAL_PORT': config.getint(section, 'EXTERNAL_PORT'),
 | 
				
			||||||
 | 
					                        'INTERNAL_PORT_START': config.getint(section, 'INTERNAL_PORT_START'),
 | 
				
			||||||
 | 
					                        'INTERNAL_PORT_STOP': config.getint(section, 'INTERNAL_PORT_STOP'),
 | 
				
			||||||
 | 
					                        'GROUP_HANGTIME': config.getint(section, 'GROUP_HANGTIME'),
 | 
				
			||||||
 | 
					                        'USE_ACL': config.getboolean(section, 'USE_ACL'),
 | 
				
			||||||
 | 
					                        'REG_ACL': config.get(section, 'REG_ACL'),
 | 
				
			||||||
 | 
					                        'SUB_ACL': config.get(section, 'SUB_ACL'),
 | 
				
			||||||
 | 
					                        'TG1_ACL': config.get(section, 'TG1_ACL'),
 | 
				
			||||||
 | 
					                        'TG2_ACL': config.get(section, 'TG2_ACL'),
 | 
				
			||||||
 | 
					                    }})
 | 
				
			||||||
 | 
					                    CONFIG['SYSTEMS'][section].update({'PEERS': {}})
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    except configparser.Error as err:
 | 
				
			||||||
 | 
					        sys.exit('Error processing configuration file -- {}'.format(err))
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    process_acls(CONFIG)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return CONFIG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Used to run this file direclty and print the config,
 | 
				
			||||||
 | 
					# which might be useful for debugging
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    import os
 | 
				
			||||||
 | 
					    import argparse
 | 
				
			||||||
 | 
					    from pprint import pprint
 | 
				
			||||||
 | 
					    from dmr_utils3.utils import int_id
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    # Change the current directory to the location of the application
 | 
				
			||||||
 | 
					    os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # CLI argument parser - handles picking up the config file from the command line, and sending a "help" message
 | 
				
			||||||
 | 
					    parser = argparse.ArgumentParser()
 | 
				
			||||||
 | 
					    parser.add_argument('-c', '--config', action='store', dest='CONFIG_FILE', help='/full/path/to/config.file (usually hblink.cfg)')
 | 
				
			||||||
 | 
					    cli_args = parser.parse_args()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Ensure we have a path for the config file, if one wasn't specified, then use the execution directory
 | 
				
			||||||
 | 
					    if not cli_args.CONFIG_FILE:
 | 
				
			||||||
 | 
					        cli_args.CONFIG_FILE = os.path.dirname(os.path.abspath(__file__))+'/hblink.cfg'
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    CONFIG = build_config(cli_args.CONFIG_FILE)
 | 
				
			||||||
 | 
					    pprint(CONFIG)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def acl_check(_id, _acl):
 | 
				
			||||||
 | 
					        id = int_id(_id)
 | 
				
			||||||
 | 
					        for entry in _acl[1]:
 | 
				
			||||||
 | 
					            if entry[0] <= id <= entry[1]:
 | 
				
			||||||
 | 
					                return _acl[0]
 | 
				
			||||||
 | 
					        return not _acl[0]
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    print(acl_check(b'\x00\x01\x37', CONFIG['GLOBAL']['TG1_ACL']))
 | 
				
			||||||
@ -196,9 +196,12 @@ class OPENBRIDGE(DatagramProtocol):
 | 
				
			|||||||
                _data = _packet[:53]
 | 
					                _data = _packet[:53]
 | 
				
			||||||
                _hash = _packet[53:]
 | 
					                _hash = _packet[53:]
 | 
				
			||||||
                _ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest()
 | 
					                _ckhs = hmac_new(self._config['PASSPHRASE'],_data,sha1).digest()
 | 
				
			||||||
 | 
					                print(ahex(_ckhs))
 | 
				
			||||||
 | 
					                print(ahex(_hash))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                print(compare_digest(_hash, _ckhs))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if compare_digest(_hash, _ckhs) and _sockaddr == self._config['TARGET_SOCK']:
 | 
					                if compare_digest(_hash, _ckhs) and _sockaddr == self._config['TARGET_SOCK']:
 | 
				
			||||||
                    print('good data')
 | 
					 | 
				
			||||||
                    _peer_id = _data[11:15]
 | 
					                    _peer_id = _data[11:15]
 | 
				
			||||||
                    _seq = _data[4]
 | 
					                    _seq = _data[4]
 | 
				
			||||||
                    _rf_src = _data[5:8]
 | 
					                    _rf_src = _data[5:8]
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user