Skip to content

Commit 71f5faa

Browse files
committed
PCAP Parser: Support converting encrypted pcap into plaintext pcap
1 parent 2786d78 commit 71f5faa

2 files changed

Lines changed: 50 additions & 32 deletions

File tree

30 Bytes
Binary file not shown.

pcap_parser/src/main.rs

Lines changed: 50 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::io::prelude::*;
77
use std::io::BufWriter;
88
use std::io::Cursor;
99
use structopt::StructOpt;
10-
use pcap::Capture;
10+
use pcap::{Capture, Linktype, Savefile};
1111
use gamestreaming::pnet::util::MacAddr;
1212
use gamestreaming::pnet::packet::ethernet::{EtherTypes, EthernetPacket};
1313
use gamestreaming::pnet::packet::ipv4::Ipv4Packet;
@@ -23,6 +23,8 @@ use gamestreaming::teredo::{Teredo, TeredoEndpoint};
2323
type Error = Box<dyn std::error::Error>;
2424
type Result<T> = std::result::Result<T, Error>;
2525

26+
const AUTH_TAG_LEN: usize = 16;
27+
2628
#[derive(Debug)]
2729
struct RtpPacketResult {
2830
is_client: bool,
@@ -194,7 +196,7 @@ struct Opt {
194196
srtp_key: Option<String>,
195197

196198
#[structopt(long)]
197-
dump_video: Option<PathBuf>,
199+
decrypt_pcap: Option<PathBuf>,
198200
}
199201

200202
fn main() {
@@ -207,6 +209,8 @@ fn main() {
207209

208210
let mut parser = PcapParser::new();
209211

212+
// Initialize Crypto context
213+
// If no key is provided, use dummy key
210214
let mut crypto_context: crypto::MsSrtpCryptoContext = {
211215
if let Some(key) = opt.srtp_key {
212216
crypto::MsSrtpCryptoContext::from_base64(&key)
@@ -218,25 +222,28 @@ fn main() {
218222
}
219223
};
220224

221-
let fhandle = {
222-
match opt.dump_video {
223-
Some(filepath) => Some(File::create(filepath).expect("Failed to create file for video-dump")),
224-
None => None
225-
}
226-
};
225+
// Only used for writing decrypted pcap
226+
let capture_out = Capture::dead(Linktype::ETHERNET)
227+
.expect("Failed to create pcap OUT handle");
227228

228-
let mut buf_writer = {
229-
match fhandle {
230-
Some(handle) => Some(BufWriter::new(handle)),
231-
None => None,
232-
}
229+
// Open handle for writing decrypted pcap
230+
let mut pcap_out_handle = match opt.decrypt_pcap {
231+
Some(filepath) => {
232+
let savefile = capture_out.savefile(filepath)
233+
.expect("Failed to create Savefile pcap OUT instance");
234+
235+
Some(savefile)
236+
},
237+
None => None
233238
};
234239

235-
while let Ok(packet) = cap.next() {
236-
if let Ok(rtp_response) = parser.handle_packet(&packet.data) {
240+
while let Ok(pcap_packet) = cap.next() {
241+
if let Ok(rtp_response) = parser.handle_packet(&pcap_packet.data) {
242+
// Handle RTP packet
237243
let packet = rtp_response.packet;
238244

239-
let decryption_result = {
245+
// Decrypt RTP packet
246+
let plaintext = {
240247
if rtp_response.is_client {
241248
// println!("CLIENT -> XBOX");
242249
crypto_context.decrypt_rtp(&packet)
@@ -245,26 +252,37 @@ fn main() {
245252
// println!("XBOX -> CLIENT");
246253
crypto_context.decrypt_rtp_as_host(&packet)
247254
}
248-
};
255+
}.expect("Failed to decrypt RTP");
249256

250-
if let Ok(plaintext) = decryption_result {
251-
let mut reader = BufReader::new(&plaintext[..]);
252-
if let Ok(rtp_packet) = rtp::packet::Packet::unmarshal(&mut reader) {
253-
packets::parse_rtp_packet(&rtp_packet);
254-
/*
255-
if let Some(ref mut writer) = buf_writer {
256-
if rtp_packet.header.ssrc == 1026 && rtp_packet.payload[0xC] == 0x4 {
257-
let frame = packets::VideoFrame::unpack(&rtp_packet.payload[..20].try_into().unwrap()).expect("Failed to read VideoFrame");
258-
println!("VideoFrame: {:?}", frame);
259-
// writer.write(&vframe).expect("Failed to write");
257+
match pcap_out_handle.as_mut() {
258+
Some(savefile) => {
259+
// Assemble plaintext packet payload
260+
let datasize_until_ciphertext = pcap_packet.data.len() - (plaintext.len() + AUTH_TAG_LEN);
261+
262+
let mut plaintext_eth_data: Vec<u8> = vec![];
263+
plaintext_eth_data.write(&pcap_packet.data[..datasize_until_ciphertext])
264+
.expect("Failed to write packet data until ciphertext");
265+
plaintext_eth_data.write(&plaintext)
266+
.expect("Failed to write decrypted ciphertext portion");
260267

261-
//return;
262-
}
268+
// Save decrypted RTP packet to pcap out
269+
savefile.write(&pcap::Packet::new(&pcap_packet.header, &plaintext_eth_data));
270+
},
271+
None => {
272+
// Parse & print packet info
273+
let mut reader = BufReader::new(&plaintext[..]);
274+
if let Ok(rtp_packet) = rtp::packet::Packet::unmarshal(&mut reader) {
275+
packets::parse_rtp_packet(&rtp_packet);
263276
}
264-
*/
265277
}
266-
} else {
267-
println!("Failed to decrypt RTP");
278+
}
279+
} else {
280+
// Write non-RTP packet as-is
281+
match pcap_out_handle.as_mut() {
282+
Some(savefile) => {
283+
savefile.write(&pcap_packet)
284+
},
285+
None => {},
268286
}
269287
}
270288
}

0 commit comments

Comments
 (0)