def handle_uri(id_pb): uri = trackURI print_info('Got uri request for {}, replying with {}', id_pb.id.hex(), uri, color='magenta') return Devialet.AudioSource.Uri(uri=uri)
def CallUnknownMethod(self, serviceId, subTypeId, request, done, typeId=0): print_info('Calling unknown method #{} from service #{} on port {}', subTypeId, serviceId, self.port) reqUUID = uuid.uuid4().bytes cmm_request = Devialet.CallMeMaybe.Request(serverId=self.serverId, serviceId=serviceId, requestId=reqUUID, type=typeId, subTypeId=subTypeId) self.request_queue[reqUUID] = (None, None, DevialetController(self.conn), done if done else self.unblock_call) self.write_rpc(cmm_request.SerializeToString(), request.SerializeToString()) if done is None: # Blocking call self.blocking_response = None while self.blocking_response is None and self.receive(): # print_info("Waiting for response on unknown method (serviceId {}, subTypeId {})", # serviceId, subTypeId) # time.sleep(1) pass if self.blocking_response is None: self.close() print_error("Server hung up before response") return self.blocking_response
def CallMethod(self, method_descriptor, rpc_controller, request, response_class, done): # Handle events and requests differently: events broadcast to every client; # Requests just register callback for later use # (Opposite of DevialetClient) if method_descriptor.GetOptions( ).Extensions[dvltMethodOptions].isNotification: # For events, broadcast immediately, don't use callback serviceId = rpc_controller.parent_service.service_id if hasattr( rpc_controller.parent_service, 'service_id') else self.find_service_id( method_descriptor.containing_service) # Special PropertyUpdate event: how do we get the property id??? typeId, subTypeId = ( 1, request.id ) if method_descriptor.name == 'propertyUpdate' else ( 0, method_descriptor.index) cmm_event = Devialet.CallMeMaybe.Event(serverId=self.serverId, serviceId=serviceId, type=typeId, subTypeId=subTypeId) print_info('Sending event {}', method_descriptor.full_name) for addrport in self.clientsocks.keys(): self.write_event_to_addr(addrport, cmm_event.SerializeToString(), request.SerializeToString()) else: # For request methods, only register callback, don't send anything self.request_callbacks[method_descriptor.full_name] = ( dvlt_pool.messages[method_descriptor.input_type.full_name], done)
def register_endpoint(self, srv): if (srv.hostUid, srv.port) not in self.endpoints: print_info('Registering endpoint {}', (srv.hostUid, srv.port)) self.endpoints[(srv.hostUid, srv.port)] = srv else: print_error('uid {} port {} already used by endpoint', srv.hostUid, srv.port)
def __init__(self, dirname): DevialetManyFlows.__init__(self) self.dirname = dirname for capture in sorted(os.listdir(self.dirname)): time, port = re.match('^([0-9]+)_([0-9]+).dat$', capture).groups() if (port, port) in self.flows: flow = self.flows[(port, port)] else: flow = DevialetFlow(name=capture, phantom_port=port, spark_port=port, start_time=datetime.fromtimestamp(int(time)/1000)) self.add_flow(flow) it = self.packet_iter(os.path.join(self.dirname, capture)) try: first_packet = next(it) # If first packet is incoming, then rpc server is Spark flow.rpc_server_is_phantom = not first_packet['direction'] flow.decode(first_packet['data'], time=first_packet['time'], incoming=False) if not flow.rpc_server_is_phantom: print_info('Found flow where Spark appears to be RPC server') for packet in it: # Switch incoming/outgoing if rpc server is spark is_incoming = packet['direction'] ^ (not flow.rpc_server_is_phantom) flow.decode(packet['data'], time=packet['time'], incoming=is_incoming) except: # Empty flow pass for key in self.flows: self.flows[key].close() self.flows[key].rpc_walk()
def rpc_walk(self, consume_incoming=True, verbose=True): # Each section should correspond to a RPC request/reply, # with 2 outgoing protobufs and 2 (or more for propertyget/multipart) incoming, # or an RPC event, with 2 (or more?) incoming, and no outgoing if verbose or len(self.incoming_sections) != 0: print_info('Walking {}', self.name) print_data('=' * 32) if not self.rpc_server_is_phantom: print_warning('RPC server appears to be Spark here') if consume_incoming: for i in range(len(self.incoming_sections)): print_data('-' * 16) incoming_section = self.incoming_sections.popleft() self.rpc_walk_one_section(incoming_section) # Useless? if len(self.incoming_sections) != 0: print_error('There were {} incoming sections remaining', len(self.incoming_sections)) else: for incoming_section in self.incoming_sections: print_data('-' * 16) self.rpc_walk_one_section(incoming_section) if len(self.outgoing_sections) != 0: print_error('There were {} outgoing sections remaining', len(self.outgoing_sections))
def open(self): try: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Port 0 means system-chosen port self.sock.bind((self.addr, self.port)) self.addr, self.port = self.sock.getsockname() self.sock.listen(5) self.register_service(self.conn) ctrl = DevialetController(self.conn) # Register callback for client connection requests self.conn.openConnection(ctrl, None, self.open_connection) self.conn.ping(ctrl, None, self.pong) # # No Callback - does a blocking RPC # conn_reply = self.conn.openConnection(ctrl, Devialet.CallMeMaybe.ConnectionRequest(version=1), None) # self.serverId = conn_reply.serverId # self.service_list = Devialet.CallMeMaybe.ServicesList(services=conn_reply.services) # # Register event callbacks for added/deleted services # self.conn.serviceAdded(ctrl, None, self.add_service) # self.conn.serviceRemoved(ctrl, None, self.remove_service) # self.conn.serverQuit(ctrl, None, self.close) print_info('Listening on port {}', self.port) # Add to endpoint database of parent whatsup servers self.wu_server.register_endpoint(self) return True except ConnectionRefusedError: exc_type, exc_obj, exc_tb = sys.exc_info() print_error("Can't Connect to {} on port {}, error {}", self.addr, self.port, exc_obj) self.sock = None return False
def CallMethod(self, method_descriptor, rpc_controller, request, response_class, done, timeout=2): # For event methods, only register callback, don't send anything if method_descriptor.GetOptions( ).Extensions[dvltMethodOptions].isNotification: # For events, response class is always empty, request class is the actual class of the event self.event_callbacks[method_descriptor.full_name] = ( dvlt_pool.messages[method_descriptor.input_type.full_name], done) else: reqUUID = uuid.uuid4().bytes serviceId = rpc_controller.parent_service.service_id if hasattr( rpc_controller.parent_service, 'service_id') else self.find_service_id( method_descriptor.containing_service) typeId, subTypeId = ( 1, 0xFFFFFFFF) if method_descriptor.name == 'propertyGet' else ( 0, method_descriptor.index) cmm_request = Devialet.CallMeMaybe.Request(serverId=self.serverId, serviceId=serviceId, requestId=reqUUID, type=typeId, subTypeId=subTypeId) # First add the callback to the queue... self.request_queue[reqUUID] = (method_descriptor, response_class, rpc_controller, done if done else self.unblock_call) if done is None: # Blocking Call self.blocked.clear() # ...Then send the actual request bytes self.write_rpc(cmm_request.SerializeToString(), request.SerializeToString()) print_info('Calling method {} from service {} ({})...', method_descriptor.name, rpc_controller.parent_service.serviceName, serviceId) print_data('... with argument:', request) if done is None: # Wait for callback to be executed or socket to die while self.sock is not None and not self.shutdown_signal and not self.blocked.wait( timeout=timeout): # Wait for blocked event to be unset print_warning('Still blocked on method {}...', method_descriptor.full_name) if self.blocking_response is None: # self.close() print_error("Server hung up before response") return self.blocking_response
def add_wu_services(self, wu_services): self.wu_service_list.services.extend(wu_services.services) for wu_service in wu_services.services: m = re.match('tcp://127.0.0.1:([0-9]+)', wu_service.endpoint) truncated_name = '.'.join(wu_service.name.split('.')[:-1]) if m is not None: port = int(m.groups()[0]) self.services_by_port.setdefault(port, []).append(truncated_name) self.ports_by_service.setdefault(truncated_name, []).append(port) print_info("New WhatsUp services added: {}", wu_services)
def connect(self): self.conn = Devialet.CallMeMaybe.Connection(self) ctrl = DevialetController(self.conn) # No Callback - does a blocking RPC conn_reply = self.conn.openConnection( ctrl, Devialet.CallMeMaybe.ConnectionRequest(version=1), None) self.serverId = conn_reply.serverId self.service_list = Devialet.CallMeMaybe.ServicesList( services=conn_reply.services) # Register event callbacks for added/deleted services self.conn.serviceAdded(ctrl, None, self.add_service) self.conn.serviceRemoved(ctrl, None, self.remove_service) self.conn.serverQuit(ctrl, None, self.close) print_info('Opened connection to {} on port {}', self.addr, self.port) print_data('List of services:', self.service_list)
def find_service(self, rep): service_name = 'com.devialet.callmemaybe.connection' try: if rep.serviceId != 0 or self.service_list.services: service_lowercase_name = [service.name for service in self.service_list.services if service.id == rep.serviceId][0] # PlayThatFunkyMusic is nowhere in protobufs # service_lowercase_name = service_lowercase_name.replace('playthatfunkymusic', 'toomanyflows') service_name = '.'.join(service_lowercase_name.split('.')[:-1]) while service_name not in dvlt_pool.service_by_name and len(service_name.split('.')) > 1: service_name = '.'.join(service_name.split('.')[:-1]) print_info('truncating {} to {}'.format(service_lowercase_name, service_name)) except IndexError: print_error('Service ID {} not in list {}', rep.serviceId, ' '.join(str(self.service_list.services).split('\n'))) return None return service_name
def remove_wu_services(self, wu_removal): for srv in wu_removal.services: try: self.wu_service_list.services.remove(srv) m = re.match('tcp://127.0.0.1:([0-9]+)', srv.endpoint) truncated_name = '.'.join(srv.name.split('.')[:-1]) if m is not None: port = int(m.groups()[0]) self.services_by_port[port].remove(truncated_name) self.ports_by_service[truncated_name].remove(port) if not self.services_by_port[port]: self.services_by_port.pop(port) if not self.ports_by_service[truncated_name]: self.ports_by_service.pop(truncated_name) print_info('WhatsUp service "{}" removed', srv.name) except ValueError: print_errordata('WhatsUp service could not be removed', srv) print_errordata('From list', self.wu_service_list)
def run(self): print_info('Searching for Devialet Device...') while not self.shutdown_signal: ready = select([self.sock], [], [], self.period) if self.shutdown_signal: break if ready[0]: data, (sender_addr, sender_port) = self.sock.recvfrom(1024) if len(data) >= 12: magic, serial_len = struct.unpack('>8sI', data[:12]) serial = data[12:] if magic == b'DVL\x01HERE' and len( data) == 12 + serial_len: if serial not in self.database or self.database[ serial] != sender_addr: self.database[serial] = sender_addr print_info( 'Found Devialet Device with serial {} at address {}', serial, sender_addr) self.queue.put((serial, sender_addr)) if self.callback is not None: self.callback(serial, sender_addr) elif magic == b'DVL\x01BYE!' and len( data) == 12 + serial_len: print_info( 'Device with serial {} at address {} exited', serial, sender_addr) self.database.pop(serial) else: print_warning('Unknown data: {}', data.hex()) # Warning: Unknown data: 44564c014259452100000010066787a949a24d37a99c26d3ff193a5a elif data == b'DVL\x01WHO?': print_info('Got Discovery request') else: print_warning('Discovery message too short: {}', data.hex()) else: if self.advertise: print_info('Advertising...') self.sock.sendto( b'DVL\x01HERE\x00\x00\x00' + bytes([len(self.serial)]) + self.serial, ('255.255.255.255', self.port))
def run(self): # self.open() timeout = 2 while not self.shutdown_signal: # print_info('One spin of SERVER loop...') socks = [s for s, f, c in self.clientsocks.values()] + [self.sock] readable, writable, errored = select(socks, [], [], timeout) if self.shutdown_signal: break # if errored: # print_warning('Shutting down server on port {}', self.port) # break # print_info('One spin of SERVER loop!') for s in readable: if s is self.sock: clientsock, (clientaddr, clientport) = self.sock.accept() if self.shutdown_signal: break clientfile = clientsock.makefile(mode='wb') self.clientsocks[(clientaddr, clientport)] = (clientsock, clientfile, False) self.flows[(clientaddr, clientport)] = DevialetFlow( name='{}:{}'.format(clientaddr, clientport), spark_port=self.port, phantom_port=clientport) print_info('Client {} on port {} connected to us!', clientaddr, clientport) else: addrport = [ a for a, (ss, f, c) in self.clientsocks.items() if ss is s ][0] data = s.recv(2048) # print_warning('data from {}: {}', addr, data) if data: print_info('Received {} on client socket {}', data.hex(), addrport) self.flows[addrport].decode(data, incoming=False) self.find_requests(addrport) else: self.close_client(addrport)
def close(self): rest_incoming = self.incoming_buf.read() rest_outgoing = self.outgoing_buf.read() if rest_incoming: self.warnings.append('Found garbage at end of incoming flow: {}...'.format( ' '.join('{:02x}'.format(x) for x in rest_incoming[:50]))) if rest_outgoing: self.warnings.append('Found garbage at end of outgoing flow: {}...'.format( ' '.join('{:02x}'.format(x) for x in rest_outgoing[:50]))) if self.warnings: print_warning(self.warnings) print_info('flow {} has {} incoming and {} outgoing sections', self.name, len(self.incoming_sections), len(self.outgoing_sections)) self.incoming_buf.close() self.outgoing_buf.close()
def try_to_find_service(self, service_name, port=None): try: ports = self.ports_by_service[service_name] if len(ports) > 1: print_warning( 'More than one possible endpoint match for service {}: {}', service_name, ports) if port is None: port = ports[0] elif port not in ports: print_warning('Requested port not in list of matches') port = ports[0] print_info('Using port {} for service {}', port, service_name) svc_class = dvlt_pool.service_by_name[service_name]._concrete_class client = DevialetClient(name=service_name + ' client', port=port, addr=self.addr) return client, svc_class(client) except KeyError: print_error("Can't find service {} in whatsup services", service_name) pass
import r2pipe import os import json from google.protobuf.descriptor_pb2 import FileDescriptorProto import google.protobuf.message from dvlt_output import print_info, print_error, print_warning dll_dir = '/path/to/spark_dlls' out_dir = './protoc_new/' for filename in os.listdir(dll_dir): if filename.endswith('.dll'): filename = os.path.join(dll_dir, filename) print_info('Exploring file {}...', filename) f = open(filename, 'rb').read() r2 = r2pipe.open(filename) r2.cmd('aaa') # print_info('Finished analysis') sections = json.loads(r2.cmd('Sj')) xrefs = r2.cmd('axF InternalAddGeneratedFile|cut -d" " -f2|sort -u').split() def get_paddr(vaddr): for section in sections: if vaddr >= section['vaddr'] and vaddr < section['vaddr'] + section['size']: return vaddr - section['vaddr'] + section['paddr'] print_error("Can't find virtual address {}", vaddr) return 0 for xref in xrefs: disasm = json.loads(r2.cmd('pdj -2 @ ' + xref)) if disasm[0]['type'] == 'push' and disasm[1]['type'] == 'push':
def pong(self, empty): print_info('Server {} ({}): Pong', self.hostUid, self.port) return Devialet.CallMeMaybe.Empty()
def open_connection(self, conn_request): print_info('Client trying to open connection, ver {}', conn_request.version) return Devialet.CallMeMaybe.ConnectionReply( serverId=self.serverId, services=self.service_list.services)
def get_host_list(self, empty): print_info('Got host list request') return Devialet.WhatsUp.WhatsUpHostsList()
def rpc_walk_one_section(self, incoming_section): incoming_pb = incoming_section.raw_protobufs if incoming_section.magic == 0xC3: # Event? try: evt = dvlt_pool.interpret_as(incoming_pb[0], 'Devialet.CallMeMaybe.Event') service_name = self.find_service(evt) method, input_pb, outputs_pb = dvlt_pool.process_rpc(service_name, evt, incoming_pb[1], incoming_pb[1:], is_event=True) if method.containing_service.full_name == 'Devialet.CallMeMaybe.Connection': if method.name == 'serviceAdded': print_info('Extending list of services') self.service_list.services.add(name=input_pb.name, id=input_pb.id) # The 'uid' parameter in the section, when present (== when magic is C3, and only on incoming packets) # should be equal to the server ID print_info('in_time:{} evt:{} {}/{:>10d}/{:>12d}{:31s} {} E', incoming_section.time, evt.serverId[:4].hex(), evt.type, evt.subTypeId, evt.serviceId, '', incoming_section.uid[:4].hex()) except IndexError: print_error('not enough incoming protos for event ({}) < 2', len(incoming_pb)) except AttributeError: pass else: try: outgoing_section = self.outgoing_sections.popleft() outgoing_pb = outgoing_section.raw_protobufs req = dvlt_pool.interpret_as(outgoing_pb[0], 'Devialet.CallMeMaybe.Request') rep = dvlt_pool.interpret_as(incoming_pb[0], 'Devialet.CallMeMaybe.Reply') bad_reqs = deque() # print('UUID {}'.format(req.requestId.hex())) # (First two bytes (or more) of request id appear to be sequential) while rep.requestId != req.requestId: bad_reqs.appendleft(outgoing_section) print_warning('Request id {} out of order', req.requestId.hex()) # print_errordata('Full Request:', req) try: outgoing_section = self.outgoing_sections.popleft() outgoing_pb = outgoing_section.raw_protobufs req = dvlt_pool.interpret_as(outgoing_pb[0], 'Devialet.CallMeMaybe.Request') except IndexError: # Reached end of outgoing_sections # print_error("Couldn't find request for reply {}", rep.requestId.hex()) break self.outgoing_sections.extendleft(bad_reqs) if not rep.isMultipart and len(incoming_pb) > 2: print_warning('we got more incoming protobufs than we should have, not Multipart') if len(outgoing_pb) > 2: print_error('we got more than 2 outgoing protobufs') if len(outgoing_pb) < 2: print_error('we got less than 2 outgoing protobufs') if len(incoming_pb) < 2: print_error('we got less than 2 incoming protobufs') service_name = self.find_service(rep) method, input_pb, outputs_pb = dvlt_pool.process_rpc( service_name, rep, outgoing_pb[1], incoming_pb[1:]) if method.containing_service.full_name == 'Devialet.CallMeMaybe.Connection': if method.name == 'openConnection': self.service_list = outputs_pb[0] print_info('out_time:{} in_time:{} req:{}/{}/{:>10d}/{:>12d}, rep:{}/{}/{:>10d}/{:>12d} {}{}{}', outgoing_section.time, incoming_section.time, req.requestId[:4].hex(), req.type, req.subTypeId, req.serviceId, rep.requestId[:4].hex(), rep.type, rep.subTypeId, rep.serviceId, 'M' if rep.isMultipart else ' ', ' ' if method.name == 'ping' else 'C' if method.name == 'openConnection' else '.', '<' if rep.requestId != req.requestId else ' ') except IndexError: print_error('Stream ended prematurely, missing outgoing section') except Exception as e: print_error('Unexpected {} {}', type(e), e)
def find_requests(self, addrport): flow = self.flows[addrport] while flow.outgoing_sections: outgoing_section = flow.outgoing_sections.popleft() outgoing_pb = outgoing_section.raw_protobufs # print_warning("Found Request") req = Devialet.CallMeMaybe.Request.FromString(outgoing_pb[0]) if req.serverId != self.serverId and req.serverId != b'\x00' * 16: print_warning( 'Oops, this request is not for us (unless this is inital conenction request): we are {}, sent to {}', self.serverId.hex(), req.serverId.hex()) try: srv = self.services[req.serviceId] if req.type == 0: try: method_desc = srv.methods_by_id[req.subTypeId] if method_desc.full_name in self.request_callbacks: (request_class, callback ) = self.request_callbacks[method_desc.full_name] response = callback( request_class.FromString(outgoing_pb[1])) rep = Devialet.CallMeMaybe.Reply( serverId=self.serverId, serviceId=req.serviceId, requestId=req.requestId, type=0, subTypeId=req.subTypeId, errorCode=0, isMultipart=False) self.write_response_to_addr( addrport, rep.SerializeToString(), response.SerializeToString()) else: print_error('Unhandled method {} from {}', method_desc.full_name, addrport) except KeyError: print_errordata( 'Method id {} not in service method dict:'.format( req.subTypeId), { k: v.full_name for (k, v) in srv.methods_by_id.items() }) elif req.type == 1 and req.subTypeId == 0xFFFFFFFF: # PropertyGet special request rep = Devialet.CallMeMaybe.Reply(serverId=self.serverId, serviceId=req.serviceId, requestId=req.requestId, type=1, subTypeId=0xFFFFFFFF, errorCode=0, isMultipart=True) print_info('Got PropertyGet request:') for name, prop in srv.properties.items(): print_data(name, prop) self.write_responses_to_addr( addrport, rep.SerializeToString(), [p.SerializeToString() for p in srv.get_properties()]) elif req.type == 1: # PropertySet special request # TODO print_errordata( 'Unhandled propertyset subtypeId={}'.format( req.subTypeId), [x.hex() for x in outgoing_pb]) pass else: print_error('Unknown request type {}', req.type) except KeyError: print_error( 'Service ID {} not in list {}', req.serviceId, ' '.join(str(self.service_list.services).split('\n'))) self.flows[addrport].outgoing_sections.clear()
# tmf_client.keep_receiving() # Init WhatsUp server wu_srv = WhatsUpServer(hostUid=hostUid) wu_srv.open() dscvr.start_advertising() wu_srv.start() def pingback(arg): print_info("Pong <--") try: while True: # ~ 20 ms round-trip for pings time.sleep(1) print_info("Ping -->") wu_client.conn.ping(DevialetController(wu_client.conn), Devialet.CallMeMaybe.Empty(), pingback) except KeyboardInterrupt: wu_client.shutdown() wu_srv.shutdown() dscvr.shutdown() print_info('join()ing client...') wu_client.join() print_info('join()ing server...') wu_srv.join() print_info('join()ing discovery..') dscvr.join()
def pingback(arg): print_info("Pong <--")
def add_service(self, service): print_info("New Service added: {}", service.name) self.service_list.services.extend([service])
import sys from datetime import datetime from collections import deque from dvlt_output import print_warning, print_info, print_error, print_data from dvlt_decode import DevialetManyFlows, DevialetFlow print_info('Loading scapy...') from scapy.all import * class SeqData: def __init__(self): self.seq = 0 self.isn = 0 self.ood = deque() class PcapFlows(DevialetManyFlows): def __init__(self, filename, spark_addr, phantom_addr, decode_by_flow=False): DevialetManyFlows.__init__(self) self.filename = filename self.spark_addr = spark_addr self.phantom_addr = phantom_addr self.decode_by_flow = decode_by_flow # print_info('Loading file...') # capture = scapy.all.rdpcap(filename) # self.sessions = capture[TCP].sessions() with PcapReader(filename) as pcap_reader: for packet in pcap_reader: # print(packet)
def remove_service(self, service): print_info("Service {} removed", service.name) self.service_list.services.remove(service)
def unblock_call(self, response): self.blocking_response = response print_info('Unblocking') self.blocked.set()
def __init__(self, filename, spark_addr, phantom_addr, decode_by_flow=False): DevialetManyFlows.__init__(self) self.filename = filename self.spark_addr = spark_addr self.phantom_addr = phantom_addr self.decode_by_flow = decode_by_flow # print_info('Loading file...') # capture = scapy.all.rdpcap(filename) # self.sessions = capture[TCP].sessions() with PcapReader(filename) as pcap_reader: for packet in pcap_reader: # print(packet) if packet.haslayer(TCP): # for packet in capture[TCP]: time = datetime.fromtimestamp(packet.time) # print(packet) # if packet. spark_port = -1 if packet[IP].src == self.spark_addr and packet[IP].dst == self.phantom_addr: spark_port = packet[TCP].sport phantom_port = packet[TCP].dport phantom_to_spark = False elif packet[IP].src == self.phantom_addr and packet[IP].dst == self.spark_addr: spark_port = packet[TCP].dport phantom_port = packet[TCP].sport phantom_to_spark = True if spark_port >= 0: if (phantom_port, spark_port) in self.flows: flow = self.flows[(phantom_port, spark_port)] else: print_warning('New Flow phantom {}, spark {}, time {}', phantom_port, spark_port, time) flow = DevialetFlow(name='phantom {}, spark {}'.format(phantom_port, spark_port), phantom_port=phantom_port, spark_port=spark_port, start_time=time) flow.phantom = SeqData() flow.spark = SeqData() # if first packet is from phantom to spark, rpc server is probably spark if phantom_to_spark: print_info('Found flow where Spark appears to be RPC server: phantom {}, spark {}', phantom_port, spark_port) flow.rpc_server_is_phantom = False self.add_flow(flow) # Reverse direction if rpc server is Spark srv_to_client = phantom_to_spark ^ (not flow.rpc_server_is_phantom) tcplen = packet[IP].len - packet[IP].ihl*4 - packet[TCP].dataofs*4 sending = (flow.phantom if phantom_to_spark else flow.spark) receiving = (flow.spark if phantom_to_spark else flow.phantom) if 'S' in packet.sprintf('%TCP.flags%') or 'F' in packet.sprintf('%TCP.flags%'): # if SYN, synchronize sequence numbers print_info('Sp {:6d} {} Ph {:6d} Len {:5d} Seq {:12d} Ack {:12d} Diff {:12d} Flags {}', spark_port, '<- ' if phantom_to_spark else ' ->', phantom_port, tcplen, packet[TCP].seq - sending.isn, packet[TCP].ack - receiving.isn, 0, packet.sprintf('%TCP.flags%'), color='red') sending.isn = packet[TCP].seq sending.seq = packet[TCP].seq + 1 if sending.ood: print_error('{} remaining in {} OOD queue', len(sending.ood), 'Phantom' if phantom_to_spark else 'Spark') sending.ood.clear() else: # print(packet[TCP].load[:12].hex()) diff = packet[TCP].seq - sending.seq print_info('Sp {:6d} {} Ph {:6d} Len {:5d} Seq {:12d} Ack {:12d} Diff {:12d} Flags {}', spark_port, '<- ' if phantom_to_spark else ' ->', phantom_port, tcplen, packet[TCP].seq - sending.isn, packet[TCP].ack - receiving.isn, diff, packet.sprintf('%TCP.flags%'), color='blue' if phantom_to_spark else 'green', reverse=(diff != 0)) if diff == 0: sending.seq = packet[TCP].seq + tcplen if tcplen: flow.decode(packet[TCP].load[:tcplen], time=time, incoming=srv_to_client) if not self.decode_by_flow: flow.rpc_walk(verbose=False) for p in list(sending.ood): l = p[IP].len - p[IP].ihl*4 - p[TCP].dataofs*4 d = p[TCP].seq - sending.seq if d == 0: sending.seq = p[TCP].seq + l if l: flow.decode(p[TCP].load[:l], time=time, incoming=srv_to_client) if not self.decode_by_flow: flow.rpc_walk(verbose=False) sending.ood.remove(p) print_info('Sp {:6d} {} Ph {:6d} Len {:5d} Seq {:12d} Ack {:12d} Diff {:12d} Flags {:3} Reordered', spark_port, '<- ' if phantom_to_spark else ' ->', phantom_port, l, p[TCP].seq - sending.isn, p[TCP].ack - receiving.isn, d, p.sprintf('%TCP.flags%'), color='magenta') else: # print_warning('{:6d} {} Ph {:6d} Len {:5d} Seq {:12d} Ack {:12d} Diff {:12d} Flags {:3} OOD', # spark_port, '<- ' if phantom_to_spark else ' ->', phantom_port, l, # p[TCP].seq - sending.isn, p[TCP].ack - receiving.isn, # d, p.sprintf('%TCP.flags%')) pass else: sending.ood.append(packet)
Devialet.TooManyFlows.TrackMsg(index=0, url=trackURL) ]), callback_test)) # tmf_playlist.tracksAdded(DevialetController(tmf_playlist), None, lambda empty: tmf_playback.play( # DevialetController(tmf_playback), Devialet.CallMeMaybe.Empty(), callback_test)) tmf_meta.propertyUpdate( DevialetController(tmf_meta), None, lambda empty: tmf_playback.play(DevialetController( tmf_playback), Devialet.CallMeMaybe.Empty(), callback_test)) # GO tmf_playlist.clear(DevialetController(tmf_playlist), Devialet.CallMeMaybe.Empty(), callback_test) print_info('Successfully cleared playlist', color='green') # tmf_client.shutdown() # time.sleep(3) # time.sleep(10) print_info('Successfully pressed play', color='green') def pingback(arg): print_info("Pong <--") try: while True: # ~ 20 ms round-trip for pings time.sleep(1)