From c4ac9e0fe398cb151901da706b391330c0a047ad Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 22 Apr 2021 23:07:44 +0200 Subject: [PATCH] Initial test suite for osmo-pcap-client Change-Id: If4a1072e75cb64f785d660e4c828c0f521d84b16 --- Makefile | 1 + library/OPCAP_Adapter.ttcn | 105 ++++++++++++ library/OPCAP_CodecPort.ttcn | 64 +++++++ library/OPCAP_CodecPort_CtrlFunct.ttcn | 52 ++++++ library/OPCAP_CodecPort_CtrlFunctdef.cc | 66 ++++++++ library/OPCAP_Templates.ttcn | 54 ++++++ library/OPCAP_Types.ttcn | 78 +++++++++ pcap-client/OPCAP_CLIENT_Tests.cfg | 18 ++ pcap-client/OPCAP_CLIENT_Tests.default | 19 +++ pcap-client/OPCAP_CLIENT_Tests.ttcn | 212 ++++++++++++++++++++++++ pcap-client/gen_links.sh | 31 ++++ pcap-client/osmo-pcap-client.cfg | 14 ++ pcap-client/regen_makefile.sh | 11 ++ 13 files changed, 725 insertions(+) create mode 100644 library/OPCAP_Adapter.ttcn create mode 100644 library/OPCAP_CodecPort.ttcn create mode 100644 library/OPCAP_CodecPort_CtrlFunct.ttcn create mode 100644 library/OPCAP_CodecPort_CtrlFunctdef.cc create mode 100644 library/OPCAP_Templates.ttcn create mode 100644 library/OPCAP_Types.ttcn create mode 100644 pcap-client/OPCAP_CLIENT_Tests.cfg create mode 100644 pcap-client/OPCAP_CLIENT_Tests.default create mode 100644 pcap-client/OPCAP_CLIENT_Tests.ttcn create mode 100755 pcap-client/gen_links.sh create mode 100644 pcap-client/osmo-pcap-client.cfg create mode 100755 pcap-client/regen_makefile.sh diff --git a/Makefile b/Makefile index 81540bacf..05670817f 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ SUBDIRS= \ mme \ msc \ ns \ + pcap-client \ pcu \ pgw \ remsim \ diff --git a/library/OPCAP_Adapter.ttcn b/library/OPCAP_Adapter.ttcn new file mode 100644 index 000000000..8bcc3fd99 --- /dev/null +++ b/library/OPCAP_Adapter.ttcn @@ -0,0 +1,105 @@ +module OPCAP_Adapter { + +/* OPCAP Adapter layer, sitting on top of OPCAP_CodecPort. + * test suites can 'inherit' in order to have a OPCAP connection to the IUT which they're testing + * + * (C) 2021 by Harald Welte + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + */ + + +import from Osmocom_Types all; +import from General_Types all; +import from OPCAP_Types all; +import from OPCAP_Templates all; +import from OPCAP_CodecPort all; +import from OPCAP_CodecPort_CtrlFunct all; +import from IPL4asp_Types all; +import from IPL4asp_PortType all; +import from Socket_API_Definitions all; + +const integer NUM_OPCAP := 3; + +type component OPCAP_Adapter_CT { + /* down-facing port to OPCAP Codec port */ + port OPCAP_CODEC_PT OPCAP[NUM_OPCAP]; + var IPL4asp_Types.ConnectionId g_opcap_conn_id[NUM_OPCAP] := { -1, -1, -1 }; +} + +private function f_set_tcp_segmentation(integer idx) runs on OPCAP_Adapter_CT { + /* Set function for dissecting the binary stream into packets */ + var f_IPL4_getMsgLen vl_f := refers(f_IPL4_fixedMsgLen); + /* Offset: 2, size of length: 2, delta: 4, multiplier: 1, big-endian */ + OPCAP_CodecPort_CtrlFunct.f_IPL4_setGetMsgLen(OPCAP[idx], g_opcap_conn_id[idx], vl_f, {2, 2, 4, 1, 0}); +} + +function f_connect(charstring remote_host, IPL4asp_Types.PortNumber remote_port, + charstring local_host, IPL4asp_Types.PortNumber local_port, integer idx := 0) +runs on OPCAP_Adapter_CT { + var IPL4asp_Types.Result res; + map(self:OPCAP[idx], system:OPCAP); + if (g_opcap_conn_id[idx] != -1) { + OPCAP_CodecPort_CtrlFunct.f_IPL4_close(OPCAP[idx], g_opcap_conn_id[idx], {tcp := {}}); + g_opcap_conn_id[idx] := -1; + } + res := OPCAP_CodecPort_CtrlFunct.f_IPL4_connect(OPCAP[idx], remote_host, remote_port, + local_host, local_port, 0, { tcp :={} }); + if (not ispresent(res.connId)) { + setverdict(fail, "Could not connect to OPCAP port, check your configuration ", + "{remote ", remote_host, ":", remote_port, " local ", local_host, ":", local_port, "}"); + mtc.stop; + } + g_opcap_conn_id[idx] := res.connId; + + f_set_tcp_segmentation(idx); +} + +/* Function to use to bind to a local port as IPA server, accepting remote clients */ +function f_bind(charstring local_host, IPL4asp_Types.PortNumber local_port, integer idx := 0) +runs on OPCAP_Adapter_CT { + var IPL4asp_Types.Result res; + map(self:OPCAP[idx], system:OPCAP); + if (g_opcap_conn_id[idx] != -1) { + OPCAP_CodecPort_CtrlFunct.f_IPL4_close(OPCAP[idx], g_opcap_conn_id[idx], {tcp := {}}); + g_opcap_conn_id[idx] := -1; + } + res := OPCAP_CodecPort_CtrlFunct.f_IPL4_listen(OPCAP[idx], local_host, local_port, { tcp:={} }); + if (not ispresent(res.connId)) { + setverdict(fail, "Could not bind to OPCAP port, check your configuration ", + "{local ", local_host, ":", local_port, "}"); + mtc.stop; + } + g_opcap_conn_id[idx] := res.connId; + + f_set_tcp_segmentation(idx); +} + +function f_wait_client_connect(integer idx) runs on OPCAP_Adapter_CT { + var IPL4asp_Types.PortEvent rx_event; + OPCAP[idx].receive(IPL4asp_Types.PortEvent:{connOpened:=?}) -> value rx_event { + log("Connection from ", rx_event.connOpened.remName, ":", rx_event.connOpened.remPort); + /* we want to store the client's connId, not the 'bind socket' one */ + g_opcap_conn_id[idx] := rx_event.connOpened.connId; + } +} + +function f_disconnect(integer idx) runs on OPCAP_Adapter_CT { + OPCAP_CodecPort_CtrlFunct.f_IPL4_close(OPCAP[idx], g_opcap_conn_id[idx], {tcp := {}}); + OPCAP[idx].clear; +}; + +function f_opcap_send(template (value) OPCAP_PDU pdu, integer idx := 0) runs on OPCAP_Adapter_CT { + OPCAP[idx].send(ts_OPCAP_Send(g_opcap_conn_id[idx], pdu)); +} + +function f_opcap_exp(template OPCAP_PDU exp, integer idx := 0) runs on OPCAP_Adapter_CT return OPCAP_PDU { + var OPCAP_RecvFrom rf; + OPCAP[idx].receive(tr_OPCAP_Recv(g_opcap_conn_id[idx], exp)) -> value rf; + return rf.msg; +} + + +} diff --git a/library/OPCAP_CodecPort.ttcn b/library/OPCAP_CodecPort.ttcn new file mode 100644 index 000000000..f2d215dbc --- /dev/null +++ b/library/OPCAP_CodecPort.ttcn @@ -0,0 +1,64 @@ +module OPCAP_CodecPort { + +/* Simple OPCAP Codec Port, translating between raw TCP octetstring payload + * towards the IPL4asp port provider, and OPCAP primitives + * which carry the decoded OPCAP data types as payload. + * + * (C) 2021 by Harald Welte + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + */ + + +import from IPL4asp_PortType all; +import from IPL4asp_Types all; +import from OPCAP_Types all; + +type record OPCAP_RecvFrom { + ConnectionId connId, + OPCAP_PDU msg +} + +type record OPCAP_Send { + ConnectionId connId, + OPCAP_PDU msg +} + +template (value) OPCAP_Send ts_OPCAP_Send(ConnectionId conn_id, template (value) OPCAP_PDU msg) := { + connId := conn_id, + msg := msg +} + +template OPCAP_RecvFrom tr_OPCAP_Recv(template ConnectionId conn_id, template OPCAP_PDU msg) := { + connId := conn_id, + msg := msg +} + +private function IPL4_to_OPCAP_RecvFrom(in ASP_RecvFrom pin, out OPCAP_RecvFrom pout) { + pout.connId := pin.connId; + pout.msg := dec_OPCAP_PDU(pin.msg); +} with { extension "prototype(fast)" } + +private function OPCAP_to_IPL4_Send(in OPCAP_Send pin, out ASP_Send pout) { + pout.connId := pin.connId; + pout.proto := { tcp := {} }; + pout.msg := enc_OPCAP_PDU(pin.msg); +} with { extension "prototype(fast)" } + +type port OPCAP_CODEC_PT message { + out OPCAP_Send; + in OPCAP_RecvFrom, + ASP_ConnId_ReadyToRelease, + ASP_Event; +} with { extension "user IPL4asp_PT + out(OPCAP_Send -> ASP_Send: function(OPCAP_to_IPL4_Send)) + in(ASP_RecvFrom -> OPCAP_RecvFrom: function(IPL4_to_OPCAP_RecvFrom); + ASP_ConnId_ReadyToRelease -> ASP_ConnId_ReadyToRelease: simple; + ASP_Event -> ASP_Event: simple)" +} + + + +} diff --git a/library/OPCAP_CodecPort_CtrlFunct.ttcn b/library/OPCAP_CodecPort_CtrlFunct.ttcn new file mode 100644 index 000000000..99a5fe747 --- /dev/null +++ b/library/OPCAP_CodecPort_CtrlFunct.ttcn @@ -0,0 +1,52 @@ +module OPCAP_CodecPort_CtrlFunct { + + import from OPCAP_CodecPort all; + import from IPL4asp_Types all; + + external function f_IPL4_listen( + inout OPCAP_CODEC_PT portRef, + in HostName locName, + in PortNumber locPort, + in ProtoTuple proto, + in OptionList options := {} + ) return Result; + + external function f_IPL4_connect( + inout OPCAP_CODEC_PT portRef, + in HostName remName, + in PortNumber remPort, + in HostName locName, + in PortNumber locPort, + in ConnectionId connId, + in ProtoTuple proto, + in OptionList options := {} + ) return Result; + + external function f_IPL4_close( + inout OPCAP_CODEC_PT portRef, + in ConnectionId id, + in ProtoTuple proto := { unspecified := {} } + ) return Result; + + external function f_IPL4_setUserData( + inout OPCAP_CODEC_PT portRef, + in ConnectionId id, + in UserData userData + ) return Result; + + external function f_IPL4_getUserData( + inout OPCAP_CODEC_PT portRef, + in ConnectionId id, + out UserData userData + ) return Result; + + external function f_IPL4_setGetMsgLen( + inout OPCAP_CODEC_PT portRef, + in ConnectionId id, + inout f_IPL4_getMsgLen f, + in ro_integer msgLenArgs + ); + + +} + diff --git a/library/OPCAP_CodecPort_CtrlFunctdef.cc b/library/OPCAP_CodecPort_CtrlFunctdef.cc new file mode 100644 index 000000000..b19138a47 --- /dev/null +++ b/library/OPCAP_CodecPort_CtrlFunctdef.cc @@ -0,0 +1,66 @@ +#include "IPL4asp_PortType.hh" +#include "OPCAP_CodecPort.hh" +#include "IPL4asp_PT.hh" + +namespace OPCAP__CodecPort__CtrlFunct { + + IPL4asp__Types::Result f__IPL4__listen( + OPCAP__CodecPort::OPCAP__CODEC__PT& portRef, + const IPL4asp__Types::HostName& locName, + const IPL4asp__Types::PortNumber& locPort, + const IPL4asp__Types::ProtoTuple& proto, + const IPL4asp__Types::OptionList& options) + { + return f__IPL4__PROVIDER__listen(portRef, locName, locPort, proto, options); + } + + IPL4asp__Types::Result f__IPL4__connect( + OPCAP__CodecPort::OPCAP__CODEC__PT& portRef, + const IPL4asp__Types::HostName& remName, + const IPL4asp__Types::PortNumber& remPort, + const IPL4asp__Types::HostName& locName, + const IPL4asp__Types::PortNumber& locPort, + const IPL4asp__Types::ConnectionId& connId, + const IPL4asp__Types::ProtoTuple& proto, + const IPL4asp__Types::OptionList& options) + { + return f__IPL4__PROVIDER__connect(portRef, remName, remPort, + locName, locPort, connId, proto, options); + } + + IPL4asp__Types::Result f__IPL4__close( + OPCAP__CodecPort::OPCAP__CODEC__PT& portRef, + const IPL4asp__Types::ConnectionId& connId, + const IPL4asp__Types::ProtoTuple& proto) + { + return f__IPL4__PROVIDER__close(portRef, connId, proto); + } + + IPL4asp__Types::Result f__IPL4__setUserData( + OPCAP__CodecPort::OPCAP__CODEC__PT& portRef, + const IPL4asp__Types::ConnectionId& connId, + const IPL4asp__Types::UserData& userData) + { + return f__IPL4__PROVIDER__setUserData(portRef, connId, userData); + } + + IPL4asp__Types::Result f__IPL4__getUserData( + OPCAP__CodecPort::OPCAP__CODEC__PT& portRef, + const IPL4asp__Types::ConnectionId& connId, + IPL4asp__Types::UserData& userData) + { + return f__IPL4__PROVIDER__getUserData(portRef, connId, userData); + } + + void f__IPL4__setGetMsgLen( + OPCAP__CodecPort::OPCAP__CODEC__PT& portRef, + const IPL4asp__Types::ConnectionId& connId, + Socket__API__Definitions::f__getMsgLen& f, + const Socket__API__Definitions::ro__integer& msgLenArgs) + { + return f__IPL4__PROVIDER__setGetMsgLen(portRef, connId, f, msgLenArgs); + } + + +} + diff --git a/library/OPCAP_Templates.ttcn b/library/OPCAP_Templates.ttcn new file mode 100644 index 000000000..0a1c884f0 --- /dev/null +++ b/library/OPCAP_Templates.ttcn @@ -0,0 +1,54 @@ +module OPCAP_Templates { + +/* OPCAP_Templates, defining TTCN-3 templates for the osmo-pcap protocol. + * + * OPCAP is a non-standard protocol used between osmo-pcap-client and osmo-pcap-server. + * + * (C) 2021 by Harald Welte + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + */ + +import from General_Types all; +import from Osmocom_Types all; +import from OPCAP_Types all; + + +template (present) OPCAP_PDU tr_OPCAP_FILE_HDR(template (present) uint32_t linktype := ?) := { + msg_type := PKT_LINK_HDR, + spare := ?, + len := 24, + u := { + file := { + magic := PCAP_MAGIC, + version_major := PCAP_VERSION_MAJOR, + version_minor := PCAP_VERSION_MINOR, + thiszone := 0, + sigfigs := 0, + snaplen := 9000, + linktype := linktype + } + } +} + +template (present) OPCAP_PDU tr_OPCAP_PKT(template (present) octetstring payload, + template (present) uint32_t caplen := ?, + template (present) uint32_t len := ?) := { + msg_type := PKT_LINK_DATA, + spare := ?, + len := ?, + u := { + packet := { + ts_sec := ?, + ts_usec := ?, + caplen := caplen, + len := len, + payload := payload + } + } +} + + +}; diff --git a/library/OPCAP_Types.ttcn b/library/OPCAP_Types.ttcn new file mode 100644 index 000000000..d244fefde --- /dev/null +++ b/library/OPCAP_Types.ttcn @@ -0,0 +1,78 @@ +module OPCAP_Types { + +/* OPCAP_Types, defining abstract TTCN-3 data types for the osmo-pcap protocol. + * + * OPCAP is a non-standard protocol used between osmo-pcap-client and osmo-pcap-server. + * + * (C) 2021 by Harald Welte + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + */ + +import from General_Types all; +import from Osmocom_Types all; + +type enumerated OpcapMsgType { + PKT_LINK_HDR (0), + PKT_LINK_DATA (1) +} with { variant "FIELDLENGTH(8)" }; + +type record OPCAP_PDU { + OpcapMsgType msg_type, + uint8_t spare, + uint16_t len, + OpcapBodyUnion u +} with { + variant (len) "LENGTHTO(u)" + variant (len) "BYTEORDER(last)" + variant (u) "CROSSTAG( + file, msg_type = PKT_LINK_HDR; + packet, msg_type = PKT_LINK_DATA; + )" +}; + +type union OpcapBodyUnion { + PcapFileHeader file, + OpcapPacket packet +}; + +/* header in front of a PKT_LINK_DATA */ +type record OpcapPacket { + uint32_t ts_sec, + uint32_t ts_usec, + uint32_t caplen, + uint32_t len, + octetstring payload +} with { + variant (caplen) "LENGTHTO(payload)" +}; + +/* below definitions are from pcap/pcap.h */ +const uint16_t PCAP_VERSION_MAJOR := 2; +const uint16_t PCAP_VERSION_MINOR := 4; +const uint32_t PCAP_MAGIC := 2712847316; //0xA1B2C3D4; + +type record PcapFileHeader { + uint32_t magic, + uint16_t version_major, + uint16_t version_minor, + uint32_t thiszone, + uint32_t sigfigs, + uint32_t snaplen, + uint32_t linktype +}; + +/* below definitions are from pcap/dlt.h */ +const uint32_t DLT_LINUX_SLL := 113; +const uint32_t DLT_EN10MB := 1; + + +external function enc_OPCAP_PDU(in OPCAP_PDU msg) return octetstring + with { extension "prototype(convert) encode(RAW)" }; + +external function dec_OPCAP_PDU(in octetstring msg) return OPCAP_PDU + with { extension "prototype(convert) decode(RAW)" }; + +} with { encode "RAW"; variant "FIELDORDER(msb)"; variant "BYTEORDER(first)" }; diff --git a/pcap-client/OPCAP_CLIENT_Tests.cfg b/pcap-client/OPCAP_CLIENT_Tests.cfg new file mode 100644 index 000000000..3476c2f9a --- /dev/null +++ b/pcap-client/OPCAP_CLIENT_Tests.cfg @@ -0,0 +1,18 @@ +[ORDERED_INCLUDE] +# Common configuration, shared between test suites +"../Common.cfg" +# testsuite specific configuration, not expected to change +"./OPCAP_CLIENT_Tests.default" + +# Local configuration below + +[LOGGING] + +[TESTPORT_PARAMETERS] + +[MODULE_PARAMETERS] + +[MAIN_CONTROLLER] + +[EXECUTE] +OPCAP_CLIENT_Tests.control diff --git a/pcap-client/OPCAP_CLIENT_Tests.default b/pcap-client/OPCAP_CLIENT_Tests.default new file mode 100644 index 000000000..2b1677bbf --- /dev/null +++ b/pcap-client/OPCAP_CLIENT_Tests.default @@ -0,0 +1,19 @@ +[LOGGING] +mtc.FileMask := LOG_ALL | TTCN_DEBUG | TTCN_MATCHING | DEBUG_ENCDEC; + +[TESTPORT_PARAMETERS] +*.VTY.CTRL_MODE := "client" +*.VTY.CTRL_HOSTNAME := "127.0.0.1" +*.VTY.CTRL_PORTNUM := "4237" +*.VTY.CTRL_LOGIN_SKIPPED := "yes" +*.VTY.CTRL_DETECT_SERVER_DISCONNECTED := "yes" +*.VTY.CTRL_READMODE := "buffered" +*.VTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes" +*.VTY.CTRL_DETECT_CONNECTION_ESTABLISHMENT_RESULT := "yes" +*.VTY.PROMPT1 := "OsmoPCAPClient> " +*.TCP.noDelay := "yes" // turn off nagle + +[MODULE_PARAMETERS] +Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoPCAPClient" + +[EXECUTE] diff --git a/pcap-client/OPCAP_CLIENT_Tests.ttcn b/pcap-client/OPCAP_CLIENT_Tests.ttcn new file mode 100644 index 000000000..5f59cafc9 --- /dev/null +++ b/pcap-client/OPCAP_CLIENT_Tests.ttcn @@ -0,0 +1,212 @@ +module OPCAP_CLIENT_Tests { + +import from OPCAP_Adapter all; +import from OPCAP_Types all; +import from OPCAP_Templates all; + +import from IPL4asp_Types all; +import from IPL4asp_PortType all; +import from Osmocom_Types all; +import from Osmocom_VTY_Functions all; +import from TELNETasp_PortType all; +import from Socket_API_Definitions all; + +type record IpPort { + charstring ip, + integer udp_port +}; + +modulepar { + /* local IP address listening for OPCAP connections */ + charstring mp_local_opcap_ip := "127.0.0.1"; + /* local TCP base port for inbound OPCAP connections */ + integer mp_local_opcap_port := 5000; + + /* IP + port for simulating user traffic */ + IpPort mp_traffic_a := { "127.0.0.23", 44423 }; + IpPort mp_traffic_b := { "127.0.0.42", 44442 }; +}; + +type component test_CT extends OPCAP_Adapter_CT { + timer g_Tguard := 30.0; + + port TELNETasp_PT VTY; + + /* port to generate IP traffic that may or may not be captured */ + port IPL4asp_PT IP; + var integer g_traffic_conn_id[2]; +}; + +private altstep as_Tguard() runs on test_CT { +[] g_Tguard.timeout { + setverdict(fail, "global guard timeout"); + mtc.stop; + } +} + +/* initialize one of the OPCAP servers, wait for client to connect */ +private function f_init_one_srv(integer idx, template (present) uint32_t linktype) runs on test_CT { + /* start guard timer */ + activate(as_Tguard()); + g_Tguard.start; + log("Waiting for client-", idx, " connection..."); + /* wait for connection */ + f_bind(mp_local_opcap_ip, mp_local_opcap_port+idx, idx); + f_wait_client_connect(idx); + /* wait for file header */ + f_opcap_exp(tr_OPCAP_FILE_HDR(linktype), idx); +}; + + +/* global initialization */ +private function f_init() runs on test_CT { + map(self:VTY, system:VTY); + f_vty_set_prompts(VTY); + f_vty_transceive(VTY, "enable"); + + map(self:IP, system:IP); + var IPL4asp_Types.Result res + + /* 0 -> 1 */ + res := f_IPL4_connect(IP, mp_traffic_b.ip, mp_traffic_b.udp_port, + mp_traffic_a.ip, mp_traffic_a.udp_port, -1, { udp:={} }); + g_traffic_conn_id[0] := res.connId; + + /* 1 -> 0 */ + res := f_IPL4_connect(IP, mp_traffic_a.ip, mp_traffic_a.udp_port, + mp_traffic_b.ip, mp_traffic_b.udp_port, -1, { udp:={} }); + g_traffic_conn_id[1] := res.connId; +} + +/* generate user traffic from A -> B */ +function f_trafic_pkt_ab(octetstring payload) runs on test_CT { + IP.send(ASP_Send:{g_traffic_conn_id[0], omit, payload}) + IP.receive(ASP_RecvFrom:{g_traffic_conn_id[1], ?, ?, ?, ?, { udp:={} }, ?, payload}); +} + +/* generate user traffic from B -> A */ +function f_trafic_pkt_ba(octetstring payload) runs on test_CT { + IP.send(ASP_Send:{g_traffic_conn_id[1], omit, payload}) + IP.receive(ASP_RecvFrom:{g_traffic_conn_id[0], ?, ?, ?, ?, { udp:={} }, ?, payload}); +} + +/* expect a specified UDP payload on the OPCAP connection 'idx' */ +function f_opcap_exp_udp(octetstring udp_payload, integer idx) runs on test_CT { + var octetstring rx_tail; + var integer udp_payload_len, rx_pdu_len; + var OPCAP_PDU rx_pdu; + + udp_payload_len := lengthof(udp_payload); + + /* sadly I couldn't figure out how to create an octetstring template + * for 'match an octetstring ending in 'udp_payload' */ + rx_pdu := f_opcap_exp(tr_OPCAP_PKT(?), idx); + rx_pdu_len := lengthof(rx_pdu.u.packet.payload); + rx_tail := substr(rx_pdu.u.packet.payload, rx_pdu_len - udp_payload_len, udp_payload_len); + if (rx_tail != udp_payload) { + log("captured UDP payload: ", rx_tail, " but expected: ", udp_payload); + setverdict(fail); + } else { + setverdict(pass); + } +} + +/* create an additional pcap-store-connection via the VTY */ +function f_vty_create_addl_connection(integer idx) runs on test_CT +{ + f_vty_config3(VTY, { "client", "pcap-store-connectio second-" & int2str(idx) }, + { "server ip " & mp_local_opcap_ip, + "server port " & int2str(mp_local_opcap_port + idx), + "connect" } + ); +} + + + +/* wait for inbound client connection and reception of link header */ +testcase TC_connect_rx_hdr() runs on test_CT +{ + f_init(); + f_init_one_srv(0, ?); + setverdict(pass); +} + +/* check if client connection is re-started after a close */ +testcase TC_reconnect(integer idx := 0) runs on test_CT +{ + f_init(); + f_init_one_srv(idx, ?); + f_sleep(2.0); + + log("Disconnecting client-", idx); + f_disconnect(idx); + + f_wait_client_connect(idx); + f_opcap_exp(tr_OPCAP_FILE_HDR(?), idx); + setverdict(pass); +} + +/* capture a packet that's within the filter */ +testcase TC_capture() runs on test_CT +{ + f_init(); + f_init_one_srv(0, ?); + + for (var integer i := 0; i < 10; i := i + 1) { + var octetstring udp_payload; + + /* we assume 1400 is low enough to avoid IP fragmentation */ + udp_payload := f_rnd_octstring(f_rnd_int(1400)); + f_trafic_pkt_ab(udp_payload); + + f_opcap_exp_udp(udp_payload, 0); + } +} + +/* wait for inbound client connections and reception of link header */ +testcase TC_multi_connect_rx_hdr() runs on test_CT +{ + f_init(); + f_init_one_srv(0, ?); + f_vty_create_addl_connection(1); + f_init_one_srv(1, ?); + setverdict(pass); +} + +/* ensure a packet that's within the filter is sent to secondary clients */ +testcase TC_multi_capture() runs on test_CT +{ + f_init(); + f_init_one_srv(0, ?); + f_vty_create_addl_connection(1); + f_init_one_srv(1, ?); + + for (var integer i := 0; i < 10; i := i + 1) { + var octetstring udp_payload; + + /* we assume 1400 is low enough to avoid IP fragmentation */ + udp_payload := f_rnd_octstring(f_rnd_int(1400)); + f_trafic_pkt_ab(udp_payload); + + /* expect packet to arrive on both simulated servers */ + f_opcap_exp_udp(udp_payload, 0); + f_opcap_exp_udp(udp_payload, 1); + } +} + +/* TODO: ensure a packet outside the filter is dropped */ +/* TODO: capture of truncated packet */ +/* TODO: stall the receive window */ +/* TODO: different link type (ethernet, not SLL) */ + + +control { + execute( TC_connect_rx_hdr() ); + execute( TC_reconnect() ); + execute( TC_capture() ); + execute( TC_multi_connect_rx_hdr() ); + execute( TC_multi_capture() ); +}; + + +}; diff --git a/pcap-client/gen_links.sh b/pcap-client/gen_links.sh new file mode 100755 index 000000000..e45995964 --- /dev/null +++ b/pcap-client/gen_links.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +BASEDIR=../deps + +. ../gen_links.sh.inc + +DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src +FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCInterface.cc TCCInterface_ip.h" +FILES+=" TCCEncoding_Functions.ttcn TCCEncoding.cc " # GSM 7-bit coding +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src +FILES="Socket_API_Definitions.ttcn" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.IPL4asp/src +FILES="IPL4asp_Functions.ttcn IPL4asp_PT.cc IPL4asp_PT.hh IPL4asp_PortType.ttcn IPL4asp_Types.ttcn IPL4asp_discovery.cc IPL4asp_protocol_L234.hh" +gen_links $DIR $FILES + +DIR=$BASEDIR/titan.TestPorts.TELNETasp/src +FILES="TELNETasp_PT.cc TELNETasp_PT.hh TELNETasp_PortType.ttcn" +gen_links $DIR $FILES + +DIR=../library +FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn Native_Functions.ttcn Native_FunctionDefs.cc " +FILES+="Osmocom_VTY_Functions.ttcn " +FILES+="OPCAP_Types.ttcn OPCAP_Templates.ttcn " +FILES+="OPCAP_CodecPort.ttcn OPCAP_CodecPort_CtrlFunct.ttcn OPCAP_CodecPort_CtrlFunctdef.cc OPCAP_Adapter.ttcn " +gen_links $DIR $FILES + +ignore_pp_results diff --git a/pcap-client/osmo-pcap-client.cfg b/pcap-client/osmo-pcap-client.cfg new file mode 100644 index 000000000..89f1801fc --- /dev/null +++ b/pcap-client/osmo-pcap-client.cfg @@ -0,0 +1,14 @@ +! +! OsmoPCAPClient (UNKNOWN-dirty) configuration saved from vty +!! +! +! +line vty + no login +! +client + pcap device lo + pcap filter udp port 44423 + pcap detect-loop 0 + server ip 127.0.0.1 + server port 5000 diff --git a/pcap-client/regen_makefile.sh b/pcap-client/regen_makefile.sh new file mode 100755 index 000000000..9e4a6ee35 --- /dev/null +++ b/pcap-client/regen_makefile.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +FILES="*.ttcn TCCConversion.cc TCCInterface.cc TCCEncoding.cc IPL4asp_PT.cc IPL4asp_discovery.cc TELNETasp_PT.cc Native_FunctionDefs.cc OPCAP_CodecPort_CtrlFunctdef.cc " +#FILES+="*.ttcnpp " +#FILES+="*.asn" + +export CPPFLAGS_TTCN3="" + +../regen-makefile.sh OPCAP_CLIENT_Tests.ttcn $FILES + +#sed -i -e 's/^LINUX_LIBS = -lxml2/LINUX_LIBS = -lxml2 -lfftranscode/' Makefile