clientbot/spykhanat.py

737 lines
45 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
# 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
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
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():
2019-11-06 20:36:42 +00:00
def __init__(self, khanat_host_service, pcap_file, msg_xml, filter_host_service, show_raw_packet, show_message_decoded, outyaml=None):
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 = {}
self.decodeImpulse = DecodeImpulse.DecodeImpulse()
self.decodeImpulseSimple = Impulse.DecodeImpulseSimple()
2019-10-24 17:45:24 +00:00
fp = open(msg_xml , 'rt')
msgRawXml = fp.read()
self.msgXml = ET.fromstring(msgRawXml)
self.decodeImpulse.loadMsg(self.msgXml)
self.decodeImpulseSimple.loadMsg(self.msgXml)
2019-11-06 20:36:42 +00:00
self.outyaml = outyaml
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:
print("pkt:", dir(pkt))
print("pkt.header:", dir(pkt.header))
print("pkt.packet:", dir(pkt.packet))
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)
print("ip_packet:", dir(ip_packet))
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))
print("udp_packet:", dir(udp_packet))
logging.getLogger(LOGGER).debug("UDP packet: %s" % udp_packet)
data = udp_packet.payload
print("data:", dir(data))
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)
def decode_server(self, clientid, msgin, receivedPacket, receivedAck, nextSentPacket=0):
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)
action = self.actionFactory.unpack(msgin)
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)
return actions
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
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)
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):
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 = []
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, _ = 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())
return actions, impulses
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 = []
impulses = []
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))
2019-10-24 17:45:24 +00:00
actions = self.decode_server(dst, msgin, CurrentSendNumber, CurrentSendNumber-1)
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 = []
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)
if action.Code == Enum.TActionCode.ACTION_DISCONNECTION_CODE:
#action.add_reference(Parent)
2019-10-24 17:45:24 +00:00
logging.getLogger(LOGGER).info("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))
logging.getLogger(LOGGER).info("impulse:%s" % str(impulse))
if impulse:
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:
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))
logging.getLogger(LOGGER).info("impulse:%s" % str(impulse))
if 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()))
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 = "inpulse_%s_%s" % (Parent[7:], 0)
)
temp.Reference = self.client_state[dst]['GenericMultiPartTempServer'].data[id].Reference
actionsbis.append(temp)
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)
for action in actionsbis:
actions.append(action)
logging.getLogger(LOGGER).info("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
2019-10-24 17:45:24 +00:00
def read(self):
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")))
2019-11-06 20:36:42 +00:00
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 = []
inpulses_servers = []
inpulses_clients = []
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, inpulses_servers = 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, inpulses_clients = 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"
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 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
if inpulses_servers:
self.outyaml.write("\ninpulseserver_%s_%d:\n" %(list_host[src], sequenceid))
id = 0
#print("-"*30)
#print(inpulses_servers)
for inpulse in inpulses_servers:
#print("-"*80)
#print(inpulse)
params = inpulse.get_parameter()
self.outyaml.write(" %s:\n" % (inpulse.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 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
# if inpulses_clients:
# self.outyaml.write("\ninpulseclient_%s_%d:\n" %(list_host[src], sequenceid))
# id = 0
# for inpulse in inpulses_clients:
# params = inpulse.get_parameter()
# self.outyaml.write(" %s:\n" % (inpulse.get_name()))
# id += 1
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']))
def main():
FORMAT = '%(asctime)-15s %(levelname)s %(filename)s:%(lineno)d %(message)s'
logging.basicConfig(format=FORMAT)
logger = []
logger.append(logging.getLogger(LOGGER))
# logger.append(logging.getLogger(CImpulseDecoder.LOGGER))
# #logger.append(logging.getLogger(DecodeImpuls.LOGGER))
# #logger.append(logging.getLogger(BitStream.LOGGER))
# logger.append(logging.getLogger(CStringManager.LOGGER))
# logger.append(logging.getLogger(CAction.LOGGER))
# logger.append(logging.getLogger(CActionFactory.LOGGER))
# logger.append(logging.getLogger(BitStream.LOGGER))
logger.append(logging.getLogger(Impulse.LOGGER))
2019-10-24 17:45:24 +00:00
CImpulseDecoder
# logger.append(logging.getLogger('CGenericMultiPartTemp'))
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)
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)
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,
filter_host_service=args.filter_host_service,
show_raw_packet=args.show_raw_packet,
show_message_decoded=args.show_message_decoded,
outyaml=args.yaml)
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()