source: libpacketdump/libpacketdump.cc @ fade02b

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