const char* DLLCALL inet_addrtop(union xp_sockaddr *addr, char *dest, size_t size) { #ifdef _WIN32 if(getnameinfo(&addr->addr, xp_sockaddr_len(addr), dest, size, NULL, 0, NI_NUMERICHOST)) safe_snprintf(dest, size, "<Error %u converting address, family=%u>", WSAGetLastError(), addr->addr.sa_family); return dest; #else switch(addr->addr.sa_family) { case AF_INET: return inet_ntop(addr->in.sin_family, &addr->in.sin_addr, dest, size); case AF_INET6: return inet_ntop(addr->in6.sin6_family, &addr->in6.sin6_addr, dest, size); case AF_UNIX: strncpy(dest, addr->un.sun_path, size); dest[size-1]=0; return dest; default: safe_snprintf(dest, size, "<unknown address family: %u>", addr->addr.sa_family); return NULL; } #endif }
SOCKET sbbs_t::ftp_data_sock(csi_t* csi, SOCKET ctrl_sock, SOCKADDR_IN* addr) { char cmd[512]; char rsp[512]; char* p; socklen_t addr_len; SOCKET data_sock; int ip_b[4]; int port_b[2]; union { DWORD dw; BYTE b[sizeof(DWORD)]; } ip_addr; union { WORD w; BYTE b[sizeof(WORD)]; } port; if(csi->ftp_mode&CS_FTP_ASCII) strcpy(cmd,"TYPE A"); else /* BINARY */ strcpy(cmd,"TYPE I"); if(!ftp_cmd(csi,ctrl_sock,cmd,rsp) || atoi(rsp)!=200) { return(INVALID_SOCKET); } if((data_sock=open_socket(SOCK_STREAM, "ftp"))==INVALID_SOCKET) { csi->socket_error=ERROR_VALUE; return(INVALID_SOCKET); } memset(addr,0,sizeof(SOCKADDR_IN)); addr->sin_addr.s_addr = htonl(startup->outgoing4.s_addr); addr->sin_family = AF_INET; if(bind(data_sock, (struct sockaddr *)addr,xp_sockaddr_len(addr))!= 0) { csi->socket_error=ERROR_VALUE; close_socket(data_sock); return(INVALID_SOCKET); } if(csi->ftp_mode&CS_FTP_PASV) { if(!ftp_cmd(csi,ctrl_sock,"PASV",rsp) || atoi(rsp)!=227 /* PASV response */) { bprintf("ftp: failure, line %d",__LINE__); close_socket(data_sock); return(INVALID_SOCKET); } p=strchr(rsp,'('); if(p==NULL) { bprintf("ftp: failure, line %d",__LINE__); close_socket(data_sock); return(INVALID_SOCKET); } p++; if(sscanf(p,"%u,%u,%u,%u,%u,%u" ,&ip_b[0],&ip_b[1],&ip_b[2],&ip_b[3] ,&port_b[0],&port_b[1])!=6) { bprintf("ftp: failure, line %d",__LINE__); close_socket(data_sock); return(INVALID_SOCKET); } ip_addr.b[0]=ip_b[0]; ip_addr.b[1]=ip_b[1]; ip_addr.b[2]=ip_b[2]; ip_addr.b[3]=ip_b[3]; port.b[0]=port_b[0]; port.b[1]=port_b[1]; addr->sin_addr.s_addr=ip_addr.dw; addr->sin_port=port.w; } else { /* Normal (Active) FTP */ addr_len=sizeof(SOCKADDR_IN); if(getsockname(data_sock, (struct sockaddr *)addr,&addr_len)!=0) { csi->socket_error=ERROR_VALUE; close_socket(data_sock); return(INVALID_SOCKET); } SOCKADDR_IN ctrl_addr; addr_len=sizeof(ctrl_addr); if(getsockname(ctrl_sock, (struct sockaddr *)&ctrl_addr,&addr_len)!=0) { csi->socket_error=ERROR_VALUE; close_socket(data_sock); return(INVALID_SOCKET); } if(listen(data_sock, 1)!= 0) { csi->socket_error=ERROR_VALUE; close_socket(data_sock); return(INVALID_SOCKET); } ip_addr.dw=ntohl(ctrl_addr.sin_addr.s_addr); port.w=ntohs(addr->sin_port); sprintf(cmd,"PORT %u,%u,%u,%u,%u,%u" ,ip_addr.b[3] ,ip_addr.b[2] ,ip_addr.b[1] ,ip_addr.b[0] ,port.b[1] ,port.b[0] ); if(!ftp_cmd(csi,ctrl_sock,cmd,rsp) || atoi(rsp)!=200 /* PORT response */) { close_socket(data_sock); return(INVALID_SOCKET); } } return(data_sock); }