diff --git a/SslSocket/basesock.cpp b/SslSocket/basesock.cpp index a49b2f9..e13d784 100644 --- a/SslSocket/basesock.cpp +++ b/SslSocket/basesock.cpp @@ -136,11 +136,13 @@ int BaseSock::Delay(void) // other functions -int BaseSock::_Connect(string host,int port) +int BaseSock::_Connect(string host,int port,bool &ipv6) { - struct sockaddr_in adr; + struct sockaddr_in6 adr; adr = GetIp(host,port); + ipv6 = !IN6_IS_ADDR_V4MAPPED(&adr.sin6_addr); + if(!setnonblocking(sock)) { return 0; @@ -260,9 +262,9 @@ int BaseSock::_Connect(string host,int port) return 0; } -int BaseSock::_Connect5(string ip, int port, string socksIp, int socksPort, string socksUser, string socksPass, bool socksSsl, int &status) +int BaseSock::_Connect5(string ip, int port, string socksIp, int socksPort, string socksUser, string socksPass, bool socksSsl, bool &ipv6, int &status) { - if(!_Connect(socksIp, socksPort)) + if(!_Connect(socksIp, socksPort, ipv6)) { status = 1; // socks connect failed return 0; @@ -340,10 +342,10 @@ int BaseSock::_Connect5(string ip, int port, string socksIp, int socksPort, stri buffer[2] = 0; buffer[3] = 1; - struct sockaddr_in adr; + struct sockaddr_in6 adr; adr = GetIp(ip,port); //memcpy(&adr.sin_addr.s_addr,buffer+4,4); - memcpy(buffer+4,&adr.sin_addr.s_addr,4); + memcpy(buffer+4,&adr.sin6_addr.s6_addr,4); //doesn't work in v6, need proto update buffer[8] = (char)(port / 256); buffer[9] = (char)(port % 256); @@ -433,7 +435,7 @@ int BaseSock::CanRead(int timeout) int BaseSock::GetSock(int &sock) { - if((sock = socket(AF_INET,SOCK_STREAM,0)) == -1) + if((sock = socket(AF_INET6,SOCK_STREAM,0)) == -1) { sock = -1; @@ -594,38 +596,26 @@ int BaseSock::setreuse(int &socket) return SocketOption(socket, SO_REUSEADDR); } -struct sockaddr_in BaseSock::GetIp(string ip,int port) +struct sockaddr_in6 BaseSock::GetIp(string ip,int port) { - struct sockaddr_in addr; - addr.sin_family = AF_INET; - unsigned long lip = inet_addr(ip.c_str()); - if(lip == INADDR_NONE) - { - struct hostent *he; - - if((he = gethostbyname(ip.c_str())) == NULL) - { - lip = inet_addr("0.0.0.0"); - addr.sin_addr.s_addr = lip; - } - else - { - addr.sin_addr = *(struct in_addr*)he->h_addr; - } - } - else - { - addr.sin_addr.s_addr = lip; - } - addr.sin_port = htons(port); - memset(&(addr.sin_zero), '\0', 8); - return addr; + struct sockaddr_in6 addr; + struct addrinfo hints, *res; + int n, sockfd; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET6; + hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_PASSIVE; + n = getaddrinfo(ip.c_str(), to_string(port).c_str(), &hints, &res); + memcpy(&addr, res->ai_addr, sizeof(addr)); + freeaddrinfo(res); + return addr; } string BaseSock::GetIpStr(string ip) { - sockaddr_in adr = GetIp(ip,0); - string tmpip(inet_ntoa(adr.sin_addr)); + sockaddr_in6 adr = GetIp(ip,0); + char buf[64]; + inet_ntop(AF_INET6, &(adr.sin6_addr), buf, 64); + string tmpip(buf); return tmpip; } @@ -943,20 +933,20 @@ void BaseSock::setquit(int quit) int BaseSock::Bind(string ip,int port) { - struct sockaddr_in adr; + struct sockaddr_in6 adr; if (ip != "") { adr = GetIp(ip,port); } else - { - adr.sin_addr.s_addr = INADDR_ANY; - adr.sin_port = htons(port); - adr.sin_family = AF_INET; - memset(&(adr.sin_zero), '\0', 8); + { + adr.sin6_addr = in6addr_any; + adr.sin6_port = htons(port); + adr.sin6_family = AF_INET6; + adr.sin6_flowinfo = 0; } if(!setreuse(sock)) return 0; - if(bind(sock,(struct sockaddr *)&adr, sizeof(struct sockaddr)) != 0) + if(bind(sock,(struct sockaddr *)&adr, sizeof(adr)) != 0) { return 0; } @@ -1265,7 +1255,7 @@ int BaseSock::_Accept(int listensock,int &newsock,string &clientip,int &clientpo { fd_set readfds; fd_set errorfds; - struct sockaddr_in adr; + struct sockaddr_in6 adr; if(sec > 0) { @@ -1327,8 +1317,10 @@ int BaseSock::_Accept(int listensock,int &newsock,string &clientip,int &clientpo return 0; } - clientip = inet_ntoa(adr.sin_addr); - clientport = ntohs(adr.sin_port); + char charbuf[INET6_ADDRSTRLEN]; + clientip = inet_ntop(adr.sin6_family, &adr.sin6_addr, charbuf, INET6_ADDRSTRLEN); + clientport = ntohs(adr.sin6_port); + if(!setnonblocking(newsock)) { diff --git a/SslSocket/basesock.h b/SslSocket/basesock.h index 1c4fa8a..6d7d769 100644 --- a/SslSocket/basesock.h +++ b/SslSocket/basesock.h @@ -45,8 +45,8 @@ friend class ServerSock; virtual int Init(void) {return 0;} // make this class abstract int Bind(string ip, int port); - int _Connect(string ip, int port); - int _Connect5(string ip, int port, string socksIp, int socksPort, string socksUser, string socksPass, bool socksSsl, int &status); + int _Connect(string ip, int port, bool &ipv6); + int _Connect5(string ip, int port, string socksIp, int socksPort, string socksUser, string socksPass, bool socksSsl, bool &ipv6, int &status); int CanRead(int timeout); int ReadLine(string &str); @@ -57,7 +57,7 @@ friend class ServerSock; int FastWrite(char *data,int nrbytes); int BlockWrite(char *data,int nrbytes); int BlockRead(char *buffer, int &nrbytes); - struct sockaddr_in GetIp(string ip, int port); + struct sockaddr_in6 GetIp(string ip, int port); string GetIpStr(string ip); void setquit(int quit); @@ -83,7 +83,6 @@ friend class ServerSock; int _shouldquit; SSL *ssl; - int SocketOption(int &,int); int setnonblocking(int); int setblocking(int); diff --git a/SslSocket/clientsock.cpp b/SslSocket/clientsock.cpp index f8309a3..e628967 100644 --- a/SslSocket/clientsock.cpp +++ b/SslSocket/clientsock.cpp @@ -5,6 +5,7 @@ ClientSock::ClientSock(void) { buffer = NULL; ssl = NULL; + _ipv6 = false; _socksIp = ""; _socksPort = 0; _socksUser = ""; @@ -290,15 +291,20 @@ void ClientSock::useSocks(bool useSocks) _useSocks = useSocks; } +bool ClientSock::ipv6(void) +{ + return _ipv6; +} + int ClientSock::Connect(string ip, int port) { if(!useSocks()) { - return _Connect(ip, port); + return _Connect(ip, port, _ipv6); } else { int status; - return _Connect5(ip, port, socksIp(), socksPort(), socksUser(), socksPass(), socksSsl(), status); + return _Connect5(ip, port, socksIp(), socksPort(), socksUser(), socksPass(), socksSsl(), _ipv6, status); } } diff --git a/SslSocket/clientsock.h b/SslSocket/clientsock.h index b39a153..32eb15d 100644 --- a/SslSocket/clientsock.h +++ b/SslSocket/clientsock.h @@ -37,6 +37,7 @@ class DLL ClientSock: public BaseSock void socksSsl(bool socksSsl); bool useSocks(void); void useSocks(bool useSocks); + bool ipv6(void); protected: @@ -46,6 +47,7 @@ class DLL ClientSock: public BaseSock string _socksUser; bool _socksSsl; bool _useSocks; + bool _ipv6; }; diff --git a/SslSocket/serversock.cpp b/SslSocket/serversock.cpp index 4f67f1c..d4579df 100644 --- a/SslSocket/serversock.cpp +++ b/SslSocket/serversock.cpp @@ -17,6 +17,7 @@ int ServerSock::Init() if(!GetSock(sock)) return 0; buffer = new char [_buffersize]; if(buffer == NULL) return 0; + if(!setreuse(sock)) return 0; return 1; } diff --git a/SslSocket/strings.cpp b/SslSocket/strings.cpp index 653e73c..0856929 100644 --- a/SslSocket/strings.cpp +++ b/SslSocket/strings.cpp @@ -295,6 +295,20 @@ bool parsePasvCmd(string cmd, string &ip, int &port) return true; } +bool parseEpsvCmd(string cmd, string &ip, int &port) { + int pos1 = cmd.find("("); + int pos2 = cmd.find(")",pos1); + if(pos1 == string::npos || pos2 == string::npos) return false; + string tmp = cmd.substr(pos1 + 1, pos2 - 2); + vector vec; + if(split(vec,tmp,'|',false) == 2) { //rfc response + ip = ""; + port = atoi(vec[0].c_str()); + return true; + } + return false; +} + bool parsePortCmd(string cmd, string &ip, int &port) { size_t pos1 = cmd.find(" "); diff --git a/SslSocket/strings.h b/SslSocket/strings.h index 3b2c5c8..8b2e1d2 100644 --- a/SslSocket/strings.h +++ b/SslSocket/strings.h @@ -20,6 +20,7 @@ DLL void getpassword(string prompt, string &pass); DLL int MatchIp(const string& ip1, const string& ip2); DLL int ftpCode(string reply); DLL bool parsePasvCmd(string cmd, string &ip, int &port); +DLL bool parseEpsvCmd(string cmd, string &ip, int &port); DLL bool parsePortCmd(string cmd, string &ip, int &port); DLL int random_range(int lowest_number, int highest_number); DLL string int2str(int); diff --git a/tbnc/entrythread.cpp b/tbnc/entrythread.cpp index 26cae15..bd3379d 100644 --- a/tbnc/entrythread.cpp +++ b/tbnc/entrythread.cpp @@ -131,10 +131,18 @@ bool EntryThread::doUser() { if(!doSsl(1)) return false; } + else if(StartsWith(toupper(userreply), "FEAT")) + { + if(!doFeat()) return false; + } else if(StartsWith(toupper(userreply), "PASV")) { if(!doPasv()) return false; } + else if(StartsWith(toupper(userreply), "EPSV")) + { + if(!doEpsv()) return false; + } else if(StartsWith(toupper(userreply), "CPSV")) { if(!doCpsv()) return false; @@ -158,8 +166,11 @@ bool EntryThread::doPasv() { string reply; bool error = false; + int ret; - if(!sitesock.WriteLine("PASV\r\n")) + if (sitesock.ipv6()) ret = sitesock.WriteLine("EPSV\r\n"); + else ret = sitesock.WriteLine("PASV\r\n"); + if(!ret) { error = true; } @@ -172,7 +183,7 @@ bool EntryThread::doPasv() else { int code = ftpCode(reply); - if(code != 227) + if(code != 227 && code != 229) { error = true; } @@ -190,7 +201,12 @@ bool EntryThread::doPasv() string ip; int port; - if(!parsePasvCmd(reply,ip,port)) return false; + if (sitesock.ipv6()) { + if(!parseEpsvCmd(reply,ip,port)) return false; + if (ip=="") ip = options->siteip; + } else { + if(!parsePasvCmd(reply,ip,port)) return false; + } PasvTrafficThread *ptt = new PasvTrafficThread(options, ip, port); if(ptt == NULL) return false; @@ -236,6 +252,113 @@ bool EntryThread::doPasv() return true; } +// handle EPSV command +bool EntryThread::doEpsv() +{ + string reply; + bool error = false; + int ret; + + if (sitesock.ipv6()) ret = sitesock.WriteLine("EPSV\r\n"); + else ret = sitesock.WriteLine("PASV\r\n"); + if(!ret) + { + error = true; + } + else + { + if(!sitesock.ReadLine(reply)) + { + error = true; + } + else + { + int code = ftpCode(reply); + if(code != 227 && code != 229) + { + error = true; + } + } + } + + if(error) + { + if(!cs.WriteLine("425 Can't open data connection.\r\n")) + { + return false; + } + return true; + } + + string ip; + int port; + if (sitesock.ipv6()) { + if(!parseEpsvCmd(reply,ip,port)) return false; + if (ip=="") ip = options->siteip; + } else { + if(!parsePasvCmd(reply,ip,port)) return false; + } + + PasvTrafficThread *ptt = new PasvTrafficThread(options, ip, port); + if(ptt == NULL) return false; + + int listenPort = port + options->addtopasvport; + + if(!ptt->InitListen(listenPort)) + { + delete ptt; + if(!cs.WriteLine("425 Can't open data connection.\r\n")) + { + return false; + } + } + else + { + if(!cs.WriteLine("229 Entering Passive Mode (|||" + int2str(listenPort) + "|)\r\n")) + { + delete ptt; + return false; + } + ptt->start(ptt); + } + return true; +} + +// handle FEAT command^M +bool EntryThread::doFeat() +{ + string reply; + bool error = false; + if(!sitesock.WriteLine("FEAT\r\n")) + { + error = true; + } + else + { + if(!sitesock.ReadLine(reply)) + { + error = true; + } + } + if (error) { + reply = "500 'FEAT': Command not understood.\r\n"; + } + else { + int index; + //index = reply.find("CPSV", 0); + //if (index!= string::npos) reply.replace(index, 4, "PASV"); + if (!clientipv6) { + index = reply.find("EPSV", 0); + if (index!= string::npos) reply.replace(index, 4, "PASV"); + index = reply.find("EPRT", 0); + if (index!= string::npos) reply.replace(index, 4, "PORT"); + } + } + + if(!cs.WriteLine(reply)) return false; + else return true; +} + // handle CPSV command bool EntryThread::doCpsv() { @@ -255,7 +378,56 @@ bool EntryThread::doCpsv() else { int code = ftpCode(reply); - if(code != 227) + if(code != 200) + { + error = true; + } + else { + if(!sitesock.WriteLine("SSCN ON\r\n")) { + error = true; + } + else { + if(!sitesock.ReadLine(reply)) { + error = true; + } + else { + int code = ftpCode(reply); + if(code != 200) { + error = true; + } + } + } + } + } + } + if(error) + { + if(!cs.WriteLine("500 'CPSV': Command not understood.\r\n")) + { + return false; + } + return true; + } + + error = false; + int ret; + + if (sitesock.ipv6()) ret = sitesock.WriteLine("EPSV\r\n"); + else ret = sitesock.WriteLine("CPSV\r\n"); + if(!ret) + { + error = true; + } + else + { + if(!sitesock.ReadLine(reply)) + { + error = true; + } + else + { + int code = ftpCode(reply); + if(code != 227 && code != 229) { error = true; } @@ -273,7 +445,12 @@ bool EntryThread::doCpsv() string ip; int port; - if(!parsePasvCmd(reply,ip,port)) return false; + if (sitesock.ipv6()) { + if(!parseEpsvCmd(reply,ip,port)) return false; + if (ip=="") ip = options->siteip; + } else { + if(!parsePasvCmd(reply,ip,port)) return false; + } PasvTrafficThread *ptt = new PasvTrafficThread(options, ip, port); if(ptt == NULL) return false; @@ -321,7 +498,10 @@ bool EntryThread::doPort(string portCmd) string reply; bool error = false; - if(!sitesock.WriteLine("PASV\r\n")) + int ret; + if (sitesock.ipv6()) ret = sitesock.WriteLine("EPSV\r\n"); + else ret = sitesock.WriteLine("PASV\r\n"); + if(!ret) { error = true; } @@ -334,7 +514,7 @@ bool EntryThread::doPort(string portCmd) else { int code = ftpCode(reply); - if(code != 227) + if(code != 227 && code != 229) { error = true; } @@ -352,7 +532,12 @@ bool EntryThread::doPort(string portCmd) string ip; int port; - if(!parsePasvCmd(reply,ip,port)) return false; + if (sitesock.ipv6()) { + if(!parseEpsvCmd(reply,ip,port)) return false; + if (ip=="") ip = options->siteip; + } else { + if(!parsePasvCmd(reply,ip,port)) return false; + } string activeip; int activeport; @@ -388,12 +573,20 @@ void EntryThread::loop(void) id = ss.str(); if(!sitesock.Init()) return; + string clientip2; + if ( clientip.length() > 7 && clientip.substr(0,7) == "::ffff:") { + clientip2 = clientip.substr(7) ; + clientipv6 = false; + } else { + clientip2 = clientip; + clientipv6 = true; + } if(options->entrylist.size() > 0) { bool found = false; for(unsigned int i=0; i < options->entrylist.size();i++) { - if(options->entrylist[i] == clientip) + if(options->entrylist[i] == clientip2) { found = true; break; @@ -414,12 +607,12 @@ void EntryThread::loop(void) string ident = "*"; if(options->idnt) { - cs.Ident(clientip,options->listenport,clientport,3,ident,options->listenip); + cs.Ident(clientip2,options->listenport,clientport,3,ident,options->listenip); } if(options->idntcmd) { stringstream ss; - ss << "IDNT " << ident << "@" << clientip << ":" << clientip << "\r\n"; + ss << "IDNT " << ident << "@" << clientip2 << ":" << clientip2 << "\r\n"; sitesock.WriteLine(ss.str()); } } @@ -485,4 +678,4 @@ EntryThread::~EntryThread(void) { cs.Close(); sitesock.Close(); -} \ No newline at end of file +} diff --git a/tbnc/entrythread.h b/tbnc/entrythread.h index 64c79dc..e86c30a 100644 --- a/tbnc/entrythread.h +++ b/tbnc/entrythread.h @@ -17,6 +17,7 @@ class EntryThread: public Thread ClientSock sitesock; string clientip; int clientport; + bool clientipv6; EntryThread(Options *options); @@ -41,6 +42,12 @@ class EntryThread: public Thread // handle PASV command bool doPasv(); + // handle EPSV command + bool doEpsv(); + + // handle FEAT command + bool doFeat(); + // handle CPSV command bool doCpsv();