Beispiel #1
0
extern int net_recv_packet(int sock, t_packet * packet, unsigned int * currsize)
{
    int          addlen;
    unsigned int header_size;
    void *       temp;

    if (!packet) {
	eventlog(eventlog_level_error,__FUNCTION__,"[%d] got NULL packet (closing connection)",sock);
	return -1;
    }

    if (!currsize) {
	eventlog(eventlog_level_error,__FUNCTION__,"[%d] got NULL currsize (closing connection)",sock);
	return -1;
    }

    if ((header_size = packet_get_header_size(packet))>=MAX_PACKET_SIZE) {
	eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not determine header size (closing connection)",sock);
	return -1;
    }

    if (!(temp = packet_get_raw_data_build(packet,*currsize))) {
	eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not obtain raw data pointer at offset %u (closing connection)",sock,*currsize);
	return -1;
    }

    if (*currsize<header_size)
	addlen = net_recv(sock, temp, header_size-*currsize);
    else {
	unsigned int total_size=packet_get_size(packet);

	if (total_size<header_size) {
	    eventlog(eventlog_level_warn,__FUNCTION__,"[%d] corrupted packet received (total_size=%u currsize=%u) (closing connection)",sock,total_size,*currsize);
	    return -1;
	}

	if (*currsize>=total_size) {
	    eventlog(eventlog_level_warn,__FUNCTION__,"[%d] more data requested for already complete packet (total_size=%u currsize=%u) (closing connection)",sock,total_size,*currsize);
	    return -1;
	}

	addlen = net_recv(sock, temp, total_size-*currsize);
    }

    if (addlen<=0) return addlen;

    *currsize += addlen;

    if (*currsize>=header_size && *currsize==packet_get_size(packet))
	return 1;

    return 0;
}
Beispiel #2
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;
}
Beispiel #3
0
extern int packet_append_lstr(t_packet * packet, t_lstr *lstr)
{
    unsigned short addlen;
    unsigned short size;

    if (!packet)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
        return -1;
    }
    if (!lstr || !lstr_get_str(lstr))
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got NULL string");
        return -1;
    }

    size = packet_get_size(packet);
    if (size>=MAX_PACKET_SIZE)
        return -1;

    if (MAX_PACKET_SIZE-(unsigned int)size>lstr_get_len(lstr))
	    addlen = lstr_get_len(lstr);
    else
	    addlen = MAX_PACKET_SIZE-size;
    if (addlen<1)
	return -1;

    std::memcpy(packet->u.data+size,lstr_get_str(lstr),addlen-1);
    packet->u.data[size+addlen-1] = '\0';
    packet_set_size(packet,size+addlen);

    return (int)addlen;
}
Beispiel #4
0
extern int packet_append_data(t_packet * packet, void const * data, unsigned int len)
{
    unsigned short addlen;
    unsigned short size;

    if (!packet)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
        return -1;
    }
    if (!data)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got NULL data");
        return -1;
    }

    size = packet_get_size(packet);
    if (size>=MAX_PACKET_SIZE)
        return -1;

    if (MAX_PACKET_SIZE-(unsigned int)size>len)
	    addlen = len;
    else
	    addlen = MAX_PACKET_SIZE-size;
    if (addlen<1)
	return -1;

    std::memcpy(packet->u.data+size,data,addlen);
    packet_set_size(packet,size+addlen);

    return (int)addlen;
}
Beispiel #5
0
extern int net_send_packet(int sock, t_packet const * packet, unsigned int * currsize)
{
    unsigned int size;
    int          addlen;

    if (!packet) {
	eventlog(eventlog_level_error,__FUNCTION__,"[%d] got NULL packet (closing connection)",sock);
	return -1;
    }

    if (!currsize) {
	eventlog(eventlog_level_error,__FUNCTION__,"[%d] got NULL currsize (closing connection)",sock);
	return -1;
    }

    if ((size = packet_get_size(packet))<1) {
	eventlog(eventlog_level_error,__FUNCTION__,"[%d] packet to send is empty (skipping it)",sock);
	*currsize = 0;
	return 1;
    }

    addlen = net_send(sock,packet_get_raw_data_const(packet,*currsize),size-*currsize);

    if (addlen <= 0) return addlen;

    *currsize += addlen;
    /* sent all data in this packet? */
    if (size==*currsize)
    {
	*currsize = 0;
	return 1;
    }

    return 0;
}
Beispiel #6
0
extern int packet_append_ntstring(t_packet * packet, char const * str)
{
    unsigned int   len;
    unsigned short addlen;
    unsigned short size;

    if (!packet)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
        return -1;
    }
    if (!str)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got NULL string");
        return -1;
    }

    len = std::strlen(str);
    size = packet_get_size(packet);
    if (size>=MAX_PACKET_SIZE)
        return -1;

    if (MAX_PACKET_SIZE-(unsigned int)size>len)
	    addlen = len;
    else
	    addlen = MAX_PACKET_SIZE-size;
    if (addlen<1)
	return -1;

    std::memcpy(packet->u.data+size,str,addlen);
    packet_set_size(packet,size+addlen);

    return (int)addlen;
}
Beispiel #7
0
static int on_d2cs_authreply(t_connection * c, t_packet const * packet)
{
	t_packet	* rpacket;
	unsigned int	version;
	unsigned int	try_version;
	unsigned int	reply;
	char const	* realmname;
	t_realm		* realm;

	if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_authreply)) {
		eventlog(eventlog_level_error,__FUNCTION__,"got bad packet size");
		return -1;
	}
	if (!(realmname=packet_get_str_const(packet,sizeof(t_d2cs_bnetd_authreply),REALM_NAME_LEN))) {
		eventlog(eventlog_level_error,__FUNCTION__,"got bad realmname");
		return -1;
	}
        if (!(realm=realmlist_find_realm(realmname))) {
		realm=realmlist_find_realm_by_ip(conn_get_addr(c)); /* should not fail - checked in handle_init_packet() handle_init.c */
		eventlog(eventlog_level_warn,__FUNCTION__, "warn: realm name mismatch %s %s", realm_get_name(realm), realmname);
		if (!(prefs_allow_d2cs_setname())) { /* fail if allow_d2cs_setname = false */
			eventlog(eventlog_level_error,__FUNCTION__, "d2cs not allowed to set realm name");
			return -1;
		}
		if (realm_get_active(realm)) { /* fail if realm already active */
			eventlog(eventlog_level_error,__FUNCTION__, "cannot set realm name to %s (realm already active)",realmname);
			return -1;
		}
		realm_set_name(realm,realmname);
        }
	version=prefs_get_d2cs_version();
	try_version=bn_int_get(packet->u.d2cs_bnetd_authreply.version);
	if (version && version != try_version) {
		eventlog(eventlog_level_error,__FUNCTION__,"d2cs version mismatch 0x%X - 0x%X",
			try_version,version);
		reply=BNETD_D2CS_AUTHREPLY_BAD_VERSION;
	} else {
		reply=BNETD_D2CS_AUTHREPLY_SUCCEED;
	}

	if (reply==BNETD_D2CS_AUTHREPLY_SUCCEED) {
		eventlog(eventlog_level_info,__FUNCTION__,"d2cs %s authed",
			addr_num_to_ip_str(conn_get_addr(c)));
		conn_set_state(c,conn_state_loggedin);
		realm_active(realm,c);
	} else {
		eventlog(eventlog_level_error,__FUNCTION__,"failed to auth d2cs %s",
			addr_num_to_ip_str(conn_get_addr(c)));
	}
	if ((rpacket=packet_create(packet_class_d2cs_bnetd))) {
		packet_set_size(rpacket,sizeof(t_bnetd_d2cs_authreply));
		packet_set_type(rpacket,BNETD_D2CS_AUTHREPLY);
		bn_int_set(&rpacket->u.bnetd_d2cs_authreply.h.seqno,1);
		bn_int_set(&rpacket->u.bnetd_d2cs_authreply.reply,reply);
		conn_push_outqueue(c,rpacket);
		packet_del_ref(rpacket);
	}
	return 0;
}
Beispiel #8
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 */
}
Beispiel #9
0
static int on_d2cs_authreply(t_connection * c, t_packet const * packet)
{
	t_packet	* rpacket;
	unsigned int	version;
	unsigned int	try_version;
	unsigned int	reply;
	char const	* realmname;
	t_realm		* realm;

	if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_authreply)) {
		eventlog(eventlog_level_error,"on_d2cs_authreply","got bad packet size");
		return -1;
	}
	if (!(realmname=packet_get_str_const(packet,sizeof(t_d2cs_bnetd_authreply),REALM_NAME_LEN))) {
		eventlog(eventlog_level_error,"on_d2cs_authreply","got bad realmname");
		return -1;
	}
        if (!(realm=realmlist_find_realm_by_ip(conn_get_addr(c)))) {
                eventlog(eventlog_level_error,"handle_init_packet", "realm not found");
                return -1;
        }
	if (realm_get_name(realm) && strcasecmp(realmname,realm_get_name(realm))) {
                eventlog(eventlog_level_error,"handle_init_packet", "warn: realm name mismatch %s %s",
			realm_get_name(realm),realmname);
	}

	version=prefs_get_d2cs_version();
	try_version=bn_int_get(packet->u.d2cs_bnetd_authreply.version);
	if (version && version != try_version) {
		eventlog(eventlog_level_error,"on_d2cs_authreply","d2cs version mismatch 0x%X - 0x%X",
			try_version,version);
		reply=BNETD_D2CS_AUTHREPLY_BAD_VERSION;
	} else {
		reply=BNETD_D2CS_AUTHREPLY_SUCCEED;
	}

	if (reply==BNETD_D2CS_AUTHREPLY_SUCCEED) {
		eventlog(eventlog_level_error,"on_d2cs_authreply","d2cs %s authed",
			addr_num_to_ip_str(conn_get_addr(c)));
		conn_set_state(c,conn_state_loggedin);
		if (prefs_allow_d2cs_setname()) realm_set_name(realm,realmname);
		realm_active(realm,c);
	} else {
		eventlog(eventlog_level_error,"on_d2cs_authreply","failed to auth d2cs %s",
			addr_num_to_ip_str(conn_get_addr(c)));
	}
	if ((rpacket=packet_create(packet_class_d2cs_bnetd))) {
		packet_set_size(rpacket,sizeof(t_bnetd_d2cs_authreply));
		packet_set_type(rpacket,BNETD_D2CS_AUTHREPLY);
		bn_int_set(&rpacket->u.bnetd_d2cs_authreply.reply,reply);
		queue_push_packet(conn_get_out_queue(c),rpacket);
		packet_del_ref(rpacket);
	}
	return 0;
}
Beispiel #10
0
extern t_packet * packet_duplicate(t_packet const * src)
{
    t_packet * p;

    if (!(p = packet_create(packet_get_class(src))))
    {
	eventlog(eventlog_level_error,__FUNCTION__,"could not create packet");
	return NULL;
    }
    packet_append_data(p,src->u.data,packet_get_size(src));
    packet_set_flags(p,packet_get_flags(src));

    return p;
}
bool socketpool_send_packet(const socketpool_t * socketpool, const packet_t * packet)
{
	sockaddr_u              sock;
    int                     sockfd;
    socklen_t               socklen;
    const struct sockaddr * dst_addr;
    
    memset(&sock, 0, sizeof(sockaddr_u));

    // Prepare socket 
    // We don't care about the dst_port set in the packet
    switch (packet->dst_ip->family) {
#ifdef USE_IPV4
        case AF_INET:
            sock.sin.sin_family = AF_INET;
            sock.sin.sin_addr   = packet->dst_ip->ip.ipv4;
            sockfd = socketpool->ipv4_sockfd;
            socklen = sizeof(struct sockaddr_in);
            dst_addr = (struct sockaddr *) &sock.sin;
            break;
#endif
#ifdef USE_IPV6
        case AF_INET6:
            sock.sin6.sin6_family = AF_INET6;
            memcpy(&sock.sin6.sin6_addr, &packet->dst_ip->ip.ipv6, sizeof(ipv6_t));
            sockfd = socketpool->ipv6_sockfd;
            socklen = sizeof(struct sockaddr_in6);
            dst_addr = (struct sockaddr *) &sock.sin6;
            break;
#endif
        default:
            fprintf(stderr, "socketpool_send_packet: Address family not supported");
            goto ERR_INVALID_FAMILY;
    }

    // Send the packet
    if (sendto(sockfd, packet_get_bytes(packet), packet_get_size(packet), 0, dst_addr, socklen) == -1) {
        perror("send_data: Sending error in queue");
        goto ERR_SEND_TO;
    }

    return true;

ERR_SEND_TO:
ERR_INVALID_FAMILY:
    return false;
}
Beispiel #12
0
extern void * packet_get_raw_data(t_packet * packet, unsigned int offset)
{
    unsigned int size;

    if (!packet)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
        return NULL;
    }
    size = (unsigned int)packet_get_size(packet);
    if (offset>=size || (((offset>=MAX_PACKET_SIZE) && (packet->pclass != packet_class_wolgameres)) || (offset>=MAX_WOL_GAMERES_PACKET_SIZE)))
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got bad offset %u for packet size %u",offset,size);
        return NULL;
    }

    return packet->u.data+offset;
}
Beispiel #13
0
extern void const * packet_get_data_const(t_packet const * packet, unsigned int offset, unsigned int len)
{
    unsigned int size;

    if (!packet)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
        return NULL;
    }
    if (len<1)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got zero length");
	return NULL;
    }
    size = (unsigned int)packet_get_size(packet);
    if (offset+len>size)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got bad offset %u and length %u for packet size %u",offset,len,size);
        return NULL;
    }

    return packet->u.data+offset;
}
Beispiel #14
0
/* maxlen includes room for NUL char */
extern char const * packet_get_str_const(t_packet const * packet, unsigned int offset, unsigned int maxlen)
{
    unsigned int size;
    unsigned int pos;

    if (!packet)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
        return NULL;
    }
    size = (unsigned int)packet_get_size(packet);
    if (offset>=size)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"got bad offset %u for packet size %u",offset,size);
        return NULL;
    }

    for (pos=offset; packet->u.data[pos]!='\0'; pos++)
	if (pos>=size || pos-offset>=maxlen)
	    return NULL;
    if (pos>=size || pos-offset>=maxlen) /* NUL must be inside too */
	return NULL;
    return packet->u.data+offset;
}
Beispiel #15
0
static int on_d2cs_charloginreq(t_connection * c, t_packet const * packet)
{
	t_connection *	client;
	char const *	charname;
	char const *	portrait;
	char const *	clienttag;
	char *	temp;
	unsigned int	sessionnum;
	t_realm * 	realm;
	char const *	realmname;
	unsigned int	pos, reply;
	t_packet *	rpacket;
	
	if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_charloginreq)) {
		eventlog(eventlog_level_error,__FUNCTION__,"got bad packet size");
		return -1;
	}
	sessionnum=bn_int_get(packet->u.d2cs_bnetd_charloginreq.sessionnum);
	pos=sizeof(t_d2cs_bnetd_charloginreq);
	if (!(charname=packet_get_str_const(packet,pos,CHAR_NAME_LEN))) {
		eventlog(eventlog_level_error,__FUNCTION__,"got bad character name");
		return -1;
	}
	pos+=strlen(charname)+1;
	if (!(portrait=packet_get_str_const(packet,pos,CHAR_PORTRAIT_LEN))) {
		eventlog(eventlog_level_error,__FUNCTION__,"got bad character portrait");
		return -1;
	}
	if (!(client=connlist_find_connection_by_sessionnum(sessionnum))) {
		eventlog(eventlog_level_error,__FUNCTION__,"user %d not found",sessionnum);
		reply = BNETD_D2CS_CHARLOGINREPLY_FAILED;
	} else if (!(clienttag=clienttag_uint_to_str(conn_get_clienttag(client)))) {
		eventlog(eventlog_level_error,__FUNCTION__,"got NULL clienttag");
		reply = BNETD_D2CS_CHARLOGINREPLY_FAILED;
	} else if (!(realm=conn_get_realm(client))) {
		eventlog(eventlog_level_error,__FUNCTION__,"got NULL realm");
		reply = BNETD_D2CS_CHARLOGINREPLY_FAILED;
	} else {
		char revtag[8];

		realmname = realm_get_name(realm);
		temp=xmalloc(strlen(clienttag)+strlen(realmname)+1+strlen(charname)+1+
			strlen(portrait)+1);
		reply = BNETD_D2CS_CHARLOGINREPLY_SUCCEED;
		strcpy(revtag,clienttag);
		strreverse(revtag);
		sprintf(temp,"%4s%s,%s,%s",revtag,realmname,charname,portrait);
		conn_set_charname(client,charname);
		conn_set_realminfo(client,temp);
		xfree(temp);
		eventlog(eventlog_level_debug,__FUNCTION__,
			"loaded portrait for character %s",charname);
	}
	if ((rpacket=packet_create(packet_class_d2cs_bnetd))) {
		packet_set_size(rpacket,sizeof(t_bnetd_d2cs_charloginreply));
		packet_set_type(rpacket,BNETD_D2CS_CHARLOGINREPLY);
		bn_int_set(&rpacket->u.bnetd_d2cs_charloginreply.h.seqno,
			bn_int_get(packet->u.d2cs_bnetd_charloginreq.h.seqno));
		bn_int_set(&rpacket->u.bnetd_d2cs_charloginreply.reply,reply);
		conn_push_outqueue(c,rpacket);
		packet_del_ref(rpacket);
	}
	return 0;
}
Beispiel #16
0
static int on_d2cs_charloginreq(t_connection * c, t_packet const * packet)
{
	t_connection * client;
	char const * charname;
	char const * portrait;
	char const * clienttag;
	char		* temp;
	unsigned int	sessionnum;
	char const * tname;
	char const * realmname;
	unsigned int	pos, reply;
	t_packet	* rpacket;
	
	if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_charloginreq)) {
		eventlog(eventlog_level_error,"on_d2cs_charloginreq","got bad packet size");
		return -1;
	}
	sessionnum=bn_int_get(packet->u.d2cs_bnetd_charloginreq.sessionnum);
	pos=sizeof(t_d2cs_bnetd_charloginreq);
	if (!(charname=packet_get_str_const(packet,pos,CHAR_NAME_LEN))) {
		eventlog(eventlog_level_error,"on_d2cs_charloginreq","got bad character name");
		return -1;
	}
	pos+=strlen(charname)+1;
	if (!(portrait=packet_get_str_const(packet,pos,CHAR_PORTRAIT_LEN))) {
		eventlog(eventlog_level_error,"on_d2cs_charloginreq","got bad character portrait");
		return -1;
	}
	if (!(client=connlist_find_connection_by_sessionnum(sessionnum))) {
		eventlog(eventlog_level_error,"on_d2cs_charloginreq","user %d not found",sessionnum);
		reply = BNETD_D2CS_CHARLOGINREPLY_FAILED;
	} else if (!(clienttag=conn_get_clienttag(client))) {
		eventlog(eventlog_level_error,"on_d2cs_charloginreq","got NULL clienttag");
		reply = BNETD_D2CS_CHARLOGINREPLY_FAILED;
	} else if (!(realmname=conn_get_realmname(client))) {
		eventlog(eventlog_level_error,"on_d2cs_charloginreq","got NULL realm name");
		reply = BNETD_D2CS_CHARLOGINREPLY_FAILED;
	} else if (!(temp=malloc(strlen(clienttag)+strlen(realmname)+1+strlen(charname)+1+\
			strlen(portrait)+1))) {
		eventlog(eventlog_level_error,"on_d2cs_charloginreq","error allocate temp");
		reply = BNETD_D2CS_CHARLOGINREPLY_FAILED;
	} else {
		reply = BNETD_D2CS_CHARLOGINREPLY_SUCCEED;
		sprintf (temp,"PX2D%s,%s,%s",realmname,charname,portrait);
		bn_int_tag_set((bn_int *)temp,clienttag);
		conn_set_charname(client,charname);
		conn_set_realminfo(client,temp);
		free(temp);
		eventlog(eventlog_level_debug,"on_d2cs_charloginreq",\
			"loaded portrait for character %s",charname);
	}
	if ((rpacket=packet_create(packet_class_d2cs_bnetd))) {
		packet_set_size(rpacket,sizeof(t_bnetd_d2cs_charloginreply));
		packet_set_type(rpacket,BNETD_D2CS_CHARLOGINREPLY);
		bn_int_set(&rpacket->u.bnetd_d2cs_charloginreply.h.seqno,\
			bn_int_get(packet->u.d2cs_bnetd_charloginreq.h.seqno));
		bn_int_set(&rpacket->u.bnetd_d2cs_charloginreply.reply,reply);
		queue_push_packet(conn_get_out_queue(c),rpacket);
		packet_del_ref(rpacket);
	}
	return 0;
}
Beispiel #17
0
static int on_d2cs_accountloginreq(t_connection * c, t_packet const * packet)
{
	unsigned int	sessionkey;
	unsigned int	sessionnum;
	unsigned int	salt;
	char const *	account;
	char const *	tname;
	t_connection	* client;
	int		reply;
	t_packet	* rpacket;
	struct
	{
		bn_int   salt;
		bn_int   sessionkey;
		bn_int   sessionnum;
		bn_int   secret;
		bn_int	 passhash[5];
	} temp;
	t_hash       secret_hash;
	char const * pass_str;
	t_hash	     passhash;
	t_hash	     try_hash;

	if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_accountloginreq)) {
		eventlog(eventlog_level_error,"on_d2cs_accountloginreq","got bad packet size");
		return -1;
	}
	if (!(account=packet_get_str_const(packet,sizeof(t_d2cs_bnetd_accountloginreq),USER_NAME_MAX))) {
		eventlog(eventlog_level_error,"on_d2cs_accountloginreq","got bad account name");
		return -1;
	}
	sessionkey=bn_int_get(packet->u.d2cs_bnetd_accountloginreq.sessionkey);
	sessionnum=bn_int_get(packet->u.d2cs_bnetd_accountloginreq.sessionnum);
	salt=bn_int_get(packet->u.d2cs_bnetd_accountloginreq.seqno);
	if (!(client=connlist_find_connection_by_sessionnum(sessionnum))) {
		eventlog(eventlog_level_error,"on_d2cs_accountloginreq","sessionnum %d not found",sessionnum);
		reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED;
	} else if (sessionkey!=conn_get_sessionkey(client)) {
		eventlog(eventlog_level_error,"on_d2cs_accountloginreq","sessionkey %d not match",sessionkey);
		reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED;
	} else if (!(tname=conn_get_username(client))) {
		eventlog(eventlog_level_error,"on_d2cs_accountloginreq","got NULL username");
		reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED;
	} else if (strcasecmp(account,tname)) {
		eventlog(eventlog_level_error,"on_d2cs_accountloginreq","username %s not match",account);
		conn_unget_username(client,tname);
		reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED;
	} else {
		conn_unget_username(client,tname);
		bn_int_set(&temp.salt,salt);
		bn_int_set(&temp.sessionkey,sessionkey);
		bn_int_set(&temp.sessionnum,sessionnum);
		bn_int_set(&temp.secret,conn_get_secret(client));
		pass_str=account_get_pass(conn_get_account(client));
		if (hash_set_str(&passhash,pass_str)<0) {
			reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED;
		} else {
			hash_to_bnhash((t_hash const *)&passhash,temp.passhash);
			bnet_hash(&secret_hash,sizeof(temp),&temp);
			bnhash_to_hash(packet->u.d2cs_bnetd_accountloginreq.secret_hash,&try_hash);
			if (hash_eq(try_hash,secret_hash)==1) {
				eventlog(eventlog_level_debug,"on_d2cs_accountloginreq","user %s loggedin on d2cs",\
					account);
				reply=BNETD_D2CS_ACCOUNTLOGINREPLY_SUCCEED;
			} else {
				eventlog(eventlog_level_error,"on_d2cs_accountloginreq","user %s hash not match",\
					account);
				reply=BNETD_D2CS_ACCOUNTLOGINREPLY_FAILED;
			}
		}
		account_unget_pass(pass_str);
	}
	if ((rpacket=packet_create(packet_class_d2cs_bnetd))) {
		packet_set_size(rpacket,sizeof(t_bnetd_d2cs_accountloginreply));
		packet_set_type(rpacket,BNETD_D2CS_ACCOUNTLOGINREPLY);
		bn_int_set(&rpacket->u.bnetd_d2cs_accountloginreply.h.seqno,\
			bn_int_get(packet->u.d2cs_bnetd_accountloginreq.h.seqno));
		bn_int_set(&rpacket->u.bnetd_d2cs_accountloginreply.reply,reply);
		queue_push_packet(conn_get_out_queue(c),rpacket);
		packet_del_ref(rpacket);
	}
	return 0;
}
Beispiel #18
0
size_t probe_get_size(const probe_t * probe) {
    return packet_get_size(probe->packet);
}
Beispiel #19
0
probe_t * probe_wrap_packet(packet_t * packet)
{
    probe_t          * probe;
    size_t             segment_size, remaining_size;
    layer_t          * layer;
    uint8_t          * segment;
    const protocol_t * protocol;

    if (!(probe = probe_create())) {
        goto ERR_PROBE_CREATE;
    }

    // Clear the probe
    packet_free(probe->packet);
    probe->packet = packet;
    probe_layers_clear(probe);

    // Prepare iteration
    segment = packet_get_bytes(probe->packet);
    remaining_size = packet_get_size(probe->packet);

    // Push layers
    for (protocol = get_first_protocol(packet); protocol; protocol = protocol->get_next_protocol(layer)) {
        if (remaining_size < protocol->write_default_header(NULL)) {
            // Not enough bytes left for the header, packet is truncated
            segment_size = remaining_size;
        } else {
            segment_size = protocol->get_header_size(segment);
        }

        if (!(layer = layer_create_from_segment(protocol, segment, segment_size))) {
            goto ERR_CREATE_LAYER;
        }

        if (!probe_push_layer(probe, layer)) {
            goto ERR_PUSH_LAYER;
        }

        segment += segment_size;
        remaining_size -= segment_size;
        if (remaining_size < 0) {
            fprintf(stderr, "probe_wrap_packet: Truncated packet\n");
            goto ERR_TRUNCATED_PACKET;
        }

        if (!protocol->get_next_protocol) {
            break;
        }
        continue;

ERR_TRUNCATED_PACKET:
ERR_PUSH_LAYER:
        layer_free(layer);
ERR_CREATE_LAYER:
        goto ERR_LAYER_DISCOVER_LAYER;
    }

    // Rq: Some packets (e.g ICMP type 3) do not have payload.
    // In this case we push an empty payload
    probe_push_payload(probe, remaining_size);

    return probe;

ERR_LAYER_DISCOVER_LAYER:
    probe_free(probe);
ERR_PROBE_CREATE:
    return NULL;
}
Beispiel #20
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;
}
Beispiel #21
0
extern int handle_bot_packet(t_connection * c, t_packet const * const packet)
{
    t_packet * rpacket;
    
    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_raw)
    {
        eventlog(eventlog_level_error,__FUNCTION__,"[%d] got bad packet (class %d)",conn_get_socket(c),(int)packet_get_class(packet));
        return -1;
    }
    
    {
	char const * const linestr=packet_get_str_const(packet,0,MAX_MESSAGE_LEN);
	
	if (packet_get_size(packet)<2) /* empty line */
	    return 0;
	if (!linestr)
	{
	    eventlog(eventlog_level_warn,__FUNCTION__,"[%d] line too long",conn_get_socket(c));
	    return 0;
	}
	
	switch (conn_get_state(c))
	{
	case conn_state_connected:
	    conn_add_flags(c,MF_PLUG);
	    conn_set_clienttag(c,CLIENTTAG_BNCHATBOT_UINT);
	    
	    {
		char const * temp=linestr;
		
		if (temp[0]=='\004') /* FIXME: no echo, ignore for now (we always do no echo) */
		    temp = &temp[1];
		
		if (temp[0]=='\0') /* empty line */
		{
		    conn_set_state(c,conn_state_bot_username); /* don't look for ^D or reset tag and flags */
		    break;
		}
		
		conn_set_state(c,conn_state_bot_password);
		
		if (conn_set_loggeduser(c,temp)<0)
		    eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set username to \"%s\"",conn_get_socket(c),temp);
		
		{
		    char const * const msg="\r\nPassword: "******"[%d] could not create rpacket",conn_get_socket(c));
			break;
		    }
#if 1 /* don't echo */
		    packet_append_ntstring(rpacket,conn_get_loggeduser(c));
#endif
		    packet_append_ntstring(rpacket,msg);
		    conn_push_outqueue(c,rpacket);
		    packet_del_ref(rpacket);
		}
	    }
	    break;
	    
	case conn_state_bot_username:
	    conn_set_state(c,conn_state_bot_password);
	    
	    if (conn_set_loggeduser(c,linestr)<0)
		eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set username to \"%s\"",conn_get_socket(c),linestr);
	    
	    {
		char const * const temp="\r\nPassword: "******"[%d] could not create rpacket",conn_get_socket(c));
		    break;
		}
#if 1 /* don't echo */
		packet_append_ntstring(rpacket,linestr);
#endif
		packet_append_ntstring(rpacket,temp);
		conn_push_outqueue(c,rpacket);
		packet_del_ref(rpacket);
	    }
	    break;
	    
	case conn_state_bot_password:
	    {
		char const * const tempa="\r\nLogin failed.\r\n\r\nUsername: "******"\r\nAccount has no bot access.\r\n\r\nUsername: "******"[%d] could not create rpacket",conn_get_socket(c));
			break;
		    }
		    
		    packet_append_ntstring(rpacket,tempa);
		    conn_push_outqueue(c,rpacket);
		    packet_del_ref(rpacket);
		    break;
		}
		if (connlist_find_connection_by_accountname(loggeduser))
		{
		    eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (already logged in)",conn_get_socket(c),loggeduser);
		    conn_set_state(c,conn_state_bot_username);
		    
		    if (!(rpacket = packet_create(packet_class_raw)))
		    {
			eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c));
			break;
		    }
		    
		    packet_append_ntstring(rpacket,tempa);
		    conn_push_outqueue(c,rpacket);
		    packet_del_ref(rpacket);
		    break;
		}
		if (!(account = accountlist_find_account(loggeduser)))
		{
			eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (bad account)",conn_get_socket(c),loggeduser);
			conn_set_state(c,conn_state_bot_username);
			
			if (!(rpacket = packet_create(packet_class_raw)))
			{
			    eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c));
			    break;
			}
			
			packet_append_ntstring(rpacket,tempa);
			conn_push_outqueue(c,rpacket);
			packet_del_ref(rpacket);
		    break;
		}
		if ((oldstrhash1 = account_get_pass(account)))
		{
		    if (hash_set_str(&oldpasshash1,oldstrhash1)<0)
		    {
			eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (corrupted passhash1?)",conn_get_socket(c),loggeduser);
			conn_set_state(c,conn_state_bot_username);
			
			if (!(rpacket = packet_create(packet_class_raw)))
			{
			    eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c));
			    break;
			}
			
			packet_append_ntstring(rpacket,tempa);
			conn_push_outqueue(c,rpacket);
			packet_del_ref(rpacket);
			break;
		    }

                    testpass = xstrdup(linestr);
		    {
			unsigned int i;
			
			for (i=0; i<strlen(testpass); i++)
			    if (isupper((int)testpass[i]))
				testpass[i] = tolower((int)testpass[i]);
		    }
		    if (bnet_hash(&trypasshash1,strlen(testpass),testpass)<0) /* FIXME: force to lowercase */
		    {
			eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (unable to hash password)",conn_get_socket(c), loggeduser);
			conn_set_state(c,conn_state_bot_username);

			xfree((void *)testpass);
			
			if (!(rpacket = packet_create(packet_class_raw)))
			{
			    eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c));
			    break;
			}
			
			packet_append_ntstring(rpacket,tempa);
			conn_push_outqueue(c,rpacket);
			packet_del_ref(rpacket);
			break;
		    }
		    xfree((void *)testpass);
		    if (hash_eq(trypasshash1,oldpasshash1)!=1)
		    {
			eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (wrong password)",conn_get_socket(c), loggeduser);
			conn_set_state(c,conn_state_bot_username);
			
			if (!(rpacket = packet_create(packet_class_raw)))
			{
			    eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c));
			    break;
			}
			
			packet_append_ntstring(rpacket,tempa);
			conn_push_outqueue(c,rpacket);
			packet_del_ref(rpacket);
			break;
		    }
		    
		    
		    if (account_get_auth_botlogin(account)!=1) /* default to false */
		    {
			eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (no bot access)",conn_get_socket(c), loggeduser);
			conn_set_state(c,conn_state_bot_username);
			
			if (!(rpacket = packet_create(packet_class_raw)))
			{
			    eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c));
			    break;
			}
			
			packet_append_ntstring(rpacket,tempb);
			conn_push_outqueue(c,rpacket);
			packet_del_ref(rpacket);
			break;
		    }
		    else if (account_get_auth_lock(account)==1) /* default to false */
		    {
			eventlog(eventlog_level_info,__FUNCTION__,"[%d] bot login for \"%s\" refused (this account is locked)",conn_get_socket(c), loggeduser);
			conn_set_state(c,conn_state_bot_username);
			
			if (!(rpacket = packet_create(packet_class_raw)))
			{
			    eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c));
			    break;
			}
			
			packet_append_ntstring(rpacket,tempb);
			conn_push_outqueue(c,rpacket);
			packet_del_ref(rpacket);
			break;
		    }
		    
		    eventlog(eventlog_level_info,__FUNCTION__,"[%d] \"%s\" bot logged in (correct password)",conn_get_socket(c), loggeduser);
		}
		else
		{
		    eventlog(eventlog_level_info,__FUNCTION__,"[%d] \"%s\" bot logged in (no password)",conn_get_socket(c), loggeduser);
		}
		    if (!(rpacket = packet_create(packet_class_raw))) /* if we got this far, let them log in even if this fails */
			eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not create rpacket",conn_get_socket(c));
		    else
		    {
			packet_append_ntstring(rpacket,"\r\n");
			conn_push_outqueue(c,rpacket);
			packet_del_ref(rpacket);
		    }

			bnetd_log(loggeduser, addr_num_to_ip_str(conn_get_addr(c)), "BOT", "LOGIN", NULL, 1, 0);
		    conn_login(c,account,loggeduser);

		    message_send_text(c,message_type_uniqueid,c,loggeduser);
		    		    
		    if (conn_set_channel(c,CHANNEL_NAME_CHAT)<0)
			conn_set_channel(c,CHANNEL_NAME_BANNED); /* should not fail */
	    }
	    break;
	    
	case conn_state_loggedin:
	    {
		t_channel const * channel;
		
		conn_set_idletime(c);
		
		if ((channel = conn_get_channel(c)))
		    channel_message_log(channel,c,1,linestr);
		/* we don't log game commands currently */
		
		if (linestr[0]=='/')
		    handle_command(c,linestr);
		else
		    if (channel && !conn_quota_exceeded(c,linestr))
			channel_message_send(channel,message_type_talk,c,linestr);
		    /* else discard */
	    }
	    break;
	    
	default:
	    eventlog(eventlog_level_error,__FUNCTION__,"[%d] unknown bot connection state %d",conn_get_socket(c),(int)conn_get_state(c));
	}
    }
    
    return 0;
}
Beispiel #22
0
extern char const * packet_get_type_str(t_packet const * packet, t_packet_dir dir)
{
    if (!packet)
    {
	eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
	return "unknown";
    }

    switch (dir)
    {
    case packet_dir_from_client:
	switch (packet->pclass)
	{
	case packet_class_init:
	    return "CLIENT_INITCONN";
	case packet_class_bnet:
	    if (packet_get_size(packet)<sizeof(t_bnet_header))
	    {
		eventlog(eventlog_level_error,__FUNCTION__,"packet is shorter than header (len=%u)",packet_get_size(packet));
		return "unknown";
	    }
	    switch (bn_short_get(packet->u.bnet.h.type))
	    {
	    case CLIENT_COMPINFO1:
				return "CLIENT_COMPINFO1";
			case CLIENT_COMPINFO2:
				return "CLIENT_COMPINFO2";
			case CLIENT_COUNTRYINFO1:
				return "CLIENT_COUNTRYINFO1";
			case CLIENT_COUNTRYINFO_109:
				return "CLIENT_COUNTRYINFO_109";
			case CLIENT_CREATEACCTREQ1:
				return "CLIENT_CREATEACCTREQ1";
			case CLIENT_UNKNOWN_2B:
				return "CLIENT_UNKNOWN_2B";
			case CLIENT_PROGIDENT:
				return "CLIENT_PROGIDENT";
			case CLIENT_AUTHREQ1:
				return "CLIENT_AUTHREQ1";
			case CLIENT_AUTHREQ_109:
				return "CLIENT_AUTHREQ_109";
			case CLIENT_REGSNOOPREPLY:
				return "CLIENT_REGSNOOPREPLY";
			case CLIENT_ICONREQ:
				return "CLIENT_ICONREQ";
			case CLIENT_LADDERSEARCHREQ:
				return "CLIENT_LADDERSEARCHREQ";
			case CLIENT_CDKEY:
				return "CLIENT_CDKEY";
			case CLIENT_CDKEY2:
				return "CLIENT_CDKEY2";
			case CLIENT_CDKEY3:
				return "CLIENT_CDKEY3";
			case CLIENT_REALMLISTREQ:
				return "CLIENT_REALMLISTREQ";
			case CLIENT_REALMLISTREQ_110:
				return "CLIENT_REALMLISTREQ_110";
			case CLIENT_PROFILEREQ:
				return "CLIENT_PROFILEREQ";
			case CLIENT_UNKNOWN_37:
				return "CLIENT_UNKNOWN_37";
			case CLIENT_UNKNOWN_39:
				return "CLIENT_UNKNOWN_39";
			case CLIENT_LOGINREQ2:
				return "CLIENT_LOGINREQ2";
			case CLIENT_MOTD_W3:
				return "CLIENT_MOTD_W3";
			case CLIENT_LOGINREQ_W3:
				return "CLIENT_LOGINREQ_W3";
			case CLIENT_LOGONPROOFREQ:
				return "CLIENT_LOGONPROOFREQ";
			case CLIENT_CREATEACCOUNT_W3:
				return "CLIENT_CREATEACCOUNT_W3";
			case CLIENT_PASSCHANGEREQ:
				return "CLIENT_PASSCHANGEREQ";
			case CLIENT_PASSCHANGEPROOFREQ:
				return "CLIENT_PASSCHANGEPROOFREQ";
			case CLIENT_CHANGEGAMEPORT:
				return "CLIENT_CHANGEGAMEPORT";
			case CLIENT_CREATEACCTREQ2:
				return "CLIENT_CREATEACCTREQ2";
			case CLIENT_UDPOK:
				return "CLIENT_UDPOK";
			case CLIENT_FILEINFOREQ:
				return "CLIENT_FILEINFOREQ";
			case CLIENT_STATSREQ:
				return "CLIENT_STATSREQ";
			case CLIENT_LOGINREQ1:
				return "CLIENT_LOGINREQ1";
			case CLIENT_CHANGEPASSREQ:
				return "CLIENT_CHANGEPASSREQ";
			case CLIENT_PLAYERINFOREQ:
				return "CLIENT_PLAYERINFOREQ";
			case CLIENT_PROGIDENT2:
				return "CLIENT_PROGIDENT2";
			case CLIENT_JOINCHANNEL:
				return "CLIENT_JOINCHANNEL";
			case CLIENT_MESSAGE:
				return "CLIENT_MESSAGE";
			case CLIENT_GAMELISTREQ:
				return "CLIENT_GAMELISTREQ";
			case CLIENT_STARTGAME1:
				return "CLIENT_STARTGAME1";
			case CLIENT_UNKNOWN_1B:
				return "CLIENT_UNKNOWN_1B";
			case CLIENT_STARTGAME3:
				return "CLIENT_STARTGAME3";
			case CLIENT_STARTGAME4:
				return "CLIENT_STARTGAME4";
			case CLIENT_CLOSEGAME:
				return "CLIENT_CLOSEGAME";
			case CLIENT_CLOSEGAME2:
				return "CLIENT_CLOSEGAME2";
			case CLIENT_LEAVECHANNEL:
				return "CLIENT_LEAVECHANNEL";
			case CLIENT_MAPAUTHREQ1:
				return "CLIENT_MAPAUTHREQ1";
			case CLIENT_MAPAUTHREQ2:
				return "CLIENT_MAPAUTHREQ2";
			case CLIENT_ADREQ:
				return "CLIENT_ADREQ";
			case CLIENT_ADACK:
				return "CLIENT_ADACK";
			case CLIENT_ADCLICK:
				return "CLIENT_ADCLICK";
			case CLIENT_ADCLICK2:
				return "CLIENT_ADCLICK2";
			case CLIENT_UNKNOWN_17:
				return "CLIENT_UNKNOWN_17";
			case CLIENT_UNKNOWN_24:
				return "CLIENT_UNKNOWN_24";
			case CLIENT_LADDERREQ:
				return "CLIENT_LADDERREQ";
			case CLIENT_ECHOREPLY:
				return "CLIENT_ECHOREPLY";
			case CLIENT_PINGREQ:
				return "CLIENT_PINGREQ";
			case CLIENT_GAME_REPORT:
				return "CLIENT_GAME_REPORT";
			case CLIENT_JOIN_GAME:
				return "CLIENT_JOIN_GAME";
			case CLIENT_STATSUPDATE:
				return "CLIENT_STATSUPDATE";
			case CLIENT_REALMJOINREQ_109:
				return "CLIENT_REALMJOINREQ_109";
			case CLIENT_CHANGECLIENT:
				return "CLIENT_CHANGECLIENT";
			case CLIENT_SETEMAILREPLY:
				return "CLIENT_SETEMAILREPLY";
			case CLIENT_GETPASSWORDREQ:
				return "CLIENT_GETPASSWORDREQ";
			case CLIENT_CHANGEEMAILREQ:
				return "CLIENT_CHANGEEMAILREQ";
			case CLIENT_CRASHDUMP:
				return "CLIENT_CRASHDUMP";
			case CLIENT_FINDANONGAME:
				return "CLIENT_FINDANONGAME";
			case CLIENT_ARRANGEDTEAM_FRIENDSCREEN:
				return "CLIENT_ARRANGEDTEAM_FRIENDSCREEN";
			case CLIENT_ARRANGEDTEAM_INVITE_FRIEND:
				return "CLIENT_ARRANGEDTEAM_INVITE_FRIEND";
			case CLIENT_ARRANGEDTEAM_ACCEPT_DECLINE_INVITE:
				return "CLIENT_ARRANGEDTEAM_ACCEPT_DECLINE_INVITE";
			case CLIENT_FRIENDSLISTREQ:
				return "CLIENT_FRIENDSLISTREQ";
			case CLIENT_FRIENDINFOREQ:
				return "CLIENT_FRIENDINFOREQ";
			case CLIENT_CLANINFOREQ:
				return "CLIENT_CLANINFOREQ";
			case CLIENT_CLAN_CREATEREQ:
				return "CLIENT_CLAN_CREATEREQ";
			case CLIENT_CLAN_CREATEINVITEREQ:
				return "CLIENT_CLAN_CREATEINVITEREQ";
			case CLIENT_CLAN_CREATEINVITEREPLY:
				return "CLIENT_CLAN_CREATEINVITEREPLY";
			case CLIENT_CLAN_DISBANDREQ:
				return "CLIENT_CLAN_DISBANDREQ";
			case CLIENT_CLAN_MEMBERNEWCHIEFREQ:
				return "CLIENT_CLAN_MEMBERNEWCHIEFREQ";
			case CLIENT_CLAN_INVITEREQ:
				return "CLIENT_CLAN_INVITEREQ";
			case CLIENT_CLANMEMBER_REMOVE_REQ:
				return "CLIENT_CLANMEMBER_REMOVE_REQ";
			case CLIENT_CLAN_INVITEREPLY:
				return "CLIENT_CLAN_INVITEREPLY";
			case CLIENT_CLANMEMBER_RANKUPDATE_REQ:
				return "CLIENT_CLANMEMBER_RANKUPDATE_REQ";
			case CLIENT_CLAN_MOTDCHG:
				return "CLIENT_CLAN_MOTDCHG";
			case CLIENT_CLAN_MOTDREQ:
				return "CLIENT_CLAN_MOTDREQ";
			case CLIENT_CLANMEMBERLIST_REQ:
				return "CLIENT_CLANMEMBERLIST_REQ";
			}
			return "unknown";

	case packet_class_file:
	    if (packet_get_size(packet)<sizeof(t_file_header))
	    {
		eventlog(eventlog_level_error,__FUNCTION__,"packet is shorter than header (len=%u)",packet_get_size(packet));
		return "unknown";
	    }
	    switch (bn_short_get(packet->u.file.h.type))
	    {
	    case CLIENT_FILE_REQ:
		return "CLIENT_FILE_REQ";
	    }
	    return "unknown";

	case packet_class_udp:
	    if (packet_get_size(packet)<sizeof(t_udp_header))
	    {
		eventlog(eventlog_level_error,__FUNCTION__,"packet is shorter than header (len=%u)",packet_get_size(packet));
		return "unknown";
	    }
	    switch (bn_int_get(packet->u.udp.h.type))
	    {
	    case SERVER_UDPTEST: /* we get these if we send stuff to ourself */
		return "SERVER_UDPTEST";
	    case CLIENT_UDPPING:
		return "CLIENT_UDPPING";
	    case CLIENT_SESSIONADDR1:
		return "CLIENT_SESSIONADDR1";
	    case CLIENT_SESSIONADDR2:
		return "CLIENT_SESSIONADDR2";
	    }
	    return "unknown";

	case packet_class_raw:
	    return "CLIENT_RAW";

       case packet_class_d2game:
	    if (packet_get_size(packet)<sizeof(t_d2game_header))
	    {
               eventlog(eventlog_level_error,__FUNCTION__,"packet is shorter than header (len=%u)",packet_get_size(packet));
               return "unknown";
	    }
	    switch (bn_byte_get(packet->u.d2game.h.type))
	    {
	    default:
		return "CLIENT_D2GAME";
	    }
	    return "unknown";

        case packet_class_d2cs:
                return "D2CS";
        case packet_class_d2gs:
                return "D2GS";
        case packet_class_d2cs_bnetd:
                return "D2CS_BNETD";

	case packet_class_w3route:
	    if (packet_get_size(packet)<sizeof(t_w3route_header))
	    {
		eventlog(eventlog_level_error,__FUNCTION__,"packet is shorter than header (len=%u)",packet_get_size(packet));
		return "unknown";
	    }
	    switch (bn_short_get(packet->u.bnet.h.type))
	    {
	    case CLIENT_W3ROUTE_REQ:
	        return "CLIENT_W3ROUTE_REQ";
	    case CLIENT_W3ROUTE_LOADINGDONE:
	        return "CLIENT_W3ROUTE_LOADINGDONE";
	    case CLIENT_W3ROUTE_ABORT:
	        return "CLIENT_W3ROUTE_ABORT";
	    case CLIENT_W3ROUTE_CONNECTED:
	        return "CLIENT_W3ROUTE_CONNECTED";
	    case CLIENT_W3ROUTE_ECHOREPLY:
	        return "CLIENT_W3ROUTE_ECHOREPLY";
	    case CLIENT_W3ROUTE_GAMERESULT:
	        return "CLIENT_W3ROUTE_GAMERESULT";
	    case CLIENT_W3ROUTE_GAMERESULT_W3XP:
	        return "CLIENT_W3ROUTE_GAMERESULT_W3XP";
	    }
	    return "unknown";

	case packet_class_none:
	    return "unknown";
	}

	eventlog(eventlog_level_error,__FUNCTION__,"packet has invalid class %d",(int)packet->pclass);
	return "unknown";

    case packet_dir_from_server:
	switch (packet->pclass)
	{
	case packet_class_init:
	    return "unknown";
	case packet_class_bnet:
	    if (packet_get_size(packet)<sizeof(t_bnet_header))
	    {
		eventlog(eventlog_level_error,__FUNCTION__,"packet is shorter than header (len=%u)",packet_get_size(packet));
		return "unknown";
	    }
	    switch (bn_short_get(packet->u.bnet.h.type))
	    {
	    case SERVER_COMPREPLY:
				return "SERVER_COMPREPLY";
			case SERVER_SESSIONKEY1:
				return "SERVER_SESSIONKEY1";
			case SERVER_SESSIONKEY2:
				return "SERVER_SESSIONKEY2";
			case SERVER_CREATEACCTREPLY1:
				return "SERVER_CREATEACCTREPLY1";
			case SERVER_AUTHREQ1:
				return "SERVER_AUTHREQ1";
			case SERVER_AUTHREQ_109:
				return "SERVER_AUTHREQ_109";
			case SERVER_AUTHREPLY1:
				return "SERVER_AUTHREPLY1";
			case SERVER_AUTHREPLY_109:
				return "SERVER_AUTHREPLY_109";
			case SERVER_REGSNOOPREQ:
				return "SERVER_REGSNOOPREQ";
			case SERVER_ICONREPLY:
				return "SERVER_ICONREPLY";
			case SERVER_LADDERSEARCHREPLY:
				return "SERVER_LADDERSEARCHREPLY";
			case SERVER_CDKEYREPLY:
				return "SERVER_CDKEYREPLY";
			case SERVER_CDKEYREPLY2:
				return "SERVER_CDKEYREPLY2";
			case SERVER_CDKEYREPLY3:
				return "SERVER_CDKEYREPLY3";
			case SERVER_REALMLISTREPLY:
				return "SERVER_REALMLISTREPLY";
			case SERVER_REALMLISTREPLY_110:
				return "SERVER_REALMLISTREPLY_110";
			case SERVER_PROFILEREPLY:
				return "SERVER_PROFILEREPLY";
			case SERVER_UNKNOWN_37:
				return "SERVER_UNKNOWN_37";
			case SERVER_MOTD_W3:
				return "SERVER_MOTD_W3";
			case SERVER_LOGINREPLY_W3:
				return "SERVER_LOGINREPLY_W3";
			case SERVER_LOGONPROOFREPLY:
				return "SERVER_LOGONPROOFREPLY";
			case SERVER_CREATEACCOUNT_W3:
				return "SERVER_CREATEACCOUNT_W3";
			case SERVER_PASSCHANGEREPLY:
				return "SERVER_PASSCHANGEREPLY";
			case SERVER_PASSCHANGEPROOFREPLY:
				return "SERVER_PASSCHANGEPROOFREPLY";
			case SERVER_LOGINREPLY2:
				return "SERVER_LOGINREPLY2";
			case SERVER_CREATEACCTREPLY2:
				return "SERVER_CREATEACCTREPLY2";
			case SERVER_FILEINFOREPLY:
				return "SERVER_FILEINFOREPLY";
			case SERVER_STATSREPLY:
				return "SERVER_STATSREPLY";
			case SERVER_LOGINREPLY1:
				return "SERVER_LOGINREPLY1";
			case SERVER_CHANGEPASSACK:
				return "SERVER_CHANGEPASSACK";
			case SERVER_PLAYERINFOREPLY:
				return "SERVER_PLAYERINFOREPLY";
			case SERVER_CHANNELLIST:
				return "SERVER_CHANNELLIST";
			case SERVER_SERVERLIST:
				return "SERVER_SERVERLIST";
			case SERVER_MESSAGE:
				return "SERVER_MESSAGE";
			case SERVER_GAMELISTREPLY:
				return "SERVER_GAMELISTREPLY";
			case SERVER_STARTGAME1_ACK:
				return "SERVER_STARTGAME1_ACK";
			case SERVER_STARTGAME3_ACK:
				return "SERVER_STARTGAME3_ACK";
			case SERVER_STARTGAME4_ACK:
				return "SERVER_STARTGAME4_ACK";
			case SERVER_MAPAUTHREPLY1:
				return "SERVER_MAPAUTHREPLY1";
			case SERVER_MAPAUTHREPLY2:
				return "SERVER_MAPAUTHREPLY2";
			case SERVER_ADREPLY:
				return "SERVER_ADREPLY";
			case SERVER_ADCLICKREPLY2:
				return "SERVER_ADCLICKREPLY2";
			case SERVER_LADDERREPLY:
				return "SERVER_LADDERREPLY";
			case SERVER_ECHOREQ:
				return "SERVER_ECHOREQ";
			case SERVER_PINGREPLY:
				return "SERVER_PINGREPLY";
			case SERVER_REALMJOINREPLY_109:
				return "SERVER_REALMJOINREPLY_109";
			case SERVER_SETEMAILREQ:
				return "SERVER_SETEMAILREQ";
			case SERVER_FINDANONGAME:
				return "SERVER_FINDANONGAME";
			case SERVER_ARRANGEDTEAM_FRIENDSCREEN:
				return "SERVER_ARRANGEDTEAM_FRIENDSCREEN";
			case SERVER_ARRANGEDTEAM_INVITE_FRIEND_ACK:
				return "SERVER_ARRANGEDTEAM_INVITE_FRIEND_ACK";
			case SERVER_ARRANGEDTEAM_SEND_INVITE:
				return "SERVER_ARRANGEDTEAM_SEND_INVITE";
			case SERVER_ARRANGEDTEAM_MEMBER_DECLINE:
				return "SERVER_ARRANGEDTEAM_MEMBER_DECLINE";
			case SERVER_FRIENDSLISTREPLY:
				return "SERVER_FRIENDSLISTREPLY";
			case SERVER_FRIENDINFOREPLY:
				return "SERVER_FRIENDINFOREPLY";
			case SERVER_FRIENDADD_ACK:
				return "SERVER_FRIENDADD_ACK";
			case SERVER_FRIENDDEL_ACK:
				return "SERVER_FRIENDDEL_ACK";
			case SERVER_FRIENDMOVE_ACK:
				return "SERVER_FRIENDMOVE_ACK";
			case SERVER_CLANINFOREPLY:
				return "SERVER_CLANINFO_REPLY";
			case SERVER_CLAN_CREATEREPLY:
				return "SERVER_CLAN_CREATEREPLY";
			case SERVER_CLAN_CREATEINVITEREPLY:
				return "SERVER_CLAN_CREATEINVITEREPLY";
			case SERVER_CLAN_CREATEINVITEREQ:
				return "SERVER_CLAN_CREATEINVITEREQ";
			case SERVER_CLAN_DISBANDREPLY:
				return "SERVER_CLAN_DISBANDREPLY";
			case SERVER_CLAN_MEMBERNEWCHIEFREPLY:
				return "SERVER_CLAN_MEMBERNEWCHIEFREPLY";
			case SERVER_CLAN_CLANACK:
				return "SERVER_CLAN_CLANACK";
			case SERVER_CLANQUITNOTIFY:
				return "SERVER_CLANQUITNOTIFY";
			case SERVER_CLAN_INVITEREPLY:
				return "SERVER_CLAN_INVITEREPLY";
			case SERVER_CLANMEMBER_REMOVE_REPLY:
				return "SERVER_CLANMEMBER_REMOVE_REPLY";
			case SERVER_CLAN_INVITEREQ:
				return "SERVER_CLAN_INVITEREQ";
			case SERVER_CLANMEMBER_RANKUPDATE_REPLY:
				return "SERVER_CLANMEMBER_RANKUPDATE_REPLY";
			case SERVER_CLAN_MOTDREPLY:
				return "SERVER_CLAN_MOTDREPLY";
			case SERVER_CLANMEMBERLIST_REPLY:
				return "SERVER_CLANMEMBERLIST_REPLY";
			case SERVER_CLANMEMBER_REMOVED_NOTIFY:
				return "SERVER_CLANMEMBER_REMOVED_NOTIFY";
			case SERVER_CLANMEMBERUPDATE:
				return "SERVER_CLANMEMBERUPDATE";
			}
			return "unknown";

	case packet_class_file:
	    if (packet_get_size(packet)<sizeof(t_file_header))
	    {
		eventlog(eventlog_level_error,__FUNCTION__,"packet is shorter than header (len=%u)",packet_get_size(packet));
		return "unknown";
	    }
	    switch (bn_short_get(packet->u.file.h.type))
	    {
	    case SERVER_FILE_REPLY:
		return "SERVER_FILE_REPLY";
	    }
	    return "unknown";

	case packet_class_udp:
	    if (packet_get_size(packet)<sizeof(t_udp_header))
	    {
		eventlog(eventlog_level_error,__FUNCTION__,"packet is shorter than header (len=%u)",packet_get_size(packet));
		return "unknown";
	    }
	    switch (bn_int_get(packet->u.udp.h.type))
	    {
	    case SERVER_UDPTEST:
		return "SERVER_UDPTEST";
	    }
	    return "unknown";

	case packet_class_raw:
	    return "SERVER_RAW";

	case packet_class_d2game:
	    if (packet_get_size(packet)<sizeof(t_d2game_header))
	    {
		eventlog(eventlog_level_error,__FUNCTION__,"packet is shorter than header (len=%u)",packet_get_size(packet));
		return "unknown";
	    }
	    switch (bn_byte_get(packet->u.d2game.h.type))
	    {
	    default:
		return "SERVER_D2GAME";
	    }
	    return "unknown";

        case packet_class_d2cs:
                return "D2CS";
        case packet_class_d2gs:
                return "D2GS";
        case packet_class_d2cs_bnetd:
                return "D2CS_BNETD";

	case packet_class_w3route:
	    if (packet_get_size(packet)<sizeof(t_w3route_header))
	    {
		eventlog(eventlog_level_error,__FUNCTION__,"packet is shorter than header (len=%u)",packet_get_size(packet));
		return "unknown";
	    }
	    switch (bn_short_get(packet->u.bnet.h.type))
	    {
	    case SERVER_W3ROUTE_READY:
	        return "SERVER_W3ROUTE_READY";
	    case SERVER_W3ROUTE_LOADINGACK:
	        return "SERVER_W3ROUTE_LOADINGACK";
	    case SERVER_W3ROUTE_ECHOREQ:
	        return "SERVER_W3ROUTE_ECHOREQ";
	    case SERVER_W3ROUTE_ACK:
	        return "SERVER_W3ROUTE_ACK";
	    case SERVER_W3ROUTE_PLAYERINFO:
	        return "SERVER_W3ROUTE_PLAYERINFO";
	    case SERVER_W3ROUTE_LEVELINFO:
	        return "SERVER_W3ROUTE_LEVELINFO";
	    case SERVER_W3ROUTE_STARTGAME1:
	        return "SERVER_W3ROUTE_STARTGAME1";
	    case SERVER_W3ROUTE_STARTGAME2:
	        return "SERVER_W3ROUTE_STARTGAME2";
	    }
	    return "unknown";
 	case packet_class_wolgameres:
	    return "CLIENT_WOLGAMERES";
	case packet_class_none:
	    return "unknown";
	}

	eventlog(eventlog_level_error,__FUNCTION__,"packet has invalid class %d",(int)packet->pclass);
	return "unknown";
    }

    eventlog(eventlog_level_error,__FUNCTION__,"got unknown direction %d",(int)dir);
    return "unknown";
}
Beispiel #23
0
extern unsigned int packet_get_type(t_packet const * packet)
{
    if (!packet)
    {
	eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
	return 0;
    }

    switch (packet->pclass)
    {
    case packet_class_init:
	return CLIENT_INITCONN; /* all init packets are of this type */

    case packet_class_bnet:
	if (packet_get_size(packet)<sizeof(t_bnet_header))
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"bnet packet is shorter than header (len=%u)",packet_get_size(packet));
	    return 0;
	}
	return (unsigned int)bn_short_get(packet->u.bnet.h.type);

    case packet_class_file:
	if (packet_get_size(packet)<sizeof(t_file_header))
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"file packet is shorter than header (len=%u)",packet_get_size(packet));
	    return 0;
	}
	return (unsigned int)bn_short_get(packet->u.file.h.type);

    case packet_class_udp:
	if (packet_get_size(packet)<sizeof(t_udp_header))
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"udp packet is shorter than header (len=%u)",packet_get_size(packet));
	    return 0;
	}
	return bn_int_get(packet->u.udp.h.type);

    case packet_class_raw:
	return 0; /* raw packets don't have a type, but don't warn because the packet dump tries anyway */

    case packet_class_d2game:
	if (packet_get_size(packet)<sizeof(t_d2game_header))
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"d2game packet is shorter than header (len=%u)",packet_get_size(packet));
	    return 0;
	}
	return bn_byte_get(packet->u.d2game.h.type);

    case packet_class_d2gs:
        if (packet_get_size(packet)<sizeof(t_d2cs_d2gs_header))
        {
            eventlog(eventlog_level_error,__FUNCTION__,"d2gs packet is shorter than header (len=%u)",packet_get_size(packet));
            return 0;
        }
        return bn_short_get(packet->u.d2cs_d2gs.h.type);
    case packet_class_d2cs_bnetd:
        if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_header)) {
                eventlog(eventlog_level_error,__FUNCTION__,"d2cs_bnetd packet shorter than header (len=%u)",packet_get_size(packet));
                return 0;
        }
        return bn_short_get(packet->u.d2cs_d2gs.h.type);

    case packet_class_d2cs:
        if (packet_get_size(packet)<sizeof(t_d2cs_client_header))
        {
            eventlog(eventlog_level_error,__FUNCTION__,"d2cs packet is shorter than header (len=%u)",packet_get_size(packet));
            return 0;
        }
        return bn_byte_get(packet->u.d2cs_client.h.type);

    case packet_class_w3route:
	if (packet_get_size(packet)<sizeof(t_w3route_header))
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"w3route packet is shorter than header (len=%u)",packet_get_size(packet));
	    return 0;
	}
	return bn_short_get(packet->u.w3route.h.type);
    case packet_class_wolgameres:
	    return 0; /* wolgameres packets don't have a type */

    default:
	eventlog(eventlog_level_error,__FUNCTION__,"packet has invalid class %d",(int)packet->pclass);
	return 0;
    }
}
int main(int argc, char ** argv)
{
    int                       exit_code = EXIT_FAILURE;
    char                    * version = strdup("version 1.0");
    const char              * usage = "usage: %s [options] host\n";
    void                    * algorithm_options;
    traceroute_options_t      traceroute_options;
    traceroute_options_t    * ptraceroute_options;
    mda_options_t             mda_options;
    probe_t                 * probe;
    pt_loop_t               * loop;
    int                       family;
    address_t                 dst_addr;
    options_t               * options;
    char                    * dst_ip;
    const char              * algorithm_name;
    const char              * protocol_name;
    bool                      use_icmp, use_udp, use_tcp;

    // Prepare the commande line options
    if (!(options = init_options(version))) {
        fprintf(stderr, "E: Can't initialize options\n");
        goto ERR_INIT_OPTIONS;
    }

    // Retrieve values passed in the command-line
    if (options_parse(options, usage, argv) != 1) {
        fprintf(stderr, "%s: destination required\n", basename(argv[0]));
        goto ERR_OPT_PARSE;
    }

    // We assume that the target IP address is always the last argument
    dst_ip         = argv[argc - 1];
    algorithm_name = algorithm_names[0];
    protocol_name  = protocol_names[0];

    // Checking if there is any conflicts between options passed in the commandline
    if (!check_options(is_icmp, is_tcp, is_udp, is_ipv4, is_ipv6, dst_port[3], src_port[3], protocol_name, algorithm_name)) {
        goto ERR_CHECK_OPTIONS;
    }

    use_icmp = is_icmp || strcmp(protocol_name, "icmp") == 0;
    use_tcp  = is_tcp  || strcmp(protocol_name, "tcp")  == 0;
    use_udp  = is_udp  || strcmp(protocol_name, "udp")  == 0;

    // If not any ip version is set, call address_guess_family.
    // If only one is set to true, set family to AF_INET or AF_INET6
    if (is_ipv4) {
        family = AF_INET;
    } else if (is_ipv6) {
        family = AF_INET6;
    } else {
        // Get address family if not defined by the user
        if (!address_guess_family(dst_ip, &family)) goto ERR_ADDRESS_GUESS_FAMILY;
    }

    // Translate the string IP / FQDN into an address_t * instance
    if (address_from_string(family, dst_ip, &dst_addr) != 0) {
        fprintf(stderr, "E: Invalid destination address %s\n", dst_ip);
        goto ERR_ADDRESS_IP_FROM_STRING;
    }

    // Probe skeleton definition: IPv4/UDP probe targetting 'dst_ip'
    if (!(probe = probe_create())) {
        fprintf(stderr,"E: Cannot create probe skeleton");
        goto ERR_PROBE_CREATE;
    }

    // Prepare the probe skeleton
    probe_set_protocols(
        probe,
        get_ip_protocol_name(family),                          // "ipv4"   | "ipv6"
        get_protocol_name(family, use_icmp, use_tcp, use_udp), // "icmpv4" | "icmpv6" | "tcp" | "udp"
        NULL
    );

    probe_set_field(probe, ADDRESS("dst_ip", &dst_addr));

    if (send_time[3]) {
        if(send_time[0] <= 10) { // seconds
            probe_set_delay(probe, DOUBLE("delay", send_time[0]));
        } else { // milli-seconds
            probe_set_delay(probe, DOUBLE("delay", 0.001 * send_time[0]));
        }
    }

    // ICMPv* do not support src_port and dst_port fields nor payload.
    if (!use_icmp) {
        uint16_t sport = 0,
                 dport = 0;

        if (use_udp) {
            // Option -U sets port to 53 (DNS) if dst_port is not explicitely set
            sport = src_port[3] ? src_port[0] : UDP_DEFAULT_SRC_PORT;
            dport = dst_port[3] ? dst_port[0] : (is_udp ? UDP_DST_PORT_USING_U : UDP_DEFAULT_DST_PORT);
        } else if (use_tcp) {
            // Option -T sets port to 80 (http) if dst_port is not explicitely set
            sport = src_port[3] ? src_port[0] : TCP_DEFAULT_SRC_PORT;
            dport = dst_port[3] ? dst_port[0] : (is_tcp ? TCP_DST_PORT_USING_T : TCP_DEFAULT_DST_PORT);
        }

        // Update ports
        probe_set_fields(
            probe,
            I16("src_port", sport),
            I16("dst_port", dport),
            NULL
        );

        // Resize payload (it will be use to set our customized checksum in the {TCP, UDP} layer)
        probe_payload_resize(probe, 2);
    }

    // Algorithm options (dedicated options)
    if (strcmp(algorithm_name, "paris-traceroute") == 0) {
        traceroute_options  = traceroute_get_default_options();
        ptraceroute_options = &traceroute_options;
        algorithm_options   = &traceroute_options;
        algorithm_name      = "traceroute";
    } else if ((strcmp(algorithm_name, "mda") == 0) || options_mda_get_is_set()) {
        mda_options         = mda_get_default_options();
        ptraceroute_options = &mda_options.traceroute_options;
        algorithm_options   = &mda_options;
        options_mda_init(&mda_options);
    } else {
        fprintf(stderr, "E: Unknown algorithm");
        goto ERR_UNKNOWN_ALGORITHM;
    }

    // Algorithm options (common options)
    options_traceroute_init(ptraceroute_options, &dst_addr);

    // Create libparistraceroute loop
    if (!(loop = pt_loop_create(loop_handler, NULL))) {
        fprintf(stderr, "E: Cannot create libparistraceroute loop");
        goto ERR_LOOP_CREATE;
    }

    // Set network options (network and verbose)
    options_network_init(loop->network, is_debug);

    printf("%s to %s (", algorithm_name, dst_ip);
    address_dump(&dst_addr);
    printf("), %u hops max, %u bytes packets\n",
           ptraceroute_options->max_ttl,
           (unsigned int)packet_get_size(probe->packet)
          );

    // Add an algorithm instance in the main loop
    if (!pt_add_instance(loop, algorithm_name, algorithm_options, probe)) {
        fprintf(stderr, "E: Cannot add the chosen algorithm");
        goto ERR_INSTANCE;
    }

    // Wait for events. They will be catched by handler_user()
    if (pt_loop(loop, 0) < 0) {
        fprintf(stderr, "E: Main loop interrupted");
        goto ERR_PT_LOOP;
    }
    exit_code = EXIT_SUCCESS;

    // Leave the program
ERR_PT_LOOP:
ERR_INSTANCE:
    // pt_loop_free() automatically removes algorithms instances,
    // probe_replies and events from the memory.
    // Options and probe must be manually removed.
    pt_loop_free(loop);
ERR_LOOP_CREATE:
ERR_UNKNOWN_ALGORITHM:
    probe_free(probe);
ERR_PROBE_CREATE:
ERR_ADDRESS_IP_FROM_STRING:
ERR_ADDRESS_GUESS_FAMILY:
    if (errno) perror(gai_strerror(errno));
ERR_CHECK_OPTIONS:
ERR_OPT_PARSE:
ERR_INIT_OPTIONS:
    free(version);
    exit(exit_code);
}
Beispiel #25
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;
}
Beispiel #26
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;
}
Beispiel #27
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);
		    }
		}
	    }
	}
Beispiel #28
0
extern int packet_set_type(t_packet * packet, unsigned int type)
{
    if (!packet)
    {
	eventlog(eventlog_level_error,__FUNCTION__,"got NULL packet");
	return -1;
    }

    switch (packet->pclass)
    {
    case packet_class_init:
	if (type!=CLIENT_INITCONN)
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"init packet type 0x%08x is not valid",type);
	    return -1;
	}
	return 0;

    case packet_class_bnet:
	if (packet_get_size(packet)<sizeof(t_bnet_header))
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"bnet packet is shorter than header (len=%u)",packet_get_size(packet));
	    return -1;
	}
	if (type>MAX_NORMAL_TYPE)
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"bnet packet type 0x%08x is too large",type);
	    return -1;
	}
	bn_short_set(&packet->u.bnet.h.type,(unsigned short)type);
	return 0;

    case packet_class_file:
	if (packet_get_size(packet)<sizeof(t_file_header))
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"file packet is shorter than header (len=%u)",packet_get_size(packet));
	    return -1;
	}
	if (type>MAX_FILE_TYPE)
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"file packet type 0x%08x is too large",type);
	    return -1;
	}
	bn_short_set(&packet->u.file.h.type,(unsigned short)type);
	return 0;

    case packet_class_udp:
	if (packet_get_size(packet)<sizeof(t_udp_header))
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"udp packet is shorter than header (len=%u)",packet_get_size(packet));
	    return -1;
	}
	bn_int_set(&packet->u.udp.h.type,type);
	return 0;

    case packet_class_d2game:
	if (packet_get_size(packet)<sizeof(t_d2game_header))
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"d2game packet is shorter than header (len=%u)",packet_get_size(packet));
	    return -1;
	}
	bn_byte_set(&packet->u.d2game.h.type,type);
	return 0;

    case packet_class_d2gs:
        if (packet_get_size(packet)<sizeof(t_d2cs_d2gs_header))
        {
            eventlog(eventlog_level_error,__FUNCTION__,"d2gs packet is shorter than header (len=%u)",packet_get_size(packet));
            return -1;
        }
        bn_short_set(&packet->u.d2cs_d2gs.h.type,type);
        return 0;

    case packet_class_d2cs_bnetd:
        if (packet_get_size(packet)<sizeof(t_d2cs_bnetd_header))
        {
            eventlog(eventlog_level_error,__FUNCTION__,"d2cs_bnetd packet is shorter than header (len=%u)",packet_get_size(packet));
            return -1;
        }
        bn_short_set(&packet->u.d2cs_bnetd.h.type,type);
        return 0;

    case packet_class_d2cs:
        if (packet_get_size(packet)<sizeof(t_d2cs_client_header))
        {
            eventlog(eventlog_level_error,__FUNCTION__,"d2cs packet is shorter than header (len=%u)",packet_get_size(packet));
            return -1;
        }
        bn_byte_set(&packet->u.d2cs_client.h.type,type);
        return 0;

    case packet_class_w3route:
	if (packet_get_size(packet)<sizeof(t_w3route_header))
	{
	    eventlog(eventlog_level_error,__FUNCTION__,"w3route packet is shorter than header (len=%u)",packet_get_size(packet));
	    return -1;
	}
	bn_short_set(&packet->u.w3route.h.type,(unsigned short)type);
	return 0;

    case packet_class_wolgameres:
	eventlog(eventlog_level_error,__FUNCTION__,"can not set packet type for wol gameres packet");
	return 0;

    case packet_class_raw:
	eventlog(eventlog_level_error,__FUNCTION__,"can not set packet type for raw packet");
	return 0;

    default:
	eventlog(eventlog_level_error,__FUNCTION__,"packet has invalid class %d",(int)packet->pclass);
	return -1;
    }
}
Beispiel #29
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;
}
Beispiel #30
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;
}