source: examples/munge/munge.c @ aca3ff4

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since aca3ff4 was aca3ff4, checked in by Perry Lorier <perry@…>, 16 years ago

Add the ability to concatenate traces

  • Property mode set to 100644
File size: 8.1 KB
Line 
1#define _GNU_SOURCE
2#include "libtrace.h"
3#include "lib/lib.h"
4#include <stdio.h>
5#include <unistd.h>
6#include <stdlib.h>
7#include <getopt.h>
8#include <stdbool.h>
9#include <stddef.h>
10#include <string.h>
11#include <pcap.h>
12#include <time.h>
13
14static int trace_link_type_to_dlt(libtrace_linktype_t t)
15{
16        static int table[] = {
17                -1, /* LEGACY */
18                -1, /* HDLC over POS */
19                DLT_EN10MB, /* Ethernet */
20                -1, /* ATM */
21                DLT_IEEE802_11, /* 802.11 */
22        };
23        if (t>sizeof(table)/sizeof(*table)) {
24                return -1;
25        }
26        return table[t];
27}
28
29void usage(char *argv0)
30{
31        fprintf(stderr,"Usage:\n"
32        "%s flags inputfile >outputfile\n"
33        "-s --encrypt-source    Encrypt the source addresses\n"
34        "-d --encrypt-dest      Encrypt the destination addresses\n"
35        "-c --cryptopan=key     Encrypt the addresses with the cryptopan\n"
36        "                       prefix preserving\n"
37        "-p --prefix=C.I.D.R/bits Substitute the prefix of the address\n"
38        "-f --filter=expr       Apply a tcpdump filter\n"
39        "-b --start-time=date   Show only packets after this time\n"
40        "-f --end-time=date     Show only packets before this time\n"
41        ,argv0);
42        exit(0);
43}
44
45// Incrementally update a checksum
46void update_in_cksum(uint16_t *csum, uint16_t old, uint16_t new)
47{
48        uint32_t sum = (~htons(*csum) & 0xFFFF) 
49                     + (~htons(old) & 0xFFFF) 
50                     + htons(new);
51        sum = (sum & 0xFFFF) + (sum >> 16);
52        *csum = htons(~(sum + (sum >> 16)));
53}
54
55void update_in_cksum32(uint16_t *csum, uint32_t old, uint32_t new)
56{
57        update_in_cksum(csum,old>>16,new>>16);
58        update_in_cksum(csum,old&0xFFFF,new&0xFFFF);
59}
60
61struct libtrace_tcp *get_tcp_from_ip(struct libtrace_ip *ip)
62{
63#define SW_IP_OFFMASK 0xff1f
64        struct libtrace_tcp *tcpptr = 0;
65
66        if ((ip->ip_p == 6) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
67                tcpptr = (struct libtrace_tcp *)((ptrdiff_t)ip+ (ip->ip_hl * 4));
68        }
69        return tcpptr;
70}
71
72struct libtrace_udp *get_udp_from_ip(struct libtrace_ip *ip)
73{
74        struct libtrace_udp *udpptr = 0;
75
76        if ((ip->ip_p == 17) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
77                udpptr = (struct libtrace_udp *)((ptrdiff_t)ip+(ip->ip_hl*4));
78        }
79        return udpptr;
80}
81
82struct libtrace_icmp *get_icmp_from_ip(struct libtrace_ip *ip)
83{
84        struct libtrace_icmp *icmpptr = 0;
85
86        if ((ip->ip_p == 17) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
87                icmpptr = (struct libtrace_icmp *)((ptrdiff_t)ip+(ip->ip_hl*4));
88        }
89        return icmpptr;
90}
91
92/* Ok this is remarkably complicated
93 *
94 * We want to change one, or the other IP address, while preserving the
95 * checksum.  TCP and UDP both include the faux header in their checksum
96 * calculations, so you have to update them too.  ICMP is even worse --
97 * it can include the original IP packet that caused the error!  So anonymise
98 * that too, but remember that it's travelling in the opposite direction so
99 * we need to encrypt the destination and source instead of the source and
100 * destination!
101 */
102void encrypt_ips(struct libtrace_ip *ip,bool enc_source,bool enc_dest)
103{
104        struct libtrace_tcp *tcp;
105        struct libtrace_udp *udp;
106        struct libtrace_icmp *icmp;
107
108        tcp=get_tcp_from_ip(ip);
109        udp=get_udp_from_ip(ip);
110        icmp=get_icmp_from_ip(ip);
111
112        if (enc_source) {
113                uint32_t old_ip=ip->ip_src.s_addr;
114                uint32_t new_ip=htonl(trace_enc_ip(
115                                        htonl(ip->ip_src.s_addr)
116                                        ));
117                update_in_cksum32(&ip->ip_sum,old_ip,new_ip);
118                if (tcp) update_in_cksum(&tcp->check,old_ip,new_ip);
119                if (udp) update_in_cksum(&udp->check,old_ip,new_ip);
120                ip->ip_src.s_addr = new_ip;
121        }
122
123        if (enc_dest) {
124                uint32_t old_ip=ip->ip_dst.s_addr;
125                uint32_t new_ip=htonl(trace_enc_ip(
126                                        htonl(ip->ip_dst.s_addr)
127                                        ));
128                update_in_cksum32(&ip->ip_sum,old_ip,new_ip);
129                if (tcp) update_in_cksum(&tcp->check,old_ip,new_ip);
130                if (udp) update_in_cksum(&udp->check,old_ip,new_ip);
131                ip->ip_dst.s_addr = new_ip;
132        }
133
134        if (icmp) {
135                /* These are error codes that return the IP packet internally */
136                if (icmp->type == 3 || icmp->type == 5 || icmp->type == 11) {
137                        encrypt_ips(
138                                        (struct libtrace_ip*)icmp+
139                                                sizeof(struct libtrace_icmp),
140                                        enc_dest,
141                                        enc_source);
142                }
143        }
144}
145
146struct libtrace_write_t {
147        pcap_dumper_t *pcap;
148};
149
150void trace_write(struct libtrace_write_t *hdl,struct libtrace_packet_t *pkt)
151{
152        struct pcap_pkthdr pcap_pkt_hdr;
153        void *link = trace_get_link(pkt);
154
155        pcap_pkt_hdr.ts=trace_get_timeval(pkt);
156        pcap_pkt_hdr.caplen = trace_get_capture_length(pkt);
157        pcap_pkt_hdr.len = trace_get_wire_length(pkt);
158        pcap_dump((u_char*)hdl->pcap, &pcap_pkt_hdr, link);
159}
160
161double parse_date(const char *date)
162{
163        struct tm *parsed_time;
164
165        parsed_time=getdate(date);
166
167        if (parsed_time) {
168                return (double)mktime(parsed_time);
169        }
170
171        switch(getdate_err) {
172                case 1:
173                        fprintf(stderr,"Cannot parse date: The DATEMSK environmental variable is null or undefined\n");
174                        break;
175                case 2:
176                        fprintf(stderr,"The date template file '%s' cannot be opened for reading\n",getenv("DATEMSK"));
177                        break;
178                case 3:
179                        fprintf(stderr,"Failed to get file status information for '%s'\n",getenv("DATEMSK"));
180                        break;
181                case 4:
182                        fprintf(stderr,"%s: Not a regular file\n",getenv("DATEMSK"));
183                        break;
184                case 5:
185                        fprintf(stderr,"An error occured reading '%s'\n",getenv("DATEMSK"));
186                        break;
187                case 6:
188                        fprintf(stderr,"Out of memory reading '%s'\n",getenv("DATEMSK"));
189                        break;
190                case 7:
191                        fprintf(stderr,"Could not parse '%s'\n",date);
192                        break;
193                case 8:
194                        fprintf(stderr,"Invalid specification in '%s'\n",getenv("DATEMSK"));
195                        break;
196                default:
197                        fprintf(stderr,"Unable to parse date '%s': Unknown error\n",date);
198        }
199        exit(1);
200}
201
202int main(int argc, char *argv[]) 
203{
204        enum enc_type_t enc_type = ENC_NONE;
205        char *key = NULL;
206        struct libtrace_filter_t *filter = NULL;
207        struct libtrace_t *trace;
208        struct libtrace_packet_t packet;
209        struct libtrace_write_t writer;
210        bool enc_source = false;
211        bool enc_dest   = false;
212        double start_time = 0;
213        double end_time = 1e100;
214        pcap_t *p = NULL;
215
216        if (argc<2)
217                usage(argv[0]);
218
219        while (1) {
220                int option_index;
221                struct option long_options[] = {
222                        { "encrypt-source",     0, 0, 's' },
223                        { "encrypt-dest",       0, 0, 'd' },
224                        { "cryptopan",          1, 0, 'c' },
225                        { "prefix",             1, 0, 'p' },
226                        { "filter",             1, 0, 'f' },
227                        { "start-time",         1, 0, 'b' },
228                        { "end-time",           1, 0, 'e' },
229                        { NULL,                 0, 0, 0 },
230                };
231
232                int c=getopt_long(argc, argv, "sb:c:de:p:f:",
233                                long_options, &option_index);
234
235                if (c==-1)
236                        break;
237
238                switch (c) {
239                        case 's': enc_source=true; break;
240                        case 'd': enc_dest  =true; break;
241                        case 'c':
242                                  if (key!=NULL) {
243                                          fprintf(stderr,"You can only have one encryption type and one key\n");
244                                          usage(argv[0]);
245                                  }
246                                  key=strdup(optarg);
247                                  enc_type = ENC_CRYPTOPAN;
248                                  break;
249                        case 'p':
250                                  if (key!=NULL) {
251                                          fprintf(stderr,"You can only have one encryption type and one key\n");
252                                          usage(argv[0]);
253                                  }
254                                  key=strdup(optarg);
255                                  enc_type = ENC_PREFIX_SUBSTITUTION;
256                                  break;
257                        case 'f':
258                                  if (filter!=NULL) {
259                                          fprintf(stderr,"You can only have one filter (use and!)\n");
260                                          usage(argv[0]);
261                                  }
262                                  filter=trace_bpf_setfilter(optarg);
263                                  break;
264                        case 'b': /* "begin" time */
265                                  start_time = parse_date(optarg);
266                                  break;
267                        case 'e': /* "end" time */
268                                  start_time = parse_date(optarg);
269                                  break;
270                        default:
271                                fprintf(stderr,"unknown option: %c\n",c);
272                                usage(argv[0]);
273
274                }
275
276        }
277
278        trace_enc_init(enc_type,key);
279
280        p = NULL;
281
282        while(optind<argc) {
283                /* Do the actual processing */
284                trace = trace_create(argv[optind]);
285                if (!trace) {
286                        fprintf(stderr,"Cannot open %s\n",argv[optind]);
287                        return 1;
288                }
289                for(;;) {
290                        struct libtrace_ip *ipptr;
291                        int psize;
292                        double ts;
293                        if ((psize = trace_read_packet(trace, &packet)) <= 0) {
294                                break;
295                        }
296                        if (!p) {
297                                p=pcap_open_dead(
298                                        trace_link_type_to_dlt(
299                                                trace_get_link_type(&packet)),
300                                        65536);
301                                writer.pcap = pcap_dump_open(p,"-");
302                                fflush((FILE *)writer.pcap);
303                        }
304
305                        /* Skip packets that don't match the filter */
306                        if (filter && !trace_bpf_filter(filter,&packet)) {
307                                continue;
308                        }
309
310                        ts = trace_get_seconds(&packet);
311
312                        /* skip packets before/after the time */
313                        if (ts < start_time || ts > end_time) {
314                                continue;
315                        }
316
317                        ipptr = trace_get_ip(&packet);
318
319                        if (ipptr && (enc_source || enc_dest))
320                                encrypt_ips(ipptr,enc_source,enc_dest);
321
322                        /* TODO: Encrypt IP's in ARP packets */
323
324                        trace_write(&writer,&packet);
325                }
326                optind++;
327        }
328        return 0;
329}
Note: See TracBrowser for help on using the repository browser.