source: libpacketdump/libpacketdump.cc @ d0f25d4

develop
Last change on this file since d0f25d4 was d0f25d4, checked in by Jacob Van Walraven <jcv9@…>, 21 months ago

Add ERF and PCAPNG decoders to libpacketdump

  • Property mode set to 100644
File size: 7.9 KB
Line 
1#include "config.h"
2#include <libtrace.h>
3#include <err.h>
4#include <time.h>
5#include "libpacketdump.h"
6#include "lt_bswap.h"
7#include <stdio.h>
8#include <netdb.h>
9#include <stdlib.h>
10#include <getopt.h>
11#include <unistd.h>
12#include <sys/socket.h>
13
14#ifdef HAVE_NETINET_ETHER
15#  include <netinet/ether.h>
16#endif
17
18
19#ifdef HAVE_INTTYPES_H
20#  include <inttypes.h>
21#else
22#  error "Can't find inttypes.h"
23#endif
24
25#ifdef HAVE_LIMITS_H
26#  include <limits.h>
27#endif
28
29#ifdef HAVE_SYS_LIMITS_H
30#  include <sys/limits.h>
31#endif
32
33#ifdef HAVE_SYS_TYPES_H
34#  include <sys/types.h>
35#endif
36#include <net/if.h>
37#include <netinet/in.h>
38#include <stdio.h>
39
40#include <net/if_arp.h>
41#ifdef HAVE_NETINET_IF_ETHER_H
42#  include <netinet/if_ether.h>
43#endif
44#include <dlfcn.h>
45#include <map>
46#include <string>
47#include <ctype.h>
48#include "libpacketdump.h"
49extern "C"{
50#include "grammar.h"
51}
52
53enum decode_style_t {
54    DECODE_NORMAL,
55    DECODE_PARSER
56};
57
58typedef void (*decode_norm_t)(uint16_t type,const char *packet,int len);
59typedef void (*decode_norm_meta)(uint16_t type,const char *packet,int len,libtrace_packet_t *p);
60typedef void (*decode_parser_t)(uint16_t type,const char *packet,int len, element_t* el);
61
62libtrace_packet_t *p;
63
64typedef union decode_funcs {
65    decode_norm_t decode_n;
66    decode_norm_meta decode_meta;
67    decode_parser_t decode_p;
68} decode_funcs_t;
69
70typedef struct decoder {
71    enum decode_style_t style;
72    decode_funcs_t *func;
73    element_t *el; // make a union of structs with all args in it for all funcs?
74} decode_t;
75
76
77static std::map<std::string,std::map<uint16_t,decode_t> > decoders;
78
79#define WIDTH 16
80
81#ifndef DIRNAME
82#define DIRNAME "./"
83#warning "No DIRNAME set!"
84#endif
85
86static void formatted_hexdump(const char *packet, int len) {
87        int i;
88
89        for(i=0;i<len; /* Nothing */ ) {
90                int j;
91                printf("\n ");
92                for(j=0;j<WIDTH;j++) {
93                        if (i+j<len)
94                                printf(" %02x",(unsigned char)packet[i+j]);
95                        else
96                                printf("   ");
97                }
98                printf("    ");
99                for(j=0;j<WIDTH;j++) {
100                        if (i+j<len)
101                                if (isprint((unsigned char)packet[i+j]))
102                                        printf("%c",(unsigned char)packet[i+j]);
103                                else
104                                        printf(".");
105                        else
106                                printf("   ");
107                }
108                if (i+WIDTH>len)
109                        break;
110                else
111                        i+=WIDTH;
112        }
113        printf("\n");
114}
115
116void trace_hexdump_packet(struct libtrace_packet_t *packet) {
117
118        libtrace_linktype_t linktype;
119        uint32_t length;
120        const char *pkt_ptr = (char *)trace_get_packet_buffer(packet, &linktype, NULL);
121
122        time_t sec = (time_t)trace_get_seconds(packet);
123       
124        length = trace_get_capture_length(packet);
125
126        if (pkt_ptr == NULL || length == 0) {
127                printf(" [No packet payload]\n");
128                return;
129        }
130
131        printf("\n%s",ctime(&sec));
132        printf(" Capture: Packet Length: %i/%i Direction Value: %i\n",
133                        (int)length,
134                        (int)trace_get_wire_length(packet),
135                        (int)trace_get_direction(packet));
136
137        formatted_hexdump(pkt_ptr, (int)length);
138        return;
139}
140
141void trace_dump_packet(struct libtrace_packet_t *packet)
142{
143        p = packet;
144
145        time_t sec = (time_t)trace_get_seconds(packet);
146        libtrace_linktype_t linktype;
147        uint32_t length;
148        const char *link=(char *)trace_get_packet_buffer(packet,&linktype,NULL);
149
150        length = trace_get_capture_length(packet);
151        fprintf(stderr, "\n%s",ctime(&sec));
152        fprintf(stderr, " Capture: Packet Length: %i/%i Direction Value: %i\n",
153                        (int)length,
154                        (int)trace_get_wire_length(packet),
155                        (int)trace_get_direction(packet));
156
157        if (!link) 
158                printf(" [No link layer available]\n");
159        else
160                decode_next(link,length, "link", linktype);
161}
162
163static void generic_decode(uint16_t type,const char *packet, int len) {
164        printf(" Unknown Protocol: %i",type);
165
166        formatted_hexdump(packet, len);
167}
168
169static void *open_so_decoder(const char *name,int type)
170{
171        char path[1024];
172        void *hdl;
173        /* Only check LIBPKTDUMPDIR if we're not setuid.  Not bulletproof, but hopefully anyone who
174         * sets uid == euid will also clear the environment (eg sudo).
175         */
176        if (getuid() == geteuid() && getenv("LIBPKTDUMPDIR")) {
177                snprintf(path,sizeof(path),"%s/%s_%i.so",getenv("LIBPKTDUMPDIR"),name,type);
178                hdl = dlopen(path,RTLD_LAZY);
179                if (hdl)
180                        return hdl;
181        }
182        /* If the variable isn't set, *or* if we don't find anything, try the system location. */
183        snprintf(path,sizeof(path),DIRNAME "/%s_%i.so",name,type);
184        hdl = dlopen(path,RTLD_LAZY);
185        if (hdl)
186                return hdl;
187
188        return hdl;
189}
190
191static void *open_protocol_decoder(const char *name, int type)
192{
193        char path[1024];
194        void *hdl;
195        /* Only check LIBPKTDUMPDIR if we're not setuid.  Not bulletproof, but hopefully anyone who
196         * sets uid == euid will also clear the environment (eg sudo).
197         */
198        if (getuid() == geteuid() && getenv("LIBPKTDUMPDIR")) {
199                snprintf(path,sizeof(path),"%s/%s_%i.protocol",getenv("LIBPKTDUMPDIR"),name,type);
200                hdl = parse_protocol_file(path);
201                if (hdl)
202                        return hdl;
203        }
204        /* Try the system directory */
205        snprintf(path,sizeof(path),DIRNAME "/%s_%i.protocol",
206                name,type);
207        hdl = parse_protocol_file(path);
208
209        if (!hdl)
210                return hdl;
211
212        return hdl;
213}
214
215void decode_next(const char *packet,int len,const char *proto_name,int type)
216{
217        std::string sname(proto_name);
218
219        // if we haven't worked out how to decode this type yet, load the
220        // appropriate files to do so
221        if (decoders[sname].find(type)==decoders[sname].end()) {
222                void *hdl;
223                decode_funcs_t *func = new decode_funcs_t;
224                decode_t dec;
225
226                /* Try and find a .so to handle this protocol */
227                hdl = open_so_decoder(sname.c_str(),type);
228                if (hdl) {
229
230                        /* PCAPNG format requires the libtrace_packet_t structure in order
231                         * to determine the byte ordering */
232                        void *s;
233                        if (type == TRACE_TYPE_PCAPNG_META || type == TRACE_TYPE_ERF_META) {
234                                s=dlsym(hdl,"decode_meta");
235                                if (s) { func->decode_meta = (decode_norm_meta)s; }
236                        } else {
237                                s=dlsym(hdl,"decode");
238                                if (s) { func->decode_n = (decode_norm_t)s; }
239                        }
240
241                        if (s) {
242                                dec.style = DECODE_NORMAL;
243                                dec.el = NULL; 
244                        }
245                        else {
246                                dlclose(hdl);
247                                hdl = NULL;
248                        }
249                }
250
251                /* We didn't successfully open the .so, try finding a .protocol that we can use */
252                if (!hdl) {
253                        hdl = open_protocol_decoder(sname.c_str(),type);
254                        if (hdl) {
255                                // use the protocol file
256                                func->decode_p = decode_protocol_file;
257                                dec.style = DECODE_PARSER;
258                                dec.el = (element_t*)hdl;
259                        }
260                }
261
262                /* No matches found, fall back to the generic decoder. */
263                /* TODO: We should have a variety of fallback decoders based on the protocol. */
264                if(!hdl)
265                {
266                        // no protocol file either, use a generic one
267                        func->decode_n = generic_decode;
268                        dec.style = DECODE_NORMAL;
269                        dec.el = NULL;
270                } 
271
272                dec.func = func;
273                decoders[sname][type] = dec;
274        }
275
276        /* TODO: Instead of haxing this here, we should provide a series of generic_decode's
277         * and let the code above deal with it.
278         */
279        if (decoders[sname][type].func->decode_n == generic_decode) {
280                /* We can't decode a link, so lets skip that and see if libtrace
281                 * knows how to find us the ip header
282                 */
283
284                /* Also, don't try to skip if the linktype is not valid,
285                 * because libtrace will just assert fail and that's never
286                 * good */
287                if (sname=="link" && type != -1) {
288                        uint16_t newtype;
289                        uint32_t newlen=len;
290                        const char *network=(const char*)trace_get_payload_from_link((void*)packet,
291                                        (libtrace_linktype_t)type,
292                                        &newtype,&newlen);
293                        if (network) {
294                                printf("skipping unknown link header of type %i to network type %i\n",type,newtype);
295                                /* Should hex dump this too. */
296                                decode_next(network,newlen,"eth",newtype);
297                                return;
298                        }
299                }
300                else {
301                        printf("unknown protocol %s/%i\n",sname.c_str(),type);
302                }
303        }
304
305        // decode using the appropriate function
306        switch(decoders[sname][type].style)
307        {
308                case DECODE_NORMAL:
309                        /* If this is a pcapng packet call the correct function and pass the
310                         * libtrace_packet_t structure. We need this to determine the byte ordering */
311                        if (type == TRACE_TYPE_PCAPNG_META || type == TRACE_TYPE_ERF_META) {
312                                decoders[sname][type].func->decode_meta(type,packet,len,p);
313                        } else {
314                                decoders[sname][type].func->decode_n(type,packet,len);
315                        }
316                        break;
317
318                case DECODE_PARSER:
319                        decoders[sname][type].func->decode_p(type,packet,len,
320                                decoders[sname][type].el);
321                        break;
322
323        };
324}
325
Note: See TracBrowser for help on using the repository browser.