Esempio n. 1
0
extern int handle_d2cs_packet(t_connection * c, t_packet const * packet)
{
	if (!c) {
		eventlog(eventlog_level_error,__FUNCTION__,"got NULL connection");
		return -1;
	}
	if (!packet) {
		eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
		return -1;
	}
	if (packet_get_class(packet)!=packet_class_d2cs_bnetd) {
		eventlog(eventlog_level_error,__FUNCTION__,"got bad packet class %d",
		packet_get_class(packet));
		return -1;
	}
	switch (conn_get_state(c)) {
		case conn_state_connected:
			switch (packet_get_type(packet)) {
				case D2CS_BNETD_AUTHREPLY:
					on_d2cs_authreply(c,packet);
					break;
				default:
					eventlog(eventlog_level_error,__FUNCTION__,
					"got unknown packet type %d",packet_get_type(packet));
					break;
			}
			break;
		case conn_state_loggedin:
			switch (packet_get_type(packet)) {
				case D2CS_BNETD_ACCOUNTLOGINREQ:
					on_d2cs_accountloginreq(c,packet);
					break;
				case D2CS_BNETD_CHARLOGINREQ:
					on_d2cs_charloginreq(c,packet);
					break;
				case D2CS_BNETD_GAMEINFOREPLY:
					on_d2cs_gameinforeply(c,packet);
					break;
				default:
					eventlog(eventlog_level_error,__FUNCTION__,
					"got unknown packet type %d",packet_get_type(packet));
					break;
			}
			break;
		default:
			eventlog(eventlog_level_error,__FUNCTION__,
				"got unknown connection state %d",conn_get_state(c));
			break;
	}
	return 0;
}
Esempio n. 2
0
/*!
 * @brief Call the dispatch routine for a given command.
 * @param command The command to call the dispatch routine on.
 * @param remote Pointer to the remote connection.
 * @param packet Pointer to the current packet.
 * @return Result of the command dispatch handler call.
 */
 DWORD command_call_dispatch(Command *command, Remote *remote, Packet *packet)
{
	DWORD res;

	// Validate the arguments, if requested.  Always make sure argument 
	// lengths are sane.
	if ((res = command_validate_arguments(command, packet)) != ERROR_SUCCESS)
		return res;

	switch (packet_get_type(packet))
	{
	case PACKET_TLV_TYPE_REQUEST:
	case PACKET_TLV_TYPE_PLAIN_REQUEST:
		if (command->request.handler)
			res = command->request.handler(remote, packet);
		break;
	case PACKET_TLV_TYPE_RESPONSE:
	case PACKET_TLV_TYPE_PLAIN_RESPONSE:
		if (command->response.handler)
			res = command->response.handler(remote, packet);
		break;
	default:
		res = ERROR_NOT_FOUND;
		break;
	}

	return res;
}
Esempio n. 3
0
// returns the next byte to send - first the packet type, then the data length
// then the channel and then the data (len bytes).
//
// Used by UART code to include type and length in packet
//
// returns -1 if empty
static int16_t read_char_from_packet(packet_t *buf) {
        int16_t rv = -1;
        switch (txstate) {
        case TX_TYPE:
                txstate = TX_LEN;
                rv = 0xff & packet_get_type(buf);
//if (rv == FS_TERM && packet_get_chan(buf) == FSFD_SETOPT) led_on();
                break;
        case TX_LEN:
                txstate = TX_CHANNEL;
                rv = (0xff & packet_get_contentlen(buf)) + 3;	// plus 2 to adhere to packet wire format
		break;
	case TX_CHANNEL:
		rv = 0xff & packet_get_chan(buf);
                if (packet_get_contentlen(buf) == 0) {
                        txstate = TX_IDLE;
                } else {
                        txstate = TX_DATA;
                }
                break;
        case TX_DATA:
                rv = 0xff & packet_read_char(buf);
                if (!packet_has_data(buf)) {
                        txstate = TX_IDLE;
                }
                break;
        default:
                break;
        }
        return rv;
}
Esempio n. 4
0
int packet_get_length(Packet* packet)
{	
	_Packet* p = (_Packet*)packet;

	switch (packet_get_type(packet))
	{
		case PACKET_TYPE_SEND_MESSAGE:
		{
			return packet_get_byte(packet, SEND_MESSAGE_LENGTH) + 2;
			break;
		}
		case PACKET_TYPE_SEND_NAME:
		{
			return packet_get_byte(packet, SEND_NAME_LENGTH) + 2;
			break;
		}
		case PACKET_TYPE_PACKETS:
		{
			int num_packets;
			return packet_packet_get_length(p, &num_packets);
			break;
		}
		default:
		{
			return PACKET_SIZES[(int)(p->type)];
			break;
		}
	}
}
Esempio n. 5
0
/*
 * Validate command arguments
 */
DWORD command_validate_arguments(Command *command, Packet *packet)
{
	PacketDispatcher *dispatcher = NULL;
	PacketTlvType type = packet_get_type(packet);
	DWORD res = ERROR_SUCCESS, 
		packetIndex, commandIndex;
	Tlv current;

	// Select the dispatcher table
	if ((type == PACKET_TLV_TYPE_RESPONSE) ||
	    (type == PACKET_TLV_TYPE_PLAIN_RESPONSE))
		dispatcher = &command->response;
	else
		dispatcher = &command->request;

	// Enumerate the arguments, validating the meta types of each
	for (commandIndex = 0, packetIndex = 0;
	     ((packet_enum_tlv(packet, packetIndex, TLV_TYPE_ANY, &current) 
			 == ERROR_SUCCESS) &&
	      (res == ERROR_SUCCESS));
	     commandIndex++, packetIndex++)
	{
		TlvMetaType tlvMetaType;

		// Check to see if we've reached the end of the command arguments
		if ((dispatcher->numArgumentTypes) &&
		    (commandIndex == (dispatcher->numArgumentTypes & ARGUMENT_FLAG_MASK)))
		{
			// If the repeat flag is set, reset the index
			if (commandIndex & ARGUMENT_FLAG_REPEAT)
				commandIndex = 0;
			else
				break;
		}
		
		// Make sure the argument is at least one of the meta types
		tlvMetaType = packet_get_tlv_meta(packet, &current);

		// Validate argument meta types
		switch (tlvMetaType)
		{
			case TLV_META_TYPE_STRING:
				if (packet_is_tlv_null_terminated(packet, &current) != ERROR_SUCCESS)
					res = ERROR_INVALID_PARAMETER;
				break;
			default:
				break;
		}
	
		if ((res != ERROR_SUCCESS) && 
		    (commandIndex < dispatcher->numArgumentTypes))
			break;
	}

	return res;
}
Esempio n. 6
0
void packet_add_packet(Packet** packet_packet_pointer, Packet* packet)
{
	Packet* packet_packet = *packet_packet_pointer;
	
	assert(packet_get_type(packet_packet) == PACKET_TYPE_PACKETS);
	assert(packet_get_type(packet) != PACKET_TYPE_PACKETS);
	
	int num_packets;
	int length = packet_packet_get_length((_Packet*)packet_packet, &num_packets);// - 1;
	int length_to_add = packet_get_length(packet);
		
 	int total_length = length + length_to_add;// + 1;
		
	*packet_packet_pointer = (Packet*)realloc((char*)packet_packet, total_length);
		
	char* character_packet = (char*)(*packet_packet_pointer);
	
	character_packet[total_length - 1] = PACKET_TYPE_UNDEFINED;
		
	memcpy(character_packet + length - 1, packet, length_to_add);
}
Esempio n. 7
0
extern int udptest_send(t_connection const * c)
{
    t_packet *         upacket;
    struct sockaddr_in caddr;
    unsigned int       tries,successes;

    memset(&caddr,0,sizeof(caddr));
    caddr.sin_family = PSOCK_AF_INET;
    caddr.sin_port = htons(conn_get_game_port(c));
    caddr.sin_addr.s_addr = htonl(conn_get_game_addr(c));

    for (tries=successes=0; successes!=2 && tries<5; tries++)
    {
        if (!(upacket = packet_create(packet_class_udp)))
        {
            eventlog(eventlog_level_error,"udptest_send","[%d] could not allocate memory for packet",conn_get_socket(c));
            continue;
        }
        packet_set_size(upacket,sizeof(t_server_udptest));
        packet_set_type(upacket,SERVER_UDPTEST);
        bn_int_tag_set(&upacket->u.server_udptest.bnettag,BNETTAG);

        if (hexstrm)
        {
            fprintf(hexstrm,"%d: send class=%s[0x%02hx] type=%s[0x%04hx] ",
                    conn_get_game_socket(c),
                    packet_get_class_str(upacket),(unsigned int)packet_get_class(upacket),
                    packet_get_type_str(upacket,packet_dir_from_server),packet_get_type(upacket));
            fprintf(hexstrm,"from=%s ",
                    addr_num_to_addr_str(conn_get_game_addr(c),conn_get_game_port(c)));
            fprintf(hexstrm,"to=%s ",
                    addr_num_to_addr_str(ntohl(caddr.sin_addr.s_addr),ntohs(caddr.sin_port)));
            fprintf(hexstrm,"length=%u\n",
                    packet_get_size(upacket));
            hexdump(hexstrm,packet_get_raw_data(upacket,0),packet_get_size(upacket));
        }

        if (psock_sendto(conn_get_game_socket(c),
                         packet_get_raw_data_const(upacket,0),packet_get_size(upacket),
                         0,(struct sockaddr *)&caddr,(psock_t_socklen)sizeof(caddr))!=(int)packet_get_size(upacket))
            eventlog(eventlog_level_error,"udptest_send","[%d] failed to send UDPTEST to %s (attempt %u) (psock_sendto: %s)",conn_get_socket(c),addr_num_to_addr_str(ntohl(caddr.sin_addr.s_addr),conn_get_game_port(c)),tries+1,strerror(psock_errno()));
        else
            successes++;

        packet_del_ref(upacket);
    }

    if (successes!=2)
        return -1;

    return 0;
}
Esempio n. 8
0
static int packet_packet_get_length(_Packet* p, int* num_packets)
{
	assert(packet_get_type((Packet*)p) == PACKET_TYPE_PACKETS);
	
	int total_length = 1;
	char* character_packet = (char*)p;
	int counter = 0;
	
	while (1)
	{
		Packet* next_packet = (Packet*)(character_packet + total_length);
		if (packet_get_type(next_packet) == PACKET_TYPE_UNDEFINED)
		{
			break;
		}
		counter++;
		total_length += packet_get_length(next_packet);	
	}
	
	*num_packets = counter;
	return total_length + 1;	
}
Esempio n. 9
0
/*
 * Create a response packet from a request, referencing the requestors 
 * message identifier.
 */
Packet *packet_create_response(Packet *request)
{
	Packet *response = NULL;
	Tlv method, requestId;
	BOOL success = FALSE;
	PacketTlvType responseType;

	if (packet_get_type(request) == PACKET_TLV_TYPE_PLAIN_REQUEST)
		responseType = PACKET_TLV_TYPE_PLAIN_RESPONSE;
	else
		responseType = PACKET_TLV_TYPE_RESPONSE;

	do
	{
		// Get the request TLV's method
		if (packet_get_tlv_string(request, TLV_TYPE_METHOD,
				&method) != ERROR_SUCCESS)
			break;

		// Try to allocate a response packet
		if (!(response = packet_create(responseType,
				(PCHAR)method.buffer)))
			break;

		// Get the request TLV's request identifier
		if (packet_get_tlv_string(request, TLV_TYPE_REQUEST_ID,
				&requestId) != ERROR_SUCCESS)
			break;

		// Add the request identifier to the packet
		packet_add_tlv_string(response, TLV_TYPE_REQUEST_ID,
				(PCHAR)requestId.buffer);

		success = TRUE;

	} while (0);

	// Cleanup on failure
	if (!success)
	{
		if (response)
			packet_destroy(response);

		response = NULL;
	}

	return response;
}
Esempio n. 10
0
static int sd_tcpoutput(int csocket, t_connection * c)
{
    unsigned int currsize;
    unsigned int totsize;
    t_packet *   packet;

    totsize = 0;
    for (;;)
    {
	currsize = conn_get_out_size(c);
	switch (net_send_packet(csocket,queue_peek_packet((t_queue const * const *)conn_get_out_queue(c)),&currsize)) /* avoid warning */
	{
	case -1:
	    conn_destroy(c);
	    return -1;

	case 0: /* still working on it */
	    conn_set_out_size(c,currsize);
	    return 0; /* bail out */

	case 1: /* done sending */
	    packet = queue_pull_packet(conn_get_out_queue(c));

	    if (hexstrm)
	    {
		fprintf(hexstrm,"%d: send class=%s[0x%02x] type=%s[0x%04x] length=%u\n",
			csocket,
			packet_get_class_str(packet),(unsigned int)packet_get_class(packet),
			packet_get_type_str(packet,packet_dir_from_server),packet_get_type(packet),
			packet_get_size(packet));
		hexdump(hexstrm,packet_get_raw_data(packet,0),packet_get_size(packet));
	    }

	    packet_del_ref(packet);
	    conn_set_out_size(c,0);

	    /* stop at about 2KB (or until out of packets or EWOULDBLOCK) */
	    if (totsize>2048 || queue_get_length((t_queue const * const *)conn_get_out_queue(c))<1)
		return 0;
	    totsize += currsize;
	}
    }

    /* not reached */
}
Esempio n. 11
0
Packet* packet_get_packet(Packet* packet_packet, int index)
{
	char* character_packet = (char*)packet_packet;
	
	int packet_index = 1;
	
	for (int i = 0; i < index; i++)
	{
		Packet* next_packet = (Packet*)(character_packet + packet_index);
		if (packet_get_type(next_packet) == PACKET_TYPE_UNDEFINED)
		{
			break;
		}
		packet_index += packet_get_length(next_packet);
	}
		
	return (Packet*)(character_packet + packet_index);
}
Esempio n. 12
0
// there shouldn't be much debug output, as sending it may invariably 
// receive the next option, triggering the option again. But it isn't
// re-entrant!
static uint8_t setopt_callback(int8_t channelno, int8_t errno, packet_t *rxpacket) {

        //debug_printf("setopt cb err=%d\n", errno);
        if (errno == CBM_ERROR_OK) {
                //debug_printf("rx command: %s\n", buf);

		uint8_t cmd = packet_get_type(rxpacket);
		uint8_t len = packet_get_contentlen(rxpacket);

		switch(cmd) {
		case FS_SETOPT:
			do_setopt(buf, len);
			break;
		case FS_RESET:
			rtconfig_pullconfig(0, NULL);
			break;
		}
        }
	// callback returns 1 to continue receiving on this channel
        return 1;
}
Esempio n. 13
0
// there shouldn't be much debug output, as sending it may invariably 
// receive the next option, triggering the option again. But it isn't
// re-entrant!
static uint8_t out_callback(int8_t channelno, int8_t errno, packet_t *rxpacket) {
	int8_t outrv;

        //debug_printf("setopt cb err=%d\n", errno);
        if (errno == CBM_ERROR_OK) {
                //debug_printf("rx command: %s\n", buf);

		uint8_t cmd = packet_get_type(rxpacket);

		switch(cmd) {
		case FS_REPLY:
			outrv = packet_get_buffer(rxpacket)[0];
			if (outrv != CBM_ERROR_OK) {
				// fallback to ASCII
				current_charset = CHARSET_ASCII;
			}	
			endpoint->provider->set_charset(endpoint->provdata, current_charset);
			break;
		}
        }
	device_unlock();
	// callback returns 1 to continue receiving on this channel
        return 0;
}
Esempio n. 14
0
extern int main(int argc, char * argv[])
{
    int                a;
    int                sd;
    struct sockaddr_in saddr;
    t_packet *         packet;
    t_packet *         rpacket;
    t_packet *         fpacket;
    char const *       clienttag=NULL;
    char const *       archtag=NULL;
    char const *       servname=NULL;
    unsigned short     servport=0;
    char const *       hexfile=NULL;
    char               text[MAX_MESSAGE_LEN];
    char const *       reqfile=NULL;
    struct hostent *   host;
    unsigned int       commpos;
    struct termios     in_attr_old;
    struct termios     in_attr_new;
    int                changed_in;
    unsigned int       currsize;
    unsigned int       filelen;
    unsigned int       startoffset;
    int                startoffsetoverride=0;
#define EXIST_ACTION_UNSPEC    -1
#define EXIST_ACTION_ASK        0
#define EXIST_ACTION_OVERWRITE  1
#define EXIST_ACTION_BACKUP     2
#define EXIST_ACTION_RESUME     3 
    int		       exist_action=EXIST_ACTION_UNSPEC;
    struct stat        exist_buf;
    char const *       filename;
    FILE *             fp;
    FILE *             hexstrm=NULL;
    int                fd_stdin;
    t_bnettime         bntime;
    time_t             tm;
    char               timestr[FILE_TIME_MAXLEN];
    unsigned int       screen_width,screen_height;
    int                munged;

    if (argc<1 || !argv || !argv[0])
    {
	fprintf(stderr,"bad arguments\n");
	return STATUS_FAILURE;
    }
    
    for (a=1; a<argc; a++)
	if (servname && isdigit((int)argv[a][0]) && a+1>=argc)
	{
            if (str_to_ushort(argv[a],&servport)<0)
            {
                fprintf(stderr,"%s: \"%s\" should be a positive integer\n",argv[0],argv[a]);
                usage(argv[0]);
            }
	}
	else if (!servname && argv[a][0]!='-' && a+2>=argc)
	    servname = argv[a];
        else if (strcmp(argv[a],"-b")==0 || strcmp(argv[a],"--client=SEXP")==0)
        {
            if (clienttag)
            {
                fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag);
                usage(argv[0]);
            }
            clienttag = CLIENTTAG_BROODWARS;
        }
        else if (strcmp(argv[a],"-d")==0 || strcmp(argv[a],"--client=DRTL")==0)
        {
            if (clienttag)
            {
                fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag);
                usage(argv[0]);
            }
            clienttag = CLIENTTAG_DIABLORTL;
        }
        else if (strcmp(argv[a],"--client=DSHR")==0)
        {
            if (clienttag)
            {
                fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag);
                usage(argv[0]);
            }
            clienttag = CLIENTTAG_DIABLOSHR;
        }
        else if (strcmp(argv[a],"-s")==0 || strcmp(argv[a],"--client=STAR")==0)
        {
            if (clienttag)
            {
                fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag);
                usage(argv[0]);
            }
            clienttag = CLIENTTAG_STARCRAFT;
        }
        else if (strcmp(argv[a],"--client=SSHR")==0)
        {
            if (clienttag)
            {
                fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag);
                usage(argv[0]);
            }
            clienttag = CLIENTTAG_SHAREWARE;
        }
	else if (strcmp(argv[a],"-w")==0 || strcmp(argv[a],"--client=W2BN")==0)
	{
            if (clienttag)
            {
                fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag);
                usage(argv[0]);
            }
            clienttag = CLIENTTAG_WARCIIBNE;
	}
        else if (strcmp(argv[a],"--client=D2DV")==0)
        {
            if (clienttag)
            {
                fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag);
                usage(argv[0]);
            }
            clienttag = CLIENTTAG_DIABLO2DV;
        }
        else if (strcmp(argv[a],"--client=D2XP")==0)
        {
            if (clienttag)
            {
                fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag);
                usage(argv[0]);
            }
            clienttag = CLIENTTAG_DIABLO2XP;
        }
        else if (strcmp(argv[a],"--client=WAR3")==0)
        {
            if (clienttag)
            {
                fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag);
                usage(argv[0]);
            }
            clienttag = CLIENTTAG_WARCRAFT3;
        }
        else if (strncmp(argv[a],"--client=",9)==0)
        {
            fprintf(stderr,"%s: unknown client tag \"%s\"\n",argv[0],&argv[a][9]);
            usage(argv[0]);
        }
	else if (strncmp(argv[a],"--hexdump=",10)==0)
	{
	    if (hexfile)
	    {
		fprintf(stderr,"%s: hexdump file was already specified as \"%s\"\n",argv[0],hexfile);
		usage(argv[0]);
	    }
	    hexfile = &argv[a][10];
	}
        else if (strcmp(argv[a],"--arch=IX86")==0)
        {
            if (archtag)
            {
                fprintf(stderr,"%s: client arch was already specified as \"%s\"\n",argv[0],archtag);
                usage(argv[0]);
            }
            archtag = ARCHTAG_WINX86;
        }
        else if (strcmp(argv[a],"--arch=PMAC")==0)
        {
            if (archtag)
            {
                fprintf(stderr,"%s: client arch was already specified as \"%s\"\n",argv[0],archtag);
                usage(argv[0]);
            }
            archtag = ARCHTAG_MACPPC;
        }
        else if (strcmp(argv[a],"--arch=XMAC")==0)
        {
            if (archtag)
            {
                fprintf(stderr,"%s: client arch was already specified as \"%s\"\n",argv[0],archtag);
                usage(argv[0]);
            }
            archtag = ARCHTAG_OSXPPC;
        }
        else if (strncmp(argv[a],"--arch=",7)==0)
        {
            fprintf(stderr,"%s: unknown arch tag \"%s\"\n",argv[0],&argv[a][9]);
            usage(argv[0]);
        }
	else if (strncmp(argv[a],"--startoffset=",14)==0)
	{
	    if (startoffsetoverride)
	    {
		fprintf(stderr,"%s: startoffset was already specified as %u\n",argv[0],startoffset);
		usage(argv[0]);
	    }
            if (str_to_uint(&argv[a][14],&startoffset)<0)
            {
                fprintf(stderr,"%s: startoffset \"%s\" should be a positive integer\n",argv[0],&argv[a][14]);
                usage(argv[0]);
            }
	    startoffsetoverride = 1;
	}
	else if (strncmp(argv[a],"--exists=",9)==0)
	{
	    if (exist_action!=EXIST_ACTION_UNSPEC)
	    {
		fprintf(stderr,"%s: exists was already specified\n",argv[0]);
		usage(argv[0]);
	    }
	    if (argv[a][9]=='o' || argv[a][9]=='O')
	    	exist_action = EXIST_ACTION_OVERWRITE;
	    else if (argv[a][9]=='a' || argv[a][9]=='A')
	    	exist_action = EXIST_ACTION_ASK;
	    else if (argv[a][9]=='b' || argv[a][9]=='B')
	    	exist_action = EXIST_ACTION_BACKUP;
	    else if (argv[a][9]=='r' || argv[a][9]=='R')
	    	exist_action = EXIST_ACTION_RESUME;
	    else {
		fprintf(stderr,"%s: exists must begin with a,A,o,O,b,B,r or R",argv[0]);
		usage(argv[0]);
	    }
	}
	else if (strncmp(argv[a],"--file=",7)==0)
	{
	    if (reqfile)
	    {
		fprintf(stderr,"%s: file was already specified as \"%s\"\n",argv[0],reqfile);
		usage(argv[0]);
	    }
	    reqfile = &argv[a][7];
	}
	else if (strcmp(argv[a],"-v")==0 || strcmp(argv[a],"--version")==0)
	{
            printf("version "BNETD_VERSION"\n");
            return 0;
	}
	else if (strcmp(argv[a],"-h")==0 || strcmp(argv[a],"--help")==0 || strcmp(argv[a],"--usage")==0)
            usage(argv[0]);
        else if (strcmp(argv[a],"--client")==0 || strcmp(argv[a],"--hexdump")==0)
        {
            fprintf(stderr,"%s: option \"%s\" requires an argument\n",argv[0],argv[a]);
            usage(argv[0]);
        }
	else
	{
	    fprintf(stderr,"%s: unknown option \"%s\"\n",argv[0],argv[a]);
	    usage(argv[0]);
	}
    
    if (servport==0)
        servport = BNETD_SERV_PORT;
    if (!clienttag)
        clienttag = CLIENTTAG_STARCRAFT;
    if (!archtag)
        archtag = ARCHTAG_WINX86;
    if (!servname)
	servname = BNETD_DEFAULT_HOST;
    if (exist_action==EXIST_ACTION_UNSPEC)
	exist_action = EXIST_ACTION_ASK;
    
    if (hexfile)
	if (!(hexstrm = fopen(hexfile,"w")))
	    fprintf(stderr,"%s: could not open file \"%s\" for writing the hexdump (fopen: %s)",argv[0],hexfile,strerror(errno));
	else
	    fprintf(hexstrm,"# dump generated by bnftp version "BNETD_VERSION"\n");
    
    if (psock_init()<0)
    {
        fprintf(stderr,"%s: could not inialialize socket functions\n",argv[0]);
        return STATUS_FAILURE;
    }
    
    if (!(host = gethostbyname(servname)))
    {
	fprintf(stderr,"%s: unknown host \"%s\"\n",argv[0],servname);
	return STATUS_FAILURE;
    }
    
    fd_stdin = fileno(stdin);
    if (tcgetattr(fd_stdin,&in_attr_old)>=0)
    {
        in_attr_new = in_attr_old;
        in_attr_new.c_lflag &= ~(ECHO | ICANON); /* turn off ECHO and ICANON */
	in_attr_new.c_cc[VMIN]  = 1; /* require reads to return at least one byte */
        in_attr_new.c_cc[VTIME] = 0; /* no timeout */
        tcsetattr(fd_stdin,TCSANOW,&in_attr_new);
        changed_in = 1;
    }
    else
    {
	fprintf(stderr,"%s: could not get terminal attributes for stdin\n",argv[0]);
	changed_in = 0;
    }
    
    if (client_get_termsize(fd_stdin,&screen_width,&screen_height)<0)
    {
        fprintf(stderr,"%s: could not determine screen size\n",argv[0]);
        if (changed_in)
            tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old);
        return STATUS_FAILURE;
    }
    
    if ((sd = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_STREAM,PSOCK_IPPROTO_TCP))<0)
    {
	fprintf(stderr,"%s: could not create socket (psock_socket: %s)\n",argv[0],strerror(psock_errno()));
	if (changed_in)
	    tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old);
	return STATUS_FAILURE;
    }
    
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = PSOCK_AF_INET;
    saddr.sin_port   = htons(servport);
    memcpy(&saddr.sin_addr.s_addr,host->h_addr_list[0],host->h_length);
    if (psock_connect(sd,(struct sockaddr *)&saddr,sizeof(saddr))<0)
    {
	fprintf(stderr,"%s: could not connect to server \"%s\" port %hu (psock_connect: %s)\n",argv[0],servname,servport,strerror(psock_errno()));
	if (changed_in)
	    tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old);
	return STATUS_FAILURE;
    }
    
    printf("Connected to %s:%hu.\n",inet_ntoa(saddr.sin_addr),servport);
    
#ifdef CLIENTDEBUG
    eventlog_set(stderr);
#endif
    
    if (!(packet = packet_create(packet_class_init)))
    {
	fprintf(stderr,"%s: could not create packet\n",argv[0]);
	if (changed_in)
	    tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old);
	return STATUS_FAILURE;
    }
    bn_byte_set(&packet->u.client_initconn.class,CLIENT_INITCONN_CLASS_FILE);
    if (hexstrm)
    {
	fprintf(hexstrm,"%d: send class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n",
		sd,
		packet_get_class_str(packet),(unsigned int)packet_get_class(packet),
		packet_get_type_str(packet,packet_dir_from_client),packet_get_type(packet),
		packet_get_size(packet));
	hexdump(hexstrm,packet_get_raw_data(packet,0),packet_get_size(packet));
    }
    client_blocksend_packet(sd,packet);
    packet_del_ref(packet);
    
    if (!(rpacket = packet_create(packet_class_file)))
    {
	fprintf(stderr,"%s: could not create packet\n",argv[0]);
	if (changed_in)
	    tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old);
	return STATUS_FAILURE;
    }
    
    if (!(fpacket = packet_create(packet_class_raw)))
    {
	fprintf(stderr,"%s: could not create packet\n",argv[0]);
	if (changed_in)
	    tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old);
	packet_del_ref(rpacket);
	return STATUS_FAILURE;
    }
    
    if (!reqfile) /* if not specified on the command line then prompt for it */
    {
    	munged = 1;
    	commpos = 0;
    	text[0] = '\0';
	
    	for (;;)
    	{
	    switch (client_get_comm("filename: ",text,sizeof(text),&commpos,1,munged,screen_width))
	    {
	    case -1: /* cancel or error */
	    	printf("\n");
	    	if (changed_in)
		    tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old);
	    	packet_del_ref(fpacket);
	    	packet_del_ref(rpacket);
	    	return STATUS_FAILURE;
		
	    case 0: /* timeout */
	    	munged = 0;
	    	continue;
		
	    case 1:
	    	munged = 0;
	    	if (text[0]=='\0')
		    continue;
	    	printf("\n");
	    }
	    break;
    	}
	reqfile = text;
    }
    
    if (stat(reqfile,&exist_buf)==0) /* check if the file exists */
    {
	char text2[MAX_MESSAGE_LEN];
	    
    	munged = 1;
	commpos = 0;
	text2[0] = '\0';
	
  	while (exist_action==EXIST_ACTION_ASK)
	{
	    switch (client_get_comm("File exists [O]verwrite, [B]ackup or [R]esume?: ",text2,sizeof(text2),&commpos,1,munged,screen_width))
	    {
	    case -1: /* cancel or error */
	    	printf("\n");
	    	if (changed_in)
		    tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old);
	    	packet_del_ref(fpacket);
	    	packet_del_ref(rpacket);
	    	return STATUS_FAILURE;
		
	    case 0: /* timeout */
	    	munged = 0;
	    	continue;
		
	    case 1:
	    	munged = 0;
	    	if (text2[0]=='\0')
		    continue;
	    	printf("\n");
		break;
	    }
	    
	    switch (text2[0])
	    {
	    case 'o':
	    case 'O':
		exist_action = EXIST_ACTION_OVERWRITE;
		break;
	    case 'b':
	    case 'B':
		exist_action = EXIST_ACTION_BACKUP;
		break;
	    case 'r':
	    case 'R':
		exist_action = EXIST_ACTION_RESUME;
		break;
	    default:
		printf("Please answer with o,O,b,B,r or R.\n");
		munged = 1;
		continue;
	    }
	    break;
	}
	
	switch (exist_action)
	{
	case EXIST_ACTION_OVERWRITE:
	    if (!startoffsetoverride)
	    	startoffset = 0;
	    break;
	case EXIST_ACTION_BACKUP:
	    {
		char *       bakfile;
		unsigned int bnr;
		int          renamed=0;
		
		if (!(bakfile = malloc(strlen(reqfile)+1+2+1))) /* assuming we go up to bnr 99 we need reqfile+'.'+'99'+'\0' */
		{
		    fprintf(stderr,"%s: unable to allocate memory for backup filename.\n",argv[0]);
		    if (changed_in)
			tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old);
		    packet_del_ref(fpacket);
		    packet_del_ref(rpacket);
		    return STATUS_FAILURE;
		}
		
		for (bnr=0; bnr<100; bnr++)
		{
		    sprintf(bakfile,"%s.%d",reqfile,bnr);
		    if (stat(bakfile,&exist_buf)==0)
			continue; /* backup exists */
		    /* backup does not exist */
		    if (rename(reqfile,bakfile)<0) /* just rename the existing file to the backup */
			fprintf(stderr,"%s: could not create backup file \"%s\" (rename: %s)\n",argv[0],bakfile,strerror(errno));
		    else
		    {
			renamed = 1;
			printf("Renaming \"%s\" to \"%s\".\n",reqfile,bakfile);
		    }
		    break;
		}
		free(bakfile);
		if (!renamed)
		{
		    fprintf(stderr,"%s: could not create backup for \"%s\".\n",argv[0],reqfile);
		    if (changed_in)
			tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old);
		    packet_del_ref(fpacket);
		    packet_del_ref(rpacket);
		    return STATUS_FAILURE;
		}
	    	if (!startoffsetoverride)
	    	    startoffset = 0;
	    }
	    break;
	case EXIST_ACTION_RESUME:
	    if (!startoffsetoverride)
	    	startoffset = exist_buf.st_size;
	    break;	    	
	}	
    }
    else
	if (!startoffsetoverride)
	    startoffset = 0;
    
    if (changed_in)
	tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old);
    
    if (!(packet = packet_create(packet_class_file)))
    {
	fprintf(stderr,"%s: could not create packet\n",argv[0]);
	packet_del_ref(fpacket);
	packet_del_ref(rpacket);
	return STATUS_FAILURE;
    }
    packet_set_size(packet,sizeof(t_client_file_req));
    packet_set_type(packet,CLIENT_FILE_REQ);
    bn_int_tag_set(&packet->u.client_file_req.archtag,archtag);
    bn_int_tag_set(&packet->u.client_file_req.clienttag,clienttag);
    bn_int_set(&packet->u.client_file_req.adid,0);
    bn_int_set(&packet->u.client_file_req.extensiontag,0);
    bn_int_set(&packet->u.client_file_req.startoffset,startoffset);
    bn_long_set_a_b(&packet->u.client_file_req.timestamp,0x00000000,0x00000000);
    packet_append_string(packet,reqfile);
    if (hexstrm)
    {
	fprintf(hexstrm,"%d: send class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n",
		sd,
		packet_get_class_str(packet),(unsigned int)packet_get_class(packet),
		packet_get_type_str(packet,packet_dir_from_client),packet_get_type(packet),
		packet_get_size(packet));
	hexdump(hexstrm,packet_get_raw_data(packet,0),packet_get_size(packet));
    }
    printf("\nRequesting info...");
    fflush(stdout);
    client_blocksend_packet(sd,packet);
    packet_del_ref(packet);
    
    do
    {
	if (client_blockrecv_packet(sd,rpacket)<0)
	{
	    fprintf(stderr,"%s: server closed connection\n",argv[0]);
	    packet_del_ref(fpacket);
	    packet_del_ref(rpacket);
	    return STATUS_FAILURE;
	}
	if (hexstrm)
	{
	    fprintf(hexstrm,"%d: recv class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n",
		     sd,
		     packet_get_class_str(rpacket),(unsigned int)packet_get_class(rpacket),
		     packet_get_type_str(rpacket,packet_dir_from_server),packet_get_type(rpacket),
		     packet_get_size(rpacket));
	    hexdump(hexstrm,packet_get_raw_data(rpacket,0),packet_get_size(rpacket));
	}
    }
    while (packet_get_type(rpacket)!=SERVER_FILE_REPLY);
    
    filelen = bn_int_get(rpacket->u.server_file_reply.filelen);
    bn_long_to_bnettime(rpacket->u.server_file_reply.timestamp,&bntime);
    tm = bnettime_to_time(bntime);
    strftime(timestr,FILE_TIME_MAXLEN,FILE_TIME_FORMAT,localtime(&tm));
    filename = packet_get_str_const(rpacket,sizeof(t_server_file_reply),MAX_FILENAME_STR);
    
    if (exist_action==EXIST_ACTION_RESUME)
    {
	if (!(fp = fopen(reqfile,"ab")))
	{
	    fprintf(stderr,"%s: could not open file \"%s\" for appending (fopen: %s)\n",argv[0],reqfile,strerror(errno));
	    packet_del_ref(fpacket);
	    packet_del_ref(rpacket);
	    return STATUS_FAILURE;
	}
    }
    else
    {
	if (!(fp = fopen(reqfile,"wb")))
	{
	    fprintf(stderr,"%s: could not open file \"%s\" for writing (fopen: %s)\n",argv[0],reqfile,strerror(errno));
	    packet_del_ref(fpacket);
	    packet_del_ref(rpacket);
	    return STATUS_FAILURE;
	}
    }
    
    printf("\n name: \"");
    str_print_term(stdout,filename,0,0);
    printf("\"\n changed: %s\n length: %u bytes\n",timestr,filelen);
    fflush(stdout);
    
    if (startoffset>0) {
	filelen -= startoffset; /* for resuming files */
	printf("Resuming at position %u (%u bytes remaining).\n",startoffset,filelen);
    }
    
    printf("\nSaving to \"%s\"...",reqfile);

    for (currsize=0; currsize+MAX_PACKET_SIZE<=filelen; currsize+=MAX_PACKET_SIZE)
    {
	printf(".");
	fflush(stdout);
	
	if (client_blockrecv_raw_packet(sd,fpacket,MAX_PACKET_SIZE)<0)
	{
	    printf("error\n");
	    fprintf(stderr,"%s: server closed connection\n",argv[0]);
	    if (fclose(fp)<0)
		fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno));
	    packet_del_ref(fpacket);
	    packet_del_ref(rpacket);
	    return STATUS_FAILURE;
	}
	if (hexstrm)
	{
	    fprintf(hexstrm,"%d: recv class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n",
		     sd,
		     packet_get_class_str(fpacket),(unsigned int)packet_get_class(fpacket),
		     packet_get_type_str(fpacket,packet_dir_from_server),packet_get_type(fpacket),
		     packet_get_size(fpacket));
	    hexdump(hexstrm,packet_get_raw_data(fpacket,0),packet_get_size(fpacket));
	}
	if (fwrite(packet_get_raw_data_const(fpacket,0),1,MAX_PACKET_SIZE,fp)<MAX_PACKET_SIZE)
	{
	    printf("error\n");
	    fprintf(stderr,"%s: could not write to file \"%s\" (fwrite: %s)\n",argv[0],reqfile,strerror(errno));
	    if (fclose(fp)<0)
		fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno));
	    packet_del_ref(fpacket);
	    packet_del_ref(rpacket);
	    return STATUS_FAILURE;
	}
    }
    filelen -= currsize;
    if (filelen)
    {
	printf(".");
	fflush(stdout);
	
	if (client_blockrecv_raw_packet(sd,fpacket,filelen)<0)
	{
	    printf("error\n");
	    fprintf(stderr,"%s: server closed connection\n",argv[0]);
	    if (fclose(fp)<0)
		fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno));
	    packet_del_ref(fpacket);
	    packet_del_ref(rpacket);
	    return STATUS_FAILURE;
	}
	if (hexstrm)
	{
	    fprintf(hexstrm,"%d: recv class=%s[0x%02hx] type=%s[0x%04hx] length=%u\n",
		     sd,
		     packet_get_class_str(fpacket),(unsigned int)packet_get_class(fpacket),
		     packet_get_type_str(fpacket,packet_dir_from_server),packet_get_type(fpacket),
		     packet_get_size(fpacket));
	    hexdump(hexstrm,packet_get_raw_data(fpacket,0),packet_get_size(fpacket));
	}
	if (fwrite(packet_get_raw_data_const(fpacket,0),1,filelen,fp)<filelen)
	{
	    printf("error\n");
	    fprintf(stderr,"%s: could not write to file \"%s\"\n",argv[0],reqfile);
	    if (fclose(fp)<0)
		fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno));
	    packet_del_ref(fpacket);
	    packet_del_ref(rpacket);
	    return STATUS_FAILURE;
	}
    }
    
    packet_del_ref(fpacket);
    packet_del_ref(rpacket);
    
    if (hexstrm)
    {
	fprintf(hexstrm,"# end of dump\n");
	if (fclose(hexstrm)<0)
	    fprintf(stderr,"%s: could not close hexdump file \"%s\" after writing (fclose: %s)",argv[0],hexfile,strerror(errno));
    }
    
    if (fclose(fp)<0)
    {
	fprintf(stderr,"%s: could not close file \"%s\" after writing (fclose: %s)\n",argv[0],reqfile,strerror(errno));
	return STATUS_FAILURE;
    }
    
    printf("done\n");
    return STATUS_FAILURE;
}
Esempio n. 15
0
extern int handle_file_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;
    }
/* REMOVED BY UNDYING SOULZZ 4/3/02 */
/*
    if (packet_get_class(packet)!=packet_class_file)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"[%d] got bad packet (class %d)",conn_get_socket(c),(int)packet_get_class(packet));
        return -1;
    }
 */   
    switch (conn_get_state(c))
    {
    case conn_state_connected:
	switch (packet_get_type(packet))
	{
	case CLIENT_FILE_REQ:
	{
	    char const * rawname;
	    
	    if (!(rawname = packet_get_str_const(packet,sizeof(t_client_file_req),MAX_FILENAME_STR)))
	    {
		eventlog(eventlog_level_error,__FUNCTION__,"[%d] got bad FILE_REQ (missing or too long filename)",conn_get_socket(c));
		
		return -1;
	    }
	    
	    file_send(c,rawname,
		      bn_int_get(packet->u.client_file_req.adid),
		      bn_int_get(packet->u.client_file_req.extensiontag),
		      bn_int_get(packet->u.client_file_req.startoffset),
		      1);
	}
	break;

	case CLIENT_FILE_REQ2:
	{
	    t_packet * rpacket = NULL;
	    if((rpacket = packet_create(packet_class_raw))) {
		    packet_set_size(rpacket,sizeof(t_server_file_unknown1));
		    bn_int_set( &rpacket->u.server_file_unknown1.unknown, 0xdeadbeef );
		    conn_push_outqueue(c, rpacket );
		    packet_del_ref( rpacket );
	    }
	    conn_set_state(c, conn_state_pending_raw);
	    break;
	}

	default:
	    eventlog(eventlog_level_error,__FUNCTION__,"[%d] unknown file packet type 0x%04x, len %u",conn_get_socket(c),packet_get_type(packet),packet_get_size(packet));
	    
	    break;
	}
	break;

    case conn_state_pending_raw:
	switch (packet_get_type(packet))
	{
	    case CLIENT_FILE_REQ3:
	    {
		char rawname[MAX_FILENAME_STR];

		psock_recv( conn_get_socket(c), rawname, MAX_FILENAME_STR, 0 );
		file_send(c, rawname, 0, 0, 0, 1);
	    }
	    break;	

	    default:
		eventlog(eventlog_level_error, __FUNCTION__, "[%d] unknown file packet type 0x%04x, len %u",conn_get_socket(c),packet_get_type(packet),packet_get_size(packet));

	    break;
	}
	break;

    default:
	eventlog(eventlog_level_error,__FUNCTION__,"[%d] unknown file connection state %d",conn_get_socket(c),(int)conn_get_state(c));
    }

    return 0;
}
Esempio n. 16
0
void packet_print(Packet* packet)
{
	switch (packet_get_type(packet))
	{
		case PACKET_TYPE_SEND_MESSAGE:
		{
			printf("Send Message: Length=%d, Message=%s\n", 
				packet_get_length(packet), 
				packet_get_string(packet, SEND_MESSAGE_TEXT));
			break;
		}
		case PACKET_TYPE_SEND_NAME:
		{
			printf("Send Name: Length=%d, Name=%s\n", 
				packet_get_length(packet), 
				packet_get_string(packet, SEND_NAME_NAME));
			break;
		}
		case PACKET_TYPE_MOUSE_DOWN:
		{
			printf("Mouse Down: Length=%d, X=%lf, Y=%lf\n", 
				packet_get_length(packet), 
				packet_get_double(packet, MOUSE_DOWN_X), 
				packet_get_double(packet, MOUSE_DOWN_Y));
			break;
		}
		case PACKET_TYPE_MOUSE_MOVE:
		{
			printf("Mouse Move: Length=%d, X=%lf, Y=%lf\n", 
				packet_get_length(packet), 
				packet_get_double(packet, MOUSE_MOVE_X), 
				packet_get_double(packet, MOUSE_MOVE_Y));
			break;
		}
		case PACKET_TYPE_MOUSE_UP:
		{
			printf("Mouse Up: Length=%d, X=%lf, Y=%lf\n", 
				packet_get_length(packet), 
				packet_get_double(packet, MOUSE_UP_X), 
				packet_get_double(packet, MOUSE_UP_Y));
			break;
		}
		case PACKET_TYPE_NEW_STROKE:
		{
			printf("New Stroke: Length=%d, ID=%d, X=%lf, Y=%lf, TYPE=%d, FILL=%d, WIDTH=%lf, R=%lf, G=%lf, B=%lf\n", 
				packet_get_length(packet), 
				packet_get_int(packet, NEW_STROKE_ID),
				packet_get_double(packet, NEW_STROKE_X), 
				packet_get_double(packet, NEW_STROKE_Y),
				packet_get_byte(packet, NEW_STROKE_SHAPE_TYPE),
				packet_get_byte(packet, NEW_STROKE_FILL),
				packet_get_double(packet, NEW_STROKE_WIDTH),
				packet_get_double(packet, NEW_STROKE_R),
				packet_get_double(packet, NEW_STROKE_G),
				packet_get_double(packet, NEW_STROKE_B));
			break;
		}
		case PACKET_TYPE_ADD_POINT:
		{
			printf("Add Point: Length=%d, ID=%d, X=%lf, Y=%lf\n", 
				packet_get_length(packet), 
				packet_get_int(packet, ADD_POINT_ID),
				packet_get_double(packet, ADD_POINT_X), 
				packet_get_double(packet, ADD_POINT_Y));
			break;
		}
		case PACKET_TYPE_DELETE:
		{
			printf("New Stroke: Length=%d, ID=%d\n", 
				packet_get_length(packet), 
				packet_get_int(packet, DELETE_ID));
			break;
		}
		case PACKET_TYPE_UPDATE:
		{
			printf("Update: Length=%d, ID=%d, X=%lf, Y=%lf, T=%lf\n", 
				packet_get_length(packet), 
				packet_get_int(packet, UPDATE_ID),
				packet_get_double(packet, UPDATE_X), 
				packet_get_double(packet, UPDATE_Y),
				packet_get_double(packet, UPDATE_ROTATION));
			break;
		}
		case PACKET_TYPE_PACKETS:
		{
			printf("Packets: Length=%d\n", packet_get_length(packet));
			int i = 0;
			Packet* p = NULL;
			do
			{
				printf("\t");
				p = packet_get_packet(packet, i);
				packet_print(p);
				i++;
			} while (packet_get_type(p) != PACKET_TYPE_UNDEFINED);
			break;
		}
		case PACKET_TYPE_NEW_CONNECTION:
		{
			printf("New Connection: Length=1\n");
			break;
		}
		case PACKET_TYPE_INK_POT:
		{
			printf("Ink: %d\n", packet_get_byte(packet, INK_POT_INK));
			break;
		}
		case PACKET_TYPE_UNDEFINED:
		default:
		{
			printf("Packet Undefined\n");
			break;
		}
	}
}
/*!
 * @brief Receive a new packet on the given remote endpoint.
 * @param remote Pointer to the \c Remote instance.
 * @param packet Pointer to a pointer that will receive the \c Packet data.
 * @return An indication of the result of processing the transmission request.
 */
static DWORD packet_receive_via_ssl(Remote *remote, Packet **packet)
{
	DWORD headerBytes = 0, payloadBytesLeft = 0, res;
	CryptoContext *crypto = NULL;
	Packet *localPacket = NULL;
	PacketHeader header;
	LONG bytesRead;
	BOOL inHeader = TRUE;
	PUCHAR payload = NULL;
	ULONG payloadLength;
	TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;

	lock_acquire(remote->lock);

	do
	{
		// Read the packet length
		while (inHeader)
		{
			if ((bytesRead = SSL_read(ctx->ssl, ((PUCHAR)&header + headerBytes), sizeof(PacketHeader)-headerBytes)) <= 0)
			{
				if (!bytesRead)
				{
					SetLastError(ERROR_NOT_FOUND);
				}

				if (bytesRead < 0)
				{
					dprintf("[PACKET] receive header failed with error code %d. SSLerror=%d, WSALastError=%d\n", bytesRead, SSL_get_error(ctx->ssl, bytesRead), WSAGetLastError());
					SetLastError(ERROR_NOT_FOUND);
				}

				break;
			}

			headerBytes += bytesRead;

			if (headerBytes != sizeof(PacketHeader))
			{
				continue;
			}

			inHeader = FALSE;
		}

		if (headerBytes != sizeof(PacketHeader))
		{
			break;
		}

		header.xor_key = ntohl(header.xor_key);

		// xor the header data
		xor_bytes(header.xor_key, &header.length, 8);

		// Initialize the header
		header.length = ntohl(header.length);

		// use TlvHeader size here, because the length doesn't include the xor byte
		payloadLength = header.length - sizeof(TlvHeader);
		payloadBytesLeft = payloadLength;

		// Allocate the payload
		if (!(payload = (PUCHAR)malloc(payloadLength)))
		{
			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
			break;
		}

		// Read the payload
		while (payloadBytesLeft > 0)
		{
			if ((bytesRead = SSL_read(ctx->ssl, payload + payloadLength - payloadBytesLeft, payloadBytesLeft)) <= 0)
			{

				if (GetLastError() == WSAEWOULDBLOCK)
				{
					continue;
				}

				if (!bytesRead)
				{
					SetLastError(ERROR_NOT_FOUND);
				}

				if (bytesRead < 0)
				{
					dprintf("[PACKET] receive payload of length %d failed with error code %d. SSLerror=%d\n", payloadLength, bytesRead, SSL_get_error(ctx->ssl, bytesRead));
					SetLastError(ERROR_NOT_FOUND);
				}

				break;
			}

			payloadBytesLeft -= bytesRead;
		}

		// Didn't finish?
		if (payloadBytesLeft)
		{
			break;
		}

		xor_bytes(header.xor_key, payload, payloadLength);

		// Allocate a packet structure
		if (!(localPacket = (Packet *)malloc(sizeof(Packet))))
		{
			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
			break;
		}

		memset(localPacket, 0, sizeof(Packet));

		// If the connection has an established cipher and this packet is not
		// plaintext, decrypt
		if ((crypto = remote_get_cipher(remote)) &&
			(packet_get_type(localPacket) != PACKET_TLV_TYPE_PLAIN_REQUEST) &&
			(packet_get_type(localPacket) != PACKET_TLV_TYPE_PLAIN_RESPONSE))
		{
			ULONG origPayloadLength = payloadLength;
			PUCHAR origPayload = payload;

			// Decrypt
			if ((res = crypto->handlers.decrypt(crypto, payload, payloadLength, &payload, &payloadLength)) != ERROR_SUCCESS)
			{
				SetLastError(res);
				break;
			}

			// We no longer need the encrypted payload
			free(origPayload);
		}

		localPacket->header.length = header.length;
		localPacket->header.type = header.type;
		localPacket->payload = payload;
		localPacket->payloadLength = payloadLength;

		*packet = localPacket;

		SetLastError(ERROR_SUCCESS);

	} while (0);

	res = GetLastError();

	// Cleanup on failure
	if (res != ERROR_SUCCESS)
	{
		if (payload)
		{
			free(payload);
		}
		if (localPacket)
		{
			free(localPacket);
		}
	}

	lock_release(remote->lock);

	return res;
}
Esempio n. 18
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;
    }
    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 (packet_get_type(packet))
    {
    case CLIENT_INITCONN:
	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;
}
Esempio n. 19
0
/*!
 * @brief Process a single command in a seperate thread of execution.
 * @param thread Pointer to the thread to execute.
 * @return Result of processing.
 */
DWORD THREADCALL command_process_thread( THREAD * thread )
{
	DWORD index       = 0;
	DWORD result      = ERROR_SUCCESS;
	Tlv methodTlv     = {0};
	Tlv requestIdTlv  = {0};
	PCHAR method      = NULL;
	PCHAR requestId   = NULL;
	Command * current = NULL;
	Remote * remote   = NULL;
	Packet * packet   = NULL;

	if( thread == NULL )
		return ERROR_INVALID_HANDLE;

	remote = (Remote *)thread->parameter1;
	if( remote == NULL )
		return ERROR_INVALID_HANDLE;

	packet = (Packet *)thread->parameter2;
	if( packet == NULL )
		return ERROR_INVALID_DATA;

	if( commandThreadList == NULL )
	{
		commandThreadList = list_create();
		if( commandThreadList == NULL )
			return ERROR_INVALID_HANDLE;
#ifndef _WIN32
		pthread_t tid;
		pthread_create(&tid, NULL, reap_zombie_thread, NULL);
		dprintf("reap_zombie_thread created, thread_id : 0x%x",tid);
#endif
	}

	list_add( commandThreadList, thread );

	__try
	{
		do
		{

			// Extract the method
			result = packet_get_tlv_string( packet, TLV_TYPE_METHOD, &methodTlv );
			if( result != ERROR_SUCCESS )
				break;

			dprintf( "[COMMAND] Processing method %s", methodTlv.buffer );

#ifdef _WIN32
			// Impersonate the thread token if needed (only on Windows)
			if(remote->hServerToken != remote->hThreadToken) {
				if(! ImpersonateLoggedOnUser(remote->hThreadToken)) {
					dprintf( "[COMMAND] Failed to impersonate thread token (%s) (%u)", methodTlv.buffer, GetLastError());
				}
			}
#endif

			// Get the request identifier if the packet has one.
			result = packet_get_tlv_string( packet, TLV_TYPE_REQUEST_ID, &requestIdTlv );
			if( result == ERROR_SUCCESS )
				requestId = (PCHAR)requestIdTlv.buffer;

			method = (PCHAR)methodTlv.buffer;

			result = ERROR_NOT_FOUND;

			// Try to find a match in the dispatch type
			for( index = 0, result = ERROR_NOT_FOUND ; result == ERROR_NOT_FOUND && commands[index].method ; index++ )
			{
				if( strcmp( commands[index].method, method ) )
					continue;

				// Call the base handler
				result = command_call_dispatch( &commands[index], remote, packet );
			}

			// Regardless of error code, try to see if someone has overriden a base handler
			for( current = extension_commands, result = ERROR_NOT_FOUND ; 
				result == ERROR_NOT_FOUND && current && current->method ; current = current->next )
			{
				if( strcmp( current->method, method ) )
					continue;

				// Call the custom handler
				result = command_call_dispatch( current, remote, packet );
			}

			dprintf("[COMMAND] Calling completion handlers...");
			// Finally, call completion routines for the provided identifier
			if( ((packet_get_type(packet) == PACKET_TLV_TYPE_RESPONSE) || (packet_get_type(packet) == PACKET_TLV_TYPE_PLAIN_RESPONSE)) && (requestId))
				packet_call_completion_handlers( remote, packet, requestId );

			// If we get here, we're successful.
			result = ERROR_SUCCESS;

		} while( 0 );
	}
	__except( EXCEPTION_EXECUTE_HANDLER )
	{
		dprintf("[COMMAND] Exception hit in command thread 0x%08X!", thread );
	}

	packet_destroy( packet );

	if( list_remove( commandThreadList, thread ) )
		thread_destroy( thread );

	return ERROR_SUCCESS;
}
Esempio n. 20
0
/*
 * Receive a new packet over HTTP using WinInet
 */
DWORD packet_receive_http_via_wininet(Remote *remote, Packet **packet) {

	DWORD headerBytes = 0, payloadBytesLeft = 0, res; 
	CryptoContext *crypto = NULL;
	Packet *localPacket = NULL;
	TlvHeader header;
	LONG bytesRead;
	BOOL inHeader = TRUE;
	PUCHAR payload = NULL;
	ULONG payloadLength;
	DWORD flags;
	DWORD flen;

	HINTERNET hReq;
	HINTERNET hRes;
	DWORD retries = 5;
	
	lock_acquire( remote->lock );

	do {

		flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_AUTO_REDIRECT | INTERNET_FLAG_NO_UI;
		if (remote->transport == METERPRETER_TRANSPORT_HTTPS) {
			flags |= INTERNET_FLAG_SECURE | INTERNET_FLAG_IGNORE_CERT_CN_INVALID | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
		}
		dprintf("[PACKET RECEIVE] HttpOpenRequest");
		hReq = HttpOpenRequest(remote->hConnection, "POST", remote->uri, NULL, NULL, NULL, flags, 0);

		if (hReq == NULL) {
			dprintf("[PACKET RECEIVE] Failed HttpOpenRequest: %d", GetLastError());
			SetLastError(ERROR_NOT_FOUND);
			break;
		}

		if (remote->transport == METERPRETER_TRANSPORT_HTTPS) {
			InternetQueryOption( hReq, INTERNET_OPTION_SECURITY_FLAGS, &flags, &flen);
			flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_FLAG_IGNORE_CERT_CN_INVALID | SECURITY_FLAG_IGNORE_UNKNOWN_CA;
			InternetSetOption(hReq, INTERNET_OPTION_SECURITY_FLAGS, &flags, flen);
		}
		
		hRes = HttpSendRequest(hReq, NULL, 0, "RECV", 4 );
		if (! hRes) {
			dprintf("[PACKET RECEIVE] Failed HttpSendRequest: %d", GetLastError());
			SetLastError(ERROR_NOT_FOUND);
			break;
		}

		// Read the packet length
		retries = 3;
		while (inHeader && retries > 0)
		{
			retries--;
			if (! InternetReadFile(hReq, ((PUCHAR)&header + headerBytes), sizeof(TlvHeader) - headerBytes, &bytesRead))  {
				dprintf("[PACKET RECEIVE] Failed HEADER InternetReadFile: %d", GetLastError());
				SetLastError(ERROR_NOT_FOUND);
				break;
			}

			// If the response contains no data, this is fine, it just means the
			// remote side had nothing to tell us. Indicate this through a 
			// ERROR_EMPTY response code so we can update the timestamp.
			if (bytesRead == 0) {
				SetLastError(ERROR_EMPTY);
				break;
			}

			headerBytes += bytesRead;
	
			if (headerBytes != sizeof(TlvHeader)) {
				continue;
			} else {
				inHeader = FALSE;
			}
		}

		if (GetLastError() == ERROR_EMPTY)
			break;
		
		if (headerBytes != sizeof(TlvHeader)) {
			SetLastError(ERROR_NOT_FOUND);
			break;
		}

		// Initialize the header
		header.length    = header.length;
		header.type      = header.type;
		payloadLength    = ntohl(header.length) - sizeof(TlvHeader);
		payloadBytesLeft = payloadLength;

		// Allocate the payload
		if (!(payload = (PUCHAR)malloc(payloadLength)))
		{
			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
			break;
		}
			
		// Read the payload
		retries = payloadBytesLeft;
		while (payloadBytesLeft > 0 && retries > 0 )
		{
			retries--;
			if (! InternetReadFile(hReq, payload + payloadLength - payloadBytesLeft, payloadBytesLeft, &bytesRead))  {
				dprintf("[PACKET RECEIVE] Failed BODY InternetReadFile: %d", GetLastError());
				SetLastError(ERROR_NOT_FOUND);
				break;
			}

			if (!bytesRead) {
				SetLastError(ERROR_NOT_FOUND);
				break;
			}

			payloadBytesLeft -= bytesRead;
		}
		
		// Didn't finish?
		if (payloadBytesLeft)
			break;

		// Allocate a packet structure
		if (!(localPacket = (Packet *)malloc(sizeof(Packet))))
		{
			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
			break;
		}

		memset( localPacket, 0, sizeof(Packet) );

		// If the connection has an established cipher and this packet is not
		// plaintext, decrypt
		if ((crypto = remote_get_cipher(remote)) &&
		    (packet_get_type(localPacket) != PACKET_TLV_TYPE_PLAIN_REQUEST) &&
		    (packet_get_type(localPacket) != PACKET_TLV_TYPE_PLAIN_RESPONSE))
		{
			ULONG origPayloadLength = payloadLength;
			PUCHAR origPayload = payload;

			// Decrypt
			if ((res = crypto->handlers.decrypt(crypto, payload, payloadLength,&payload, &payloadLength)) != ERROR_SUCCESS)
			{
				SetLastError(res);
				break;
			}

			// We no longer need the encrypted payload
			free(origPayload);
		}

		localPacket->header.length = header.length;
		localPacket->header.type   = header.type;
		localPacket->payload       = payload;
		localPacket->payloadLength = payloadLength;

		*packet = localPacket;

		SetLastError(ERROR_SUCCESS);

	} while (0);

	res = GetLastError();

	// Cleanup on failure
	if (res != ERROR_SUCCESS)
	{
		if (payload)
			free(payload);
		if (localPacket)
			free(localPacket);
	}

	if (hReq) 
		InternetCloseHandle(hReq);

	lock_release( remote->lock );

	return res;
}
Esempio n. 21
0
/*
 * Transmit and destroy a packet over HTTP(S)
 */
DWORD packet_transmit_via_http(Remote *remote, Packet *packet, PacketRequestCompletion *completion)
{
	CryptoContext *crypto;
	Tlv requestId;
	DWORD res;
#ifdef _UNIX
	int local_error = -1;
#endif


	lock_acquire( remote->lock );

	// If the packet does not already have a request identifier, create one for it
	if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,&requestId) != ERROR_SUCCESS)
	{
		DWORD index;
		CHAR rid[32];

		rid[sizeof(rid) - 1] = 0;

		for (index = 0; index < sizeof(rid) - 1; index++)
			rid[index] = (rand() % 0x5e) + 0x21;

		packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid);
	}

	do
	{
		// If a completion routine was supplied and the packet has a request 
		// identifier, insert the completion routine into the list
		if ((completion) &&
		    (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,
				&requestId) == ERROR_SUCCESS))
			packet_add_completion_handler((LPCSTR)requestId.buffer, completion);

		// If the endpoint has a cipher established and this is not a plaintext
		// packet, we encrypt
		if ((crypto = remote_get_cipher(remote)) &&
		    (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_REQUEST) &&
		    (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_RESPONSE))
		{
			ULONG origPayloadLength = packet->payloadLength;
			PUCHAR origPayload = packet->payload;

			// Encrypt
			if ((res = crypto->handlers.encrypt(crypto, packet->payload, 
					packet->payloadLength, &packet->payload, 
					&packet->payloadLength)) !=
					ERROR_SUCCESS)
			{
				SetLastError(res);
				break;
			}

			// Destroy the original payload as we no longer need it
			free(origPayload);

			// Update the header length
			packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader));
		}

#ifdef _WIN32
		dprintf("Transmitting packet of length %d to remote", packet->payloadLength);
		res = packet_transmit_via_http_wininet(remote, packet, completion);
#else
		// XXX: Implement non-windows HTTP delivery
#endif

		if(res < 0) {
			dprintf("[PACKET] transmit failed with return %d\n", res);
			break;
		}

		SetLastError(ERROR_SUCCESS);
	} while (0);

	res = GetLastError();

	// Destroy the packet
	packet_destroy(packet);

	lock_release( remote->lock );

	return res;
}
Esempio n. 22
0
static int proxy_process(unsigned short server_listen_port, struct sockaddr_in servaddr)
{
    int                lsock;
    struct sockaddr_in laddr;
    t_psock_fd_set     rfds, wfds;
    int                highest_fd;
    int                udpsock;
    t_virtconn *       vc;
    t_elem const *     curr;
    int                csocket;
    int                ssocket;
    
    if ((udpsock = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_DGRAM,PSOCK_IPPROTO_UDP))<0)
    {
	eventlog(eventlog_level_error,__FUNCTION__,"could not create UDP socket (psock_socket: %s)",pstrerror(psock_errno()));
	return -1;
    }
    if (psock_ctl(udpsock,PSOCK_NONBLOCK)<0)
	eventlog(eventlog_level_error,__FUNCTION__,"could not set UDP listen socket to non-blocking mode (psock_ctl: %s)",pstrerror(psock_errno()));
    
    if ((lsock = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_STREAM,PSOCK_IPPROTO_TCP))<0)
    {
	eventlog(eventlog_level_error,__FUNCTION__,"could not create listening socket (psock_socket: %s)",pstrerror(psock_errno()));
        psock_close(udpsock);
	return -1;
    }
    
    {
	int val=1;
	
	if (psock_setsockopt(lsock,PSOCK_SOL_SOCKET,PSOCK_SO_REUSEADDR,&val,(psock_t_socklen)sizeof(int))<0)
	    eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set socket option SO_REUSEADDR (psock_setsockopt: %s)",lsock,pstrerror(psock_errno()));
	/* not a fatal error... */
    }
    
    memset(&laddr,0,sizeof(laddr));
    laddr.sin_family = PSOCK_AF_INET;
    laddr.sin_port = htons(server_listen_port);
    laddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (psock_bind(lsock,(struct sockaddr *)&laddr,(psock_t_socklen)sizeof(laddr))<0)
    {
	eventlog(eventlog_level_error,__FUNCTION__,"could not bind socket to address 0.0.0.0:%hu TCP (psock_bind: %s)",server_listen_port,pstrerror(psock_errno()));
        psock_close(udpsock);
	psock_close(lsock);
	return -1;
    }
    
    memset(&laddr,0,sizeof(laddr));
    laddr.sin_family = PSOCK_AF_INET;
    laddr.sin_port = htons(server_listen_port);
    laddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (psock_bind(udpsock,(struct sockaddr *)&laddr,(psock_t_socklen)sizeof(laddr))<0)
    {
	eventlog(eventlog_level_error,__FUNCTION__,"could not bind socket to address 0.0.0.0:%hu UDP (psock_bind: %s)",server_listen_port,pstrerror(psock_errno()));
	psock_close(udpsock);
	psock_close(lsock);
	return -1;
    }
    eventlog(eventlog_level_info,__FUNCTION__,"bound to UDP port %hu",server_listen_port);
    
    /* tell socket to listen for connections */
    if (psock_listen(lsock,LISTEN_QUEUE)<0)
    {
	eventlog(eventlog_level_error,__FUNCTION__,"could not listen (psock_listen: %s)",pstrerror(psock_errno()));
        psock_close(udpsock);
	psock_close(lsock);
	return -1;
    }
    if (psock_ctl(lsock,PSOCK_NONBLOCK)<0)
	eventlog(eventlog_level_error,__FUNCTION__,"could not set TCP listen socket to non-blocking mode (psock_ctl: %s)",pstrerror(psock_errno()));
    
    eventlog(eventlog_level_info,__FUNCTION__,"listening on TCP port %hu",server_listen_port);
    
    for (;;)
    {
	/* loop over all connections to create the sets for select() */
	PSOCK_FD_ZERO(&rfds);
	PSOCK_FD_ZERO(&wfds);
	highest_fd = lsock;
	PSOCK_FD_SET(lsock,&rfds);
	if (udpsock>highest_fd)
	    highest_fd = udpsock;
	PSOCK_FD_SET(udpsock,&rfds);
	
	LIST_TRAVERSE_CONST(virtconnlist(),curr)
	{
	    vc = elem_get_data(curr);
            csocket = virtconn_get_client_socket(vc);
	    if (queue_get_length((t_queue const * const *)virtconn_get_clientout_queue(vc))>0)
	        PSOCK_FD_SET(csocket,&wfds); /* pending output, also check for writeability */
	    PSOCK_FD_SET(csocket,&rfds);
            
	    if (csocket>highest_fd)
                highest_fd = csocket;
	    
	    switch (virtconn_get_state(vc))
	    {
	    case virtconn_state_connecting:
		eventlog(eventlog_level_debug,__FUNCTION__,"waiting for %d to finish connecting",ssocket);
		ssocket = virtconn_get_server_socket(vc);
		PSOCK_FD_SET(ssocket,&wfds); /* wait for connect to complete */
		
		if (ssocket>highest_fd)
		    highest_fd = ssocket;
		break;
	    case virtconn_state_connected:
		eventlog(eventlog_level_debug,__FUNCTION__,"checking for reading on connected socket %d",ssocket);
		ssocket = virtconn_get_server_socket(vc);
		if (queue_get_length((t_queue const * const *)virtconn_get_serverout_queue(vc))>0)
		    PSOCK_FD_SET(ssocket,&wfds); /* pending output, also check for writeability */
		PSOCK_FD_SET(ssocket,&rfds);
		
		if (ssocket>highest_fd)
		    highest_fd = ssocket;
		break;
	    default: /* avoid warning */
		break;
	    }
	}
	
	/* find which sockets need servicing */
	if (psock_select(highest_fd+1,&rfds,&wfds,NULL,NULL)<0)
	{
	    if (errno!=PSOCK_EINTR)
	        eventlog(eventlog_level_error,__FUNCTION__,"select failed (select: %s)",pstrerror(errno));
	    continue;
	}
	
	/* check for incoming connection */
	if (PSOCK_FD_ISSET(lsock,&rfds))
	{
            int                asock;
	    struct sockaddr_in caddr;
	    psock_t_socklen    caddr_len;
            
	    /* accept the connection */
	    caddr_len = sizeof(caddr);
	    if ((asock = psock_accept(lsock,(struct sockaddr *)&caddr,&caddr_len))<0)
	    {
		if (psock_errno()==PSOCK_EWOULDBLOCK || psock_errno()==PSOCK_ECONNABORTED) /* BSD, POSIX error for aborted connections, SYSV often uses EAGAIN */
		    eventlog(eventlog_level_error,__FUNCTION__,"client aborted connection (psock_accept: %s)",pstrerror(psock_errno()));
		else /* EAGAIN can mean out of resources _or_ connection aborted */
		    if (psock_errno()!=PSOCK_EINTR)
			eventlog(eventlog_level_error,__FUNCTION__,"could not accept new connection (psock_accept: %s)",pstrerror(psock_errno()));
	    }
	    else
	    {
		int ssd;
		int val=1;
		
		eventlog(eventlog_level_info,__FUNCTION__,"[%d] accepted connection from %s:%hu",asock,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
		
		if (psock_setsockopt(asock,PSOCK_SOL_SOCKET,PSOCK_SO_KEEPALIVE,&val,(psock_t_socklen)sizeof(val))<0)
		    eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set socket option SO_KEEPALIVE (psock_setsockopt: %s)",asock,pstrerror(psock_errno()));
		    /* not a fatal error */
		
		if (psock_ctl(asock,PSOCK_NONBLOCK)<0)
		{
		    eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set TCP socket to non-blocking mode (closing connection) (psock_ctl: %s)",asock,pstrerror(psock_errno()));
		    psock_close(asock);
		}
		else
		    if ((ssd = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_STREAM,PSOCK_IPPROTO_TCP))<0)
		    {
			eventlog(eventlog_level_error,__FUNCTION__,"[%d] could create TCP socket (closing connection) (psock_socket: %s)",asock,pstrerror(psock_errno()));
			psock_close(asock);
		    }
		    else
			if (psock_ctl(ssd,PSOCK_NONBLOCK)<0)
			{
			    eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set TCP socket to non-blocking mode (closing connection) (psock_ctl: %s)",asock,pstrerror(psock_errno()));
			    psock_close(ssd);
			    psock_close(asock);
			}
			else
			    if (!(vc = virtconn_create(asock,ssd,ntohl(caddr.sin_addr.s_addr),BNETD_MIN_TEST_PORT)))
			    {
				eventlog(eventlog_level_error,__FUNCTION__,"[%d] unable to create new connection (closing connection)",asock);
				psock_close(ssd);
				psock_close(asock);
			    }
			    else
			    {
				memset(&caddr,0,sizeof(caddr));
				caddr.sin_family = PSOCK_AF_INET;
				caddr.sin_port = htons(virtconn_get_udpport(vc));
				caddr.sin_addr.s_addr = htonl(virtconn_get_udpaddr(vc));
				eventlog(eventlog_level_info,__FUNCTION__,"[%d] addr now %s:%hu",asock,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
			    }
	    }
	}
	
	eventlog(eventlog_level_debug,__FUNCTION__,"checking for incoming UDP");
	if (PSOCK_FD_ISSET(udpsock,&rfds))
	{
	    t_packet *         upacket;
	    struct sockaddr_in toaddr;
	    struct sockaddr_in fromaddr;
	    psock_t_socklen    fromlen;
	    int                len;
	    
	    if (!(upacket = packet_create(packet_class_raw)))
		eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw packet for input");
	    else
	    {
		/* packet_set_flags(upacket,PROXY_FLAG_UDP);*/
		
		fromlen = sizeof(fromaddr);
		if ((len = psock_recvfrom(udpsock,packet_get_raw_data_build(upacket,0),MAX_PACKET_SIZE,0,(struct sockaddr *)&fromaddr,&fromlen))<0)
		{
		    if (psock_errno()!=PSOCK_EINTR && psock_errno()!=PSOCK_EAGAIN && psock_errno()!=PSOCK_EWOULDBLOCK)
			eventlog(eventlog_level_error,__FUNCTION__,"could not recv UDP datagram (psock_recvfrom: %s)",pstrerror(psock_errno()));
		}
		else
		{
		    if (fromaddr.sin_family!=PSOCK_AF_INET)
			eventlog(eventlog_level_error,__FUNCTION__,"got UDP datagram with bad address family %d",fromaddr.sin_family);
		    else
		    {
			char tempa[32];
			char tempb[32];
			
			packet_set_size(upacket,len);
			
			if (fromaddr.sin_addr.s_addr==servaddr.sin_addr.s_addr) /* from server */
			{
			    if ((curr = list_get_first_const(virtconnlist()))) /* hack.. find proper client */
			    {
				vc = elem_get_data(curr);
				memset(&toaddr,0,sizeof(toaddr));
				toaddr.sin_family = PSOCK_AF_INET;
				toaddr.sin_port = htons(virtconn_get_udpport(vc));
				toaddr.sin_addr.s_addr = htonl(virtconn_get_udpaddr(vc));
				eventlog(eventlog_level_info,__FUNCTION__,"[%d] addr by UDP send is %s:%hu",virtconn_get_client_socket(vc),inet_ntoa(toaddr.sin_addr),ntohs(toaddr.sin_port));
				
				if (hexstrm)
				{
				    strcpy(tempa,inet_ntoa(fromaddr.sin_addr));
				    strcpy(tempb,inet_ntoa(toaddr.sin_addr));
				    fprintf(hexstrm,"%d: srv prot=UDP from=%s:%hu to=%s:%hu length=%d\n",
					    udpsock,
					    tempa,
					    ntohs(fromaddr.sin_port),
					    tempb,
					    ntohs(toaddr.sin_port),
					    len);
				    hexdump(hexstrm,packet_get_raw_data(upacket,0),len);
				}
				
				/*queue_push_packet(virtconn_get_clientout_queue(__));*/ /* where to queue ... */
				for (;;) /* hack.. just block for now */
				{
				    if (psock_sendto(udpsock,packet_get_raw_data_const(upacket,0),len,0,
					             (struct sockaddr *)&toaddr,(psock_t_socklen)sizeof(toaddr))<len)
				    {
					if (psock_errno()==PSOCK_EINTR || psock_errno()==PSOCK_EAGAIN || psock_errno()==PSOCK_EWOULDBLOCK)
					    continue;
					eventlog(eventlog_level_error,__FUNCTION__,"could not send UDP datagram to client (psock_sendto: %s)",pstrerror(psock_errno()));
				    }
				    break;
				}
			    }
			}
			else /* from client */
			{
			    if (hexstrm)
			    {
				strcpy(tempa,inet_ntoa(fromaddr.sin_addr));
				strcpy(tempb,inet_ntoa(servaddr.sin_addr));
				
				fprintf(hexstrm,"%d: clt prot=UDP from=%s:%hu to=%s:%hu length=%d\n",
					udpsock,
					tempa,
					ntohs(fromaddr.sin_port),
					tempb,
					ntohs(servaddr.sin_port),
					len);
				hexdump(hexstrm,packet_get_raw_data(upacket,0),len);
			    }
			    /*queue_push_packet(virtconn_get_serverout_queue(vc));*/
			    for (;;) /* hack.. just block for now */
			    {
				if (psock_sendto(udpsock,packet_get_raw_data_const(upacket,0),len,0,
					         (struct sockaddr *)&servaddr,(psock_t_socklen)sizeof(servaddr))<len)
				{
				    if (psock_errno()==PSOCK_EINTR || psock_errno()==PSOCK_EAGAIN || psock_errno()==PSOCK_EWOULDBLOCK)
					continue;
				    eventlog(eventlog_level_error,__FUNCTION__,"could not send UDP datagram to server (psock_sendto: %s)",pstrerror(psock_errno()));
				}
				break;
			    }
			}
		    }
		}
		packet_del_ref(upacket);
	    }
	}
	
	/* search connections for sockets that need service */
	eventlog(eventlog_level_debug,__FUNCTION__,"checking for sockets that need service");
	LIST_TRAVERSE_CONST(virtconnlist(),curr)
	{
	    unsigned int currsize;
	    t_packet *   packet;
	    
	    vc = elem_get_data(curr);
	    
            csocket = virtconn_get_client_socket(vc);
	    if (virtconn_get_state(vc)==virtconn_state_connected ||
		virtconn_get_state(vc)==virtconn_state_connecting)
		ssocket = virtconn_get_server_socket(vc);
	    else
		ssocket = -1;
	    
	    eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for client readability",csocket);
	    if (PSOCK_FD_ISSET(csocket,&rfds))
	    {
		if (virtconn_get_state(vc)==virtconn_state_initial)
		{
		    if (init_virtconn(vc,servaddr)<0)
		    {
			virtconn_destroy(vc);
			continue;
		    }
		}
		else
		{
		    currsize = virtconn_get_clientin_size(vc);
		    
		    if (!queue_get_length(virtconn_get_clientin_queue(vc)))
		    {
			switch (virtconn_get_class(vc))
			{
			case virtconn_class_bnet:
			    if (!(packet = packet_create(packet_class_bnet)))
			    {
				eventlog(eventlog_level_error,__FUNCTION__,"could not allocate normal packet for input");
				continue;
			    }
			    break;
			case virtconn_class_file:
			    if (!(packet = packet_create(packet_class_file)))
			    {
				eventlog(eventlog_level_error,__FUNCTION__,"could not allocate file packet for input");
				continue;
			    }
			    break;
			case virtconn_class_bot:
			    if (!(packet = packet_create(packet_class_raw)))
			    {
				eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw packet for input");
				continue;
			    }
			    packet_set_size(packet,1); /* start by only reading one char */
			    break;
			default:
			    eventlog(eventlog_level_error,__FUNCTION__,"[%d] connection has bad type (closing connection)",virtconn_get_client_socket(vc));
			    virtconn_destroy(vc);
			    continue;
			}
			queue_push_packet(virtconn_get_clientin_queue(vc),packet);
			packet_del_ref(packet);
			if (!queue_get_length(virtconn_get_clientin_queue(vc)))
			    continue; /* push failed */
			currsize = 0;
		    }
		    
		    packet = queue_peek_packet((t_queue const * const *)virtconn_get_clientin_queue(vc)); /* avoid warning */
		    switch (net_recv_packet(csocket,packet,&currsize))
		    {
		    case -1:
			virtconn_destroy(vc);
			continue;
			
		    case 0: /* still working on it */
			virtconn_set_clientin_size(vc,currsize);
			break;
			
		    case 1: /* done reading */
			if (virtconn_get_class(vc)==virtconn_class_bot &&
			    currsize<MAX_PACKET_SIZE)
			{
			    char const * const temp=packet_get_raw_data_const(packet,0);
			    
			    if (temp[currsize-1]!='\r' && temp[currsize-1]!='\n')
			    {
				virtconn_set_clientin_size(vc,currsize);
				packet_set_size(packet,currsize+1);
			        break; /* no end of line, get another char */
			    }
			    /* got a complete line... fall through */
			}
			
			packet = queue_pull_packet(virtconn_get_clientin_queue(vc));
			
			if (hexstrm)
			{
			    fprintf(hexstrm,"%d: cli class=%s[0x%04hx] type=%s[0x%04hx] length=%hu\n",
				    csocket,
				    packet_get_class_str(packet),packet_get_class(packet),
				    packet_get_type_str(packet,packet_dir_from_client),packet_get_type(packet),
				    packet_get_size(packet));
			    hexdump(hexstrm,packet_get_raw_data_const(packet,0),packet_get_size(packet));
			}
			
			queue_push_packet(virtconn_get_serverout_queue(vc),packet);
			packet_del_ref(packet);
			virtconn_set_clientin_size(vc,0);
		    }
		}
	    }
	    
	    eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for server readability",ssocket);
	    if (ssocket!=-1 && PSOCK_FD_ISSET(ssocket,&rfds))
	    {
		currsize = virtconn_get_serverin_size(vc);
		
		if (!queue_get_length(virtconn_get_serverin_queue(vc)))
		{
		    switch (virtconn_get_class(vc))
		    {
		    case virtconn_class_bnet:
			if (!(packet = packet_create(packet_class_bnet)))
			{
			    eventlog(eventlog_level_error,__FUNCTION__,"could not allocate normal packet for input");
			    continue;
			}
			break;
		    case virtconn_class_file:
			{
			    unsigned int fileleft;
			    
			    if ((fileleft = virtconn_get_fileleft(vc))>0)
			    {
				if (!(packet = packet_create(packet_class_raw)))
				{
				    eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw file packet for input");
				    continue;
				}
				if (fileleft>MAX_PACKET_SIZE)
				    packet_set_size(packet,MAX_PACKET_SIZE);
				else
				    packet_set_size(packet,fileleft);
			    }
			    else
			    {
				if (!(packet = packet_create(packet_class_file)))
				{
				    eventlog(eventlog_level_error,__FUNCTION__,"could not allocate file packet for input");
				    continue;
				}
			    }
			}
			break;
		    case virtconn_class_bot:
			if (!(packet = packet_create(packet_class_raw)))
			{
			    eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw packet for input");
			    continue;
			}
			packet_set_size(packet,MAX_PACKET_SIZE); /* read as much as possible */
			break;
		    default:
			eventlog(eventlog_level_error,__FUNCTION__,"[%d] connection has bad type (closing connection)",virtconn_get_client_socket(vc));
			virtconn_destroy(vc);
			continue;
		    }
		    queue_push_packet(virtconn_get_serverin_queue(vc),packet);
		    packet_del_ref(packet);
		    if (!queue_get_length(virtconn_get_serverin_queue(vc)))
			continue; /* push failed */
		    currsize = 0;
		}
		
		packet = queue_peek_packet((t_queue const * const *)virtconn_get_serverin_queue(vc)); /* avoid warning */
		switch (net_recv_packet(ssocket,packet,&currsize))
		{
		case -1:
		    virtconn_destroy(vc);
		    continue;
		    
		case 0: /* still working on it */
		    virtconn_set_serverin_size(vc,currsize);
		    if (virtconn_get_class(vc)!=virtconn_class_bot || currsize<1)
			break;
		    else
			packet_set_size(packet,currsize);
		    /* fallthough... we take what we can get with the bot data */
		    
		case 1: /* done reading */
		    packet = queue_pull_packet(virtconn_get_serverin_queue(vc));
		    if (virtconn_get_class(vc)==virtconn_class_file)
		    {
			unsigned int len=virtconn_get_fileleft(vc);
			
			if (len)
			    virtconn_set_fileleft(vc,len-currsize);
			else if (packet_get_type(packet)==SERVER_FILE_REPLY &&
				 packet_get_size(packet)>=sizeof(t_server_file_reply))
			    virtconn_set_fileleft(vc,bn_int_get(packet->u.server_file_reply.filelen));
		    }
		    queue_push_packet(virtconn_get_clientout_queue(vc),packet);
		    packet_del_ref(packet);
		    virtconn_set_serverin_size(vc,0);
		}
	    }
	    
	    eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for client writeability",csocket);
	    if (PSOCK_FD_ISSET(csocket,&wfds))
	    {
		currsize = virtconn_get_clientout_size(vc);
		switch (net_send_packet(csocket,queue_peek_packet((t_queue const * const *)virtconn_get_clientout_queue(vc)),&currsize)) /* avoid warning */
		{
		case -1:
		    virtconn_destroy(vc);
		    continue;
		    
		case 0: /* still working on it */
		    virtconn_set_clientout_size(vc,currsize);
		    break;
		    
		case 1: /* done sending */
		    packet = queue_pull_packet(virtconn_get_clientout_queue(vc));
		    
		    if (hexstrm)
		    {
			fprintf(hexstrm,"%d: srv class=%s[0x%04hx] type=%s[0x%04hx] length=%hu\n",
				csocket,
				packet_get_class_str(packet),packet_get_class(packet),
				packet_get_type_str(packet,packet_dir_from_server),packet_get_type(packet),
				packet_get_size(packet));
			hexdump(hexstrm,packet_get_raw_data(packet,0),packet_get_size(packet));
		    }
		    
		    packet_del_ref(packet);
		    virtconn_set_clientout_size(vc,0);
		}
	    }
	    
	    eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for server writeability",ssocket);
	    if (ssocket!=-1 && PSOCK_FD_ISSET(ssocket,&wfds))
	    {
		if (virtconn_get_state(vc)==virtconn_state_connecting)
		{
		    int             err;
		    psock_t_socklen errlen;
		    
		    err = 0;
		    errlen = sizeof(err);
		    if (psock_getsockopt(ssocket,PSOCK_SOL_SOCKET,PSOCK_SO_ERROR,&err,&errlen)<0)
		    {
			eventlog(eventlog_level_error,__FUNCTION__,"[%d] unable to read socket error (psock_getsockopt[psock_connect]: %s)",virtconn_get_client_socket(vc),pstrerror(psock_errno()));
			virtconn_destroy(vc);
			continue;
		    }
		    if (errlen==0 || err==0)
			virtconn_set_state(vc,virtconn_state_connected);
		    else
		    {
			eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not connect to server (psock_getsockopt[psock_connect]: %s)",virtconn_get_client_socket(vc),pstrerror(err));
			virtconn_destroy(vc);
			continue;
		    }
		}
		else
		{
		    currsize = virtconn_get_serverout_size(vc);
		    switch (net_send_packet(ssocket,queue_peek_packet((t_queue const * const *)virtconn_get_serverout_queue(vc)),&currsize)) /* avoid warning */
		    {
		    case -1:
			virtconn_destroy(vc);
			continue;
			
		    case 0: /* still working on it */
			virtconn_set_serverout_size(vc,currsize);
			break;
			
		    case 1: /* done sending */
			packet = queue_pull_packet(virtconn_get_serverout_queue(vc));
			packet_del_ref(packet);
			virtconn_set_serverout_size(vc,0);
		    }
		}
	    }
	}
Esempio n. 23
0
/*
 * Transmit and destroy a packet
 */
DWORD packet_transmit(Remote *remote, Packet *packet, 
		PacketRequestCompletion *completion)
{
	CryptoContext *crypto;
	Tlv requestId;
	DWORD res;
	DWORD idx;
#ifdef _UNIX
	int local_error = -1;
#endif	

	// If the packet does not already have a request identifier, create
	// one for it
	if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,
			&requestId) != ERROR_SUCCESS)
	{
		DWORD index;
		CHAR rid[32];

		rid[sizeof(rid) - 1] = 0;

		for (index = 0; 
		     index < sizeof(rid) - 1; 
		     index++)
			rid[index] = (rand() % 0x5e) + 0x21;

		packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID,
				rid);
	}

	do
	{
		// If a completion routine was supplied and the packet has a request 
		// identifier, insert the completion routine into the list
		if ((completion) &&
		    (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,
				&requestId) == ERROR_SUCCESS))
			packet_add_completion_handler((LPCSTR)requestId.buffer, completion);

		// If the endpoint has a cipher established and this is not a plaintext
		// packet, we encrypt
		if ((crypto = remote_get_cipher(remote)) &&
		    (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_REQUEST) &&
		    (packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_RESPONSE))
		{
			ULONG origPayloadLength = packet->payloadLength;
			PUCHAR origPayload = packet->payload;

			// Encrypt
			if ((res = crypto->handlers.encrypt(crypto, packet->payload, 
					packet->payloadLength, &packet->payload, 
					&packet->payloadLength)) !=
					ERROR_SUCCESS)
			{
				SetLastError(res);
				break;
			}

			// Destroy the original payload as we no longer need it
			free(origPayload);

			// Update the header length
			packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader));
		}

		idx = 0;
		while( idx < sizeof(packet->header)) { 
			// Transmit the packet's header (length, type)
			res = SSL_write(
				remote->ssl, 
				(LPCSTR)(&packet->header) + idx, 
				sizeof(packet->header) - idx
			);
				
			if(res <= 0) {
				dprintf("transmit header failed with return %d at index %d\n", res, idx);
				break;
			}
			idx += res;
		}
		if(res < 0) break;

		idx = 0;
		while( idx < packet->payloadLength) { 
			// Transmit the packet's payload (length, type)
			res = SSL_write(
				remote->ssl, 
				packet->payload + idx,
				packet->payloadLength - idx
			);
			if(res < 0)
				break;

			idx += res;
		}
		if(res < 0) {
			dprintf("transmit header failed with return %d at index %d\n", res, idx);
			break;
		}

		SetLastError(ERROR_SUCCESS);
	} while (0);

	res = GetLastError();
	
	// Destroy the packet
	packet_destroy(packet);

	return res;
}
Esempio n. 24
0
/*
 * Receive a new packet
 */
DWORD packet_receive(Remote *remote, Packet **packet)
{
	DWORD headerBytes = 0, payloadBytesLeft = 0, res; 
	CryptoContext *crypto = NULL;
	Packet *localPacket = NULL;
	TlvHeader header;
	LONG bytesRead;
	BOOL inHeader = TRUE;
	PUCHAR payload = NULL;
	ULONG payloadLength;
#ifdef _UNIX
	int local_error = -1;
#endif	
	do
	{
		// Read the packet length
		while (inHeader)
		{
			if ((bytesRead = SSL_read(remote->ssl, 
					((PUCHAR)&header + headerBytes), 
					sizeof(TlvHeader) - headerBytes)) <= 0)
			{
				if (!bytesRead)
					SetLastError(ERROR_NOT_FOUND);

				if(bytesRead < 0) {
					dprintf("receive header failed with error code %d\n", bytesRead);
					SetLastError(ERROR_NOT_FOUND);
				}

				break;
			}

			headerBytes += bytesRead;
	
			if (headerBytes != sizeof(TlvHeader))
				continue;
			else
				inHeader = FALSE;
		}
		
		if (bytesRead != sizeof(TlvHeader))
			break;

		// Initialize the header
		header.length    = header.length;
		header.type      = header.type;
		payloadLength    = ntohl(header.length) - sizeof(TlvHeader);
		payloadBytesLeft = payloadLength;

		// Allocate the payload
		if (!(payload = (PUCHAR)malloc(payloadLength)))
		{
			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
			break;
		}
			
		// Read the payload
		while (payloadBytesLeft > 0)
		{
			if ((bytesRead = SSL_read(remote->ssl, 
					payload + payloadLength - payloadBytesLeft, 
					payloadBytesLeft)) <= 0)
			{

				if (GetLastError() == WSAEWOULDBLOCK)
					continue;

				if (!bytesRead)
					SetLastError(ERROR_NOT_FOUND);

				if(bytesRead < 0) {
					dprintf("receive payload of length %d failed with error code %d\n", payloadLength, bytesRead);
					SetLastError(ERROR_NOT_FOUND);
				}

				break;
			}

			payloadBytesLeft -= bytesRead;
		}
		
		// Didn't finish?
		if (payloadBytesLeft)
			break;

		// Allocate a packet structure
		if (!(localPacket = (Packet *)malloc(sizeof(Packet))))
		{
			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
			break;
		}

		// If the connection has an established cipher and this packet is not
		// plaintext, decrypt
		if ((crypto = remote_get_cipher(remote)) &&
		    (packet_get_type(localPacket) != PACKET_TLV_TYPE_PLAIN_REQUEST) &&
		    (packet_get_type(localPacket) != PACKET_TLV_TYPE_PLAIN_RESPONSE))
		{
			ULONG origPayloadLength = payloadLength;
			PUCHAR origPayload = payload;

			// Decrypt
			if ((res = crypto->handlers.decrypt(crypto, payload, payloadLength,
					&payload, &payloadLength)) != ERROR_SUCCESS)
			{
				SetLastError(res);
				break;
			}

			// We no longer need the encrypted payload
			free(origPayload);
		}

		localPacket->header.length = header.length;
		localPacket->header.type   = header.type;
		localPacket->payload       = payload;
		localPacket->payloadLength = payloadLength;

		*packet = localPacket;

		SetLastError(ERROR_SUCCESS);

	} while (0);

	res = GetLastError();

	// Cleanup on failure
	if (res != ERROR_SUCCESS)
	{
		if (payload)
			free(payload);
		if (localPacket)
			free(localPacket);
	}

	return res;
}
Esempio n. 25
0
/*!
 * @brief Create a response packet from a request.
 * @details Create a response packet from a request, referencing the requestors
 * message identifier.
 * @param request The request \c Packet to build a response for.
 * @return Pointer to a new \c Packet.
 */
Packet *packet_create_response(Packet *request)
{
	Packet *response = NULL;
	Tlv method, requestId;
	BOOL success = FALSE;
	PacketTlvType responseType;

	if (packet_get_type(request) == PACKET_TLV_TYPE_PLAIN_REQUEST)
	{
		responseType = PACKET_TLV_TYPE_PLAIN_RESPONSE;
	}
	else
	{
		responseType = PACKET_TLV_TYPE_RESPONSE;
	}

	do
	{
		// Get the request TLV's method
		if (packet_get_tlv_string(request, TLV_TYPE_METHOD, &method) != ERROR_SUCCESS)
		{
			break;
		}

		// Try to allocate a response packet
		if (!(response = packet_create(responseType, (PCHAR)method.buffer)))
		{
			break;
		}

		// Get the request TLV's request identifier
		if (packet_get_tlv_string(request, TLV_TYPE_REQUEST_ID, &requestId) != ERROR_SUCCESS)
		{
			break;
		}

		// Add the request identifier to the packet
		packet_add_tlv_string(response, TLV_TYPE_REQUEST_ID, (PCHAR)requestId.buffer);

		// If the packet that is being handled is considered local, then we
		// associate the response with the request so that it can be handled
		// locally (and vice versa)
		if (request->local)
		{
			request->partner = response;
			response->partner = request;
		}

		success = TRUE;

	} while (0);

	// Cleanup on failure
	if (!success)
	{
		if (response)
		{
			packet_destroy(response);
		}

		response = NULL;
	}

	return response;
}
Esempio n. 26
0
static int on_bnetd_charloginreply(t_connection * c, t_packet * packet)
{
	unsigned int	seqno;
	t_sq		* sq;
	t_connection	* client;
	t_packet	* opacket, * rpacket;
	int		result, reply, type;
	char const	* charname;
	t_elem		* elem;

	if (!packet || !c)
	    return -1;

	seqno=bn_int_get(packet->u.d2cs_bnetd.h.seqno);
	if (!(sq=sqlist_find_sq(seqno))) {
		eventlog(eventlog_level_error,__FUNCTION__,"seqno %d not found",seqno);
		return -1;
	}
	if (!(client=d2cs_connlist_find_connection_by_sessionnum(sq_get_clientid(sq)))) {
		eventlog(eventlog_level_error,__FUNCTION__,"client %d not found",sq_get_clientid(sq));
		sq_destroy(sq,&elem);
		return -1;
	}
	if (!(opacket=sq_get_packet(sq))) {
		eventlog(eventlog_level_error,__FUNCTION__,"previous packet missing (seqno: %d)",seqno);
		sq_destroy(sq,&elem);
		return -1;
	}
	type=packet_get_type(opacket);
	result=bn_int_get(packet->u.bnetd_d2cs_charloginreply.reply);
	if (type==CLIENT_D2CS_CREATECHARREQ) {
		charname=packet_get_str_const(opacket,sizeof(t_client_d2cs_createcharreq),MAX_CHARNAME_LEN);
		if (result==BNETD_D2CS_CHARLOGINREPLY_SUCCEED) {
			if (conn_check_multilogin(client,charname)<0) {
				eventlog(eventlog_level_error,__FUNCTION__,"character %s is already logged in",charname);
				reply = D2CS_CLIENT_CHARLOGINREPLY_FAILED;
			} else {
				reply= D2CS_CLIENT_CREATECHARREPLY_SUCCEED;
				eventlog(eventlog_level_info,__FUNCTION__,"character %s authed",charname);
				d2cs_conn_set_charname(client,charname);
				d2cs_conn_set_state(client,conn_state_char_authed);
			}
		} else {
			reply = D2CS_CLIENT_CREATECHARREPLY_FAILED;
			eventlog(eventlog_level_error,__FUNCTION__,"failed to auth character %s",charname);
		}
		if ((rpacket=packet_create(packet_class_d2cs))) {
			packet_set_size(rpacket,sizeof(t_d2cs_client_createcharreply));
			packet_set_type(rpacket,D2CS_CLIENT_CREATECHARREPLY);
			bn_int_set(&rpacket->u.d2cs_client_createcharreply.reply,reply);
			conn_push_outqueue(client,rpacket);
			packet_del_ref(rpacket);
		}
	} else if (type==CLIENT_D2CS_CHARLOGINREQ) {
		charname=packet_get_str_const(opacket,sizeof(t_client_d2cs_charloginreq),MAX_CHARNAME_LEN);
		if (result==BNETD_D2CS_CHARLOGINREPLY_SUCCEED) {
			if (conn_check_multilogin(client,charname)<0) {
				eventlog(eventlog_level_error,__FUNCTION__,"character %s is already logged in",charname);
				reply = D2CS_CLIENT_CHARLOGINREPLY_FAILED;
			} else {
				reply = D2CS_CLIENT_CHARLOGINREPLY_SUCCEED;
				eventlog(eventlog_level_info,__FUNCTION__,"character %s authed",charname);
				d2cs_conn_set_charname(client,charname);
				d2cs_conn_set_state(client,conn_state_char_authed);
			}
		} else {
			reply = D2CS_CLIENT_CHARLOGINREPLY_FAILED;
			eventlog(eventlog_level_error,__FUNCTION__,"failed to auth character %s",charname);
		}
		if ((rpacket=packet_create(packet_class_d2cs))) {
			packet_set_size(rpacket,sizeof(t_d2cs_client_charloginreply));
			packet_set_type(rpacket,D2CS_CLIENT_CHARLOGINREPLY);
			bn_int_set(&rpacket->u.d2cs_client_charloginreply.reply,reply);
			conn_push_outqueue(client,rpacket);
			packet_del_ref(rpacket);
		}
	} else {
		eventlog(eventlog_level_error,__FUNCTION__,"got bad packet type %d",type);
		sq_destroy(sq,&elem);
		return -1;
	}
	sq_destroy(sq,&elem);
	return 0;
}
Esempio n. 27
0
static int sd_udpinput(t_addr *const curr_laddr, const t_laddr_info *laddr_info,
		       int ssocket, int usocket)
{
  int             err;
  psock_t_socklen errlen;
  t_packet *      upacket;

  if (laddr_info == NULL) {
    (void)ssocket;
  }
  err = 0;
  errlen = sizeof(err);
  if (psock_getsockopt(usocket,PSOCK_SOL_SOCKET,PSOCK_SO_ERROR,&err,&errlen)<0)
  {
    eventlog(eventlog_level_error,"sd_udpinput","[%d] unable to read socket error (psock_getsockopt: %s)",usocket,strerror(psock_errno()));
    return -1;
  }
  if (errlen && err) /* if it was an error, there is no packet to read */
  {
    eventlog(eventlog_level_error,"sd_udpinput","[%d] async UDP socket error notification (psock_getsockopt: %s)",usocket,strerror(err));
    return -1;
  }
  if (!(upacket = packet_create(packet_class_udp)))
  {
    eventlog(eventlog_level_error,"sd_udpinput","could not allocate raw packet for input");
    return -1;
  }

  {
    struct sockaddr_in fromaddr;
    psock_t_socklen    fromlen;
    int                len;

    fromlen = sizeof(fromaddr);
    if ((len = psock_recvfrom(usocket,packet_get_raw_data_build(upacket,0),MAX_PACKET_SIZE,0,(struct sockaddr *)&fromaddr,&fromlen))<0)
    {
      if (
#ifdef PSOCK_EINTR
	  psock_errno()!=PSOCK_EINTR &&
#endif
#ifdef PSOCK_EAGAIN
	  psock_errno()!=PSOCK_EAGAIN &&
#endif
#ifdef PSOCK_EWOULDBLOCK
	  psock_errno()!=PSOCK_EWOULDBLOCK &&
#endif
	  1)
	eventlog(eventlog_level_error,"sd_udpinput","could not recv UDP datagram (psock_recvfrom: %s)",strerror(psock_errno()));
      packet_del_ref(upacket);
      return -1;
    }

    if (fromaddr.sin_family!=PSOCK_AF_INET)
    {
      eventlog(eventlog_level_error,"sd_udpinput","got UDP datagram with bad address family %d",(int)fromaddr.sin_family);
      packet_del_ref(upacket);
      return -1;
    }

    packet_set_size(upacket,len);

    if (hexstrm)
    {
      char tempa[32];

      if (!addr_get_addr_str(curr_laddr,tempa,sizeof(tempa)))
	strcpy(tempa,"x.x.x.x:x");
      fprintf(hexstrm,"%d: recv class=%s[0x%02x] type=%s[0x%04x] from=%s to=%s length=%u\n",
	      usocket,
	      packet_get_class_str(upacket),(unsigned int)packet_get_class(upacket),
	      packet_get_type_str(upacket,packet_dir_from_client),packet_get_type(upacket),
	      addr_num_to_addr_str(ntohl(fromaddr.sin_addr.s_addr),ntohs(fromaddr.sin_port)),
	      tempa,
	      packet_get_size(upacket));
      hexdump(hexstrm,packet_get_raw_data(upacket,0),packet_get_size(upacket));
    }

    handle_udp_packet(usocket,ntohl(fromaddr.sin_addr.s_addr),ntohs(fromaddr.sin_port),upacket);
    packet_del_ref(upacket);
  }

  return 0;
}
/*!
 * @brief Transmit a packet via SSL _and_ destroy it.
 * @param remote Pointer to the \c Remote instance.
 * @param packet Pointer to the \c Packet that is to be sent.
 * @param completion Pointer to the completion routines to process.
 * @return An indication of the result of processing the transmission request.
 * @remark This uses an SSL-encrypted TCP channel, and does not imply the use of HTTPS.
 */
DWORD packet_transmit_via_ssl(Remote* remote, Packet* packet, PacketRequestCompletion* completion)
{
	CryptoContext* crypto;
	Tlv requestId;
	DWORD res;
	DWORD idx;
	TcpTransportContext* ctx = (TcpTransportContext*)remote->transport->ctx;

	lock_acquire(remote->lock);

	// If the packet does not already have a request identifier, create one for it
	if (packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID, &requestId) != ERROR_SUCCESS)
	{
		DWORD index;
		CHAR rid[32];

		rid[sizeof(rid)-1] = 0;

		for (index = 0; index < sizeof(rid)-1; index++)
		{
			rid[index] = (rand() % 0x5e) + 0x21;
		}

		packet_add_tlv_string(packet, TLV_TYPE_REQUEST_ID, rid);
	}

	do
	{
		// If a completion routine was supplied and the packet has a request
		// identifier, insert the completion routine into the list
		if ((completion) &&
			(packet_get_tlv_string(packet, TLV_TYPE_REQUEST_ID,
			&requestId) == ERROR_SUCCESS))
		{
			packet_add_completion_handler((LPCSTR)requestId.buffer, completion);
		}

		// If the endpoint has a cipher established and this is not a plaintext
		// packet, we encrypt
		if ((crypto = remote_get_cipher(remote)) &&
			(packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_REQUEST) &&
			(packet_get_type(packet) != PACKET_TLV_TYPE_PLAIN_RESPONSE))
		{
			ULONG origPayloadLength = packet->payloadLength;
			PUCHAR origPayload = packet->payload;

			// Encrypt
			if ((res = crypto->handlers.encrypt(crypto, packet->payload,
				packet->payloadLength, &packet->payload,
				&packet->payloadLength)) !=
				ERROR_SUCCESS)
			{
				SetLastError(res);
				break;
			}

			// Destroy the original payload as we no longer need it
			free(origPayload);

			// Update the header length
			packet->header.length = htonl(packet->payloadLength + sizeof(TlvHeader));
		}

		dprintf("[PACKET] New xor key for sending");
		packet->header.xor_key = rand_xor_key();
		// before transmission, xor the whole lot, starting with the body
		xor_bytes(packet->header.xor_key, (LPBYTE)packet->payload, packet->payloadLength);
		// then the header
		xor_bytes(packet->header.xor_key, (LPBYTE)&packet->header.length, 8);
		// be sure to switch the xor header before writing
		packet->header.xor_key = htonl(packet->header.xor_key);

		idx = 0;
		while (idx < sizeof(packet->header))
		{
			// Transmit the packet's header (length, type)
			res = SSL_write(
				ctx->ssl,
				(LPCSTR)(&packet->header) + idx,
				sizeof(packet->header) - idx
				);

			if (res <= 0)
			{
				dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx);
				break;
			}
			idx += res;
		}

		if (res < 0)
		{
			break;
		}

		idx = 0;
		while (idx < packet->payloadLength)
		{
			// Transmit the packet's payload (length, type)
			res = SSL_write(
				ctx->ssl,
				packet->payload + idx,
				packet->payloadLength - idx
				);

			if (res < 0)
			{
				break;
			}

			idx += res;
		}

		if (res < 0)
		{
			dprintf("[PACKET] transmit header failed with return %d at index %d\n", res, idx);
			break;
		}

		SetLastError(ERROR_SUCCESS);
	} while (0);

	res = GetLastError();

	// Destroy the packet
	packet_destroy(packet);

	lock_release(remote->lock);

	return res;
}
Esempio n. 29
0
static int sd_tcpinput(int csocket, t_connection * c)
{
    unsigned int currsize;
    t_packet *   packet;

    currsize = conn_get_in_size(c);

    if (!*conn_get_in_queue(c))
    {
	switch (conn_get_class(c))
	{
	case conn_class_init:
	    if (!(packet = packet_create(packet_class_init)))
	    {
		eventlog(eventlog_level_error,"sd_tcpinput","could not allocate init packet for input");
		return -1;
	    }
	    break;
         case conn_class_d2cs_bnetd:
            if (!(packet = packet_create(packet_class_d2cs_bnetd)))
            {
                eventlog(eventlog_level_error,"server_process","could not allocate d2cs_bnetd packet");
                return -1;
            }
            break;
	case conn_class_bnet:
	    if (!(packet = packet_create(packet_class_bnet)))
	    {
		eventlog(eventlog_level_error,"sd_tcpinput","could not allocate bnet packet for input");
		return -1;
	    }
	    break;
	case conn_class_file:
	    if (!(packet = packet_create(packet_class_file)))
	    {
		eventlog(eventlog_level_error,"sd_tcpinput","could not allocate file packet for input");
		return -1;
	    }
	    break;
	case conn_class_bits:
	    if (!(packet = packet_create(packet_class_bits)))
	    {
		eventlog(eventlog_level_error,"sd_tcpinput","could not allocate BITS packet for input");
		return -1;
	    }
	    break;
	case conn_class_defer:
	case conn_class_bot:
	case conn_class_irc:
	case conn_class_telnet:
	    if (!(packet = packet_create(packet_class_raw)))
	    {
		eventlog(eventlog_level_error,"sd_tcpinput","could not allocate raw packet for input");
		return -1;
	    }
	    packet_set_size(packet,1); /* start by only reading one char */
	    break;
	case conn_class_auth:
	    if (!(packet = packet_create(packet_class_auth)))
	    {
		eventlog(eventlog_level_error,"sd_tcpinput","could not allocate auth packet for input");
		return -1;
	    }
	    break;
	default:
	    eventlog(eventlog_level_error,"sd_tcpinput","[%d] connection has bad class (closing connection)",conn_get_socket(c));
	    conn_destroy(c);
	    return -1;
	}
	queue_push_packet(conn_get_in_queue(c),packet);
	packet_del_ref(packet);
	if (!*conn_get_in_queue(c))
	    return -1; /* push failed */
	currsize = 0;
    }

    packet = queue_peek_packet((t_queue const * const *)conn_get_in_queue(c)); /* avoid warning */
    switch (net_recv_packet(csocket,packet,&currsize))
    {
    case -1:
	eventlog(eventlog_level_debug,"sd_tcpinput","[%d] read FAILED (closing connection)",conn_get_socket(c));
	conn_destroy(c);
	return -1;

    case 0: /* still working on it */
	/* eventlog(eventlog_level_debug,"sd_tcpinput","[%d] still reading \"%s\" packet (%u of %u bytes so far)",conn_get_socket(c),packet_get_class_str(packet),conn_get_in_size(c),packet_get_size(packet)); */
	conn_set_in_size(c,currsize);
	break;

    case 1: /* done reading */
	switch (conn_get_class(c))
	{
	case conn_class_defer:
	    {
		unsigned char const * const temp=packet_get_raw_data_const(packet,0);

		eventlog(eventlog_level_debug,"sd_tcpinput","[%d] got first packet byte %02x",conn_get_socket(c),(unsigned int)temp[0]);
		if (temp[0]==(unsigned char)0xff) /* HACK: thankfully all bnet packet types end with ff */
		{
		    conn_set_class(c,conn_class_bnet);
		    conn_set_in_size(c,currsize);
		    packet_set_class(packet,packet_class_bnet);
		    eventlog(eventlog_level_debug,"sd_tcpinput","[%d] defered connection class is bnet",conn_get_socket(c));
		}
		else
		{
		    conn_set_class(c,conn_class_auth);
		    conn_set_in_size(c,currsize);
		    packet_set_class(packet,packet_class_auth);
		    eventlog(eventlog_level_debug,"sd_tcpinput","[%d] defered connection class is auth",conn_get_socket(c));
		}
	    }
	    break;

	case conn_class_bot:
	case conn_class_telnet:
	    if (currsize<MAX_PACKET_SIZE) /* if we overflow, we can't wait for the end of the line.
					     handle_*_packet() should take care of it */
	    {
		char const * const temp=packet_get_raw_data_const(packet,0);

		if ((temp[currsize-1]=='\003')||(temp[currsize-1]=='\004')) {
		    /* we have to ignore these special characters, since
		     * some bots even send them after login (eg. UltimateBot)
		     */
		    currsize--;
		    break;
		}

		if (temp[currsize-1]!='\r' && temp[currsize-1]!='\n')
		{
		    conn_set_in_size(c,currsize);
		    packet_set_size(packet,currsize+1);
		    break; /* no end of line, get another char */
		}
	    }
	    /* got a complete line or overflow, so: */
	    /*FALLTHRU*/
	default:
	    packet = queue_pull_packet(conn_get_in_queue(c));

	    if (hexstrm)
	    {
		fprintf(hexstrm,"%d: recv class=%s[0x%02x] type=%s[0x%04x] length=%u\n",
			csocket,
			packet_get_class_str(packet),(unsigned int)packet_get_class(packet),
			packet_get_type_str(packet,packet_dir_from_client),packet_get_type(packet),
			packet_get_size(packet));
		hexdump(hexstrm,packet_get_raw_data_const(packet,0),packet_get_size(packet));
	    }

	    if (conn_get_class(c)==conn_class_bot ||
		conn_get_class(c)==conn_class_telnet) /* NUL terminate the line to make life easier */
	    {
		char * const temp=packet_get_raw_data(packet,0);

		if (temp[currsize-1]=='\r' || temp[currsize-1]=='\n')
		    temp[currsize-1] = '\0'; /* have to do it here instead of above so everything
						is intact for the hexdump */
	    }

	    {
		int ret;

		switch (conn_get_class(c))
		{
		case conn_class_bits:
#ifdef WITH_BITS
		    ret = handle_bits_packet(c,packet);
#else
		    eventlog(eventlog_level_error,"sd_tcpinput","[%d] BITS not enabled (closing connection)",conn_get_socket(c));
		    ret = -1;
#endif
		    break;
		case conn_class_init:
		    ret = handle_init_packet(c,packet);
		    break;
		case conn_class_bnet:
		    ret = handle_bnet_packet(c,packet);
		    break;
                case conn_class_d2cs_bnetd:
                    ret = handle_d2cs_packet(c,packet);
                    break;
		case conn_class_bot:
		    ret = handle_bot_packet(c,packet);
		    break;
		case conn_class_telnet:
		    ret = handle_telnet_packet(c,packet);
		    break;
		case conn_class_file:
		    ret = handle_file_packet(c,packet);
		    break;
		case conn_class_auth:
		    ret = handle_auth_packet(c,packet);
		    break;
		case conn_class_irc:
		    ret = handle_irc_packet(c,packet);
		    break;
		default:
		    eventlog(eventlog_level_error,"sd_tcpinput","[%d] bad packet class %d (closing connection)",conn_get_socket(c),(int)packet_get_class(packet));
		    ret = -1;
		}
		packet_del_ref(packet);
		if (ret<0)
		{
		    conn_destroy(c);
		    return -1;
		}
	    }

	    conn_set_in_size(c,0);
	}
    }

    return 0;
}