Exemple #1
0
void PktAnalyzer::analyzer(Packet &pkt)
{
	Poco::Stopwatch sw;
	_logger.debug("Got packet from queue");

	unsigned char *full_packet=pkt.get_payload();
	int id = pkt.get_id();
	uint32_t size = pkt.get_size();
	struct nfq_q_handle *qh=pkt.get_qh();
	struct ip *iph = (struct ip *)full_packet;
	struct ip6_hdr *iph6 = (struct ip6_hdr *)full_packet;

	// определяем версию протокола
	int ip_version=0;
	if(iph->ip_v == 6)
		ip_version = 6;
	else if (iph->ip_v == 4)
		ip_version = 4;
	if(!ip_version)
	{
		_logger.error("Unsupported IP protocol version %d for packet id %d",(int) iph->ip_v, id);
		nfq_set_verdict(qh,id,NF_ACCEPT,0,NULL);
		dump_file(full_packet,size,id);
		return ;
	}

	unsigned char *pkt_data_ptr = NULL;
	struct tcphdr* tcph;

	pkt_data_ptr = full_packet + (ip_version == 4 ? sizeof(struct ip) : sizeof(struct ip6_hdr));

	tcph = (struct tcphdr *) pkt_data_ptr;

	// длина ip заголовка
	int iphlen = iphdr(full_packet)->ihl*4; // ipv4
	if(ip_version == 6)
		iphlen = sizeof(struct ip6_hdr);

	// длина tcp заголовка
	int tcphlen = tcphdr(full_packet+iphlen)->doff*4;

	// общая длина всех заголовков
	uint32_t hlen = iphlen + tcphlen;

	_parent->inc_total_bytes_packets(size);

	// пропускаем пакет без данных
	if(hlen == size)
	{
		nfq_set_verdict(qh,id,NF_ACCEPT,0,NULL);
		return ;
	}

	int tcp_src_port=ntohs(tcph->source);
	int tcp_dst_port=ntohs(tcph->dest);
	std::unique_ptr<Poco::Net::IPAddress> src_ip;
	std::unique_ptr<Poco::Net::IPAddress> dst_ip;
	if(ip_version == 4)
	{
		src_ip.reset(new Poco::Net::IPAddress(&iph->ip_src,sizeof(in_addr)));
		dst_ip.reset(new Poco::Net::IPAddress(&iph->ip_dst,sizeof(in_addr)));
	} else {
		src_ip.reset(new Poco::Net::IPAddress(&iph6->ip6_src,sizeof(in6_addr)));
		dst_ip.reset(new Poco::Net::IPAddress(&iph6->ip6_dst,sizeof(in6_addr)));
	}

	uint8_t ip_protocol=(ip_version == 4 ? iph->ip_p : iph6->ip6_ctlun.ip6_un1.ip6_un1_nxt);


	{
		Poco::ScopedReadRWLock lock(nfqFilter::_ipportMapMutex);
		IPPortMap::iterator it_ip=nfqFilter::_ipportMap->find(*dst_ip.get());
		if(it_ip != nfqFilter::_ipportMap->end())
		{
			unsigned short port=tcp_dst_port;
			if (it_ip->second.size() == 0 || it_ip->second.find(port) != it_ip->second.end())
			{
				_parent->inc_matched_ip_port();
				if(_config.send_rst)
				{
					_logger.debug("HostList: Send RST to the client (%s) and server (%s) (packet no %d)",src_ip->toString(),dst_ip->toString(),id);
					std::string empty_str;
					SenderTask::queue.enqueueNotification(new RedirectNotification(tcp_src_port, tcp_dst_port,src_ip.get(), dst_ip.get(),/*acknum*/ tcph->ack_seq, /*seqnum*/ tcph->seq,/* flag psh */ (tcph->psh ? 1 : 0 ),empty_str,true));
					_parent->inc_sended_rst();
					nfq_set_verdict(qh,id,NF_DROP,0,NULL);
				} else {
					_logger.debug("HostList: Set mark %d to packet no %d  port %hu",_config.mark_value,id,port);
					_parent->inc_marked_hosts();
					nfq_set_verdict2(qh,id,NF_ACCEPT,_config.mark_value,0,NULL);
				}
				return ;
			}
		}
	}


	// nDPI usage
	sw.reset();
	sw.start();
	nDPIWrapper nw;

	struct ndpi_flow_struct *flow=nw.get_flow();

	uint32_t current_tickt = 0;
	ndpi_protocol protocol = ndpi_detection_process_packet(nfqFilter::my_ndpi_struct, flow, full_packet, size, current_tickt, nw.get_src(), nw.get_dst());

	if(protocol.protocol == NDPI_PROTOCOL_UNKNOWN)
	{
		_logger.debug("Guessing protocol...");
		protocol = ndpi_guess_undetected_protocol(nfqFilter::my_ndpi_struct,
		   ip_protocol,
		   0,//ip
		   tcp_src_port, // sport
		   0,
		   tcp_dst_port); // dport
	}
	_logger.debug("Protocol is %hu/%hu ",protocol.master_protocol,protocol.protocol);
	sw.stop();
	_logger.debug("nDPI protocol detection occupied %ld us",sw.elapsed());
	if(protocol.master_protocol == NDPI_PROTOCOL_SSL || protocol.protocol == NDPI_PROTOCOL_SSL || protocol.protocol == NDPI_PROTOCOL_TOR)
	{
		if(flow->l4.tcp.ssl_seen_client_cert == 1)
		{
			std::string ssl_client;
			_logger.debug("Analysing SSL protocol");
			if(flow->protos.ssl.client_certificate[0] != '\0')
			{
				ssl_client=flow->protos.ssl.client_certificate;
				_logger.debug("SSL client is: %s",ssl_client);
			}
			if(!ssl_client.empty())
			{
				sw.reset();
				sw.start();
				if(_config.lower_host)
					std::transform(ssl_client.begin(), ssl_client.end(), ssl_client.begin(), ::tolower);
				AhoCorasickPlus::Match match;
				std::size_t host_len=ssl_client.length();
				bool found=false;
				{
					Poco::Mutex::ScopedLock lock(nfqFilter::_sslMutex);
					nfqFilter::atm_ssl->search(ssl_client,false);
					while(nfqFilter::atm_ssl->findNext(match) && !found)
					{
						if(match.pattern.length != host_len)
						{
							DomainsMatchType::Iterator it=nfqFilter::_SSLdomainsMatchType->find(match.id);
							bool exact_match=false;
							if(it != nfqFilter::_SSLdomainsMatchType->end())
								exact_match = it->second;
							if(exact_match)
								continue;
							if(ssl_client[host_len-match.pattern.length-1] != '.')
								continue;
						}
						found=true;
					}
				}
				sw.stop();
				_logger.debug("SSL Host seek occupied %ld us, host: %s",sw.elapsed(),ssl_client);
				if(found)
				{
					_parent->inc_matched_ssl();
					if(_config.send_rst)
					{
						_logger.debug("SSLHostList: Send RST to the client (%s) and server (%s) (packet no %d)",src_ip->toString(),dst_ip->toString(),id);
						std::string empty_str;
						SenderTask::queue.enqueueNotification(new RedirectNotification(tcp_src_port, tcp_dst_port,src_ip.get(), dst_ip.get(),/*acknum*/ tcph->ack_seq, /*seqnum*/ tcph->seq,/* flag psh */ (tcph->psh ? 1 : 0 ),empty_str,true));
						_parent->inc_sended_rst();
						nfq_set_verdict(qh,id,NF_DROP,0,NULL);
					} else {
						_logger.debug("SSLHostList: Set mark %d to packet no %d, ssl host name: %s",_config.mark_value,id,ssl_client);
						_parent->inc_marked_ssl();
						nfq_set_verdict2(qh,id,NF_ACCEPT,_config.mark_value,0,NULL);
					}
					return ;
				} else {
					nfq_set_verdict(qh,id,NF_ACCEPT,0,NULL);
					return ;
				}
			} else {
				if(_config.block_undetected_ssl)
				{
					Poco::ScopedReadRWLock lock(nfqFilter::_sslIpsSetMutex);
					if(nfqFilter::_sslIps->try_search_exact_ip(*dst_ip.get()))
					{
						_parent->inc_matched_ssl_ip();
						_logger.debug("Blocking/Marking SSL client hello packet from %s:%d to %s:%d", src_ip->toString(),tcp_src_port,dst_ip->toString(),tcp_dst_port);
						if(_config.send_rst)
						{
							_logger.debug("SSLClientHello: Send RST to the client (%s) and server (%s) (packet no %d)",src_ip->toString(),dst_ip->toString(),id);
							std::string empty_str;
							SenderTask::queue.enqueueNotification(new RedirectNotification(tcp_src_port, tcp_dst_port,src_ip.get(), dst_ip.get(),/*acknum*/ tcph->ack_seq, /*seqnum*/ tcph->seq,/* flag psh */ (tcph->psh ? 1 : 0 ),empty_str,true));
							_parent->inc_sended_rst();
							nfq_set_verdict(qh,id,NF_DROP,0,NULL);
						} else {
							_logger.debug("SSLClientHello: Set mark %d to packet no %d",_config.mark_value,id);
							_parent->inc_marked_ssl();
							nfq_set_verdict2(qh,id,NF_ACCEPT,_config.mark_value,0,NULL);
						}
						return ;
					}
				}
				_logger.debug("No ssl client certificate found! Accept packet from %s:%d to %s:%d.",src_ip->toString(),tcp_src_port,dst_ip->toString(),tcp_dst_port);
			}
		}
		nfq_set_verdict(qh,id,NF_ACCEPT,0,NULL);
		return ;
	}
	if(protocol.master_protocol != NDPI_PROTOCOL_HTTP && protocol.protocol != NDPI_PROTOCOL_HTTP && protocol.protocol != NDPI_PROTOCOL_DIRECT_DOWNLOAD_LINK)
	{
		_logger.debug("Not http protocol. Protocol is %hu/%hu from %s:%d to %s:%d",protocol.master_protocol,protocol.protocol,src_ip->toString(),tcp_src_port,dst_ip->toString(),tcp_dst_port);
		nfq_set_verdict(qh,id,NF_ACCEPT,0,NULL);
		return ;
	}

	_logger.debug("Got HTTP protocol");

	std::string host((char *)&flow->host_server_name[0]);
	if((flow->http.method == HTTP_METHOD_GET || flow->http.method == HTTP_METHOD_POST || flow->http.method == HTTP_METHOD_HEAD) && !host.empty())
	{
		int dot_del=0;
		if(host[host.length()-1] == '.')
		{
			dot_del=host.length()-1;
			host.erase(dot_del,1);
		}
		if(_config.lower_host)
			std::transform(host.begin(), host.end(), host.begin(), ::tolower);
		sw.reset();
		sw.start();

		AhoCorasickPlus::Match match;
		bool found=false;
		{
			Poco::Mutex::ScopedLock lock(nfqFilter::_domainMapMutex);
			nfqFilter::atm_domains->search(host,false);
			std::size_t host_len=host.length();
			while(nfqFilter::atm_domains->findNext(match) && !found)
			{
				if(match.pattern.length != host_len)
				{
					DomainsMatchType::Iterator it=nfqFilter::_domainsMatchType->find(match.id);
					bool exact_match=false;
					if(it != nfqFilter::_domainsMatchType->end())
						exact_match = it->second;
					if(exact_match)
						continue;
					if(host[host_len-match.pattern.length-1] != '.')
						continue;
				}
				found=true;
			}
		}
		sw.stop();
		_logger.debug("Host seek occupied %ld us",sw.elapsed());
		if(found)
		{
			_logger.debug("Host %s present in domain (file line %d) list from ip %s", host, match.id, src_ip->toString());
			std::string add_param;
			switch (_config.add_p_type)
			{
				case A_TYPE_ID: add_param="id="+std::to_string(match.id);
						break;
				case A_TYPE_URL: add_param="url="+host;
						break;
				default: break;
			}
			SenderTask::queue.enqueueNotification(new RedirectNotification(tcp_src_port, tcp_dst_port, src_ip.get(), dst_ip.get(),/*acknum*/ tcph->ack_seq, /*seqnum*/ tcph->seq,/* flag psh */ (tcph->psh ? 1 : 0 ),add_param));
			_parent->inc_redirected_domains();
			nfq_set_verdict(qh,id,NF_DROP,0,NULL);
			return ;
		}
		sw.reset();
		sw.start();
		found=false;
		std::string uri_o(flow->http.url ? flow->http.url : "");
		if(flow->http.url)
		{
			std::string uri;
			if(dot_del)
				uri_o.erase(dot_del+7,1);
			try
			{
				Poco::URI uri_p(uri_o);
				uri_p.normalize();
				uri.assign(uri_p.toString());
				if(_config.url_decode)
				{
#ifdef __USE_POCO_URI_DECODE
					Poco::URI::decode(uri_p.toString(),uri);
#else
					uri=url_decode(uri);
#endif
				}
			} catch (Poco::SyntaxException &ex)
			{
				_logger.debug("An SyntaxException occured: '%s' on URI: '%s'",ex.displayText(), uri_o);
				uri.assign(flow->http.url);
			}

			{
				Poco::Mutex::ScopedLock lock(nfqFilter::_urlMapMutex);
				nfqFilter::atm->search(uri,false);
				while(nfqFilter::atm->findNext(match) && !found)
				{
					if(_config.match_url_exactly && uri.length() != match.pattern.length)
						continue;
					found=true;
				}
			}
			sw.stop();
			_logger.debug("URL seek occupied %ld us for uri %s",sw.elapsed(),uri);
			if(found)
			{
				_logger.debug("URL %s present in url (file pos %u) list from ip %s",uri,match.id,src_ip->toString());
				std::string add_param;
				switch (_config.add_p_type)
				{
					case A_TYPE_ID: add_param="id="+std::to_string(match.id);
							break;
					case A_TYPE_URL: add_param="url="+uri;
							break;
						default: break;
				}
				SenderTask::queue.enqueueNotification(new RedirectNotification(tcp_src_port, tcp_dst_port,src_ip.get(),dst_ip.get(),/*acknum*/ tcph->ack_seq, /*seqnum*/ tcph->seq,/* flag psh */ (tcph->psh ? 1 : 0 ),add_param));
				_parent->inc_redirected_urls();
				nfq_set_verdict(qh,id,NF_DROP,0,NULL);
				return ;
			}
		}
	}
	nfq_set_verdict(qh,id,NF_ACCEPT,0,NULL);
}
void PlayerThread::run() {
	unsigned char iPacket;
	Poco::Stopwatch Timer;

	_fRunning=true;

	Timer.start();
	while (_fRunning) {
		if (!isAssigned()) {
			while(!isAssigned()) {
				if (_fRunning==false) { break; }
				Thread::sleep(50);
			}
			if (_fRunning==false) { continue; }
			Timer.reset();
		} 


		try {
			//Thread Ticks
			Timer.stop();
			_iThreadTicks += Timer.elapsed() / 1000;
			Timer.reset();
			Timer.start();


			if (!_fSpawned && _iThreadTicks >= FC_MAXLOGINTIME) {
				Disconnect("Login timed out");
				continue;
			}

			Interval_KeepAlive(); 
			Interval_Time();
			Interval_HandleMovement();
			Interval_Movement();
			Interval_CalculateSpeed();
			Interval_CheckPosition();
			Interval_CheckEating();


			iPacket = _NetworkInRoot.readByte();

			if (!_fSpawned &&  (iPacket!=0x01 && iPacket!=0x02 && iPacket!=0xFE)) {
				Disconnect("Login not done!");
				continue;
			}

			//cout<<"Package recovered:"<<std::hex<<int(iPacket)<<"\n";
			switch (iPacket) {
			case 0x0:
				Packet0_KeepAlive();
				break;
			case 0x1:
				if (isSpawned()) {
					Disconnect("Login already done!");
					continue;
				}
				Packet1_Login();
				break;
			case 0x2:
				if (isSpawned()) {
					Disconnect("Login already done!");
					continue;
				}
				Packet2_Handshake();
				break;
			case 0x3:
				Packet3_Chat();
				break;
			case 0xa: 
				Packet10_Player();
				break;
			case 0xb:
				Packet11_Position();
				break;
			case 0xc: 
				Packet12_Look();
				break;
			case 0xd: 
				Packet13_PosAndLook();
				break;
			case 0xe:
				Packet14_Digging();
				break;
			case 0xf: 
				Packet15_PlayerBlockPlacement();
				break;
			case 0x10: 
				Packet16_HoldingChange();
				break;
			case 0x12: 
				Packet18_Animation();
				break;
			case 0x13: 
				Packet19_EntityAction();
				break;
			case 0x65: 
				Packet101_CloseWindow();
				break;
			case 0x66:
				Packet102_WindowClick();
				break;
			case 0xFE: //Server List Ping
				Packet254_ServerListPing();
				break;
			case 0xFF: //Disconnect
				Packet255_Disconnect();
				break;
			default: 
				Disconnect("Unknown packet!");
				cout<<"Unknown packet received! 0x"<<std::hex<<int(iPacket)<<endl;
				break;
			}
		} catch (Poco::RuntimeException) {
			Disconnect(FC_LEAVE_OTHER);
		}
	}
	if(_fAssigned){Disconnect(FC_LEAVE_OTHER);}
	_fRunning=true;
}