source: tools/traceanon/traceanon.c @ c11c3ce

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