Пример #1
0
	def handle_recv(self, pair):
		station, packet = pair
		
		message = PIAMessage()
		
		stream = StreamIn(packet.payload, self.settings)
		while not stream.eof():
			peek = stream.peek(stream.available())
			if all(x == 0xFF for x in peek):
				break
			
			message = message.copy()
			if not self.encoder.decode(stream, message):
				return
			
			if message.flags & 0x10:
				message.payload = zlib.decompress(message.payload)
			
			if station.id is None:
				station.id = message.station_id
			elif station.id != message.station_id:
				logger.error("Received message with wrong station id")
				return
			
			self.messages.append((station, message))
Пример #2
0
    def parse_browse_reply(self, data, key, challenge):
        stream = StreamIn(data, self.settings)
        if stream.u8() != 1:
            return None

        size = stream.u32()
        data = stream.read(size)

        if not self.verify_challenge_reply(stream, key, challenge):
            return None

        if not stream.eof():
            logger.warning("Browse reply is bigger than expected")
            return None

        stream = StreamIn(data, self.settings)

        try:
            session_info = stream.extract(LanSessionInfo)
        except Exception as e:
            logger.warning("Failed to parse LanSessionInfo: %s", e)
            return None

        if not stream.eof():
            logger.warning("LanSessionInfo has unexpected size")
            return None

        return session_info
Пример #3
0
    def handle_ack(self, station, data):
        logger.debug("Received ack")

        stream = StreamIn(data, self.settings)
        stream.skip(4)
        ack_id = stream.u32()

        self.resender.acknowledge(station, ack_id)
Пример #4
0
 def decode(self, stream):
     if stream.settings.get("pia.version") < 51000:
         self.connection_info = stream.extract(StationConnectionInfo)
     else:
         substream = StreamIn(stream.read(0x3E), stream.settings)
         location = substream.extract(StationLocation)
         self.connection_info = StationConnectionInfo(location)
     self.index = stream.u8()
     stream.align(4)
Пример #5
0
	def handle_session_reply(self, station, data):
		logger.debug("Received session reply")
		
		stream = StreamIn(data, self.settings)
		stream.skip(12)
		
		session_id = stream.u32()
			
		if session_id not in self.host_requests:
			logger.warning("Received unexpected session reply")
			return
			
		self.session_requests[session_id].update(stream)
Пример #6
0
    def parse_browse_reply(self, data, key, challenge):
        stream = StreamIn(data, self.settings)
        if stream.u8() != 1:
            return None

        if stream.size() != 0x551:
            logger.warning(
                "Browse reply has unexpected size (expected 1361 bytes, got %i)"
                % stream.size())
            return None

        size = stream.u32()
        if size != 0x512:
            logger.warning(
                "LanSessionInfo has unexpected size (expected 1298 bytes, got %i)"
                % size)
            return None

        try:
            session_info = stream.extract(LanSessionInfo)
        except Exception as e:
            import traceback
            traceback.print_exc()
            logger.warning("Failed to parse LanSessionInfo: %s", e)
            return None

        if not self.verify_challenge_reply(stream, key, challenge):
            return None
        return session_info
Пример #7
0
    def handle_join_response(self, station, data):
        logger.debug("Received join response")

        if self.join_response_parser is None:
            logger.error("Received unexpected join response")
            return

        if data[1] == 0:
            reason = data[4]
            logger.error("Join request was denied: %i", reason)
            self.join_response_parser.error = True
            return

        stream = StreamIn(data, self.settings)
        stream.skip(1)

        if self.join_response_parser.update(stream):
            ack_id = stream.u32()
            self.station_protocol.send_ack(station, ack_id)
Пример #8
0
	def handle_connection_response(self, station, data):
		logger.debug("Received connection response")
		
		if station.connection_state not in [ConnectionState.WAIT_RESPONSE, ConnectionState.WAIT_INVERSE_RESPONSE]:
			logger.error("Received unexpected connection response")
			return
			
		stream = StreamIn(data, self.settings)
		stream.skip(1)
		
		identification = self.process_connection_response(stream)
		if identification is not None:
			ack_id = stream.u32()
			self.send_ack(station, ack_id)
			
			station.identification_info = identification
			if station.connection_state == ConnectionState.WAIT_INVERSE_RESPONSE:
				self.send_connection_response(station)
			station.connection_state = ConnectionState.CONNECTED
		else:
			station.connection_state = ConnectionState.ERROR
Пример #9
0
	def handle_session_request(self, station, data):
		logger.debug("Received session request")
		
		if len(data) != 0x10:
			logger.error("Session request has unexpected size")
			return
		
		stream = StreamIn(data, self.settings)
		stream.skip(12)
		
		session_id = stream.u32()
		
		session_info = self.session.get_session_info()
		if session_info.session_id != session_id:
			logger.warning("Received session request with different session id")
			return
			
		if not self.session.is_host():
			logger.info("Ignoring session request because we aren't host")
			return
		
		self.send_session_reply(station, session_info)
Пример #10
0
	def handle_host_reply(self, station, data):
		logger.debug("Received host reply")
		
		stream = StreamIn(data, self.settings)
		stream.skip(12)
		
		session_id = stream.u32()
		
		if self.settings.get("pia.version") < 51000:
			host = stream.extract(StationConnectionInfo).public
		else:
			host = stream.extract(StationLocation)
			
		if session_id not in self.host_requests:
			logger.warning("Received unexpected host reply")
			return
			
		self.host_requests[session_id] = host
Пример #11
0
    def parse_browse_request(self, data):
        stream = StreamIn(data, self.settings)
        if stream.u8() != 0:
            logger.debug("Message is not a browse request")
            return None

        size = stream.u32()
        end = stream.tell() + size

        criteria = stream.extract(LanSessionSearchCriteria)
        if stream.tell() != end:
            logger.warning("LanSessionSearchCriteria has unexpected size")
            return None

        reply = self.parse_challenge(stream)
        if reply is None:
            return None

        if not stream.eof():
            logger.warning("Browse request is bigger than expected")
            return None

        logger.info("Received browse request")
        return criteria, reply
Пример #12
0
    def decode(self, data):
        data = self.check_signature(data)
        if data is None:
            logger.error("Invalid packet signature")
            return False

        stream = StreamIn(data, self.settings)
        if stream.u32() != 0x32AB9864:
            logger.error("Invalid packet identifier")
            return False

        if self.settings.get("pia.header_version") > 0:
            byte = stream.u8()
            encrypted = byte >> 7
            version = byte & 0x7F

            if version != self.settings.get("pia.header_version"):
                logger.error("Unexpected packet version: %i", version)
                return False
        else:
            encryption = stream.u8()
            if encryption not in [1, 2]:
                logger.error("Invalid encryption mode")
                return False

            encrypted = encryption == 2

        self.connection_id = stream.u8()
        self.sequence_id = stream.u16()

        if self.settings.get("pia.header_version") == 0:
            self.session_timer = stream.u16()
            self.rtt_timer = stream.u16()

        if self.settings.get(
                "pia.encryption_method") == EncryptionMethod.AES_GCM:
            self.nonce = stream.u64()
            self.signature = stream.read(16)

        payload = stream.read(stream.available())
        if encrypted:
            payload = self.decrypt(payload)
            if payload is None:
                return False

        self.payload = payload
        return True
Пример #13
0
    def handle_connection_request(self, station, data):
        logger.debug("Received connection request")

        stream = StreamIn(data, self.settings)
        stream.skip(1)

        connection_id = stream.u8()
        version = stream.u8()
        inverse = stream.bool()

        if version != self.version:
            logger.error(
                "Received connection request with wrong version number")
            self.send_denying_connection_response(station, 2)
            return

        local_station = self.session.local_station()
        local_info = local_station.connection_info.local
        if self.version >= 7:
            if stream.pid() != local_info.pid:
                logger.error("Received connection request with wrong pid")
                return
        if self.version >= 8:
            if stream.u32() != local_info.cid:
                logger.error("Received connection request with wrong cid")
                return
            inverse_id = stream.u8()
            if inverse_id != station.connection_id_out_temp:
                logger.error(
                    "Received connection request with wrong inverse connection id: %i",
                    inverse_id)
                return

        if self.version == 8:
            conn_info = stream.extract(StationConnectionInfo)
        else:
            location = stream.extract(StationLocation)
            conn_info = StationConnectionInfo(location)

        ack_id = stream.u32()

        if inverse:
            if station.connection_state != ConnectionState.WAIT_INVERSE_REQUEST:
                logger.error("Received unexpected inverse connection request")
                self.send_denying_connection_response(station, 1)
                return

            station.connection_id_in_temp = connection_id
            station.connection_info = conn_info

            self.send_ack(station, ack_id)
            self.send_connection_response(station)

            station.connection_state = ConnectionState.WAIT_RESPONSE
        else:
            if station.connection_state != ConnectionState.DISCONNECTED:
                logger.error("Received unexpected connection request")
                self.send_denying_connection_response(station, 1)
                return

            station.connection_id_out_temp = random.randint(2, 0xFF)
            station.connection_id_in_temp = connection_id
            station.connection_info = conn_info

            self.send_ack(station, ack_id)
            self.send_connection_request(station, connection_id)

            station.connection_state = ConnectionState.WAIT_INVERSE_RESPONSE