]> git.ipfire.org Git - people/ms/suricata.git/blame - rust/src/snmp/snmp.rs
app-layer: include DetectEngineState in AppLayerTxData
[people/ms/suricata.git] / rust / src / snmp / snmp.rs
CommitLineData
2f5834cd 1/* Copyright (C) 2017-2020 Open Information Security Foundation
2df840a8
PC
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18// written by Pierre Chifflier <chifflier@wzdftpd.net>
19
42e5065a 20use crate::snmp::snmp_parser::*;
baf30cfc 21use crate::core::{self, *};
2f5834cd 22use crate::applayer::{self, *};
2df840a8 23use std;
18448f6e 24use std::ffi::CString;
2df840a8 25
5b809f77
PC
26use der_parser::ber::BerObjectContent;
27use der_parser::der::parse_der_sequence;
2df840a8
PC
28use der_parser::oid::Oid;
29use nom;
5b809f77
PC
30use nom::IResult;
31use nom::error::ErrorKind;
2df840a8 32
18448f6e 33#[derive(AppLayerEvent)]
2df840a8 34pub enum SNMPEvent {
18448f6e 35 MalformedData,
2df840a8 36 UnknownSecurityModel,
af7d245a 37 VersionMismatch,
2df840a8
PC
38}
39
6b8517dc 40pub struct SNMPState<'a> {
2df840a8
PC
41 /// SNMP protocol version
42 pub version: u32,
43
44 /// List of transactions for this session
6b8517dc 45 transactions: Vec<SNMPTransaction<'a>>,
2df840a8
PC
46
47 /// tx counter for assigning incrementing id's to tx's
48 tx_id: u64,
49}
50
6b8517dc 51pub struct SNMPPduInfo<'a> {
2df840a8
PC
52 pub pdu_type: PduType,
53
54 pub err: ErrorStatus,
55
6b8517dc 56 pub trap_type: Option<(TrapType,Oid<'a>,NetworkAddress)>,
2df840a8 57
6b8517dc 58 pub vars: Vec<Oid<'a>>,
2df840a8
PC
59}
60
6b8517dc 61pub struct SNMPTransaction<'a> {
aa608e0c
PC
62 /// PDU version
63 pub version: u32,
64
2df840a8 65 /// PDU info, if present (and cleartext)
6b8517dc 66 pub info: Option<SNMPPduInfo<'a>>,
2df840a8
PC
67
68 /// Community, if present (SNMPv2)
69 pub community: Option<String>,
70
71 /// USM info, if present (SNMPv3)
72 pub usm: Option<String>,
73
74 /// True if transaction was encrypted
75 pub encrypted: bool,
76
77 /// The internal transaction id
78 id: u64,
79
2df840a8
PC
80 /// The events associated with this transaction
81 events: *mut core::AppLayerDecoderEvents,
82
11e24345 83 tx_data: applayer::AppLayerTxData,
2df840a8
PC
84}
85
3f2d2bc1
JI
86impl<'a> Transaction for SNMPTransaction<'a> {
87 fn id(&self) -> u64 {
88 self.id
89 }
90}
2df840a8 91
6b8517dc
ET
92impl<'a> SNMPState<'a> {
93 pub fn new() -> SNMPState<'a> {
2df840a8
PC
94 SNMPState{
95 version: 0,
96 transactions: Vec::new(),
97 tx_id: 0,
98 }
99 }
100}
101
6b8517dc
ET
102impl<'a> Default for SNMPPduInfo<'a> {
103 fn default() -> SNMPPduInfo<'a> {
2df840a8
PC
104 SNMPPduInfo{
105 pdu_type: PduType(0),
106 err: ErrorStatus::NoError,
107 trap_type: None,
108 vars: Vec::new()
109 }
110 }
111}
112
3f2d2bc1
JI
113impl<'a> State<SNMPTransaction<'a>> for SNMPState<'a> {
114 fn get_transactions(&self) -> &[SNMPTransaction<'a>] {
115 &self.transactions
116 }
117}
118
6b8517dc
ET
119impl<'a> SNMPState<'a> {
120 fn add_pdu_info(&mut self, pdu: &SnmpPdu<'a>, tx: &mut SNMPTransaction<'a>) {
2df840a8
PC
121 let mut pdu_info = SNMPPduInfo::default();
122 pdu_info.pdu_type = pdu.pdu_type();
60324740 123 match *pdu {
2df840a8
PC
124 SnmpPdu::Generic(ref pdu) => {
125 pdu_info.err = pdu.err;
126 },
127 SnmpPdu::Bulk(_) => {
128 },
129 SnmpPdu::TrapV1(ref t) => {
ac3a20b6 130 pdu_info.trap_type = Some((t.generic_trap,t.enterprise.clone(),t.agent_addr));
2df840a8
PC
131 }
132 }
6b8517dc
ET
133
134 for var in pdu.vars_iter() {
135 pdu_info.vars.push(var.oid.to_owned());
2df840a8
PC
136 }
137 tx.info = Some(pdu_info);
138 }
139
baf30cfc 140 fn handle_snmp_v12(&mut self, msg: SnmpMessage<'a>, _direction: Direction) -> i32 {
1880f694 141 let mut tx = self.new_tx();
af7d245a
PC
142 // in the message, version is encoded as 0 (version 1) or 1 (version 2)
143 if self.version != msg.version + 1 {
144 SCLogDebug!("SNMP version mismatch: expected {}, received {}", self.version, msg.version+1);
145 self.set_event_tx(&mut tx, SNMPEvent::VersionMismatch);
146 }
1880f694 147 self.add_pdu_info(&msg.pdu, &mut tx);
ac3a20b6 148 tx.community = Some(msg.community);
1880f694
PC
149 self.transactions.push(tx);
150 0
2df840a8
PC
151 }
152
baf30cfc 153 fn handle_snmp_v3(&mut self, msg: SnmpV3Message<'a>, _direction: Direction) -> i32 {
1880f694 154 let mut tx = self.new_tx();
af7d245a
PC
155 if self.version != msg.version {
156 SCLogDebug!("SNMP version mismatch: expected {}, received {}", self.version, msg.version);
157 self.set_event_tx(&mut tx, SNMPEvent::VersionMismatch);
158 }
1880f694
PC
159 match msg.data {
160 ScopedPduData::Plaintext(pdu) => {
161 self.add_pdu_info(&pdu.data, &mut tx);
2df840a8 162 },
1880f694
PC
163 _ => {
164 tx.encrypted = true;
165 }
166 }
167 match msg.security_params {
168 SecurityParameters::USM(usm) => {
ac3a20b6 169 tx.usm = Some(usm.msg_user_name);
2df840a8 170 },
1880f694
PC
171 _ => {
172 self.set_event_tx(&mut tx, SNMPEvent::UnknownSecurityModel);
173 }
2df840a8 174 }
1880f694
PC
175 self.transactions.push(tx);
176 0
2df840a8
PC
177 }
178
179 /// Parse an SNMP request message
180 ///
44d3f264 181 /// Returns 0 if successful, or -1 on error
baf30cfc 182 fn parse(&mut self, i: &'a [u8], direction: Direction) -> i32 {
2df840a8
PC
183 if self.version == 0 {
184 match parse_pdu_enveloppe_version(i) {
185 Ok((_,x)) => self.version = x,
186 _ => (),
187 }
188 }
1880f694
PC
189 match parse_snmp_generic_message(i) {
190 Ok((_rem,SnmpGenericMessage::V1(msg))) |
191 Ok((_rem,SnmpGenericMessage::V2(msg))) => self.handle_snmp_v12(msg, direction),
192 Ok((_rem,SnmpGenericMessage::V3(msg))) => self.handle_snmp_v3(msg, direction),
ef575533
PA
193 Err(_e) => {
194 SCLogDebug!("parse_snmp failed: {:?}", _e);
1880f694
PC
195 self.set_event(SNMPEvent::MalformedData);
196 -1
197 },
2df840a8
PC
198 }
199 }
200
201 fn free(&mut self) {
202 // All transactions are freed when the `transactions` object is freed.
203 // But let's be explicit
204 self.transactions.clear();
205 }
206
6b8517dc 207 fn new_tx(&mut self) -> SNMPTransaction<'a> {
2df840a8 208 self.tx_id += 1;
aa608e0c 209 SNMPTransaction::new(self.version, self.tx_id)
2df840a8
PC
210 }
211
212 fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&SNMPTransaction> {
57b233f4 213 self.transactions.iter().rev().find(|&tx| tx.id == tx_id + 1)
2df840a8
PC
214 }
215
216 fn free_tx(&mut self, tx_id: u64) {
69cf5c9e 217 let tx = self.transactions.iter().position(|tx| tx.id == tx_id + 1);
2df840a8
PC
218 debug_assert!(tx != None);
219 if let Some(idx) = tx {
220 let _ = self.transactions.remove(idx);
221 }
222 }
223
224 /// Set an event. The event is set on the most recent transaction.
225 fn set_event(&mut self, event: SNMPEvent) {
226 if let Some(tx) = self.transactions.last_mut() {
227 let ev = event as u8;
228 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev);
229 }
230 }
231
232 /// Set an event on a specific transaction.
233 fn set_event_tx(&self, tx: &mut SNMPTransaction, event: SNMPEvent) {
234 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, event as u8);
235 }
2df840a8
PC
236}
237
6b8517dc
ET
238impl<'a> SNMPTransaction<'a> {
239 pub fn new(version: u32, id: u64) -> SNMPTransaction<'a> {
2df840a8 240 SNMPTransaction {
aa608e0c 241 version,
2df840a8
PC
242 info: None,
243 community: None,
244 usm: None,
245 encrypted: false,
246 id: id,
2df840a8 247 events: std::ptr::null_mut(),
11e24345 248 tx_data: applayer::AppLayerTxData::new(),
2df840a8
PC
249 }
250 }
251
252 fn free(&mut self) {
922a453d 253 if !self.events.is_null() {
2df840a8
PC
254 core::sc_app_layer_decoder_events_free_events(&mut self.events);
255 }
256 }
257}
258
6b8517dc 259impl<'a> Drop for SNMPTransaction<'a> {
2df840a8
PC
260 fn drop(&mut self) {
261 self.free();
262 }
263}
264
265
266
267
268
269
270/// Returns *mut SNMPState
271#[no_mangle]
547d6c2d 272pub extern "C" fn rs_snmp_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void {
2df840a8
PC
273 let state = SNMPState::new();
274 let boxed = Box::new(state);
53413f2d 275 return Box::into_raw(boxed) as *mut _;
2df840a8
PC
276}
277
278/// Params:
279/// - state: *mut SNMPState as void pointer
280#[no_mangle]
643864a8 281pub extern "C" fn rs_snmp_state_free(state: *mut std::os::raw::c_void) {
53413f2d 282 let mut snmp_state = unsafe{ Box::from_raw(state as *mut SNMPState) };
2df840a8
PC
283 snmp_state.free();
284}
285
286#[no_mangle]
363b5f99 287pub unsafe extern "C" fn rs_snmp_parse_request(_flow: *const core::Flow,
643864a8
JL
288 state: *mut std::os::raw::c_void,
289 _pstate: *mut std::os::raw::c_void,
c1b30fe9 290 input: *const u8,
2df840a8 291 input_len: u32,
643864a8 292 _data: *const std::os::raw::c_void,
44d3f264 293 _flags: u8) -> AppLayerResult {
2df840a8
PC
294 let buf = build_slice!(input,input_len as usize);
295 let state = cast_pointer!(state,SNMPState);
baf30cfc 296 state.parse(buf, Direction::ToServer).into()
2df840a8
PC
297}
298
299#[no_mangle]
363b5f99 300pub unsafe extern "C" fn rs_snmp_parse_response(_flow: *const core::Flow,
643864a8
JL
301 state: *mut std::os::raw::c_void,
302 _pstate: *mut std::os::raw::c_void,
c1b30fe9 303 input: *const u8,
2df840a8 304 input_len: u32,
643864a8 305 _data: *const std::os::raw::c_void,
44d3f264 306 _flags: u8) -> AppLayerResult {
2df840a8
PC
307 let buf = build_slice!(input,input_len as usize);
308 let state = cast_pointer!(state,SNMPState);
baf30cfc 309 state.parse(buf, Direction::ToClient).into()
2df840a8
PC
310}
311
312#[no_mangle]
363b5f99 313pub unsafe extern "C" fn rs_snmp_state_get_tx(state: *mut std::os::raw::c_void,
c1b30fe9 314 tx_id: u64)
643864a8 315 -> *mut std::os::raw::c_void
2df840a8
PC
316{
317 let state = cast_pointer!(state,SNMPState);
318 match state.get_tx_by_id(tx_id) {
53413f2d 319 Some(tx) => tx as *const _ as *mut _,
2df840a8
PC
320 None => std::ptr::null_mut(),
321 }
322}
323
324#[no_mangle]
363b5f99 325pub unsafe extern "C" fn rs_snmp_state_get_tx_count(state: *mut std::os::raw::c_void)
c1b30fe9 326 -> u64
2df840a8
PC
327{
328 let state = cast_pointer!(state,SNMPState);
329 state.tx_id
330}
331
332#[no_mangle]
363b5f99 333pub unsafe extern "C" fn rs_snmp_state_tx_free(state: *mut std::os::raw::c_void,
c1b30fe9 334 tx_id: u64)
2df840a8
PC
335{
336 let state = cast_pointer!(state,SNMPState);
337 state.free_tx(tx_id);
338}
339
2df840a8 340#[no_mangle]
643864a8 341pub extern "C" fn rs_snmp_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void,
c1b30fe9 342 _direction: u8)
643864a8 343 -> std::os::raw::c_int
2df840a8
PC
344{
345 1
346}
347
2df840a8 348#[no_mangle]
363b5f99 349pub unsafe extern "C" fn rs_snmp_state_get_events(tx: *mut std::os::raw::c_void)
643864a8 350 -> *mut core::AppLayerDecoderEvents
2df840a8 351{
643864a8
JL
352 let tx = cast_pointer!(tx, SNMPTransaction);
353 return tx.events;
2df840a8
PC
354}
355
2df840a8
PC
356static mut ALPROTO_SNMP : AppProto = ALPROTO_UNKNOWN;
357
358// Read PDU sequence and extract version, if similar to SNMP definition
359fn parse_pdu_enveloppe_version(i:&[u8]) -> IResult<&[u8],u32> {
360 match parse_der_sequence(i) {
361 Ok((_,x)) => {
362 match x.content {
5b809f77 363 BerObjectContent::Sequence(ref v) => {
2df840a8
PC
364 if v.len() == 3 {
365 match v[0].as_u32() {
366 Ok(0) => { return Ok((i,1)); }, // possibly SNMPv1
367 Ok(1) => { return Ok((i,2)); }, // possibly SNMPv2c
368 _ => ()
369 }
370 } else if v.len() == 4 && v[0].as_u32() == Ok(3) {
371 return Ok((i,3)); // possibly SNMPv3
372 }
373 },
374 _ => ()
375 };
376 Err(nom::Err::Error(error_position!(i, ErrorKind::Verify)))
377 },
378 Err(nom::Err::Incomplete(i)) => Err(nom::Err::Incomplete(i)),
379 Err(nom::Err::Failure(_)) |
380 Err(nom::Err::Error(_)) => Err(nom::Err::Error(error_position!(i,ErrorKind::Verify)))
381 }
382}
383
384#[no_mangle]
363b5f99 385pub unsafe extern "C" fn rs_snmp_probing_parser(_flow: *const Flow,
2df840a8 386 _direction: u8,
c1b30fe9 387 input:*const u8,
2df840a8
PC
388 input_len: u32,
389 _rdir: *mut u8) -> AppProto {
390 let slice = build_slice!(input,input_len as usize);
363b5f99
JI
391 let alproto = ALPROTO_SNMP;
392 if slice.len() < 4 { return ALPROTO_FAILED; }
2df840a8
PC
393 match parse_pdu_enveloppe_version(slice) {
394 Ok((_,_)) => alproto,
395 Err(nom::Err::Incomplete(_)) => ALPROTO_UNKNOWN,
363b5f99 396 _ => ALPROTO_FAILED,
2df840a8
PC
397 }
398}
399
11e24345 400export_tx_data_get!(rs_snmp_get_tx_data, SNMPTransaction);
e2c846d0 401
2df840a8
PC
402const PARSER_NAME : &'static [u8] = b"snmp\0";
403
404#[no_mangle]
405pub unsafe extern "C" fn rs_register_snmp_parser() {
406 let default_port = CString::new("161").unwrap();
407 let mut parser = RustParser {
6911cc01
JL
408 name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
409 default_port : default_port.as_ptr(),
410 ipproto : core::IPPROTO_UDP,
66632465
PA
411 probe_ts : Some(rs_snmp_probing_parser),
412 probe_tc : Some(rs_snmp_probing_parser),
6911cc01
JL
413 min_depth : 0,
414 max_depth : 16,
415 state_new : rs_snmp_state_new,
416 state_free : rs_snmp_state_free,
417 tx_free : rs_snmp_state_tx_free,
418 parse_ts : rs_snmp_parse_request,
419 parse_tc : rs_snmp_parse_response,
420 get_tx_count : rs_snmp_state_get_tx_count,
421 get_tx : rs_snmp_state_get_tx,
efc9a7a3
VJ
422 tx_comp_st_ts : 1,
423 tx_comp_st_tc : 1,
6911cc01 424 tx_get_progress : rs_snmp_tx_get_alstate_progress,
6911cc01 425 get_events : Some(rs_snmp_state_get_events),
18448f6e
JI
426 get_eventinfo : Some(SNMPEvent::get_event_info),
427 get_eventinfo_byid : Some(SNMPEvent::get_event_info_by_id),
6911cc01
JL
428 localstorage_new : None,
429 localstorage_free : None,
6911cc01 430 get_files : None,
3f2d2bc1 431 get_tx_iterator : Some(applayer::state_get_tx_iterator::<SNMPState, SNMPTransaction>),
c94a5e63 432 get_tx_data : rs_snmp_get_tx_data,
5665fc83 433 apply_tx_config : None,
fc7d59d9 434 flags : APP_LAYER_PARSER_OPT_UNIDIR_TXS,
4da0d9bd 435 truncate : None,
2df840a8
PC
436 };
437 let ip_proto_str = CString::new("udp").unwrap();
438 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
439 // port 161
440 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
441 // store the allocated ID for the probe function
442 ALPROTO_SNMP = alproto;
443 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
444 let _ = AppLayerRegisterParser(&parser, alproto);
445 }
2df840a8
PC
446 // port 162
447 let default_port_traps = CString::new("162").unwrap();
448 parser.default_port = default_port_traps.as_ptr();
449 let _ = AppLayerRegisterProtocolDetection(&parser, 1);
450 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
451 let _ = AppLayerRegisterParser(&parser, alproto);
452 }
453 } else {
6911cc01 454 SCLogDebug!("Protocol detector and parser disabled for SNMP.");
2df840a8
PC
455 }
456}