Skip to main content

resynth/stdlib/ipv4/
mod.rs

1use std::net::Ipv4Addr;
2
3use pkt::Packet;
4use pkt::eth::{eth_hdr, ethertype};
5use pkt::ipv4::{ip_hdr, proto};
6
7use ezpkt::IpFrag;
8
9use crate::libapi::{Class, ClassDef, FuncDef, Module};
10use crate::str::Buf;
11use crate::sym::Symbol;
12use crate::val::{Val, ValDef};
13
14mod icmp;
15mod tcp;
16mod udp;
17
18use icmp::ICMP4;
19use tcp::TCP4;
20use udp::UDP4;
21
22const PROTO: Module = module! {
23    /// # IP Protocols
24    resynth mod proto {
25        ICMP => Symbol::u8(proto::ICMP),
26        TCP => Symbol::u8(proto::TCP),
27        UDP => Symbol::u8(proto::UDP),
28        GRE => Symbol::u8(proto::GRE),
29    }
30};
31
32const IPV4_DGRAM_OVERHEAD: usize = std::mem::size_of::<eth_hdr>() + std::mem::size_of::<ip_hdr>();
33
34const DGRAM: FuncDef = func!(
35    /// Create a raw IPv4 header or datagram
36    resynth fn datagram(
37        src: Ip4,
38        dst: Ip4,
39        =>
40        id: U16 = 0,
41        evil: Bool = false,
42        df: Bool = false,
43        mf: Bool = false,
44        ttl: U8 = 64,
45        frag_off: U16 = 0,
46        proto: U8 = proto::UDP,
47        =>
48        Str
49    ) -> Pkt
50    |mut args| {
51        let src: Ipv4Addr = args.next().into();
52        let dst: Ipv4Addr = args.next().into();
53
54        let id: u16 = args.next().into();
55        let evil: bool = args.next().into();
56        let df: bool = args.next().into();
57        let mf: bool = args.next().into();
58        let ttl: u8 = args.next().into();
59        let frag_off: u16 = args.next().into();
60        let proto: u8 = args.next().into();
61
62        let data: Buf = args.join_extra(b"").into();
63
64        let payload_size: u16 = data.len() as u16;
65        let tot_len: u16 = std::mem::size_of::<ip_hdr>() as u16 + payload_size;
66
67        let eth = eth_hdr::new(
68            src.into(),
69            dst.into(),
70            ethertype::IPV4,
71        );
72
73        let mut iph = ip_hdr::default();
74        iph.set_tot_len(tot_len)
75            .set_id(id)
76            .set_evil(evil)
77            .set_df(df)
78            .set_mf(mf)
79            .set_frag_off(frag_off)
80            .set_ttl(ttl)
81            .set_protocol(proto)
82            .set_saddr(src)
83            .set_daddr(dst)
84            .calc_csum();
85
86        let pkt = Packet::with_capacity(IPV4_DGRAM_OVERHEAD + payload_size as usize);
87        pkt.push(eth);
88        pkt.push(iph);
89        pkt.push_bytes(data);
90
91        Ok(Val::from(pkt))
92    }
93);
94
95const FRAG_FRAGMENT: FuncDef = func!(
96    /// Returns an IPv4 packet fragment
97    ///
98    /// ### Arguments
99    /// * `frag_off` Offset in 8-byte blocks
100    /// * `len` Length in bytes
101    /// * 'raw' If true, then omit ethernet header
102    resynth fn fragment(
103        frag_off: U16,
104        len: U16,
105        =>
106        raw: Bool = false,
107        =>
108        Str
109    ) -> Pkt
110    |mut args| {
111        let obj = args.take_this();
112        let mut r = obj.borrow_mut();
113        let this: &mut IpFrag = r.as_mut_any().downcast_mut().unwrap();
114
115        let frag_off: u16 = args.next().into();
116        let len: u16 = args.next().into();
117        let raw: bool = args.next().into();
118
119        Ok(this.fragment(frag_off, len, raw).into())
120    }
121);
122
123const FRAG_TAIL: FuncDef = func!(
124    /// Returns an IPv4 tail-fragment, ie. with MF (more-fragments) bit set to zero.
125    /// This is just a convenience function which omits the len parameter.
126    ///
127    /// ### Arguments
128    /// * `frag_off` Offset in 8-byte blocks
129    /// * 'raw' If true, then omit ethernet header
130    resynth fn tail(
131        frag_off: U16,
132        =>
133        raw: Bool = false,
134        =>
135        Str
136    ) -> Pkt
137    |mut args| {
138        let obj = args.take_this();
139        let mut r = obj.borrow_mut();
140        let this: &mut IpFrag = r.as_mut_any().downcast_mut().unwrap();
141
142        let frag_off: u16 = args.next().into();
143        let raw: bool = args.next().into();
144
145        Ok(this.tail(frag_off, raw).into())
146    }
147);
148
149const FRAG_DATAGRAM: FuncDef = func!(
150    /// Return the entire datagram without fragmenting it
151    ///
152    /// ### Arguments
153    /// * 'raw' If true, then omit ethernet header
154    resynth fn datagram(
155        =>
156        raw: Bool = false,
157        =>
158        Str
159    ) -> Pkt
160    |mut args| {
161        let obj = args.take_this();
162        let mut r = obj.borrow_mut();
163        let this: &mut IpFrag = r.as_mut_any().downcast_mut().unwrap();
164        let raw: bool = args.next().into();
165
166        Ok(this.datagram(raw).into())
167    }
168);
169
170const IPFRAG: ClassDef = class!(
171    /// # IP Packet Fragment Builder
172    resynth class IpFrag {
173        fragment => Symbol::Func(&FRAG_FRAGMENT),
174        tail => Symbol::Func(&FRAG_TAIL),
175        datagram => Symbol::Func(&FRAG_DATAGRAM),
176    }
177);
178
179impl Class for IpFrag {
180    fn def(&self) -> &'static ClassDef {
181        &IPFRAG
182    }
183}
184
185const FRAG: FuncDef = func!(
186    /// Create a context for a packet which can be arbitrarily fragmented
187    resynth fn frag(
188        src: Ip4,
189        dst: Ip4,
190        =>
191        id: U16 = 0,
192        evil: Bool = false,
193        df: Bool = false,
194        ttl: U8 = 64,
195        proto: U8 = proto::UDP,
196        =>
197        Str
198    ) -> Obj
199    |mut args| {
200        let src: Ipv4Addr = args.next().into();
201        let dst: Ipv4Addr = args.next().into();
202
203        let id: u16 = args.next().into();
204        let evil: bool = args.next().into();
205        let df: bool = args.next().into();
206        let ttl: u8 = args.next().into();
207        let proto: u8 = args.next().into();
208
209        let payload: Buf = args.join_extra(b"").into();
210
211        let mut iph: ip_hdr = Default::default();
212        iph
213            .set_id(id)
214            .set_evil(evil)
215            .set_df(df)
216            .set_ttl(ttl)
217            .set_protocol(proto)
218            .set_saddr(src)
219            .set_daddr(dst);
220
221        Ok(Val::from(IpFrag::new(iph, payload.cow_buffer().into())))
222    }
223);
224
225pub const IPV4: Module = module! {
226    /// # Internet Protocol Version 4
227    resynth mod ipv4 {
228        IpFrag => Symbol::Class(&IPFRAG),
229        tcp => Symbol::Module(&TCP4),
230        udp => Symbol::Module(&UDP4),
231        icmp => Symbol::Module(&ICMP4),
232        datagram => Symbol::Func(&DGRAM),
233        frag => Symbol::Func(&FRAG),
234        proto => Symbol::Module(&PROTO),
235    }
236};