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; }
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; }
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; }
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; }
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; }
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; }
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; }
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 */ }
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; }
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; }
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; }
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; }
/* 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; }
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; }
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; }
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; }
size_t probe_get_size(const probe_t * probe) { return packet_get_size(probe->packet); }
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; }
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; }
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; }
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"; }
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); }
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; }
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; }
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); } } } }
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; } }
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; }
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; }