document the default privilege drop (Closes #34)
[prads.git] / src / prads.c
blobe90332e9a9237a259f599f57545ba1acb119e406
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 u_ntop(network[i].addr, af, output);
200 dlog("net: %s\n", output);
201 u_ntop(network[i].mask, af, output);
202 dlog("mask: %s\n", output);
203 u_ntop(ip_vec.ip6, af, output);
204 dlog("ip: %s\n", output);
205 #endif
206 if (network[i].type == AF_INET6) {
207 #if(1)
208 /* apologies for the uglyness */
209 #ifdef HAVE_SSE2
210 #define compare128(x,y) __builtin_ia32_pcmpeqd128((x), (y))
211 // the builtin is only available on sse2!
212 t.v = __builtin_ia32_pcmpeqd128(
213 ip_vec.v & network[i].mask_v,
214 network[i].addr_v);
215 if (t.i[0] & t.i[1])
216 #else
217 #define compare128(x,y) memcmp(&(x),&(y),16)
218 t.v = ip_vec.v & network[i].mask_v;
219 // xor(a,b) == 0 iff a==b
220 if (!( (t.i[0] ^ network[i].addr64[0]) &
221 (t.i[1] ^ network[i].addr64[1]) ))
222 #endif
224 our = 1;
225 break;
228 #else
229 if ((ip_s.__u6_addr.__u6_addr32[0] & network[i].mask.__u6_addr.__u6_addr32[0])
230 == network[i].addr.__u6_addr.__u6_addr32[0]
231 && (ip_s.__u6_addr.__u6_addr32[1] & network[i].mask.__u6_addr.__u6_addr32[1])
232 == network[i].addr.__u6_addr.__u6_addr32[1]
233 && (ip_s.__u6_addr.__u6_addr32[2] & network[i].mask.__u6_addr.__u6_addr32[2])
234 == network[i].addr.__u6_addr.__u6_addr32[2]
235 && (ip_s.__u6_addr.__u6_addr32[3] & network[i].mask.__u6_addr.__u6_addr32[3])
236 == network[i].addr.__u6_addr.__u6_addr32[3]) {
237 our = 1;
238 break;
240 #endif
244 break;
245 default:
246 fprintf(stderr,
247 "non-ip packets of type %d aren't filtered by netmask yet\n", af);
248 our = 1;
250 #ifdef DEBUG
251 if (af == AF_INET6){
252 inet_ntop(af, (struct in6addr*) ipptr, output, MAX_NETS);
253 }else{
254 inet_ntop(af, (uint32_t*)ipptr, output, MAX_NETS);
256 if (our){
257 vlog(0x2, "Address %s is in our network.\n", output);
258 } else {
259 vlog(0x2, "Address %s is not our network.\n", output);
261 #endif
262 return our;
265 void prepare_eth (packetinfo *pi)
267 if (pi->packet + ETHERNET_HEADER_LEN > pi->end_ptr) return;
268 config.pr_s.eth_recv++;
269 pi->eth_hdr = (ether_header *) (pi->packet);
270 pi->eth_type = ntohs(pi->eth_hdr->eth_ip_type);
271 pi->eth_hlen = ETHERNET_HEADER_LEN;
272 return;
275 void parse_eth (packetinfo *pi)
277 if (!IS_CSSET(&config,CS_MAC)) return;
278 /* update_asset_arp(pi->eth_hdr->ether_src, pi);
280 uint8_t *mac = pi->eth_hdr->ether_src;
282 * XXX: how is mac matching supposed to work?
283 * answer: lookup macs on pertinent frames
284 * and hash into mac asset database
285 * mac assets are like regular assets,
286 * and contain references to other assets they involve
287 if(! pi->asset->mace)
288 mac_entry *match = match_mac(config.sig_mac, mac, 48);
289 //pi->asset->mace ;
291 print_mac(mac);
292 olog("mac matched: %s\n", match->vendor);
294 // call update_asset_mac or smth?
295 // stats?
296 //config.pr_s.eth_recv++;
298 return;
302 void check_vlan (packetinfo *pi)
304 if (pi->eth_type == ETHERNET_TYPE_8021Q) {
305 vlog(0x3, "[*] ETHERNET TYPE 8021Q\n");
306 config.pr_s.vlan_recv++;
307 pi->vlan = pi->eth_hdr->eth_8_vid;
308 pi->eth_type = ntohs(pi->eth_hdr->eth_8_ip_type);
309 pi->eth_hlen += 4;
311 /* This is b0rked - kwy and ebf fix */
312 } else if (pi->eth_type ==
313 (ETHERNET_TYPE_802Q1MT | ETHERNET_TYPE_802Q1MT2 |
314 ETHERNET_TYPE_802Q1MT3 | ETHERNET_TYPE_8021AD)) {
315 vlog(0x3, "[*] ETHERNET TYPE 802Q1MT\n");
316 pi->mvlan = pi->eth_hdr->eth_82_mvid;
317 pi->eth_type = ntohs(pi->eth_hdr->eth_82_ip_type);
318 pi->eth_hlen += 8;
320 return;
323 void prepare_ip4 (packetinfo *pi)
325 config.pr_s.ip4_recv++;
326 pi->af = AF_INET;
327 pi->ip4 = (ip4_header *) (pi->packet + pi->eth_hlen);
328 pi->packet_bytes = (ntohs(pi->ip4->ip_len) - (IP_HL(pi->ip4) * 4));
330 pi->our = filter_packet(pi->af, &PI_IP4SRC(pi));
331 vlog(0x3, "Got %s IPv4 Packet...\n", (pi->our?"our":"foregin"));
332 return;
335 void parse_ip4 (packetinfo *pi)
337 switch (pi->ip4->ip_p) {
338 case IP_PROTO_TCP:
339 prepare_tcp(pi);
340 if (!pi->our)
341 break;
342 parse_tcp(pi);
343 break;
344 case IP_PROTO_UDP:
345 prepare_udp(pi);
346 if (!pi->our)
347 break;
348 parse_udp(pi);
349 break;
350 case IP_PROTO_ICMP:
351 prepare_icmp(pi);
352 if (!pi->our)
353 break;
354 parse_icmp(pi);
355 break;
356 case IP_PROTO_IP4:
357 prepare_ip4ip(pi);
358 break;
359 case IP_PROTO_IP6:
360 prepare_ip4ip(pi);
361 break;
362 case IP_PROTO_GRE:
363 prepare_gre(pi);
364 parse_gre(pi);
365 break;
367 default:
368 prepare_other(pi);
369 if (!pi->our)
370 break;
371 parse_other(pi);
373 return;
376 void prepare_gre (packetinfo *pi)
378 config.pr_s.gre_recv++;
379 if((pi->pheader->caplen - pi->eth_hlen) < GRE_HDR_LEN) {
380 return;
382 if (pi->af == AF_INET) {
383 vlog(0x3, "[*] IPv4 PROTOCOL TYPE GRE:\n");
384 pi->greh = (gre_header *) (pi->packet + pi->eth_hlen + (IP_HL(pi->ip4) * 4));
385 } else if (pi->af == AF_INET6) {
386 vlog(0x3, "[*] IPv6 PROTOCOL TYPE GRE:\n");
387 pi->greh = (gre_header *) (pi->packet + pi->eth_hlen + IP6_HEADER_LEN);
389 pi->proto = IP_PROTO_GRE;
390 return;
393 void parse_gre (packetinfo *pi)
395 uint16_t gre_header_len = GRE_HDR_LEN;
396 gre_sre_header *gsre = NULL;
397 uint16_t len = (pi->pheader->caplen - pi->eth_hlen);
399 update_asset(pi);
401 switch (GRE_GET_VERSION(pi->greh))
403 case GRE_VERSION_0:
404 /* Adjust header length based on content */
405 if (GRE_FLAG_ISSET_KY(pi->greh))
406 gre_header_len += GRE_KEY_LEN;
407 if (GRE_FLAG_ISSET_SQ(pi->greh))
408 gre_header_len += GRE_SEQ_LEN;
409 if (GRE_FLAG_ISSET_CHKSUM(pi->greh) || GRE_FLAG_ISSET_ROUTE(pi->greh))
410 gre_header_len += GRE_CHKSUM_LEN + GRE_OFFSET_LEN;
411 if (gre_header_len > len) {
412 return;
414 if (GRE_FLAG_ISSET_ROUTE(pi->greh))
416 gsre = (gre_sre_header *)(pi->greh + gre_header_len);
417 if (gsre == NULL) return;
418 while (1)
420 if ((gre_header_len+GRE_SRE_HDR_LEN) > len) {
421 break;
423 gre_header_len += GRE_SRE_HDR_LEN;
425 if (gsre != NULL && (ntohs(gsre->af) == 0) && (gsre->sre_length == 0))
426 break;
428 gre_header_len += gsre->sre_length;
429 gsre = (gre_sre_header *)(pi->greh + gre_header_len);
430 if (gsre == NULL)
431 return;
434 break;
436 case GRE_VERSION_1:
437 /* GRE version 1 doenst support the fields below RFC 1701 */
438 if (GRE_FLAG_ISSET_CHKSUM(pi->greh)) {
439 return;
441 if (GRE_FLAG_ISSET_ROUTE(pi->greh)) {
442 return;
444 if (GRE_FLAG_ISSET_SSR(pi->greh)) {
445 return;
447 if (GRE_FLAG_ISSET_RECUR(pi->greh)) {
448 return;
450 if (GREV1_FLAG_ISSET_FLAGS(pi->greh)) {
451 return;
453 if (GRE_GET_PROTO(pi->greh) != GRE_PROTO_PPP) {
454 return;
456 if (!(GRE_FLAG_ISSET_KY(pi->greh))) {
457 return;
460 gre_header_len += GRE_KEY_LEN;
462 /* Adjust header length based on content */
463 if (GRE_FLAG_ISSET_SQ(pi->greh))
464 gre_header_len += GRE_SEQ_LEN;
465 if (GREV1_FLAG_ISSET_ACK(pi->greh))
466 gre_header_len += GREV1_ACK_LEN;
467 if (gre_header_len > len) {
468 return;
470 break;
472 default:
473 /* Error */
474 return;
477 prepare_greip(pi);
478 return;
481 void prepare_ip6ip (packetinfo *pi)
483 packetinfo pipi;
484 memset(&pipi, 0, sizeof(packetinfo));
485 config.pr_s.ip6ip_recv++;
486 pipi.pheader = pi->pheader;
487 pipi.packet = (pi->packet + pi->eth_hlen + IP6_HEADER_LEN);
488 pipi.end_ptr = pi->end_ptr;
489 if (pi->ip6->next == IP_PROTO_IP4) {
490 prepare_ip4(&pipi);
491 parse_ip4(&pipi);
492 return;
493 } else {
494 prepare_ip6(&pipi);
495 parse_ip6(&pipi);
496 return;
500 void prepare_greip (packetinfo *pi)
502 packetinfo pipi;
503 memset(&pipi, 0, sizeof(packetinfo));
504 pipi.pheader = pi->pheader;
505 pipi.packet = (pi->packet + pi->eth_hlen + pi->gre_hlen);
506 pipi.end_ptr = pi->end_ptr;
507 if (GRE_GET_PROTO(pi->greh) == IP_PROTO_IP4) {
508 prepare_ip4(&pipi);
509 parse_ip4(&pipi);
510 return;
511 } else if (GRE_GET_PROTO(pi->greh) == IP_PROTO_IP6) {
512 prepare_ip6(&pipi);
513 parse_ip6(&pipi);
514 return;
515 } else {
516 /* Not more implemented atm */
517 vlog(0x3, "[*] - NOT CHECKING GRE PACKAGE TYPE Other\n");
518 return;
522 void prepare_ip4ip (packetinfo *pi)
524 packetinfo pipi;
525 memset(&pipi, 0, sizeof(packetinfo));
526 config.pr_s.ip4ip_recv++;
527 pipi.pheader = pi->pheader;
528 pipi.packet = (pi->packet + pi->eth_hlen + (IP_HL(pi->ip4) * 4));
529 pipi.end_ptr = pi->end_ptr;
530 if (pi->ip4->ip_p == IP_PROTO_IP4) {
531 prepare_ip4(&pipi);
532 parse_ip4(&pipi);
533 return;
534 } else {
535 prepare_ip6(&pipi);
536 parse_ip6(&pipi);
537 return;
541 void prepare_ip6 (packetinfo *pi)
543 config.pr_s.ip6_recv++;
544 pi->af = AF_INET6;
545 pi->ip6 = (ip6_header *) (pi->packet + pi->eth_hlen);
546 pi->packet_bytes = ntohs(pi->ip6->len);
547 // may be dropped due to macros plus
548 //pi->ip_src = PI_IP6SRC(pi);
549 //pi->ip_dst = PI_IP6DST(pi);
550 pi->our = filter_packet(pi->af, &PI_IP6SRC(pi));
551 vlog(0x3, "Got %s IPv6 Packet...\n", (pi->our?"our":"foregin"));
552 return;
555 void parse_ip6 (packetinfo *pi)
557 switch (pi->ip6->next) {
558 case IP_PROTO_TCP:
559 prepare_tcp(pi);
560 if (!pi->our)
561 break;
562 parse_tcp(pi);
563 break;
564 case IP_PROTO_UDP:
565 prepare_udp(pi);
566 if (!pi->our)
567 break;
568 parse_udp(pi);
569 break;
570 case IP6_PROTO_ICMP:
571 prepare_icmp(pi);
572 if (!pi->our)
573 break;
574 parse_icmp(pi);
575 break;
576 case IP_PROTO_IP4:
577 prepare_ip6ip(pi);
578 break;
579 case IP_PROTO_IP6:
580 prepare_ip6ip(pi);
581 break;
583 default:
584 prepare_other(pi);
586 * if (check != 0) {
587 * olog("[*] - CHECKING OTHER PACKAGE\n");
588 * update_asset(AF_INET6,ip6->ip_src);
589 * service_other(*pi->ip4,*tcph)
590 * fp_other(ip, ttl, ipopts, len, id, ipflags, df);
591 * }else{
592 * olog("[*] - NOT CHECKING OTHER PACKAGE\n");
593 * }
595 break;
597 return;
600 void parse_arp (packetinfo *pi)
602 vlog(0x3, "[*] Got ARP packet...\n");
603 config.pr_s.arp_recv++;
604 if (!IS_CSSET(&config,CS_ARP)) return;
605 pi->af = AF_INET;
606 pi->arph = (ether_arp *) (pi->packet + pi->eth_hlen);
608 if (ntohs(pi->arph->ea_hdr.ar_op) == ARPOP_REPLY) {
609 if (filter_packet(pi->af, &pi->arph->arp_spa)) {
610 update_asset_arp(pi->arph->arp_sha, pi);
612 /* arp_check(eth_hdr,pi->pheader->ts.tv_sec); */
613 } else {
614 vlog(0x3, "[*] ARP TYPE: %d\n",ntohs(pi->arph->ea_hdr.ar_op));
618 void set_pkt_end_ptr (packetinfo *pi)
620 /* Paranoia! */
621 if (pi->pheader->len <= SNAPLENGTH) {
622 pi->end_ptr = (pi->packet + pi->pheader->len);
623 } else {
624 pi->end_ptr = (pi->packet + SNAPLENGTH);
626 return;
629 void prepare_tcp (packetinfo *pi)
631 config.pr_s.tcp_recv++;
632 if (pi->af==AF_INET) {
633 vlog(0x3, "[*] IPv4 PROTOCOL TYPE TCP:\n");
634 pi->tcph = (tcp_header *) (pi->packet + pi->eth_hlen + (IP_HL(pi->ip4) * 4));
635 pi->plen = (pi->pheader->caplen - (TCP_OFFSET(pi->tcph)) * 4 - (IP_HL(pi->ip4) * 4) - pi->eth_hlen);
636 pi->payload = (pi->packet + pi->eth_hlen + (IP_HL(pi->ip4) * 4) + (TCP_OFFSET(pi->tcph) * 4));
637 } else if (pi->af==AF_INET6) {
638 vlog(0x3, "[*] IPv6 PROTOCOL TYPE TCP:\n");
639 pi->tcph = (tcp_header *) (pi->packet + pi->eth_hlen + IP6_HEADER_LEN);
640 pi->plen = (pi->pheader->caplen - (TCP_OFFSET(pi->tcph)) * 4 - IP6_HEADER_LEN - pi->eth_hlen);
641 pi->payload = (pi->packet + pi->eth_hlen + IP6_HEADER_LEN + (TCP_OFFSET(pi->tcph)*4));
643 pi->proto = IP_PROTO_TCP;
644 pi->s_port = pi->tcph->src_port;
645 pi->d_port = pi->tcph->dst_port;
646 connection_tracking(pi);
647 //cx_track_simd_ipv4(pi);
648 if(config.payload)
649 dump_payload(pi->payload, (config.payload < pi->plen)?config.payload:pi->plen);
650 return;
653 void parse_tcp (packetinfo *pi)
655 update_asset(pi);
657 if (TCP_ISFLAGSET(pi->tcph, (TF_SYN))) {
658 if (!TCP_ISFLAGSET(pi->tcph, (TF_ACK))) {
659 if (IS_COSET(&config,CO_SYN)) {
660 vlog(0x3, "[*] - Got a SYN from a CLIENT: dst_port:%d\n",ntohs(pi->tcph->dst_port));
661 fp_tcp(pi, CO_SYN);
662 return;
664 } else {
665 if (IS_COSET(&config,CO_SYNACK)) {
666 vlog(0x3, "[*] Got a SYNACK from a SERVER: src_port:%d\n", ntohs(pi->tcph->src_port));
667 fp_tcp(pi, CO_SYNACK);
668 if (pi->sc != SC_SERVER)
669 reverse_pi_cxt(pi);
670 return;
675 // Check payload for known magic bytes that defines files!
677 if (pi->sc == SC_CLIENT && !ISSET_CXT_DONT_CHECK_CLIENT(pi)) {
678 if (IS_CSSET(&config,CS_TCP_CLIENT)
679 && !ISSET_DONT_CHECK_CLIENT(pi)) {
680 if (pi->af == AF_INET)
681 client_tcp4(pi, config.sig_client_tcp);
682 else
683 client_tcp6(pi, config.sig_client_tcp);
685 goto bastard_checks;
687 } else if (pi->sc == SC_SERVER && !ISSET_CXT_DONT_CHECK_SERVER(pi)) {
688 if (IS_CSSET(&config,CS_TCP_SERVER)
689 && !ISSET_DONT_CHECK_SERVICE(pi)) {
690 if (pi->af == AF_INET)
691 service_tcp4(pi, config.sig_serv_tcp);
692 else
693 service_tcp6(pi, config.sig_serv_tcp);
695 goto bastard_checks;
697 vlog(0x3, "[*] - NOT CHECKING TCP PACKAGE\n");
698 return;
700 bastard_checks:
701 if (IS_COSET(&config,CO_ACK)
702 && TCP_ISFLAGSET(pi->tcph, (TF_ACK))
703 && !TCP_ISFLAGSET(pi->tcph, (TF_SYN))
704 && !TCP_ISFLAGSET(pi->tcph, (TF_RST))
705 && !TCP_ISFLAGSET(pi->tcph, (TF_FIN))) {
706 vlog(0x3, "[*] Got a STRAY-ACK: src_port:%d\n",ntohs(pi->tcph->src_port));
707 fp_tcp(pi, CO_ACK);
708 return;
709 } else if (IS_COSET(&config,CO_FIN) && TCP_ISFLAGSET(pi->tcph, (TF_FIN))) {
710 vlog(0x3, "[*] Got a FIN: src_port:%d\n",ntohs(pi->tcph->src_port));
711 fp_tcp(pi, CO_FIN);
712 return;
713 } else if (IS_COSET(&config,CO_RST) && TCP_ISFLAGSET(pi->tcph, (TF_RST))) {
714 vlog(0x3, "[*] Got a RST: src_port:%d\n",ntohs(pi->tcph->src_port));
715 fp_tcp(pi, CO_RST);
716 return;
720 void prepare_udp (packetinfo *pi)
722 config.pr_s.udp_recv++;
723 if (pi->af==AF_INET) {
724 vlog(0x3, "[*] IPv4 PROTOCOL TYPE UDP:\n");
725 pi->udph = (udp_header *) (pi->packet + pi->eth_hlen + (IP_HL(pi->ip4) * 4));
726 pi->plen = pi->pheader->caplen - UDP_HEADER_LEN -
727 (IP_HL(pi->ip4) * 4) - pi->eth_hlen;
728 pi->payload = (pi->packet + pi->eth_hlen +
729 (IP_HL(pi->ip4) * 4) + UDP_HEADER_LEN);
731 } else if (pi->af==AF_INET6) {
732 vlog(0x3, "[*] IPv6 PROTOCOL TYPE UDP:\n");
733 pi->udph = (udp_header *) (pi->packet + pi->eth_hlen + + IP6_HEADER_LEN);
734 pi->plen = pi->pheader->caplen - UDP_HEADER_LEN -
735 IP6_HEADER_LEN - pi->eth_hlen;
736 pi->payload = (pi->packet + pi->eth_hlen +
737 IP6_HEADER_LEN + UDP_HEADER_LEN);
739 pi->proto = IP_PROTO_UDP;
740 pi->s_port = pi->udph->src_port;
741 pi->d_port = pi->udph->dst_port;
742 connection_tracking(pi);
743 //cx_track_simd_ipv4(pi);
744 if(config.payload)
745 dump_payload(pi->payload, (config.payload < pi->plen)?config.payload:pi->plen);
746 return;
749 void parse_udp (packetinfo *pi)
751 update_asset(pi);
752 //if (is_set_guess_upd_direction(config)) {
753 udp_guess_direction(pi); // fix DNS server transfers?
754 // Check for Passive DNS
755 if ( ntohs(pi->s_port) == 53 || ntohs(pi->s_port) == 5353 ) {
756 // For now - Proof of Concept! - Fix output way
757 if(config.cflags & CONFIG_PDNS) {
758 static char ip_addr_s[INET6_ADDRSTRLEN];
759 u_ntop_src(pi, ip_addr_s);
760 dump_dns(pi->payload, pi->plen, stdout, "\n", ip_addr_s, pi->pheader->ts.tv_sec);
763 if (IS_COSET(&config, CO_DHCP) && ntohs(pi->s_port) == 68 && ntohs(pi->d_port) == 67) {
764 dhcp_fingerprint(pi); /* basic DHCP parsing*/
766 // if (IS_COSET(&config,CO_DNS) && (pi->sc == SC_SERVER && ntohs(pi->s_port) == 53)) passive_dns (pi);
768 if (IS_CSSET(&config,CS_UDP_SERVICES)) {
769 if (pi->af == AF_INET) {
771 if (!ISSET_DONT_CHECK_SERVICE(pi)||!ISSET_DONT_CHECK_CLIENT(pi)) {
772 // Check for UDP SERVICE
773 service_udp4(pi, config.sig_serv_udp);
775 // UPD Fingerprinting
776 if (IS_COSET(&config,CO_UDP)) fp_udp4(pi, pi->ip4, pi->udph, pi->end_ptr);
777 } else if (pi->af == AF_INET6) {
778 if (!ISSET_DONT_CHECK_SERVICE(pi)||!ISSET_DONT_CHECK_CLIENT(pi)) {
779 service_udp6(pi, config.sig_client_udp);
781 /* fp_udp(ip6, ttl, ipopts, len, id, ipflags, df); */
783 return;
784 } else {
785 vlog(0x3, "[*] - NOT CHECKING UDP PACKAGE\n");
786 return;
790 void prepare_icmp (packetinfo *pi)
792 config.pr_s.icmp_recv++;
793 if (pi->af==AF_INET) {
794 vlog(0x3, "[*] IPv4 PROTOCOL TYPE ICMP:\n");
795 pi->icmph = (icmp_header *) (pi->packet + pi->eth_hlen + (IP_HL(pi->ip4) * 4));
796 pi->proto = IP_PROTO_ICMP;
798 } else if (pi->af==AF_INET6) {
799 vlog(0x3, "[*] IPv6 PROTOCOL TYPE ICMP:\n");
800 pi->icmp6h = (icmp6_header *) (pi->packet + pi->eth_hlen + IP6_HEADER_LEN);
801 pi->proto = IP6_PROTO_ICMP;
803 pi->s_port = 0;
804 pi->d_port = 0;
806 * DO change ip6->hop_lmt to 0 or something
808 connection_tracking(pi);
809 return;
812 void parse_icmp (packetinfo *pi)
814 update_asset(pi);
816 if (IS_COSET(&config,CO_ICMP)) {
817 if (pi->cxt->check == 0x00) {
818 pi->cxt->check = 0x10; //for now - stop icmp fp quick
819 if (pi->af==AF_INET) {
820 fp_icmp4(pi, pi->ip4, pi->icmph, pi->end_ptr);
821 // could look for icmp spesific data in package abcde...
822 // service_icmp(*pi->ip4,*tcph
823 } else if (pi->af==AF_INET6) {
824 add_asset(pi);
825 fp_icmp6(pi, pi->ip6, pi->icmp6h, pi->end_ptr);
827 } else {
828 vlog(0x3, "[*] - NOT CHECKING ICMP PACKAGE\n");
833 void prepare_other (packetinfo *pi)
835 config.pr_s.othert_recv++;
836 if (pi->af==AF_INET) {
837 vlog(0x3, "[*] IPv4 PROTOCOL TYPE OTHER: %d\n",pi->ip4->ip_p);
839 } else if (pi->af==AF_INET6) {
840 vlog(0x3, "[*] IPv6 PROTOCOL TYPE OTHER: %d\n",pi->ip6->next);
843 pi->s_port = 0;
844 pi->d_port = 0;
845 connection_tracking(pi);
846 return;
849 void parse_other (packetinfo *pi)
851 update_asset(pi);
853 if (pi->cxt->check == 0x00) {
854 if (IS_COSET(&config,CO_OTHER)) {
855 pi->cxt->check = 0x01; // no more checks
856 // service_other(*pi->ip4,*transporth);
857 // fp_other(pi->ipX, ttl, ipopts, len, id, ipflags, df);
858 } else {
859 vlog(0x3, "[*] - NOT CHECKING *OTHER* PACKAGE\n");
864 void udp_guess_direction(packetinfo *pi)
866 /* Stupid hack :( for DNS/port 53 */
867 if (ntohs(pi->d_port) == 53) {
868 if (pi->sc == SC_CLIENT) return;
869 else pi->sc = SC_CLIENT;
871 } else if (ntohs(pi->s_port) == 53) {
872 if (pi->sc == SC_SERVER) return;
873 else pi->sc = SC_SERVER;
877 int parse_network (char *net_s, struct in6_addr *network)
879 int type;
880 char *t;
881 if (NULL != (t = strchr(net_s, ':'))) {
882 type = AF_INET6;
883 if (!inet_pton(type, net_s, network)) {
884 perror("parse_nets6");
885 return -1;
887 dlog("Network6 %-36s \t -> %08x:%08x:%08x:%08x\n",
888 net_s,
889 IP6ADDR(network)
891 } else {
892 type = AF_INET;
893 if (!inet_pton(type, net_s, &IP4ADDR(network))) {
894 perror("parse_nets");
895 return -1;
897 dlog("Network4 %16s \t-> 0x%08x\n", net_s, IP4ADDR(network));
899 return type;
902 int parse_netmask (char *f, int type, struct in6_addr *netmask)
904 char *t;
905 uint32_t mask;
906 char output[MAX_NETS];
907 // parse netmask into host order
908 if (type == AF_INET && (t = strchr(f, '.')) > f && t-f < 4) {
909 // full ipv4 netmask : dotted quads
910 inet_pton(type, f, &IP4ADDR(netmask));
911 dlog("mask 4 %s \t-> 0x%08x\n", f, IP4ADDR(netmask));
912 } else if (type == AF_INET6 && NULL != (t = strchr(f, ':'))) {
913 // full ipv6 netmasÄž
914 dlog("mask 6 %s\n", f);
915 inet_pton(type, f, netmask);
916 } else {
917 // cidr form
918 sscanf(f, "%u", &mask);
919 dlog("cidr %u \t-> ", mask);
920 if (type == AF_INET) {
921 uint32_t shift = 32 - mask;
922 if (mask)
923 IP4ADDR(netmask) = ntohl( ((unsigned int)-1 >> shift)<< shift);
924 else
925 IP4ADDR(netmask) = 0;
927 dlog("0x%08x\n", IP4ADDR(netmask));
928 } else if (type == AF_INET6) {
929 //mask = 128 - mask;
930 int j = 0;
931 memset(netmask, 0, sizeof(struct in6_addr));
933 while (mask > 8) {
934 netmask->s6_addr[j++] = 0xff;
935 mask -= 8;
937 if (mask > 0) {
938 netmask->s6_addr[j] = -1 << (8 - mask);
940 #ifdef DEBUG
941 inet_ntop(type, &IP4ADDR(netmask), output, MAX_NETS);
942 dlog("mask: %s\n", output);
943 #endif
944 // pcap packets are in host order.
945 IP6ADDR0(netmask) = ntohl(IP6ADDR0(netmask));
946 IP6ADDR1(netmask) = ntohl(IP6ADDR1(netmask));
947 IP6ADDR2(netmask) = ntohl(IP6ADDR2(netmask));
948 IP6ADDR3(netmask) = ntohl(IP6ADDR3(netmask));
952 return 0;
955 /* parse strings of the form ip/cidr or ip/mask like:
956 * "10.10.10.10/255.255.255.128,10.10.10.10/25" and
957 * "dead:be:eef2:1aa::b5ff:fe96:37a2/64,..."
959 * an IPv6 address is 8 x 4 hex digits. missing digits are padded with zeroes.
961 void parse_nets(const char *s_net, fmask *network)
963 /* f -> for processing
964 * p -> frob pointer
965 * t -> to pointer */
966 char *f, *p, *snet;
967 int type, len, i = 0;
968 struct in6_addr network6, netmask6;
970 // snet is a mutable copy of the args,freed @ nets_end
971 len = strlen(s_net);
972 //snet = calloc(1, len);
973 snet = calloc(1, (len + 1)); /* to have \0 too :-) */
974 strncpy(snet, s_net, len);
975 f = snet;
976 while (f && 0 != (p = strchr(f, '/'))) {
977 // convert network address
978 *p = '\0';
979 type = parse_network(f, &network6);
980 if (type != AF_INET && type != AF_INET6) {
981 perror("parse_network");
982 goto nets_end;
984 // convert netmask
985 f = p + 1;
986 p = strchr(f, ',');
987 if (p) {
988 *p = '\0';
990 parse_netmask(f, type, &netmask6);
992 // poke in the gathered information
993 switch (type) {
994 case AF_INET:
995 case AF_INET6:
996 network[i].addr = network6;
997 network[i].mask = netmask6;
998 network[i].type = type;
999 break;
1001 default:
1002 fprintf(stderr, "parse_nets: invalid address family!\n");
1003 goto nets_end;
1006 nets = ++i;
1008 if (i > MAX_NETS) {
1009 elog("Max networks reached, stopped parsing at %d nets.\n", i-1);
1010 goto nets_end;
1014 // continue parsing at p, which might point to another network range
1015 f = p;
1016 if(p) f++;
1018 nets_end:
1019 free(snet);
1020 return;
1023 void game_over()
1026 if (inpacket == 0) {
1027 end_sessions(); /* Need to have correct human output when reading -r pcap */
1028 clear_asset_list();
1029 end_all_sessions();
1030 del_known_services();
1031 del_signature_lists();
1032 unload_tcp_sigs();
1033 end_logging();
1034 if(!ISSET_CONFIG_QUIET(config)){
1035 print_prads_stats();
1036 if(!config.pcap_file)
1037 print_pcap_stats();
1039 if (config.handle != NULL) pcap_close(config.handle);
1040 if (ISSET_CONFIG_SYSLOG(config)) closelog();
1041 free_config();
1042 olog("[*] prads ended.\n");
1043 exit(0);
1045 intr_flag = 1;
1048 void reparse_conf()
1050 if(inpacket == 0) {
1051 olog("Reparsing config file...");
1052 parse_config_file(config.file);
1053 end_sessions();
1054 intr_flag = 0;
1055 return;
1057 intr_flag = 4;
1060 void check_interrupt()
1063 if (intr_flag == 1) {
1064 game_over();
1065 } else if (intr_flag == 2) {
1066 update_asset_list();
1067 } else if (intr_flag == 3) {
1068 set_end_sessions();
1069 } else if (intr_flag == 4) {
1070 reparse_conf();
1071 } else {
1072 intr_flag = 0;
1076 void set_end_sessions()
1078 intr_flag = 3;
1080 if (inpacket == 0) {
1081 tstamp = time(NULL);
1082 end_sessions();
1083 /* if no cxtracking is turned on - dont log to disk */
1084 /* if (log_cxt == 1) log_expired_cxt(); */
1085 /* if no asset detection is turned on - dont log to disk! */
1086 /* if (log_assets == 1) update_asset_list(); */
1087 update_asset_list();
1088 intr_flag = 0;
1089 alarm(SIG_ALRM);
1091 // install self again
1092 signal(SIGUSR1, set_end_sessions);
1095 void print_prads_stats()
1097 extern uint64_t cxtrackerid; // cxt.c
1098 olog("-- prads:\n");
1099 olog("-- Total packets received from libpcap :%12u\n",config.pr_s.got_packets);
1100 olog("-- Total Ethernet packets received :%12u\n",config.pr_s.eth_recv);
1101 olog("-- Total VLAN packets received :%12u\n",config.pr_s.vlan_recv);
1102 olog("-- Total ARP packets received :%12u\n",config.pr_s.arp_recv);
1103 olog("-- Total IPv4 packets received :%12u\n",config.pr_s.ip4_recv);
1104 olog("-- Total IPv6 packets received :%12u\n",config.pr_s.ip6_recv);
1105 olog("-- Total Other link packets received :%12u\n",config.pr_s.otherl_recv);
1106 olog("-- Total IPinIPv4 packets received :%12u\n",config.pr_s.ip4ip_recv);
1107 olog("-- Total IPinIPv6 packets received :%12u\n",config.pr_s.ip6ip_recv);
1108 olog("-- Total GRE packets received :%12u\n",config.pr_s.gre_recv);
1109 olog("-- Total TCP packets received :%12u\n",config.pr_s.tcp_recv);
1110 olog("-- Total UDP packets received :%12u\n",config.pr_s.udp_recv);
1111 olog("-- Total ICMP packets received :%12u\n",config.pr_s.icmp_recv);
1112 olog("-- Total Other transport packets received :%12u\n",config.pr_s.othert_recv);
1113 olog("--\n");
1114 olog("-- Total sessions tracked :%12lu\n", cxtrackerid);
1115 olog("-- Total assets detected :%12u\n",config.pr_s.assets);
1116 olog("-- Total TCP OS fingerprints detected :%12u\n",config.pr_s.tcp_os_assets);
1117 olog("-- Total UDP OS fingerprints detected :%12u\n",config.pr_s.udp_os_assets);
1118 olog("-- Total ICMP OS fingerprints detected :%12u\n",config.pr_s.icmp_os_assets);
1119 olog("-- Total DHCP OS fingerprints detected :%12u\n",config.pr_s.dhcp_os_assets);
1120 olog("-- Total TCP service assets detected :%12u\n",config.pr_s.tcp_services);
1121 olog("-- Total TCP client assets detected :%12u\n",config.pr_s.tcp_clients);
1122 olog("-- Total UDP service assets detected :%12u\n",config.pr_s.udp_services);
1123 olog("-- Total UDP client assets detected :%12u\n",config.pr_s.udp_clients);
1127 static void usage()
1129 olog("USAGE:\n");
1130 olog(" $ prads [options]\n");
1131 olog("\n");
1132 olog(" OPTIONS:\n");
1133 olog("\n");
1134 olog(" -i <iface> Network device <iface> (default: eth0).\n");
1135 olog(" -r <file> Read pcap <file>.\n");
1136 olog(" -c <file> Read config from <file>\n");
1137 olog(" -b <filter> Apply Berkeley packet filter <filter>.\n");
1138 olog(" -u <user> Run as user <user> (Default: uid 1)\n");
1139 olog(" -g <group> Run as group <group> (Default: gid 1)\n");
1140 olog(" -d Do not drop privileges.\n");
1141 olog(" -a <nets> Specify home nets (eg: '192.168.0.0/25,10.0.0.0/255.0.0.0').\n");
1142 olog(" -D Daemonize.\n");
1143 //olog(" -d to logdir\n");
1144 olog(" -p <pidfile> Name of pidfile - inside chroot\n");
1145 olog(" -l <file> Log assets to <file> (default: '%s')\n", config.assetlog);
1146 olog(" -f <FIFO> Log assets to <FIFO>\n");
1147 olog(" -B Log connections to ringbuffer\n");
1148 olog(" -C <dir> Chroot into <dir> before dropping privs.\n");
1149 olog(" -XFRMSAK Flag picker: X - clear flags, F:FIN, R:RST, M:MAC, S:SYN, A:ACK, K:SYNACK\n");
1150 olog(" -UTtI Service checks: U:UDP, T:TCP-server, I:ICMP, t:TCP-cLient\n");
1151 olog(" -P DHCP fingerprinting.\n");
1152 olog(" -s <snaplen> Dump <snaplen> bytes of each payload.\n");
1153 olog(" -v Verbose output - repeat for more verbosity.\n");
1154 olog(" -q Quiet - try harder not to produce output.\n");
1155 olog(" -L <dir> log cxtracker type output to <dir>.\n");
1156 olog(" -O Connection tracking [O]utput - per-packet!\n");
1157 olog(" -x Conne[x]ion tracking output - New, expired and ended.\n");
1158 olog(" -Z Passive DNS (Experimental).\n");
1159 olog(" -H DHCP fingerprinting (Expermiental).\n");
1160 olog(" -h This help message.\n");
1163 int load_bpf(globalconfig* conf, const char* file)
1165 int sz, i;
1166 FILE* fs;
1167 char* lineptr;
1168 struct stat statbuf;
1169 fs = fopen(file, "r");
1170 if(!fs){
1171 perror("bpf file");
1172 return 1;
1174 if(fstat(fileno(fs), &statbuf)){
1175 perror("oh god my eyes!");
1176 fclose(fs);
1177 return 2;
1179 sz = statbuf.st_size;
1180 if(conf->bpff) free(conf->bpff);
1181 if(!(conf->bpff = calloc(sz, 1))){
1182 perror("mem alloc");
1183 fclose(fs);
1184 return 3;
1186 lineptr = conf->bpff;
1187 // read file but ignore comments and newlines
1188 while(fgets(lineptr, sz-(conf->bpff-lineptr), fs)) {
1189 // skip spaces
1190 for(i=0;;i++)
1191 if(lineptr[i] != ' ')
1192 break;
1193 // scan ahead and kill comments
1194 for(i=0;lineptr[i];i++)
1195 switch(lineptr[i]){
1196 case '#': // comment on the line
1197 lineptr[i] = '\n'; // end line here
1198 lineptr[i+1] = '\0'; // ends outer loop & string
1199 case '\n': // end-of-line
1200 case '\0': // end-of-string
1201 break;
1203 if(i<=1) continue; // empty line
1204 lineptr = lineptr+strlen(lineptr);
1206 fclose(fs);
1207 olog("[*] BPF file\t\t %s (%d bytes read)\n", conf->bpf_file, sz);
1208 if(config.verbose) olog("BPF: { %s}\n", conf->bpff);
1209 return 0;
1213 int prads_initialize(globalconfig *conf)
1215 if (conf->bpf_file) {
1216 if(load_bpf(conf, conf->bpf_file)){
1217 elog("[!] Failed to load bpf from file.\n");
1220 if (conf->pcap_file) {
1221 struct stat sb;
1222 if(stat(conf->pcap_file, &sb) || !sb.st_size) {
1223 elog("[!] '%s' not a pcap. Bailing.\n", conf->pcap_file);
1224 exit(1);
1227 /* Read from PCAP file specified by '-r' switch. */
1228 olog("[*] Reading from file %s\n", conf->pcap_file);
1229 if (!(conf->handle = pcap_open_offline(conf->pcap_file, conf->errbuf))) {
1230 olog("[*] Unable to open %s. (%s)\n", conf->pcap_file, conf->errbuf);
1233 } else {
1234 int uid, gid;
1235 if(conf->drop_privs_flag) {
1236 if(getuid() != 0) {
1237 conf->drop_privs_flag = 0;
1238 elog("[!] Can't drop privileges, not root.\n");
1239 } else {
1240 /* getting numerical ids before chroot call */
1241 gid = get_gid(conf->group_name);
1242 uid = get_uid(conf->user_name, &gid);
1243 if(!gid){
1244 elog("[!] Problem finding user %s group %s\n", conf->user_name, conf->group_name);
1245 exit(ENOENT);
1247 if (gid && getuid() == 0 && initgroups(conf->user_name, gid) < 0) {
1248 elog("[!] Unable to init group names (%s/%u)\n", conf->user_name, gid);
1253 /* * look up an available device if non specified */
1254 if (conf->dev == 0x0)
1255 conf->dev = pcap_lookupdev(conf->errbuf);
1256 if (conf->dev){
1257 *conf->errbuf = 0;
1258 }else{
1259 elog("[*] Error looking up device: '%s', try setting device with -i flag.\n", conf->errbuf);
1260 exit(1);
1263 olog("[*] Device: %s\n", conf->dev);
1265 if ((conf->handle = pcap_open_live(conf->dev, SNAPLENGTH, 1, 500, conf->errbuf)) == NULL) {
1266 elog("[!] Error pcap_open_live: %s \n", conf->errbuf);
1267 exit(1);
1269 /* * B0rk if we see an error... */
1270 if (strlen(conf->errbuf) > 0) {
1271 elog("[*] Error errbuf: %s \n", conf->errbuf);
1272 exit(1);
1275 if(conf->chroot_dir){
1277 olog("[*] Chrooting to dir '%s'..\n", conf->chroot_dir);
1278 if(set_chroot()){
1279 elog("[!] failed to chroot\n");
1280 exit(1);
1283 /* gotta create/chown pidfile before dropping privs */
1284 if(conf->pidfile)
1285 touch_pid_file(conf->pidfile, uid, gid);
1287 if (conf->drop_privs_flag && ( uid || gid)) {
1288 olog("[*] Dropping privileges to %s:%s...\n",
1289 conf->user_name?conf->user_name:"", conf->group_name?conf->group_name:"");
1290 drop_privs(uid, gid);
1293 if(conf->pidfile){
1294 if (!is_valid_path(conf->pidfile)){
1295 elog("[!] Pidfile '%s' is not writable.\n", conf->pidfile);
1296 exit(ENOENT);
1299 if (conf->daemon_flag) {
1300 olog("[*] Daemonizing...\n");
1301 daemonize(NULL);
1303 if (conf->pidfile) {
1304 int rc;
1305 if((rc=create_pid_file(conf->pidfile))) {
1306 elog("[!] pidfile error, wrong permissions or prads already running? %s: %s\n", conf->pidfile, strerror(rc));
1307 exit(ENOENT);
1311 return 0;
1314 void prads_version(void)
1316 olog("[*] prads %s\n", VERSION);
1317 olog(" Using %s\n", pcap_lib_version());
1318 olog(" Using PCRE version %s\n", pcre_version());
1321 /* magic main */
1322 int main(int argc, char *argv[])
1324 int32_t rc = 0;
1325 int ch = 0, verbose_already = 0;
1327 vlog(2, "%08x =? %08x, endianness: %s\n\n", 0xdeadbeef, ntohl(0xdeadbeef), (0xdead == ntohs(0xdead)?"big":"little") );
1329 memset(&config, 0, sizeof(globalconfig));
1330 set_default_config_options(&config);
1332 inpacket = gameover = intr_flag = 0;
1334 signal(SIGTERM, game_over);
1335 signal(SIGINT, game_over);
1336 signal(SIGQUIT, game_over);
1337 signal(SIGALRM, set_end_sessions);
1338 signal(SIGHUP, reparse_conf);
1339 signal(SIGUSR1, set_end_sessions);
1340 #ifdef DEBUG
1341 signal(SIGUSR1, cxt_log_buckets);
1342 #endif
1344 // do first-pass args parse for commandline-passed config file
1345 opterr = 0;
1346 while ((ch = getopt(argc, argv, ARGS)) != -1)
1347 switch (ch) {
1348 case 'c':
1349 config.file = optarg;
1350 break;
1351 case 'v':
1352 config.verbose++;
1353 break;
1354 case 'q':
1355 config.cflags |= CONFIG_QUIET;
1356 break;
1357 case 'h':
1358 usage();
1359 exit(0);
1360 default:
1361 break;
1364 if(config.verbose)
1365 verbose_already = 1;
1367 parse_config_file(config.file);
1369 // reset verbosity before 2nd coming, but only if set on cli
1370 if(verbose_already)
1371 config.verbose = 0;
1372 optind = 1;
1373 prads_version();
1375 if(parse_args(&config, argc, argv, ARGS) != 0){
1376 usage();
1377 exit(0);
1380 // we're done parsing configs - now initialize prads
1382 if(ISSET_CONFIG_SYSLOG(config)) {
1383 openlog("prads", LOG_PID | LOG_CONS, LOG_DAEMON);
1386 if(config.cxtlogdir){
1387 static char log_prefix[PATH_MAX];
1388 snprintf(log_prefix, PATH_MAX, "%sstats.%s",
1389 config.cxtlogdir, config.dev? config.dev : "pcap");
1390 rc = init_logging(LOG_SGUIL, log_prefix, 0);
1391 if (rc)
1392 perror("Logging to sguil output failed!");
1395 if (config.ringbuffer) {
1396 rc = init_logging(LOG_RINGBUFFER, NULL, config.cflags);
1397 if (rc)
1398 perror("Logging to ringbuffer failed!");
1401 if (config.cflags & (CONFIG_VERBOSE | CONFIG_CXWRITE | CONFIG_CONNECT)) {
1402 rc = init_logging(LOG_STDOUT, NULL, config.cflags);
1403 if(rc) perror("Logging to standard out failed!");
1406 if(config.assetlog) {
1407 olog("logging to file '%s'\n", config.assetlog);
1408 rc = init_logging(LOG_FILE, config.assetlog, config.cflags);
1409 if(rc) perror("Logging to file failed!");
1411 if(config.fifo) {
1412 olog("logging to FIFO '%s'\n", config.fifo);
1413 rc = init_logging(LOG_FIFO, config.fifo, config.cflags);
1414 if(rc) perror("Logging to fifo failed!");
1416 if(config.s_net){
1417 parse_nets(config.s_net, network);
1419 olog("[*] Loading fingerprints:\n");
1420 /* helper macro to avoid duplicate code */
1421 #define load_foo(func, conf, flag, file, hash, len, dump) \
1422 if(config. conf & flag) { \
1423 int _rc; \
1424 olog(" %-11s %s\n", # flag, (config. file)); \
1425 _rc = func (config. file, & config. hash, config. len); \
1426 if(_rc) perror( #flag " load failed!"); \
1427 else if(config.verbose > 1) { \
1428 printf("[*] Dumping " #flag " signatures:\n"); \
1429 dump (config. hash, config. len); \
1430 printf("[*] " #flag " signature dump ends.\n"); \
1434 load_foo(load_mac , cof, CS_MAC, sig_file_mac, sig_mac, mac_hashsize, dump_macs);
1435 load_foo(load_sigs, ctf, CO_SYN, sig_file_syn, sig_syn, sig_hashsize, dump_sigs);
1436 load_foo(load_sigs, ctf, CO_SYNACK, sig_file_synack, sig_synack, sig_hashsize, dump_sigs);
1437 load_foo(load_sigs, ctf, CO_ACK, sig_file_ack, sig_ack, sig_hashsize, dump_sigs);
1438 load_foo(load_sigs, ctf, CO_FIN, sig_file_fin, sig_fin, sig_hashsize, dump_sigs);
1439 load_foo(load_sigs, ctf, CO_RST, sig_file_rst, sig_rst, sig_hashsize, dump_sigs);
1440 load_foo(load_dhcp_sigs, ctf, CO_DHCP, sig_file_dhcp, sig_dhcp, sig_hashsize, dump_dhcp_sigs);
1441 load_foo(load_servicefp_file, cof, CS_TCP_SERVER, sig_file_serv_tcp, sig_serv_tcp, sig_hashsize, dump_sig_service);
1442 load_foo(load_servicefp_file, cof, CS_UDP_SERVICES, sig_file_serv_udp, sig_serv_udp, sig_hashsize, dump_sig_service);
1443 load_foo(load_servicefp_file, cof, CS_TCP_CLIENT, sig_file_cli_tcp, sig_client_tcp, sig_hashsize, dump_sig_service);
1444 init_services();
1446 display_config(&config);
1448 prads_initialize(&config);
1450 alarm(SIG_ALRM);
1452 /** segfaults on empty pcap! */
1453 struct bpf_program cfilter; /**/
1454 if ((pcap_compile(config.handle, &cfilter, config.bpff, 1, config.net_mask)) == -1) {
1455 olog("[*] Error pcap_compile user_filter: %s\n", pcap_geterr(config.handle));
1456 exit(1);
1459 if (pcap_setfilter(config.handle, &cfilter)) {
1460 olog("[*] Unable to set pcap filter! %s", pcap_geterr(config.handle));
1462 pcap_freecode(&cfilter);
1464 cxt_init();
1465 olog("[*] Sniffing...\n");
1466 pcap_loop(config.handle, -1, got_packet, NULL);
1468 game_over();
1469 return (0);