source: tools/traceanon/traceanon.c @ 4a5678c

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivelibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 4a5678c was 4a5678c, checked in by Shane Alcock <salcock@…>, 6 years ago

Fixed a couple of annoying things about traceanon

Added a -f option to filter packets received from the input source.
Unfortunately, we already had an option using '-f' so I have changed that
option to use -F so that all of our tools can be consistent. Apologies in
advance to anyone whose scripts break because of this change.

traceanon will now handle keyboard interrupts nicely when reading from a live
source -- any buffered output will now be written nicely to disk rather than
being lost forever.

Updated manpage for traceanon to match new options.

  • Property mode set to 100644
File size: 10.2 KB
Line 
1#define _GNU_SOURCE
2#include "libtrace.h"
3#include <stdio.h>
4#include <unistd.h>
5#include <stdlib.h>
6#include <getopt.h>
7#include <stdbool.h>
8#include <stddef.h>
9#include <string.h>
10#include <time.h>
11#include <signal.h>
12#include "ipenc.h"
13
14static void usage(char *argv0)
15{
16        fprintf(stderr,"Usage:\n"
17        "%s flags inputfile outputfile\n"
18        "-s --encrypt-source    Encrypt the source addresses\n"
19        "-d --encrypt-dest      Encrypt the destination addresses\n"
20        "-c --cryptopan=key     Encrypt the addresses with the cryptopan\n"
21        "                       prefix preserving\n"
22        "-F --keyfile=file      A file containing the cryptopan key\n"
23        "-f --filter=expr       Discard all packets that do not match the\n"
24        "                       provided BPF expression\n"
25        "-p --prefix=C.I.D.R/bits Substitute the prefix of the address\n"
26        "-H --libtrace-help     Print libtrace runtime documentation\n"
27        "-z --compress-level    Compress the output trace at the specified level\n"
28        "-Z --compress-type     Compress the output trace using the specified\n"
29        "                       compression algorithm\n"
30        ,argv0);
31        exit(1);
32}
33
34volatile int done=0;
35
36static void cleanup_signal(int sig)
37{
38        (void)sig;
39        done=1;
40        trace_interrupt();
41}
42
43/* Incrementally update a checksum */
44static void update_in_cksum(uint16_t *csum, uint16_t old, uint16_t new)
45{
46        uint32_t sum = (~htons(*csum) & 0xFFFF) 
47                     + (~htons(old) & 0xFFFF) 
48                     + htons(new);
49        sum = (sum & 0xFFFF) + (sum >> 16);
50        *csum = htons(~(sum + (sum >> 16)));
51}
52
53static void update_in_cksum32(uint16_t *csum, uint32_t old, uint32_t new)
54{
55        update_in_cksum(csum,(uint16_t)(old>>16),(uint16_t)(new>>16));
56        update_in_cksum(csum,(uint16_t)(old&0xFFFF),(uint16_t)(new&0xFFFF));
57}
58
59/* Ok this is remarkably complicated
60 *
61 * We want to change one, or the other IP address, while preserving
62 * the checksum.  TCP and UDP both include the faux header in their
63 * checksum calculations, so you have to update them too.  ICMP is
64 * even worse -- it can include the original IP packet that caused the
65 * error!  So anonymise that too, but remember that it's travelling in
66 * the opposite direction so we need to encrypt the destination and
67 * source instead of the source and destination!
68 */
69static void encrypt_ips(struct libtrace_ip *ip,bool enc_source,bool enc_dest)
70{
71        struct libtrace_tcp *tcp;
72        struct libtrace_udp *udp;
73        struct libtrace_icmp *icmp;
74
75        tcp=trace_get_tcp_from_ip(ip,NULL);
76        udp=trace_get_udp_from_ip(ip,NULL);
77        icmp=trace_get_icmp_from_ip(ip,NULL);
78
79        if (enc_source) {
80                uint32_t old_ip=ip->ip_src.s_addr;
81                uint32_t new_ip=htonl(enc_ip(
82                                        htonl(ip->ip_src.s_addr)
83                                        ));
84                update_in_cksum32(&ip->ip_sum,old_ip,new_ip);
85                if (tcp) update_in_cksum32(&tcp->check,old_ip,new_ip);
86                if (udp) update_in_cksum32(&udp->check,old_ip,new_ip);
87                ip->ip_src.s_addr = new_ip;
88        }
89
90        if (enc_dest) {
91                uint32_t old_ip=ip->ip_dst.s_addr;
92                uint32_t new_ip=htonl(enc_ip(
93                                        htonl(ip->ip_dst.s_addr)
94                                        ));
95                update_in_cksum32(&ip->ip_sum,old_ip,new_ip);
96                if (tcp) update_in_cksum32(&tcp->check,old_ip,new_ip);
97                if (udp) update_in_cksum32(&udp->check,old_ip,new_ip);
98                ip->ip_dst.s_addr = new_ip;
99        }
100
101        if (icmp) {
102                /* These are error codes that return the IP packet
103                 * internally
104                 */
105               
106                if (icmp->type == 3 
107                                || icmp->type == 5 
108                                || icmp->type == 11) {
109                        char *ptr = (char *)icmp;
110                        encrypt_ips(
111                                (struct libtrace_ip*)(ptr+
112                                        sizeof(struct libtrace_icmp)),
113                                enc_dest,
114                                enc_source);
115                }
116
117                if (enc_source || enc_dest)
118                        icmp->checksum = 0;
119        }
120}
121
122int main(int argc, char *argv[]) 
123{
124        enum enc_type_t enc_type = ENC_NONE;
125        char *key = NULL;
126        struct libtrace_t *trace = 0;
127        struct libtrace_packet_t *packet = trace_create_packet();
128        struct libtrace_out_t *writer = 0;
129        struct libtrace_filter_t *filter = NULL;
130        bool enc_source = false;
131        bool enc_dest   = false;
132        char *output = 0;
133        int level = -1;
134        char *filterstring = NULL;
135        char *compress_type_str=NULL;
136        trace_option_compresstype_t compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
137        struct sigaction sigact;
138
139        if (argc<2)
140                usage(argv[0]);
141
142        sigact.sa_handler = cleanup_signal;
143        sigemptyset(&sigact.sa_mask);
144        sigact.sa_flags = SA_RESTART;
145
146        signal(SIGINT,&cleanup_signal);
147        signal(SIGTERM,&cleanup_signal);
148
149        while (1) {
150                int option_index;
151                struct option long_options[] = {
152                        { "encrypt-source",     0, 0, 's' },
153                        { "encrypt-dest",       0, 0, 'd' },
154                        { "cryptopan",          1, 0, 'c' },
155                        { "cryptopan-file",     1, 0, 'F' },
156                        { "filter",             1, 0, 'f' },
157                        { "prefix",             1, 0, 'p' },
158                        { "compress-level",     1, 0, 'z' },
159                        { "compress-type",      1, 0, 'Z' },
160                        { "libtrace-help",      0, 0, 'H' },
161                        { NULL,                 0, 0, 0   },
162                };
163
164                int c=getopt_long(argc, argv, "Z:z:sc:f:dp:H",
165                                long_options, &option_index);
166
167                if (c==-1)
168                        break;
169
170                switch (c) {
171                        case 'Z': compress_type_str=optarg; break;         
172                        case 'z': level = atoi(optarg); break;
173                        case 's': enc_source=true; break;
174                        case 'd': enc_dest  =true; break;
175                        case 'f': filterstring = optarg; break;
176                        case 'c':
177                                  if (key!=NULL) {
178                                          fprintf(stderr,"You can only have one encryption type and one key\n");
179                                          usage(argv[0]);
180                                  }
181                                  key=strdup(optarg);
182                                  enc_type = ENC_CRYPTOPAN;
183                                  break;
184                        case 'F':
185                                  if(key != NULL) {
186                                    fprintf(stderr,"You can only have one encryption type and one key\n");
187                                    usage(argv[0]);
188                                  }
189                                  FILE * infile = fopen(optarg,"rb");
190                                  if(infile == NULL) {
191                                    perror("Failed to open cryptopan keyfile");
192                                    return 1;
193                                  }
194                                  key = (char *) malloc(sizeof(char *) * 32);
195                                  if(fread(key,1,32,infile) != 32) {
196                                    if(ferror(infile)) {
197                                      perror("Failed while reading cryptopan keyfile");
198                                    }
199                                  }
200                                  fclose(infile);
201                                  enc_type = ENC_CRYPTOPAN;
202                                  break;
203                        case 'p':
204                                  if (key!=NULL) {
205                                          fprintf(stderr,"You can only have one encryption type and one key\n");
206                                          usage(argv[0]);
207                                  }
208                                  key=strdup(optarg);
209                                  enc_type = ENC_PREFIX_SUBSTITUTION;
210                                  break;
211                        case 'H':
212                                  trace_help(); 
213                                  exit(1); 
214                                  break;
215                        default:
216                                fprintf(stderr,"unknown option: %c\n",c);
217                                usage(argv[0]);
218
219                }
220
221        }
222
223        if (compress_type_str == NULL && level >= 0) {
224                fprintf(stderr, "Compression level set, but no compression type was defined, setting to gzip\n");
225                compress_type = TRACE_OPTION_COMPRESSTYPE_ZLIB;
226        }
227
228        else if (compress_type_str == NULL) {
229                /* If a level or type is not specified, use the "none"
230                 * compression module */
231                compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
232        }
233
234        /* I decided to be fairly generous in what I accept for the
235         * compression type string */
236        else if (strncmp(compress_type_str, "gz", 2) == 0 ||
237                        strncmp(compress_type_str, "zlib", 4) == 0) {
238                compress_type = TRACE_OPTION_COMPRESSTYPE_ZLIB;
239        } else if (strncmp(compress_type_str, "bz", 2) == 0) {
240                compress_type = TRACE_OPTION_COMPRESSTYPE_BZ2;
241        } else if (strncmp(compress_type_str, "lzo", 3) == 0) {
242                compress_type = TRACE_OPTION_COMPRESSTYPE_LZO;
243        } else if (strncmp(compress_type_str, "xz", 2) == 0) {
244                compress_type = TRACE_OPTION_COMPRESSTYPE_LZMA;
245        } else if (strncmp(compress_type_str, "no", 2) == 0) {
246                compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
247        } else {
248                fprintf(stderr, "Unknown compression type: %s\n",
249                        compress_type_str);
250                return 1;
251        }
252       
253
254        if (filterstring) {
255            filter = trace_create_filter(filterstring);
256        }
257
258        enc_init(enc_type,key);
259
260        /* open input uri */
261        trace = trace_create(argv[optind]);
262        if (trace_is_err(trace)) {
263                trace_perror(trace,"trace_create");
264                trace_destroy(trace);
265                return 1;
266        }
267
268        if (optind +1>= argc) {
269                /* no output specified, output in same format to
270                 * stdout
271                 */
272                output = strdup("erf:-");
273                writer = trace_create_output(output);
274        } else {
275                writer = trace_create_output(argv[optind +1]);
276        }
277        if (trace_is_err_output(writer)) {
278                trace_perror_output(writer,"trace_create_output");
279                trace_destroy_output(writer);
280                trace_destroy(trace);
281                return 1;
282        }
283       
284        /* Hopefully this will deal nicely with people who want to crank the
285         * compression level up to 11 :) */
286        if (level > 9) {
287                fprintf(stderr, "WARNING: Compression level > 9 specified, setting to 9 instead\n");
288                level = 9;
289        }
290
291        if (level >= 0 && trace_config_output(writer, 
292                        TRACE_OPTION_OUTPUT_COMPRESS, &level) == -1) {
293                trace_perror_output(writer, "Configuring compression level");
294                trace_destroy_output(writer);
295                trace_destroy(trace);
296                return 1;
297        }
298
299        if (trace_config_output(writer, TRACE_OPTION_OUTPUT_COMPRESSTYPE,
300                                &compress_type) == -1) {
301                trace_perror_output(writer, "Configuring compression type");
302                trace_destroy_output(writer);
303                trace_destroy(trace);
304                return 1;
305        }
306
307        if (filter && trace_config(trace, TRACE_OPTION_FILTER, filter) == -1) {
308                trace_perror(trace, "Configuring input filter");
309                trace_destroy_output(writer);
310                trace_destroy(trace);
311                return 1;
312        }
313
314        if (trace_start(trace)==-1) {
315                trace_perror(trace,"trace_start");
316                trace_destroy_output(writer);
317                trace_destroy(trace);
318                return 1;
319        }
320        if (trace_start_output(writer)==-1) {
321                trace_perror_output(writer,"trace_start_output");
322                trace_destroy_output(writer);
323                trace_destroy(trace);
324                return 1;
325        }
326        for(;;) {
327                struct libtrace_ip *ipptr;
328                libtrace_udp_t *udp = NULL;
329                libtrace_tcp_t *tcp = NULL;
330
331                int psize;
332                psize = trace_read_packet(trace, packet);
333                if (psize <= 0) {
334                        break;
335                }
336
337                ipptr = trace_get_ip(packet);
338
339                if (ipptr && (enc_source || enc_dest)) {
340                        encrypt_ips(ipptr,enc_source,enc_dest);
341                        ipptr->ip_sum = 0;
342                }
343
344                /* Replace checksums so that IP encryption cannot be
345                 * reversed */
346
347                /* XXX replace with nice use of trace_get_transport() */
348
349                udp = trace_get_udp(packet);
350                if (udp && (enc_source || enc_dest)) {
351                        udp->check = 0;
352                } 
353
354                tcp = trace_get_tcp(packet);
355                if (tcp && (enc_source || enc_dest)) {
356                        tcp->check = 0;
357                }
358       
359                /* TODO: Encrypt IP's in ARP packets */
360
361                if (trace_write_packet(writer,packet)==-1) {
362                        trace_perror_output(writer,"writer");
363                        break;
364                }
365
366                if (done)
367                    break;
368        }
369        if (trace_is_err(trace)) {
370            trace_perror(trace,"read_packet");
371        }
372
373        if (filter)
374            trace_destroy_filter(filter);
375       
376        trace_destroy_packet(packet);
377        trace_destroy(trace);
378        trace_destroy_output(writer);
379        return 0;
380}
Note: See TracBrowser for help on using the repository browser.