blob: 5f59cafc9bc34970e65840e6ff0fcd8cc8c5a1e9 [file] [log] [blame]
Harald Weltec4ac9e02021-04-22 23:07:44 +02001module OPCAP_CLIENT_Tests {
2
3import from OPCAP_Adapter all;
4import from OPCAP_Types all;
5import from OPCAP_Templates all;
6
7import from IPL4asp_Types all;
8import from IPL4asp_PortType all;
9import from Osmocom_Types all;
10import from Osmocom_VTY_Functions all;
11import from TELNETasp_PortType all;
12import from Socket_API_Definitions all;
13
14type record IpPort {
15 charstring ip,
16 integer udp_port
17};
18
19modulepar {
20 /* local IP address listening for OPCAP connections */
21 charstring mp_local_opcap_ip := "127.0.0.1";
22 /* local TCP base port for inbound OPCAP connections */
23 integer mp_local_opcap_port := 5000;
24
25 /* IP + port for simulating user traffic */
26 IpPort mp_traffic_a := { "127.0.0.23", 44423 };
27 IpPort mp_traffic_b := { "127.0.0.42", 44442 };
28};
29
30type component test_CT extends OPCAP_Adapter_CT {
31 timer g_Tguard := 30.0;
32
33 port TELNETasp_PT VTY;
34
35 /* port to generate IP traffic that may or may not be captured */
36 port IPL4asp_PT IP;
37 var integer g_traffic_conn_id[2];
38};
39
40private altstep as_Tguard() runs on test_CT {
41[] g_Tguard.timeout {
42 setverdict(fail, "global guard timeout");
43 mtc.stop;
44 }
45}
46
47/* initialize one of the OPCAP servers, wait for client to connect */
48private function f_init_one_srv(integer idx, template (present) uint32_t linktype) runs on test_CT {
49 /* start guard timer */
50 activate(as_Tguard());
51 g_Tguard.start;
52 log("Waiting for client-", idx, " connection...");
53 /* wait for connection */
54 f_bind(mp_local_opcap_ip, mp_local_opcap_port+idx, idx);
55 f_wait_client_connect(idx);
56 /* wait for file header */
57 f_opcap_exp(tr_OPCAP_FILE_HDR(linktype), idx);
58};
59
60
61/* global initialization */
62private function f_init() runs on test_CT {
63 map(self:VTY, system:VTY);
64 f_vty_set_prompts(VTY);
65 f_vty_transceive(VTY, "enable");
66
67 map(self:IP, system:IP);
68 var IPL4asp_Types.Result res
69
70 /* 0 -> 1 */
71 res := f_IPL4_connect(IP, mp_traffic_b.ip, mp_traffic_b.udp_port,
72 mp_traffic_a.ip, mp_traffic_a.udp_port, -1, { udp:={} });
73 g_traffic_conn_id[0] := res.connId;
74
75 /* 1 -> 0 */
76 res := f_IPL4_connect(IP, mp_traffic_a.ip, mp_traffic_a.udp_port,
77 mp_traffic_b.ip, mp_traffic_b.udp_port, -1, { udp:={} });
78 g_traffic_conn_id[1] := res.connId;
79}
80
81/* generate user traffic from A -> B */
82function f_trafic_pkt_ab(octetstring payload) runs on test_CT {
83 IP.send(ASP_Send:{g_traffic_conn_id[0], omit, payload})
84 IP.receive(ASP_RecvFrom:{g_traffic_conn_id[1], ?, ?, ?, ?, { udp:={} }, ?, payload});
85}
86
87/* generate user traffic from B -> A */
88function f_trafic_pkt_ba(octetstring payload) runs on test_CT {
89 IP.send(ASP_Send:{g_traffic_conn_id[1], omit, payload})
90 IP.receive(ASP_RecvFrom:{g_traffic_conn_id[0], ?, ?, ?, ?, { udp:={} }, ?, payload});
91}
92
93/* expect a specified UDP payload on the OPCAP connection 'idx' */
94function f_opcap_exp_udp(octetstring udp_payload, integer idx) runs on test_CT {
95 var octetstring rx_tail;
96 var integer udp_payload_len, rx_pdu_len;
97 var OPCAP_PDU rx_pdu;
98
99 udp_payload_len := lengthof(udp_payload);
100
101 /* sadly I couldn't figure out how to create an octetstring template
102 * for 'match an octetstring ending in 'udp_payload' */
103 rx_pdu := f_opcap_exp(tr_OPCAP_PKT(?), idx);
104 rx_pdu_len := lengthof(rx_pdu.u.packet.payload);
105 rx_tail := substr(rx_pdu.u.packet.payload, rx_pdu_len - udp_payload_len, udp_payload_len);
106 if (rx_tail != udp_payload) {
107 log("captured UDP payload: ", rx_tail, " but expected: ", udp_payload);
108 setverdict(fail);
109 } else {
110 setverdict(pass);
111 }
112}
113
114/* create an additional pcap-store-connection via the VTY */
115function f_vty_create_addl_connection(integer idx) runs on test_CT
116{
117 f_vty_config3(VTY, { "client", "pcap-store-connectio second-" & int2str(idx) },
118 { "server ip " & mp_local_opcap_ip,
119 "server port " & int2str(mp_local_opcap_port + idx),
120 "connect" }
121 );
122}
123
124
125
126/* wait for inbound client connection and reception of link header */
127testcase TC_connect_rx_hdr() runs on test_CT
128{
129 f_init();
130 f_init_one_srv(0, ?);
131 setverdict(pass);
132}
133
134/* check if client connection is re-started after a close */
135testcase TC_reconnect(integer idx := 0) runs on test_CT
136{
137 f_init();
138 f_init_one_srv(idx, ?);
139 f_sleep(2.0);
140
141 log("Disconnecting client-", idx);
142 f_disconnect(idx);
143
144 f_wait_client_connect(idx);
145 f_opcap_exp(tr_OPCAP_FILE_HDR(?), idx);
146 setverdict(pass);
147}
148
149/* capture a packet that's within the filter */
150testcase TC_capture() runs on test_CT
151{
152 f_init();
153 f_init_one_srv(0, ?);
154
155 for (var integer i := 0; i < 10; i := i + 1) {
156 var octetstring udp_payload;
157
158 /* we assume 1400 is low enough to avoid IP fragmentation */
159 udp_payload := f_rnd_octstring(f_rnd_int(1400));
160 f_trafic_pkt_ab(udp_payload);
161
162 f_opcap_exp_udp(udp_payload, 0);
163 }
164}
165
166/* wait for inbound client connections and reception of link header */
167testcase TC_multi_connect_rx_hdr() runs on test_CT
168{
169 f_init();
170 f_init_one_srv(0, ?);
171 f_vty_create_addl_connection(1);
172 f_init_one_srv(1, ?);
173 setverdict(pass);
174}
175
176/* ensure a packet that's within the filter is sent to secondary clients */
177testcase TC_multi_capture() runs on test_CT
178{
179 f_init();
180 f_init_one_srv(0, ?);
181 f_vty_create_addl_connection(1);
182 f_init_one_srv(1, ?);
183
184 for (var integer i := 0; i < 10; i := i + 1) {
185 var octetstring udp_payload;
186
187 /* we assume 1400 is low enough to avoid IP fragmentation */
188 udp_payload := f_rnd_octstring(f_rnd_int(1400));
189 f_trafic_pkt_ab(udp_payload);
190
191 /* expect packet to arrive on both simulated servers */
192 f_opcap_exp_udp(udp_payload, 0);
193 f_opcap_exp_udp(udp_payload, 1);
194 }
195}
196
197/* TODO: ensure a packet outside the filter is dropped */
198/* TODO: capture of truncated packet */
199/* TODO: stall the receive window */
200/* TODO: different link type (ethernet, not SLL) */
201
202
203control {
204 execute( TC_connect_rx_hdr() );
205 execute( TC_reconnect() );
206 execute( TC_capture() );
207 execute( TC_multi_connect_rx_hdr() );
208 execute( TC_multi_capture() );
209};
210
211
212};