Exemple #1
0
static int sd_accept(t_addr const * curr_laddr, t_laddr_info const * laddr_info, int ssocket, int usocket)
{
    char               tempa[32];
    int                csocket;
    struct sockaddr_in caddr;
    psock_t_socklen    caddr_len;
    unsigned int       raddr;
    unsigned short     rport;

    if (!addr_get_addr_str(curr_laddr,tempa,sizeof(tempa)))
	strcpy(tempa,"x.x.x.x:x");

    /* accept the connection */
    memset(&caddr,0,sizeof(caddr)); /* not sure if this is needed... modern systems are ok anyway */
    caddr_len = sizeof(caddr);
    if ((csocket = psock_accept(ssocket,(struct sockaddr *)&caddr,&caddr_len))<0)
    {
	/* BSD, POSIX error for aborted connections, SYSV often uses EAGAIN or EPROTO */
	if (
#ifdef PSOCK_EWOULDBLOCK
	    psock_errno()==PSOCK_EWOULDBLOCK ||
#endif
#ifdef PSOCK_ECONNABORTED
	    psock_errno()==PSOCK_ECONNABORTED ||
#endif
#ifdef PSOCK_EPROTO
	    psock_errno()==PSOCK_EPROTO ||
#endif
	    0)
	    eventlog(eventlog_level_error,"sd_accept","client aborted connection on %s (psock_accept: %s)",tempa,strerror(psock_errno()));
	else /* EAGAIN can mean out of resources _or_ connection aborted :( */
	    if (
#ifdef PSOCK_EINTR
		psock_errno()!=PSOCK_EINTR &&
#endif
		1)
		eventlog(eventlog_level_error,"sd_accept","could not accept new connection on %s (psock_accept: %s)",tempa,strerror(psock_errno()));
	return -1;
    }

#ifdef HAVE_POLL
    if (csocket>=BNETD_MAX_SOCKETS) /* This check is a bit too strict (csocket is probably
                                     * greater than the number of connections) but this makes
                                     * life easier later.
                                     */
    {
	eventlog(eventlog_level_error,"sd_accept","csocket is beyond range allowed by BNETD_MAX_SOCKETS for poll() (%d>=%d)",csocket,BNETD_MAX_SOCKETS);
	psock_close(csocket);
	return -1;
    }
#else
# ifdef FD_SETSIZE
    if (csocket>=FD_SETSIZE) /* fd_set size is determined at compile time */
    {
	eventlog(eventlog_level_error,"sd_accept","csocket is beyond range allowed by FD_SETSIZE for select() (%d>=%d)",csocket,FD_SETSIZE);
	psock_close(csocket);
	return -1;
    }
# endif
#endif
    if (ipbanlist_check(inet_ntoa(caddr.sin_addr))!=0)
    {
	eventlog(eventlog_level_info,"sd_accept","[%d] connection from banned address %s denied (closing connection)",csocket,inet_ntoa(caddr.sin_addr));
	psock_close(csocket);
	return -1;
    }

    eventlog(eventlog_level_info,"sd_accept","[%d] accepted connection from %s on %s",csocket,addr_num_to_addr_str(ntohl(caddr.sin_addr.s_addr),ntohs(caddr.sin_port)),tempa);

    if (prefs_get_use_keepalive())
    {
	int val=1;

	if (psock_setsockopt(csocket,PSOCK_SOL_SOCKET,PSOCK_SO_KEEPALIVE,&val,(psock_t_socklen)sizeof(val))<0)
	    eventlog(eventlog_level_error,"sd_accept","[%d] could not set socket option SO_KEEPALIVE (psock_setsockopt: %s)",csocket,strerror(psock_errno()));
	/* not a fatal error */
    }

    {
	struct sockaddr_in rsaddr;
	psock_t_socklen    rlen;

	memset(&rsaddr,0,sizeof(rsaddr)); /* not sure if this is needed... modern systems are ok anyway */
	rlen = sizeof(rsaddr);
	if (psock_getsockname(csocket,(struct sockaddr *)&rsaddr,&rlen)<0)
	{
	    eventlog(eventlog_level_error,"sd_accept","[%d] unable to determine real local port (psock_getsockname: %s)",csocket,strerror(psock_errno()));
	    /* not a fatal error */
	    raddr = addr_get_ip(curr_laddr);
	    rport = addr_get_port(curr_laddr);
	}
	else
	{
	    if (rsaddr.sin_family!=PSOCK_AF_INET)
	    {
		eventlog(eventlog_level_error,"sd_accept","local address returned with bad address family %d",(int)rsaddr.sin_family);
		/* not a fatal error */
		raddr = addr_get_ip(curr_laddr);
		rport = addr_get_port(curr_laddr);
	    }
	    else
	    {
		raddr = ntohl(rsaddr.sin_addr.s_addr);
		rport = ntohs(rsaddr.sin_port);
	    }
	}
    }

    if (psock_ctl(csocket,PSOCK_NONBLOCK)<0)
    {
	eventlog(eventlog_level_error,"sd_accept","[%d] could not set TCP socket to non-blocking mode (closing connection) (psock_ctl: %s)",csocket,strerror(psock_errno()));
	psock_close(csocket);
	return -1;
    }

    {
	t_connection * c;

	if (!(c = conn_create(csocket,usocket,raddr,rport,addr_get_ip(curr_laddr),addr_get_port(curr_laddr),ntohl(caddr.sin_addr.s_addr),ntohs(caddr.sin_port))))
	{
	    eventlog(eventlog_level_error,"sd_accept","[%d] unable to create new connection (closing connection)",csocket);
	    psock_close(csocket);
	    return -1;
	}

	eventlog(eventlog_level_debug,"sd_accept","[%d] client connected to a %s listening address",csocket,laddr_type_get_str(laddr_info->type));
	switch (laddr_info->type)
	{
	case laddr_type_irc:
	    conn_set_class(c,conn_class_irc);
	    conn_set_state(c,conn_state_connected);
	    break;
	case laddr_type_telnet:
	    conn_set_class(c,conn_class_telnet);
	    conn_set_state(c,conn_state_connected);
	    break;
	case laddr_type_bnet:
	default:
	    /* We have to wait for an initial "magic" byte on bnet connections to
             * tell us exactly what connection class we are dealing with.
             */
	    break;
	}
    }

    return 0;
}
Exemple #2
0
extern int handle_init_packet(t_connection * c, t_packet const * const packet)
{
	if (!c)
	{
		eventlog(eventlog_level_error,__FUNCTION__,"[%d] got NULL connection",conn_get_socket(c));
		return -1;
	}
	if (!packet)
	{
		eventlog(eventlog_level_error,__FUNCTION__,"[%d] got NULL packet",conn_get_socket(c));
		return -1;
	}

	switch (packet_get_type(packet))
	{
	case MIRROR_GREET:
		if (packet_get_class(packet)!=packet_mirror_greet)
		{
			eventlog(eventlog_level_error,__FUNCTION__,"[%d] got bad packet (class %d)",conn_get_socket(c),(int)packet_get_class(packet));
			return -1;
		}
		conn_set_addr(c, packet->u.mirror_greet.remote_addr);
		conn_set_port(c, packet->u.mirror_greet.remote_port);
		eventlog(eventlog_level_info,__FUNCTION__,"[%d] mirror greet detected for %s", conn_get_socket(c), addr_num_to_addr_str(conn_get_addr(c),conn_get_port(c)));
		conn_set_mirror(c, 2);
		if (ipbanlist_check(addr_num_to_ip_str(conn_get_addr(c)))!=0)
		{
			return -1;
		}
		if ((prefs_get_max_conns_per_IP()!=0) && (connlist_count_connections(conn_get_addr(c)) > prefs_get_max_conns_per_IP()))
		{
			return -1;
		}
		break;
	case CLIENT_INITCONN:
		if (packet_get_class(packet)!=packet_class_init)
		{
			eventlog(eventlog_level_error,__FUNCTION__,"[%d] got bad packet (class %d)",conn_get_socket(c),(int)packet_get_class(packet));
			return -1;
		}
		switch (bn_byte_get(packet->u.client_initconn.class))
		{
		case CLIENT_INITCONN_CLASS_BNET:
			eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated bnet connection",conn_get_socket(c));
			conn_set_state(c,conn_state_connected);
			conn_set_class(c,conn_class_bnet);

			break;

		case CLIENT_INITCONN_CLASS_FILE:
			eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated file download connection",conn_get_socket(c));
			conn_set_state(c,conn_state_connected);
			conn_set_class(c,conn_class_file);

			break;

		case CLIENT_INITCONN_CLASS_BOT:
			eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated chat bot connection",conn_get_socket(c));
			conn_set_state(c,conn_state_connected);
			conn_set_class(c,conn_class_bot);

			break;

		case CLIENT_INITCONN_CLASS_TELNET:
			eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated telnet connection",conn_get_socket(c));
			conn_set_state(c,conn_state_connected);
			conn_set_class(c,conn_class_telnet);

			break;

		case CLIENT_INITCONN_CLASS_D2CS_BNETD:
			{
				eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated d2cs_bnetd connection",conn_get_socket(c));

				if (!(realmlist_find_realm_by_ip(conn_get_addr(c))))
				{
					eventlog(eventlog_level_info,__FUNCTION__, "[%d] d2cs connection from unknown ip address %s",conn_get_socket(c),addr_num_to_addr_str(conn_get_addr(c),conn_get_port(c)));
					return -1;
				}

				conn_set_state(c,conn_state_connected);
				conn_set_class(c,conn_class_d2cs_bnetd);
				if (handle_d2cs_init(c)<0)
				{
					eventlog(eventlog_level_info,__FUNCTION__,"faild to init d2cs connection");
					return -1;
				}
			}
			break;

		case CLIENT_INITCONN_CLASS_ENC:
			eventlog(eventlog_level_info,__FUNCTION__,"[%d] client initiated encrypted connection (not supported)",conn_get_socket(c));
			return -1;

		default:
			eventlog(eventlog_level_error,__FUNCTION__,"[%d] client requested unknown class 0x%02x (length %d) (closing connection)",conn_get_socket(c),(unsigned int)bn_byte_get(packet->u.client_initconn.class),packet_get_size(packet));
			return -1;
		}
		break;
	default:
		eventlog(eventlog_level_error,__FUNCTION__,"[%d] unknown init packet type 0x%04x, len %u",conn_get_socket(c),packet_get_type(packet),packet_get_size(packet));
		return -1;
	}

	return 0;
}