How to properly use NmAddFilter and NmAddField functions when writing an app using NmApi?
I'm trying to make an executable which can use the functionality provided by Network Monitor 3.4 API. So far I've managed to successfully record traffic, but now I'm attempting to preform analysis on the live data before it will be recorded. I try to use examples provided in the in-app documentation but its not always possible due to language difference (I'm writing mine in rust).
Although the binding seem to work fine, and I guess It's more a question of me misinterpreting the function call or something...
below is the stripped down version of my code:
#![allow(non_camel_case_types, non_snake_case)]
use cpp_xport::core_funcs::NMAPI::{NmCreateCaptureFile, NmOpenCaptureEngine, NmConfigAdapter, NmStopCapture, NmCloseHandle, NmAddFrame, NmStartCapture, NmGetAdapterCount, NmLoadNplParser, NmAddFilter, NmCreateFrameParserConfiguration, NmAddField, NmCreateFrameParser, NmParseFrame, NmEvaluateFilter, NmGetFieldValueString};
use cpp_xport::shared::types::*;
use std::mem::zeroed;
use std::thread::sleep;
use std::time::{Duration, SystemTime};
use cpp_xport::util::WideString::{ToWide, FromWide};
use std::ptr::null_mut;
use cpp_xport::shared::types::NmNplParserLoadingOption::NmAppendRegisteredNplSets;
use cpp_xport::shared::types::NmFrameParserOptimizeOption::NmParserOptimizeNone;
use std::ops::AddAssign;
use cpp_xport::shared::types::BOOL::{FALSE, TRUE};
/// Wi-Fi network interface
pub const adapter_idx: ULONG = 4;
/// struct for passing handles to callback
pub struct HandleBundle {
pub frames_elapsed: ULONG,
pub integrity_check: &'static str, //'// to cancel the highlight, rust lifetime character is misinterpreted for string start or something
pub cap_file: HANDLE,
pub frame_parser: HANDLE,
pub filter_id: ULONG,
pub field_id: ULONG,
}
/// on frame callback
pub unsafe extern "system" fn _MyFrameIndication(hCaptureEngine: HANDLE, adapterIndex: ULONG, pContext: LPVOID, hRawFrame: HANDLE) {
/// getting the HandleBundle
let handle_bundle: &mut HandleBundle = (pContext as *mut HandleBundle).as_mut().unwrap();
println!("integrity check, handle bundle says: {}", handle_bundle.integrity_check);
/// frame preprocessing
let mut parsed_frame: HANDLE = unsafe {zeroed()};
let ret = unsafe { NmParseFrame(handle_bundle.frame_parser, hRawFrame, handle_bundle.frames_elapsed,
0, &mut parsed_frame, null_mut())
};
handle_bundle.frames_elapsed.add_assign(1); /// incrementing frame count by 1
println!("NmParseFrame: {}",ret);
assert_eq!(ret, 0);
/// using the filter added to evaluate the frame data
let mut passed: BOOL = FALSE;
let ret = unsafe {
NmEvaluateFilter(parsed_frame,
handle_bundle.filter_id,
&mut passed)
};
println!("NmEvaluateFilter: {}",ret);
assert_eq!(ret, 0);
/// if the frame data triggers our filter
if passed == TRUE {
/// extracting the value from the added field into string buffer
let mut string_buffer: Vec<u16> = vec![0_u16;256]; /// making a wide string buffer of known length
let ret = unsafe {
NmGetFieldValueString(parsed_frame,
handle_bundle.field_id,
256,
string_buffer.as_mut_ptr())
};
println!("NmGetFieldValueString: {}", ret);
assert_eq!(ret, 0);
/// outputting the value
println!("field value: {}", FromWide(string_buffer.as_mut_ptr(), 256));
}
/// releasing the parsed frame handle
unsafe {
NmCloseHandle(parsed_frame)
};
/// storing the raw frame in the capture file
let ret = unsafe {
NmAddFrame(handle_bundle.cap_file, hRawFrame)
};
println!("NmAddFrame: {}",ret);
assert_eq!(ret, 0);
/// releasing the raw frame handle
unsafe {
NmCloseHandle(hRawFrame)
};
}
/// build (on init) callback
pub unsafe extern "system" fn _onBuild(_: PVOID, _: ULONG, _: LPCWSTR, _: ULONG) {
println!("on init called");
}
fn main () {
/// opening a file to store the capture
let mut myCapFile: HANDLE = unsafe { zeroed() };
let mut CapSize: ULONG = unsafe { zeroed() };
let mut pname: Vec<u16> = ToWide("C:\\Users\\grass\\Desktop\\codes\\Rust\\cpp_xport\\res\\20sec.cap");
let ret = unsafe { NmCreateCaptureFile(pname.as_mut_ptr(), 2000,
0, &mut myCapFile as PHANDLE, &mut CapSize)
};
println!("NmCreateCaptureFile: {}", ret);
assert_eq!(ret, 0);
/// initializing the capture engine
let mut myCaptureEngine: HANDLE = unsafe { zeroed() };
let ret = unsafe { NmOpenCaptureEngine(&mut myCaptureEngine) };
println!("NmOpenCaptureEngine: {}", ret);
assert_eq!(ret, 0);
// =============================================================================================
/// loads configuration language parser
let mut parser: HANDLE = unsafe {zeroed()};
let ret = unsafe { NmLoadNplParser(null_mut(),
NmAppendRegisteredNplSets,
Some(_onBuild),
null_mut(), &mut parser) };
println!("NmLoadNplParser: {}",ret);
assert_eq!(ret, 0);
/// creates a frame parser config
let mut parser_config: HANDLE = unsafe {zeroed()};
let ret = unsafe { NmCreateFrameParserConfiguration(parser,
Some(_onBuild),
null_mut(),
&mut parser_config) };
println!("NmCreateFrameParserConfiguration: {}",ret);
assert_eq!(ret, 0);
/// adds a filtering rule to the frame parser config
let mut rule = ToWide("http.request.command == \"GET\"");
let mut filter_id: ULONG = 0;
let ret = unsafe { NmAddFilter(parser_config,
rule.as_mut_ptr(),
&mut filter_id)
};
println!("NmAddFilter: {}",ret);
assert_eq!(ret, 0);
/// enables optimized access to the selected fields (http.request.uri in this case)
let mut field_id: ULONG = 0;
let ret = unsafe {
let mut eq_string = ToWide("http.request.uri");
NmAddField(parser_config,
eq_string.as_mut_ptr(),
&mut field_id)
};
println!("NmAddField: {}", ret);
assert_eq!(ret, 0);
/// creates the frame parser
let mut frame_parser: HANDLE = unsafe {zeroed()};
let ret = unsafe {
NmCreateFrameParser(parser_config,
&mut frame_parser,
NmParserOptimizeNone)
};
println!("NmCreateFrameParser: {}", ret);
assert_eq!(ret, 0);
// =============================================================================================
/// getting the number of available network interfaces
let mut total_ifaces: ULONG = unsafe { zeroed() };
let ret = unsafe { NmGetAdapterCount(myCaptureEngine, &mut total_ifaces as PULONG) };
println!("NmGetAdapterCount: {}", ret);
assert_eq!(ret, 0);
println!("{} network interfaces are available", total_ifaces);
/// configuring network monitor to use certain adapter, and assign per frame callback
/// using pCallerContext to pass a bundle with handles
let mut handle_bundle: HandleBundle = HandleBundle {
frames_elapsed: 0,
integrity_check: "hewwo, warudo",
cap_file: myCapFile,
frame_parser: frame_parser,
filter_id: filter_id,
field_id: field_id,
};
let ret = unsafe { NmConfigAdapter(myCaptureEngine,
adapter_idx,
Some(_MyFrameIndication),
&mut handle_bundle as *mut _ as _,
NmCaptureCallbackExitMode::DiscardRemainFrames)
};
println!("configuring adapter: code is {}", ret);
assert_eq!(ret, 0);
/// starting capture
let ret = unsafe {
NmStartCapture(myCaptureEngine,
adapter_idx,
NmAdapterCaptureMode::NmLocalOnly)
};
println!("starting capture: code is {}",ret);
assert_eq!(ret, 0);
// =============================================================================================
/// wasting time
let before = SystemTime::now();
while (SystemTime::now().duration_since(before).unwrap().as_secs() < 25) {
}
// =============================================================================================
println!("stopping capture");
/// closing the capture
unsafe {
NmStopCapture(myCaptureEngine, adapter_idx)
};
println!("releasing handles");
/// releasing the capture engine and file
unsafe {
NmCloseHandle(myCaptureEngine);
NmCloseHandle(myCapFile);
}
// =============================================================================================
}
to ensure i have the traffic needed for testing - I've created and ran in parallel the following python script:
import requests
from kivy.app import App
from kivy.uix.label import Label
from kivy.clock import Clock
class MyApp(App):
def build(self):
self.dot_counter = 0
self.lbl = Label(text="hello")
Clock.schedule_interval(self.update_status_code, 1)
return self.lbl
def update_status_code(self, *args):
self.lbl.text = str(requests.get("https://google.com").status_code)+("."*self.dot_counter)
self.dot_counter = self.dot_counter + 1 if self.dot_counter < 4 else 0
if __name__ == '__main__':
MyApp().run()
Still I cant get the NmEvaluateFilter function to output true.