comparison pcap/rtp-gsmfr-extr.c @ 15:851ca64e38e9

rtp-gsmfr-extr program written, compiles
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 20 Nov 2022 04:15:44 +0000
parents
children 10f11a2d4042
comparison
equal deleted inserted replaced
14:69ed7af28473 15:851ca64e38e9
1 /*
2 * This program reads a pcap file, extracts packets belonging to a
3 * particular RTP stream as identified by a source or destination
4 * IP:port, verifies that an unbroken RTP stream is present, in
5 * GSM FR or EFR codec, and writes the FR/EFR frame stream to our
6 * extended-libgsm format binary file, to be fed to decoding test
7 * programs.
8 */
9
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <strings.h>
18 #include <pcap/pcap.h>
19
20 static pcap_t *pcap;
21 static in_addr_t match_ip_addr;
22 static u_short match_udp_port;
23 static unsigned iphdr_addr_offset, udphdr_port_offset;
24 static unsigned link_hdr_len, ethertype_offset;
25 static FILE *outfile;
26 static int stream_init_flag;
27 static unsigned last_seq, last_tstamp, stream_ssrc;
28
29 static void
30 check_dl_type()
31 {
32 int dltype;
33
34 dltype = pcap_datalink(pcap);
35 switch (dltype) {
36 case DLT_EN10MB:
37 link_hdr_len = 14;
38 ethertype_offset = 12;
39 break;
40 case DLT_RAW:
41 link_hdr_len = 0;
42 break;
43 case DLT_LINUX_SLL:
44 link_hdr_len = 16;
45 ethertype_offset = 14;
46 break;
47 default:
48 fprintf(stderr, "error: unsupported data link type %d\n",
49 dltype);
50 exit(1);
51 }
52 }
53
54 static void
55 rtp_stream_logic(rtp_hdr, pkt_idx)
56 u_char *rtp_hdr;
57 unsigned pkt_idx;
58 {
59 unsigned cur_seq, cur_tstamp, cur_ssrc;
60
61 cur_seq = (rtp_hdr[2] << 8) | rtp_hdr[3];
62 cur_tstamp = (rtp_hdr[4] << 24) | (rtp_hdr[5] << 16) |
63 (rtp_hdr[6] << 8) | rtp_hdr[7];
64 cur_ssrc = (rtp_hdr[8] << 24) | (rtp_hdr[9] << 16) |
65 (rtp_hdr[10] << 8) | rtp_hdr[11];
66 if (stream_init_flag) {
67 if (cur_ssrc != stream_ssrc) {
68 fprintf(stderr,
69 "error in packet #%u: SSRC change from 0x%08X to 0x%08X\n",
70 pkt_idx, stream_ssrc, cur_ssrc);
71 exit(1);
72 }
73 if (cur_seq != last_seq + 1) {
74 fprintf(stderr,
75 "error in packet #%u: seq break from 0x%04X to 0x%04X\n",
76 pkt_idx, last_seq, cur_seq);
77 exit(1);
78 }
79 if (cur_tstamp != last_tstamp + 160) {
80 fprintf(stderr,
81 "error in packet #%u: timestamp break from 0x%08X to 0x%08X\n",
82 pkt_idx, last_tstamp, cur_tstamp);
83 exit(1);
84 }
85 } else {
86 stream_init_flag = 1;
87 stream_ssrc = cur_ssrc;
88 }
89 last_seq = cur_seq;
90 last_tstamp = cur_tstamp;
91 }
92
93 static void
94 process_packet(pkt, caplen, pkt_idx)
95 u_char *pkt;
96 unsigned caplen, pkt_idx;
97 {
98 unsigned udplen, payload_len;
99
100 if (caplen < link_hdr_len + 28)
101 return;
102 if (link_hdr_len) {
103 if (pkt[ethertype_offset] != 0x08)
104 return;
105 if (pkt[ethertype_offset+1] != 0x00)
106 return;
107 pkt += link_hdr_len;
108 caplen -= link_hdr_len;
109 }
110 /* check IP header */
111 if (pkt[0] != 0x45)
112 return;
113 if (pkt[9] != 17) /* UDP */
114 return;
115 if (bcmp(pkt + iphdr_addr_offset, &match_ip_addr, 4))
116 return;
117 /* check UDP header */
118 if (bcmp(pkt + 20 + udphdr_port_offset, &match_udp_port, 2))
119 return;
120 /* it is our target - now scrutinize it */
121 udplen = (pkt[24] << 8) | pkt[25];
122 if (caplen < udplen + 20) {
123 fprintf(stderr,
124 "error: packet #%u is truncated in the capture\n",
125 pkt_idx);
126 exit(1);
127 }
128 if (udplen < 20) {
129 fprintf(stderr,
130 "error in packet #%u: UDP length is too short for RTP header\n",
131 pkt_idx);
132 exit(1);
133 }
134 if (pkt[28] != 0x80) {
135 fprintf(stderr,
136 "error in packet #%u: unsupported RTP header structure\n",
137 pkt_idx);
138 exit(1);
139 }
140 rtp_stream_logic(pkt + 28, pkt_idx);
141 payload_len = udplen - 20;
142 switch (payload_len) {
143 case 2:
144 if (pkt[40] == 0xBF)
145 break;
146 goto bad_payload;
147 case 31:
148 if ((pkt[40] & 0xF0) == 0xC0)
149 break;
150 goto bad_payload;
151 case 33:
152 if ((pkt[40] & 0xF0) == 0xD0)
153 break;
154 /* FALL THRU */
155 default:
156 bad_payload:
157 fprintf(stderr, "error in packet #%u: unsupported payload\n",
158 pkt_idx);
159 exit(1);
160 }
161 fwrite(pkt + 40, 1, payload_len, outfile);
162 }
163
164 main(argc, argv)
165 char **argv;
166 {
167 char errbuf[PCAP_ERRBUF_SIZE];
168 u_char *pkt;
169 struct pcap_pkthdr pkthdr;
170 unsigned pkt_idx;
171
172 if (argc != 6) {
173 fprintf(stderr,
174 "usage: %s pcap-file src|dest ip-addr udp-port outfile\n",
175 argv[0]);
176 exit(1);
177 }
178 pcap = pcap_open_offline(argv[1], errbuf);
179 if (!pcap) {
180 fprintf(stderr, "%s: %s\n", argv[1], errbuf);
181 exit(1);
182 }
183 check_dl_type();
184 if (!strcmp(argv[2], "src")) {
185 iphdr_addr_offset = 12;
186 udphdr_port_offset = 0;
187 } else if (!strcmp(argv[2], "dest")) {
188 iphdr_addr_offset = 16;
189 udphdr_port_offset = 2;
190 } else {
191 fprintf(stderr,
192 "error: direction argument must be \"src\" or \"dest\"\n");
193 exit(1);
194 }
195 match_ip_addr = inet_addr(argv[3]);
196 if (match_ip_addr == INADDR_NONE) {
197 fprintf(stderr, "error: IP address argument is invalid\n");
198 exit(1);
199 }
200 match_udp_port = htons(strtoul(argv[4], 0, 0));
201 outfile = fopen(argv[5], "w");
202 if (!outfile) {
203 perror(argv[5]);
204 exit(1);
205 }
206 for (pkt_idx = 0; ; pkt_idx++) {
207 pkt = pcap_next(pcap, &pkthdr);
208 if (!pkt)
209 break;
210 process_packet(pkt, (unsigned) pkthdr.caplen, pkt_idx);
211 }
212 if (!stream_init_flag) {
213 fprintf(stderr, "error: specified RTP stream not found\n");
214 exit(1);
215 }
216 fclose(outfile);
217 exit(0);
218 }