comparison pcap-study/rtp-tfo-trace.c @ 10:e686bc92c7d8

revamp for new subdir structure and configure script
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 15 May 2024 01:44:46 +0000
parents rtp-tfo-trace.c@41eba040785a
children
comparison
equal deleted inserted replaced
9:c00510e1ae8b 10:e686bc92c7d8
1 /*
2 * This program reads a pcap file containing RTP packets of a PSTN call
3 * (PCMU or PCMA, 160 samples per RTP packet), flowing in one or both
4 * directions, and looks for TFO IS messages.
5 */
6
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <netinet/in.h>
10 #include <arpa/inet.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <strings.h>
15 #include <pcap/pcap.h>
16
17 static pcap_t *pcap;
18 static in_addr_t match_ip_addr;
19 static u_short match_udp_port;
20 static unsigned link_hdr_len, ethertype_offset;
21
22 static struct onedir {
23 int init_flag;
24 unsigned last_seq;
25 unsigned last_tstamp;
26 unsigned stream_ssrc;
27 u_char is_hunt_buf[320];
28 int is_state;
29 unsigned is_hunt_fill;
30 unsigned is_offset;
31 unsigned is_alignment;
32 unsigned is_bit_count;
33 unsigned is_rx_word;
34 } rx_state, tx_state;
35
36 static const u_char hdr_pattern[20] = {0, 1, 0, 1, 0, 1, 1, 0, 1, 0,
37 0, 1, 1, 0, 1, 0, 1, 0, 0, 1};
38
39 static void
40 check_dl_type()
41 {
42 int dltype;
43
44 dltype = pcap_datalink(pcap);
45 switch (dltype) {
46 case DLT_EN10MB:
47 link_hdr_len = 14;
48 ethertype_offset = 12;
49 break;
50 case DLT_RAW:
51 link_hdr_len = 0;
52 break;
53 case DLT_LINUX_SLL:
54 link_hdr_len = 16;
55 ethertype_offset = 14;
56 break;
57 default:
58 fprintf(stderr, "error: unsupported data link type %d\n",
59 dltype);
60 exit(1);
61 }
62 }
63
64 static void
65 rtp_stream_logic(rtp_hdr, pkt_idx, st, dir_str)
66 u_char *rtp_hdr;
67 unsigned pkt_idx;
68 struct onedir *st;
69 char *dir_str;
70 {
71 unsigned cur_seq, cur_tstamp, cur_ssrc;
72
73 cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3];
74 cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) |
75 (rtp_hdr[6] << 8) | rtp_hdr[7];
76 cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) |
77 (rtp_hdr[10] << 8) | rtp_hdr[11];
78 if (st->init_flag) {
79 if (cur_ssrc != st->stream_ssrc) {
80 printf(
81 "error in %s packet #%u: SSRC change from 0x%08X to 0x%08X\n",
82 dir_str, pkt_idx, st->stream_ssrc, cur_ssrc);
83 } else if (cur_seq != st->last_seq + 1 &&
84 (cur_seq != 0 || st->last_seq != 0xFFFF)) {
85 printf(
86 "error in %s packet #%u: seq break from 0x%04X to 0x%04X\n",
87 dir_str, pkt_idx, st->last_seq, cur_seq);
88 } else if (cur_tstamp != st->last_tstamp + 160) {
89 printf(
90 "error in %s packet #%u: timestamp break from 0x%08X to 0x%08X\n",
91 dir_str, pkt_idx, st->last_tstamp, cur_tstamp);
92 }
93 } else
94 st->init_flag = 1;
95 st->last_seq = cur_seq;
96 st->last_tstamp = cur_tstamp;
97 st->stream_ssrc = cur_ssrc;
98 }
99
100 static void
101 is_rx_hunt(input_pos, pkt_idx, st, dir_str)
102 unsigned input_pos;
103 unsigned pkt_idx;
104 struct onedir *st;
105 char *dir_str;
106 {
107 unsigned offset, n;
108
109 for (offset = 0; offset < 16; offset++) {
110 for (n = 0; n < 20; n++)
111 if ((st->is_hunt_buf[offset + n*16] & 1) !=
112 hdr_pattern[n])
113 break;
114 if (n == 20)
115 break;
116 }
117 if (n != 20)
118 return;
119 st->is_offset = offset;
120 st->is_alignment = input_pos * 16 + offset;
121 st->is_state = 1;
122 st->is_bit_count = 0;
123 st->is_rx_word = 0;
124 st->is_hunt_fill = 0;
125 }
126
127 static void
128 is_process_cmd(pkt_idx, st, dir_str)
129 unsigned pkt_idx;
130 struct onedir *st;
131 char *dir_str;
132 {
133 int cont;
134
135 printf("#%u: %s (align %u) ", pkt_idx, dir_str, st->is_alignment);
136 switch (st->is_rx_word) {
137 case 0x05D:
138 printf("IS_REQ\n");
139 cont = 1;
140 break;
141 case 0x0BA:
142 printf("IS_ACK\n");
143 cont = 1;
144 break;
145 case 0x0E7:
146 printf("IS_IPE\n");
147 cont = 1;
148 break;
149 case 0x129:
150 printf("IS_FILL\n");
151 cont = 0;
152 break;
153 case 0x174:
154 printf("IS_DUP\n");
155 cont = 0;
156 break;
157 case 0x193:
158 printf("IS_SYL\n");
159 cont = 0;
160 break;
161 default:
162 printf("Unknown IS_Command 0x%03X\n", st->is_rx_word);
163 cont = 0;
164 }
165 if (cont) {
166 st->is_state = 2;
167 st->is_bit_count = 0;
168 st->is_rx_word = 0;
169 } else
170 st->is_state = 0;
171 }
172
173 static void
174 is_process_ext(pkt_idx, st, dir_str)
175 unsigned pkt_idx;
176 struct onedir *st;
177 char *dir_str;
178 {
179 printf("#%u: %s IS_Extension: 0x%05X", pkt_idx, dir_str,
180 st->is_rx_word);
181 if (st->is_rx_word & 0x80200) {
182 printf(" (bad sync)\n");
183 st->is_state = 0;
184 return;
185 }
186 switch (st->is_rx_word & 3) {
187 case 0:
188 printf(" (final)\n");
189 st->is_state = 0;
190 return;
191 case 3:
192 printf(" (continue)\n");
193 st->is_state = 2;
194 st->is_bit_count = 0;
195 st->is_rx_word = 0;
196 return;
197 default:
198 printf(" (bad EX)\n");
199 st->is_state = 0;
200 }
201 }
202
203 static void
204 is_rx_process(input, input_pos, pkt_idx, st, dir_str)
205 uint8_t *input;
206 unsigned input_pos;
207 unsigned pkt_idx;
208 struct onedir *st;
209 char *dir_str;
210 {
211 unsigned new_bit;
212
213 memmove(st->is_hunt_buf, st->is_hunt_buf + 16, 304);
214 memcpy(st->is_hunt_buf + 304, input, 16);
215 if (!st->is_state) {
216 if (st->is_hunt_fill < 20)
217 st->is_hunt_fill++;
218 if (st->is_hunt_fill == 20)
219 is_rx_hunt(input_pos, pkt_idx, st, dir_str);
220 return;
221 }
222 new_bit = input[st->is_offset] & 1;
223 st->is_rx_word <<= 1;
224 st->is_rx_word |= new_bit;
225 st->is_bit_count++;
226 if (st->is_state == 1 && st->is_bit_count == 10)
227 is_process_cmd(pkt_idx, st, dir_str);
228 else if (st->is_state == 2 && st->is_bit_count == 20)
229 is_process_ext(pkt_idx, st, dir_str);
230 }
231
232 static void
233 process_packet_onedir(pkt, caplen, pkt_idx, st, dir_str)
234 u_char *pkt;
235 unsigned caplen, pkt_idx;
236 struct onedir *st;
237 char *dir_str;
238 {
239 unsigned udplen, payload_len;
240 unsigned is_chunk;
241
242 udplen = (pkt[24] << 8) | pkt[25];
243 if (caplen < udplen + 20) {
244 printf("error: %s packet #%u is truncated in the capture\n",
245 dir_str, pkt_idx);
246 return;
247 }
248 if (udplen < 20) {
249 printf(
250 "error in %s packet #%u: UDP length is too short for RTP header\n",
251 dir_str, pkt_idx);
252 return;
253 }
254 if (pkt[28] != 0x80) {
255 printf(
256 "error in %s packet #%u: unsupported RTP header structure\n",
257 dir_str, pkt_idx);
258 return;
259 }
260 rtp_stream_logic(pkt + 28, pkt_idx, st, dir_str);
261 payload_len = udplen - 20;
262 if (payload_len != 160) {
263 printf("error in %s packet #%u: wrong payload length\n",
264 dir_str, pkt_idx);
265 return;
266 }
267 for (is_chunk = 0; is_chunk < 10; is_chunk++)
268 is_rx_process(pkt + 40 + is_chunk * 16, is_chunk, pkt_idx, st,
269 dir_str);
270 }
271
272 static void
273 process_packet(pkt, caplen, pkt_idx)
274 u_char *pkt;
275 unsigned caplen, pkt_idx;
276 {
277 if (caplen < link_hdr_len + 28)
278 return;
279 if (link_hdr_len) {
280 if (pkt[ethertype_offset] != 0x08)
281 return;
282 if (pkt[ethertype_offset+1] != 0x00)
283 return;
284 pkt += link_hdr_len;
285 caplen -= link_hdr_len;
286 }
287 /* check IP header */
288 if (pkt[0] != 0x45)
289 return;
290 if (pkt[9] != 17) /* UDP */
291 return;
292 if (!bcmp(pkt + 12, &match_ip_addr, 4) &&
293 !bcmp(pkt + 20, &match_udp_port, 2))
294 process_packet_onedir(pkt, caplen, pkt_idx, &tx_state, "-->");
295 else if (!bcmp(pkt + 16, &match_ip_addr, 4) &&
296 !bcmp(pkt + 22, &match_udp_port, 2))
297 process_packet_onedir(pkt, caplen, pkt_idx, &rx_state, "<--");
298 }
299
300 main(argc, argv)
301 char **argv;
302 {
303 char errbuf[PCAP_ERRBUF_SIZE];
304 u_char *pkt;
305 struct pcap_pkthdr pkthdr;
306 unsigned pkt_idx;
307
308 if (argc != 4) {
309 fprintf(stderr, "usage: %s pcap-file ip-addr udp-port\n",
310 argv[0]);
311 exit(1);
312 }
313 pcap = pcap_open_offline(argv[1], errbuf);
314 if (!pcap) {
315 fprintf(stderr, "%s: %s\n", argv[1], errbuf);
316 exit(1);
317 }
318 check_dl_type();
319 match_ip_addr = inet_addr(argv[2]);
320 if (match_ip_addr == INADDR_NONE) {
321 fprintf(stderr, "error: IP address argument is invalid\n");
322 exit(1);
323 }
324 match_udp_port = htons(strtoul(argv[3], 0, 0));
325 for (pkt_idx = 0; ; pkt_idx++) {
326 pkt = pcap_next(pcap, &pkthdr);
327 if (!pkt)
328 break;
329 process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx);
330 }
331 if (!tx_state.init_flag)
332 printf(
333 "Warning: found no packets with src matching specified IP:port\n");
334 if (!rx_state.init_flag)
335 printf(
336 "Warning: found no packets with dest matching specified IP:port\n");
337 exit(0);
338 }