source: tools/traceanon/traceanon.c @ 97b5bf4

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 97b5bf4 was 97b5bf4, checked in by Shane Alcock <salcock@…>, 12 years ago
  • Updated traceanon to support a compression type option
  • Property mode set to 100644
File size: 8.3 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 "ipenc.h"
12
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        "-p --prefix=C.I.D.R/bits Substitute the prefix of the address\n"
23        "-H --libtrace-help     Print libtrace runtime documentation\n"
24        "-z --compression-level Compress the output trace at the specified level\n"
25        "-Z --compression-type  Compress the output trace using the specified                                   compression algorithm\n"
26        ,argv0);
27        exit(1);
28}
29
30/* Incrementally update a checksum */
31static void update_in_cksum(uint16_t *csum, uint16_t old, uint16_t new)
32{
33        uint32_t sum = (~htons(*csum) & 0xFFFF) 
34                     + (~htons(old) & 0xFFFF) 
35                     + htons(new);
36        sum = (sum & 0xFFFF) + (sum >> 16);
37        *csum = htons(~(sum + (sum >> 16)));
38}
39
40static void update_in_cksum32(uint16_t *csum, uint32_t old, uint32_t new)
41{
42        update_in_cksum(csum,(uint16_t)(old>>16),(uint16_t)(new>>16));
43        update_in_cksum(csum,(uint16_t)(old&0xFFFF),(uint16_t)(new&0xFFFF));
44}
45
46/* Ok this is remarkably complicated
47 *
48 * We want to change one, or the other IP address, while preserving
49 * the checksum.  TCP and UDP both include the faux header in their
50 * checksum calculations, so you have to update them too.  ICMP is
51 * even worse -- it can include the original IP packet that caused the
52 * error!  So anonymise that too, but remember that it's travelling in
53 * the opposite direction so we need to encrypt the destination and
54 * source instead of the source and destination!
55 */
56static void encrypt_ips(struct libtrace_ip *ip,bool enc_source,bool enc_dest)
57{
58        struct libtrace_tcp *tcp;
59        struct libtrace_udp *udp;
60        struct libtrace_icmp *icmp;
61
62        tcp=trace_get_tcp_from_ip(ip,NULL);
63        udp=trace_get_udp_from_ip(ip,NULL);
64        icmp=trace_get_icmp_from_ip(ip,NULL);
65
66        if (enc_source) {
67                uint32_t old_ip=ip->ip_src.s_addr;
68                uint32_t new_ip=htonl(enc_ip(
69                                        htonl(ip->ip_src.s_addr)
70                                        ));
71                update_in_cksum32(&ip->ip_sum,old_ip,new_ip);
72                if (tcp) update_in_cksum32(&tcp->check,old_ip,new_ip);
73                if (udp) update_in_cksum32(&udp->check,old_ip,new_ip);
74                ip->ip_src.s_addr = new_ip;
75        }
76
77        if (enc_dest) {
78                uint32_t old_ip=ip->ip_dst.s_addr;
79                uint32_t new_ip=htonl(enc_ip(
80                                        htonl(ip->ip_dst.s_addr)
81                                        ));
82                update_in_cksum32(&ip->ip_sum,old_ip,new_ip);
83                if (tcp) update_in_cksum32(&tcp->check,old_ip,new_ip);
84                if (udp) update_in_cksum32(&udp->check,old_ip,new_ip);
85                ip->ip_dst.s_addr = new_ip;
86        }
87
88        if (icmp) {
89                /* These are error codes that return the IP packet
90                 * internally
91                 */
92                if (icmp->type == 3 
93                                || icmp->type == 5 
94                                || icmp->type == 11) {
95                        encrypt_ips(
96                                (struct libtrace_ip*)icmp+
97                                        sizeof(struct libtrace_icmp),
98                                enc_dest,
99                                enc_source);
100                }
101        }
102}
103
104int main(int argc, char *argv[]) 
105{
106        enum enc_type_t enc_type = ENC_NONE;
107        char *key = NULL;
108        struct libtrace_t *trace = 0;
109        struct libtrace_packet_t *packet = trace_create_packet();
110        struct libtrace_out_t *writer = 0;
111        bool enc_source = false;
112        bool enc_dest   = false;
113        char *output = 0;
114        int level = -1;
115        char *compress_type_str=NULL;
116        trace_option_compresstype_t compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
117
118
119        if (argc<2)
120                usage(argv[0]);
121
122        while (1) {
123                int option_index;
124                struct option long_options[] = {
125                        { "encrypt-source",     0, 0, 's' },
126                        { "encrypt-dest",       0, 0, 'd' },
127                        { "cryptopan",          1, 0, 'c' },
128                        { "prefix",             1, 0, 'p' },
129                        { "compression-level",  1, 0, 'z' },
130                        { "compression-type",   1, 0, 'Z' },
131                        { "libtrace-help",      0, 0, 'H' },
132                        { NULL,                 0, 0, 0   },
133                };
134
135                int c=getopt_long(argc, argv, "Z:z:sc:dp:H",
136                                long_options, &option_index);
137
138                if (c==-1)
139                        break;
140
141                switch (c) {
142                        case 'Z': compress_type_str=optarg; break;         
143                        case 'z': level = atoi(optarg); break;
144                        case 's': enc_source=true; break;
145                        case 'd': enc_dest  =true; break;
146                        case 'c':
147                                  if (key!=NULL) {
148                                          fprintf(stderr,"You can only have one encryption type and one key\n");
149                                          usage(argv[0]);
150                                  }
151                                  key=strdup(optarg);
152                                  enc_type = ENC_CRYPTOPAN;
153                                  break;
154                        case 'p':
155                                  if (key!=NULL) {
156                                          fprintf(stderr,"You can only have one encryption type and one key\n");
157                                          usage(argv[0]);
158                                  }
159                                  key=strdup(optarg);
160                                  enc_type = ENC_PREFIX_SUBSTITUTION;
161                                  break;
162                        case 'H':
163                                  trace_help(); 
164                                  exit(1); 
165                                  break;
166                        default:
167                                fprintf(stderr,"unknown option: %c\n",c);
168                                usage(argv[0]);
169
170                }
171
172        }
173
174        if (compress_type_str == NULL && level >= 0) {
175                fprintf(stderr, "Compression level set, but no compression type was defined, setting to gzip\n");
176                compress_type = TRACE_OPTION_COMPRESSTYPE_ZLIB;
177        }
178
179        else if (compress_type_str == NULL) {
180                /* If a level or type is not specified, use the "none"
181                 * compression module */
182                compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
183        }
184
185        /* I decided to be fairly generous in what I accept for the
186         * compression type string */
187        else if (strncmp(compress_type_str, "gz", 2) == 0 ||
188                        strncmp(compress_type_str, "zlib", 4) == 0) {
189                compress_type = TRACE_OPTION_COMPRESSTYPE_ZLIB;
190        } else if (strncmp(compress_type_str, "bz", 2) == 0) {
191                compress_type = TRACE_OPTION_COMPRESSTYPE_BZ2;
192        } else if (strncmp(compress_type_str, "lzo", 3) == 0) {
193                compress_type = TRACE_OPTION_COMPRESSTYPE_LZO;
194        } else if (strncmp(compress_type_str, "no", 2) == 0) {
195                compress_type = TRACE_OPTION_COMPRESSTYPE_NONE;
196        } else {
197                fprintf(stderr, "Unknown compression type: %s\n",
198                        compress_type_str);
199                return 1;
200        }
201       
202
203        enc_init(enc_type,key);
204
205        /* open input uri */
206        trace = trace_create(argv[optind]);
207        if (trace_is_err(trace)) {
208                trace_perror(trace,argv[optind]);
209                trace_destroy(trace);
210                return 1;
211        }
212
213        if (optind +1>= argc) {
214                /* no output specified, output in same format to
215                 * stdout
216                 */
217                output = strdup("erf:-");
218                writer = trace_create_output(output);
219        } else {
220                writer = trace_create_output(argv[optind +1]);
221        }
222        if (trace_is_err_output(writer)) {
223                trace_perror_output(writer,"trace_create_output");
224                trace_destroy_output(writer);
225                trace_destroy(trace);
226                return 1;
227        }
228       
229        /* Hopefully this will deal nicely with people who want to crank the
230         * compression level up to 11 :) */
231        if (level > 9) {
232                fprintf(stderr, "WARNING: Compression level > 9 specified, setting to 9 instead\n");
233                level = 9;
234        }
235
236        if (level >= 0 && trace_config_output(writer, 
237                        TRACE_OPTION_OUTPUT_COMPRESS, &level) == -1) {
238                trace_perror_output(writer, "Configuring compression level");
239                trace_destroy_output(writer);
240                trace_destroy(trace);
241                return 1;
242        }
243
244        if (trace_config_output(writer, TRACE_OPTION_OUTPUT_COMPRESSTYPE,
245                                &compress_type) == -1) {
246                trace_perror_output(writer, "Configuring compression type");
247                trace_destroy_output(writer);
248                trace_destroy(trace);
249                return 1;
250        }
251
252        if (trace_start(trace)==-1) {
253                trace_perror(trace,"trace_start");
254                return 1;
255        }
256        if (trace_start_output(writer)==-1) {
257                trace_perror_output(writer,"trace_start_output");
258        }
259        for(;;) {
260                struct libtrace_ip *ipptr;
261                libtrace_udp_t *udp = NULL;
262                libtrace_tcp_t *tcp = NULL;
263
264                int psize;
265                psize = trace_read_packet(trace, packet);
266                if (psize == 0) {
267                        break;
268                }
269                if (psize < 0) {
270                        trace_perror(trace,"read_packet");
271                        break;
272                }
273
274                ipptr = trace_get_ip(packet);
275
276                if (ipptr && (enc_source || enc_dest)) {
277                        encrypt_ips(ipptr,enc_source,enc_dest);
278                        ipptr->ip_sum = 0;
279                }
280
281                /* Replace checksums so that IP encryption cannot be
282                 * reversed */
283
284                /* XXX replace with nice use of trace_get_transport() */
285
286                udp = trace_get_udp(packet);
287                if (udp && (enc_source || enc_dest)) {
288                        udp->check = 0;
289                } 
290
291                tcp = trace_get_tcp(packet);
292                if (tcp && (enc_source || enc_dest)) {
293                        tcp->check = 0;
294                }
295
296                /* TODO: Encrypt IP's in ARP packets */
297
298                if (trace_write_packet(writer,packet)==-1) {
299                        trace_perror_output(writer,"writer");
300                        break;
301                }
302        }
303        trace_destroy_packet(packet);
304        trace_destroy(trace);
305        trace_destroy_output(writer);
306        return 0;
307}
Note: See TracBrowser for help on using the repository browser.