source: libpacketdump/libpacketdump.cc @ 8b49230

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 8b49230 was 8b49230, checked in by Shane Alcock <salcock@…>, 7 years ago

Fixed problems with decoding RadioTap? headers with libpacketdump on big endian
hosts

  • Moved byteswapX functions to a separate source file so that libpacketdump can also link against them.
  • bswap_* macros have been moved into lt_bswap.h so they can be used without having to include the entire libtrace_int.h header
  • Fixed endianness issues with the "fields" inside the RadioTap? header.
  • Property mode set to 100644
File size: 7.1 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_parser_t)(uint16_t type,const char *packet,int len, element_t* el);
60
61typedef union decode_funcs {
62    decode_norm_t decode_n;
63    decode_parser_t decode_p;
64} decode_funcs_t;
65
66typedef struct decoder {
67    enum decode_style_t style;
68    decode_funcs_t *func;
69    element_t *el; // make a union of structs with all args in it for all funcs?
70} decode_t;
71
72
73static std::map<std::string,std::map<uint16_t,decode_t> > decoders;
74
75#define WIDTH 16
76
77#ifndef DIRNAME
78#define DIRNAME "./"
79#warning "No DIRNAME set!"
80#endif
81
82static void formatted_hexdump(const char *packet, int len) {
83        int i;
84
85        for(i=0;i<len; /* Nothing */ ) {
86                int j;
87                printf("\n ");
88                for(j=0;j<WIDTH;j++) {
89                        if (i+j<len)
90                                printf(" %02x",(unsigned char)packet[i+j]);
91                        else
92                                printf("   ");
93                }
94                printf("    ");
95                for(j=0;j<WIDTH;j++) {
96                        if (i+j<len)
97                                if (isprint((unsigned char)packet[i+j]))
98                                        printf("%c",(unsigned char)packet[i+j]);
99                                else
100                                        printf(".");
101                        else
102                                printf("   ");
103                }
104                if (i+WIDTH>len)
105                        break;
106                else
107                        i+=WIDTH;
108        }
109        printf("\n");
110}
111
112void trace_hexdump_packet(struct libtrace_packet_t *packet) {
113
114        libtrace_linktype_t linktype;
115        uint32_t length;
116        const char *pkt_ptr = (char *)trace_get_packet_buffer(packet, &linktype, NULL);
117
118        time_t sec = (time_t)trace_get_seconds(packet);
119       
120        length = trace_get_capture_length(packet);
121
122        if (pkt_ptr == NULL || length == 0) {
123                printf(" [No packet payload]\n");
124                return;
125        }
126
127        printf("\n%s",ctime(&sec));
128        printf(" Capture: Packet Length: %i/%i Direction Value: %i\n",
129                        (int)length,
130                        (int)trace_get_wire_length(packet),
131                        (int)trace_get_direction(packet));
132       
133
134        formatted_hexdump(pkt_ptr, (int)length);
135        return;
136}
137
138void trace_dump_packet(struct libtrace_packet_t *packet)
139{
140        time_t sec = (time_t)trace_get_seconds(packet);
141        libtrace_linktype_t linktype;
142        uint32_t length;
143        const char *link=(char *)trace_get_packet_buffer(packet,&linktype,NULL);
144       
145        length = trace_get_capture_length(packet);
146
147        printf("\n%s",ctime(&sec));
148        printf(" Capture: Packet Length: %i/%i Direction Value: %i\n",
149                        (int)length,
150                        (int)trace_get_wire_length(packet),
151                        (int)trace_get_direction(packet));
152        if (!link) 
153                printf(" [No link layer available]\n");
154        else
155                decode_next(link,length, "link",
156                        linktype);
157}
158
159static void generic_decode(uint16_t type,const char *packet, int len) {
160        printf(" Unknown Protocol: %i",type);
161
162        formatted_hexdump(packet, len);
163}
164
165static void *open_so_decoder(const char *name,int type)
166{
167        char path[1024];
168        void *hdl;
169        /* Only check LIBPKTDUMPDIR if we're not setuid.  Not bulletproof, but hopefully anyone who
170         * sets uid == euid will also clear the environment (eg sudo).
171         */
172        if (getuid() == geteuid() && getenv("LIBPKTDUMPDIR")) {
173                snprintf(path,sizeof(path),"%s/%s_%i.so",getenv("LIBPKTDUMPDIR"),name,type);
174                hdl = dlopen(path,RTLD_LAZY);
175                if (hdl)
176                        return hdl;
177        }
178        /* If the variable isn't set, *or* if we don't find anything, try the system location. */
179        snprintf(path,sizeof(path),DIRNAME "/%s_%i.so",name,type);
180        hdl = dlopen(path,RTLD_LAZY);
181        if (hdl)
182                return hdl;
183
184        return hdl;
185}
186
187static void *open_protocol_decoder(const char *name, int type)
188{
189        char path[1024];
190        void *hdl;
191        /* Only check LIBPKTDUMPDIR if we're not setuid.  Not bulletproof, but hopefully anyone who
192         * sets uid == euid will also clear the environment (eg sudo).
193         */
194        if (getuid() == geteuid() && getenv("LIBPKTDUMPDIR")) {
195                snprintf(path,sizeof(path),"%s/%s_%i.protocol",getenv("LIBPKTDUMPDIR"),name,type);
196                hdl = parse_protocol_file(path);
197                if (hdl)
198                        return hdl;
199        }
200        /* Try the system directory */
201        snprintf(path,sizeof(path),DIRNAME "/%s_%i.protocol",
202                name,type);
203        hdl = parse_protocol_file(path);
204
205        if (!hdl)
206                return hdl;
207
208        return hdl;
209}
210
211void decode_next(const char *packet,int len,const char *proto_name,int type)
212{
213        std::string sname(proto_name);
214
215        // if we haven't worked out how to decode this type yet, load the
216        // appropriate files to do so
217        if (decoders[sname].find(type)==decoders[sname].end()) {
218                void *hdl;
219                decode_funcs_t *func = new decode_funcs_t;
220                decode_t dec;
221
222                /* Try and find a .so to handle this protocol */
223                hdl = open_so_decoder(sname.c_str(),type);
224                if (hdl) {
225                        void *s=dlsym(hdl,"decode");
226                        if (s) {
227                                // use the shared library
228                                func->decode_n = (decode_norm_t)s;
229                                dec.style = DECODE_NORMAL;
230                                dec.el = NULL; 
231                        }
232                        else {
233                                dlclose(hdl);
234                                hdl = NULL;
235                        }
236                }
237
238                /* We didn't successfully open the .so, try finding a .protocol that we can use */
239                if (!hdl) {
240                        hdl = open_protocol_decoder(sname.c_str(),type);
241                        if (hdl) {
242                                // use the protocol file
243                                func->decode_p = decode_protocol_file;
244                                dec.style = DECODE_PARSER;
245                                dec.el = (element_t*)hdl;
246                        }
247                }
248
249                /* No matches found, fall back to the generic decoder. */
250                /* TODO: We should have a variety of fallback decoders based on the protocol. */
251                if(!hdl)
252                {
253                        // no protocol file either, use a generic one
254                        func->decode_n = generic_decode;
255                        dec.style = DECODE_NORMAL;
256                        dec.el = NULL;
257                } 
258
259                dec.func = func;
260                decoders[sname][type] = dec;
261        }
262
263        /* TODO: Instead of haxing this here, we should provide a series of generic_decode's
264         * and let the code above deal with it.
265         */
266        if (decoders[sname][type].func->decode_n == generic_decode) {
267                /* We can't decode a link, so lets skip that and see if libtrace
268                 * knows how to find us the ip header
269                 */
270
271                /* Also, don't try to skip if the linktype is not valid,
272                 * because libtrace will just assert fail and that's never
273                 * good */
274                if (sname=="link" && type != -1) {
275                        uint16_t newtype;
276                        uint32_t newlen=len;
277                        const char *network=(const char*)trace_get_payload_from_link((void*)packet,
278                                        (libtrace_linktype_t)type,
279                                        &newtype,&newlen);
280                        if (network) {
281                                printf("skipping unknown link header of type %i to network type %i\n",type,newtype);
282                                /* Should hex dump this too. */
283                                decode_next(network,newlen,"eth",newtype);
284                                return;
285                        }
286                }
287                else {
288                        printf("unknown protocol %s/%i\n",sname.c_str(),type);
289                }
290        }
291
292        // decode using the appropriate function
293        switch(decoders[sname][type].style)
294        {
295                case DECODE_NORMAL:
296                        decoders[sname][type].func->decode_n(type,packet,len);
297                        break;
298
299                case DECODE_PARSER:
300                        decoders[sname][type].func->decode_p(type,packet,len,
301                                decoders[sname][type].el);
302                        break;
303
304        };
305}
306
Note: See TracBrowser for help on using the repository browser.