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"
49 extern "C"{
50 #include "grammar.h"
51 }
52
53 enum decode_style_t {
54 DECODE_NORMAL,
55 DECODE_PARSER
56 };
57
58 typedef void (*decode_norm_t)(uint16_t type,const char *packet,int len);
59 typedef void (*decode_parser_t)(uint16_t type,const char *packet,int len, element_t* el);
60
61 typedef union decode_funcs {
62 decode_norm_t decode_n;
63 decode_parser_t decode_p;
64 } decode_funcs_t;
65
66 typedef 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
73 static 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
formatted_hexdump(const char * packet,int len)82 static 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
trace_hexdump_packet(struct libtrace_packet_t * packet)112 void 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
trace_dump_packet(struct libtrace_packet_t * packet)138 void 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
generic_decode(uint16_t type,const char * packet,int len)159 static 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
open_so_decoder(const char * name,int type)165 static 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
open_protocol_decoder(const char * name,int type)187 static 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
decode_next(const char * packet,int len,const char * proto_name,int type)211 void 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
307