From b24cb4d6e105452343e331be4418168834d0a1d6 Mon Sep 17 00:00:00 2001 From: Florian Wickert Date: Fri, 7 Jun 2024 17:17:25 +0200 Subject: [PATCH 1/2] add missing 'this->' in CjvxMexCallsProfileTpl.h and CjvxMexCallsTpl.h without this only MSVC accepts this (which is non-standard) --- .../include/CjvxMexCallsProfileTpl.h | 32 +++++++++---------- .../include/CjvxMexCallsTpl.h | 14 ++++---- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/sources/jvxLibraries/jvxLexternalCall/include/CjvxMexCallsProfileTpl.h b/sources/jvxLibraries/jvxLexternalCall/include/CjvxMexCallsProfileTpl.h index 80f1f9b4..20fc795e 100644 --- a/sources/jvxLibraries/jvxLexternalCall/include/CjvxMexCallsProfileTpl.h +++ b/sources/jvxLibraries/jvxLexternalCall/include/CjvxMexCallsProfileTpl.h @@ -32,10 +32,10 @@ class CjvxMexCallsProfileTpl : public CjvxMexCallsTpl, public CjvxMexCallsPro { jvxErrorType res = JVX_NO_ERROR; - CjvxMexCalls::prepare_connect_icon_enter(_common_set_icon.theData_in); + CjvxMexCalls::prepare_connect_icon_enter(this->_common_set_icon.theData_in); // Run this code before actually preparing this component to allow pre-run configuration in jvxDebugConfigAec - if (_theExtCallHandler) + if (this->_theExtCallHandler) { // We need to run this BEFORE we run any prepare call to obtain the // modified parameter settings in the Matlab startup @@ -57,15 +57,15 @@ class CjvxMexCallsProfileTpl : public CjvxMexCallsTpl, public CjvxMexCallsPro if (res == JVX_NO_ERROR) { // Matlab initialization is complete here - res = CjvxMexCalls::prepare_connect_icon_leave(_common_set_icon.theData_in, &_common_set_ocon.theData_out); + res = CjvxMexCalls::prepare_connect_icon_leave(this->_common_set_icon.theData_in, &this->_common_set_ocon.theData_out); } if (res == JVX_NO_ERROR) { JVX_SAFE_ALLOCATE_2DFIELD_CPP_Z(dbgFldCopyInputs, jvxData, - _common_set_icon.theData_in->con_params.number_channels, - _common_set_icon.theData_in->con_params.buffersize); + this->_common_set_icon.theData_in->con_params.number_channels, + this->_common_set_icon.theData_in->con_params.buffersize); if (config.matlab_profiling_enabled) { @@ -93,9 +93,9 @@ class CjvxMexCallsProfileTpl : public CjvxMexCallsTpl, public CjvxMexCallsPro res = local_deallocate_profiling(); } - CjvxMexCalls::postprocess_connect_icon_enter(_common_set_icon.theData_in); + CjvxMexCalls::postprocess_connect_icon_enter(this->_common_set_icon.theData_in); - JVX_SAFE_DELETE_2DFIELD(dbgFldCopyInputs, _common_set_icon.theData_in->con_params.number_channels); + JVX_SAFE_DELETE_2DFIELD(dbgFldCopyInputs, this->_common_set_icon.theData_in->con_params.number_channels); // Ignore all return values - if these functions fail we have a more severe problem!! @@ -103,7 +103,7 @@ class CjvxMexCallsProfileTpl : public CjvxMexCallsTpl, public CjvxMexCallsPro res = T::postprocess_connect_icon(JVX_CONNECTION_FEEDBACK_CALL(fdb)); - res = CjvxMexCalls::postprocess_connect_icon_leave(_common_set_icon.theData_in); + res = CjvxMexCalls::postprocess_connect_icon_leave(this->_common_set_icon.theData_in); return res; }; @@ -125,15 +125,15 @@ class CjvxMexCallsProfileTpl : public CjvxMexCallsTpl, public CjvxMexCallsPro // Check if checkbox in Matlab processing was checked // The checkbox can be activated/deactivated while processing!! - if (_theExtCallHandler) + if (this->_theExtCallHandler) { CjvxMexCalls::is_matlab_processing_engaged(&engaged); } if(engaged) { - jvxData** buffers_in = jvx_process_icon_extract_input_buffers(_common_set_icon.theData_in, idx_stage); - jvxData** buffers_out = jvx_process_icon_extract_output_buffers(_common_set_ocon.theData_out); + jvxData** buffers_in = jvx_process_icon_extract_input_buffers(this->_common_set_icon.theData_in, idx_stage); + jvxData** buffers_out = jvx_process_icon_extract_output_buffers(this->_common_set_ocon.theData_out); // =================================================== // This case to run Matlab and C code in parallel @@ -148,26 +148,26 @@ class CjvxMexCallsProfileTpl : public CjvxMexCallsTpl, public CjvxMexCallsPro if (!skipCCode) { // Copy input data for later usage - for (i = 0; i < _common_set_icon.theData_in->con_params.number_channels; i++) + for (i = 0; i < this->_common_set_icon.theData_in->con_params.number_channels; i++) { jvxData* ptrTo = dbgFldCopyInputs[i]; jvxData* ptrFrom = (jvxData*)buffers_in[i]; - memcpy(ptrTo, ptrFrom, sizeof(jvxData) * _common_set_icon.theData_in->con_params.buffersize); + memcpy(ptrTo, ptrFrom, sizeof(jvxData) * this->_common_set_icon.theData_in->con_params.buffersize); } } // This lets Matlab run one frame of processing // ====================================================================================== - res = CjvxMexCalls::process_buffers_icon(_common_set_icon.theData_in, &_common_set_ocon.theData_out); + res = CjvxMexCalls::process_buffers_icon(this->_common_set_icon.theData_in, &this->_common_set_ocon.theData_out); // ====================================================================================== if (!skipCCode) { - for (i = 0; i < _common_set_icon.theData_in->con_params.number_channels; i++) + for (i = 0; i < this->_common_set_icon.theData_in->con_params.number_channels; i++) { jvxData* ptrFrom = dbgFldCopyInputs[i]; jvxData* ptrTo = (jvxData*)buffers_in[i]; - memcpy(ptrTo, ptrFrom, sizeof(jvxData) * _common_set_icon.theData_in->con_params.buffersize); + memcpy(ptrTo, ptrFrom, sizeof(jvxData) * this->_common_set_icon.theData_in->con_params.buffersize); } } } diff --git a/sources/jvxLibraries/jvxLexternalCall/include/CjvxMexCallsTpl.h b/sources/jvxLibraries/jvxLexternalCall/include/CjvxMexCallsTpl.h index 275d7d95..b115704c 100644 --- a/sources/jvxLibraries/jvxLexternalCall/include/CjvxMexCallsTpl.h +++ b/sources/jvxLibraries/jvxLexternalCall/include/CjvxMexCallsTpl.h @@ -20,7 +20,7 @@ class CjvxMexCallsTpl : public CjvxMexCalls, public T initExternalCall(); // Run mex call base classes function to init matlab call handles - res = CjvxMexCalls::select(_common_set_min.theHostRef, static_cast(this), "", + res = CjvxMexCalls::select(this->_common_set_min.theHostRef, static_cast(this), "", _theExtCallObjectName.c_str()); } return(res); @@ -93,15 +93,15 @@ class CjvxMexCallsTpl : public CjvxMexCalls, public T jvxErrorType res = JVX_NO_ERROR; // onPrepareConnectMexCalls(); - CjvxMexCalls::prepare_sender_to_receiver(_common_set_icon.theData_in); + CjvxMexCalls::prepare_sender_to_receiver(this->_common_set_icon.theData_in); res = T::prepare_connect_icon(JVX_CONNECTION_FEEDBACK_CALL(fdb)); if (res == JVX_NO_ERROR) { - CjvxMexCalls::prepare_complete_receiver_to_sender(_common_set_icon.theData_in, &_common_set_ocon.theData_out); + CjvxMexCalls::prepare_complete_receiver_to_sender(this->_common_set_icon.theData_in, &this->_common_set_ocon.theData_out); } else { - CjvxMexCalls::postprocess_sender_to_receiver(_common_set_icon.theData_in); + CjvxMexCalls::postprocess_sender_to_receiver(this->_common_set_icon.theData_in); } return res; }; @@ -109,9 +109,9 @@ class CjvxMexCallsTpl : public CjvxMexCalls, public T jvxErrorType postprocess_connect_icon(JVX_CONNECTION_FEEDBACK_TYPE(fdb)) override { jvxErrorType res = JVX_NO_ERROR; - CjvxMexCalls::before_postprocess_receiver_to_sender(_common_set_icon.theData_in); + CjvxMexCalls::before_postprocess_receiver_to_sender(this->_common_set_icon.theData_in); res = T::postprocess_connect_icon(JVX_CONNECTION_FEEDBACK_CALL(fdb)); - CjvxMexCalls::postprocess_sender_to_receiver(_common_set_icon.theData_in); + CjvxMexCalls::postprocess_sender_to_receiver(this->_common_set_icon.theData_in); return res; }; @@ -129,7 +129,7 @@ class CjvxMexCallsTpl : public CjvxMexCalls, public T // This lets Matlab run one frame of processing // ====================================================================================== - res = CjvxMexCalls::process_buffers_icon(_common_set_icon.theData_in, &_common_set_ocon.theData_out); + res = CjvxMexCalls::process_buffers_icon(this->_common_set_icon.theData_in, &this->_common_set_ocon.theData_out); // ====================================================================================== return T::fwd_process_buffers_icon(mt_mask, idx_stage); From 201de6038ceb4e34d883d8bba9ab8332cdf9cb88 Mon Sep 17 00:00:00 2001 From: Florian Wickert Date: Thu, 20 Jun 2024 15:46:20 +0200 Subject: [PATCH 2/2] add ART tracker mock tool This is a tool to simulate the presence of an ART tracker on the network. The packets are taken from a prerecorded network trace. The destination ip address is replaced with a new one. --- python/art-tracker-mock/README.md | 20 +++++++ python/art-tracker-mock/main.py | 67 ++++++++++++++++++++++++ python/art-tracker-mock/requirements.txt | 1 + 3 files changed, 88 insertions(+) create mode 100644 python/art-tracker-mock/README.md create mode 100644 python/art-tracker-mock/main.py create mode 100644 python/art-tracker-mock/requirements.txt diff --git a/python/art-tracker-mock/README.md b/python/art-tracker-mock/README.md new file mode 100644 index 00000000..d664666e --- /dev/null +++ b/python/art-tracker-mock/README.md @@ -0,0 +1,20 @@ +# Getting started +Setup virtualenv: +```sh +python3 -m venv .venv +. .venv/bin/activate +``` +Install dependencies +```sh +pip install -r requirements.txt +``` + +## 1. Capture network trace with an actual ART tracker +## 2. Run ART Tracker mock +```sh +python3 main.py trace.pcapng 192.168.0.10 65000 127.0.0.1 +``` +Where `192.168.0.10` is the original destination host and `65000` the destination port. +The new destination host is `127.0.0.1` in this example. The destination port is unchanged. + +It keeps sending the packages from the trace file in an endless loop until interrupted by a KeyboardInterrupt. diff --git a/python/art-tracker-mock/main.py b/python/art-tracker-mock/main.py new file mode 100644 index 00000000..af2fe168 --- /dev/null +++ b/python/art-tracker-mock/main.py @@ -0,0 +1,67 @@ +import sys +import socket +import time +from pathlib import Path +from ipaddress import ip_address +from dataclasses import dataclass + +from scapy.all import rdpcap, IP, UDP + +@dataclass +class Packet: + payload: bytes + dest_port: int + delay: float + + +def _get_sequence_id(payload: bytes) -> int: + start = 3 + end = payload.find(b"\r\n", 3, 50) + return int(payload[start:end]) + + +def _read_packets(pcap_file: Path, pcap_ip: ip_address, pcap_ports: list[int]) -> list[Packet]: + res: list[Packet] = [] + with pcap_file.open("rb") as f_in: + packets = rdpcap(f_in) + last_time: float | None = None + for pkt in (pkt for pkt in packets if IP in pkt and UDP in pkt): + ip_layer = pkt[IP] + udp_layer = pkt[UDP] + payload = bytes(udp_layer.payload) + if udp_layer.dport in pcap_ports and payload[0:3] == b"fr " and ip_address(ip_layer.dst) == pcap_ip: + delay: float + if last_time is not None: + delay = float(pkt.time) - last_time + else: + delay = 0. + res.append(Packet(payload, udp_layer.dport, delay)) + last_time = float(pkt.time) + return res + + +def main(pcap_file: Path, pcap_ip: ip_address, pcap_ports: list[int], dest_ip: ip_address): + packets = _read_packets(pcap_file, pcap_ip, pcap_ports) + num_packets = len(packets) + udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + sequence_id = 0 + while True: + sequence_id += 1 + packet = packets[sequence_id % num_packets] + time.sleep(packet.delay) + # TODO spoof sequence id + udp_socket.sendto(packet.payload, (str(dest_ip), packet.dest_port)) + finally: + udp_socket.close() + + +if __name__ == "__main__": + if len(sys.argv) != 5: + sys.stderr.write(f"Usage: {sys.argv[0]} pcap-file pcap-dest-ip pcap-dest-ports dest-ip\npcap-dest-ports are comma separated\n") + sys.exit(1) + pcap_file = Path(sys.argv[1]) + pcap_dest_ip = ip_address(sys.argv[2]) + pcap_dest_ports = [int(x) for x in sys.argv[3].split(",")] + dest_ip = ip_address(sys.argv[4]) + main(pcap_file, pcap_dest_ip, pcap_dest_ports, dest_ip) diff --git a/python/art-tracker-mock/requirements.txt b/python/art-tracker-mock/requirements.txt new file mode 100644 index 00000000..30564abd --- /dev/null +++ b/python/art-tracker-mock/requirements.txt @@ -0,0 +1 @@ +scapy