Merge pull request #56 from wuruilong01/master
[prads.git] / src / prads.c
blobefe4319ab88d796cf594601790ae86adca0fae7f
1 /*
2 ** This file is a part of PRADS.
3 **
4 ** Copyright (C) 2009, Redpill Linpro
5 ** Copyright (C) 2009, Edward Fjellskål <edward.fjellskaal@redpill-linpro.com>
6 ** Copyright (C) 2009, Kacper Wysocki <kacper.wysocki@redpill-linpro.com>
7 **
8 ** This program is free software; you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License as published by
10 ** the Free Software Foundation; either version 2 of the License, or
11 ** (at your option) any later version.
13 ** This program is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ** GNU General Public License for more details.
18 ** You should have received a copy of the GNU General Public License
19 ** along with this program; if not, write to the Free Software
20 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 /* I N C L U D E S *********************************************************/
25 #ifdef __APPLE__
26 #include <sys/malloc.h>
27 #elseif !defined(__FreeBSD__)
28 #include <malloc.h>
29 #endif
31 #include "common.h"
32 #include "prads.h"
33 #include "config.h"
34 #include "sys_func.h"
35 #include "assets.h"
36 #include "cxt.h"
37 #include "ipfp/ipfp.h"
38 #include "servicefp/servicefp.h"
39 #include "sig.h"
40 #include "mac.h"
41 #include "tcp.h"
42 #include "dump_dns.h"
43 #include "dhcp.h"
44 //#include "output-plugins/log_init.h"
45 #include "output-plugins/log.h"
47 #ifndef CONFDIR
48 #define CONFDIR "/etc/prads/"
49 #endif
51 #define ARGS "C:c:b:d:Dg:hi:p:r:u:va:l:L:f:qtxs:OXFRMSAKUTIZtHPB"
53 /* G L O B A L S *** (or candidates for refactoring, as we say)***********/
54 globalconfig config;
55 extern int optind, opterr, optopt; // getopt()
57 time_t tstamp;
58 servicelist *services[MAX_PORTS];
59 int inpacket, gameover, intr_flag;
60 int nets = 1;
62 fmask network[MAX_NETS];
64 // static strings for comparison
65 // - this is lame and should be a flag!
66 struct tagbstring tUNKNOWN = bsStatic("unknown");
67 bstring UNKNOWN = & tUNKNOWN;
69 /* I N T E R N A L P R O T O T Y P E S ***********************************/
70 static void usage();
71 void check_vlan (packetinfo *pi);
72 void prepare_eth (packetinfo *pi);
73 void prepare_ip4 (packetinfo *pi);
74 void prepare_ip4ip (packetinfo *pi);
75 void prepare_ip6 (packetinfo *pi);
76 void prepare_ip6ip (packetinfo *pi);
77 void prepare_tcp (packetinfo *pi);
78 void prepare_udp (packetinfo *pi);
79 void prepare_icmp (packetinfo *pi);
80 void prepare_gre (packetinfo *pi);
81 void prepare_greip (packetinfo *pi);
82 void prepare_other (packetinfo *pi);
83 void parse_eth (packetinfo *pi);
84 void parse_ip4 (packetinfo *pi);
85 void parse_ip6 (packetinfo *pi);
86 void parse_tcp (packetinfo *pi);
87 void parse_udp (packetinfo *pi);
88 void parse_icmp (packetinfo *pi);
89 void parse_gre (packetinfo *pi);
90 void parse_other (packetinfo *pi);
91 void parse_arp (packetinfo *pi);
92 int parse_network (char *net_s, struct in6_addr *network);
93 int parse_netmask (char *f, int type, struct in6_addr *netmask);
94 void parse_nets(const char *s_net, fmask *network);
96 void udp_guess_direction(packetinfo *pi);
97 void set_pkt_end_ptr (packetinfo *pi);
98 inline int filter_packet(const int af, void *ip);
100 /* F U N C T I O N S ********************************************************/
102 void got_packet(u_char * useless, const struct pcap_pkthdr *pheader,
103 const u_char * packet)
105 config.pr_s.got_packets++;
106 packetinfo pstruct = {0};
107 packetinfo *pi = &pstruct;
108 pi->our = 1;
109 pi->packet = packet;
110 pi->pheader = pheader;
111 set_pkt_end_ptr (pi);
112 tstamp = pi->pheader->ts.tv_sec; // Global
113 if (intr_flag != 0) {
114 check_interrupt();
116 inpacket = 1;
117 prepare_eth(pi);
118 check_vlan(pi);
119 parse_eth(pi);
121 if (pi->eth_type == ETHERNET_TYPE_IP) {
122 prepare_ip4(pi);
123 parse_ip4(pi);
124 goto packet_end;
125 } else if (pi->eth_type == ETHERNET_TYPE_IPV6) {
126 prepare_ip6(pi);
127 parse_ip6(pi);
128 goto packet_end;
129 } else if (pi->eth_type == ETHERNET_TYPE_ARP) {
130 parse_arp(pi);
131 goto packet_end;
133 config.pr_s.otherl_recv++;
134 vlog(0x3, "[*] ETHERNET TYPE : %x\n",pi->eth_hdr->eth_ip_type);
135 packet_end:
136 #ifdef DEBUG
137 if (!pi->our) vlog(0x3, "Not our network packet. Tracked, but not logged.\n");
138 #endif
139 inpacket = 0;
140 return;
143 /* does this ip belong to our network? do we care about the packet?
145 * unfortunately pcap sends us packets in host order
146 * Return value: boolean
148 inline int filter_packet(const int af, void *ipptr)
149 //const struct in6_addr *ip_s)
151 ip6v ip_vec;
152 ip6v t;
154 int i, our = 0;
155 char output[INET_ADDRSTRLEN + 1];
156 switch (af) {
157 case AF_INET:
159 struct in6_addr *ip = (struct in6_addr *) ipptr;
160 for (i = 0; i < MAX_NETS && i < nets; i++) {
161 if (network[i].type != AF_INET)
162 continue;
163 #ifdef DEBUG_PACKET
164 u_ntop(network[i].addr, af, output);
165 dlog("Filter: %s\n", output);
166 u_ntop(network[i].mask, af, output);
167 dlog("mask: %s\n", output);
168 u_ntop(*ip, af, output);
169 dlog("ip: %s\n", output);
170 #endif
171 if((IP4ADDR(ip) & IP4ADDR(&network[i].mask))
172 == (IP4ADDR(&network[i].addr) & IP4ADDR(&network[i].mask)) ){
173 our = 1;
174 break;
176 #ifdef DEBUG_PACKET
177 else {
178 dlog("%8x %8x %8x\n", IP4ADDR(ip) & IP4ADDR(&network[i].mask), IP4ADDR(&network[i].addr) & IP4ADDR(&network[i].mask), IP4ADDR(&network[i].mask));
180 #endif
183 break;
184 case AF_INET6:
186 /* 32-bit comparison of ipv6 nets.
187 * can do better here by using 64-bit or SIMD instructions
188 * this code needs more thought and work
191 * PS: use same code for ipv4 - 0 bytes and SIMD doesnt care*/
193 // copy the in6_addr pointed to by ipptr into the vector. grr!
194 memcpy(&ip_vec.ip6,ipptr, sizeof(struct in6_addr));
195 for (i = 0; i < MAX_NETS && i < nets; i++) {
196 if(network[i].type != AF_INET6)
197 continue;
198 #ifdef DEBUG_PACKET
199 struct in6_addr tmp_netmask;
201 IP6ADDR0(&tmp_netmask) = htonl(IP6ADDR0(&network[i].mask));
202 IP6ADDR1(&tmp_netmask) = htonl(IP6ADDR1(&network[i].mask));
203 IP6ADDR2(&tmp_netmask) = htonl(IP6ADDR2(&network[i].mask));
204 IP6ADDR3(&tmp_netmask) = htonl(IP6ADDR3(&network[i].mask));
206 u_ntop(network[i].addr, af, output);
207 dlog("net: %s\n", output);
208 u_ntop(tmp_netmask, af, output);
209 dlog("mask: %s\n", output);
210 u_ntop(ip_vec.ip6, af, output);
211 dlog("ip: %s\n", output);
212 #endif
213 if (network[i].type == AF_INET6) {
214 #if(1)
215 /* apologies for the uglyness */
216 #ifdef HAVE_SSE2
217 #define compare128(x,y) __builtin_ia32_pcmpeqd128((x), (y))
218 // the builtin is only available on sse2!
219 t.v = __builtin_ia32_pcmpeqd128(
220 ip_vec.v & network[i].mask_v,
221 network[i].addr_v);
222 if (t.i[0] & t.i[1])
223 #else
224 #define compare128(x,y) memcmp(&(x),&(y),16)
225 t.v = ip_vec.v & network[i].mask_v;
226 // xor(a,b) == 0 iff a==b
227 if (!( (t.i[0] ^ network[i].addr64[0]) &
228 (t.i[1] ^ network[i].addr64[1]) ))
229 #endif
231 our = 1;
232 break;
235 #else
236 if ((ip_s.__u6_addr.__u6_addr32[0] & network[i].mask.__u6_addr.__u6_addr32[0])
237 == network[i].addr.__u6_addr.__u6_addr32[0]
238 && (ip_s.__u6_addr.__u6_addr32[1] & network[i].mask.__u6_addr.__u6_addr32[1])
239 == network[i].addr.__u6_addr.__u6_addr32[1]
240 && (ip_s.__u6_addr.__u6_addr32[2] & network[i].mask.__u6_addr.__u6_addr32[2])
241 == network[i].addr.__u6_addr.__u6_addr32[2]
242 && (ip_s.__u6_addr.__u6_addr32[3] & network[i].mask.__u6_addr.__u6_addr32[3])
243 == network[i].addr.__u6_addr.__u6_addr32[3]) {
244 our = 1;
245 break;
247 #endif
251 break;
252 default:
253 fprintf(stderr,
254 "non-ip packets of type %d aren't filtered by netmask yet\n", af);
255 our = 1;
257 #ifdef DEBUG
258 if (af == AF_INET6){
259 inet_ntop(af, (struct in6addr*) ipptr, output, MAX_NETS);
260 }else{
261 inet_ntop(af, (uint32_t*)ipptr, output, MAX_NETS);
263 if (our){
264 vlog(0x2, "Address %s is in our network.\n", output);
265 } else {
266 vlog(0x2, "Address %s is not our network.\n", output);
268 #endif
269 return our;
272 void prepare_eth (packetinfo *pi)
274 if (pi->packet + ETHERNET_HEADER_LEN > pi->end_ptr) return;
275 config.pr_s.eth_recv++;
276 pi->eth_hdr = (ether_header *) (pi->packet);
277 pi->eth_type = ntohs(pi->eth_hdr->eth_ip_type);
278 pi->eth_hlen = ETHERNET_HEADER_LEN;
279 return;
282 void parse_eth (packetinfo *pi)
284 if (!IS_CSSET(&config,CS_MAC)) return;
285 /* update_asset_arp(pi->eth_hdr->ether_src, pi);
287 uint8_t *mac = pi->eth_hdr->ether_src;
289 * XXX: how is mac matching supposed to work?
290 * answer: lookup macs on pertinent frames
291 * and hash into mac asset database
292 * mac assets are like regular assets,
293 * and contain references to other assets they involve
294 if(! pi->asset->mace)
295 mac_entry *match = match_mac(config.sig_mac, mac, 48);
296 //pi->asset->mace ;
298 print_mac(mac);
299 olog("mac matched: %s\n", match->vendor);
301 // call update_asset_mac or smth?
302 // stats?
303 //config.pr_s.eth_recv++;
305 return;
309 void check_vlan (packetinfo *pi)
311 if (pi->eth_type == ETHERNET_TYPE_8021Q) {
312 vlog(0x3, "[*] ETHERNET TYPE 8021Q\n");
313 config.pr_s.vlan_recv++;
314 pi->vlan = pi->eth_hdr->eth_8_vid;
315 pi->eth_type = ntohs(pi->eth_hdr->eth_8_ip_type);
316 pi->eth_hlen += 4;
318 /* This is b0rked - kwy and ebf fix */
319 } else if (pi->eth_type ==
320 (ETHERNET_TYPE_802Q1MT | ETHERNET_TYPE_802Q1MT2 |
321 ETHERNET_TYPE_802Q1MT3 | ETHERNET_TYPE_8021AD)) {
322 vlog(0x3, "[*] ETHERNET TYPE 802Q1MT\n");
323 pi->mvlan = pi->eth_hdr->eth_82_mvid;
324 pi->eth_type = ntohs(pi->eth_hdr->eth_82_ip_type);
325 pi->eth_hlen += 8;
327 return;
330 void prepare_ip4 (packetinfo *pi)
332 config.pr_s.ip4_recv++;
333 pi->af = AF_INET;
334 pi->ip4 = (ip4_header *) (pi->packet + pi->eth_hlen);
335 pi->packet_bytes = (ntohs(pi->ip4->ip_len) - (IP_HL(pi->ip4) * 4));
337 pi->our = filter_packet(pi->af, &PI_IP4SRC(pi));
338 vlog(0x3, "Got %s IPv4 Packet...\n", (pi->our?"our":"foregin"));
339 return;
342 void parse_ip4 (packetinfo *pi)
344 switch (pi->ip4->ip_p) {
345 case IP_PROTO_TCP:
346 prepare_tcp(pi);
347 if (!pi->our)
348 break;
349 parse_tcp(pi);
350 break;
351 case IP_PROTO_UDP:
352 prepare_udp(pi);
353 if (!pi->our)
354 break;
355 parse_udp(pi);
356 break;
357 case IP_PROTO_ICMP:
358 prepare_icmp(pi);
359 if (!pi->our)
360 break;
361 parse_icmp(pi);
362 break;
363 case IP_PROTO_IP4:
364 prepare_ip4ip(pi);
365 break;
366 case IP_PROTO_IP6:
367 prepare_ip4ip(pi);
368 break;
369 case IP_PROTO_GRE:
370 /* Note: fragmented IPv4 GRE packets will be
371 skipped in the following functions as the
372 interesting information for prads is in the
373 first packet and flow-assembly is not part
374 of prads
376 prepare_gre(pi);
377 parse_gre(pi);
378 break;
380 default:
381 prepare_other(pi);
382 if (!pi->our)
383 break;
384 parse_other(pi);
386 return;
389 void prepare_gre (packetinfo *pi)
391 config.pr_s.gre_recv++;
392 // do not handle fragmented IPv4 gre packets
393 if(pi->af == AF_INET && pi->ip4->ip_off > 0){
394 return;
396 if((pi->pheader->caplen - pi->eth_hlen) < GRE_HDR_LEN) {
397 return;
399 if (pi->af == AF_INET) {
400 vlog(0x3, "[*] IPv4 PROTOCOL TYPE GRE:\n");
401 pi->greh = (gre_header *) (pi->packet + pi->eth_hlen + (IP_HL(pi->ip4) * 4));
402 } else if (pi->af == AF_INET6) {
403 vlog(0x3, "[*] IPv6 PROTOCOL TYPE GRE:\n");
404 pi->greh = (gre_header *) (pi->packet + pi->eth_hlen + IP6_HEADER_LEN);
406 pi->proto = IP_PROTO_GRE;
407 return;
410 void parse_gre (packetinfo *pi)
412 uint16_t gre_header_len = GRE_HDR_LEN;
413 gre_sre_header *gsre = NULL;
414 uint16_t len = (pi->pheader->caplen - pi->eth_hlen);
416 // do not process invalid packets
417 if(len < GRE_HDR_LEN){
418 return;
420 // do not process fragmented GRE packets
421 if(pi->af == AF_INET && pi->ip4->ip_off > 0){
422 return;
425 update_asset(pi);
427 switch (GRE_GET_VERSION(pi->greh))
429 case GRE_VERSION_0:
430 /* Adjust header length based on content */
431 if (GRE_FLAG_ISSET_KY(pi->greh))
432 gre_header_len += GRE_KEY_LEN;
433 if (GRE_FLAG_ISSET_SQ(pi->greh))
434 gre_header_len += GRE_SEQ_LEN;
435 if (GRE_FLAG_ISSET_CHKSUM(pi->greh) || GRE_FLAG_ISSET_ROUTE(pi->greh))
436 gre_header_len += GRE_CHKSUM_LEN + GRE_OFFSET_LEN;
437 if (gre_header_len > len) {
438 return;
440 if (GRE_FLAG_ISSET_ROUTE(pi->greh))
442 gsre = (gre_sre_header *)(pi->greh + gre_header_len);
443 if (gsre == NULL) return;
444 while (1)
446 if ((gre_header_len+GRE_SRE_HDR_LEN) > len) {
447 break;
449 gre_header_len += GRE_SRE_HDR_LEN;
451 if (gsre != NULL && (ntohs(gsre->af) == 0) && (gsre->sre_length == 0))
452 break;
454 gre_header_len += gsre->sre_length;
455 gsre = (gre_sre_header *)(pi->greh + gre_header_len);
456 if (gsre == NULL)
457 return;
460 pi->gre_hlen = gre_header_len;
461 break;
463 case GRE_VERSION_1:
464 /* GRE version 1 doenst support the fields below RFC 1701 */
465 if (GRE_FLAG_ISSET_CHKSUM(pi->greh)) {
466 return;
468 if (GRE_FLAG_ISSET_ROUTE(pi->greh)) {
469 return;
471 if (GRE_FLAG_ISSET_SSR(pi->greh)) {
472 return;
474 if (GRE_FLAG_ISSET_RECUR(pi->greh)) {
475 return;
477 if (GREV1_FLAG_ISSET_FLAGS(pi->greh)) {
478 return;
480 if (GRE_GET_PROTO(pi->greh) != GRE_PROTO_PPP) {
481 return;
483 if (!(GRE_FLAG_ISSET_KY(pi->greh))) {
484 return;
487 gre_header_len += GRE_KEY_LEN;
489 /* Adjust header length based on content */
490 if (GRE_FLAG_ISSET_SQ(pi->greh))
491 gre_header_len += GRE_SEQ_LEN;
492 if (GREV1_FLAG_ISSET_ACK(pi->greh))
493 gre_header_len += GREV1_ACK_LEN;
494 if (gre_header_len > len) {
495 return;
497 break;
499 default:
500 /* Error */
501 return;
504 prepare_greip(pi);
505 return;
508 void prepare_ip6ip (packetinfo *pi)
510 packetinfo pipi;
511 memset(&pipi, 0, sizeof(packetinfo));
512 config.pr_s.ip6ip_recv++;
513 pipi.pheader = pi->pheader;
514 pipi.packet = (pi->packet + pi->eth_hlen + IP6_HEADER_LEN);
515 pipi.end_ptr = pi->end_ptr;
516 if (pi->ip6->next == IP_PROTO_IP4) {
517 prepare_ip4(&pipi);
518 parse_ip4(&pipi);
519 return;
520 } else {
521 prepare_ip6(&pipi);
522 parse_ip6(&pipi);
523 return;
527 void prepare_greip (packetinfo *pi)
529 packetinfo pipi;
530 memset(&pipi, 0, sizeof(packetinfo));
531 pipi.pheader = pi->pheader;
532 pipi.packet = (pi->packet + pi->eth_hlen + pi->gre_hlen);
533 pipi.end_ptr = pi->end_ptr;
534 if (GRE_GET_PROTO(pi->greh) == IP_PROTO_IP4) {
535 prepare_ip4(&pipi);
536 parse_ip4(&pipi);
537 return;
538 } else if (GRE_GET_PROTO(pi->greh) == IP_PROTO_IP6) {
539 prepare_ip6(&pipi);
540 parse_ip6(&pipi);
541 return;
542 } else {
543 /* Not more implemented atm */
544 vlog(0x3, "[*] - NOT CHECKING GRE PACKAGE TYPE Other\n");
545 return;
549 void prepare_ip4ip (packetinfo *pi)
551 packetinfo pipi;
552 memset(&pipi, 0, sizeof(packetinfo));
553 config.pr_s.ip4ip_recv++;
554 pipi.pheader = pi->pheader;
555 pipi.packet = (pi->packet + pi->eth_hlen + (IP_HL(pi->ip4) * 4));
556 pipi.end_ptr = pi->end_ptr;
557 if (pi->ip4->ip_p == IP_PROTO_IP4) {
558 prepare_ip4(&pipi);
559 parse_ip4(&pipi);
560 return;
561 } else {
562 prepare_ip6(&pipi);
563 parse_ip6(&pipi);
564 return;
568 void prepare_ip6 (packetinfo *pi)
570 config.pr_s.ip6_recv++;
571 pi->af = AF_INET6;
572 pi->ip6 = (ip6_header *) (pi->packet + pi->eth_hlen);
573 pi->packet_bytes = ntohs(pi->ip6->len);
574 // may be dropped due to macros plus
575 //pi->ip_src = PI_IP6SRC(pi);
576 //pi->ip_dst = PI_IP6DST(pi);
577 pi->our = filter_packet(pi->af, &PI_IP6SRC(pi));
578 vlog(0x3, "Got %s IPv6 Packet...\n", (pi->our?"our":"foregin"));
579 return;
582 void parse_ip6 (packetinfo *pi)
584 switch (pi->ip6->next) {
585 case IP_PROTO_TCP:
586 prepare_tcp(pi);
587 if (!pi->our)
588 break;
589 parse_tcp(pi);
590 break;
591 case IP_PROTO_UDP:
592 prepare_udp(pi);
593 if (!pi->our)
594 break;
595 parse_udp(pi);
596 break;
597 case IP6_PROTO_ICMP:
598 prepare_icmp(pi);
599 if (!pi->our)
600 break;
601 parse_icmp(pi);
602 break;
603 case IP_PROTO_IP4:
604 prepare_ip6ip(pi);
605 break;
606 case IP_PROTO_IP6:
607 prepare_ip6ip(pi);
608 break;
610 default:
611 prepare_other(pi);
613 * if (check != 0) {
614 * olog("[*] - CHECKING OTHER PACKAGE\n");
615 * update_asset(AF_INET6,ip6->ip_src);
616 * service_other(*pi->ip4,*tcph)
617 * fp_other(ip, ttl, ipopts, len, id, ipflags, df);
618 * }else{
619 * olog("[*] - NOT CHECKING OTHER PACKAGE\n");
620 * }
622 break;
624 return;
627 void parse_arp (packetinfo *pi)
629 vlog(0x3, "[*] Got ARP packet...\n");
630 config.pr_s.arp_recv++;
631 if (!IS_CSSET(&config,CS_ARP)) return;
632 pi->af = AF_INET;
633 pi->arph = (ether_arp *) (pi->packet + pi->eth_hlen);
635 if (ntohs(pi->arph->ea_hdr.ar_op) == ARPOP_REPLY) {
636 if (filter_packet(pi->af, &pi->arph->arp_spa)) {
637 update_asset_arp(pi->arph->arp_sha, pi);
639 /* arp_check(eth_hdr,pi->pheader->ts.tv_sec); */
640 } else {
641 vlog(0x3, "[*] ARP TYPE: %d\n",ntohs(pi->arph->ea_hdr.ar_op));
645 void set_pkt_end_ptr (packetinfo *pi)
647 /* Paranoia! */
648 if (pi->pheader->len <= SNAPLENGTH) {
649 pi->end_ptr = (pi->packet + pi->pheader->len);
650 } else {
651 pi->end_ptr = (pi->packet + SNAPLENGTH);
653 return;
656 void prepare_tcp (packetinfo *pi)
658 config.pr_s.tcp_recv++;
659 if (pi->af==AF_INET) {
660 vlog(0x3, "[*] IPv4 PROTOCOL TYPE TCP:\n");
661 pi->tcph = (tcp_header *) (pi->packet + pi->eth_hlen + (IP_HL(pi->ip4) * 4));
662 pi->plen = (pi->pheader->caplen - (TCP_OFFSET(pi->tcph)) * 4 - (IP_HL(pi->ip4) * 4) - pi->eth_hlen);
663 pi->payload = (pi->packet + pi->eth_hlen + (IP_HL(pi->ip4) * 4) + (TCP_OFFSET(pi->tcph) * 4));
664 } else if (pi->af==AF_INET6) {
665 vlog(0x3, "[*] IPv6 PROTOCOL TYPE TCP:\n");
666 pi->tcph = (tcp_header *) (pi->packet + pi->eth_hlen + IP6_HEADER_LEN);
667 pi->plen = (pi->pheader->caplen - (TCP_OFFSET(pi->tcph)) * 4 - IP6_HEADER_LEN - pi->eth_hlen);
668 pi->payload = (pi->packet + pi->eth_hlen + IP6_HEADER_LEN + (TCP_OFFSET(pi->tcph)*4));
670 pi->proto = IP_PROTO_TCP;
671 pi->s_port = pi->tcph->src_port;
672 pi->d_port = pi->tcph->dst_port;
673 connection_tracking(pi);
674 //cx_track_simd_ipv4(pi);
675 if(config.payload)
676 dump_payload(pi->payload, (config.payload < pi->plen)?config.payload:pi->plen);
677 return;
680 void parse_tcp (packetinfo *pi)
682 update_asset(pi);
684 if (TCP_ISFLAGSET(pi->tcph, (TF_SYN))) {
685 if (!TCP_ISFLAGSET(pi->tcph, (TF_ACK))) {
686 if (IS_COSET(&config,CO_SYN)) {
687 vlog(0x3, "[*] - Got a SYN from a CLIENT: dst_port:%d\n",ntohs(pi->tcph->dst_port));
688 fp_tcp(pi, CO_SYN);
689 return;
691 } else {
692 if (IS_COSET(&config,CO_SYNACK)) {
693 vlog(0x3, "[*] Got a SYNACK from a SERVER: src_port:%d\n", ntohs(pi->tcph->src_port));
694 fp_tcp(pi, CO_SYNACK);
695 if (pi->sc != SC_SERVER)
696 reverse_pi_cxt(pi);
697 return;
702 // Check payload for known magic bytes that defines files!
704 if (pi->sc == SC_CLIENT && !ISSET_CXT_DONT_CHECK_CLIENT(pi)) {
705 if (IS_CSSET(&config,CS_TCP_CLIENT)
706 && !ISSET_DONT_CHECK_CLIENT(pi)) {
707 if (pi->af == AF_INET)
708 client_tcp4(pi, config.sig_client_tcp);
709 else
710 client_tcp6(pi, config.sig_client_tcp);
712 goto bastard_checks;
714 } else if (pi->sc == SC_SERVER && !ISSET_CXT_DONT_CHECK_SERVER(pi)) {
715 if (IS_CSSET(&config,CS_TCP_SERVER)
716 && !ISSET_DONT_CHECK_SERVICE(pi)) {
717 if (pi->af == AF_INET)
718 service_tcp4(pi, config.sig_serv_tcp);
719 else
720 service_tcp6(pi, config.sig_serv_tcp);
722 goto bastard_checks;
724 vlog(0x3, "[*] - NOT CHECKING TCP PACKAGE\n");
725 return;
727 bastard_checks:
728 if (IS_COSET(&config,CO_ACK)
729 && TCP_ISFLAGSET(pi->tcph, (TF_ACK))
730 && !TCP_ISFLAGSET(pi->tcph, (TF_SYN))
731 && !TCP_ISFLAGSET(pi->tcph, (TF_RST))
732 && !TCP_ISFLAGSET(pi->tcph, (TF_FIN))) {
733 vlog(0x3, "[*] Got a STRAY-ACK: src_port:%d\n",ntohs(pi->tcph->src_port));
734 fp_tcp(pi, CO_ACK);
735 return;
736 } else if (IS_COSET(&config,CO_FIN) && TCP_ISFLAGSET(pi->tcph, (TF_FIN))) {
737 vlog(0x3, "[*] Got a FIN: src_port:%d\n",ntohs(pi->tcph->src_port));
738 fp_tcp(pi, CO_FIN);
739 return;
740 } else if (IS_COSET(&config,CO_RST) && TCP_ISFLAGSET(pi->tcph, (TF_RST))) {
741 vlog(0x3, "[*] Got a RST: src_port:%d\n",ntohs(pi->tcph->src_port));
742 fp_tcp(pi, CO_RST);
743 return;
747 void prepare_udp (packetinfo *pi)
749 config.pr_s.udp_recv++;
750 if (pi->af==AF_INET) {
751 vlog(0x3, "[*] IPv4 PROTOCOL TYPE UDP:\n");
752 pi->udph = (udp_header *) (pi->packet + pi->eth_hlen + (IP_HL(pi->ip4) * 4));
753 pi->plen = pi->pheader->caplen - UDP_HEADER_LEN -
754 (IP_HL(pi->ip4) * 4) - pi->eth_hlen;
755 pi->payload = (pi->packet + pi->eth_hlen +
756 (IP_HL(pi->ip4) * 4) + UDP_HEADER_LEN);
758 } else if (pi->af==AF_INET6) {
759 vlog(0x3, "[*] IPv6 PROTOCOL TYPE UDP:\n");
760 pi->udph = (udp_header *) (pi->packet + pi->eth_hlen + + IP6_HEADER_LEN);
761 pi->plen = pi->pheader->caplen - UDP_HEADER_LEN -
762 IP6_HEADER_LEN - pi->eth_hlen;
763 pi->payload = (pi->packet + pi->eth_hlen +
764 IP6_HEADER_LEN + UDP_HEADER_LEN);
766 pi->proto = IP_PROTO_UDP;
767 pi->s_port = pi->udph->src_port;
768 pi->d_port = pi->udph->dst_port;
769 connection_tracking(pi);
770 //cx_track_simd_ipv4(pi);
771 if(config.payload)
772 dump_payload(pi->payload, (config.payload < pi->plen)?config.payload:pi->plen);
773 return;
776 void parse_udp (packetinfo *pi)
778 update_asset(pi);
779 //if (is_set_guess_upd_direction(config)) {
780 udp_guess_direction(pi); // fix DNS server transfers?
781 // Check for Passive DNS
782 if ( ntohs(pi->s_port) == 53 || ntohs(pi->s_port) == 5353 ) {
783 // For now - Proof of Concept! - Fix output way
784 if(config.cflags & CONFIG_PDNS) {
785 static char ip_addr_s[INET6_ADDRSTRLEN];
786 u_ntop_src(pi, ip_addr_s);
787 dump_dns(pi->payload, pi->plen, stdout, "\n", ip_addr_s, pi->pheader->ts.tv_sec);
790 if (IS_COSET(&config, CO_DHCP) && ntohs(pi->s_port) == 68 && ntohs(pi->d_port) == 67) {
791 dhcp_fingerprint(pi); /* basic DHCP parsing*/
793 // if (IS_COSET(&config,CO_DNS) && (pi->sc == SC_SERVER && ntohs(pi->s_port) == 53)) passive_dns (pi);
795 if (IS_CSSET(&config,CS_UDP_SERVICES)) {
796 if (pi->af == AF_INET) {
798 if (!ISSET_DONT_CHECK_SERVICE(pi)||!ISSET_DONT_CHECK_CLIENT(pi)) {
799 // Check for UDP SERVICE
800 service_udp4(pi, config.sig_serv_udp);
802 // UPD Fingerprinting
803 if (IS_COSET(&config,CO_UDP)) fp_udp4(pi, pi->ip4, pi->udph, pi->end_ptr);
804 } else if (pi->af == AF_INET6) {
805 if (!ISSET_DONT_CHECK_SERVICE(pi)||!ISSET_DONT_CHECK_CLIENT(pi)) {
806 service_udp6(pi, config.sig_client_udp);
808 /* fp_udp(ip6, ttl, ipopts, len, id, ipflags, df); */
810 return;
811 } else {
812 vlog(0x3, "[*] - NOT CHECKING UDP PACKAGE\n");
813 return;
817 void prepare_icmp (packetinfo *pi)
819 config.pr_s.icmp_recv++;
820 if (pi->af==AF_INET) {
821 vlog(0x3, "[*] IPv4 PROTOCOL TYPE ICMP:\n");
822 pi->icmph = (icmp_header *) (pi->packet + pi->eth_hlen + (IP_HL(pi->ip4) * 4));
823 pi->proto = IP_PROTO_ICMP;
825 } else if (pi->af==AF_INET6) {
826 vlog(0x3, "[*] IPv6 PROTOCOL TYPE ICMP:\n");
827 pi->icmp6h = (icmp6_header *) (pi->packet + pi->eth_hlen + IP6_HEADER_LEN);
828 pi->proto = IP6_PROTO_ICMP;
830 pi->s_port = 0;
831 pi->d_port = 0;
833 * DO change ip6->hop_lmt to 0 or something
835 connection_tracking(pi);
836 return;
839 void parse_icmp (packetinfo *pi)
841 update_asset(pi);
843 if (IS_COSET(&config,CO_ICMP)) {
844 if (pi->cxt->check == 0x00) {
845 pi->cxt->check = 0x10; //for now - stop icmp fp quick
846 if (pi->af==AF_INET) {
847 fp_icmp4(pi, pi->ip4, pi->icmph, pi->end_ptr);
848 // could look for icmp spesific data in package abcde...
849 // service_icmp(*pi->ip4,*tcph
850 } else if (pi->af==AF_INET6) {
851 add_asset(pi);
852 fp_icmp6(pi, pi->ip6, pi->icmp6h, pi->end_ptr);
854 } else {
855 vlog(0x3, "[*] - NOT CHECKING ICMP PACKAGE\n");
860 void prepare_other (packetinfo *pi)
862 config.pr_s.othert_recv++;
863 if (pi->af==AF_INET) {
864 vlog(0x3, "[*] IPv4 PROTOCOL TYPE OTHER: %d\n",pi->ip4->ip_p);
866 } else if (pi->af==AF_INET6) {
867 vlog(0x3, "[*] IPv6 PROTOCOL TYPE OTHER: %d\n",pi->ip6->next);
870 pi->s_port = 0;
871 pi->d_port = 0;
872 connection_tracking(pi);
873 return;
876 void parse_other (packetinfo *pi)
878 update_asset(pi);
880 if (pi->cxt->check == 0x00) {
881 if (IS_COSET(&config,CO_OTHER)) {
882 pi->cxt->check = 0x01; // no more checks
883 // service_other(*pi->ip4,*transporth);
884 // fp_other(pi->ipX, ttl, ipopts, len, id, ipflags, df);
885 } else {
886 vlog(0x3, "[*] - NOT CHECKING *OTHER* PACKAGE\n");
891 void udp_guess_direction(packetinfo *pi)
893 /* Stupid hack :( for DNS/port 53 */
894 if (ntohs(pi->d_port) == 53) {
895 if (pi->sc == SC_CLIENT) return;
896 else pi->sc = SC_CLIENT;
898 } else if (ntohs(pi->s_port) == 53) {
899 if (pi->sc == SC_SERVER) return;
900 else pi->sc = SC_SERVER;
904 int parse_network (char *net_s, struct in6_addr *network)
906 int type;
907 char *t;
908 if (NULL != (t = strchr(net_s, ':'))) {
909 type = AF_INET6;
910 if (!inet_pton(type, net_s, network)) {
911 perror("parse_nets6");
912 return -1;
914 dlog("Network6 %-36s \t -> %08x:%08x:%08x:%08x\n",
915 net_s,
916 IP6ADDR(network)
918 } else {
919 type = AF_INET;
920 if (!inet_pton(type, net_s, &IP4ADDR(network))) {
921 perror("parse_nets");
922 return -1;
924 dlog("Network4 %16s \t-> 0x%08x\n", net_s, IP4ADDR(network));
926 return type;
929 int parse_netmask (char *f, int type, struct in6_addr *netmask)
931 char *t;
932 uint32_t mask;
933 char output[MAX_NETS];
934 // parse netmask into host order
935 if (type == AF_INET && (t = strchr(f, '.')) > f && t-f < 4) {
936 // full ipv4 netmask : dotted quads
937 inet_pton(type, f, &IP4ADDR(netmask));
938 dlog("mask 4 %s \t-> 0x%08x\n", f, IP4ADDR(netmask));
939 } else if (type == AF_INET6 && NULL != (t = strchr(f, ':'))) {
940 // full ipv6 netmasÄž
941 dlog("mask 6 %s\n", f);
942 inet_pton(type, f, netmask);
943 } else {
944 // cidr form
945 sscanf(f, "%u", &mask);
946 dlog("cidr %u \t-> ", mask);
947 if (type == AF_INET) {
948 uint32_t shift = 32 - mask;
949 if (mask)
950 IP4ADDR(netmask) = ntohl( ((unsigned int)-1 >> shift)<< shift);
951 else
952 IP4ADDR(netmask) = 0;
954 dlog("0x%08x\n", IP4ADDR(netmask));
955 } else if (type == AF_INET6) {
956 //mask = 128 - mask;
957 int j = 0;
958 memset(netmask, 0, sizeof(struct in6_addr));
960 while (mask > 8) {
961 netmask->s6_addr[j++] = 0xff;
962 mask -= 8;
964 if (mask > 0) {
965 netmask->s6_addr[j] = -1 << (8 - mask);
967 #ifdef DEBUG
968 inet_ntop(type, &IP4ADDR(netmask), output, MAX_NETS);
969 dlog("mask: %s\n", output);
970 #endif
971 // pcap packets are in host order.
972 IP6ADDR0(netmask) = ntohl(IP6ADDR0(netmask));
973 IP6ADDR1(netmask) = ntohl(IP6ADDR1(netmask));
974 IP6ADDR2(netmask) = ntohl(IP6ADDR2(netmask));
975 IP6ADDR3(netmask) = ntohl(IP6ADDR3(netmask));
979 return 0;
982 /* parse strings of the form ip/cidr or ip/mask like:
983 * "10.10.10.10/255.255.255.128,10.10.10.10/25" and
984 * "dead:be:eef2:1aa::b5ff:fe96:37a2/64,..."
986 * an IPv6 address is 8 x 4 hex digits. missing digits are padded with zeroes.
988 void parse_nets(const char *s_net, fmask *network)
990 /* f -> for processing
991 * p -> frob pointer
992 * t -> to pointer */
993 char *f, *p, *snet;
994 int type, len, i = 0;
995 struct in6_addr network6, netmask6;
997 // snet is a mutable copy of the args,freed @ nets_end
998 len = strlen(s_net);
999 //snet = calloc(1, len);
1000 snet = calloc(1, (len + 1)); /* to have \0 too :-) */
1001 strncpy(snet, s_net, len);
1002 f = snet;
1003 while (f && 0 != (p = strchr(f, '/'))) {
1004 // convert network address
1005 *p = '\0';
1006 type = parse_network(f, &network6);
1007 if (type != AF_INET && type != AF_INET6) {
1008 perror("parse_network");
1009 goto nets_end;
1011 // convert netmask
1012 f = p + 1;
1013 p = strchr(f, ',');
1014 if (p) {
1015 *p = '\0';
1017 parse_netmask(f, type, &netmask6);
1019 // poke in the gathered information
1020 switch (type) {
1021 case AF_INET:
1022 case AF_INET6:
1023 network[i].addr = network6;
1024 network[i].mask = netmask6;
1025 network[i].type = type;
1026 break;
1028 default:
1029 fprintf(stderr, "parse_nets: invalid address family!\n");
1030 goto nets_end;
1033 nets = ++i;
1035 if (i > MAX_NETS) {
1036 elog("Max networks reached, stopped parsing at %d nets.\n", i-1);
1037 goto nets_end;
1041 // continue parsing at p, which might point to another network range
1042 f = p;
1043 if(p) f++;
1045 nets_end:
1046 free(snet);
1047 return;
1050 void game_over()
1053 if (inpacket == 0) {
1054 end_sessions(); /* Need to have correct human output when reading -r pcap */
1055 clear_asset_list();
1056 end_all_sessions();
1057 del_known_services();
1058 del_signature_lists();
1059 unload_tcp_sigs();
1060 end_logging();
1061 if(!ISSET_CONFIG_QUIET(config)){
1062 print_prads_stats();
1063 if(!config.pcap_file)
1064 print_pcap_stats();
1066 if (config.handle != NULL) pcap_close(config.handle);
1067 if (ISSET_CONFIG_SYSLOG(config)) closelog();
1068 free_config();
1069 olog("[*] prads ended.\n");
1070 exit(0);
1072 intr_flag = 1;
1075 void reparse_conf()
1077 if(inpacket == 0) {
1078 olog("Reparsing config file...");
1079 parse_config_file(config.file);
1080 end_sessions();
1081 intr_flag = 0;
1082 return;
1084 intr_flag = 4;
1087 void check_interrupt()
1090 if (intr_flag == 1) {
1091 game_over();
1092 } else if (intr_flag == 2) {
1093 update_asset_list();
1094 } else if (intr_flag == 3) {
1095 set_end_sessions();
1096 } else if (intr_flag == 4) {
1097 reparse_conf();
1098 } else {
1099 intr_flag = 0;
1103 void set_end_sessions()
1105 intr_flag = 3;
1107 if (inpacket == 0) {
1108 tstamp = time(NULL);
1109 end_sessions();
1110 /* if no cxtracking is turned on - dont log to disk */
1111 /* if (log_cxt == 1) log_expired_cxt(); */
1112 /* if no asset detection is turned on - dont log to disk! */
1113 /* if (log_assets == 1) update_asset_list(); */
1114 update_asset_list();
1115 intr_flag = 0;
1116 alarm(SIG_ALRM);
1118 // install self again
1119 signal(SIGUSR1, set_end_sessions);
1122 void print_prads_stats()
1124 extern uint64_t cxtrackerid; // cxt.c
1125 olog("-- prads:\n");
1126 olog("-- Total packets received from libpcap :%12u\n",config.pr_s.got_packets);
1127 olog("-- Total Ethernet packets received :%12u\n",config.pr_s.eth_recv);
1128 olog("-- Total VLAN packets received :%12u\n",config.pr_s.vlan_recv);
1129 olog("-- Total ARP packets received :%12u\n",config.pr_s.arp_recv);
1130 olog("-- Total IPv4 packets received :%12u\n",config.pr_s.ip4_recv);
1131 olog("-- Total IPv6 packets received :%12u\n",config.pr_s.ip6_recv);
1132 olog("-- Total Other link packets received :%12u\n",config.pr_s.otherl_recv);
1133 olog("-- Total IPinIPv4 packets received :%12u\n",config.pr_s.ip4ip_recv);
1134 olog("-- Total IPinIPv6 packets received :%12u\n",config.pr_s.ip6ip_recv);
1135 olog("-- Total GRE packets received :%12u\n",config.pr_s.gre_recv);
1136 olog("-- Total TCP packets received :%12u\n",config.pr_s.tcp_recv);
1137 olog("-- Total UDP packets received :%12u\n",config.pr_s.udp_recv);
1138 olog("-- Total ICMP packets received :%12u\n",config.pr_s.icmp_recv);
1139 olog("-- Total Other transport packets received :%12u\n",config.pr_s.othert_recv);
1140 olog("--\n");
1141 olog("-- Total sessions tracked :%12lu\n", cxtrackerid);
1142 olog("-- Total assets detected :%12u\n",config.pr_s.assets);
1143 olog("-- Total TCP OS fingerprints detected :%12u\n",config.pr_s.tcp_os_assets);
1144 olog("-- Total UDP OS fingerprints detected :%12u\n",config.pr_s.udp_os_assets);
1145 olog("-- Total ICMP OS fingerprints detected :%12u\n",config.pr_s.icmp_os_assets);
1146 olog("-- Total DHCP OS fingerprints detected :%12u\n",config.pr_s.dhcp_os_assets);
1147 olog("-- Total TCP service assets detected :%12u\n",config.pr_s.tcp_services);
1148 olog("-- Total TCP client assets detected :%12u\n",config.pr_s.tcp_clients);
1149 olog("-- Total UDP service assets detected :%12u\n",config.pr_s.udp_services);
1150 olog("-- Total UDP client assets detected :%12u\n",config.pr_s.udp_clients);
1154 static void usage()
1156 olog("USAGE:\n");
1157 olog(" $ prads [options]\n");
1158 olog("\n");
1159 olog(" OPTIONS:\n");
1160 olog("\n");
1161 olog(" -i <iface> Network device <iface> (default: eth0).\n");
1162 olog(" -r <file> Read pcap <file>.\n");
1163 olog(" -c <file> Read config from <file>\n");
1164 olog(" -b <filter> Apply Berkeley packet filter <filter>.\n");
1165 olog(" -u <user> Run as user <user> (Default: uid 1)\n");
1166 olog(" -g <group> Run as group <group> (Default: gid 1)\n");
1167 olog(" -d Do not drop privileges.\n");
1168 olog(" -a <nets> Specify home nets (eg: '192.168.0.0/25,10.0.0.0/255.0.0.0').\n");
1169 olog(" -D Daemonize.\n");
1170 olog(" -p <pidfile> Name of pidfile - inside chroot\n");
1171 olog(" -l <file> Log assets to <file> (default: '%s')\n", config.assetlog);
1172 olog(" -f <FIFO> Log assets to <FIFO>\n");
1173 olog(" -B Log connections to ringbuffer\n");
1174 olog(" -C <dir> Chroot into <dir> before dropping privs.\n");
1175 olog(" -XFRMSAK Flag picker: X - clear flags, F:FIN, R:RST, M:MAC, S:SYN, A:ACK, K:SYNACK\n");
1176 olog(" -UTtI Service checks: U:UDP, T:TCP-server, I:ICMP, t:TCP-cLient\n");
1177 olog(" -P DHCP fingerprinting.\n");
1178 olog(" -s <snaplen> Dump <snaplen> bytes of each payload.\n");
1179 olog(" -v Verbose output - repeat for more verbosity.\n");
1180 olog(" -q Quiet - try harder not to produce output.\n");
1181 olog(" -L <dir> log cxtracker type output to <dir> (will be owned by <uid>).\n");
1182 olog(" -O Connection tracking [O]utput - per-packet!\n");
1183 olog(" -x Conne[x]ion tracking output - New, expired and ended.\n");
1184 olog(" -Z Passive DNS (Experimental).\n");
1185 olog(" -H DHCP fingerprinting (Expermiental).\n");
1186 olog(" -h This help message.\n");
1189 int load_bpf(globalconfig* conf, const char* file)
1191 int sz, i;
1192 FILE* fs;
1193 char* lineptr;
1194 struct stat statbuf;
1195 fs = fopen(file, "r");
1196 if(!fs){
1197 perror("bpf file");
1198 return 1;
1200 if(fstat(fileno(fs), &statbuf)){
1201 perror("oh god my eyes!");
1202 fclose(fs);
1203 return 2;
1205 sz = statbuf.st_size;
1206 if(conf->bpff) free(conf->bpff);
1207 if(!(conf->bpff = calloc(sz, 1))){
1208 perror("mem alloc");
1209 fclose(fs);
1210 return 3;
1212 lineptr = conf->bpff;
1213 // read file but ignore comments and newlines
1214 while(fgets(lineptr, sz-(conf->bpff-lineptr), fs)) {
1215 // skip spaces
1216 for(i=0;;i++)
1217 if(lineptr[i] != ' ')
1218 break;
1219 // scan ahead and kill comments
1220 for(i=0;lineptr[i];i++)
1221 switch(lineptr[i]){
1222 case '#': // comment on the line
1223 lineptr[i] = '\n'; // end line here
1224 lineptr[i+1] = '\0'; // ends outer loop & string
1225 case '\n': // end-of-line
1226 case '\0': // end-of-string
1227 break;
1229 if(i<=1) continue; // empty line
1230 lineptr = lineptr+strlen(lineptr);
1232 fclose(fs);
1233 olog("[*] BPF file\t\t %s (%d bytes read)\n", conf->bpf_file, sz);
1234 if(config.verbose) olog("BPF: { %s}\n", conf->bpff);
1235 return 0;
1239 int prads_initialize(globalconfig *conf)
1241 if (conf->bpf_file) {
1242 if(load_bpf(conf, conf->bpf_file)){
1243 elog("[!] Failed to load bpf from file.\n");
1246 if (conf->pcap_file) {
1247 struct stat sb;
1248 if(stat(conf->pcap_file, &sb) || !sb.st_size) {
1249 elog("[!] '%s' not a pcap. Bailing.\n", conf->pcap_file);
1250 exit(1);
1253 /* Read from PCAP file specified by '-r' switch. */
1254 olog("[*] Reading from file %s\n", conf->pcap_file);
1255 if (!(conf->handle = pcap_open_offline(conf->pcap_file, conf->errbuf))) {
1256 olog("[*] Unable to open %s. (%s)\n", conf->pcap_file, conf->errbuf);
1259 } else {
1260 int uid, gid;
1261 if(conf->drop_privs_flag) {
1262 if(getuid() != 0) {
1263 conf->drop_privs_flag = 0;
1264 elog("[!] Can't drop privileges, not root.\n");
1265 } else {
1266 /* getting numerical ids before chroot call */
1267 gid = get_gid(conf->group_name);
1268 uid = get_uid(conf->user_name, &gid);
1269 if(!gid){
1270 elog("[!] Problem finding user %s group %s\n", conf->user_name, conf->group_name);
1271 exit(ENOENT);
1273 if (gid && getuid() == 0 && initgroups(conf->user_name, gid) < 0) {
1274 elog("[!] Unable to init group names (%s/%u)\n", conf->user_name, gid);
1279 /* * look up an available device if non specified */
1280 if (conf->dev == 0x0)
1281 conf->dev = pcap_lookupdev(conf->errbuf);
1282 if (conf->dev){
1283 *conf->errbuf = 0;
1284 }else{
1285 elog("[*] Error looking up device: '%s', try setting device with -i flag.\n", conf->errbuf);
1286 exit(1);
1289 olog("[*] Device: %s\n", conf->dev);
1291 if ((conf->handle = pcap_open_live(conf->dev, SNAPLENGTH, 1, 500, conf->errbuf)) == NULL) {
1292 elog("[!] Error pcap_open_live: %s \n", conf->errbuf);
1293 exit(1);
1295 /* * B0rk if we see an error... */
1296 if (strlen(conf->errbuf) > 0) {
1297 elog("[*] Error errbuf: %s \n", conf->errbuf);
1298 exit(1);
1301 if(conf->chroot_dir){
1303 olog("[*] Chrooting to dir '%s'..\n", conf->chroot_dir);
1304 if(set_chroot()){
1305 elog("[!] failed to chroot\n");
1306 exit(1);
1309 /* gotta create/chown pidfile before dropping privs */
1310 if(conf->pidfile)
1311 touch_pid_file(conf->pidfile, uid, gid);
1313 if (conf->drop_privs_flag && ( uid || gid)) {
1314 olog("[*] Dropping privileges to %s:%s...\n",
1315 conf->user_name?conf->user_name:"", conf->group_name?conf->group_name:"");
1316 drop_privs(uid, gid);
1318 /* NOTE: we init sancp-style conntrack-logging after dropping privs,
1319 * because the logs need rotation after dropping privs */
1320 if(config.cxtlogdir[0] != '\0'){
1321 static char log_prefix[PATH_MAX];
1322 snprintf(log_prefix, PATH_MAX, "%sstats.%s",
1323 config.cxtlogdir, config.dev? config.dev : "pcap");
1324 int rc = init_logging(LOG_SGUIL, log_prefix, 0);
1325 if (rc)
1326 perror("Logging to sguil output failed!");
1329 if(conf->pidfile){
1330 if (!is_valid_path(conf->pidfile)){
1331 elog("[!] Pidfile '%s' is not writable.\n", conf->pidfile);
1332 exit(ENOENT);
1335 if (conf->daemon_flag) {
1336 olog("[*] Daemonizing...\n");
1337 daemonize(NULL);
1339 if (conf->pidfile) {
1340 int rc;
1341 if((rc=create_pid_file(conf->pidfile))) {
1342 elog("[!] pidfile error, wrong permissions or prads already running? %s: %s\n", conf->pidfile, strerror(rc));
1343 exit(ENOENT);
1347 return 0;
1350 void prads_version(void)
1352 olog("[*] prads %s\n", VERSION);
1353 olog(" Using %s\n", pcap_lib_version());
1354 olog(" Using PCRE version %s\n", pcre_version());
1357 /* magic main */
1358 int main(int argc, char *argv[])
1360 int32_t rc = 0;
1361 int ch = 0, verbose_already = 0;
1363 vlog(2, "%08x =? %08x, endianness: %s\n\n", 0xdeadbeef, ntohl(0xdeadbeef), (0xdead == ntohs(0xdead)?"big":"little") );
1365 memset(&config, 0, sizeof(globalconfig));
1366 set_default_config_options(&config);
1368 inpacket = gameover = intr_flag = 0;
1370 signal(SIGTERM, game_over);
1371 signal(SIGINT, game_over);
1372 signal(SIGQUIT, game_over);
1373 signal(SIGALRM, set_end_sessions);
1374 signal(SIGHUP, reparse_conf);
1375 signal(SIGUSR1, set_end_sessions);
1376 #ifdef DEBUG
1377 signal(SIGUSR1, cxt_log_buckets);
1378 #endif
1380 // do first-pass args parse for commandline-passed config file
1381 opterr = 0;
1382 while ((ch = getopt(argc, argv, ARGS)) != -1)
1383 switch (ch) {
1384 case 'c':
1385 config.file = optarg;
1386 break;
1387 case 'v':
1388 config.verbose++;
1389 break;
1390 case 'q':
1391 config.cflags |= CONFIG_QUIET;
1392 break;
1393 case 'h':
1394 usage();
1395 exit(0);
1396 default:
1397 break;
1400 if(config.verbose)
1401 verbose_already = 1;
1403 parse_config_file(config.file);
1405 // reset verbosity before 2nd coming, but only if set on cli
1406 if(verbose_already)
1407 config.verbose = 0;
1408 optind = 1;
1409 prads_version();
1411 if(parse_args(&config, argc, argv, ARGS) != 0){
1412 usage();
1413 exit(0);
1415 // we're done parsing configs - now initialize prads
1416 if(ISSET_CONFIG_SYSLOG(config)) {
1417 openlog("prads", LOG_PID | LOG_CONS, LOG_DAEMON);
1419 if (config.ringbuffer) {
1420 rc = init_logging(LOG_RINGBUFFER, NULL, config.cflags);
1421 if (rc)
1422 perror("Logging to ringbuffer failed!");
1424 if (config.cflags & (CONFIG_VERBOSE | CONFIG_CXWRITE | CONFIG_CONNECT)) {
1425 rc = init_logging(LOG_STDOUT, NULL, config.cflags);
1426 if(rc) perror("Logging to standard out failed!");
1428 if(config.assetlog) {
1429 olog("logging to file '%s'\n", config.assetlog);
1430 rc = init_logging(LOG_FILE, config.assetlog, config.cflags);
1431 if(rc) perror("Logging to file failed!");
1433 if(config.fifo) {
1434 olog("logging to FIFO '%s'\n", config.fifo);
1435 rc = init_logging(LOG_FIFO, config.fifo, config.cflags);
1436 if(rc) perror("Logging to fifo failed!");
1438 /* moved NOTE: cxtlog is inited in prads_initialize, after dropping privs */
1439 if(config.s_net){
1440 parse_nets(config.s_net, network);
1442 olog("[*] Loading fingerprints:\n");
1443 /* helper macro to avoid duplicate code */
1444 #define load_foo(func, conf, flag, file, hash, len, dump) \
1445 if(config. conf & flag) { \
1446 int _rc; \
1447 olog(" %-11s %s\n", # flag, (config. file)); \
1448 _rc = func (config. file, & config. hash, config. len); \
1449 if(_rc) perror( #flag " load failed!"); \
1450 else if(config.verbose > 1) { \
1451 printf("[*] Dumping " #flag " signatures:\n"); \
1452 dump (config. hash, config. len); \
1453 printf("[*] " #flag " signature dump ends.\n"); \
1457 load_foo(load_mac , cof, CS_MAC, sig_file_mac, sig_mac, mac_hashsize, dump_macs);
1458 load_foo(load_sigs, ctf, CO_SYN, sig_file_syn, sig_syn, sig_hashsize, dump_sigs);
1459 load_foo(load_sigs, ctf, CO_SYNACK, sig_file_synack, sig_synack, sig_hashsize, dump_sigs);
1460 load_foo(load_sigs, ctf, CO_ACK, sig_file_ack, sig_ack, sig_hashsize, dump_sigs);
1461 load_foo(load_sigs, ctf, CO_FIN, sig_file_fin, sig_fin, sig_hashsize, dump_sigs);
1462 load_foo(load_sigs, ctf, CO_RST, sig_file_rst, sig_rst, sig_hashsize, dump_sigs);
1463 load_foo(load_dhcp_sigs, ctf, CO_DHCP, sig_file_dhcp, sig_dhcp, sig_hashsize, dump_dhcp_sigs);
1464 load_foo(load_servicefp_file, cof, CS_TCP_SERVER, sig_file_serv_tcp, sig_serv_tcp, sig_hashsize, dump_sig_service);
1465 load_foo(load_servicefp_file, cof, CS_UDP_SERVICES, sig_file_serv_udp, sig_serv_udp, sig_hashsize, dump_sig_service);
1466 load_foo(load_servicefp_file, cof, CS_TCP_CLIENT, sig_file_cli_tcp, sig_client_tcp, sig_hashsize, dump_sig_service);
1467 init_services();
1469 display_config(&config);
1471 prads_initialize(&config);
1473 alarm(SIG_ALRM);
1475 /** segfaults on empty pcap! */
1476 struct bpf_program cfilter; /**/
1477 if ((pcap_compile(config.handle, &cfilter, config.bpff, 1, config.net_mask)) == -1) {
1478 olog("[*] Error pcap_compile user_filter: %s\n", pcap_geterr(config.handle));
1479 exit(1);
1482 if (pcap_setfilter(config.handle, &cfilter)) {
1483 olog("[*] Unable to set pcap filter! %s", pcap_geterr(config.handle));
1485 pcap_freecode(&cfilter);
1487 cxt_init();
1488 olog("[*] Sniffing...\n");
1489 pcap_loop(config.handle, -1, got_packet, NULL);
1491 game_over();
1492 return (0);