pcap_parser/
serialize.rs

1use crate::pcap::*;
2use crate::pcapng::*;
3use cookie_factory::bytes::{le_i32, le_i64, le_u16, le_u32};
4use cookie_factory::combinator::slice;
5use cookie_factory::multi::many_ref;
6use cookie_factory::sequence::tuple;
7use cookie_factory::{gen, GenError, SerializeFn};
8use rusticata_macros::align32;
9use std::borrow::Cow;
10use std::io::Write;
11
12/// Common trait for all serialization functions
13pub trait ToVec {
14    /// Serialize to bytes representation (little-endian).
15    /// Check values and fix all fields before serializing.
16    fn to_vec(&mut self) -> Result<Vec<u8>, GenError> {
17        self.fix();
18        self.to_vec_raw()
19    }
20
21    /// Check and correct all fields: use magic, fix lengths fields and other values if possible.
22    fn fix(&mut self) {}
23
24    /// Serialize to bytes representation (little-endian). Do not check values
25    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError>;
26}
27
28impl ToVec for PcapHeader {
29    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
30        let mut v = Vec::with_capacity(24);
31
32        gen(
33            tuple((
34                le_u32(self.magic_number),
35                le_u16(self.version_major),
36                le_u16(self.version_minor),
37                le_i32(self.thiszone),
38                le_u32(self.sigfigs),
39                le_u32(self.snaplen),
40                le_u32(self.network.0 as u32),
41            )),
42            &mut v,
43        )
44        .map(|res| res.0.to_vec())
45    }
46}
47
48impl ToVec for LegacyPcapBlock<'_> {
49    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
50        let mut v = Vec::with_capacity(self.data.len() + 16);
51
52        gen(
53            tuple((
54                le_u32(self.ts_sec),
55                le_u32(self.ts_usec),
56                le_u32(self.caplen),
57                le_u32(self.origlen),
58                slice(self.data),
59            )),
60            &mut v,
61        )
62        // pcap records have no alignment constraints
63        .map(|res| res.0.to_vec())
64    }
65}
66
67fn padding_for<'a, W: Write + 'a>(unaligned_length: u32) -> impl SerializeFn<W> + 'a {
68    let length = align32!(unaligned_length) - unaligned_length;
69    slice(if length > 0 {
70        &[0, 0, 0, 0][..length as usize]
71    } else {
72        b""
73    })
74}
75
76impl ToVec for PcapNGOption<'_> {
77    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
78        let mut v = Vec::new();
79        gen(pcapngoption_le(self), &mut v).map(|res| res.0.to_vec())
80    }
81}
82
83fn pcapngoption_le<'a, 'b: 'a, W: Write + 'a>(i: &'b PcapNGOption) -> impl SerializeFn<W> + 'a {
84    tuple((
85        le_u16(i.code.0),
86        le_u16(i.len),
87        slice(&i.value),
88        padding_for(i.value.len() as u32),
89    ))
90}
91
92fn options_length(options: &[PcapNGOption]) -> usize {
93    options.iter().map(|o| align32!(4 + o.value.len())).sum()
94}
95
96fn fix_options(options: &mut Vec<PcapNGOption>) {
97    options.retain(|e| e.code != OptionCode::EndOfOpt);
98    if options.is_empty() {
99        // No EndOfOpt is required if there are no options.
100    } else {
101        options.push(PcapNGOption {
102            code: OptionCode::EndOfOpt,
103            len: 0,
104            value: Cow::Borrowed(&[]),
105        })
106    }
107}
108
109impl ToVec for SectionHeaderBlock<'_> {
110    /// Check and correct all fields: use magic, version and fix lengths fields
111    fn fix(&mut self) {
112        self.block_type = SHB_MAGIC;
113        // XXX bom as BE could be valid
114        self.bom = BOM_MAGIC;
115        self.major_version = 1;
116        self.minor_version = 0;
117        fix_options(&mut self.options);
118        // fix length
119        let length = (28 + options_length(&self.options)) as u32;
120        self.block_len1 = length;
121        self.block_len2 = length;
122    }
123
124    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
125        let mut v = Vec::with_capacity(64);
126        gen(
127            tuple((
128                le_u32(self.block_type),
129                le_u32(self.block_len1),
130                le_u32(self.bom),
131                le_u16(self.major_version),
132                le_u16(self.minor_version),
133                le_i64(self.section_len),
134                many_ref(&self.options, pcapngoption_le),
135                le_u32(self.block_len2),
136            )),
137            &mut v,
138        )
139        .map(|res| res.0.to_vec())
140    }
141}
142
143impl ToVec for InterfaceDescriptionBlock<'_> {
144    /// Check and correct all fields: use magic, set time resolution and fix lengths fields
145    fn fix(&mut self) {
146        self.block_type = IDB_MAGIC;
147        self.reserved = 0;
148        // check time resolutopn
149        if !self.options.iter().any(|o| o.code == OptionCode::IfTsresol) {
150            let tsresol_bytes = vec![self.if_tsresol, 0, 0, 0];
151            self.options.push(PcapNGOption {
152                code: OptionCode::IfTsresol,
153                len: 1,
154                value: Cow::Owned(tsresol_bytes),
155            });
156        }
157        if !self
158            .options
159            .iter()
160            .any(|o| o.code == OptionCode::IfTsoffset)
161        {
162            let tsoffset_bytes = self.if_tsoffset.to_le_bytes();
163            self.options.push(PcapNGOption {
164                code: OptionCode::IfTsoffset,
165                len: 8,
166                value: Cow::Owned(tsoffset_bytes.to_vec()),
167            });
168        }
169        fix_options(&mut self.options);
170        // fix length
171        let length = (20 + options_length(&self.options)) as u32;
172        self.block_len1 = length;
173        self.block_len2 = length;
174    }
175
176    /// Serialize to bytes representation. Do not check values
177    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
178        let mut v = Vec::with_capacity(64);
179        gen(
180            tuple((
181                le_u32(self.block_type),
182                le_u32(self.block_len1),
183                le_u16(self.linktype.0 as u16),
184                le_u16(self.reserved),
185                le_u32(self.snaplen),
186                many_ref(&self.options, pcapngoption_le),
187                le_u32(self.block_len2),
188            )),
189            &mut v,
190        )
191        .map(|res| res.0.to_vec())
192    }
193}
194
195impl ToVec for EnhancedPacketBlock<'_> {
196    /// Check and correct all fields: use magic, version and fix lengths fields
197    fn fix(&mut self) {
198        self.block_type = EPB_MAGIC;
199        fix_options(&mut self.options);
200        // fix length
201        let length = (32 + self.data.len() + options_length(&self.options)) as u32;
202        self.block_len1 = align32!(length);
203        self.block_len2 = self.block_len1;
204    }
205
206    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
207        let mut v = Vec::with_capacity(64);
208        gen(
209            tuple((
210                le_u32(self.block_type),
211                le_u32(self.block_len1),
212                le_u32(self.if_id),
213                le_u32(self.ts_high),
214                le_u32(self.ts_low),
215                le_u32(self.caplen),
216                le_u32(self.origlen),
217                slice(self.data),
218                padding_for(self.data.len() as u32),
219                many_ref(&self.options, pcapngoption_le),
220                le_u32(self.block_len2),
221            )),
222            &mut v,
223        )
224        .map(|res| res.0.to_vec())
225    }
226}
227
228impl ToVec for SimplePacketBlock<'_> {
229    fn fix(&mut self) {
230        self.block_type = SPB_MAGIC;
231        // fix length
232        self.block_len1 = (16 + align32!(self.data.len())) as u32;
233        self.block_len2 = self.block_len1;
234    }
235
236    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
237        let mut v = Vec::with_capacity(64);
238        gen(
239            tuple((
240                le_u32(self.block_type),
241                le_u32(self.block_len1),
242                le_u32(self.origlen),
243                slice(self.data),
244                padding_for(self.data.len() as u32),
245                le_u32(self.block_len2),
246            )),
247            &mut v,
248        )
249        .map(|res| res.0.to_vec())
250    }
251}
252
253fn namerecord_le<'a, 'b: 'a, W: Write + 'a>(i: &'b NameRecord) -> impl SerializeFn<W> + 'a {
254    tuple((
255        le_u16(i.record_type.0),
256        le_u16(i.record_value.len() as u16),
257        slice(i.record_value),
258    ))
259}
260
261fn namerecords_length(nr: &[NameRecord]) -> usize {
262    nr.iter().map(|n| align32!(2 + n.record_value.len())).sum()
263}
264
265impl ToVec for NameResolutionBlock<'_> {
266    fn fix(&mut self) {
267        self.block_type = NRB_MAGIC;
268        fix_options(&mut self.options);
269        // fix length
270        let length = (12 + namerecords_length(&self.nr) + options_length(&self.options)) as u32;
271        self.block_len1 = align32!(length);
272        self.block_len2 = self.block_len1;
273    }
274
275    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
276        let mut v = Vec::with_capacity(64);
277        gen(
278            tuple((
279                le_u32(self.block_type),
280                le_u32(self.block_len1),
281                many_ref(&self.nr, namerecord_le),
282                many_ref(&self.options, pcapngoption_le),
283                le_u32(self.block_len2),
284            )),
285            &mut v,
286        )
287        .map(|res| res.0.to_vec())
288    }
289}
290
291impl ToVec for InterfaceStatisticsBlock<'_> {
292    fn fix(&mut self) {
293        self.block_type = ISB_MAGIC;
294        fix_options(&mut self.options);
295        // fix length
296        self.block_len1 = (24 + align32!(options_length(&self.options))) as u32;
297        self.block_len2 = self.block_len1;
298    }
299
300    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
301        let mut v = Vec::with_capacity(64);
302        gen(
303            tuple((
304                le_u32(self.block_type),
305                le_u32(self.block_len1),
306                le_u32(self.if_id),
307                le_u32(self.ts_high),
308                le_u32(self.ts_low),
309                many_ref(&self.options, pcapngoption_le),
310                le_u32(self.block_len2),
311            )),
312            &mut v,
313        )
314        .map(|res| res.0.to_vec())
315    }
316}
317
318impl ToVec for SystemdJournalExportBlock<'_> {
319    fn fix(&mut self) {
320        if self.block_type != SJE_MAGIC {
321            self.block_type = SJE_MAGIC;
322        }
323        // fix length
324        self.block_len1 = (12 + align32!(self.data.len())) as u32;
325        self.block_len2 = self.block_len1;
326    }
327
328    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
329        let mut v = Vec::with_capacity(64);
330        gen(
331            tuple((
332                le_u32(self.block_type),
333                le_u32(self.block_len1),
334                slice(self.data),
335                padding_for(self.data.len() as u32),
336                le_u32(self.block_len2),
337            )),
338            &mut v,
339        )
340        .map(|res| res.0.to_vec())
341    }
342}
343
344impl ToVec for DecryptionSecretsBlock<'_> {
345    fn fix(&mut self) {
346        if self.block_type != DSB_MAGIC {
347            self.block_type = DSB_MAGIC;
348        }
349        fix_options(&mut self.options);
350        // fix length
351        self.block_len1 =
352            (20 + align32!(options_length(&self.options)) + align32!(self.data.len())) as u32;
353        self.block_len2 = self.block_len1;
354    }
355
356    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
357        let mut v = Vec::with_capacity(64);
358        gen(
359            tuple((
360                le_u32(self.block_type),
361                le_u32(self.block_len1),
362                le_u32(self.secrets_type.0),
363                le_u32(self.secrets_len),
364                slice(self.data),
365                padding_for(self.data.len() as u32),
366                many_ref(&self.options, pcapngoption_le),
367                le_u32(self.block_len2),
368            )),
369            &mut v,
370        )
371        .map(|res| res.0.to_vec())
372    }
373}
374
375impl ToVec for ProcessInformationBlock<'_> {
376    /// Check and correct all fields: use magic, version and fix lengths fields
377    fn fix(&mut self) {
378        self.block_type = PIB_MAGIC;
379        fix_options(&mut self.options);
380        // fix length
381        let length = (16 + options_length(&self.options)) as u32;
382        self.block_len1 = align32!(length);
383        self.block_len2 = self.block_len1;
384    }
385
386    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
387        let mut v = Vec::with_capacity(64);
388        gen(
389            tuple((
390                le_u32(self.block_type),
391                le_u32(self.block_len1),
392                le_u32(self.process_id),
393                many_ref(&self.options, pcapngoption_le),
394                le_u32(self.block_len2),
395            )),
396            &mut v,
397        )
398        .map(|res| res.0.to_vec())
399    }
400}
401
402impl ToVec for CustomBlock<'_> {
403    fn fix(&mut self) {
404        if self.block_type != DCB_MAGIC && self.block_type != CB_MAGIC {
405            self.block_type = CB_MAGIC;
406        }
407        // fix length
408        self.block_len1 = (16 + align32!(self.data.len())) as u32;
409        self.block_len2 = self.block_len1;
410    }
411
412    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
413        let mut v = Vec::with_capacity(64);
414        gen(
415            tuple((
416                le_u32(self.block_type),
417                le_u32(self.block_len1),
418                le_u32(self.pen),
419                slice(self.data),
420                padding_for(self.data.len() as u32),
421                le_u32(self.block_len2),
422            )),
423            &mut v,
424        )
425        .map(|res| res.0.to_vec())
426    }
427}
428
429impl ToVec for UnknownBlock<'_> {
430    fn fix(&mut self) {
431        // do not touch type, it is unknown
432        // fix length
433        self.block_len1 = (12 + align32!(self.data.len())) as u32;
434        self.block_len2 = self.block_len1;
435    }
436
437    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
438        let mut v = Vec::new();
439        gen(
440            tuple((
441                le_u32(self.block_type),
442                le_u32(self.block_len1),
443                slice(self.data),
444                padding_for(self.data.len() as u32),
445                le_u32(self.block_len2),
446            )),
447            &mut v,
448        )
449        .map(|res| res.0.to_vec())
450    }
451}
452
453impl ToVec for Block<'_> {
454    fn fix(&mut self) {
455        match self {
456            Block::SectionHeader(b) => b.fix(),
457            Block::InterfaceDescription(b) => b.fix(),
458            Block::EnhancedPacket(b) => b.fix(),
459            Block::SimplePacket(b) => b.fix(),
460            Block::NameResolution(b) => b.fix(),
461            Block::InterfaceStatistics(b) => b.fix(),
462            Block::SystemdJournalExport(b) => b.fix(),
463            Block::DecryptionSecrets(b) => b.fix(),
464            Block::ProcessInformation(b) => b.fix(),
465            Block::Custom(b) => b.fix(),
466            Block::Unknown(b) => b.fix(),
467        }
468    }
469
470    fn to_vec_raw(&self) -> Result<Vec<u8>, GenError> {
471        match self {
472            Block::SectionHeader(b) => b.to_vec_raw(),
473            Block::InterfaceDescription(b) => b.to_vec_raw(),
474            Block::EnhancedPacket(b) => b.to_vec_raw(),
475            Block::SimplePacket(b) => b.to_vec_raw(),
476            Block::NameResolution(b) => b.to_vec_raw(),
477            Block::InterfaceStatistics(b) => b.to_vec_raw(),
478            Block::SystemdJournalExport(b) => b.to_vec_raw(),
479            Block::DecryptionSecrets(b) => b.to_vec_raw(),
480            Block::ProcessInformation(b) => b.to_vec_raw(),
481            Block::Custom(b) => b.to_vec_raw(),
482            Block::Unknown(b) => b.to_vec_raw(),
483        }
484    }
485}
486
487#[cfg(test)]
488mod tests {
489    use std::borrow::Cow;
490
491    use crate::pcap::tests::PCAP_HDR;
492    use crate::pcap::{parse_pcap_frame, parse_pcap_header};
493    use crate::pcapng::*;
494    use crate::serialize::ToVec;
495    use crate::traits::tests::{
496        FRAME_PCAP, FRAME_PCAPNG_DSB, FRAME_PCAPNG_EPB, FRAME_PCAPNG_EPB_WITH_OPTIONS,
497        FRAME_PCAPNG_SHB,
498    };
499    use crate::Linktype;
500
501    #[test]
502    fn test_serialize_pcap_header() {
503        let (rem, hdr) = parse_pcap_header(PCAP_HDR).expect("header parsing failed");
504        assert!(rem.is_empty());
505        assert_eq!(hdr.magic_number, 0xa1b2_c3d4);
506        assert_eq!(hdr.version_major, 2);
507        assert_eq!(hdr.version_minor, 4);
508        assert_eq!(hdr.snaplen, 262_144);
509        let v = hdr.to_vec_raw().expect("serialize");
510        assert_eq!(v.len(), PCAP_HDR.len());
511        assert_eq!(v, PCAP_HDR);
512    }
513    #[test]
514    fn test_serialize_pcap_frame() {
515        let (rem, pkt) = parse_pcap_frame(FRAME_PCAP).expect("packet parsing failed");
516        assert!(rem.is_empty());
517        assert_eq!(pkt.origlen, 74);
518        assert_eq!(pkt.ts_usec, 562_913);
519        assert_eq!(pkt.ts_sec, 1_515_933_236);
520        let v = pkt.to_vec_raw().expect("serialize");
521        println!("self.data.len: {}", pkt.data.len());
522        assert_eq!(v.len(), FRAME_PCAP.len());
523        assert_eq!(v, FRAME_PCAP);
524    }
525
526    fn frame_should_not_be_fixed(frame: &[u8]) {
527        let (rem, mut pkt) = parse_block_le(frame).expect("packet parsing failed");
528        assert!(rem.is_empty());
529        assert_eq!(pkt.to_vec().unwrap(), frame);
530    }
531
532    #[test]
533    fn test_dsb_not_fixed() {
534        frame_should_not_be_fixed(FRAME_PCAPNG_DSB);
535    }
536    #[test]
537    fn test_epb_not_fixed() {
538        frame_should_not_be_fixed(FRAME_PCAPNG_EPB);
539    }
540    #[test]
541    fn test_epb_with_options_not_fixed() {
542        frame_should_not_be_fixed(FRAME_PCAPNG_EPB_WITH_OPTIONS);
543    }
544    #[test]
545    fn test_shb_not_fixed() {
546        frame_should_not_be_fixed(FRAME_PCAPNG_SHB);
547    }
548
549    #[test]
550    fn test_serialize_shb() {
551        let shb = SectionHeaderBlock {
552            block_type: SHB_MAGIC,
553            block_len1: 28,
554            bom: BOM_MAGIC,
555            major_version: 1,
556            minor_version: 0,
557            section_len: -1,
558            options: Vec::new(),
559            block_len2: 28,
560        };
561        let v = shb.to_vec_raw().expect("serialize");
562        // println!("shb.to_vec_raw: {:?}", v);
563        let res = parse_sectionheaderblock_le(&v);
564        assert!(res.is_ok());
565    }
566    #[test]
567    fn test_serialize_shb_fix() {
568        let mut shb = SectionHeaderBlock {
569            block_type: 0,
570            block_len1: 0,
571            bom: 0,
572            major_version: 0,
573            minor_version: 0,
574            section_len: -1,
575            options: vec![
576                // Unaligned option length
577                PcapNGOption {
578                    code: OptionCode::ShbUserAppl,
579                    len: 5,
580                    value: Cow::Borrowed(b"meows"),
581                },
582                // Missing endofopt
583            ],
584            block_len2: 0,
585        };
586
587        let v = shb.to_vec().expect("serialize");
588        // println!("shb.to_vec_raw: {:?}", v);
589        let res = parse_sectionheaderblock_le(&v);
590        // println!("res: {:?}", res);
591        res.unwrap();
592    }
593    #[test]
594    fn test_serialize_shb_options() {
595        let shb = SectionHeaderBlock {
596            block_type: SHB_MAGIC,
597            block_len1: 28 + 8,
598            bom: BOM_MAGIC,
599            major_version: 1,
600            minor_version: 0,
601            section_len: -1,
602            options: vec![PcapNGOption {
603                code: OptionCode(0),
604                len: 3,
605                value: Cow::Borrowed(&[0, 0, 0, 0]),
606            }],
607            block_len2: 28 + 8,
608        };
609        let v = shb.to_vec_raw().expect("serialize");
610        // println!("shb.to_vec_raw: {:?}", v);
611        let res = parse_sectionheaderblock_le(&v);
612        // println!("res: {:?}", res);
613        assert!(res.is_ok());
614    }
615    #[test]
616    fn test_serialize_idb() {
617        let mut idb = InterfaceDescriptionBlock {
618            block_type: IDB_MAGIC,
619            block_len1: 20,
620            linktype: Linktype::RAW,
621            reserved: 0,
622            snaplen: 65535,
623            options: vec![],
624            block_len2: 20,
625            if_tsresol: 6,
626            if_tsoffset: 0,
627        };
628        let v = idb.to_vec().expect("serialize");
629        // println!("idb.to_vec: {:?}", v);
630        let res = parse_interfacedescriptionblock_le(&v);
631        assert!(res.is_ok());
632    }
633    #[test]
634    fn test_serialize_epb() {
635        let (rem, pkt) = parse_block_le(FRAME_PCAPNG_EPB).expect("packet creation failed");
636        assert!(rem.is_empty());
637        if let Block::EnhancedPacket(mut epb) = pkt {
638            let v = epb.to_vec().expect("serialize");
639            // NOTE: v and FRAME_PCAPNG_EPB are different (interface id changes)
640            // println!("epb.to_vec: {:?}", v);
641            let res = parse_enhancedpacketblock_le(&v);
642            assert!(res.is_ok());
643        }
644    }
645    #[test]
646    fn test_serialize_epb_with_options() {
647        let (rem, pkt) =
648            parse_block_le(FRAME_PCAPNG_EPB_WITH_OPTIONS).expect("packet creation failed");
649        assert!(rem.is_empty());
650        if let Block::EnhancedPacket(mut epb) = pkt {
651            let v = epb.to_vec().expect("serialize");
652            // println!("epb.to_vec: {:?}", v);
653            let res = parse_enhancedpacketblock_le(&v);
654            assert!(res.is_ok());
655        }
656    }
657    #[test]
658    fn test_serialize_dsb() {
659        let (rem, pkt) = parse_block_le(FRAME_PCAPNG_DSB).expect("packet creation failed");
660        assert!(rem.is_empty());
661        assert!(pkt.magic() == DSB_MAGIC);
662        if let Block::DecryptionSecrets(mut dsb) = pkt {
663            let v = dsb.to_vec().expect("serialize");
664            let res = parse_decryptionsecretsblock_le(&v);
665            assert!(res.is_ok());
666        }
667    }
668}