Example #1
0
/**
 * This checks the sockets for input and exceptions, does the right
 * thing.
 *
 * There are 2 lists we need to look through - init_sockets is a list */
void doeric_server()
{
	int i, pollret, rr;
	struct sockaddr_in addr;
	socklen_t addrlen = sizeof(addr);
	player *pl, *next;

#if CS_LOGSTATS
	if ((time(NULL) - cst_lst.time_start) >= CS_LOGTIME)
	{
		write_cs_stats();
	}
#endif

	FD_ZERO(&tmp_read);
	FD_ZERO(&tmp_write);
	FD_ZERO(&tmp_exceptions);

	for (i = 0; i < socket_info.allocated_sockets; i++)
	{
		if (init_sockets[i].status == Ns_Add && !is_fd_valid(init_sockets[i].fd))
		{
			LOG(llevDebug, "doeric_server(): Invalid waiting fd %d\n", i);
			init_sockets[i].status = Ns_Dead;
		}

		if (init_sockets[i].status == Ns_Dead)
		{
			FREE_SOCKET(i);
		}
		else if (init_sockets[i].status == Ns_Zombie)
		{
			if (init_sockets[i].login_count++ >= 1000000 / MAX_TIME)
			{
				init_sockets[i].status = Ns_Dead;
			}
		}
		else if (init_sockets[i].status != Ns_Avail)
		{
			if (init_sockets[i].status > Ns_Wait)
			{
				/* Kill this socket after being 3 minutes idle */
				if (init_sockets[i].login_count++ >= 60 * 4 * (1000000 / MAX_TIME))
				{
					FREE_SOCKET(i);
					continue;
				}
			}

			FD_SET((uint32) init_sockets[i].fd, &tmp_read);
			FD_SET((uint32) init_sockets[i].fd, &tmp_write);
			FD_SET((uint32) init_sockets[i].fd, &tmp_exceptions);
		}
	}

	/* Go through the players. Let the loop set the next pl value, since
	 * we may remove some. */
	for (pl = first_player; pl != NULL; )
	{
		if (pl->socket.status != Ns_Dead && !is_fd_valid(pl->socket.fd))
		{
			LOG(llevDebug, "doeric_server(): Invalid file descriptor for player %s [%s]: %d\n", (pl->ob && pl->ob->name) ? pl->ob->name : "(unnamed player?)", (pl->socket.host) ? pl->socket.host : "(unknown ip?)", pl->socket.fd);
			pl->socket.status = Ns_Dead;
		}

		if (pl->socket.status == Ns_Dead)
		{
			player *npl = pl->next;

			remove_ns_dead_player(pl);
			pl = npl;
		}
		else if (pl->socket.status == Ns_Zombie)
		{
			if (pl->socket.login_count++ >= 1000000 / MAX_TIME)
			{
				pl->socket.status = Ns_Dead;
			}
		}
		else
		{
			FD_SET((uint32) pl->socket.fd, &tmp_read);
			FD_SET((uint32) pl->socket.fd, &tmp_write);
			FD_SET((uint32) pl->socket.fd, &tmp_exceptions);
			pl = pl->next;
		}
	}

	socket_info.timeout.tv_sec = 0;
	socket_info.timeout.tv_usec = 0;

	pollret = select(socket_info.max_filedescriptor, &tmp_read, &tmp_write, &tmp_exceptions, &socket_info.timeout);

	if (pollret == -1)
	{
		LOG(llevDebug, "DEBUG: doeric_server(): select failed: %s\n", strerror_local(errno));
		return;
	}

	/* Following adds a new connection */
	if (pollret && FD_ISSET(init_sockets[0].fd, &tmp_read))
	{
		int newsocknum = 0;

		/* If this is the case, all sockets are currently in use */
		if (socket_info.allocated_sockets <= socket_info.nconns)
		{
			init_sockets = realloc(init_sockets, sizeof(socket_struct) * (socket_info.nconns + 1));

			if (!init_sockets)
			{
				LOG(llevError, "ERROR: doeric_server(): Out of memory\n");
			}

			newsocknum = socket_info.allocated_sockets;
			socket_info.allocated_sockets++;
			init_sockets[newsocknum].status = Ns_Avail;
		}
		else
		{
			int j;

			for (j = 1; j < socket_info.allocated_sockets; j++)
			{
				if (init_sockets[j].status == Ns_Avail)
				{
					newsocknum = j;
					break;
				}
			}
		}

		init_sockets[newsocknum].fd = accept(init_sockets[0].fd, (struct sockaddr *) &addr, &addrlen);

		if (init_sockets[newsocknum].fd == -1)
		{
			LOG(llevDebug, "doeric_server(): accept failed: %s\n", strerror_local(errno));
		}
		else
		{
			char buf[MAX_BUF];
			long ip = ntohl(addr.sin_addr.s_addr);

			snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld", (ip >> 24) & 255, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);

			if (checkbanned(NULL, buf))
			{
				LOG(llevInfo, "BAN: Banned IP tried to connect. [%s]\n", buf);
#ifndef WIN32
				close(init_sockets[newsocknum].fd);
#else
				shutdown(init_sockets[newsocknum].fd, SD_BOTH);
				closesocket(init_sockets[newsocknum].fd);
#endif
				init_sockets[newsocknum].fd = -1;
			}
			else
			{
				init_connection(&init_sockets[newsocknum], buf);
				socket_info.nconns++;
			}
		}
	}
Example #2
0
static PF_FORWARD_ACTION filter_cb(unsigned char *header, unsigned char *packet, unsigned int len, unsigned int recvindex, unsigned int sendindex, IPAddr nextrecvhop, IPAddr nextsendhop)
{
	PGNOTIFICATION pgn={0};
	const IP_HEADER *iph=(IP_HEADER*)header;
	const PGIPRANGE *range=NULL;
	const ULONG src=NTOHL(iph->ipSource);
	const ULONG dest=NTOHL(iph->ipDestination);
	USHORT srcport=0;
	USHORT destport=0;
	int opening=1;
	int http = 0;
	int forced_log = 0;

	//if the protocol is TCP or UDP
	if(iph->ipProtocol==6 || iph->ipProtocol==17)
	{
		const TCP_HEADER *tcp=(TCP_HEADER*)packet;
		srcport=NTOHS(tcp->sourcePort);
		destport=NTOHS(tcp->destinationPort);

		if(iph->ipProtocol==6)
		{
			opening=(tcp->ack==0);

			if(!g_internal->blockhttp && (srcport==80 || srcport==443 || destport==80 || destport==443))
			{
				http = 1;
			}
		}
	}

	if(!http)
	{
		KIRQL irq;

		KeAcquireSpinLock(&g_internal->rangeslock, &irq);

		//TODO: test allowed ranges.
		// -> beez : this is not working
		if(g_internal->allowedcount) 
		{
			range = inranges(g_internal->allowedranges, g_internal->allowedcount, src);
			if(!range) 
				range = inranges(g_internal->allowedranges, g_internal->allowedcount, dest);

			if(range)
			{
				pgn.label = range->label;
				pgn.labelsid = g_internal->allowedlabelsid;
				pgn.action = 1;
			}
		}

		if(!range && g_internal->blockedcount)
		{
			range=inranges(g_internal->blockedranges, g_internal->blockedcount, src);
			if(!range) 
				range=inranges(g_internal->blockedranges, g_internal->blockedcount, dest);

			if(range)
			{
				pgn.label = range->label;
				pgn.labelsid = g_internal->blockedlabelsid;
				pgn.action = 0;
			}
		}

		KeReleaseSpinLock(&g_internal->rangeslock, irq);
	}
	
	//seems like connection is oppening up. This means no special action
	if(!range)
	{
		pgn.action = 2;
	}

	//we filter only incomming and not already processed trafic for ports and connections
	if( sendindex == INVALID_PF_IF_INDEX && range == NULL && http == 0 )
	{
		unsigned int i;
		for(i=0;i<g_internal->perma_allow_list_length;i++)
			if( src == g_internal->perma_allow_list[ i ] )
				break;
		if( i == g_internal->perma_allow_list_length )
		{
			//he is sending us a TCP or UDP packet and we test if our port is open. 
			//If not he does not know about our open ports then we can ban him since he is scanning us
			if( destport != 0 && g_internal->f_port_open_ports[ destport ] == 0 && g_internal->disable_port_scan_detector == 0)
			{
#ifdef USE_FIXED_LIST
				CheckInsertedAndAddIPForBan( src );
#else
				Addbanned( src );
#endif
				forced_log = 1;
				pgn.action = 20;

			}
			//a new tcp connection. See if he is spamming connections
			else if( opening && g_internal->disable_connection_flood_detector == 0 ) 
			{
				//check if we are already banning this IP
#ifdef USE_FIXED_LIST
				int i;
				for(i=0;i<TEMP_BLOCK_LIST;i++)
					if( g_internal->temp_connection_flood_banns[ i ] == src )
					{
						forced_log = 1;
						pgn.action = 30;
						break;
					}
#else
				if( checkbanned( src ) != 0 )
				{
					forced_log = 1;
					pgn.action = 30;
				}
#endif
				//not yet in banlist then check if we should add it
				if( forced_log == 0 )
				{
					if( src == g_internal->f_cons_last_received_IP )
					{
						g_internal->f_cons_last_received_IP_count++;
						if( g_internal->f_cons_last_received_IP_count >= g_internal->f_cons_last_received_IP_count_limit )
						{
							//yes he is a flooder
#ifdef USE_FIXED_LIST
							g_internal->temp_connection_flood_banns[ g_internal->temp_block_count ] = src;
							g_internal->temp_block_count = (g_internal->temp_block_count + 1) & TEMP_BLOCK_LIST_MASK;
#else
							Addbanned( src );
#endif
							forced_log = 1;
							pgn.action = 30;
						}
					}
					else
					{
						//memorize new IP to see how many times it will consecutively connect
						g_internal->f_cons_last_received_IP = src;
						g_internal->f_cons_last_received_IP_count = 0;
					}
				}
			}
		}
	}

	if( range || opening 
		|| ( forced_log == 1 && IsListEmpty( &g_internal->queue.irp_list ) && g_internal->blockhttp == 0 ) //this is required or on DDOS CPU usage will go to 100%..
		) 
	{
		pgn.protocol=iph->ipProtocol;

		pgn.source.addr4.sin_family = AF_INET;
		pgn.source.addr4.sin_addr.s_addr = iph->ipSource;
		pgn.source.addr4.sin_port = HTONS(srcport);

		pgn.dest.addr4.sin_family = AF_INET;
		pgn.dest.addr4.sin_addr.s_addr = iph->ipDestination;
		pgn.dest.addr4.sin_port = HTONS(destport);

		Notification_Send(&g_internal->queue, &pgn);

		if( pgn.action != 1 && pgn.action != 2 )
			return PF_DROP;
	}

	return PF_FORWARD;
}