@@ -0,0 +1,2096 @@
+%22%22%22Utilities for analyzing with VPN over DNS socket sessions.%22%22%22%0A%0Afrom vodreassembler import util%0A%0A%0Aclass SocketSession:%0A  def __init__(self, data):%0A    super().__init__()%0A    self._data = data%0A%0A  @property%0A  def uuid(self):%0A    return self._data%5B'uuid'%5D%0A%0A  @property%0A  def session_id(self):%0A    return self._data%5B'id'%5D%0A%0A  @property%0A  def all_tickets(self):%0A    return self._data%5B'tickets'%5D%0A%0A  @classmethod%0A  def find_all(cls, ticket_db):%0A    %22%22%22Find all socket sessions from given ticket_db.%22%22%22%0A    socket_db = %7B%7D%0A    for ticket in ticket_db:%0A      try:%0A        req_string, req_binary = _parse_request_data(ticket)%0A        uuid, msgtype, *other_params = req_string.split('%5Cxa7')%0A        uuid = int(uuid)%0A        # TODO(toukoaozaki): support other message types%0A        if msgtype == 'SocketData':%0A          socket_id = int(other_params%5B0%5D)%0A          key = (uuid, socket_id)%0A          if key not in socket_db:%0A            socket_db%5Bkey%5D = %7B'uuid': uuid, 'id': socket_id, 'tickets': %5B%5D%7D%0A          socket_db%5Bkey%5D%5B'tickets'%5D.append(ticket)%0A      except (util.IncompleteDataError, ValueError):%0A        pass%0A    return tuple(cls(data) for data in socket_db.values())%0A%0A  def __repr__(self):%0A    return ('SocketSession(uuid=%7B!r%7D, '%0A            'session_id=%7B!r%7D, '%0A            'num_tickets=%7B!r%7D)').format(self.uuid,%0A                                        self.session_id,%0A                                        len(self.all_tickets))%0A%0A%0A# Those utilities should be part of Ticket interface.%0A# TODO(toukoaozaki): refactor code into Ticket interface.%0Adef _parse_request_data(ticket):%0A  data = ticket.request_data%0A  is_binary = ticket.is_binary%0A  if data is None:%0A    raise util.IncompleteDataError()%0A  string_length = data%5B0%5D%0A  assert (string_length != 0) == is_binary%0A  return data%5B1:string_length+1%5D.decode('utf-8'), data%5Bstring_length+1:%5D or None%0A%0Adef _parse_response_data(data, is_binary):%0A  if data is None:%0A    raise util.IncompleteDataError()%0A  if is_binary:%0A    string_length = data%5B0%5D%0A    return data%5B1:string_length+1%5D.decode('utf-8'), data%5Bstring_length+1:%5D%0A  return data.decode('utf-8'), None%0A

Add socket module for analyzing sockets from tickets.