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"
43 //#include "output-plugins/log_init.h"
44 #include "output-plugins/log.h"
47 #define CONFDIR "/etc/prads/"
50 /* G L O B A L S *** (or candidates for refactoring, as we say)***********/
53 servicelist
*services
[MAX_PORTS
];
54 signature
*sig_serv_tcp
= NULL
;
55 signature
*sig_serv_udp
= NULL
;
56 signature
*sig_client_tcp
= NULL
;
57 signature
*sig_client_udp
= NULL
;
58 int inpacket
, gameover
, intr_flag
;
61 struct fmask network
[MAX_NETS
];
63 // static strings for comparison
64 // - this is lame and should be a flag!
65 struct tagbstring tUNKNOWN
= bsStatic("unknown");
66 bstring UNKNOWN
= & tUNKNOWN
;
68 /* I N T E R N A L P R O T O T Y P E S ***********************************/
70 void check_vlan (packetinfo
*pi
);
71 void prepare_eth (packetinfo
*pi
);
72 void prepare_ip4 (packetinfo
*pi
);
73 void prepare_ip4ip (packetinfo
*pi
);
74 void prepare_ip6 (packetinfo
*pi
);
75 void prepare_ip6ip (packetinfo
*pi
);
76 void prepare_tcp (packetinfo
*pi
);
77 void prepare_udp (packetinfo
*pi
);
78 void prepare_icmp (packetinfo
*pi
);
79 void prepare_gre (packetinfo
*pi
);
80 void prepare_greip (packetinfo
*pi
);
81 void prepare_other (packetinfo
*pi
);
82 void parse_eth (packetinfo
*pi
);
83 void parse_ip4 (packetinfo
*pi
);
84 void parse_ip6 (packetinfo
*pi
);
85 void parse_tcp (packetinfo
*pi
);
86 void parse_udp (packetinfo
*pi
);
87 void parse_icmp (packetinfo
*pi
);
88 void parse_gre (packetinfo
*pi
);
89 void parse_other (packetinfo
*pi
);
90 void parse_arp (packetinfo
*pi
);
91 int parse_network (char *net_s
, struct in6_addr
*network
);
92 int parse_netmask (char *f
, int type
, struct in6_addr
*netmask
);
93 void parse_nets(const char *s_net
, struct fmask
*network
);
95 void udp_guess_direction(packetinfo
*pi
);
96 void set_pkt_end_ptr (packetinfo
*pi
);
97 inline int filter_packet(const int af
, void *ip
);
99 /* F U N C T I O N S ********************************************************/
101 void got_packet(u_char
* useless
, const struct pcap_pkthdr
*pheader
,
102 const u_char
* packet
)
104 config
.pr_s
.got_packets
++;
105 packetinfo pstruct
= {0};
106 packetinfo
*pi
= &pstruct
;
107 // memset(&pi, 0, sizeof(packetinfo));
108 //pi = (packetinfo *) calloc(1, sizeof(packetinfo));
111 pi
->pheader
= pheader
;
112 set_pkt_end_ptr (pi
);
113 tstamp
= pi
->pheader
->ts
.tv_sec
; // Global
114 if (intr_flag
!= 0) {
122 if (pi
->eth_type
== ETHERNET_TYPE_IP
) {
126 } else if (pi
->eth_type
== ETHERNET_TYPE_IPV6
) {
130 } else if (pi
->eth_type
== ETHERNET_TYPE_ARP
) {
134 config
.pr_s
.otherl_recv
++;
135 vlog(0x3, "[*] ETHERNET TYPE : %x\n",pi
->eth_hdr
->eth_ip_type
);
138 if (!pi
->our
) vlog(0x3, "Not our network packet. Tracked, but not logged.\n");
145 /* does this ip belong to our network? do we care about the packet?
147 * unfortunately pcap sends us packets in host order
148 * Return value: boolean
150 inline int filter_packet(const int af
, void *ipptr
)
151 //const struct in6_addr *ip_s)
157 char output
[MAX_NETS
];
161 uint32_t *ip
= (uint32_t *) ipptr
;
162 for (i
= 0; i
< MAX_NETS
&& i
< nets
; i
++) {
163 if (network
[i
].type
!= AF_INET
)
166 inet_ntop(af
, &network
[i
].addr
.__u6_addr
.__u6_addr32
[0], output
, MAX_NETS
);
167 vlog(0x2, "Filter: %s\n", output
);
168 inet_ntop(af
, &network
[i
].mask
.__u6_addr
.__u6_addr32
[0], output
, MAX_NETS
);
169 vlog(0x2, "mask: %s\n", output
);
170 inet_ntop(af
, ip
, output
, MAX_NETS
);
171 vlog(0x2, "ip: %s\n", output
);
173 if((*ip
& IP4ADDR(&network
[i
].mask
))
174 == IP4ADDR(&network
[i
].addr
)){
183 /* 32-bit comparison of ipv6 nets.
184 * can do better here by using 64-bit or SIMD instructions
187 * PS: use same code for ipv4 - 0 bytes and SIMD doesnt care*/
189 ip_vec
.ip6
= *((struct in6_addr
*)ipptr
);
190 for (i
= 0; i
< MAX_NETS
&& i
< nets
; i
++) {
191 if(network
[i
].type
!= AF_INET6
)
194 inet_ntop(af
, &network
[i
].addr
, output
, MAX_NETS
);
195 dlog("net: %s\n", output
);
196 inet_ntop(af
, &network
[i
].mask
, output
, MAX_NETS
);
197 dlog("mask: %s\n", output
);
198 inet_ntop(af
, &PI_IP6SRC(pi
), output
, MAX_NETS
);
199 dlog("ip: %s\n", output
);
201 if (network
[i
].type
== AF_INET6
) {
203 /* apologies for the uglyness */
205 #define compare128(x,y) __builtin_ia32_pcmpeqd128((x), (y))
206 // the builtin is only available on sse2!
207 t
.v
= __builtin_ia32_pcmpeqd128(
208 ip_vec
.v
& network
[i
].mask_v
,
212 #define compare128(x,y) memcmp(&(x),&(y),16)
213 t
.v
= ip_vec
.v
& network
[i
].mask_v
;
214 // xor(a,b) == 0 iff a==b
215 if (!( (t
.i
[0] ^ network
[i
].addr64
[0]) &
216 (t
.i
[1] ^ network
[i
].addr64
[1]) ))
224 if ((ip_s
.__u6_addr
.__u6_addr32
[0] & network
[i
].mask
.__u6_addr
.__u6_addr32
[0])
225 == network
[i
].addr
.__u6_addr
.__u6_addr32
[0]
226 && (ip_s
.__u6_addr
.__u6_addr32
[1] & network
[i
].mask
.__u6_addr
.__u6_addr32
[1])
227 == network
[i
].addr
.__u6_addr
.__u6_addr32
[1]
228 && (ip_s
.__u6_addr
.__u6_addr32
[2] & network
[i
].mask
.__u6_addr
.__u6_addr32
[2])
229 == network
[i
].addr
.__u6_addr
.__u6_addr32
[2]
230 && (ip_s
.__u6_addr
.__u6_addr32
[3] & network
[i
].mask
.__u6_addr
.__u6_addr32
[3])
231 == network
[i
].addr
.__u6_addr
.__u6_addr32
[3]) {
242 "non-ip packets of type %d aren't filtered by netmask yet\n", af
);
247 inet_ntop(af
, (struct in6addr
*) ipptr
, output
, MAX_NETS
);
249 inet_ntop(af
, (uint32_t*)ipptr
, output
, MAX_NETS
);
252 vlog(0x2, "Address %s is in our network.\n", output
);
254 vlog(0x2, "Address %s is not our network.\n", output
);
260 void prepare_eth (packetinfo
*pi
)
262 if (pi
->packet
+ ETHERNET_HEADER_LEN
> pi
->end_ptr
) return;
263 config
.pr_s
.eth_recv
++;
264 pi
->eth_hdr
= (ether_header
*) (pi
->packet
);
265 pi
->eth_type
= ntohs(pi
->eth_hdr
->eth_ip_type
);
266 pi
->eth_hlen
= ETHERNET_HEADER_LEN
;
270 void parse_eth (packetinfo
*pi
)
272 if (!IS_CSSET(&config
,CS_MAC
)) return;
273 /* update_asset_arp(pi->eth_hdr->ether_src, pi);
275 uint8_t *mac = pi->eth_hdr->ether_src;
277 * XXX: how is mac matching supposed to work?
278 * answer: lookup macs on pertinent frames
279 * and hash into mac asset database
280 * mac assets are like regular assets,
281 * and contain references to other assets they involve
282 if(! pi->asset->mace)
283 mac_entry *match = match_mac(config.sig_mac, mac, 48);
287 olog("mac matched: %s\n", match->vendor);
289 // call update_asset_mac or smth?
291 //config.pr_s.eth_recv++;
297 void check_vlan (packetinfo
*pi
)
299 if (pi
->eth_type
== ETHERNET_TYPE_8021Q
) {
300 vlog(0x3, "[*] ETHERNET TYPE 8021Q\n");
301 config
.pr_s
.vlan_recv
++;
302 pi
->vlan
= pi
->eth_hdr
->eth_8_vid
;
303 pi
->eth_type
= ntohs(pi
->eth_hdr
->eth_8_ip_type
);
306 /* This is b0rked - kwy and ebf fix */
307 } else if (pi
->eth_type
==
308 (ETHERNET_TYPE_802Q1MT
| ETHERNET_TYPE_802Q1MT2
|
309 ETHERNET_TYPE_802Q1MT3
| ETHERNET_TYPE_8021AD
)) {
310 vlog(0x3, "[*] ETHERNET TYPE 802Q1MT\n");
311 pi
->mvlan
= pi
->eth_hdr
->eth_82_mvid
;
312 pi
->eth_type
= ntohs(pi
->eth_hdr
->eth_82_ip_type
);
318 void prepare_ip4 (packetinfo
*pi
)
320 config
.pr_s
.ip4_recv
++;
322 pi
->ip4
= (ip4_header
*) (pi
->packet
+ pi
->eth_hlen
);
323 pi
->packet_bytes
= (pi
->ip4
->ip_len
- (IP_HL(pi
->ip4
) * 4));
325 pi
->our
= filter_packet(pi
->af
, &PI_IP4SRC(pi
));
326 vlog(0x3, "Got %s IPv4 Packet...\n", (pi
->our
?"our":"foregin"));
330 void parse_ip4 (packetinfo
*pi
)
332 switch (pi
->ip4
->ip_p
) {
371 void prepare_gre (packetinfo
*pi
)
373 config
.pr_s
.gre_recv
++;
374 if((pi
->pheader
->caplen
- pi
->eth_hlen
) < GRE_HDR_LEN
) {
377 if (pi
->af
== AF_INET
) {
378 vlog(0x3, "[*] IPv4 PROTOCOL TYPE GRE:\n");
379 pi
->greh
= (gre_header
*) (pi
->packet
+ pi
->eth_hlen
+ (IP_HL(pi
->ip4
) * 4));
380 } else if (pi
->af
== AF_INET6
) {
381 vlog(0x3, "[*] IPv6 PROTOCOL TYPE GRE:\n");
382 pi
->greh
= (gre_header
*) (pi
->packet
+ pi
->eth_hlen
+ IP6_HEADER_LEN
);
384 pi
->proto
= IP_PROTO_GRE
;
388 void parse_gre (packetinfo
*pi
)
390 uint16_t gre_header_len
= GRE_HDR_LEN
;
391 gre_sre_header
*gsre
= NULL
;
392 uint16_t len
= (pi
->pheader
->caplen
- pi
->eth_hlen
);
396 switch (GRE_GET_VERSION(pi
->greh
))
399 /* Adjust header length based on content */
400 if (GRE_FLAG_ISSET_KY(pi
->greh
))
401 gre_header_len
+= GRE_KEY_LEN
;
402 if (GRE_FLAG_ISSET_SQ(pi
->greh
))
403 gre_header_len
+= GRE_SEQ_LEN
;
404 if (GRE_FLAG_ISSET_CHKSUM(pi
->greh
) || GRE_FLAG_ISSET_ROUTE(pi
->greh
))
405 gre_header_len
+= GRE_CHKSUM_LEN
+ GRE_OFFSET_LEN
;
406 if (gre_header_len
> len
) {
409 if (GRE_FLAG_ISSET_ROUTE(pi
->greh
))
411 gsre
= (gre_sre_header
*)(pi
->greh
+ gre_header_len
);
412 if (gsre
== NULL
) return;
415 if ((gre_header_len
+GRE_SRE_HDR_LEN
) > len
) {
418 gre_header_len
+= GRE_SRE_HDR_LEN
;
420 if (gsre
!= NULL
&& (ntohs(gsre
->af
) == 0) && (gsre
->sre_length
== 0))
423 gre_header_len
+= gsre
->sre_length
;
424 gsre
= (gre_sre_header
*)(pi
->greh
+ gre_header_len
);
432 /* GRE version 1 doenst support the fields below RFC 1701 */
433 if (GRE_FLAG_ISSET_CHKSUM(pi
->greh
)) {
436 if (GRE_FLAG_ISSET_ROUTE(pi
->greh
)) {
439 if (GRE_FLAG_ISSET_SSR(pi
->greh
)) {
442 if (GRE_FLAG_ISSET_RECUR(pi
->greh
)) {
445 if (GREV1_FLAG_ISSET_FLAGS(pi
->greh
)) {
448 if (GRE_GET_PROTO(pi
->greh
) != GRE_PROTO_PPP
) {
451 if (!(GRE_FLAG_ISSET_KY(pi
->greh
))) {
455 gre_header_len
+= GRE_KEY_LEN
;
457 /* Adjust header length based on content */
458 if (GRE_FLAG_ISSET_SQ(pi
->greh
))
459 gre_header_len
+= GRE_SEQ_LEN
;
460 if (GREV1_FLAG_ISSET_ACK(pi
->greh
))
461 gre_header_len
+= GREV1_ACK_LEN
;
462 if (gre_header_len
> len
) {
476 void prepare_ip6ip (packetinfo
*pi
)
479 memset(&pipi
, 0, sizeof(packetinfo
));
480 config
.pr_s
.ip6ip_recv
++;
481 pipi
.pheader
= pi
->pheader
;
482 pipi
.packet
= (pi
->packet
+ pi
->eth_hlen
+ IP6_HEADER_LEN
);
483 pipi
.end_ptr
= pi
->end_ptr
;
484 if (pi
->ip6
->next
== IP_PROTO_IP4
) {
495 void prepare_greip (packetinfo
*pi
)
498 memset(&pipi
, 0, sizeof(packetinfo
));
499 pipi
.pheader
= pi
->pheader
;
500 pipi
.packet
= (pi
->packet
+ pi
->eth_hlen
+ pi
->gre_hlen
);
501 pipi
.end_ptr
= pi
->end_ptr
;
502 if (GRE_GET_PROTO(pi
->greh
) == IP_PROTO_IP4
) {
506 } else if (GRE_GET_PROTO(pi
->greh
) == IP_PROTO_IP6
) {
511 /* Not more implemented atm */
512 vlog(0x3, "[*] - NOT CHECKING GRE PACKAGE TYPE Other\n");
516 void prepare_ip4ip (packetinfo
*pi
)
519 memset(&pipi
, 0, sizeof(packetinfo
));
520 config
.pr_s
.ip4ip_recv
++;
521 pipi
.pheader
= pi
->pheader
;
522 pipi
.packet
= (pi
->packet
+ pi
->eth_hlen
+ (IP_HL(pi
->ip4
) * 4));
523 pipi
.end_ptr
= pi
->end_ptr
;
524 if (pi
->ip4
->ip_p
== IP_PROTO_IP4
) {
535 void prepare_ip6 (packetinfo
*pi
)
537 config
.pr_s
.ip6_recv
++;
539 pi
->ip6
= (ip6_header
*) (pi
->packet
+ pi
->eth_hlen
);
540 pi
->packet_bytes
= pi
->ip6
->len
;
541 // may be dropped due to macros plus
542 //pi->ip_src = PI_IP6SRC(pi);
543 //pi->ip_dst = PI_IP6DST(pi);
544 pi
->our
= filter_packet(pi
->af
, &PI_IP6SRC(pi
));
545 vlog(0x3, "Got %s IPv6 Packet...\n", (pi
->our
?"our":"foregin"));
549 void parse_ip6 (packetinfo
*pi
)
551 switch (pi
->ip6
->next
) {
581 * olog("[*] - CHECKING OTHER PACKAGE\n");
582 * update_asset(AF_INET6,ip6->ip_src);
583 * service_other(*pi->ip4,*tcph)
584 * fp_other(ip, ttl, ipopts, len, id, ipflags, df);
586 * olog("[*] - NOT CHECKING OTHER PACKAGE\n");
594 void parse_arp (packetinfo
*pi
)
596 vlog(0x3, "[*] Got ARP packet...\n");
597 config
.pr_s
.arp_recv
++;
598 if (!IS_CSSET(&config
,CS_ARP
)) return;
600 pi
->arph
= (ether_arp
*) (pi
->packet
+ pi
->eth_hlen
);
602 if (ntohs(pi
->arph
->ea_hdr
.ar_op
) == ARPOP_REPLY
) {
603 if (filter_packet(pi
->af
, &pi
->arph
->arp_spa
)) {
604 update_asset_arp(pi
->arph
->arp_sha
, pi
);
606 /* arp_check(eth_hdr,pi->pheader->ts.tv_sec); */
608 vlog(0x3, "[*] ARP TYPE: %d\n",ntohs(pi
->arph
->ea_hdr
.ar_op
));
612 void set_pkt_end_ptr (packetinfo
*pi
)
615 if (pi
->pheader
->len
<= SNAPLENGTH
) {
616 pi
->end_ptr
= (pi
->packet
+ pi
->pheader
->len
);
618 pi
->end_ptr
= (pi
->packet
+ SNAPLENGTH
);
623 void prepare_tcp (packetinfo
*pi
)
625 config
.pr_s
.tcp_recv
++;
626 if (pi
->af
==AF_INET
) {
627 vlog(0x3, "[*] IPv4 PROTOCOL TYPE TCP:\n");
628 pi
->tcph
= (tcp_header
*) (pi
->packet
+ pi
->eth_hlen
+ (IP_HL(pi
->ip4
) * 4));
629 pi
->plen
= (pi
->pheader
->caplen
- (TCP_OFFSET(pi
->tcph
)) * 4 - (IP_HL(pi
->ip4
) * 4) - pi
->eth_hlen
);
630 pi
->payload
= (char *)(pi
->packet
+ pi
->eth_hlen
+ (IP_HL(pi
->ip4
) * 4) + (TCP_OFFSET(pi
->tcph
) * 4));
631 } else if (pi
->af
==AF_INET6
) {
632 vlog(0x3, "[*] IPv6 PROTOCOL TYPE TCP:\n");
633 pi
->tcph
= (tcp_header
*) (pi
->packet
+ pi
->eth_hlen
+ IP6_HEADER_LEN
);
634 pi
->plen
= (pi
->pheader
->caplen
- (TCP_OFFSET(pi
->tcph
)) * 4 - IP6_HEADER_LEN
- pi
->eth_hlen
);
635 pi
->payload
= (char *)(pi
->packet
+ pi
->eth_hlen
+ IP6_HEADER_LEN
+ (TCP_OFFSET(pi
->tcph
)*4));
637 pi
->proto
= IP_PROTO_TCP
;
638 pi
->s_port
= pi
->tcph
->src_port
;
639 pi
->d_port
= pi
->tcph
->dst_port
;
640 connection_tracking(pi
);
641 //cx_track_simd_ipv4(pi);
645 void parse_tcp (packetinfo
*pi
)
649 if (TCP_ISFLAGSET(pi
->tcph
, (TF_SYN
))) {
650 if (!TCP_ISFLAGSET(pi
->tcph
, (TF_ACK
))) {
651 if (IS_COSET(&config
,CO_SYN
)) {
652 vlog(0x3, "[*] - Got a SYN from a CLIENT: dst_port:%d\n",ntohs(pi
->tcph
->dst_port
));
657 if (IS_COSET(&config
,CO_SYNACK
)) {
658 vlog(0x3, "[*] Got a SYNACK from a SERVER: src_port:%d\n", ntohs(pi
->tcph
->src_port
));
659 fp_tcp(pi
, CO_SYNACK
);
660 if (pi
->sc
!= SC_SERVER
) reverse_pi_cxt(pi
);
666 // Check payload for known magic bytes that defines files!
668 if (pi
->sc
== SC_CLIENT
&& !ISSET_CXT_DONT_CHECK_CLIENT(pi
)) {
669 if (IS_CSSET(&config
,CS_TCP_CLIENT
)
670 && !ISSET_DONT_CHECK_CLIENT(pi
)) {
671 if (pi
->af
== AF_INET
) client_tcp4(pi
);
672 else client_tcp6(pi
);
676 } else if (pi
->sc
== SC_SERVER
&& !ISSET_CXT_DONT_CHECK_SERVER(pi
)) {
677 if (IS_CSSET(&config
,CS_TCP_SERVER
)
678 && !ISSET_DONT_CHECK_SERVICE(pi
)) {
679 if (pi
->af
== AF_INET
) service_tcp4(pi
);
680 else service_tcp6(pi
);
684 vlog(0x3, "[*] - NOT CHECKING TCP PACKAGE\n");
688 if (IS_COSET(&config
,CO_ACK
)
689 && TCP_ISFLAGSET(pi
->tcph
, (TF_ACK
))
690 && !TCP_ISFLAGSET(pi
->tcph
, (TF_SYN
))
691 && !TCP_ISFLAGSET(pi
->tcph
, (TF_RST
))
692 && !TCP_ISFLAGSET(pi
->tcph
, (TF_FIN
))) {
693 vlog(0x3, "[*] Got a STRAY-ACK: src_port:%d\n",ntohs(pi
->tcph
->src_port
));
696 } else if (IS_COSET(&config
,CO_FIN
) && TCP_ISFLAGSET(pi
->tcph
, (TF_FIN
))) {
697 vlog(0x3, "[*] Got a FIN: src_port:%d\n",ntohs(pi
->tcph
->src_port
));
700 } else if (IS_COSET(&config
,CO_RST
) && TCP_ISFLAGSET(pi
->tcph
, (TF_RST
))) {
701 vlog(0x3, "[*] Got a RST: src_port:%d\n",ntohs(pi
->tcph
->src_port
));
707 void prepare_udp (packetinfo
*pi
)
709 config
.pr_s
.udp_recv
++;
710 if (pi
->af
==AF_INET
) {
711 vlog(0x3, "[*] IPv4 PROTOCOL TYPE UDP:\n");
712 pi
->udph
= (udp_header
*) (pi
->packet
+ pi
->eth_hlen
+ (IP_HL(pi
->ip4
) * 4));
713 pi
->plen
= pi
->pheader
->caplen
- UDP_HEADER_LEN
-
714 (IP_HL(pi
->ip4
) * 4) - pi
->eth_hlen
;
715 pi
->payload
= (char *)(pi
->packet
+ pi
->eth_hlen
+
716 (IP_HL(pi
->ip4
) * 4) + UDP_HEADER_LEN
);
718 } else if (pi
->af
==AF_INET6
) {
719 vlog(0x3, "[*] IPv6 PROTOCOL TYPE UDP:\n");
720 pi
->udph
= (udp_header
*) (pi
->packet
+ pi
->eth_hlen
+ + IP6_HEADER_LEN
);
721 pi
->plen
= pi
->pheader
->caplen
- UDP_HEADER_LEN
-
722 IP6_HEADER_LEN
- pi
->eth_hlen
;
723 pi
->payload
= (char *)(pi
->packet
+ pi
->eth_hlen
+
724 IP6_HEADER_LEN
+ UDP_HEADER_LEN
);
726 pi
->proto
= IP_PROTO_UDP
;
727 pi
->s_port
= pi
->udph
->src_port
;
728 pi
->d_port
= pi
->udph
->dst_port
;
729 connection_tracking(pi
);
730 //cx_track_simd_ipv4(pi);
734 void parse_udp (packetinfo
*pi
)
737 //if (is_set_guess_upd_direction(config)) {
738 udp_guess_direction(pi
); // fix DNS server transfers?
739 // Check for Passive DNS
740 // if (IS_COSET(&config,CO_DNS) && (pi->sc == SC_SERVER && ntohs(pi->s_port) == 53)) passive_dns (pi);
742 if (IS_CSSET(&config
,CS_UDP_SERVICES
)) {
743 if (pi
->af
== AF_INET
) {
745 if (!ISSET_DONT_CHECK_SERVICE(pi
)||!ISSET_DONT_CHECK_CLIENT(pi
)) {
746 // Check for UDP SERVICE
749 // UPD Fingerprinting
750 if (IS_COSET(&config
,CO_UDP
)) fp_udp4(pi
, pi
->ip4
, pi
->udph
, pi
->end_ptr
);
751 } else if (pi
->af
== AF_INET6
) {
752 if (!ISSET_DONT_CHECK_SERVICE(pi
)||!ISSET_DONT_CHECK_CLIENT(pi
)) {
755 /* fp_udp(ip6, ttl, ipopts, len, id, ipflags, df); */
759 vlog(0x3, "[*] - NOT CHECKING UDP PACKAGE\n");
764 void prepare_icmp (packetinfo
*pi
)
766 config
.pr_s
.icmp_recv
++;
767 if (pi
->af
==AF_INET
) {
768 vlog(0x3, "[*] IPv4 PROTOCOL TYPE ICMP:\n");
769 pi
->icmph
= (icmp_header
*) (pi
->packet
+ pi
->eth_hlen
+ (IP_HL(pi
->ip4
) * 4));
770 pi
->proto
= IP_PROTO_ICMP
;
772 } else if (pi
->af
==AF_INET6
) {
773 vlog(0x3, "[*] IPv6 PROTOCOL TYPE ICMP:\n");
774 pi
->icmp6h
= (icmp6_header
*) (pi
->packet
+ pi
->eth_hlen
+ IP6_HEADER_LEN
);
775 pi
->proto
= IP6_PROTO_ICMP
;
780 * DO change ip6->hop_lmt to 0 or something
782 connection_tracking(pi
);
786 void parse_icmp (packetinfo
*pi
)
790 if (IS_COSET(&config
,CO_ICMP
)) {
791 if (pi
->cxt
->check
== 0x00) {
792 pi
->cxt
->check
= 0x10; //for now - stop icmp fp quick
793 if (pi
->af
==AF_INET
) {
794 fp_icmp4(pi
, pi
->ip4
, pi
->icmph
, pi
->end_ptr
);
795 // could look for icmp spesific data in package abcde...
796 // service_icmp(*pi->ip4,*tcph
797 } else if (pi
->af
==AF_INET6
) {
799 fp_icmp6(pi
, pi
->ip6
, pi
->icmp6h
, pi
->end_ptr
);
802 vlog(0x3, "[*] - NOT CHECKING ICMP PACKAGE\n");
807 void prepare_other (packetinfo
*pi
)
809 config
.pr_s
.othert_recv
++;
810 if (pi
->af
==AF_INET
) {
811 vlog(0x3, "[*] IPv4 PROTOCOL TYPE OTHER: %d\n",pi
->ip4
->ip_p
);
813 } else if (pi
->af
==AF_INET6
) {
814 vlog(0x3, "[*] IPv6 PROTOCOL TYPE OTHER: %d\n",pi
->ip6
->next
);
819 connection_tracking(pi
);
823 void parse_other (packetinfo
*pi
)
827 if (pi
->cxt
->check
== 0x00) {
828 if (IS_COSET(&config
,CO_OTHER
)) {
829 pi
->cxt
->check
= 0x01; // no more checks
830 // service_other(*pi->ip4,*transporth);
831 // fp_other(pi->ipX, ttl, ipopts, len, id, ipflags, df);
833 vlog(0x3, "[*] - NOT CHECKING *OTHER* PACKAGE\n");
838 void udp_guess_direction(packetinfo
*pi
)
840 /* Stupid hack :( for DNS/port 53 */
841 if (ntohs(pi
->d_port
) == 53) {
842 if (pi
->sc
== SC_CLIENT
) return;
843 else pi
->sc
= SC_CLIENT
;
845 } else if (ntohs(pi
->s_port
) == 53) {
846 if (pi
->sc
== SC_SERVER
) return;
847 else pi
->sc
= SC_SERVER
;
851 int parse_network (char *net_s
, struct in6_addr
*network
)
855 if (NULL
!= (t
= strchr(net_s
, ':'))) {
857 if (!inet_pton(type
, net_s
, network
)) {
858 perror("parse_nets6");
861 olog("Network6 %-36s \t -> %08x:%08x:%08x:%08x\n",
867 if (!inet_pton(type
, net_s
, &IP4ADDR(network
))) {
868 perror("parse_nets");
871 olog("Network4 %16s \t-> 0x%08x\n", net_s
, IP4ADDR(network
));
876 int parse_netmask (char *f
, int type
, struct in6_addr
*netmask
)
880 char output
[MAX_NETS
];
881 // parse netmask into host order
882 if (type
== AF_INET
&& (t
= strchr(f
, '.')) > f
&& t
-f
< 4) {
883 // full ipv4 netmask : dotted quads
884 inet_pton(type
, f
, &IP4ADDR(netmask
));
885 olog("mask 4 %s \t-> 0x%08x\n", f
, IP4ADDR(netmask
));
886 } else if (type
== AF_INET6
&& NULL
!= (t
= strchr(f
, ':'))) {
887 // full ipv6 netmasÄž
888 olog("mask 6 %s\n", f
);
889 inet_pton(type
, f
, netmask
);
892 sscanf(f
, "%u", &mask
);
893 olog("cidr %u \t-> ", mask
);
894 if (type
== AF_INET
) {
895 uint32_t shift
= 32 - mask
;
897 IP4ADDR(netmask
) = ntohl( ((unsigned int)-1 >> shift
)<< shift
);
899 IP4ADDR(netmask
) = 0;
901 olog("0x%08x\n", IP4ADDR(netmask
));
902 } else if (type
== AF_INET6
) {
905 memset(netmask
, 0, sizeof(struct in6_addr
));
908 netmask
->s6_addr
[j
++] = 0xff;
912 netmask
->s6_addr
[j
] = -1 << (8 - mask
);
914 inet_ntop(type
, &IP4ADDR(netmask
), output
, MAX_NETS
);
915 olog("mask: %s\n", output
);
916 // pcap packets are in host order.
917 IP6ADDR0(netmask
) = ntohl(IP6ADDR0(netmask
));
918 IP6ADDR1(netmask
) = ntohl(IP6ADDR1(netmask
));
919 IP6ADDR2(netmask
) = ntohl(IP6ADDR2(netmask
));
920 IP6ADDR3(netmask
) = ntohl(IP6ADDR3(netmask
));
927 /* parse strings of the form ip/cidr or ip/mask like:
928 * "10.10.10.10/255.255.255.128,10.10.10.10/25" and
929 * "dead:be:eef2:1aa::b5ff:fe96:37a2/64,..."
931 * an IPv6 address is 8 x 4 hex digits. missing digits are padded with zeroes.
933 void parse_nets(const char *s_net
, struct fmask
*network
)
935 /* f -> for processing
939 int type
, len
, i
= 0;
940 struct in6_addr network6
, netmask6
;
942 // snet is a mutable copy of the args,freed @ nets_end
944 //snet = calloc(1, len);
945 snet
= calloc(1, (len
+ 1)); /* to have \0 too :-) */
946 strncpy(snet
, s_net
, len
);
948 while (f
&& 0 != (p
= strchr(f
, '/'))) {
949 // convert network address
951 type
= parse_network(f
, &network6
);
952 if (type
!= AF_INET
&& type
!= AF_INET6
) {
953 perror("parse_network");
962 parse_netmask(f
, type
, &netmask6
);
964 // poke in the gathered information
968 network
[i
].addr
= network6
;
969 network
[i
].mask
= netmask6
;
970 network
[i
].type
= type
;
974 fprintf(stderr
, "parse_nets: invalid address family!\n");
981 elog("Max networks reached, stopped parsing at %d nets.\n", i
-1);
986 // continue parsing at p, which might point to another network range
999 //update_asset_list();
1003 del_known_services();
1004 del_signature_lists();
1007 print_prads_stats();
1009 if (config
.handle
!= NULL
) pcap_close(config
.handle
);
1010 free_config(); // segfault here !
1011 printf("\nprads ended\n");
1017 void check_interrupt()
1020 if (intr_flag
== 1) {
1022 } else if (intr_flag
== 2) {
1023 update_asset_list();
1024 } else if (intr_flag
== 3) {
1031 void set_end_sessions()
1035 if (inpacket
== 0) {
1036 tstamp
= time(NULL
);
1038 /* if no cxtracking is turned on - dont log to disk */
1039 /* if (log_cxt == 1) log_expired_cxt(); */
1040 /* if no asset detection is turned on - dont log to disk! */
1041 /* if (log_assets == 1) update_asset_list(); */
1042 update_asset_list();
1044 alarm(CHECK_TIMEOUT
);
1048 void print_prads_stats()
1050 extern uint64_t cxtrackerid
; // cxt.c
1051 printf("\n-- prads:");
1052 printf("\n-- Total packets received from libpcap :%12u",config
.pr_s
.got_packets
);
1053 printf("\n-- Total Ethernet packets received :%12u",config
.pr_s
.eth_recv
);
1054 printf("\n-- Total VLAN packets received :%12u",config
.pr_s
.vlan_recv
);
1055 printf("\n-- Total ARP packets received :%12u",config
.pr_s
.arp_recv
);
1056 printf("\n-- Total IPv4 packets received :%12u",config
.pr_s
.ip4_recv
);
1057 printf("\n-- Total IPv6 packets received :%12u",config
.pr_s
.ip6_recv
);
1058 printf("\n-- Total Other link packets received :%12u",config
.pr_s
.otherl_recv
);
1059 printf("\n-- Total IPinIPv4 packets received :%12u",config
.pr_s
.ip4ip_recv
);
1060 printf("\n-- Total IPinIPv6 packets received :%12u",config
.pr_s
.ip6ip_recv
);
1061 printf("\n-- Total GRE packets received :%12u",config
.pr_s
.gre_recv
);
1062 printf("\n-- Total TCP packets received :%12u",config
.pr_s
.tcp_recv
);
1063 printf("\n-- Total UDP packets received :%12u",config
.pr_s
.udp_recv
);
1064 printf("\n-- Total ICMP packets received :%12u",config
.pr_s
.icmp_recv
);
1065 printf("\n-- Total Other transport packets received :%12u",config
.pr_s
.othert_recv
);
1067 printf("\n-- Total sessions tracked :%12lu", cxtrackerid
);
1068 printf("\n-- Total assets detected :%12u",config
.pr_s
.assets
);
1069 printf("\n-- Total TCP OS fingerprints detected :%12u",config
.pr_s
.tcp_os_assets
);
1070 printf("\n-- Total UDP OS fingerprints detected :%12u",config
.pr_s
.udp_os_assets
);
1071 printf("\n-- Total ICMP OS fingerprints detected :%12u",config
.pr_s
.icmp_os_assets
);
1072 printf("\n-- Total DHCP OS fingerprints detected :%12u",config
.pr_s
.dhcp_os_assets
);
1073 printf("\n-- Total TCP service assets detected :%12u",config
.pr_s
.tcp_services
);
1074 printf("\n-- Total TCP client assets detected :%12u",config
.pr_s
.tcp_clients
);
1075 printf("\n-- Total UDP service assets detected :%12u",config
.pr_s
.udp_services
);
1076 printf("\n-- Total UDP client assets detected :%12u",config
.pr_s
.udp_clients
);
1083 olog(" $ prads [options]\n");
1085 olog(" OPTIONS:\n");
1087 olog(" -i <iface> Network device <iface> (default: eth0).\n");
1088 olog(" -r <file> Read pcap <file>.\n");
1089 olog(" -c <file> Read config from <file>\n");
1090 olog(" -b <filter> Apply Berkeley packet filter <filter>.\n");
1091 //olog(" -d to logdir\n");
1092 olog(" -u <user> Run as user <user>.\n");
1093 olog(" -g <group> Run as group <group>.\n");
1094 olog(" -a <nets> Specify home nets (eg: '192.168.0.0/25,10.0.0.0/255.0.0.0').\n");
1095 olog(" -D Enables daemon mode.\n");
1096 olog(" -p <pidfile> Name of pidfile\n");
1097 olog(" -P <path> Pid lives in <path>\n");
1098 olog(" -l <file> Log assets to <file> (default: '%s')\n", config
.assetlog
);
1099 olog(" -f <FIFO> Log assets to <FIFO>");
1100 olog(" -C <dir> Chroot into <dir> before dropping privs.\n");
1101 olog(" -h This help message.\n");
1102 olog(" -v Verbose.\n");
1106 extern int optind
, opterr
, optopt
; // getopt()
1109 int main(int argc
, char *argv
[])
1112 int ch
= 0, verbose_already
= 0;
1114 vlog(2, "%08x =? %08x, endianness: %s\n\n", 0xdeadbeef, ntohl(0xdeadbeef), (0xdead == ntohs(0xdead)?"big":"little") );
1116 memset(&config
, 0, sizeof(globalconfig
));
1117 set_default_config_options();
1118 bstring pconfile
= bfromcstr(CONFDIR
"prads.conf");
1119 //parse_config_file(pconfile);
1120 //bdestroy (pconfile);
1122 inpacket
= gameover
= intr_flag
= 0;
1124 signal(SIGTERM
, game_over
);
1125 signal(SIGINT
, game_over
);
1126 signal(SIGQUIT
, game_over
);
1127 signal(SIGALRM
, set_end_sessions
);
1128 //signal(SIGALRM, game_over); // Use this to debug segfault when exiting
1130 // do first-pass args parse for commandline-passed config file
1132 #define ARGS "C:c:b:d:Dg:hi:p:r:P:u:va:l:f:"
1133 while ((ch
= getopt(argc
, argv
, ARGS
)) != -1)
1136 pconfile
= bfromcstr(optarg
);
1149 verbose_already
= 1;
1151 parse_config_file(pconfile
);
1153 // reset verbosity before 2nd coming, but only if set on cli
1158 while ((ch
= getopt(argc
, argv
, ARGS
)) != -1)
1161 config
.s_net
= strdup(optarg
);
1164 pconfile
= bfromcstr(optarg
);
1167 config
.chroot_dir
= strdup(optarg
);
1170 config
.dev
= strdup(optarg
);
1173 config
.pcap_file
= blk2bstr(optarg
, strlen(optarg
));
1176 config
.bpff
= strdup(optarg
);
1182 config
.dpath
= strdup(optarg
);
1189 config
.daemon_flag
= 1;
1192 config
.user_name
= strdup(optarg
);
1193 config
.drop_privs_flag
= 1;
1196 config
.group_name
= strdup(optarg
);
1197 config
.drop_privs_flag
= 1;
1200 config
.pidfile
= strdup(optarg
);
1203 config
.pidpath
= strdup(optarg
);
1206 config
.assetlog
= strdup(optarg
);
1209 config
.fifo
= strdup(optarg
);
1212 elog("unrecognized argument: '%c'\n", optopt
);
1215 elog("Did not recognize argument '%c'\n", ch
);
1218 bdestroy (pconfile
);
1219 // we're done parsing configs - now initialize prads
1222 rc
= init_logging(LOG_STDOUT
, NULL
, config
.verbose
);
1223 if(rc
) perror("Logging to standard out failed!");
1226 if(config
.assetlog
) {
1227 olog("logging to file '%s'\n", config
.assetlog
);
1228 rc
= init_logging(LOG_FILE
, config
.assetlog
, config
.verbose
);
1229 if(rc
) perror("Logging to file failed!");
1232 olog("logging to FIFO '%s'\n", config
.fifo
);
1233 rc
= init_logging(LOG_FIFO
, config
.fifo
, config
.verbose
);
1234 if(rc
) perror("Logging to fifo failed!");
1238 parse_nets(config
.s_net
, network
);
1240 if(config
.ctf
& CS_MAC
){
1241 olog("[*] Loading MAC fingerprints from file %s\n", config
.sig_file_mac
);
1242 rc
= load_mac(config
.sig_file_mac
, &config
.sig_mac
, 0);
1243 if(rc
) perror("mac loadage failed!");
1246 if(config
.ctf
& CO_SYN
){
1247 olog("[*] Loading SYN fingerprints\n");
1248 rc
= load_sigs(config
.sig_file_syn
, &config
.sig_syn
, config
.sig_hashsize
);
1249 if(rc
) perror("syn loadage failed!");
1250 if(config
.verbose
> 1)
1251 dump_sigs(config
.sig_syn
, config
.sig_hashsize
);
1253 if(config
.ctf
& CO_SYNACK
){
1254 olog("[*] Loading SYNACK fingerprints\n");
1255 rc
= load_sigs(config
.sig_file_synack
, &config
.sig_synack
, config
.sig_hashsize
);
1256 if(rc
) perror("synack loadage failed!");
1257 if(config
.verbose
> 1)
1258 dump_sigs(config
.sig_synack
, config
.sig_hashsize
);
1260 if(config
.ctf
& CO_ACK
){
1261 olog("[*] Loading STRAY-ACK fingerprints\n");
1262 rc
= load_sigs(config
.sig_file_ack
, &config
.sig_ack
, config
.sig_hashsize
);
1263 if(rc
) perror("stray-ack loadage failed!");
1264 if(config
.verbose
> 1)
1265 dump_sigs(config
.sig_ack
, config
.sig_hashsize
);
1267 if(config
.ctf
& CO_FIN
){
1268 olog("[*] Loading FIN fingerprints\n");
1269 rc
= load_sigs(config
.sig_file_fin
, &config
.sig_fin
, config
.sig_hashsize
);
1270 if(rc
) perror("fin loadage failed!");
1271 if(config
.verbose
> 1)
1272 dump_sigs(config
.sig_fin
, config
.sig_hashsize
);
1274 if(config
.ctf
& CO_RST
){
1275 olog("[*] Loading RST fingerprints\n");
1276 rc
= load_sigs(config
.sig_file_rst
, &config
.sig_rst
, config
.sig_hashsize
);
1277 if(rc
) perror("rst loadage failed!");
1278 if(config
.verbose
> 1)
1279 dump_sigs(config
.sig_rst
, config
.sig_hashsize
);
1282 olog("\n[*] Running prads %s\n", VERSION
);
1283 olog("[*] Using %s\n", pcap_lib_version());
1284 olog("[*] Using PCRE version %s\n", pcre_version());
1286 //if (config.verbose) display_config();
1289 // should be config file too
1290 load_servicefp_file(1, CONFDIR
"tcp-service.sig");
1291 load_servicefp_file(2, CONFDIR
"udp-service.sig");
1292 load_servicefp_file(3, CONFDIR
"tcp-clients.sig");
1293 //load_servicefp_file(4, CONFDIR "udp-client.sig");
1296 if (config
.pcap_file
) {
1297 /* Read from PCAP file specified by '-r' switch. */
1298 olog("[*] Reading from file %s\n", bdata(config
.pcap_file
));
1299 if (!(config
.handle
= pcap_open_offline(bdata(config
.pcap_file
), config
.errbuf
))) {
1300 olog("[*] Unable to open %s. (%s)", bdata(config
.pcap_file
), config
.errbuf
);
1306 olog("[*] You must be root..\n");
1311 * look up an available device if non specified
1313 if (config
.dev
== 0x0)
1314 config
.dev
= pcap_lookupdev(config
.errbuf
);
1315 olog("[*] Device: %s\n", config
.dev
);
1317 if ((config
.handle
= pcap_open_live(config
.dev
, SNAPLENGTH
, 1, 500, config
.errbuf
)) == NULL
) {
1318 olog("[*] Error pcap_open_live: %s \n", config
.errbuf
);
1320 } //else if ((pcap_compile(config.handle, &config.cfilter, config.bpff, 1, config.net_mask)) == -1) {
1321 // olog("[*] Error pcap_compile user_filter: %s\n",
1322 // pcap_geterr(config.handle));
1327 * B0rk if we see an error...
1329 if (strlen(config
.errbuf
) > 0) {
1330 elog("[*] Error errbuf: %s \n", config
.errbuf
);
1334 if(config
.chroot_dir
){
1335 olog("[*] Chrooting to dir '%s'..\n", config
.chroot_dir
);
1337 elog("[!] failed to chroot\n");
1342 if (config
.drop_privs_flag
) {
1343 olog("[*] Dropping privs...\n");
1347 if (config
.daemon_flag
) {
1348 if (!is_valid_path(config
.pidpath
))
1350 ("[*] PID path \"%s\" is bad, check privilege.", config
.pidpath
);
1351 openlog("prads", LOG_PID
| LOG_CONS
, LOG_DAEMON
);
1352 olog("[*] Daemonizing...\n\n");
1359 alarm(CHECK_TIMEOUT
);
1361 if ((pcap_compile(config
.handle
, &config
.cfilter
, config
.bpff
, 1, config
.net_mask
)) == -1) {
1362 olog("[*] Error pcap_compile user_filter: %s\n", pcap_geterr(config
.handle
));
1366 if (pcap_setfilter(config
.handle
, &config
.cfilter
)) {
1367 olog("[*] Unable to set pcap filter! %s", pcap_geterr(config
.handle
));
1371 olog("[*] Sniffing...\n\n");
1372 pcap_loop(config
.handle
, -1, got_packet
, NULL
);
1375 //pcap_close(config.handle);
1379 //void free_config()
1381 // if (config.dev != NULL) free (config.dev);
1382 // if (config.cfilter.bf_insns != NULL) free (config.cfilter.bf_insns);