2 ** This file is a part of PRADS.
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>
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 *********************************************************/
26 #include <sys/malloc.h>
37 #include "ipfp/ipfp.h"
38 #include "servicefp/servicefp.h"
40 #include "util-cxt-queue.h"
45 //#include "output-plugins/log_init.h"
46 #include "output-plugins/log.h"
49 #define CONFDIR "/etc/prads/"
52 /* G L O B A L S *** (or candidates for refactoring, as we say)***********/
55 servicelist
*services
[MAX_PORTS
];
56 int inpacket
, gameover
, intr_flag
;
59 fmask network
[MAX_NETS
];
61 // static strings for comparison
62 // - this is lame and should be a flag!
63 struct tagbstring tUNKNOWN
= bsStatic("unknown");
64 bstring UNKNOWN
= & tUNKNOWN
;
66 /* I N T E R N A L P R O T O T Y P E S ***********************************/
68 void check_vlan (packetinfo
*pi
);
69 void prepare_eth (packetinfo
*pi
);
70 void prepare_ip4 (packetinfo
*pi
);
71 void prepare_ip4ip (packetinfo
*pi
);
72 void prepare_ip6 (packetinfo
*pi
);
73 void prepare_ip6ip (packetinfo
*pi
);
74 void prepare_tcp (packetinfo
*pi
);
75 void prepare_udp (packetinfo
*pi
);
76 void prepare_icmp (packetinfo
*pi
);
77 void prepare_gre (packetinfo
*pi
);
78 void prepare_greip (packetinfo
*pi
);
79 void prepare_other (packetinfo
*pi
);
80 void parse_eth (packetinfo
*pi
);
81 void parse_ip4 (packetinfo
*pi
);
82 void parse_ip6 (packetinfo
*pi
);
83 void parse_tcp (packetinfo
*pi
);
84 void parse_udp (packetinfo
*pi
);
85 void parse_icmp (packetinfo
*pi
);
86 void parse_gre (packetinfo
*pi
);
87 void parse_other (packetinfo
*pi
);
88 void parse_arp (packetinfo
*pi
);
89 int parse_network (char *net_s
, struct in6_addr
*network
);
90 int parse_netmask (char *f
, int type
, struct in6_addr
*netmask
);
91 void parse_nets(const char *s_net
, fmask
*network
);
93 void udp_guess_direction(packetinfo
*pi
);
94 void set_pkt_end_ptr (packetinfo
*pi
);
95 inline int filter_packet(const int af
, void *ip
);
97 /* F U N C T I O N S ********************************************************/
99 void got_packet(u_char
* useless
, const struct pcap_pkthdr
*pheader
,
100 const u_char
* packet
)
102 config
.pr_s
.got_packets
++;
103 packetinfo pstruct
= {0};
104 packetinfo
*pi
= &pstruct
;
105 // memset(&pi, 0, sizeof(packetinfo));
106 //pi = (packetinfo *) calloc(1, sizeof(packetinfo));
109 pi
->pheader
= pheader
;
110 set_pkt_end_ptr (pi
);
111 tstamp
= pi
->pheader
->ts
.tv_sec
; // Global
112 if (intr_flag
!= 0) {
120 if (pi
->eth_type
== ETHERNET_TYPE_IP
) {
124 } else if (pi
->eth_type
== ETHERNET_TYPE_IPV6
) {
128 } else if (pi
->eth_type
== ETHERNET_TYPE_ARP
) {
132 config
.pr_s
.otherl_recv
++;
133 vlog(0x3, "[*] ETHERNET TYPE : %x\n",pi
->eth_hdr
->eth_ip_type
);
136 if (!pi
->our
) vlog(0x3, "Not our network packet. Tracked, but not logged.\n");
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)
155 char output
[INET_ADDRSTRLEN
+ 1];
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
)
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
);
171 if((IP4ADDR(ip
) & IP4ADDR(&network
[i
].mask
))
172 == (IP4ADDR(&network
[i
].addr
) & IP4ADDR(&network
[i
].mask
)) ){
178 dlog("%8x %8x %8x\n", IP4ADDR(ip
) & IP4ADDR(&network
[i
].mask
), IP4ADDR(&network
[i
].addr
) & IP4ADDR(&network
[i
].mask
), IP4ADDR(&network
[i
].mask
));
186 /* 32-bit comparison of ipv6 nets.
187 * can do better here by using 64-bit or SIMD instructions
190 * PS: use same code for ipv4 - 0 bytes and SIMD doesnt care*/
192 ip_vec
.ip6
= *((struct in6_addr
*)ipptr
);
193 for (i
= 0; i
< MAX_NETS
&& i
< nets
; i
++) {
194 if(network
[i
].type
!= AF_INET6
)
197 u_ntop(network
[i
].addr
, af
, output
);
198 dlog("net: %s\n", output
);
199 u_ntop(network
[i
].mask
, af
, output
);
200 dlog("mask: %s\n", output
);
201 u_ntop(ip_vec
.ip6
, af
, output
);
202 dlog("ip: %s\n", output
);
204 if (network
[i
].type
== AF_INET6
) {
206 /* apologies for the uglyness */
208 #define compare128(x,y) __builtin_ia32_pcmpeqd128((x), (y))
209 // the builtin is only available on sse2!
210 t
.v
= __builtin_ia32_pcmpeqd128(
211 ip_vec
.v
& network
[i
].mask_v
,
215 #define compare128(x,y) memcmp(&(x),&(y),16)
216 t
.v
= ip_vec
.v
& network
[i
].mask_v
;
217 // xor(a,b) == 0 iff a==b
218 if (!( (t
.i
[0] ^ network
[i
].addr64
[0]) &
219 (t
.i
[1] ^ network
[i
].addr64
[1]) ))
227 if ((ip_s
.__u6_addr
.__u6_addr32
[0] & network
[i
].mask
.__u6_addr
.__u6_addr32
[0])
228 == network
[i
].addr
.__u6_addr
.__u6_addr32
[0]
229 && (ip_s
.__u6_addr
.__u6_addr32
[1] & network
[i
].mask
.__u6_addr
.__u6_addr32
[1])
230 == network
[i
].addr
.__u6_addr
.__u6_addr32
[1]
231 && (ip_s
.__u6_addr
.__u6_addr32
[2] & network
[i
].mask
.__u6_addr
.__u6_addr32
[2])
232 == network
[i
].addr
.__u6_addr
.__u6_addr32
[2]
233 && (ip_s
.__u6_addr
.__u6_addr32
[3] & network
[i
].mask
.__u6_addr
.__u6_addr32
[3])
234 == network
[i
].addr
.__u6_addr
.__u6_addr32
[3]) {
245 "non-ip packets of type %d aren't filtered by netmask yet\n", af
);
250 inet_ntop(af
, (struct in6addr
*) ipptr
, output
, MAX_NETS
);
252 inet_ntop(af
, (uint32_t*)ipptr
, output
, MAX_NETS
);
255 vlog(0x2, "Address %s is in our network.\n", output
);
257 vlog(0x2, "Address %s is not our network.\n", output
);
263 void prepare_eth (packetinfo
*pi
)
265 if (pi
->packet
+ ETHERNET_HEADER_LEN
> pi
->end_ptr
) return;
266 config
.pr_s
.eth_recv
++;
267 pi
->eth_hdr
= (ether_header
*) (pi
->packet
);
268 pi
->eth_type
= ntohs(pi
->eth_hdr
->eth_ip_type
);
269 pi
->eth_hlen
= ETHERNET_HEADER_LEN
;
273 void parse_eth (packetinfo
*pi
)
275 if (!IS_CSSET(&config
,CS_MAC
)) return;
276 /* update_asset_arp(pi->eth_hdr->ether_src, pi);
278 uint8_t *mac = pi->eth_hdr->ether_src;
280 * XXX: how is mac matching supposed to work?
281 * answer: lookup macs on pertinent frames
282 * and hash into mac asset database
283 * mac assets are like regular assets,
284 * and contain references to other assets they involve
285 if(! pi->asset->mace)
286 mac_entry *match = match_mac(config.sig_mac, mac, 48);
290 olog("mac matched: %s\n", match->vendor);
292 // call update_asset_mac or smth?
294 //config.pr_s.eth_recv++;
300 void check_vlan (packetinfo
*pi
)
302 if (pi
->eth_type
== ETHERNET_TYPE_8021Q
) {
303 vlog(0x3, "[*] ETHERNET TYPE 8021Q\n");
304 config
.pr_s
.vlan_recv
++;
305 pi
->vlan
= pi
->eth_hdr
->eth_8_vid
;
306 pi
->eth_type
= ntohs(pi
->eth_hdr
->eth_8_ip_type
);
309 /* This is b0rked - kwy and ebf fix */
310 } else if (pi
->eth_type
==
311 (ETHERNET_TYPE_802Q1MT
| ETHERNET_TYPE_802Q1MT2
|
312 ETHERNET_TYPE_802Q1MT3
| ETHERNET_TYPE_8021AD
)) {
313 vlog(0x3, "[*] ETHERNET TYPE 802Q1MT\n");
314 pi
->mvlan
= pi
->eth_hdr
->eth_82_mvid
;
315 pi
->eth_type
= ntohs(pi
->eth_hdr
->eth_82_ip_type
);
321 void prepare_ip4 (packetinfo
*pi
)
323 config
.pr_s
.ip4_recv
++;
325 pi
->ip4
= (ip4_header
*) (pi
->packet
+ pi
->eth_hlen
);
326 pi
->packet_bytes
= (pi
->ip4
->ip_len
- (IP_HL(pi
->ip4
) * 4));
328 pi
->our
= filter_packet(pi
->af
, &PI_IP4SRC(pi
));
329 vlog(0x3, "Got %s IPv4 Packet...\n", (pi
->our
?"our":"foregin"));
333 void parse_ip4 (packetinfo
*pi
)
335 switch (pi
->ip4
->ip_p
) {
374 void prepare_gre (packetinfo
*pi
)
376 config
.pr_s
.gre_recv
++;
377 if((pi
->pheader
->caplen
- pi
->eth_hlen
) < GRE_HDR_LEN
) {
380 if (pi
->af
== AF_INET
) {
381 vlog(0x3, "[*] IPv4 PROTOCOL TYPE GRE:\n");
382 pi
->greh
= (gre_header
*) (pi
->packet
+ pi
->eth_hlen
+ (IP_HL(pi
->ip4
) * 4));
383 } else if (pi
->af
== AF_INET6
) {
384 vlog(0x3, "[*] IPv6 PROTOCOL TYPE GRE:\n");
385 pi
->greh
= (gre_header
*) (pi
->packet
+ pi
->eth_hlen
+ IP6_HEADER_LEN
);
387 pi
->proto
= IP_PROTO_GRE
;
391 void parse_gre (packetinfo
*pi
)
393 uint16_t gre_header_len
= GRE_HDR_LEN
;
394 gre_sre_header
*gsre
= NULL
;
395 uint16_t len
= (pi
->pheader
->caplen
- pi
->eth_hlen
);
399 switch (GRE_GET_VERSION(pi
->greh
))
402 /* Adjust header length based on content */
403 if (GRE_FLAG_ISSET_KY(pi
->greh
))
404 gre_header_len
+= GRE_KEY_LEN
;
405 if (GRE_FLAG_ISSET_SQ(pi
->greh
))
406 gre_header_len
+= GRE_SEQ_LEN
;
407 if (GRE_FLAG_ISSET_CHKSUM(pi
->greh
) || GRE_FLAG_ISSET_ROUTE(pi
->greh
))
408 gre_header_len
+= GRE_CHKSUM_LEN
+ GRE_OFFSET_LEN
;
409 if (gre_header_len
> len
) {
412 if (GRE_FLAG_ISSET_ROUTE(pi
->greh
))
414 gsre
= (gre_sre_header
*)(pi
->greh
+ gre_header_len
);
415 if (gsre
== NULL
) return;
418 if ((gre_header_len
+GRE_SRE_HDR_LEN
) > len
) {
421 gre_header_len
+= GRE_SRE_HDR_LEN
;
423 if (gsre
!= NULL
&& (ntohs(gsre
->af
) == 0) && (gsre
->sre_length
== 0))
426 gre_header_len
+= gsre
->sre_length
;
427 gsre
= (gre_sre_header
*)(pi
->greh
+ gre_header_len
);
435 /* GRE version 1 doenst support the fields below RFC 1701 */
436 if (GRE_FLAG_ISSET_CHKSUM(pi
->greh
)) {
439 if (GRE_FLAG_ISSET_ROUTE(pi
->greh
)) {
442 if (GRE_FLAG_ISSET_SSR(pi
->greh
)) {
445 if (GRE_FLAG_ISSET_RECUR(pi
->greh
)) {
448 if (GREV1_FLAG_ISSET_FLAGS(pi
->greh
)) {
451 if (GRE_GET_PROTO(pi
->greh
) != GRE_PROTO_PPP
) {
454 if (!(GRE_FLAG_ISSET_KY(pi
->greh
))) {
458 gre_header_len
+= GRE_KEY_LEN
;
460 /* Adjust header length based on content */
461 if (GRE_FLAG_ISSET_SQ(pi
->greh
))
462 gre_header_len
+= GRE_SEQ_LEN
;
463 if (GREV1_FLAG_ISSET_ACK(pi
->greh
))
464 gre_header_len
+= GREV1_ACK_LEN
;
465 if (gre_header_len
> len
) {
479 void prepare_ip6ip (packetinfo
*pi
)
482 memset(&pipi
, 0, sizeof(packetinfo
));
483 config
.pr_s
.ip6ip_recv
++;
484 pipi
.pheader
= pi
->pheader
;
485 pipi
.packet
= (pi
->packet
+ pi
->eth_hlen
+ IP6_HEADER_LEN
);
486 pipi
.end_ptr
= pi
->end_ptr
;
487 if (pi
->ip6
->next
== IP_PROTO_IP4
) {
498 void prepare_greip (packetinfo
*pi
)
501 memset(&pipi
, 0, sizeof(packetinfo
));
502 pipi
.pheader
= pi
->pheader
;
503 pipi
.packet
= (pi
->packet
+ pi
->eth_hlen
+ pi
->gre_hlen
);
504 pipi
.end_ptr
= pi
->end_ptr
;
505 if (GRE_GET_PROTO(pi
->greh
) == IP_PROTO_IP4
) {
509 } else if (GRE_GET_PROTO(pi
->greh
) == IP_PROTO_IP6
) {
514 /* Not more implemented atm */
515 vlog(0x3, "[*] - NOT CHECKING GRE PACKAGE TYPE Other\n");
520 void prepare_ip4ip (packetinfo
*pi
)
523 memset(&pipi
, 0, sizeof(packetinfo
));
524 config
.pr_s
.ip4ip_recv
++;
525 pipi
.pheader
= pi
->pheader
;
526 pipi
.packet
= (pi
->packet
+ pi
->eth_hlen
+ (IP_HL(pi
->ip4
) * 4));
527 pipi
.end_ptr
= pi
->end_ptr
;
528 if (pi
->ip4
->ip_p
== IP_PROTO_IP4
) {
539 void prepare_ip6 (packetinfo
*pi
)
541 config
.pr_s
.ip6_recv
++;
543 pi
->ip6
= (ip6_header
*) (pi
->packet
+ pi
->eth_hlen
);
544 pi
->packet_bytes
= pi
->ip6
->len
;
545 // may be dropped due to macros plus
546 //pi->ip_src = PI_IP6SRC(pi);
547 //pi->ip_dst = PI_IP6DST(pi);
548 pi
->our
= filter_packet(pi
->af
, &PI_IP6SRC(pi
));
549 vlog(0x3, "Got %s IPv6 Packet...\n", (pi
->our
?"our":"foregin"));
553 void parse_ip6 (packetinfo
*pi
)
555 switch (pi
->ip6
->next
) {
585 * olog("[*] - CHECKING OTHER PACKAGE\n");
586 * update_asset(AF_INET6,ip6->ip_src);
587 * service_other(*pi->ip4,*tcph)
588 * fp_other(ip, ttl, ipopts, len, id, ipflags, df);
590 * olog("[*] - NOT CHECKING OTHER PACKAGE\n");
598 void parse_arp (packetinfo
*pi
)
600 vlog(0x3, "[*] Got ARP packet...\n");
601 config
.pr_s
.arp_recv
++;
602 if (!IS_CSSET(&config
,CS_ARP
)) return;
604 pi
->arph
= (ether_arp
*) (pi
->packet
+ pi
->eth_hlen
);
606 if (ntohs(pi
->arph
->ea_hdr
.ar_op
) == ARPOP_REPLY
) {
607 if (filter_packet(pi
->af
, &pi
->arph
->arp_spa
)) {
608 update_asset_arp(pi
->arph
->arp_sha
, pi
);
610 /* arp_check(eth_hdr,pi->pheader->ts.tv_sec); */
612 vlog(0x3, "[*] ARP TYPE: %d\n",ntohs(pi
->arph
->ea_hdr
.ar_op
));
616 void set_pkt_end_ptr (packetinfo
*pi
)
619 if (pi
->pheader
->len
<= SNAPLENGTH
) {
620 pi
->end_ptr
= (pi
->packet
+ pi
->pheader
->len
);
622 pi
->end_ptr
= (pi
->packet
+ SNAPLENGTH
);
627 void prepare_tcp (packetinfo
*pi
)
629 config
.pr_s
.tcp_recv
++;
630 if (pi
->af
==AF_INET
) {
631 vlog(0x3, "[*] IPv4 PROTOCOL TYPE TCP:\n");
632 pi
->tcph
= (tcp_header
*) (pi
->packet
+ pi
->eth_hlen
+ (IP_HL(pi
->ip4
) * 4));
633 pi
->plen
= (pi
->pheader
->caplen
- (TCP_OFFSET(pi
->tcph
)) * 4 - (IP_HL(pi
->ip4
) * 4) - pi
->eth_hlen
);
634 pi
->payload
= (pi
->packet
+ pi
->eth_hlen
+ (IP_HL(pi
->ip4
) * 4) + (TCP_OFFSET(pi
->tcph
) * 4));
635 } else if (pi
->af
==AF_INET6
) {
636 vlog(0x3, "[*] IPv6 PROTOCOL TYPE TCP:\n");
637 pi
->tcph
= (tcp_header
*) (pi
->packet
+ pi
->eth_hlen
+ IP6_HEADER_LEN
);
638 pi
->plen
= (pi
->pheader
->caplen
- (TCP_OFFSET(pi
->tcph
)) * 4 - IP6_HEADER_LEN
- pi
->eth_hlen
);
639 pi
->payload
= (pi
->packet
+ pi
->eth_hlen
+ IP6_HEADER_LEN
+ (TCP_OFFSET(pi
->tcph
)*4));
641 pi
->proto
= IP_PROTO_TCP
;
642 pi
->s_port
= pi
->tcph
->src_port
;
643 pi
->d_port
= pi
->tcph
->dst_port
;
644 connection_tracking(pi
);
645 //cx_track_simd_ipv4(pi);
647 dump_payload(pi
->payload
, (config
.payload
< pi
->plen
)?config
.payload
:pi
->plen
);
651 void parse_tcp (packetinfo
*pi
)
655 if (TCP_ISFLAGSET(pi
->tcph
, (TF_SYN
))) {
656 if (!TCP_ISFLAGSET(pi
->tcph
, (TF_ACK
))) {
657 if (IS_COSET(&config
,CO_SYN
)) {
658 vlog(0x3, "[*] - Got a SYN from a CLIENT: dst_port:%d\n",ntohs(pi
->tcph
->dst_port
));
663 if (IS_COSET(&config
,CO_SYNACK
)) {
664 vlog(0x3, "[*] Got a SYNACK from a SERVER: src_port:%d\n", ntohs(pi
->tcph
->src_port
));
665 fp_tcp(pi
, CO_SYNACK
);
666 if (pi
->sc
!= SC_SERVER
)
673 // Check payload for known magic bytes that defines files!
675 if (pi
->sc
== SC_CLIENT
&& !ISSET_CXT_DONT_CHECK_CLIENT(pi
)) {
676 if (IS_CSSET(&config
,CS_TCP_CLIENT
)
677 && !ISSET_DONT_CHECK_CLIENT(pi
)) {
678 if (pi
->af
== AF_INET
)
679 client_tcp4(pi
, config
.sig_client_tcp
);
681 client_tcp6(pi
, config
.sig_client_tcp
);
685 } else if (pi
->sc
== SC_SERVER
&& !ISSET_CXT_DONT_CHECK_SERVER(pi
)) {
686 if (IS_CSSET(&config
,CS_TCP_SERVER
)
687 && !ISSET_DONT_CHECK_SERVICE(pi
)) {
688 if (pi
->af
== AF_INET
)
689 service_tcp4(pi
, config
.sig_serv_tcp
);
691 service_tcp6(pi
, config
.sig_serv_tcp
);
695 vlog(0x3, "[*] - NOT CHECKING TCP PACKAGE\n");
699 if (IS_COSET(&config
,CO_ACK
)
700 && TCP_ISFLAGSET(pi
->tcph
, (TF_ACK
))
701 && !TCP_ISFLAGSET(pi
->tcph
, (TF_SYN
))
702 && !TCP_ISFLAGSET(pi
->tcph
, (TF_RST
))
703 && !TCP_ISFLAGSET(pi
->tcph
, (TF_FIN
))) {
704 vlog(0x3, "[*] Got a STRAY-ACK: src_port:%d\n",ntohs(pi
->tcph
->src_port
));
707 } else if (IS_COSET(&config
,CO_FIN
) && TCP_ISFLAGSET(pi
->tcph
, (TF_FIN
))) {
708 vlog(0x3, "[*] Got a FIN: src_port:%d\n",ntohs(pi
->tcph
->src_port
));
711 } else if (IS_COSET(&config
,CO_RST
) && TCP_ISFLAGSET(pi
->tcph
, (TF_RST
))) {
712 vlog(0x3, "[*] Got a RST: src_port:%d\n",ntohs(pi
->tcph
->src_port
));
718 void prepare_udp (packetinfo
*pi
)
720 config
.pr_s
.udp_recv
++;
721 if (pi
->af
==AF_INET
) {
722 vlog(0x3, "[*] IPv4 PROTOCOL TYPE UDP:\n");
723 pi
->udph
= (udp_header
*) (pi
->packet
+ pi
->eth_hlen
+ (IP_HL(pi
->ip4
) * 4));
724 pi
->plen
= pi
->pheader
->caplen
- UDP_HEADER_LEN
-
725 (IP_HL(pi
->ip4
) * 4) - pi
->eth_hlen
;
726 pi
->payload
= (pi
->packet
+ pi
->eth_hlen
+
727 (IP_HL(pi
->ip4
) * 4) + UDP_HEADER_LEN
);
729 } else if (pi
->af
==AF_INET6
) {
730 vlog(0x3, "[*] IPv6 PROTOCOL TYPE UDP:\n");
731 pi
->udph
= (udp_header
*) (pi
->packet
+ pi
->eth_hlen
+ + IP6_HEADER_LEN
);
732 pi
->plen
= pi
->pheader
->caplen
- UDP_HEADER_LEN
-
733 IP6_HEADER_LEN
- pi
->eth_hlen
;
734 pi
->payload
= (pi
->packet
+ pi
->eth_hlen
+
735 IP6_HEADER_LEN
+ UDP_HEADER_LEN
);
737 pi
->proto
= IP_PROTO_UDP
;
738 pi
->s_port
= pi
->udph
->src_port
;
739 pi
->d_port
= pi
->udph
->dst_port
;
740 connection_tracking(pi
);
741 //cx_track_simd_ipv4(pi);
743 dump_payload(pi
->payload
, (config
.payload
< pi
->plen
)?config
.payload
:pi
->plen
);
747 void parse_udp (packetinfo
*pi
)
750 //if (is_set_guess_upd_direction(config)) {
751 udp_guess_direction(pi
); // fix DNS server transfers?
752 // Check for Passive DNS
753 static char ip_addr_s
[INET6_ADDRSTRLEN
];
754 u_ntop_src(pi
, ip_addr_s
);
755 if ( ntohs(pi
->s_port
) == 53 ) {
756 // For now - Proof of Concept! - Fix output way
757 if(config
.cflags
& CONFIG_PDNS
)
758 dump_dns(pi
->payload
, pi
->plen
, stdout
, "\n", ip_addr_s
, pi
->pheader
->ts
.tv_sec
);
760 // if (IS_COSET(&config,CO_DNS) && (pi->sc == SC_SERVER && ntohs(pi->s_port) == 53)) passive_dns (pi);
762 if (IS_CSSET(&config
,CS_UDP_SERVICES
)) {
763 if (pi
->af
== AF_INET
) {
765 if (!ISSET_DONT_CHECK_SERVICE(pi
)||!ISSET_DONT_CHECK_CLIENT(pi
)) {
766 // Check for UDP SERVICE
767 service_udp4(pi
, config
.sig_serv_udp
);
769 // UPD Fingerprinting
770 if (IS_COSET(&config
,CO_UDP
)) fp_udp4(pi
, pi
->ip4
, pi
->udph
, pi
->end_ptr
);
771 } else if (pi
->af
== AF_INET6
) {
772 if (!ISSET_DONT_CHECK_SERVICE(pi
)||!ISSET_DONT_CHECK_CLIENT(pi
)) {
773 service_udp6(pi
, config
.sig_client_udp
);
775 /* fp_udp(ip6, ttl, ipopts, len, id, ipflags, df); */
779 vlog(0x3, "[*] - NOT CHECKING UDP PACKAGE\n");
784 void prepare_icmp (packetinfo
*pi
)
786 config
.pr_s
.icmp_recv
++;
787 if (pi
->af
==AF_INET
) {
788 vlog(0x3, "[*] IPv4 PROTOCOL TYPE ICMP:\n");
789 pi
->icmph
= (icmp_header
*) (pi
->packet
+ pi
->eth_hlen
+ (IP_HL(pi
->ip4
) * 4));
790 pi
->proto
= IP_PROTO_ICMP
;
792 } else if (pi
->af
==AF_INET6
) {
793 vlog(0x3, "[*] IPv6 PROTOCOL TYPE ICMP:\n");
794 pi
->icmp6h
= (icmp6_header
*) (pi
->packet
+ pi
->eth_hlen
+ IP6_HEADER_LEN
);
795 pi
->proto
= IP6_PROTO_ICMP
;
800 * DO change ip6->hop_lmt to 0 or something
802 connection_tracking(pi
);
806 void parse_icmp (packetinfo
*pi
)
810 if (IS_COSET(&config
,CO_ICMP
)) {
811 if (pi
->cxt
->check
== 0x00) {
812 pi
->cxt
->check
= 0x10; //for now - stop icmp fp quick
813 if (pi
->af
==AF_INET
) {
814 fp_icmp4(pi
, pi
->ip4
, pi
->icmph
, pi
->end_ptr
);
815 // could look for icmp spesific data in package abcde...
816 // service_icmp(*pi->ip4,*tcph
817 } else if (pi
->af
==AF_INET6
) {
819 fp_icmp6(pi
, pi
->ip6
, pi
->icmp6h
, pi
->end_ptr
);
822 vlog(0x3, "[*] - NOT CHECKING ICMP PACKAGE\n");
827 void prepare_other (packetinfo
*pi
)
829 config
.pr_s
.othert_recv
++;
830 if (pi
->af
==AF_INET
) {
831 vlog(0x3, "[*] IPv4 PROTOCOL TYPE OTHER: %d\n",pi
->ip4
->ip_p
);
833 } else if (pi
->af
==AF_INET6
) {
834 vlog(0x3, "[*] IPv6 PROTOCOL TYPE OTHER: %d\n",pi
->ip6
->next
);
839 connection_tracking(pi
);
843 void parse_other (packetinfo
*pi
)
847 if (pi
->cxt
->check
== 0x00) {
848 if (IS_COSET(&config
,CO_OTHER
)) {
849 pi
->cxt
->check
= 0x01; // no more checks
850 // service_other(*pi->ip4,*transporth);
851 // fp_other(pi->ipX, ttl, ipopts, len, id, ipflags, df);
853 vlog(0x3, "[*] - NOT CHECKING *OTHER* PACKAGE\n");
858 void udp_guess_direction(packetinfo
*pi
)
860 /* Stupid hack :( for DNS/port 53 */
861 if (ntohs(pi
->d_port
) == 53) {
862 if (pi
->sc
== SC_CLIENT
) return;
863 else pi
->sc
= SC_CLIENT
;
865 } else if (ntohs(pi
->s_port
) == 53) {
866 if (pi
->sc
== SC_SERVER
) return;
867 else pi
->sc
= SC_SERVER
;
871 int parse_network (char *net_s
, struct in6_addr
*network
)
875 if (NULL
!= (t
= strchr(net_s
, ':'))) {
877 if (!inet_pton(type
, net_s
, network
)) {
878 perror("parse_nets6");
881 dlog("Network6 %-36s \t -> %08x:%08x:%08x:%08x\n",
887 if (!inet_pton(type
, net_s
, &IP4ADDR(network
))) {
888 perror("parse_nets");
891 dlog("Network4 %16s \t-> 0x%08x\n", net_s
, IP4ADDR(network
));
896 int parse_netmask (char *f
, int type
, struct in6_addr
*netmask
)
900 char output
[MAX_NETS
];
901 // parse netmask into host order
902 if (type
== AF_INET
&& (t
= strchr(f
, '.')) > f
&& t
-f
< 4) {
903 // full ipv4 netmask : dotted quads
904 inet_pton(type
, f
, &IP4ADDR(netmask
));
905 dlog("mask 4 %s \t-> 0x%08x\n", f
, IP4ADDR(netmask
));
906 } else if (type
== AF_INET6
&& NULL
!= (t
= strchr(f
, ':'))) {
907 // full ipv6 netmasÄž
908 dlog("mask 6 %s\n", f
);
909 inet_pton(type
, f
, netmask
);
912 sscanf(f
, "%u", &mask
);
913 dlog("cidr %u \t-> ", mask
);
914 if (type
== AF_INET
) {
915 uint32_t shift
= 32 - mask
;
917 IP4ADDR(netmask
) = ntohl( ((unsigned int)-1 >> shift
)<< shift
);
919 IP4ADDR(netmask
) = 0;
921 dlog("0x%08x\n", IP4ADDR(netmask
));
922 } else if (type
== AF_INET6
) {
925 memset(netmask
, 0, sizeof(struct in6_addr
));
928 netmask
->s6_addr
[j
++] = 0xff;
932 netmask
->s6_addr
[j
] = -1 << (8 - mask
);
934 inet_ntop(type
, &IP4ADDR(netmask
), output
, MAX_NETS
);
935 dlog("mask: %s\n", output
);
936 // pcap packets are in host order.
937 IP6ADDR0(netmask
) = ntohl(IP6ADDR0(netmask
));
938 IP6ADDR1(netmask
) = ntohl(IP6ADDR1(netmask
));
939 IP6ADDR2(netmask
) = ntohl(IP6ADDR2(netmask
));
940 IP6ADDR3(netmask
) = ntohl(IP6ADDR3(netmask
));
947 /* parse strings of the form ip/cidr or ip/mask like:
948 * "10.10.10.10/255.255.255.128,10.10.10.10/25" and
949 * "dead:be:eef2:1aa::b5ff:fe96:37a2/64,..."
951 * an IPv6 address is 8 x 4 hex digits. missing digits are padded with zeroes.
953 void parse_nets(const char *s_net
, fmask
*network
)
955 /* f -> for processing
959 int type
, len
, i
= 0;
960 struct in6_addr network6
, netmask6
;
962 // snet is a mutable copy of the args,freed @ nets_end
964 //snet = calloc(1, len);
965 snet
= calloc(1, (len
+ 1)); /* to have \0 too :-) */
966 strncpy(snet
, s_net
, len
);
968 while (f
&& 0 != (p
= strchr(f
, '/'))) {
969 // convert network address
971 type
= parse_network(f
, &network6
);
972 if (type
!= AF_INET
&& type
!= AF_INET6
) {
973 perror("parse_network");
982 parse_netmask(f
, type
, &netmask6
);
984 // poke in the gathered information
988 network
[i
].addr
= network6
;
989 network
[i
].mask
= netmask6
;
990 network
[i
].type
= type
;
994 fprintf(stderr
, "parse_nets: invalid address family!\n");
1001 elog("Max networks reached, stopped parsing at %d nets.\n", i
-1);
1006 // continue parsing at p, which might point to another network range
1018 if (inpacket
== 0) {
1019 end_sessions(); /* Need to have correct human output when reading -r pcap */
1020 //cxt_write_all(); /* redundant ? see end_all_sessions(); */
1023 del_known_services();
1024 del_signature_lists();
1027 if(!ISSET_CONFIG_QUIET(config
)){
1028 print_prads_stats();
1029 if(!config
.pcap_file
)
1032 if (config
.handle
!= NULL
) pcap_close(config
.handle
);
1034 olog("\n[*] prads ended.\n");
1040 void check_interrupt()
1043 if (intr_flag
== 1) {
1045 } else if (intr_flag
== 2) {
1046 update_asset_list();
1047 } else if (intr_flag
== 3) {
1054 void set_end_sessions()
1058 if (inpacket
== 0) {
1059 tstamp
= time(NULL
);
1061 /* if no cxtracking is turned on - dont log to disk */
1062 /* if (log_cxt == 1) log_expired_cxt(); */
1063 /* if no asset detection is turned on - dont log to disk! */
1064 /* if (log_assets == 1) update_asset_list(); */
1065 update_asset_list();
1071 void print_prads_stats()
1073 extern uint64_t cxtrackerid
; // cxt.c
1074 olog("-- prads:\n");
1075 olog("-- Total packets received from libpcap :%12u\n",config
.pr_s
.got_packets
);
1076 olog("-- Total Ethernet packets received :%12u\n",config
.pr_s
.eth_recv
);
1077 olog("-- Total VLAN packets received :%12u\n",config
.pr_s
.vlan_recv
);
1078 olog("-- Total ARP packets received :%12u\n",config
.pr_s
.arp_recv
);
1079 olog("-- Total IPv4 packets received :%12u\n",config
.pr_s
.ip4_recv
);
1080 olog("-- Total IPv6 packets received :%12u\n",config
.pr_s
.ip6_recv
);
1081 olog("-- Total Other link packets received :%12u\n",config
.pr_s
.otherl_recv
);
1082 olog("-- Total IPinIPv4 packets received :%12u\n",config
.pr_s
.ip4ip_recv
);
1083 olog("-- Total IPinIPv6 packets received :%12u\n",config
.pr_s
.ip6ip_recv
);
1084 olog("-- Total GRE packets received :%12u\n",config
.pr_s
.gre_recv
);
1085 olog("-- Total TCP packets received :%12u\n",config
.pr_s
.tcp_recv
);
1086 olog("-- Total UDP packets received :%12u\n",config
.pr_s
.udp_recv
);
1087 olog("-- Total ICMP packets received :%12u\n",config
.pr_s
.icmp_recv
);
1088 olog("-- Total Other transport packets received :%12u\n",config
.pr_s
.othert_recv
);
1090 olog("-- Total sessions tracked :%12lu\n", cxtrackerid
);
1091 olog("-- Total assets detected :%12u\n",config
.pr_s
.assets
);
1092 olog("-- Total TCP OS fingerprints detected :%12u\n",config
.pr_s
.tcp_os_assets
);
1093 olog("-- Total UDP OS fingerprints detected :%12u\n",config
.pr_s
.udp_os_assets
);
1094 olog("-- Total ICMP OS fingerprints detected :%12u\n",config
.pr_s
.icmp_os_assets
);
1095 olog("-- Total DHCP OS fingerprints detected :%12u\n",config
.pr_s
.dhcp_os_assets
);
1096 olog("-- Total TCP service assets detected :%12u\n",config
.pr_s
.tcp_services
);
1097 olog("-- Total TCP client assets detected :%12u\n",config
.pr_s
.tcp_clients
);
1098 olog("-- Total UDP service assets detected :%12u\n",config
.pr_s
.udp_services
);
1099 olog("-- Total UDP client assets detected :%12u\n",config
.pr_s
.udp_clients
);
1106 olog(" $ prads [options]\n");
1108 olog(" OPTIONS:\n");
1110 olog(" -i <iface> Network device <iface> (default: eth0).\n");
1111 olog(" -r <file> Read pcap <file>.\n");
1112 olog(" -c <file> Read config from <file>\n");
1113 olog(" -b <filter> Apply Berkeley packet filter <filter>.\n");
1114 olog(" -u <user> Run as user <user>.\n");
1115 olog(" -g <group> Run as group <group>.\n");
1116 olog(" -a <nets> Specify home nets (eg: '192.168.0.0/25,10.0.0.0/255.0.0.0').\n");
1117 olog(" -D Enables daemon mode.\n");
1118 //olog(" -d to logdir\n");
1119 olog(" -p <pidfile> Name of pidfile - inside chroot\n");
1120 olog(" -l <file> Log assets to <file> (default: '%s')\n", config
.assetlog
);
1121 olog(" -f <FIFO> Log assets to <FIFO>\n");
1122 olog(" -C <dir> Chroot into <dir> before dropping privs.\n");
1123 olog(" -XFRMSAK Flag picker: X - clear flags, F:FIN, R:RST, M:MAC, S:SYN, A:ACK, K:SYNACK\n");
1124 olog(" -UTtI Service checks: U:UDP, T:TCP-server, I:ICMP, t:TCP-cLient\n");
1125 olog(" -s <snaplen> Dump <snaplen> bytes of each payload.\n");
1126 olog(" -v Verbose output - repeat for more verbosity.\n");
1127 olog(" -q Quiet - try harder not to produce output.\n");
1128 olog(" -O Connection tracking [O]utput - per-packet!\n");
1129 olog(" -x Conne[x]ion tracking output - New, expired and ended.\n");
1130 olog(" -Z Passive DNS (Experimental).\n");
1131 olog(" -h This help message.\n");
1135 extern int optind
, opterr
, optopt
; // getopt()
1138 int main(int argc
, char *argv
[])
1141 int ch
= 0, verbose_already
= 0;
1143 vlog(2, "%08x =? %08x, endianness: %s\n\n", 0xdeadbeef, ntohl(0xdeadbeef), (0xdead == ntohs(0xdead)?"big":"little") );
1145 memset(&config
, 0, sizeof(globalconfig
));
1146 set_default_config_options();
1147 bstring pconfile
= bfromcstr(CONFDIR
"prads.conf");
1148 //parse_config_file(pconfile);
1149 //bdestroy (pconfile);
1151 inpacket
= gameover
= intr_flag
= 0;
1153 signal(SIGTERM
, game_over
);
1154 signal(SIGINT
, game_over
);
1155 signal(SIGQUIT
, game_over
);
1156 signal(SIGALRM
, set_end_sessions
);
1157 //signal(SIGALRM, game_over); // Use this to debug segfault when exiting
1159 // do first-pass args parse for commandline-passed config file
1161 #define ARGS "C:c:b:d:Dg:hi:p:r:P:u:va:l:f:qtxs:OXFRMSAKUTIZt"
1162 while ((ch
= getopt(argc
, argv
, ARGS
)) != -1)
1165 pconfile
= bfromcstr(optarg
);
1178 verbose_already
= 1;
1180 parse_config_file(pconfile
);
1182 // reset verbosity before 2nd coming, but only if set on cli
1187 while ((ch
= getopt(argc
, argv
, ARGS
)) != -1)
1190 if(strlen(optarg
) == 0)
1191 config
.s_net
= DEFAULT_NETS
;
1193 config
.s_net
= strdup(optarg
);
1196 pconfile
= bfromcstr(optarg
);
1199 config
.chroot_dir
= strdup(optarg
);
1202 config
.dev
= strdup(optarg
);
1205 config
.pcap_file
= strdup(optarg
);
1208 config
.bpff
= strdup(optarg
);
1212 config
.cflags
|= CONFIG_VERBOSE
;
1215 config
.dpath
= strdup(optarg
);
1222 config
.daemon_flag
= 1;
1225 config
.user_name
= strdup(optarg
);
1226 config
.drop_privs_flag
= 1;
1229 config
.group_name
= strdup(optarg
);
1230 config
.drop_privs_flag
= 1;
1233 config
.pidfile
= strdup(optarg
);
1236 config
.assetlog
= strdup(optarg
);
1239 config
.fifo
= strdup(optarg
);
1242 config
.payload
= strtol(optarg
, NULL
, 0);
1245 config
.cflags
|= CONFIG_QUIET
;
1248 config
.cflags
|= CONFIG_CONNECT
;
1251 config
.cflags
|= CONFIG_PDNS
;
1254 config
.cflags
|= CONFIG_CXWRITE
;
1261 config
.ctf
|= CO_FIN
;
1264 config
.ctf
|= CO_RST
;
1267 config
.cof
|= CS_MAC
;
1268 config
.cof
|= CS_ARP
;
1271 config
.ctf
|= CO_SYN
;
1274 config
.ctf
|= CO_ACK
;
1277 config
.ctf
|= CO_SYNACK
;
1280 config
.cof
|= CS_UDP_SERVICES
;
1283 config
.cof
|= CS_TCP_SERVER
;
1286 config
.cof
|= CS_ICMP
;
1289 config
.cof
|= CS_TCP_CLIENT
;
1292 elog("unrecognized argument: '%c'\n", optopt
);
1295 elog("Did not recognize argument '%c'\n", ch
);
1298 bdestroy (pconfile
);
1299 // we're done parsing configs - now initialize prads
1302 rc
= init_logging(LOG_STDOUT
, NULL
, config
.verbose
);
1303 if(rc
) perror("Logging to standard out failed!");
1306 if(config
.assetlog
) {
1307 olog("logging to file '%s'\n", config
.assetlog
);
1308 rc
= init_logging(LOG_FILE
, config
.assetlog
, config
.verbose
);
1309 if(rc
) perror("Logging to file failed!");
1312 olog("logging to FIFO '%s'\n", config
.fifo
);
1313 rc
= init_logging(LOG_FIFO
, config
.fifo
, config
.verbose
);
1314 if(rc
) perror("Logging to fifo failed!");
1317 parse_nets(config
.s_net
, network
);
1319 olog("[*] Loading fingerprints:\n");
1320 /* helper macro to avoid duplicate code */
1321 #define load_foo(func, conf, flag, file, hash, len, dump) \
1322 if(config. conf & flag) { \
1324 olog(" %-11s %s\n", # flag, (config. file)); \
1325 _rc = func (config. file, & config. hash, config. len); \
1326 if(_rc) perror( #flag " load failed!"); \
1327 else if(config.verbose > 1) { \
1328 printf("[*] Dumping " #flag " signatures:\n"); \
1329 dump (config. hash, config. len); \
1330 printf("[*] " #flag " signature dump ends.\n"); \
1334 load_foo(load_mac
, cof
, CS_MAC
, sig_file_mac
, sig_mac
, mac_hashsize
, dump_macs
);
1335 load_foo(load_sigs
, ctf
, CO_SYN
, sig_file_syn
, sig_syn
, sig_hashsize
, dump_sigs
);
1336 load_foo(load_sigs
, ctf
, CO_SYNACK
, sig_file_synack
, sig_synack
, sig_hashsize
, dump_sigs
);
1337 load_foo(load_sigs
, ctf
, CO_ACK
, sig_file_ack
, sig_ack
, sig_hashsize
, dump_sigs
);
1338 load_foo(load_sigs
, ctf
, CO_FIN
, sig_file_fin
, sig_fin
, sig_hashsize
, dump_sigs
);
1339 load_foo(load_sigs
, ctf
, CO_RST
, sig_file_rst
, sig_rst
, sig_hashsize
, dump_sigs
);
1341 load_foo(load_servicefp_file
, cof
, CS_TCP_SERVER
, sig_file_serv_tcp
, sig_serv_tcp
, sig_hashsize
, dump_sig_service
);
1342 load_foo(load_servicefp_file
, cof
, CS_UDP_SERVICES
, sig_file_serv_udp
, sig_serv_udp
, sig_hashsize
, dump_sig_service
);
1343 load_foo(load_servicefp_file
, cof
, CS_TCP_CLIENT
, sig_file_cli_tcp
, sig_client_tcp
, sig_hashsize
, dump_sig_service
);
1346 olog("\n[*] Running prads %s\n", VERSION
);
1347 olog(" Using %s\n", pcap_lib_version());
1348 olog(" Using PCRE version %s\n", pcre_version());
1350 //if (config.verbose) display_config();
1353 if (config
.pcap_file
) {
1354 /* Read from PCAP file specified by '-r' switch. */
1355 olog("[*] Reading from file %s\n", config
.pcap_file
);
1356 if (!(config
.handle
= pcap_open_offline(config
.pcap_file
, config
.errbuf
))) {
1357 olog("[*] Unable to open %s. (%s)", config
.pcap_file
, config
.errbuf
);
1362 /* * look up an available device if non specified */
1363 if (config
.dev
== 0x0)
1364 config
.dev
= pcap_lookupdev(config
.errbuf
);
1365 olog("[*] Device: %s\n", config
.dev
);
1367 if ((config
.handle
= pcap_open_live(config
.dev
, SNAPLENGTH
, 1, 500, config
.errbuf
)) == NULL
) {
1368 olog("[*] Error pcap_open_live: %s \n", config
.errbuf
);
1371 /* * B0rk if we see an error... */
1372 if (strlen(config
.errbuf
) > 0) {
1373 elog("[*] Error errbuf: %s \n", config
.errbuf
);
1377 if(config
.chroot_dir
){
1378 olog("[*] Chrooting to dir '%s'..\n", config
.chroot_dir
);
1380 elog("[!] failed to chroot\n");
1385 if (config
.drop_privs_flag
) {
1386 olog("[*] Dropping privs...\n");
1390 if (config
.daemon_flag
) {
1391 if (!is_valid_path(config
.pidfile
))
1392 elog("[*] Unable to create pidfile '%s'\n", config
.pidfile
);
1393 openlog("prads", LOG_PID
| LOG_CONS
, LOG_DAEMON
);
1394 olog("[*] Daemonizing...\n\n");
1403 /** segfaults on empty pcap! */
1404 if ((pcap_compile(config
.handle
, &config
.cfilter
, config
.bpff
, 1, config
.net_mask
)) == -1) {
1405 olog("[*] Error pcap_compile user_filter: %s\n", pcap_geterr(config
.handle
));
1409 if (pcap_setfilter(config
.handle
, &config
.cfilter
)) {
1410 olog("[*] Unable to set pcap filter! %s", pcap_geterr(config
.handle
));
1414 olog("[*] Sniffing...\n\n");
1415 pcap_loop(config
.handle
, -1, got_packet
, NULL
);
1418 //pcap_close(config.handle);
1422 //void free_config()
1424 // if (config.dev != NULL) free (config.dev);
1425 // if (config.cfilter.bf_insns != NULL) free (config.cfilter.bf_insns);