Support IPv6 address for FTP via HTTP tunneling.

We use control connection address as data connection address, so we
don't need to store both address and port. We just store port in
PASV/EPSV response and use SocketCore::getPeerInfo() to get peer's
address when needed.
pull/4/head
Tatsuhiro Tsujikawa 2011-11-14 23:19:37 +09:00
parent 97a9242cbe
commit 27dda3c65c
4 changed files with 33 additions and 26 deletions

View File

@ -86,11 +86,13 @@ FtpNegotiationCommand::FtpNegotiationCommand
const SocketHandle& socket, const SocketHandle& socket,
Seq seq, Seq seq,
const std::string& baseWorkingDir): const std::string& baseWorkingDir):
AbstractCommand(cuid, req, fileEntry, requestGroup, e, socket), sequence_(seq), AbstractCommand(cuid, req, fileEntry, requestGroup, e, socket),
sequence_(seq),
ftp_(new FtpConnection(cuid, socket, req, ftp_(new FtpConnection(cuid, socket, req,
e->getAuthConfigFactory()->createAuthConfig e->getAuthConfigFactory()->createAuthConfig
(req, requestGroup->getOption().get()), (req, requestGroup->getOption().get()),
getOption().get())) getOption().get())),
pasvPort_(0)
{ {
ftp_->setBaseWorkingDir(baseWorkingDir); ftp_->setBaseWorkingDir(baseWorkingDir);
if(seq == SEQ_RECV_GREETING) { if(seq == SEQ_RECV_GREETING) {
@ -606,10 +608,7 @@ bool FtpNegotiationCommand::recvEpsv() {
return false; return false;
} }
if(status == 229) { if(status == 229) {
std::pair<std::string, uint16_t> peerInfo; pasvPort_ = port;
getSocket()->getPeerInfo(peerInfo);
peerInfo.second = port;
dataConnAddr_ = peerInfo;
return preparePasvConnect(); return preparePasvConnect();
} else { } else {
sequence_ = SEQ_SEND_PASV; sequence_ = SEQ_SEND_PASV;
@ -637,27 +636,24 @@ bool FtpNegotiationCommand::recvPasv() {
throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status), throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
error_code::FTP_PROTOCOL_ERROR); error_code::FTP_PROTOCOL_ERROR);
} }
std::pair<std::string, uint16_t> peerInfo; pasvPort_ = dest.second;;
getSocket()->getPeerInfo(peerInfo);
peerInfo.second = dest.second;;
dataConnAddr_ = peerInfo;
return preparePasvConnect(); return preparePasvConnect();
} }
bool FtpNegotiationCommand::preparePasvConnect() { bool FtpNegotiationCommand::preparePasvConnect() {
// TODO Should we check to see that dataConnAddr_.first is not in
// noProxy list?
if(isProxyDefined()) { if(isProxyDefined()) {
sequence_ = SEQ_RESOLVE_PROXY; sequence_ = SEQ_RESOLVE_PROXY;
return true; return true;
} else { } else {
std::pair<std::string, uint16_t> dataAddr;
getSocket()->getPeerInfo(dataAddr);
// make a data connection to the server. // make a data connection to the server.
A2_LOG_INFO(fmt(MSG_CONNECTING_TO_SERVER, A2_LOG_INFO(fmt(MSG_CONNECTING_TO_SERVER,
getCuid(), getCuid(),
dataConnAddr_.first.c_str(), dataAddr.first.c_str(),
dataConnAddr_.second)); pasvPort_));
dataSocket_.reset(new SocketCore()); dataSocket_.reset(new SocketCore());
dataSocket_->establishConnection(dataConnAddr_.first, dataConnAddr_.second); dataSocket_->establishConnection(dataAddr.first, pasvPort_);
disableReadCheckSocket(); disableReadCheckSocket();
setWriteCheckSocket(dataSocket_); setWriteCheckSocket(dataSocket_);
sequence_ = SEQ_SEND_REST_PASV; sequence_ = SEQ_SEND_REST_PASV;
@ -722,9 +718,14 @@ bool FtpNegotiationCommand::sendTunnelRequest()
httpRequest->setUserAgent(getOption()->get(PREF_USER_AGENT)); httpRequest->setUserAgent(getOption()->get(PREF_USER_AGENT));
SharedHandle<Request> req(new Request()); SharedHandle<Request> req(new Request());
// Construct fake URI in order to use HttpRequest // Construct fake URI in order to use HttpRequest
// TODO Handle IPv6 address; it must be enclosed with []. std::pair<std::string, uint16_t> dataAddr;
req->setUri(fmt("ftp://%s:%u", int family = getSocket()->getPeerInfo(dataAddr);
dataConnAddr_.first.c_str(), dataConnAddr_.second)); uri::UriStruct us;
us.protocol = "ftp";
us.host = dataAddr.first;
us.port = pasvPort_;
us.ipv6LiteralAddress = (family == AF_INET6);
req->setUri(uri::construct(us));
httpRequest->setRequest(req); httpRequest->setRequest(req);
httpRequest->setProxyRequest(createProxyRequest()); httpRequest->setProxyRequest(createProxyRequest());
http_->sendProxyRequest(httpRequest); http_->sendProxyRequest(httpRequest);

View File

@ -147,8 +147,8 @@ private:
SharedHandle<FtpConnection> ftp_; SharedHandle<FtpConnection> ftp_;
// For tunneling // For tunneling
SharedHandle<HttpConnection> http_; SharedHandle<HttpConnection> http_;
// IP, Port pair in pasv response // Port number in PASV/EPSV response
std::pair<std::string, uint16_t> dataConnAddr_; uint16_t pasvPort_;
// Resolved address for proxy // Resolved address for proxy
std::string proxyAddr_; std::string proxyAddr_;

View File

@ -345,12 +345,13 @@ SocketCore* SocketCore::acceptConnection() const
return new SocketCore(fd, sockType_); return new SocketCore(fd, sockType_);
} }
void SocketCore::getAddrInfo(std::pair<std::string, uint16_t>& addrinfo) const int SocketCore::getAddrInfo(std::pair<std::string, uint16_t>& addrinfo) const
{ {
sockaddr_union sockaddr; sockaddr_union sockaddr;
socklen_t len = sizeof(sockaddr); socklen_t len = sizeof(sockaddr);
getAddrInfo(sockaddr, len); getAddrInfo(sockaddr, len);
addrinfo = util::getNumericNameInfo(&sockaddr.sa, len); addrinfo = util::getNumericNameInfo(&sockaddr.sa, len);
return sockaddr.storage.ss_family;
} }
void SocketCore::getAddrInfo(sockaddr_union& sockaddr, socklen_t& len) const void SocketCore::getAddrInfo(sockaddr_union& sockaddr, socklen_t& len) const
@ -369,7 +370,7 @@ int SocketCore::getAddressFamily() const
return sockaddr.storage.ss_family; return sockaddr.storage.ss_family;
} }
void SocketCore::getPeerInfo(std::pair<std::string, uint16_t>& peerinfo) const int SocketCore::getPeerInfo(std::pair<std::string, uint16_t>& peerinfo) const
{ {
sockaddr_union sockaddr; sockaddr_union sockaddr;
socklen_t len = sizeof(sockaddr); socklen_t len = sizeof(sockaddr);
@ -378,6 +379,7 @@ void SocketCore::getPeerInfo(std::pair<std::string, uint16_t>& peerinfo) const
throw DL_ABORT_EX(fmt(EX_SOCKET_GET_NAME, errorMsg(errNum).c_str())); throw DL_ABORT_EX(fmt(EX_SOCKET_GET_NAME, errorMsg(errNum).c_str()));
} }
peerinfo = util::getNumericNameInfo(&sockaddr.sa, len); peerinfo = util::getNumericNameInfo(&sockaddr.sa, len);
return sockaddr.storage.ss_family;
} }
void SocketCore::establishConnection(const std::string& host, uint16_t port) void SocketCore::establishConnection(const std::string& host, uint16_t port)

View File

@ -147,10 +147,12 @@ public:
void beginListen(); void beginListen();
/** /**
* Stores host address and port of this socket to addrinfo. * Stores host address and port of this socket to addrinfo and
* returns address family.
*
* @param addrinfo placeholder to store host address and port. * @param addrinfo placeholder to store host address and port.
*/ */
void getAddrInfo(std::pair<std::string, uint16_t>& addrinfo) const; int getAddrInfo(std::pair<std::string, uint16_t>& addrinfo) const;
/** /**
* Stores address of this socket to sockaddr. len must be * Stores address of this socket to sockaddr. len must be
@ -168,10 +170,12 @@ public:
int getAddressFamily() const; int getAddressFamily() const;
/** /**
* Stores peer's address and port to peerinfo. * Stores peer's address and port to peerinfo and returns address
* family.
*
* @param peerinfo placeholder to store peer's address and port. * @param peerinfo placeholder to store peer's address and port.
*/ */
void getPeerInfo(std::pair<std::string, uint16_t>& peerinfo) const; int getPeerInfo(std::pair<std::string, uint16_t>& peerinfo) const;
/** /**
* Accepts incoming connection on this socket. * Accepts incoming connection on this socket.