137 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			137 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								import socket
							 | 
						||
| 
								 | 
							
								import binascii
							 | 
						||
| 
								 | 
							
								import hmac
							 | 
						||
| 
								 | 
							
								import hashlib
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Data structure for holding IPSC information
							 | 
						||
| 
								 | 
							
								NETWORK = {
							 | 
						||
| 
								 | 
							
								    'IPSC1': {
							 | 
						||
| 
								 | 
							
								        'LOCAL': {
							 | 
						||
| 
								 | 
							
								            'DESCRIPTION': 'K0USY Lecompton, KS - Master',
							 | 
						||
| 
								 | 
							
								            'MODE': b'\x6A',
							 | 
						||
| 
								 | 
							
								            'PORT': 50001,
							 | 
						||
| 
								 | 
							
								            'RADIO_ID': binascii.unhexlify('00000001'),
							 | 
						||
| 
								 | 
							
								            'AUTH_KEY': binascii.unhexlify('0000000000000000000000000000000000012345')
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								        'MASTER': {
							 | 
						||
| 
								 | 
							
								            'IP': '24.143.49.121',
							 | 
						||
| 
								 | 
							
								            'MODE': b'\x6A',
							 | 
						||
| 
								 | 
							
								            'PORT': 50000,
							 | 
						||
| 
								 | 
							
								            'RADIO_ID': '',
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								        'PEERS': [  # each list entry will be a dictionary for IP, RADIO ID and PORT
							 | 
						||
| 
								 | 
							
								            #{'IP': '100.200.1.1', 'PORT': 50000, 'RADIO_ID': b'\x00\x00\x00\xFF'},
							 | 
						||
| 
								 | 
							
								        ]        
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Known IPSC Message Types
							 | 
						||
| 
								 | 
							
								RDAC_CTL              = b'\x70'
							 | 
						||
| 
								 | 
							
								GROUP_VOICE           = b'\x80'
							 | 
						||
| 
								 | 
							
								GROUP_DATA            = b'\x83'
							 | 
						||
| 
								 | 
							
								PVT_DATA              = b'\x84'
							 | 
						||
| 
								 | 
							
								REG_REQ               = b'\x90'
							 | 
						||
| 
								 | 
							
								REG_REPLY             = b'\x91'
							 | 
						||
| 
								 | 
							
								PEER_LIST_REQ         = b'\x92'
							 | 
						||
| 
								 | 
							
								PEER_LIST_REPLY       = b'\x93'
							 | 
						||
| 
								 | 
							
								PEER_KEEP_ALIVE_REQ   = b'\x94'
							 | 
						||
| 
								 | 
							
								PEER_KEEP_ALIVE_REPLY = b'\x95'
							 | 
						||
| 
								 | 
							
								KEEP_ALIVE_REQ        = b'\x96'
							 | 
						||
| 
								 | 
							
								KEEP_ALIVE_REPLY      = b'\x97'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# IPSC information
							 | 
						||
| 
								 | 
							
								IPSC_TS_BOTH   = b'\x6A'             # Both Timeslots IPSC enabled
							 | 
						||
| 
								 | 
							
								IPSC_OP_VER    = b'\x04\x03'         # 0x04, 0x03 -- seems to be current version of IPSC
							 | 
						||
| 
								 | 
							
								IPSC_OLD_VER   = b'\x04\x00'         # 0x04, 0x02 -- oldest version of IPSC suppoerted
							 | 
						||
| 
								 | 
							
								IPSC_FLAGS     = b'\x00\x00\x80\xDC' # Just accept this... it works, we know some of the pieces
							 | 
						||
| 
								 | 
							
								 
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#********** FUNCTIONS THAT WE WILL USE
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# function to send a payload to a defined socket
							 | 
						||
| 
								 | 
							
								def send_auth_packet (_dest_addr, _dest_port, _socket, _data, _key):
							 | 
						||
| 
								 | 
							
								    _hash = binascii.unhexlify((hmac.new(_key,_data,hashlib.sha1)).hexdigest()[:20])
							 | 
						||
| 
								 | 
							
								    print("==> Sending Authenticated Packet")
							 | 
						||
| 
								 | 
							
								    print("    Destination IP:", _dest_addr)
							 | 
						||
| 
								 | 
							
								    print("    Destination UDP Port:", _dest_port)
							 | 
						||
| 
								 | 
							
								    print("    Raw Packet:", binascii.b2a_hex(_data + _hash))
							 | 
						||
| 
								 | 
							
								    _socket.sendto((_data+_hash), (_dest_addr, _dest_port))
							 | 
						||
| 
								 | 
							
								    return
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Note: This function ignores authentiation information!!!
							 | 
						||
| 
								 | 
							
								def receive_packet(_socket):
							 | 
						||
| 
								 | 
							
								    _data = (_socket.recv(1024))
							 | 
						||
| 
								 | 
							
								    _peer_id = str(int(binascii.b2a_hex(_data[2:5]), 16))
							 | 
						||
| 
								 | 
							
								    _mode = binascii.b2a_hex(_data[5:6])
							 | 
						||
| 
								 | 
							
								    print('<== Response Recieved from Radio ID:', _peer_id)
							 | 
						||
| 
								 | 
							
								    print('    Raw Packet:', binascii.b2a_hex(_data))
							 | 
						||
| 
								 | 
							
								    # Parse returned information
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    _packettype = (_data[0:1])
							 | 
						||
| 
								 | 
							
								    _sock = 'IPSC1'
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    if (_packettype == REG_REQ):
							 | 
						||
| 
								 | 
							
								        print(" >> This is a registration packet")
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								    elif (_packettype == REG_REPLY):
							 | 
						||
| 
								 | 
							
								        print(" >> This is a registration reply packet")
							 | 
						||
| 
								 | 
							
								        
							 | 
						||
| 
								 | 
							
								    elif (_packettype == PEER_LIST_REPLY):
							 | 
						||
| 
								 | 
							
								        print(">> This packet is a peer list from the master")
							 | 
						||
| 
								 | 
							
								        _num_peers = int(str(int(binascii.b2a_hex(_data[5:7]), 16))[1:])
							 | 
						||
| 
								 | 
							
								        # print('>>There are', binascii.b2a_hex(_data[5:7]), 'peers in this IPSC (RAW)')
							 | 
						||
| 
								 | 
							
								        print('>> There are', _num_peers, 'peers in this IPSC')
							 | 
						||
| 
								 | 
							
								        for i in range(7, (_num_peers*11)+7, 11):
							 | 
						||
| 
								 | 
							
								            NETWORK[_sock]['PEERS'].append({
							 | 
						||
| 
								 | 
							
								            'RADIO_ID': binascii.b2a_hex(_data[i:i+4]), 
							 | 
						||
| 
								 | 
							
								            'IP':       binascii.b2a_hex(_data[i+4:i+8]), 
							 | 
						||
| 
								 | 
							
								            'PORT':     binascii.b2a_hex(_data[i+8:i+10]), 
							 | 
						||
| 
								 | 
							
								            'MODE':     binascii.b2a_hex(_data[i+10:i+11])
							 | 
						||
| 
								 | 
							
								            })
							 | 
						||
| 
								 | 
							
								        print_peer_list('IPSC1')        
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    return _data, _packettype
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def print_peer_list(_ipsc_network):
							 | 
						||
| 
								 | 
							
								  print(NETWORK[_ipsc_network]['LOCAL']['DESCRIPTION'])
							 | 
						||
| 
								 | 
							
								  for dictionary in NETWORK[_ipsc_network]['PEERS']:
							 | 
						||
| 
								 | 
							
								    hex_address = dictionary['IP']
							 | 
						||
| 
								 | 
							
								    hex_port = dictionary['PORT']
							 | 
						||
| 
								 | 
							
								    hex_radio_id = dictionary['RADIO_ID']
							 | 
						||
| 
								 | 
							
								    hex_mode = dictionary['MODE']
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    address = [int(hex_address[0:2], 16), int(hex_address[2:4], 16), int(hex_address[4:6], 16), int(hex_address[6:8], 16)]
							 | 
						||
| 
								 | 
							
								    port = int(hex_port, 16)
							 | 
						||
| 
								 | 
							
								    radio_id = int(hex_radio_id, 16)
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								    print(address[0],".",address[1],".",address[2],".",address[3],"\t", sep='', end='')
							 | 
						||
| 
								 | 
							
								    print(port, radio_id, hex_mode, sep='\t')
							 | 
						||
| 
								 | 
							
								  return
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#********** THE ACTUAL MEAT
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Create a socket to conetact IPSC Network #1
							 | 
						||
| 
								 | 
							
								ipsc1_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
							 | 
						||
| 
								 | 
							
								ipsc1_sock.bind(('', NETWORK['IPSC1']['LOCAL']['PORT']))
							 | 
						||
| 
								 | 
							
								ipsc1_sock.setblocking(0)
							 | 
						||
| 
								 | 
							
								ipsc1_sock.settimeout(60)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								CTL_SUFFIX              = (IPSC_TS_BOTH + IPSC_FLAGS + IPSC_OP_VER + IPSC_OLD_VER)
							 | 
						||
| 
								 | 
							
								REG_REQ_PACKET          = (REG_REQ + NETWORK['IPSC1']['LOCAL']['RADIO_ID'] + CTL_SUFFIX)
							 | 
						||
| 
								 | 
							
								KEEP_ALIVE_PACKET        = (KEEP_ALIVE_REQ + NETWORK['IPSC1']['LOCAL']['RADIO_ID'] + CTL_SUFFIX)
							 | 
						||
| 
								 | 
							
								PEER_LIST_REQ_PACKET    = (PEER_LIST_REQ + NETWORK['IPSC1']['LOCAL']['RADIO_ID'])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Send registration packet
							 | 
						||
| 
								 | 
							
								send_auth_packet(NETWORK['IPSC1']['MASTER']['IP'], NETWORK['IPSC1']['MASTER']['PORT'], ipsc1_sock, REG_REQ_PACKET, NETWORK['IPSC1']['LOCAL']['AUTH_KEY'])
							 | 
						||
| 
								 | 
							
								receive_packet(ipsc1_sock)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Send keep alive packet
							 | 
						||
| 
								 | 
							
								send_auth_packet(NETWORK['IPSC1']['MASTER']['IP'], NETWORK['IPSC1']['MASTER']['PORT'], ipsc1_sock, KEEP_ALIVE_PACKET, NETWORK['IPSC1']['LOCAL']['AUTH_KEY'])
							 | 
						||
| 
								 | 
							
								receive_packet(ipsc1_sock)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# Request peer list from master
							 | 
						||
| 
								 | 
							
								send_auth_packet(NETWORK['IPSC1']['MASTER']['IP'], NETWORK['IPSC1']['MASTER']['PORT'], ipsc1_sock, PEER_LIST_REQ_PACKET, NETWORK['IPSC1']['LOCAL']['AUTH_KEY'])
							 | 
						||
| 
								 | 
							
								receive_packet(ipsc1_sock)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ipsc1_sock.close
							 |