/** * 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++; } } }
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; }