clientbot/spykhanat.py

1097 lines
69 KiB
Python
Raw Normal View History

2019-10-24 17:45:24 +00:00
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# script to read pcap file (communcation with khanat)
#
# Copyright (C) 2019 AleaJactaEst
#
# 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, see <http://www.gnu.org/licenses/>.
# Ex.:
# sudo tcpdump -i docker0 -w capture2.pcap
# ./spykhanat.py --pcap-file=../capture2.pcap --msg-xml=../khanat-opennel-code/code/ryzom/common/data_common/msg.xml
2020-07-27 20:17:48 +00:00
# ./spykhanat.py -m ../khanat-opennel-code/code/ryzom/common/data_common/msg.xml --yaml capture-2020-07-08-00-33-khanatclient.yml -w ../khanat-opennel-code/code/ryzom/common/data_common/database.xml -p capture-2020-07-08-00-33-khanatclient.pcap --filter-host-service='172.17.0.2:47851'
#
# FILEDATA="capture-2020-07-08-00-33-khanatclient.pcap"
# ./spykhanat.py -m ../khanat-opennel-code/code/ryzom/common/data_common/msg.xml --yaml ${FILEDATA::-5}.yml -w ../khanat-opennel-code/code/ryzom/common/data_common/database.xml -p $FILEDATA --filter-host-service='172.17.0.2:47851'
#
2019-10-24 17:45:24 +00:00
# install pcapfile
# pip install pypcapfile
2019-10-24 17:45:24 +00:00
import argparse
import logging
from pcapfile import savefile
from pcapfile.protocols.linklayer import ethernet
from pcapfile.protocols.network import ip
from pcapfile.protocols.transport import udp
from pcapfile.protocols.transport import tcp
import binascii
import re
from tools import BitStream
from tools import Enum
from tools import CActionFactory
from tools import CBitSet
from tools import DecodeImpulse
2020-07-20 19:56:58 +00:00
from tools import DecodeDatabase
2019-10-24 17:45:24 +00:00
from tools import World
from tools import CGenericMultiPartTemp
from tools import CImpulseDecoder
#from tools import CStringManager
2019-10-24 17:45:24 +00:00
from tools import CAction
from tools import Impulse
2020-07-20 19:56:58 +00:00
from tools import CPropertyDecoder
2020-07-27 20:17:48 +00:00
from tools import TVPNodeBase
2019-10-24 17:45:24 +00:00
import xml.etree.ElementTree as ET
2019-11-03 12:42:13 +00:00
from datetime import datetime
2019-10-24 17:45:24 +00:00
LOGGER = 'SpyKhanat'
#file = open('capture2.pcap' , 'rb')
#pcapfile = savefile.load_savefile(file,verbose=True)
#pkt = pcapfile.packets[0]
#print(pkt.raw())
#print(pkt.timestamp)
#eth_frame = ethernet.Ethernet(pkt.raw())
#print(eth_frame)
#ip_packet = ip.IP(binascii.unhexlify(eth_frame.payload))
#print(ip_packet)
def write_yaml_str_or_array(outyaml, nbspace, value):
if type(value) == str:
outyaml.write(" " * nbspace + "- %s\n" % (value))
else:
for key in value:
outyaml.write(" " * nbspace + "- %s\n" % (key))
outyaml.write(" " * nbspace + str(type(value)) + "\n")
2019-10-24 17:45:24 +00:00
class SpyPcap():
def __init__(self, khanat_host_service, pcap_file, msg_xml, database_xml, filter_host_service, show_raw_packet, show_message_decoded, outyaml=None, outcsv=False):
2019-10-24 17:45:24 +00:00
if khanat_host_service:
self.khanat_host_service = re.compile(khanat_host_service)
else:
self.khanat_host_service = None
self.pcap_file = pcap_file
self.msg_xml = msg_xml
if filter_host_service:
self.filter_host_service = re.compile(filter_host_service)
else:
self.filter_host_service = None
self.show_raw_packet = show_raw_packet
self.show_message_decoded = show_message_decoded
self.actionFactory = CActionFactory.CActionFactory(None)
self.client_state = {}
2020-07-20 19:56:58 +00:00
# msg.xml
2019-10-24 17:45:24 +00:00
self.decodeImpulse = DecodeImpulse.DecodeImpulse()
self.decodeImpulseSimple = Impulse.DecodeImpulseSimple()
2019-10-24 17:45:24 +00:00
fp = open(msg_xml , 'rt')
msgRawXml = fp.read()
2020-07-20 19:56:58 +00:00
fp.close()
2019-10-24 17:45:24 +00:00
self.msgXml = ET.fromstring(msgRawXml)
self.decodeImpulse.loadMsg(self.msgXml)
self.decodeImpulseSimple.loadMsg(self.msgXml)
2020-07-20 19:56:58 +00:00
# database.xml
#self.decodeDatabase = DecodeDatabase.DecodeDatabase()
fp = open(database_xml, 'rt')
databaseRawXml = fp.read()
fp.close()
self.databaseXml = ET.fromstring(databaseRawXml)
2020-11-11 15:33:08 +00:00
#self.decodeImpulseSimple.loadDatabase(self.databaseXml)
2020-07-20 19:56:58 +00:00
self.decodeDatabase = DecodeDatabase.DecodeDatabase()
self.decodeDatabase.loadDatabase(self.databaseXml)
2020-11-11 15:33:08 +00:00
self.decodeImpulseSimple.loadDatabase(self.decodeDatabase)
2020-07-20 19:56:58 +00:00
# outyaml
2019-11-06 20:36:42 +00:00
self.outyaml = outyaml
self.outcsv = outcsv
2019-10-24 17:45:24 +00:00
def readRaw(self):
file = open( self.pcap_file , 'rb')
pcapfile = savefile.load_savefile(file,verbose=False)
for pkt in pcapfile.packets:
2020-11-25 19:57:28 +00:00
#print("pkt:", dir(pkt))
#print("pkt.header:", dir(pkt.header))
#print("pkt.packet:", dir(pkt.packet))
2019-10-24 17:45:24 +00:00
logging.getLogger(LOGGER).debug("raw: %s" % pkt.raw())
2019-11-03 12:42:13 +00:00
logging.getLogger(LOGGER).debug("timestamp: %s (%s)" % (pkt.timestamp,datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S")))
2019-10-24 17:45:24 +00:00
eth_frame = ethernet.Ethernet(pkt.raw())
logging.getLogger(LOGGER).debug("eth_frame: %s" % eth_frame)
if eth_frame.type == 2048:
ip_packet = ip.IP(binascii.unhexlify(eth_frame.payload))
logging.getLogger(LOGGER).debug("ip packet: %s" % ip_packet)
2020-11-25 19:57:28 +00:00
#print("ip_packet:", dir(ip_packet))
2019-10-24 17:45:24 +00:00
logging.getLogger(LOGGER).debug("ip packet: %s ->%s" % (ip_packet.src.decode(), ip_packet.dst.decode()) )
if ip_packet.p == 17:
# UDP
logging.getLogger(LOGGER).debug("ip packet: protocol UDP (%s)" % ip_packet.p)
udp_packet = udp.UDP(binascii.unhexlify(ip_packet.payload))
2020-11-25 19:57:28 +00:00
#print("udp_packet:", dir(udp_packet))
2019-10-24 17:45:24 +00:00
logging.getLogger(LOGGER).debug("UDP packet: %s" % udp_packet)
data = udp_packet.payload
2020-11-25 19:57:28 +00:00
#print("data:", dir(data))
2019-10-24 17:45:24 +00:00
logging.getLogger(LOGGER).debug("data packet: %s" % data)
data = udp_packet.payload
logging.getLogger(LOGGER).info("data packet: timestamp:%s src:%s:%d dst:%s:%d data:%s" % (pkt.timestamp,
ip_packet.src.decode(), udp_packet.src_port,
ip_packet.dst.decode(), udp_packet.dst_port,
data.decode()))
elif ip_packet.p == 6:
# TCP
logging.getLogger(LOGGER).debug("ip packet: protocol TCP (%s)" % ip_packet.p)
tcp_packet = tcp.TCP(binascii.unhexlify(ip_packet.payload))
data = tcp_packet.payload
logging.getLogger(LOGGER).info("data packet: timestamp:%s src:%s:%d dst:%s:%d data:%s" % (pkt.timestamp,
ip_packet.src.decode(), tcp_packet.src_port,
ip_packet.dst.decode(), tcp_packet.dst_port,
data.decode()))
else:
logging.getLogger(LOGGER).debug("ip packet: protocol (%s)" % ip_packet.p)
def detect_khanat_server(self, packets):
hostdetected = {}
for pkt in packets:
eth_frame = ethernet.Ethernet(pkt.raw())
if eth_frame.type == 2048:
ip_packet = ip.IP(binascii.unhexlify(eth_frame.payload))
if ip_packet.p == 17: # UDP
udp_packet = udp.UDP(binascii.unhexlify(ip_packet.payload))
data = udp_packet.payload
host = "%s:%d" % (ip_packet.src.decode(), udp_packet.src_port)
hostdetected.setdefault(host, 0)
if len(data) == 20:
hostdetected[host] += 1
id = None
max = 0
for host in hostdetected:
if id:
if max < hostdetected[host]:
max = hostdetected[host]
id = host
else:
max = hostdetected[host]
id = host
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).info(" host :%s" % id)
2019-10-24 17:45:24 +00:00
return id
def initialize_client(self, clientid):
self.client_state.setdefault(clientid, {'CurrentReceivedNumber': 0,
'CurrentSendNumber': 0,
'LastReceivedAck': 0,
2019-11-03 12:42:13 +00:00
'AckBitMask': 0,
2019-10-24 17:45:24 +00:00
'RegisteredAction': {},
'world': World.World(),
'GenericMultiPartTempServer': CGenericMultiPartTemp.GenericMultiPartTemp(),
'GenericMultiPartTempClient': CGenericMultiPartTemp.GenericMultiPartTemp(),
2019-10-24 17:45:24 +00:00
'CImpulseDecoder': None,
'CActionFactory': None,
2019-10-24 17:45:24 +00:00
'LastAck0': [-1],
'LastAck1': [-1, -1],
'LastAck2': [-1, -1, -1, -1]})
self.client_state[clientid]['CImpulseDecoder'] = CImpulseDecoder.CImpulseDecoder(self.client_state[clientid]['world'])
self.client_state[clientid]['CActionFactory'] = CActionFactory.CActionFactory(self.client_state[clientid]['world'])
2019-10-24 17:45:24 +00:00
def add_registered_action(self, clientid, action):
self.client_state[clientid]['RegisteredAction'].setdefault(action.Code, [])
self.client_state[clientid]['RegisteredAction'][action.Code].append(action)
2020-07-27 20:17:48 +00:00
self.client_state[clientid]['PropertyDecoder'] = CPropertyDecoder.CPropertyDecoder()
self.client_state[clientid]['VisualPropertyTreeRoot'] = TVPNodeBase.TVPNodeBase("_VisualPropertyTreeRoot")
self.client_state[clientid]['VisualPropertyTreeRoot'].build_tree()
# def decodeDiscreetProperties(self, clientid, msgin):
# # khanat-opennel-code/code/ryzom/client/src/network_connection.h:148 void decodeDiscreetProperties( NLMISC::CBitMemStream& msgin )
# BranchHasPayload = msgin.readBool("BranchHasPayload")
# if BranchHasPayload:
# if self.client_state[clientid]['VisualPropertyTreeRoot'].isLeaf():
# PropIndex = self.client_state[clientid]['VisualPropertyTreeRoot'].PropIndex
# self.client_state[clientid]['VisualPropertyTreeRoot'].decodeDiscreetProperty(msgin, PropIndex)
#if ( BranchHasPayload )
# {
# if ( isLeaf() )
# {
# SlotContext.NetworkConnection->decodeDiscreetProperty( msgin, PropIndex );
# }
# else
# {
# if ( a() ) a()->decodeDiscreetProperties( msgin );
# if ( b() ) b()->decodeDiscreetProperties( msgin );
# }
# }
2020-07-20 19:56:58 +00:00
def decodeVisualProperties(self, clientid, msgin):
"""
2020-07-27 20:17:48 +00:00
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1512 void CNetworkConnection::decodeVisualProperties( CBitMemStream& msgin )
2020-07-20 19:56:58 +00:00
"""
actions = []
2020-07-27 20:17:48 +00:00
properties = []
notices = {}
2020-07-20 19:56:58 +00:00
try:
while True:
2020-07-27 20:17:48 +00:00
property = {}
2020-07-20 19:56:58 +00:00
# if ( msgin.getPosInBit() + (sizeof(TCLEntityId)*8) > msgin.length()*8 ) return
2020-07-27 20:17:48 +00:00
# if msgin.sizeRead() + (8*8 ) > msgin.sizeData() * 8:
#if msgin.needRead() < (8*8):
if msgin.needRead() < 8:
logging.getLogger(LOGGER).debug("too small no decodeVisualProperties [{0} > {1}]".format(msgin.sizeRead() + (8*8 ), msgin.sizeData() * 8 ))
2020-11-25 19:57:28 +00:00
logging.getLogger(LOGGER).debug("properties:%s" % str(properties))
return properties, notices
2020-07-27 20:17:48 +00:00
logging.getLogger(LOGGER).debug("too small no decodeVisualProperties [{0} > {1}]".format(msgin.sizeRead() + (8*8 ), msgin.sizeData() * 8 ))
2020-07-20 19:56:58 +00:00
slot = msgin.readUint8("Slot")
2020-07-27 20:17:48 +00:00
property['slot'] = slot
hearder = 'VisualProperty/Slot'+str(slot) + '/'
2020-07-20 19:56:58 +00:00
associationBits = msgin.readSerial(2, "associationBits")
notices.setdefault(hearder + 'associationBits', associationBits)
2020-07-27 20:17:48 +00:00
property['associationBits'] = associationBits
logging.getLogger(LOGGER).debug("slot:{0} (associationBits:{1})".format(slot, associationBits))
2020-07-20 19:56:58 +00:00
if self.client_state[clientid]['PropertyDecoder'] .associationBitsHaveChanged( slot, associationBits ) and (slot==0):
if self.client_state[clientid]['PropertyDecoder'] .isUsed( slot ):
sheet = self.client_state[clientid]['PropertyDecoder'] .getSheet(slot)
2020-07-27 20:17:48 +00:00
property['sheet'] = sheet
notices.setdefault(hearder + 'sheet', sheet)
2020-07-27 20:17:48 +00:00
logging.getLogger(LOGGER).debug("sheet:{0}".format(sheet))
# TODO - remove sheet found in the list
2020-07-20 19:56:58 +00:00
timestampIsThere = msgin.readBool("timestampIsThere")
if timestampIsThere:
timestampDelta = msgin.readSerial(4, "timestampDelta")
timestamp = self.client_state[clientid]['CurrentReceivedNumber'] - timestampDelta
2020-07-27 20:17:48 +00:00
logging.getLogger(LOGGER).debug("timestamp:{0} (timestampDelta:{1})".format(timestamp, timestampDelta))
2020-07-20 19:56:58 +00:00
else:
timestamp = self.client_state[clientid]['CurrentReceivedNumber']
2020-07-27 20:17:48 +00:00
logging.getLogger(LOGGER).debug("timestamp:{0}".format(timestamp))
property['timestamp'] = timestamp
notices.setdefault(hearder + 'timestamp', timestamp)
2020-07-27 20:17:48 +00:00
property.setdefault('Actions', [])
2020-07-20 19:56:58 +00:00
# Tree
# currentNode->a()
2020-07-27 20:17:48 +00:00
BranchHasPayload = msgin.readBool("BranchHasPayload [_VisualPropertyTreeRoot.VPA]")
logging.getLogger(LOGGER).debug("_VisualPropertyTreeRoot.VPA->BranchHasPayload:{0}".format(BranchHasPayload))
2020-07-20 19:56:58 +00:00
if BranchHasPayload:
# _PropertyDecoder.receive( _CurrentReceivedNumber, ap );
# Create a new action
cActionPosition = CAction.CActionPosition(slot, Enum.TActionCode.ACTION_POSITION_CODE, self.client_state[clientid]['world'])
2020-07-27 20:17:48 +00:00
cActionPosition.set_name('POSITION_CODE')
cActionPosition.set_header_notice(hearder + 'POSITION_CODE')
2020-07-20 19:56:58 +00:00
self.client_state[clientid]['PropertyDecoder'] .receive(cActionPosition)
cActionPosition.unpack(msgin)
actions.append(cActionPosition)
for key in cActionPosition.notice:
notices.setdefault(key, cActionPosition.notice[key])
#notice.setdefault(hearder + 'POSITION_CODE', cActionPosition)
2020-07-27 20:17:48 +00:00
property['Actions'] .append(cActionPosition)
2020-07-20 19:56:58 +00:00
# currentNode->b()
2020-07-27 20:17:48 +00:00
BranchHasPayload = msgin.readBool("BranchHasPayload [_VisualPropertyTreeRoot.VPB]")
logging.getLogger(LOGGER).debug("_VisualPropertyTreeRoot.VPB->BranchHasPayload:{0}".format(BranchHasPayload))
2020-07-20 19:56:58 +00:00
if BranchHasPayload:
# currentNode->b()->a()
2020-07-27 20:17:48 +00:00
BranchHasPayload = msgin.readBool("BranchHasPayload [_VisualPropertyTreeRoot.VPB.VPA]")
logging.getLogger(LOGGER).debug("_VisualPropertyTreeRoot.VPB.VPA->BranchHasPayload:{0}".format(BranchHasPayload))
if BranchHasPayload:
# Create a new action -> PROPERTY_ORIENTATION
cActionOrientation= CAction.CActionSint64(slot, Enum.TPropIndex.PROPERTY_ORIENTATION, self.client_state[clientid]['world'])
cActionOrientation.set_header_notice(hearder + 'Sint64')
2020-07-27 20:17:48 +00:00
cActionOrientation.setNbBits(Enum.TPropIndex.PROPERTY_ORIENTATION, 'PROPERTY_ORIENTATION')
cActionOrientation.set_name('PROPERTY_ORIENTATION')
cActionOrientation.unpack(msgin)
#self.client_state[clientid]['PropertyDecoder'] .receive(cActionPosition)
actions.append(cActionOrientation)
for key in cActionOrientation.notice:
notices.setdefault(key, cActionOrientation.notice[key])
2020-07-27 20:17:48 +00:00
property['Actions'] .append(cActionOrientation)
2020-07-20 19:56:58 +00:00
# Discreet properties
2020-07-27 20:17:48 +00:00
# _VisualPropertyTreeRoot->b()->b()
actions, addnotices = self.client_state[clientid]['VisualPropertyTreeRoot'].decodeDiscreetPropertiesVpbVpb(clientid, msgin, slot, self.client_state[clientid]['world'])
for key in addnotices:
notices.setdefault(hearder + key, addnotices[key])
2020-07-27 20:17:48 +00:00
for action in actions:
property['Actions'] .append(action)
#self.decodeDiscreetProperties(clientid, msgin)
properties.append(property)
except Exception as e:
raise e
2020-07-20 19:56:58 +00:00
except:
# Detect end of stream (little hard to close)
pass
return properties, notices
2019-10-24 17:45:24 +00:00
def decode_server(self, clientid, msgin, receivedPacket, receivedAck, nextSentPacket=0):
2020-07-20 19:56:58 +00:00
"""
2020-07-27 20:17:48 +00:00
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1312 void CNetworkConnection::receiveNormalMessage(CBitMemStream &msgin)
khanat-opennel-code/code/ryzom/client/src/impulse_decoder.cpp:38 void CImpulseDecoder::decode(CBitMemStream &inbox, TPacketNumber receivedPacket, TPacketNumber receivedAck, TPacketNumber nextSentPacket, vector<CLFECOMMON::CAction *> &actions)
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1512 void CNetworkConnection::decodeVisualProperties( CBitMemStream& msgin )
2020-07-20 19:56:58 +00:00
"""
2019-10-24 17:45:24 +00:00
actions = []
for level in range(0, 3):
if level == 0:
lAck = self.client_state[clientid]['LastAck0']
channel = 0
elif level == 1:
lAck = self.client_state[clientid]['LastAck1']
channel = receivedPacket & 1
elif level == 2:
lAck = self.client_state[clientid]['LastAck2']
channel = receivedPacket & 3
keep = True
checkOnce = False
num = 0
#logging.getLogger(LOGGER).debug("level:%d channel:%d lAck:%s" %(level, channel, ':'.join([str(x) for x in lAck])))
# lastAck = lAck[channel]
while True:
next = msgin.readBool('next:' + str(level) + ':' + str(channel))
if not next:
break
if not checkOnce:
checkOnce = True
keep = receivedAck >= lAck[channel]
logging.getLogger(LOGGER).debug("keep:%s [%d => %d]" % (str(keep), receivedAck, lAck[channel]))
if keep:
lAck[channel] = nextSentPacket
logging.getLogger(LOGGER).debug("lAck:%s" % ':'.join([str(x) for x in lAck]))
pass
num += 1
#actionFactory = CAction.CActionFactory(None)
2020-07-27 20:17:48 +00:00
logging.getLogger(LOGGER).debug("[decode_server] (%s)" % (msgin.showAllData()))
try:
action = self.actionFactory.unpack(msgin)
except Exception as e:
logging.getLogger(LOGGER).debug("[decode_server] (%s)" % (msgin.showAllData()))
raise e
2019-10-24 17:45:24 +00:00
logging.getLogger(LOGGER).debug("action:%s" % action)
#action = self._CActionFactory.unpack(msgin)
if keep:
logging.getLogger(LOGGER).debug("keep Code:%s" % str(action.Code))
actions.append(action)
elif action:
logging.getLogger(LOGGER).debug("append Code:%s" % str(action.Code))
self.add_registered_action(clientid, action)
2020-07-27 20:17:48 +00:00
# khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:1512 void CNetworkConnection::decodeVisualProperties( CBitMemStream& msgin )
properties, notices = self.decodeVisualProperties(clientid, msgin)
return actions, properties, notices
2019-10-24 17:45:24 +00:00
def decode_client_send_normal_message(self, msgin, clientid, dst, sequenceid, name, Reference):
'''
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:2029 void CNetworkConnection::sendNormalMessage()
khanat-opennel-code/code/ryzom/common/src/game_share/action_block.cpp:36 void CActionBlock::serial(CBitMemStream &msg)
'''
#actions = self.client_state[clientid]['CImpulseDecoder'].decode(msgin, self.client_state[clientid]['CurrentReceivedNumber'], self.client_state[clientid]['LastReceivedAck'], self.client_state[clientid]['CurrentSendNumber'] )
actions = []
impulses = []
noerror = True
msgin.disable_LogErrorOnStreamOverflow()
while noerror:
try:
cycle = msgin.readUint32("Cycle")
num = msgin.readUint8("num")
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[Client -> Server] Cycle:%u num:%u" % (cycle, num))
for i in range(0, num):
actions.append(self.client_state[clientid]['CActionFactory'].unpack(msgin, Reference, name))
pass
except BitStream.OverflowError:
noerror = False
2020-05-08 13:49:07 +00:00
except RuntimeError:
noerror = False
except TypeError as e:
logging.getLogger(LOGGER).debug("[Client -> Server] Impossible to decode %s (not read:%u, msg:%s)" % (e.__class__, msgin.needRead(), msgin.showAllData()))
#raise e
except Exception as e:
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[Client -> Server] end %s (not read:%u)" % (e.__class__, msgin.needRead()))
raise e
msgin.enable_LogErrorOnStreamOverflow()
ids = 0
for action in actions:
try:
impulse = action.decodeImpulseSimple(
self.decodeImpulseSimple,
self.client_state[clientid]['world'],
self.client_state[clientid]['GenericMultiPartTempClient'],
Reference = name
) #, Reference = Parent, Name = "%s_%d" % (target, 0))
if impulse:
impulses.append(impulse)
2020-05-08 13:49:07 +00:00
except BitStream.OverflowError as e:
logging.getLogger(LOGGER).debug("[Client -> Server] error:%s : %s"% (e.__class__, msgin.showAllData()))
except AttributeError as e:
logging.getLogger(LOGGER).debug("[Client -> Server] error:%s : %s"% (e.__class__, msgin.showAllData()))
#raise "Bad message"
except Impulse.ImpulseNoElement:
pass
ids += 1
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[Client -> Server] detail actions [%d] => %s" % ( len(actions), ', '.join([str(x) for x in actions])))
# decodeVisualProperties( msgin );
return actions, impulses
2019-10-24 17:45:24 +00:00
def decode_client_message(self, msgin, clientid, dst, sequenceid, name, Parent, Source):
2020-12-01 21:57:45 +00:00
importantinfo = {}
target = "%s_%s" % (Source, Parent[7:])
2019-10-24 17:45:24 +00:00
CurrentReceivedNumber = msgin.readSint32('CurrentReceivedNumber')
SystemMode = msgin.readBool('SystemMode')
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[Client -> Server] {CurrentReceivedNumber:%d, SystemMode:%d, src:%s, dst:%s}" % (CurrentReceivedNumber, SystemMode, clientid, dst))
2019-10-24 17:45:24 +00:00
self.initialize_client(clientid)
self.client_state[clientid]['CurrentReceivedNumber'] = CurrentReceivedNumber
actions = []
impulses = []
2020-07-20 19:56:58 +00:00
databases = []
2019-10-24 17:45:24 +00:00
if not SystemMode:
2019-11-03 12:42:13 +00:00
'''
khanat-opennel-code/code/ryzom/client/src/network_connection.cpp:2029 void CNetworkConnection::sendNormalMessage()
'''
2019-10-24 17:45:24 +00:00
LastReceivedAck = msgin.readSint32('LastReceivedAck')
self.client_state[clientid]['LastReceivedAck'] = LastReceivedAck
2019-11-03 12:42:13 +00:00
AckBitMask = msgin.readUint32('AckBitMask')
self.client_state[clientid]['AckBitMask'] = AckBitMask
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).info("[Client -> Server] Normal Mode {CurrentReceivedNumber:%d, src:%s, dst:%s, LastReceivedAck:%d}" % (CurrentReceivedNumber, clientid, dst, LastReceivedAck))
# self.decode_server(msgin, _CurrentReceivedNumber, _CurrentReceivedNumber-1)
actions, impulses = self.decode_client_send_normal_message(msgin, clientid, dst, sequenceid, "%s_%d" % (target, 0), Parent)
2019-10-24 17:45:24 +00:00
else:
message = msgin.readUint8('message')
try:
typeMessage = Enum.CLFECOMMON(message).name
except ValueError:
typeMessage = "Unknown"
if message == Enum.CLFECOMMON.SYSTEM_LOGIN_CODE:
UserAddr = msgin.readUint32('UserAddr')
UserKey = msgin.readUint32('UserKey')
UserId = msgin.readUint32('UserId')
LanguageCode = msgin.readString('LanguageCode')
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).info("[Client -> Server] System Mode:%s {CurrentReceivedNumber:%d, src:%s, dst:%s, UserAddr:%d, UserId:%d, UserAddr:%d LanguageCode:%s}" %
2019-10-24 17:45:24 +00:00
(typeMessage, CurrentReceivedNumber, clientid, dst, UserAddr, UserKey, UserId, LanguageCode))
action = CAction.CActionFake('SYSTEM_LOGIN_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
2019-10-24 17:45:24 +00:00
elif message == Enum.CLFECOMMON.SYSTEM_PROBE_CODE:
LatestProbe = msgin.readSint32('LatestProbe')
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).info("[Client -> Server] System Mode:%s probe:%d {CurrentReceivedNumber:%d, src:%s, dst:%s}" % (typeMessage,
2019-10-24 17:45:24 +00:00
LatestProbe, CurrentReceivedNumber, clientid, dst))
action = CAction.CActionFake('SYSTEM_PROBE_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
2019-10-24 17:45:24 +00:00
elif message == Enum.CLFECOMMON.SYSTEM_SYNC_CODE:
Synchronize = msgin.readUint32('Synchronize')
stime = msgin.readSint64('stime')
LatestSync = msgin.readUint32('LatestSync')
MsgData = msgin.readArrayUint8(16, 'MsgData')
md5Msg = bytes(MsgData)
DatabaseData = msgin.readArrayUint8(16, 'DatabaseData')
md5Database = bytes(DatabaseData)
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).info("[Client -> Server] System Mode:%s {CurrentReceivedNumber:%d, src:%s, dst:%s, Synchronize:%d, stime:%d, LatestSync:%d, MsgData:%s, DatabaseData:%s}" % (
2019-10-24 17:45:24 +00:00
typeMessage, CurrentReceivedNumber, clientid, dst, Synchronize, stime, LatestSync, binascii.hexlify(md5Msg).decode(), binascii.hexlify(md5Database).decode()))
action = CAction.CActionFake('SYSTEM_SYNC_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
2019-10-24 17:45:24 +00:00
elif message == Enum.CLFECOMMON.SYSTEM_ACK_SYNC_CODE:
LastReceivedNumber = msgin.readSint32('LastReceivedNumber')
LastAckInLongAck = msgin.readSint32('LastAckInLongAck')
LongAckBitField = CBitSet.CBitSet()
LongAckBitField.readSerial(msgin, 'LongAckBitField')
LatestSync = msgin.readSint32('LatestSync')
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).info("[Client -> Server] System Mode:%s {CurrentReceivedNumber:%d, src:%s, dst:%s, LastReceivedNumber:%d, LastAckInLongAck:%d, LatestSync:%d, LongAckBitField:%s}" % (
2019-10-24 17:45:24 +00:00
typeMessage, CurrentReceivedNumber, clientid, dst, LastReceivedNumber, LastAckInLongAck, LatestSync, LongAckBitField))
action = CAction.CActionFake('SYSTEM_ACK_SYNC_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
2019-10-24 17:45:24 +00:00
elif message == Enum.CLFECOMMON.SYSTEM_ACK_PROBE_CODE:
SizeLatestProbes = msgin.readSint32('SizeLatestProbes')
LatestProbes = []
for data in range(0, SizeLatestProbes):
LatestProbes.append(msgin.readSint32('LatestProbes'))
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).info("[Client -> Server] System Mode:%s (%d) {CurrentReceivedNumber:%d, src:%s, dst:%s, SizeLatestProbes:%d, LatestProbes:%s}" % (typeMessage, message, CurrentReceivedNumber, clientid, dst, SizeLatestProbes, str(LatestProbes)))
action = CAction.CActionFake('SYSTEM_ACK_PROBE_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
2019-10-24 17:45:24 +00:00
else:
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).info("[Client -> Server] System Mode:%s (%d) {CurrentReceivedNumber:%d, src:%s, dst:%s}" % (typeMessage, message, CurrentReceivedNumber, clientid, dst))
logging.getLogger(LOGGER).debug("[Client -> Server] msg:%s" % msgin.showAllData())
2020-12-01 21:57:45 +00:00
return actions, impulses, databases, importantinfo
2019-10-24 17:45:24 +00:00
def decode_khanat_message(self, msgin, src, dst, sequenceid, clientname, Parent, Source):
target = "%s_%s" % (Source, Parent[7:])
actions = []
2020-07-27 20:17:48 +00:00
properties = []
impulses = []
2020-07-20 19:56:58 +00:00
databases = []
notices = {}
2019-10-24 17:45:24 +00:00
CurrentSendNumber = msgin.readSint32('CurrentSendNumber')
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[Server -> Client] {CurrentSendNumber:%d, src:%s, dst:%s}" % (CurrentSendNumber, src, dst))
2019-10-24 17:45:24 +00:00
SystemMode = msgin.readBool('SystemMode')
self.initialize_client(dst)
self.client_state[dst]['CurrentSendNumber'] = CurrentSendNumber
id = 0
2019-10-24 17:45:24 +00:00
if not SystemMode:
_LastReceivedAck = msgin.readSint32('LastReceivedAck');
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[Server -> Client] Normal Mode {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d}" % (CurrentSendNumber, src, dst, _LastReceivedAck))
actions, properties, notices = self.decode_server(dst, msgin, CurrentSendNumber, CurrentSendNumber-1)
2019-10-24 17:45:24 +00:00
if actions:
logging.getLogger(LOGGER).debug('list actions: [' + str(len(actions)) + '] ' +','.join( [ str(x) for x in actions] ) )
else:
logging.getLogger(LOGGER).debug('list actions: None')
# Decode the actions received in the impulsions
logging.getLogger(LOGGER).debug('=' * 80)
actionsbis = []
2020-11-28 17:20:23 +00:00
logging.getLogger(LOGGER).debug("size[actions] %d" % len(actions))
2019-10-24 17:45:24 +00:00
for action in actions:
referenceBis = "%s_%d" % (target, id)
action.add_reference(Parent)
action.set_name(referenceBis)
2019-10-24 17:45:24 +00:00
logging.getLogger(LOGGER).debug('-' * 80)
logging.getLogger(LOGGER).debug('Analyse actions:%s', action)
2020-11-28 17:20:23 +00:00
logging.getLogger(LOGGER).debug("size[actions] %d" % len(actions))
2019-10-24 17:45:24 +00:00
if action.Code == Enum.TActionCode.ACTION_DISCONNECTION_CODE:
#action.add_reference(Parent)
2020-11-28 17:20:23 +00:00
logging.getLogger(LOGGER).debug("Action : ACTION_DISCONNECTION_CODE")
actionsbis.append(CAction.CActionFake('ACTION_DISCONNECTION_CODE', self.client_state[dst]['GenericMultiPartTempServer'].data[id].read())) # , Reference = Parent, Name = "%s_%d" % (target, 0)
2019-10-24 17:45:24 +00:00
elif action.Code == Enum.TActionCode.ACTION_GENERIC_CODE:
#action.add_reference(Parent)
#action.genericAction(self.decodeImpulse, self.client_state[dst]['world'], self.client_state[dst]['GenericMultiPartTempServer']) #, Reference = Parent, Name = "%s_%d" % (target, 0))
try:
impulse = action.decodeImpulseSimple(
self.decodeImpulseSimple,
self.client_state[dst]['world'],
self.client_state[dst]['GenericMultiPartTempServer'],
Reference = [Parent, ],
Name = "%s_%d" % (target, 0)
) #, Reference = Parent, Name = "%s_%d" % (target, 0))
2020-11-28 17:20:23 +00:00
#logging.getLogger(LOGGER).info("impulse:%s" % str(impulse))
if impulse:
2020-11-25 19:57:28 +00:00
logging.getLogger(LOGGER).debug("type impulse:%s" % str(type(impulse)))
2020-07-20 19:56:58 +00:00
database = None
#database = impulse.readDatabases(self.client_state[dst]['world'], self.decodeDatabase)
if database:
databases.append(database)
impulses.append(impulse)
except Impulse.ImpulseNoElement:
pass
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).info("[Server -> Client] ACTION_GENERIC_CODE : {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d, action:%s}" % (CurrentSendNumber, src, dst, _LastReceivedAck, action))
2019-10-24 17:45:24 +00:00
elif action.Code == Enum.TActionCode.ACTION_GENERIC_MULTI_PART_CODE:
#action.genericAction(self.decodeImpulse, self.client_state[dst]['world'], self.client_state[dst]['GenericMultiPartTempServer'], Reference = referenceBis) #, Reference = Parent, Name = "%s_%d" % (target, 0))
try:
2020-07-20 19:56:58 +00:00
logging.getLogger(LOGGER).debug("[Server -> Client] ACTION_GENERIC_MULTI_PART_CODE : %s OKKKKKKKK " % action)
impulse = action.decodeImpulseSimple(
self.decodeImpulseSimple,
self.client_state[dst]['world'],
self.client_state[dst]['GenericMultiPartTempServer'],
Reference = Parent,
Name = "%s_%d" % (target, 0)
) #, Reference = Parent, Name = "%s_%d" % (target, 0))
2020-11-28 17:20:23 +00:00
logging.getLogger(LOGGER).debug("impulse:%s" % str(impulse))
if impulse:
2020-11-25 19:57:28 +00:00
logging.getLogger(LOGGER).debug("type impulse:%s" % str(type(impulse)))
impulses.append(impulse)
except Impulse.ImpulseNoElement:
pass
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[Server -> Client] ACTION_GENERIC_MULTI_PART_CODE : %s" % action)
for id in self.client_state[dst]['GenericMultiPartTempServer'].data:
logging.getLogger(LOGGER).info("[Server -> Client] ACTION_GENERIC_MULTI_PART_CODE {id:%d, available:%s NbBlock:%d/%d, isDecoded:%s, FirstRead:%s}" % (
id,
self.client_state[dst]['GenericMultiPartTempServer'].data[id].isAvailable(),
self.client_state[dst]['GenericMultiPartTempServer'].data[id].getNbCurrentBlock(),
self.client_state[dst]['GenericMultiPartTempServer'].data[id].NbBlock,
self.client_state[dst]['GenericMultiPartTempServer'].data[id].isDecoded(),
self.client_state[dst]['GenericMultiPartTempServer'].data[id].FirstRead
))
if self.client_state[dst]['GenericMultiPartTempServer'].data[id].isAvailable():
logging.getLogger(LOGGER).info("[Server -> Client] ACTION_GENERIC_MULTI_PART_CODE {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d, id:%d, msg:%s}" % (
CurrentSendNumber, src, dst, _LastReceivedAck, id,
self.client_state[dst]['GenericMultiPartTempServer'].data[id].read().showAllData()))
2020-07-20 19:56:58 +00:00
## temp = CAction.CActionFake('ACTION_GENERIC_MULTI_PART_CODE',
## self.client_state[dst]['GenericMultiPartTempServer'].data[id].read(),
## # {'coucou': ', '.join(self.client_state[dst]['GenericMultiPartTemp'].data[id].Reference)},
## # Reference = self.client_state[dst]['GenericMultiPartTemp'].data[id].Reference,
## Name = "impulse_%s_%s" % (Parent[7:], 0)
## )
## temp.Reference = self.client_state[dst]['GenericMultiPartTempServer'].data[id].Reference
## #actionsbis.append(temp)
msg = self.client_state[dst]['GenericMultiPartTempServer'].data[id].MsgDecoded
msg.reset_read()
# #print("------->", msg.needRead(), "/", msg.sizeData())
# #print("------>", type(self.client_state[dst]['GenericMultiPartTempServer'].data[id]))
action = CAction.CActionFake('ACTION_GENERIC_MULTI_PART_CODE',
msg,
# {'coucou': ', '.join(self.client_state[dst]['GenericMultiPartTemp'].data[id].Reference)},
2020-07-20 19:56:58 +00:00
Reference = self.client_state[dst]['GenericMultiPartTempServer'].data[id].Reference,
Name = "impulse_%s_%s" % (Parent[7:], 0)
)
2020-07-20 19:56:58 +00:00
try:
impulse = action.decodeImpulseSimple(
self.decodeImpulseSimple,
self.client_state[dst]['world'],
self.client_state[dst]['GenericMultiPartTempServer'],
Reference = self.client_state[dst]['GenericMultiPartTempServer'].data[id].Reference,
Name = "%s_%d" % (target, 0)
) #, Reference = Parent, Name = "%s_%d" % (target, 0))
if impulse:
2020-11-25 19:57:28 +00:00
logging.getLogger(LOGGER).debug("type impulse:%s" % str(type(impulse)))
2020-07-20 19:56:58 +00:00
impulses.append(impulse)
except Impulse.ImpulseNoElement:
pass
actionsbis.append(action)
# try:
# impulse = {"Type": "CActionFake.ACTION_GENERIC_MULTI_PART_CODE"}
# impulse["state"] = "message partially decoded"
# tmp = self.decodeImpulseSimple.execute(msg, self.client_state[dst]['world'])
# print("-"*80)
# print(tmp)
# print("-"*80)
# impulse['Message'] = msg.extractAllData()
# impulse['Reference'] = self.client_state[dst]['GenericMultiPartTempServer'].data[id].Reference
# impulse['Name'] = "Impulse_%s_%d" % (target, 0)
## impulse = action.decodeImpulseSimple(
## self.decodeImpulseSimple,
## self.client_state[dst]['world'],
## self.client_state[dst]['GenericMultiPartTempServer'],
## Reference = Parent,
## Name = "%s_%d" % (target, 0)
## ) #, Reference = Parent, Name = "%s_%d" % (target, 0))
# print("-"*80)
# logging.getLogger(LOGGER).info("impulse:%s" % str(impulse))
# if impulse:
# print("spykhanat.py:473", type(impulse))
# impulses.append(impulse)
# except Impulse.ImpulseNoElement:
# pass
# print(impulses)
#raise "quoi"
else:
logging.getLogger(LOGGER).info("[Server -> Client] ACTION_GENERIC_MULTI_PART_CODE {CurrentSendNumber:%d, src:%s, dst:%s, _LastReceivedAck:%d, id:%d}" % (
CurrentSendNumber, src, dst, _LastReceivedAck, id))
2019-10-24 17:45:24 +00:00
elif action.Code == Enum.TActionCode.ACTION_DUMMY_CODE:
#action.add_reference(Parent)
2019-10-24 17:45:24 +00:00
logging.getLogger(LOGGER).info("Action : ACTION_DUMMY_CODE")
actionsbis.append(CAction.CActionFake('ACTION_DUMMY_CODE', self.client_state[dst]['GenericMultiPartTempServer'].data[id].read(), Reference=Parent, Name = "%s_%d" % (target, 0)))
2019-10-24 17:45:24 +00:00
self.add_registered_action(dst, action)
id += 1
2019-10-24 17:45:24 +00:00
# # remove all old actions that are acked
# while self._Actions and self._Actions[0].FirstPacket != 0 and self._Actions[0].FirstPacket < self._LastReceivedAck:
# logging.getLogger(LOGGER).debug("remove old action [%d/%d] : %s" % (self._Actions[0].FirstPacket, self._LastReceivedAck, self._Actions[0]))
# self._Actions.pop(0)
2020-11-28 17:20:23 +00:00
logging.getLogger(LOGGER).debug("size[actions] %d" % len(actions))
for action in actionsbis:
actions.append(action)
2020-11-28 17:20:23 +00:00
logging.getLogger(LOGGER).debug("impulses:%s" % str(impulses))
2019-10-24 17:45:24 +00:00
else:
message = msgin.readUint8('message')
#referenceBis = "%s_%d" % (Parent, id)
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[Server -> Client] System Mode {CurrentSendNumber:%d, src:%s, dst:%s, message:%d" % (CurrentSendNumber, src, dst, message))
2019-10-24 17:45:24 +00:00
if message == Enum.CLFECOMMON.SYSTEM_SYNC_CODE:
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[Server -> Client] Synchronize")
2019-10-24 17:45:24 +00:00
Synchronize = msgin.readUint32('Synchronize')
stime = msgin.readSint64('stime')
LatestSync = msgin.readUint32('LatestSync')
MsgData = msgin.readArrayUint8(16, 'MsgData')
DatabaseData = msgin.readArrayUint8(16, 'DatabaseData')
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).info("[Server -> Client] System Mode / Synchronize {CurrentSendNumber:%d, src:%s, dst:%s, message:%d, Synchronize:%d, stime:%d, LatestSync:%d, MsgData:%s, DatabaseData:%s}" % (CurrentSendNumber, src, dst, message, Synchronize, stime, LatestSync, str(MsgData), str(DatabaseData)))
action = CAction.CActionFake('SYSTEM_SYNC_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
2019-10-24 17:45:24 +00:00
elif message == Enum.CLFECOMMON.SYSTEM_STALLED_CODE:
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[Server -> Client] Stalled")
logging.getLogger(LOGGER).info("[Server -> Client] System Mode / Stalled {CurrentSendNumber:%d, src:%s, dst:%s, message:%d}" % (CurrentSendNumber, src, dst, message))
action = CAction.CActionFake('SYSTEM_STALLED_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
2019-10-24 17:45:24 +00:00
elif message == Enum.CLFECOMMON.SYSTEM_PROBE_CODE:
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[Server -> Client] Probe")
2019-10-24 17:45:24 +00:00
LatestProbe = msgin.readSint32('LatestProbe')
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).info("[Server -> Client] System Mode / Probe {CurrentSendNumber:%d, src:%s, dst:%s, message:%d, LatestProbe:%d}" % (CurrentSendNumber, src, dst, message, LatestProbe))
action = CAction.CActionFake('SYSTEM_PROBE_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
2019-10-24 17:45:24 +00:00
elif message == Enum.CLFECOMMON.SYSTEM_SERVER_DOWN_CODE:
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).info("[Server -> Client] System Mode / BACK-END DOWN {CurrentSendNumber:%d, src:%s, dst:%s, message:%d}" % (CurrentSendNumber, src, dst, message))
action = CAction.CActionFake('SYSTEM_SERVER_DOWN_CODE', msgin, Reference=Parent, Name = "%s_%d" % (target, 0))
actions.append(action)
2019-10-24 17:45:24 +00:00
else:
logging.getLogger(LOGGER).warning("CNET: received system %d in state Login" % message)
#cActionFactory = CAction.CActionFactory(None)
#cActionFactory.unpack(msgin)
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[Server -> Client] msg:%s" % msgin.showAllData())
#logging.getLogger(LOGGER).info("impulses:%s" % str(impulses))
return actions, impulses, databases, properties, notices
2019-10-24 17:45:24 +00:00
def read(self):
2020-11-28 17:20:23 +00:00
logging.getLogger(LOGGER).info("Conversion => Start")
fullconverted = True
2019-10-24 17:45:24 +00:00
file = open( self.pcap_file , 'rb')
pcapfile = savefile.load_savefile(file,verbose=False)
khanat_host = self.detect_khanat_server(pcapfile.packets)
2019-11-06 20:36:42 +00:00
clientid = 1
serverid = 1
list_host = {}
sequenceid = 1
sequencenum = 1
if self.outyaml:
self.outyaml.write("# Generated : %s\n\n" % (datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
if self.outcsv:
self.outcsv.write("Date,Packet Id,Source,Destination,Key,Value\n")
2019-10-24 17:45:24 +00:00
for pkt in pcapfile.packets:
eth_frame = ethernet.Ethernet(pkt.raw())
if eth_frame.type == 2048:
ip_packet = ip.IP(binascii.unhexlify(eth_frame.payload))
if ip_packet.p == 17:
# UDP
udp_packet = udp.UDP(binascii.unhexlify(ip_packet.payload))
data = udp_packet.payload
if udp_packet.src_port == 53 or udp_packet.dst_port == 53:
continue
if udp_packet.src_port == 5353 and ip_packet.src.decode() == "224.0.0.251":
continue
if udp_packet.dst_port == 5353 and ip_packet.dst.decode() == "224.0.0.251":
continue
2019-10-24 17:45:24 +00:00
if not self.filter_host_service or self.filter_host_service.match("%s:%d" % (ip_packet.src.decode(), udp_packet.src_port)) or self.filter_host_service.match("%s:%d" % (ip_packet.dst.decode(), udp_packet.dst_port)):
Reference = "packet_%d" % sequenceid
2019-10-24 17:45:24 +00:00
logging.getLogger(LOGGER).debug("-" * 80)
actions_clients = []
actions_servers = []
2020-07-20 19:56:58 +00:00
impulses_servers = []
impulses_clients = []
2020-07-27 20:17:48 +00:00
properties_servers = []
2019-10-24 17:45:24 +00:00
if self.show_raw_packet:
2019-11-03 12:42:13 +00:00
logging.getLogger(LOGGER).debug("[raw packet] timestamp:%s [%s] src:%s:%d dst:%s:%d data:%s" % (pkt.timestamp,
datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"),
2019-10-24 17:45:24 +00:00
ip_packet.src.decode(), udp_packet.src_port,
ip_packet.dst.decode(), udp_packet.dst_port,
data.decode()))
msgin = BitStream.BitStream()
msgin.fromBytes(binascii.unhexlify(data))
src = "%s:%d" % (ip_packet.src.decode(), udp_packet.src_port)
dst = "%s:%d" % (ip_packet.dst.decode(), udp_packet.dst_port)
2019-11-03 12:42:13 +00:00
2019-10-24 17:45:24 +00:00
if (self.khanat_host_service and self.khanat_host_service.match(src)) or ( not self.khanat_host_service and khanat_host == src):
2019-11-06 20:36:42 +00:00
if src not in list_host:
2019-11-06 21:33:35 +00:00
name = "Server%d" % serverid
list_host.setdefault(src, name)
2019-11-06 20:36:42 +00:00
serverid += 1
2019-10-24 17:45:24 +00:00
else:
2019-11-06 20:36:42 +00:00
if src not in list_host:
2019-11-06 21:33:35 +00:00
name = "Client%d" % clientid
list_host.setdefault(src, name)
clientid += 1
if (self.khanat_host_service and self.khanat_host_service.match(dst)) or ( not self.khanat_host_service and khanat_host == dst):
if dst not in list_host:
name = "Server%d" % serverid
list_host.setdefault(dst, name)
serverid += 1
else:
if dst not in list_host:
name = "Client%d" % clientid
list_host.setdefault(dst, name)
2019-11-06 20:36:42 +00:00
clientid += 1
2019-11-06 21:33:35 +00:00
if (self.khanat_host_service and self.khanat_host_service.match(src)) or ( not self.khanat_host_service and khanat_host == src):
_provenance = 'Server -> Client'
logging.getLogger(LOGGER).debug("[%s] (message received) [%s] %s" % (_provenance, datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), msgin.showAllData()))
actions_servers, impulses_servers, databases_servers, properties_servers, notices = self.decode_khanat_message(msgin, src, dst, sequenceid, list_host[dst], Reference, list_host[src])
2019-11-06 21:33:35 +00:00
else:
_provenance = 'Client -> Server'
2019-11-03 12:42:13 +00:00
logging.getLogger(LOGGER).debug("[%s] (message received) [%s] %s" % (_provenance, datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), msgin.showAllData()))
actions_clients, impulses_clients, databases_clients, notices = self.decode_client_message(msgin, src, dst, sequenceid, list_host[dst], Reference, list_host[src])
2019-11-06 20:36:42 +00:00
if not msgin.checkOnlyZeroAtEnd(): # msgin.needRead() > 7:
moredata = "message partially decoded"
2020-11-28 17:20:23 +00:00
fullconverted = False
else:
moredata = 'message decoded'
2019-10-24 17:45:24 +00:00
if self.show_message_decoded:
2019-11-06 20:36:42 +00:00
logging.getLogger(LOGGER).debug("[%s] (%s) %s" % (_provenance, moredata, msgin.showAllData()))
if notices:
2020-12-01 21:57:45 +00:00
havedata = True
else:
havedata = False
if not havedata:
for action in actions_servers:
if action.get_notice():
havedata = True
break
if not havedata:
for action in actions_clients:
if action.get_notice():
havedata = True
break
2020-12-01 21:57:45 +00:00
if not havedata:
for impulse_data in impulses_servers:
if impulse_data.get_notice():
havedata = True
break
if not havedata:
for impulse_data in impulses_clients:
if impulse_data.get_notice():
havedata = True
break
2020-12-01 21:57:45 +00:00
if havedata:
print(datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), "[", Reference, "]", list_host[src], "->", list_host[dst])
for key in notices:
print(" " * 3, key, ":", notices[key])
for action in actions_servers:
data = action.get_notice()
for key in data:
print(" " * 3, key, ":", data[key])
for action in actions_clients:
data = action.get_notice()
for key in data:
print(" " * 3, key, ":", data[key])
for impulse_data in impulses_servers:
data = impulse_data.get_notice()
for key in data:
print(" " * 3, key, ":", data[key])
for impulse_data in impulses_clients:
data = impulse_data.get_notice()
for key in data:
print(" " * 3, key, ":", data[key])
print("")
if self.outcsv:
for key in notices:
self.outcsv.write("%s,%s,%s,%s,%s,%s\n" % (datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), Reference, list_host[src], list_host[dst], key, notices[key]))
for action in actions_servers:
data = action.get_notice()
for key in data:
self.outcsv.write("%s,%s,%s,%s,%s,%s\n" % (datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), Reference, list_host[src], list_host[dst], key, data[key]))
for action in actions_clients:
data = action.get_notice()
for key in data:
self.outcsv.write("%s,%s,%s,%s,%s,%s\n" % (datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), Reference, list_host[src], list_host[dst], key, data[key]))
2020-12-01 21:57:45 +00:00
for impulse_data in impulses_servers:
data = impulse_data.get_notice()
for key in data:
self.outcsv.write("%s,%s,%s,%s,%s,%s\n" % (datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), Reference, list_host[src], list_host[dst], key, data[key]))
for impulse_data in impulses_clients:
data = impulse_data.get_notice()
for key in data:
self.outcsv.write("%s,%s,%s,%s,%s,%s\n" % (datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"), Reference, list_host[src], list_host[dst], key, data[key]))
2020-12-01 21:57:45 +00:00
2019-11-06 20:36:42 +00:00
if self.outyaml:
self.outyaml.write("\n%s:\n sequence: %d\n time: %s\n source: %s\n destination: %s\n function: %s\n adress_source: %s\n adress_destination: %s\n state: %s\n message:\n" % (
Reference,
sequencenum,
2019-11-06 20:36:42 +00:00
datetime.fromtimestamp(pkt.timestamp).strftime("%Y/%m/%d %H:%M:%S"),
list_host[src],
2019-11-06 21:33:35 +00:00
list_host[dst],
_provenance,
2019-11-06 20:36:42 +00:00
src,
dst,
moredata
))
for key in msgin.extractAllData():
self.outyaml.write(" - %s\n" % key)
if actions_servers:
self.outyaml.write("\nblock_%s_%d:\n" %(list_host[src], sequenceid))
id = 0
for action in actions_servers:
params = action.get_parameter()
self.outyaml.write(" %s:\n" % (action.get_name()))
# if "parent" in params:
# self.outyaml.write(" parent: %s\n" % (params['parent']))
# elif "Reference" in params:
# #self.outyaml.write(" parents: %s\n" % (', '.join(params['Reference'])))
# self.outyaml.write(" parents:\n")
# for key in params['Reference']:
# self.outyaml.write(" - %s\n" % (key))
# else:
# self.outyaml.write(" parent: udp_%s\n" % (sequenceid))
self.outyaml.write(" receivedby: client\n")
self.outyaml.write(" sequence: %s\n" % (sequencenum))
self.outyaml.write(" source: %s\n" % (list_host[src]))
self.outyaml.write(" destination: %s\n" % (list_host[dst]))
for key in params:
if key == 'Message':
self.outyaml.write(" %s:\n" % (key))
for key2 in params[key]:
self.outyaml.write(" - %s\n" % key2)
elif key == "Reference":
self.outyaml.write(" parents:\n")
for key in params['Reference']:
self.outyaml.write(" - %s\n" % (key))
#elif key != 'parent':
else:
self.outyaml.write(" %s: %s\n" % (key, params[key]))
#self.outyaml.write(" %s: %s\n" % (key, params[key]))
id += 1
2020-07-20 19:56:58 +00:00
# if databases_servers:
# self.outyaml.write("\ndatabaseserver_%s_%d:\n" %(list_host[src], sequenceid))
# id = 0
# for databases in databases_servers:
# params = impulse_data.get_parameter()
# self.outyaml.write(" %s:\n" % (impulse_data.get_name()))
# for key in params:
# if key == 'Message':
# self.outyaml.write(" %s:\n" % (key))
# for key2 in params[key]:
# self.outyaml.write(" - %s\n" % key2)
# elif key == "Reference":
# self.outyaml.write(" parents:\n")
# for key in params['Reference']:
# self.outyaml.write(" - %s\n" % (key))
# #elif key != 'parent':
# else:
# self.outyaml.write(" %s: %s\n" % (key, params[key]))
# #self.outyaml.write(" %s: %s\n" % (key, params[key]))
# id += 1
# #print("-"*30)
if impulses_servers:
self.outyaml.write("\nimpulseserver_%s_%d:\n" %(list_host[src], sequenceid))
id = 0
#print("-"*30)
2020-07-20 19:56:58 +00:00
#print(impulses_servers)
2020-12-01 21:57:45 +00:00
#print(impulses_servers)
2020-07-20 19:56:58 +00:00
for impulse_data in impulses_servers:
#print("-"*80)
2020-07-20 19:56:58 +00:00
#print(Impulse)
2020-12-01 21:57:45 +00:00
#print(impulse_data)
2020-07-20 19:56:58 +00:00
params = impulse_data.get_parameter()
self.outyaml.write(" %s:\n" % (impulse_data.get_name()))
for key in params:
if key == 'Message':
self.outyaml.write(" %s:\n" % (key))
for key2 in params[key]:
self.outyaml.write(" - %s\n" % key2)
elif key == "Reference":
self.outyaml.write(" parents:\n")
for key in params['Reference']:
self.outyaml.write(" - %s\n" % (key))
#elif key != 'parent':
else:
self.outyaml.write(" %s: %s\n" % (key, params[key]))
#self.outyaml.write(" %s: %s\n" % (key, params[key]))
id += 1
#print("-"*30)
2020-07-27 20:17:48 +00:00
if properties_servers:
self.outyaml.write("\nvisual_properties_%s_%d:\n" %(list_host[src], sequenceid))
for property in properties_servers:
self.outyaml.write(" slot: %d\n" % (property['slot']))
self.outyaml.write(" parents: %s\n" % Reference)
self.outyaml.write(" associationBits: %d\n" % (property['associationBits']))
self.outyaml.write(" timestamp: %d\n" % (property['timestamp']))
for action in property['Actions']:
try:
action.print_yaml(self.outyaml, " ")
#self.outyaml.write(" %s: %s\n" % (action.get_name(), str(action.get_property())))
2020-07-27 20:17:48 +00:00
except AttributeError:
# TODO - change print if CAtion is Position or other (and not CActionSint64)
params = action.get_parameter()
self.outyaml.write(" %s:\n" % (action.get_name()))
for key in params:
if key == "Reference":
pass
elif key == "GameCycle":
pass
elif key == "Slot":
pass
else:
self.outyaml.write(" %s: %s\n" % (key, params[key]))
2020-07-20 19:56:58 +00:00
if actions_clients:
self.outyaml.write("\nblock_%s_%d:\n" %(list_host[src], sequenceid))
id = 0
for action in actions_clients:
self.outyaml.write(" %s:\n" % (action.get_name()))
self.outyaml.write(" receivedby: server\n")
self.outyaml.write(" sequence: %s\n" % (sequencenum))
self.outyaml.write(" source: %s\n" % (list_host[src]))
self.outyaml.write(" destination: %s\n" % (list_host[dst]))
params = action.get_parameter()
for key in params:
if key == 'Message':
self.outyaml.write(" %s:\n" % (key))
for key2 in params[key]:
self.outyaml.write(" - %s\n" % key2)
elif key == "Reference":
self.outyaml.write(" parents:\n")
for key in params['Reference']:
self.outyaml.write(" - %s\n" % (key))
else:
self.outyaml.write(" %s: %s\n" % (key, params[key]))
#self.outyaml.write(" %s: %s\n" % (key, params[key]))
id += 1
2020-07-20 19:56:58 +00:00
# if impulses_clients:
# self.outyaml.write("\nImpulseclient_%s_%d:\n" %(list_host[src], sequenceid))
# id = 0
2020-07-20 19:56:58 +00:00
# for Impulse in impulses_clients:
# params = Impulse.get_parameter()
# self.outyaml.write(" %s:\n" % (Impulse.get_name()))
# id += 1
2020-07-27 20:17:48 +00:00
#if Reference == 'packet_409':
# raise "STOP"
2019-11-06 20:36:42 +00:00
sequenceid += 1
sequencenum += 1
2019-10-24 17:45:24 +00:00
for client in self.client_state:
logging.getLogger(LOGGER).debug("%s [server tick:%d, client tick:%d]" %(client, self.client_state[client]['CurrentSendNumber'], self.client_state[client]['CurrentReceivedNumber']))
2020-11-28 17:20:23 +00:00
if fullconverted:
logging.getLogger(LOGGER).info("Full converted")
print("\nEnd : Full converted")
2020-11-28 17:20:23 +00:00
else:
logging.getLogger(LOGGER).info("Partially converted")
print("\nEnd : Partially converted")
2020-11-28 17:20:23 +00:00
logging.getLogger(LOGGER).info("Conversion => End")
2019-10-24 17:45:24 +00:00
def main():
FORMAT = '%(asctime)-15s %(levelname)s %(filename)s:%(lineno)d %(message)s'
logging.basicConfig(format=FORMAT)
logger = []
2020-11-28 17:20:23 +00:00
logger.append(logging.getLogger(LOGGER))
# logger.append(logging.getLogger(CImpulseDecoder.LOGGER))
# #logger.append(logging.getLogger(DecodeImpuls.LOGGER))
2020-11-28 17:20:23 +00:00
#logger.append(logging.getLogger(BitStream.LOGGER))
# logger.append(logging.getLogger(CStringManager.LOGGER))
2020-07-27 20:17:48 +00:00
#logger.append(logging.getLogger(CAction.LOGGER))
#logger.append(logging.getLogger(CActionFactory.LOGGER))
2020-11-25 19:57:28 +00:00
#logger.append(logging.getLogger(BitStream.LOGGER))
2020-11-28 17:20:23 +00:00
#logger.append(logging.getLogger(DecodeDatabase.LOGGER))
#logger.append(logging.getLogger(Impulse.LOGGER))
2020-07-27 20:17:48 +00:00
#logger.append(logging.getLogger(TVPNodeBase.LOGGER))
# CImpulseDecoder
2019-10-24 17:45:24 +00:00
# logger.append(logging.getLogger('CGenericMultiPartTemp'))
2020-11-25 19:57:28 +00:00
#logger.append(logging.getLogger(DecodeDatabase.LOGGER))
2019-10-24 17:45:24 +00:00
parser = argparse.ArgumentParser()
parser.add_argument("--khanat-host-service", help="filter to detect khanat host:service (FES)")
parser.add_argument("--filter-host-service", help="filter host:service")
parser.add_argument("-d", "--debug", help="show debug message", action='store_true')
2019-11-06 20:36:42 +00:00
parser.add_argument("-v", "--verbose", help="show verbose message", action='store_true')
2019-10-24 17:45:24 +00:00
parser.add_argument("-p", "--pcap-file", help="file pcap to read", required=True)
parser.add_argument("-m", "--msg-xml", help="file msg.xml (from server khanat)", required=True)
2020-07-20 19:56:58 +00:00
parser.add_argument("-w", "--database-xml", help="file database.xml (from server khanat)", required=True)
2019-10-24 17:45:24 +00:00
parser.add_argument("-r", "--raw", help="show message raw", action='store_true')
2019-11-06 20:36:42 +00:00
parser.add_argument("--yaml", help="generate YAML file (decode all message)", type=argparse.FileType('w'), default=None)
parser.add_argument("--csv", help="generate CSV file (essential message)", type=argparse.FileType('w'), default=None)
2019-10-24 17:45:24 +00:00
parser.add_argument("--show-raw-packet", help="show packet (raw data)", action='store_true')
parser.add_argument("--show-message-decoded", help="show packet (raw data)", action='store_true')
args = parser.parse_args()
if args.debug:
level = logging.getLevelName('DEBUG')
2019-11-06 20:36:42 +00:00
elif args.verbose:
2019-10-24 17:45:24 +00:00
level = logging.getLevelName('INFO')
2019-11-06 20:36:42 +00:00
else:
level = logging.getLevelName('WARNING')
2019-10-24 17:45:24 +00:00
for logid in logger:
logid.setLevel(level)
logging.getLogger(LOGGER).info("Begin")
2019-11-06 20:36:42 +00:00
spy = SpyPcap(khanat_host_service=args.khanat_host_service,
pcap_file=args.pcap_file,
msg_xml=args.msg_xml,
2020-07-20 19:56:58 +00:00
database_xml=args.database_xml,
2019-11-06 20:36:42 +00:00
filter_host_service=args.filter_host_service,
show_raw_packet=args.show_raw_packet,
show_message_decoded=args.show_message_decoded,
outyaml=args.yaml,
outcsv=args.csv)
2019-10-24 17:45:24 +00:00
if args.raw:
spy.readRaw()
else:
spy.read()
logging.getLogger(LOGGER).info("End")
if __name__ == "__main__":
main()