8000 parse_pcap_klap: various code cleanups (#1138) · python-kasa/python-kasa@4640dfa · GitHub
[go: up one dir, main page]

Skip to content

Commit 4640dfa

Browse files
rytilahtisdb9696
andauthored
parse_pcap_klap: various code cleanups (#1138)
Co-authored-by: Steven B <51370195+sdb9696@users.noreply.github.com>
1 parent b2f3971 commit 4640dfa

File tree

1 file changed

+65
-68
lines changed

1 file changed

+65
-68
lines changed

devtools/parse_pcap_klap.py

Lines changed: 65 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@
2929
from kasa.protocol import DEFAULT_CREDENTIALS, get_default_credentials
3030

3131

32+
def _get_seq_from_query(packet):
33+
"""Return sequence number for the query."""
34+
query = packet.http.get("request_uri_query")
35+
if query is None:
8000 36+
raise Exception("No request_uri_query found")
37+
# use regex to get: seq=(\d+)
38+
seq = re.search(r"seq=(\d+)", query)
39+
if seq is not None:
40+
return int(seq.group(1))
41+
raise Exception("Unable to find sequence number")
42+
43+
3244
def _is_http_response_for_packet(response, packet):
3345
"""Return True if the *response* contains a response for request in *packet*.
3446
@@ -41,10 +53,7 @@ def _is_http_response_for_packet(response, packet):
4153
):
4254
return True
4355
# tshark 4.4.0
44-
if response.http.request_uri == packet.http.request_uri:
45-
return True
46-
47-
return False
56+
return response.http.request_uri == packet.http.request_uri
4857

4958

5059
class MyEncryptionSession(KlapEncryptionSession):
@@ -244,71 +253,59 @@ def main(
244253
if packet.ip.src != source_host:
245254
continue
246255
# we only care about http packets
247-
if hasattr(
248-
packet, "http"
249-
): # this is redundant, as pyshark is set to only load http packets
250-
if hasattr(packet.http, "request_uri_path"):
251-
uri = packet.http.get("request_uri_path")
252-
elif hasattr(packet.http, "request_uri"):
253-
uri = packet.http.get("request_uri")
254-
else:
255-
uri = None
256-
if hasattr(packet.http, "request_uri_query"):
257-
query = packet.http.get("request_uri_query")
258-
# use regex to get: seq=(\d+)
259-
seq = re.search(r"seq=(\d+)", query)
260-
if seq is not None:
261-
operator.seq = int(
262-
seq.group(1)
263-
) # grab the sequence number from the query
264-
data = (
265-
# Windows and linux file_data attribute returns different
266-
# pretty format so get the raw field value.
267-
packet.http.get_field_value("file_data", raw=True)
268-
if hasattr(packet.http, "file_data")
269-
else None
270-
)
271-
match uri:
272-
case "/app/request":
273-
if packet.ip.dst != device_ip:
274-
continue
275-
assert isinstance(data, str) # noqa: S101
276-
message = bytes.fromhex(data)
277-
try:
278-
plaintext = operator.decrypt(message)
279-
payload = json.loads(plaintext)
280-
print(json.dumps(payload, indent=2))
281-
packets.append(payload)
282-
except ValueError:
283-
print("Insufficient data to decrypt thus far")
284-
285< 8000 span class="diff-text-marker">-
case "/app/handshake1":
286-
if packet.ip.dst != device_ip:
287-
continue
288-
assert isinstance(data, str) # noqa: S101
289-
message = bytes.fromhex(data)
290-
operator.local_seed = message
291-
response = None
292-
print(
293-
f"got handshake1 in {packet_number}, "
294-
f"looking for the response"
295-
)
296-
while (
297-
True
298-
): # we are going to now look for the response to this request
299-
response = capture.next()
300-
if _is_http_response_for_packet(response, packet):
301-
print(f"found response in {packet_number}")
302-
break
303-
data = response.http.get_field_value("file_data", raw=True)
304-
message = bytes.fromhex(data)
305-
operator.remote_seed = message[0:16]
306-
operator.remote_auth_hash = message[16:]
307-
308-
case "/app/handshake2":
309-
continue # we don't care about this
310-
case _:
256+
# this is redundant, as pyshark is set to only load http packets
257+
if not hasattr(packet, "http"):
258+
continue
259+
260+
uri = packet.http.get("request_uri_path", packet.http.get("request_uri"))
261+
if uri is None:
262+
continue
263+
264+
operator.seq = _get_seq_from_query(packet)
265+
266+
# Windows and linux file_data attribute returns different
267+
# pretty format so get the raw field value.
268+
data = packet.http.get_field_value("file_data", raw=True)
269+< A3DB div class="diff-text-inner">
270+
match uri:
271+
case "/app/request":
272+
if packet.ip.dst != device_ip:
273+
continue
274+
message = bytes.fromhex(data)
275+
try:
276+
plaintext = operator.decrypt(message)
277+
payload = json.loads(plaintext)
278+
print(json.dumps(payload, indent=2))
279+
packets.append(payload)
280+
except ValueError:
281+
print("Insufficient data to decrypt thus far")
282+
283+
case "/app/handshake1":
284+
if packet.ip.dst != device_ip:
311285
continue
286+
message = bytes.fromhex(data)
287+
operator.local_seed = message
288+
response = None
289+
print(
290+
f"got handshake1 in {packet_number}, "
291+
f"looking for the response"
292+
)
293+
while (
294+
True
295+
): # we are going to now look for the response to this request
296+
response = capture.next()
297+
if _is_http_response_for_packet(response, packet):
298+
print(f"found response in {packet_number}")
299+
break
300+
data = response.http.get_field_value("file_data", raw=True)
301+
message = bytes.fromhex(data)
302+
operator.remote_seed = message[0:16]
303+
operator.remote_auth_hash = message[16:]
304+
305+
case "/app/handshake2":
306+
continue # we don't care about this
307+
case _:
308+
continue
312309
except StopIteration:
313310
break
314311

0 commit comments

Comments
 (0)
0