Exemplo n.º 1
0
	bool add(char c) {
		int x = index(c); s[n++] = c;
		Node *p = get(last);
		if (!p->ch[x]) {
			last = New_Node(p->len + 2);
			if (last->len == 1) {
				last->suffix = even;
			}
			else last->suffix = get(p->suffix)->ch[x];//guarantee proper suffix
			p->ch[x] = last;
			cnt++;
			mx = max(mx, last->len);
			return 1;
		}
		else {
			last = p->ch[x];
			return 0;
		}
	}
Exemplo n.º 2
0
void ProcessPacket(NodeList_t *NodeList, pcap_dev_t *pcap_dev, const struct pcap_pkthdr *hdr, const u_char *data) {
struct FlowNode	*Node;
struct ip 	  *ip;
void		  *payload, *defragmented;
uint32_t	  size_ip, offset, data_len, payload_len, bytes;
uint16_t	  version, ethertype, proto;
#ifdef DEVEL
char		  s1[64];
char		  s2[64];
#endif
static unsigned pkg_cnt = 0;

	pkg_cnt++;
	dbg_printf("\nNext Packet: %u\n", pkg_cnt);

	pcap_dev->proc_stat.packets++;
	offset = pcap_dev->linkoffset;

	Node = New_Node();
	if ( !Node ) {
		pcap_dev->proc_stat.skipped++;
		LogError("Node allocation error - skip packet");
		return;
	}

	if ( pcap_dev->linktype == DLT_EN10MB ) {
		ethertype = data[12] << 0x08 | data[13];
		int	IEEE802 = ethertype <= 1500;
		if ( IEEE802 ) {
			pcap_dev->proc_stat.skipped++;
			Free_Node(Node);
			return;
		}
		REDO_LINK:
			switch (ethertype) {
				case 0x800:	 // IPv4
				case 0x86DD: // IPv6
					break;
				case 0x8100: {	// VLAN 
					do {
						vlan_hdr_t *vlan_hdr = (vlan_hdr_t *)(data + offset);  // offset points to end of link layer
						dbg_printf("VLAN ID: %u, type: 0x%x\n", ntohs(vlan_hdr->vlan_id), ntohs(vlan_hdr->type) );
						ethertype = ntohs(vlan_hdr->type);
/*
pkt->vlans[pkt->vlan_count].pcp = (p[0] >> 5) & 7;
	  pkt->vlans[pkt->vlan_count].cfi = (p[0] >> 4) & 1;
	  pkt->vlans[pkt->vlan_count].vid = uint_16_be(p) & 0xfff;
*/
						offset += 4;
					} while ( ethertype == 0x8100 );
			
					// redo ethertype evaluation
					goto REDO_LINK;
					} break;
				case 0x806:	 // skip ARP
					// silently skip ARP
					pcap_dev->proc_stat.skipped++;
					return;
					break;
				case 0x26:	 // ?? multicast router termination ??
				case 0x4305: // B.A.T.M.A.N. BATADV
				case 0x886f: // MS NLB heartbeat
				case 0x88a2: // ATA over ethernet
				case 0x88cc: // CISCO LLDP
				case 0x9000: // Loop
				case 0x880b: // PPP - rfc 7042
					pcap_dev->proc_stat.skipped++;
					if ( Node->proto ) {
						// if it's an encap which we do not understand yet - push tunnel
						Push_Node(NodeList, Node);
					} else {
						pcap_dev->proc_stat.skipped++;
						dbg_printf("Skip Ethertype 0x%x", ethertype);
						Free_Node(Node);
					}
					return;
					break;
				default:
					pcap_dev->proc_stat.unknown++;
					LogError("Unsupported link type: 0x%x, packet: %u", ethertype, pkg_cnt);
					Free_Node(Node);
					return;
			}
	}

	if (hdr->caplen < offset) {
		pcap_dev->proc_stat.short_snap++;
		LogError("Short packet: %u/%u", hdr->caplen, offset);
		Free_Node(Node);
		return;
	}

	Node->t_first.tv_sec = hdr->ts.tv_sec;
	Node->t_first.tv_usec = hdr->ts.tv_usec;
	Node->t_last.tv_sec  = hdr->ts.tv_sec;
	Node->t_last.tv_usec  = hdr->ts.tv_usec;

	data	 = data + offset;
	data_len = hdr->caplen - offset;
	offset	 = 0;
	defragmented = NULL;

	// IP decoding
	REDO_IPPROTO:
	// IP decoding
	if ( defragmented ) {
		// data is sitting on a defragmented IPv4 packet memory region
		// REDO loop could result in a memory leak, if again IP is fragmented
		// XXX memory leak to be fixed
		LogError("Fragmentation memory leak triggered!");
	}

	ip  	= (struct ip *)(data + offset); // offset points to end of link layer
	version = ip->ip_v;	 // ip version

	if ( version == 6 ) {
		uint64_t *addr;
		struct ip6_hdr *ip6 = (struct ip6_hdr *) (data + offset);
		size_ip = sizeof(struct ip6_hdr);
		offset = size_ip;	// offset point to end of IP header

		if ( data_len < size_ip ) {
			LogError("Packet: %u Length error: data_len: %u < size IPV6: %u, captured: %u, hdr len: %u", 
				pkg_cnt, data_len, size_ip, hdr->caplen, hdr->len);	
			pcap_dev->proc_stat.short_snap++;
			Free_Node(Node);
			return;
		}

		// XXX Extension headers not processed
		proto		= ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
		payload_len = bytes = ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);

		if (data_len < (payload_len + size_ip) ) {
			// capture len was limited - so adapt payload_len
			payload_len = data_len - size_ip;
		}

		dbg_printf("Packet IPv6, SRC %s, DST %s, ",
			inet_ntop(AF_INET6, &ip6->ip6_src, s1, sizeof(s1)),
			inet_ntop(AF_INET6, &ip6->ip6_dst, s2, sizeof(s2)));

		payload = (void *)ip + size_ip;

		addr = (uint64_t *)&ip6->ip6_src;
		Node->src_addr.v6[0] = ntohll(addr[0]);
		Node->src_addr.v6[1] = ntohll(addr[1]);

		addr = (uint64_t *)&ip6->ip6_dst;
		Node->dst_addr.v6[0] = ntohll(addr[0]);
		Node->dst_addr.v6[1] = ntohll(addr[1]);
		Node->version = AF_INET6;

	} else if ( version == 4 ) {
		uint16_t ip_off = ntohs(ip->ip_off);
		uint32_t frag_offset = (ip_off & IP_OFFMASK) << 3;
		size_ip = (ip->ip_hl << 2);
		offset = size_ip;	// offset point to end of IP header

		if ( data_len < size_ip ) {
			LogError("Packet: %u Length error: data_len: %u < size IPV4: %u, captured: %u, hdr len: %u", 
				pkg_cnt, data_len, size_ip, hdr->caplen, hdr->len);	
			pcap_dev->proc_stat.short_snap++;
			Free_Node(Node);
			return;
		}

		payload_len = ntohs(ip->ip_len);
		dbg_printf("size IP hader: %u, len: %u, %u\n", size_ip, ip->ip_len, payload_len);

		payload_len -= size_ip;	// ajust length compatibel IPv6
		bytes 		= payload_len;
		payload = (void *)ip + size_ip;
		proto   = ip->ip_p;

		if (data_len < (payload_len + size_ip) ) {
			// capture len was limited - so adapt payload_len
			payload_len = data_len - size_ip;
			pcap_dev->proc_stat.short_snap++;
		}

		dbg_printf("Packet IPv4 SRC %s, DST %s, ",
			inet_ntop(AF_INET, &ip->ip_src, s1, sizeof(s1)),
			inet_ntop(AF_INET, &ip->ip_dst, s2, sizeof(s2)));

		// IPv4 defragmentation
		if ( (ip_off & IP_MF) || frag_offset ) {
			uint16_t ip_id = ntohs(ip->ip_id);
#ifdef DEVEL
			if ( frag_offset == 0 )
				printf("Fragmented packet: first segement: ip_off: %u, frag_offset: %u\n", ip_off, frag_offset);
			if (( ip_off & IP_MF ) && frag_offset )
				printf("Fragmented packet: middle segement: ip_off: %u, frag_offset: %u\n", ip_off, frag_offset);
			if (( ip_off & IP_MF ) == 0  )
				printf("Fragmented packet: last segement: ip_off: %u, frag_offset: %u\n", ip_off, frag_offset);
#endif
			// fragmented packet
			defragmented = IPFrag_tree_Update(ip->ip_src.s_addr, ip->ip_dst.s_addr, ip_id, &payload_len, ip_off, payload);
			if ( defragmented == NULL ) {
				// not yet complete
				dbg_printf("Fragmentation not yet completed\n");
				return;
			}
			dbg_printf("Fragmentation assembled\n");
			// packet defragmented - set payload to defragmented data
			payload = defragmented;
		} 

		Node->src_addr.v6[0] = 0;
		Node->src_addr.v6[1] = 0;
		Node->src_addr.v4 = ntohl(ip->ip_src.s_addr);

		Node->dst_addr.v6[0] = 0;
		Node->dst_addr.v6[1] = 0;
		Node->dst_addr.v4 = ntohl(ip->ip_dst.s_addr);
		Node->version = AF_INET;
	} else {
		LogError("ProcessPacket() Unsupprted protocol version: %i", version);
		pcap_dev->proc_stat.unknown++;
		Free_Node(Node);
		return;
	}

	Node->packets = 1;
	Node->bytes   = bytes;
	Node->proto   = proto;
	dbg_printf("Payload: %u bytes, Full packet: %u bytes\n", payload_len, bytes);

	// TCP/UDP decoding
	switch (proto) {
		case IPPROTO_UDP: {
			struct udphdr *udp = (struct udphdr *)payload;
			uint16_t UDPlen = ntohs(udp->uh_ulen);
			if ( UDPlen < 8 ) {
				LogError("UDP payload legth error: %u bytes < 8\n",
					UDPlen);
				Free_Node(Node);
				break;
			}
			uint32_t size_udp_payload = ntohs(udp->uh_ulen) - 8;

			if ( (bytes == payload_len ) && (payload_len - sizeof(struct udphdr)) != size_udp_payload ) {
				LogError("UDP payload legth error: Expected %u, have %u bytes\n",
					size_udp_payload, (payload_len - (unsigned)sizeof(struct udphdr)));
				Free_Node(Node);
				break;
			}
			payload = payload + sizeof(struct udphdr);
			payload_len -= sizeof(struct udphdr);
			dbg_printf("UDP: size: %u, SRC: %i, DST: %i\n", 
				size_udp_payload, ntohs(udp->uh_sport), ntohs(udp->uh_dport));

			Node->flags = 0;
			Node->src_port = ntohs(udp->uh_sport);
			Node->dst_port = ntohs(udp->uh_dport);

			if ( hdr->caplen == hdr->len ) {
				// process payload of full packets
				if ( (bytes == payload_len) && (Node->src_port == 53 || Node->dst_port == 53) ) 
 					content_decode_dns(Node, payload, payload_len);
			}
			Push_Node(NodeList, Node);
			} break;
		case IPPROTO_TCP: {
			struct tcphdr *tcp = (struct tcphdr *)payload;
			uint32_t size_tcp;
			size_tcp = tcp->th_off << 2;

			if ( payload_len < size_tcp ) {
				LogError("TCP header length error: len: %u < size TCP header: %u", payload_len, size_tcp);	
				pcap_dev->proc_stat.short_snap++;
				Free_Node(Node);
				break;
			}

			payload = payload + size_tcp;
			payload_len -= size_tcp;
			dbg_printf("Size TCP header: %u, size TCP payload: %u ", size_tcp, payload_len);
			dbg_printf("src %i, DST %i, flags %i : ", 
				ntohs(tcp->th_sport), ntohs(tcp->th_dport), tcp->th_flags);

#ifdef DEVEL
			if ( tcp->th_flags & TH_SYN )  printf("SYN ");
			if ( tcp->th_flags & TH_ACK )  printf("ACK ");
			if ( tcp->th_flags & TH_URG )  printf("URG ");
			if ( tcp->th_flags & TH_PUSH ) printf("PUSH ");
			if ( tcp->th_flags & TH_FIN )  printf("FIN ");
			if ( tcp->th_flags & TH_RST )  printf("RST ");
			printf("\n");
#endif

			Node->flags = tcp->th_flags;
			Node->src_port = ntohs(tcp->th_sport);
			Node->dst_port = ntohs(tcp->th_dport);
			Push_Node(NodeList, Node);

			} break;
		case IPPROTO_ICMP: {
			struct icmp *icmp = (struct icmp *)payload;

			Node->dst_port = (icmp->icmp_type << 8 ) + icmp->icmp_code;
			dbg_printf("IPv%d ICMP proto: %u, type: %u, code: %u\n", version, ip->ip_p, icmp->icmp_type, icmp->icmp_code);
			Push_Node(NodeList, Node);
			} break;
		case IPPROTO_ICMPV6: {
			struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)payload;

			Node->dst_port = (icmp6->icmp6_type << 8 ) + icmp6->icmp6_code;
			dbg_printf("IPv%d ICMP proto: %u, type: %u, code: %u\n", version, ip->ip_p, icmp6->icmp6_type, icmp6->icmp6_code);
			Push_Node(NodeList, Node);
			} break;
		case IPPROTO_IPV6: {
			uint32_t size_inner_ip = sizeof(struct ip6_hdr);

			if ( payload_len < size_inner_ip ) {
				LogError("IPIPv6 tunnel header length error: len: %u < size inner IP: %u", payload_len, size_inner_ip);	
				pcap_dev->proc_stat.short_snap++;
				if ( defragmented ) {
					free(defragmented);
					defragmented = NULL;
				}
				Free_Node(Node);
				return;
			}
			offset   = 0;
			data 	 = payload;
			data_len = payload_len;

//			// move IP to tun IP
			Node->tun_src_addr = Node->src_addr;
			Node->tun_dst_addr = Node->dst_addr;
			Node->tun_proto	= IPPROTO_IPIP;

			dbg_printf("IPIPv6 tunnel - inner IPv6:\n");

			// redo proto evaluation
			goto REDO_IPPROTO;
			} break;
		case IPPROTO_IPIP: {
			struct ip *inner_ip	= (struct ip *)payload;
			uint32_t size_inner_ip = (inner_ip->ip_hl << 2);

			if ( payload_len < size_inner_ip ) {
				LogError("IPIP tunnel header length error: len: %u < size inner IP: %u", payload_len, size_inner_ip);	
				pcap_dev->proc_stat.short_snap++;
				Free_Node(Node);
				break;
			}
			offset   = 0;
			data 	 = payload;
			data_len = payload_len;

			// move IP to tun IP
			Node->tun_src_addr = Node->src_addr;
			Node->tun_dst_addr = Node->dst_addr;
			Node->tun_proto	= IPPROTO_IPIP;

			dbg_printf("IPIP tunnel - inner IP:\n");

			// redo proto evaluation
			goto REDO_IPPROTO;

			} break;
		case IPPROTO_GRE: {
			gre_hdr_t *gre_hdr = (gre_hdr_t *)payload;
			uint32_t gre_hdr_size = sizeof(gre_hdr_t); // offset points to end of inner IP

			if ( payload_len < gre_hdr_size ) {
				LogError("GRE tunnel header length error: len: %u < size GRE hdr: %u", payload_len, gre_hdr_size);	
				pcap_dev->proc_stat.short_snap++;
				Free_Node(Node);
				break;
			}

			dbg_printf("GRE proto encapsulation: type: 0x%x\n", ethertype);
			ethertype = ntohs(gre_hdr->type);
			offset   = gre_hdr_size;
			data 	 = payload;
			data_len = payload_len;

			// move IP to tun IP
			Node->tun_src_addr = Node->src_addr;
			Node->tun_dst_addr = Node->dst_addr;
			Node->tun_proto	= IPPROTO_GRE;

			// redo IP proto evaluation
			goto REDO_LINK;

			} break;
		default: 
			// not handled protocol - simply save node
			Push_Node(NodeList, Node);
			pcap_dev->proc_stat.unknown++;
			break;
	}

	if ( defragmented ) {
		free(defragmented);
		defragmented = NULL;
		dbg_printf("Defragmented buffer freed for proto %u", proto);	
	}


} // End of ProcessPacket
Exemplo n.º 3
0
 void Init() {
     node = 0;
     New_Node();
 }
Exemplo n.º 4
0
__attribute__((noreturn)) static void *p_packet_thread(void *thread_data) {
// argument dispatching
p_packet_thread_args_t *args = (p_packet_thread_args_t *)thread_data;
pcap_dev_t *pcap_dev = args->pcap_dev;
time_t t_win		 = args->t_win;
char *pcap_datadir 	 = args->pcap_datadir;
int subdir_index	 = args->subdir_index;
int live		 	 = args->live;
// locals
p_pcap_flush_thread_args_t p_flush_thread_args;
pcapfile_t *pcapfile;
time_t t_start;
int err;

	dbg_printf("New packet thread[%lu]\n", (long unsigned)args->tid);
	args->done = 0;
	args->exit = 0;

	err = pthread_setspecific( buffer_key, (void *)args );
	if ( err ) {
		LogError("[%lu] pthread_setspecific() error in %s line %d: %s\n", 
			(long unsigned)args->tid, __FILE__, __LINE__, strerror(errno) );
		args->done = 1;
		args->exit = 255;
   		pthread_kill(args->parent, SIGUSR1);
		pthread_exit((void *)args);
		/* NOTREACHED */
	}

	/* start flush and pcap file handler thread */
	if ( pcap_datadir ) {
		// just allocate pcapfile and buffers - we need to share pcapfile
		pcapfile = OpenNewPcapFile(pcap_dev->handle, NULL, NULL);
		if ( !pcapfile ) {
			args->done = 1;
			args->exit = 255;
   			pthread_kill(args->parent, SIGUSR1);
			pthread_exit((void *)args);
			/* NOTREACHED */
		}

		p_flush_thread_args.done 	 	 = 0;
		p_flush_thread_args.exit 	 	 = 0;
		p_flush_thread_args.parent 	 	 = args->tid;
		p_flush_thread_args.pcap_dev 	 = args->pcap_dev;
		p_flush_thread_args.subdir_index = subdir_index;
		p_flush_thread_args.pcap_datadir = pcap_datadir;
		p_flush_thread_args.pcapfile 	 = pcapfile;

		err = pthread_create(&p_flush_thread_args.tid, NULL, p_pcap_flush_thread, (void *)&p_flush_thread_args);
		if ( err ) {
			LogError("pthread_create() error in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
			args->done = 1;
			args->exit = 255;
   			pthread_kill(args->parent, SIGUSR1);
			pthread_exit((void *)args);
		}
		dbg_printf("Started flush thread[%lu]\n", (long unsigned)p_flush_thread_args.tid);

	} else {
		pcapfile = NULL;
	}

	err = 0;
	t_start = 0;
	while ( 1 ) {
		struct pcap_pkthdr *hdr; 
		const u_char 	   *data;
		struct timeval tv;
		time_t t_clock;
		int ret;

		if ( !args->done ) {
			ret = pcap_next_ex(pcap_dev->handle, &hdr, &data);
			t_clock = 0;
			switch (ret) {
				case 1: {
					// packet read ok
					t_clock = hdr->ts.tv_sec;
					// process packet for flow cache
					ProcessPacket(args->NodeList, pcap_dev, hdr, data);
					if ( pcap_datadir ) {
						// keep the packet
						if (((t_clock - t_start) >= t_win)) { 
							// first packet or rotate file
							if ( t_start != 0 ) {
								RotateFile(pcapfile, t_start, live);
							}
							// if first packet - set t_start here
							t_start = t_clock - (t_clock % t_win);
						} 
						PcapDump(pcapfile, hdr, data);
					} 
					} break;
				case 0: {
					// live capture idle cycle
					dbg_printf("pcap_next_ex() read live - timeout\n");	
					gettimeofday(&tv, NULL);
					t_clock = tv.tv_sec;
					if ((t_clock - t_start) >= t_win) { /* rotate file */
						if ( t_start ) {
							// if not first packet, where t_start = 0
							struct FlowNode	*Node = New_Node();
							Node->t_first = tv;
							Node->t_last  = tv;
							Node->fin  	  = SIGNAL_NODE;
							Push_Node(args->NodeList, Node);
							if ( pcap_datadir )
							// keep the packet
								RotateFile(pcapfile, t_start, live);
							LogInfo("Packet processing stats: Total: %u, Skipped: %u, Unknown: %u, Short snaplen: %u", 
								pcap_dev->proc_stat.packets, pcap_dev->proc_stat.skipped, 
								pcap_dev->proc_stat.unknown, pcap_dev->proc_stat.short_snap);
						}
						t_start = t_clock - (t_clock % t_win);
						memset((void *)&(pcap_dev->proc_stat), 0, sizeof(proc_stat_t));
					} 
					} break;
				case -1:
					// signal error reading the packet
    				err = 1;
					LogError("pcap_next_ex() read error: '%s'", pcap_geterr(pcap_dev->handle));	
					args->done = 1;
					continue;
					break;
				case -2: // End of packet file
					// signal parent, job is done
    				err = 1;
					LogInfo("pcap_next_ex() end of file");	
					args->done = 1;
					LogInfo("Packet processing stats: Total: %u, Skipped: %u, Unknown: %u, Short snaplen: %u", 
						pcap_dev->proc_stat.packets, pcap_dev->proc_stat.skipped, 
						pcap_dev->proc_stat.unknown, pcap_dev->proc_stat.short_snap);
					continue;
					break;
				default:
    				err = 1;
					pcap_breakloop(pcap_dev->handle);
					LogError("Unexpected pcap_next_ex() return value: %i", ret);
					args->done = 1;
					continue;
			}

		}

		if ( args->done ) 
			break;

	}

	if ( pcap_datadir ) {
		dbg_printf("Wait for flush thread to complete\n");
   		pthread_mutex_lock(&pcapfile->m_pbuff);
    	while ( pcapfile->alternate_size ) {
        	pthread_cond_wait(&pcapfile->c_pbuff, &pcapfile->m_pbuff);
    	}
		pcapfile->t_CloseRename = t_start;
   		pthread_mutex_unlock(&pcapfile->m_pbuff);
		dbg_printf("Wait done.\n");

		LogInfo("Signal flush thread[%lu] to terminate", p_flush_thread_args.tid);
		SignalThreadTerminate((thread_info_t *)&p_flush_thread_args, &pcapfile->c_pbuff);
	}

	if ( err ) 
  		pthread_kill(args->parent, SIGUSR1);

	LogInfo("Packet processing stats: Total: %u, Skipped: %u, Unknown: %u, Short snaplen: %u", 
		pcap_dev->proc_stat.packets, pcap_dev->proc_stat.skipped, 
		pcap_dev->proc_stat.unknown, pcap_dev->proc_stat.short_snap);
	LogInfo("Terminating packet dumping: exit: %i", args->exit);
	dbg_printf("End packet thread[%lu]\n", (long unsigned)args->tid);

	pthread_exit((void *)args);
	/* NOTREACHED */

} /* End of p_packet_thread */