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

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 4c92c49 was 4c92c49, checked in by Andreas Löf <andreas.lof@…>, 11 years ago

added a command line argument to read cryptopam keys from a file and also updated the man page to describe the feature. Still untested though, need to run the code on spectre for that

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