1use nom::bytes::streaming::take;
2use nom::combinator::{cond, map, map_parser, rest};
3use nom::error::{make_error, ErrorKind};
4use nom::multi::count;
5use nom::number::streaming::{be_u16, be_u32, be_u64, be_u8};
6use nom::{Err, IResult};
7use rusticata_macros::newtype_enum;
8
9#[derive(Debug, PartialEq)]
11pub struct OpenVPNPacket<'a> {
12 pub hdr: OpenVPNHdr,
13 pub msg: Payload<'a>,
14}
15
16#[derive(Debug, PartialEq)]
20pub struct OpenVPNHdr {
21 pub plen: Option<u16>,
23 pub opcode: Opcode,
24 pub key: u8,
25}
26
27#[derive(Copy, Clone, PartialEq, Eq)]
28pub struct Opcode(pub u8);
29
30newtype_enum! {
31impl debug Opcode {
32 P_CONTROL_HARD_RESET_CLIENT_V1 = 0x1,
33 P_CONTROL_HARD_RESET_SERVER_V1 = 0x2,
34 P_CONTROL_SOFT_RESET_V1 = 0x3,
35 P_CONTROL_V1 = 0x4,
36 P_ACK_V1 = 0x5,
37 P_DATA_V1 = 0x6,
38 P_CONTROL_HARD_RESET_CLIENT_V2 = 0x7,
39 P_CONTROL_HARD_RESET_SERVER_V2 = 0x8,
40 P_DATA_V2 = 0x9,
41}
42}
43
44#[derive(Debug, PartialEq)]
46pub enum Payload<'a> {
47 Control(PControl<'a>),
48 Ack(PAck<'a>),
49 Data(PData<'a>),
50}
51
52#[derive(Debug, PartialEq)]
54pub struct PControl<'a> {
55 pub session_id: u64,
56 pub hmac: &'a [u8],
58 pub packet_id: u32,
60 pub net_time: u32,
62 pub msg_ar_len: u8,
63 pub msg_ar: Option<Vec<u32>>,
64 pub msg_packet_id: u32,
65 pub remote_session_id: Option<u64>,
66 pub payload: &'a [u8],
67}
68
69#[derive(Debug, PartialEq)]
71pub struct PAck<'a> {
72 pub session_id: u64,
73 pub hmac: &'a [u8],
75 pub packet_id: u32,
77 pub net_time: u32,
79 pub msg_ar_len: u8,
80 pub msg_ar: Option<Vec<u32>>,
81 pub remote_session_id: Option<u64>,
82}
83
84#[derive(Debug, PartialEq)]
88pub struct PData<'a> {
89 pub contents: &'a [u8],
90}
91
92pub fn parse_openvpn_tcp(i: &[u8]) -> IResult<&[u8], OpenVPNPacket> {
94 let (i, hdr) = parse_openvpn_header_tcp(i)?;
95 let plen = match hdr.plen {
98 Some(plen) if plen >= 2 => plen,
99 _ => return Err(Err::Error(make_error(i, ErrorKind::LengthValue))),
100 };
101 let (i, msg) = map_parser(take(plen - 1), parse_openvpn_msg_payload(hdr.opcode))(i)?;
102 Ok((i, OpenVPNPacket { hdr, msg }))
103}
104
105pub fn parse_openvpn_udp(i: &[u8]) -> IResult<&[u8], OpenVPNPacket> {
109 let (i, hdr) = parse_openvpn_header_udp(i)?;
110 let (i, msg) = parse_openvpn_msg_payload(hdr.opcode)(i)?;
111 Ok((i, OpenVPNPacket { hdr, msg }))
112}
113
114pub fn parse_openvpn_header_tcp(i: &[u8]) -> IResult<&[u8], OpenVPNHdr> {
115 let (i, plen) = be_u16(i)?;
116 let (i, opcode_and_key) = be_u8(i)?;
117 let opcode = Opcode(opcode_and_key >> 3);
119 let key = opcode_and_key & 0b111;
120 let hdr = OpenVPNHdr {
121 plen: Some(plen),
122 opcode,
123 key,
124 };
125 Ok((i, hdr))
126}
127
128pub fn parse_openvpn_header_udp(i: &[u8]) -> IResult<&[u8], OpenVPNHdr> {
129 let (i, opcode_and_key) = be_u8(i)?;
130 let opcode = Opcode(opcode_and_key >> 3);
132 let key = opcode_and_key & 0b111;
133 let hdr = OpenVPNHdr {
134 plen: None,
135 opcode,
136 key,
137 };
138 Ok((i, hdr))
139}
140
141pub fn parse_openvpn_msg_payload(msg_type: Opcode) -> impl FnMut(&[u8]) -> IResult<&[u8], Payload> {
142 move |i| match msg_type {
143 Opcode::P_CONTROL_HARD_RESET_CLIENT_V1
144 | Opcode::P_CONTROL_HARD_RESET_SERVER_V1
145 | Opcode::P_CONTROL_SOFT_RESET_V1
146 | Opcode::P_CONTROL_V1
147 | Opcode::P_CONTROL_HARD_RESET_CLIENT_V2
148 | Opcode::P_CONTROL_HARD_RESET_SERVER_V2 => {
149 map(parse_openvpn_msg_pcontrol, Payload::Control)(i)
150 }
151 Opcode::P_ACK_V1 => map(parse_openvpn_msg_pack, Payload::Ack)(i),
152 Opcode::P_DATA_V1 | Opcode::P_DATA_V2 => {
153 map(rest, |x| Payload::Data(PData { contents: x }))(i)
154 }
155 _ => Err(::nom::Err::Error(make_error(i, ErrorKind::Tag))),
156 }
157}
158
159pub fn parse_openvpn_msg_pcontrol(i: &[u8]) -> IResult<&[u8], PControl> {
160 let (i, session_id) = be_u64(i)?;
161 let (i, hmac) = take(20usize)(i)?;
162 let (i, packet_id) = be_u32(i)?;
163 let (i, net_time) = be_u32(i)?;
164 let (i, msg_ar_len) = be_u8(i)?;
165 let (i, msg_ar) = cond(msg_ar_len > 0, count(be_u32, msg_ar_len as usize))(i)?;
166 let (i, remote_session_id) = cond(msg_ar_len > 0, be_u64)(i)?;
167 let (i, msg_packet_id) = be_u32(i)?;
168 let (i, payload) = rest(i)?;
169 let pcontrol = PControl {
170 session_id,
171 hmac,
172 packet_id,
173 net_time,
174 msg_ar_len,
175 msg_ar,
176 remote_session_id,
177 msg_packet_id,
178 payload,
179 };
180 Ok((i, pcontrol))
181}
182
183pub fn parse_openvpn_msg_pack(i: &[u8]) -> IResult<&[u8], PAck> {
184 let (i, session_id) = be_u64(i)?;
185 let (i, hmac) = take(20usize)(i)?;
186 let (i, packet_id) = be_u32(i)?;
187 let (i, net_time) = be_u32(i)?;
188 let (i, msg_ar_len) = be_u8(i)?;
189 let (i, msg_ar) = cond(msg_ar_len > 0, count(be_u32, msg_ar_len as usize))(i)?;
190 let (i, remote_session_id) = cond(msg_ar_len > 0, be_u64)(i)?;
191 let pack = PAck {
192 session_id,
193 hmac,
194 packet_id,
195 net_time,
196 msg_ar_len,
197 msg_ar,
198 remote_session_id,
199 };
200 Ok((i, pack))
201}