source: examples/munge/munge.c @ 5959435

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

Add new munge program to the libtrace examples

  • Property mode set to 100644
File size: 6.5 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
13static int trace_link_type_to_dlt(libtrace_linktype_t t)
14{
15        static int table[] = {
16                -1, /* LEGACY */
17                -1, /* HDLC over POS */
18                DLT_EN10MB, /* Ethernet */
19                -1, /* ATM */
20                DLT_IEEE802_11, /* 802.11 */
21        };
22        if (t>sizeof(table)/sizeof(*table)) {
23                return -1;
24        }
25        return table[t];
26}
27
28void usage(char *argv0)
29{
30        fprintf(stderr,"Usage:\n"
31        "%s flags inputfile >outputfile\n"
32        "-s --encrypt-source    Encrypt the source addresses\n"
33        "-d --encrypt-dest      Encrypt the destination addresses\n"
34        "-c --cryptopan=key     Encrypt the addresses with the cryptopan\n"
35        "                       prefix preserving\n"
36        "-p --prefix=C.I.D.R/bits Substitute the prefix of the address\n"
37        "-f --filter=expr       Apply a tcpdump filter\n"
38        ,argv0);
39        exit(0);
40}
41
42// Incrementally update a checksum
43void update_in_cksum(uint16_t *csum, uint16_t old, uint16_t new)
44{
45        uint32_t sum = (~htons(*csum) & 0xFFFF) 
46                     + (~htons(old) & 0xFFFF) 
47                     + htons(new);
48        sum = (sum & 0xFFFF) + (sum >> 16);
49        *csum = htons(~(sum + (sum >> 16)));
50}
51
52void update_in_cksum32(uint16_t *csum, uint32_t old, uint32_t new)
53{
54        update_in_cksum(csum,old>>16,new>>16);
55        update_in_cksum(csum,old&0xFFFF,new&0xFFFF);
56}
57
58struct libtrace_tcp *get_tcp_from_ip(struct libtrace_ip *ip)
59{
60#define SW_IP_OFFMASK 0xff1f
61        struct libtrace_tcp *tcpptr = 0;
62
63        if ((ip->ip_p == 6) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
64                tcpptr = (struct libtrace_tcp *)((ptrdiff_t)ip+ (ip->ip_hl * 4));
65        }
66        return tcpptr;
67}
68
69struct libtrace_udp *get_udp_from_ip(struct libtrace_ip *ip)
70{
71        struct libtrace_udp *udpptr = 0;
72
73        if ((ip->ip_p == 17) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
74                udpptr = (struct libtrace_udp *)((ptrdiff_t)ip+(ip->ip_hl*4));
75        }
76        return udpptr;
77}
78
79struct libtrace_icmp *get_icmp_from_ip(struct libtrace_ip *ip)
80{
81        struct libtrace_icmp *icmpptr = 0;
82
83        if ((ip->ip_p == 17) && ((ip->ip_off & SW_IP_OFFMASK) == 0))  {
84                icmpptr = (struct libtrace_icmp *)((ptrdiff_t)ip+(ip->ip_hl*4));
85        }
86        return icmpptr;
87}
88
89/* Ok this is remarkably complicated
90 *
91 * We want to change one, or the other IP address, while preserving the
92 * checksum.  TCP and UDP both include the faux header in their checksum
93 * calculations, so you have to update them too.  ICMP is even worse --
94 * it can include the original IP packet that caused the error!  So anonymise
95 * that too, but remember that it's travelling in the opposite direction so
96 * we need to encrypt the destination and source instead of the source and
97 * destination!
98 */
99void encrypt_ips(struct libtrace_ip *ip,bool enc_source,bool enc_dest)
100{
101        struct libtrace_tcp *tcp;
102        struct libtrace_udp *udp;
103        struct libtrace_icmp *icmp;
104
105        tcp=get_tcp_from_ip(ip);
106        udp=get_udp_from_ip(ip);
107        icmp=get_icmp_from_ip(ip);
108
109        if (enc_source) {
110                uint32_t old_ip=ip->ip_src.s_addr;
111                uint32_t new_ip=htonl(trace_enc_ip(
112                                        htonl(ip->ip_src.s_addr)
113                                        ));
114                update_in_cksum32(&ip->ip_sum,old_ip,new_ip);
115                if (tcp) update_in_cksum(&tcp->check,old_ip,new_ip);
116                if (udp) update_in_cksum(&udp->check,old_ip,new_ip);
117                ip->ip_src.s_addr = new_ip;
118                fprintf(stderr,"enc'd source\n");
119        }
120
121        if (enc_dest) {
122                uint32_t old_ip=ip->ip_dst.s_addr;
123                uint32_t new_ip=htonl(trace_enc_ip(
124                                        htonl(ip->ip_dst.s_addr)
125                                        ));
126                update_in_cksum32(&ip->ip_sum,old_ip,new_ip);
127                if (tcp) update_in_cksum(&tcp->check,old_ip,new_ip);
128                if (udp) update_in_cksum(&udp->check,old_ip,new_ip);
129                ip->ip_dst.s_addr = new_ip;
130                fprintf(stderr,"enc'ing dest %08x->%08x\n",old_ip,new_ip);
131        }
132
133        if (icmp) {
134                /* These are error codes that return the IP packet internally */
135                if (icmp->type == 3 || icmp->type == 5 || icmp->type == 11) {
136                        encrypt_ips(
137                                        (struct libtrace_ip*)icmp+
138                                                sizeof(struct libtrace_icmp),
139                                        enc_dest,
140                                        enc_source);
141                }
142        }
143}
144
145struct libtrace_write_t {
146        pcap_dumper_t *pcap;
147};
148
149void trace_write(struct libtrace_write_t *hdl,struct libtrace_packet_t *pkt)
150{
151        struct pcap_pkthdr pcap_pkt_hdr;
152        void *link = trace_get_link(pkt);
153
154        pcap_pkt_hdr.ts=trace_get_timeval(pkt);
155        pcap_pkt_hdr.caplen = trace_get_capture_length(pkt);
156        pcap_pkt_hdr.len = trace_get_wire_length(pkt);
157        pcap_dump((u_char*)hdl->pcap, &pcap_pkt_hdr, link);
158}
159
160int main(int argc, char *argv[]) 
161{
162        enum enc_type_t enc_type = ENC_NONE;
163        char *key = NULL;
164        struct libtrace_filter_t *filter = NULL;
165        struct libtrace_t *trace;
166        struct libtrace_packet_t packet;
167        struct libtrace_write_t writer;
168        bool enc_source = false;
169        bool enc_dest   = false;
170        pcap_t *p = NULL;
171
172        if (argc<2)
173                usage(argv[0]);
174
175        while (1) {
176                int option_index;
177                struct option long_options[] = {
178                        { "encrypt-source",     0, 0, 's' },
179                        { "encrypt-dest",       0, 0, 'd' },
180                        { "cryptopan",          1, 0, 'c' },
181                        { "prefix",             1, 0, 'p' },
182                        { "filter",             1, 0, 'f' },
183                        { NULL,                 0, 0, 0 },
184                };
185
186                int c=getopt_long(argc, argv, "sdc:p:f:",
187                                long_options, &option_index);
188
189                if (c==-1)
190                        break;
191
192                switch (c) {
193                        case 's': enc_source=true; break;
194                        case 'd': enc_dest  =true; break;
195                        case 'c':
196                                  if (key!=NULL) {
197                                          fprintf(stderr,"You can only have one encryption type and one key\n");
198                                          usage(argv[0]);
199                                  }
200                                  key=strdup(optarg);
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 'f':
212                                  if (filter!=NULL) {
213                                          fprintf(stderr,"You can only have one filter (use and!)\n");
214                                          usage(argv[0]);
215                                  }
216                                  filter=trace_bpf_setfilter(optarg);
217                                  break;
218                        default:
219                                printf("unknown option: %c\n",c);
220                                usage(argv[0]);
221
222                }
223
224        }
225
226        trace_enc_init(enc_type,key);
227
228        /* Do the actual processing */
229        trace = trace_create(argv[optind]);
230        if (!trace) {
231                fprintf(stderr,"Cannot open %s\n",argv[optind]);
232                return 1;
233        }
234        p = NULL;
235        for(;;) {
236                struct libtrace_ip *ipptr;
237                int psize;
238                if ((psize = trace_read_packet(trace, &packet)) <= 0) {
239                        break;
240                }
241                if (!p) {
242                        p=pcap_open_dead(
243                                trace_link_type_to_dlt(
244                                        trace_get_link_type(&packet)),
245                                65536);
246                        writer.pcap = pcap_dump_open(p,"-");
247                        fflush((FILE *)writer.pcap);
248                }
249
250                /* Skip packets that don't match the filter */
251                if (filter && !trace_bpf_filter(filter,&packet)) {
252                        continue;
253                }
254
255                ipptr = trace_get_ip(&packet);
256
257                if (ipptr && (enc_source || enc_dest))
258                        encrypt_ips(ipptr,enc_source,enc_dest);
259                else
260                        fprintf(stderr,"No enc\n");
261
262                /* TODO: Encrypt IP's in ARP packets */
263
264                trace_write(&writer,&packet);
265        }
266        return 0;
267}
Note: See TracBrowser for help on using the repository browser.