Interface (e.g eth0) setting using setsockopt on secure socket prior to connect is failing
Expected behavior
Using a HTTPSClientSession object prior to connect should be able to set socket options to bind it to a specific interface e.g eth0,eth1
Actual behavior
When we directly try to set socket option using m_HTTPSClientSession->socket().setOption() the call throws exception invalid socket. To avoid invalid socket issue tried to derive HTTPSClientSession so init of socket is accessible and able to use setsockopt on valid socket. Though this option is set successfully, the actual sokcet used to connect as part of SecureStreamSocketImpl is different (SecureSocketImpl _impl) so it doesn't get connected with provided interface details whihc are set on different socket.
Steps to reproduce the problem
(please make this a SSCCE, if applicable and reasonable)
POCO version
1.9.0
Compiler and version
Operating system and version
Other relevant information
Went through the below pullrequest changes which is available on latest develop which supports bind to srcAddress prior to connect. https://github.com/pocoproject/poco/pull/2078/files But in some cases if routing is through default at network layer bind does not help. Need to set interface specifically.
I agree that if you don't have special routing with binding source ip address it won't work all that well in ipv4 (unless traffic is via directly connected LAN). Won't selecting the interface have a similar problem?
Did you have a chance to read through the file regarding the routing rules needed?: NetSSL_OpenSSL/samples/SetSourceIP/SetSourceIp.readme
Definitely OS support via special routing rules will make the source ip address binding feature more useful. And I assume something similar will be needed for this additional feature you are discussing.
About your request, do you mean you want to use SO_BINDTODEVICE with setOption()? From what I am reading that seems to be Linux specific and might need privileged access from the process.
Hello Rocco,
Please find my answers inline below.
I agree that if you don't have special routing with binding source ip address it won't work all that well in ipv4 (unless traffic is via directly connected LAN). Won't selecting the interface have a similar problem?
p-neels :: Selecting an interface using setsockopt on linux environment did work for me. I could see the packet count increasing on ifconfig command for the interface to which had done a bind.
Did you have a chance to read through the file regarding the routing rules needed?: NetSSL_OpenSSL/samples/SetSourceIP/SetSourceIp.readme
p-neels :: I did went through the above mentioned read me also tried out the complete patch.Yes I agree there needs to be some special routing setup in this kind of use case. There are some constraints to set the routing for alternate interface.
Definitely OS support via special routing rules will make the source ip address binding feature more useful. And I assume something similar will be needed for this additional feature you are discussing.
About your request, do you mean you want to use SO_BINDTODEVICE with setOption()? From what I am reading that seems to be Linux specific and might need privileged access from the process.
p-neels :: Below is the solution I tried on Linux environment. Not sure about windows. Yes the process needs to have privileged access.
std::string interface("eth1"); Poco::Net::StreamSocket interfaceSocket; interfaceSocket.init(AF_INET); struct ifreq ifrInst; memset(&ifrInst, 0x00, sizeof(ifrInst)); strncpy(ifrInst.ifr_name, interface.c_str(), IFNAMSIZ); int ret = setsockopt(interfaceSocket.impl()->sockfd(), SOL_SOCKET, SO_BINDTODEVICE, (char*)&ifrInst, sizeof(ifrInst));
There is a relation between this request and #2422
Just to clarify, the example you provide with StreamSocket class is working for you, but you want to do the same with HTTPClientSession?
For StreamSocket did you try something like this?
std::string interface("eth1"); Poco::Net::StreamSocket interfaceSocket; interfaceSocket.init(AF_INET); interfaceSocket.impl()->setRawOption(SOL_SOCKET, SO_BINDTODEVICE, interface.c_str(), interface.length()+1);
Working on a fix based on the previous post, for HTTPClientSession.
Suggested solution for StreamSocket probably doesn't work, from what I am seeing. Will continue later this week.
Is it resolved? I want to set a interface to a socket before trying to connect to the server!
Is it resolved? I want to set a interface to a socket before trying to connect to the server!
Have extended the poco class in my application to get this issue resolved.
Would you mind sharing your code?
I am also looking for the same thing. I want to connect to the server via particular interface only. Please help.
Sure will share you the code extract to connect on a specific interface.
@abhiarora4 Please find below the sample code snapshot for connecting on specific interface which I tried
class HTTPSCustomClientSession : public HTTPSClientSession { public: // Creates a unconnected HTTPSCustomClientSession using the given host and port,using the given SSL context. HTTPSCustomClientSession(const std::string& host, Poco::UInt16 port, Context::Ptr pContext,const std::string& interfaceID);
// Destroys the HTTPSCustomClientSession and closes the underlying socket.
~HTTPSCustomClientSession(){}
void connect(const SocketAddress& address);
protected: StreamSocket proxyConnect(); IPAddress srcAddr; std::string m_intf; //Specific interface on which connection needs to be done
private: HTTPSCustomClientSession(){} };
HTTPSCustomClientSession::HTTPSCustomClientSession(const std::string& host, Poco::UInt16 port, Context::Ptr pContext,const std::string& interfaceID): HTTPSClientSession(host,port,pContext) { if(interfaceID.size() > 0) m_intf = interfaceID; }
void HTTPSCustomClientSession::connect(const SocketAddress& address) { if(!m_intf.empty()) { if (getProxyHost().empty() || bypassProxy()) {
SecureStreamSocket sss(socket());
if (sss.getPeerHostName().empty())
{
sss.setPeerHostName(getHost());
}
if (((Poco::Net::SecureStreamSocketImpl*)socket().impl())->context()->sessionCacheEnabled())//edited
{
sss.useSession(sslSession());//edited
}
StreamSocket intfSocket;
intfSocket.init(AF_INET);
int ret = 0;
struct ifreq ifr;
memset(&ifr, 0x00, sizeof(ifr));
strncpy(ifr.ifr_name, m_intf.c_str(), IFNAMSIZ);
ret = setsockopt(intfSocket.impl()->sockfd(), SOL_SOCKET, SO_BINDTODEVICE, (char*)&ifr, sizeof(ifr));
if(ret != 0)
{
//As setsockopt has failed need not proceed further as it might route using default path
throw Poco::Net::InterfaceNotFoundException("setsockopt on interface failed", m_intf);
}
try{
//Similar code to calling void SecureSocketImpl::connect(const SocketAddress& address, const Poco::Timespan& timeout, bool performHandshake)
intfSocket.connect(address,getTimeout());
}
catch (Poco::Exception& ){
throw;
}
intfSocket.setReceiveTimeout(getTimeout());
intfSocket.setSendTimeout(getTimeout());
//this will internally perform connectSSL
Poco::Net::SecureStreamSocket secureSocket = SecureStreamSocket::attach(intfSocket, getHost(), ((Poco::Net::SecureStreamSocketImpl*)socket().impl())->context(), sslSession());
attachSocket(secureSocket);
intfSocket.setReceiveTimeout(socket().getReceiveTimeout());
intfSocket.setSendTimeout(socket().getSendTimeout());
if (((Poco::Net::SecureStreamSocketImpl*)socket().impl())->context()->sessionCacheEnabled())//edited
{
sslSession() = secureSocket.currentSession();//edited
}
}
else
{
StreamSocket proxySocket(proxyConnect());
SecureStreamSocket secureSocket = SecureStreamSocket::attach(proxySocket, getHost(), ((Poco::Net::SecureStreamSocketImpl*)socket().impl())->context(), sslSession());
attachSocket(secureSocket);
if (((Poco::Net::SecureStreamSocketImpl*)socket().impl())->context()->sessionCacheEnabled())//edited
{
sslSession() = secureSocket.currentSession();//edited
}
}
}else //If no interface to be set continue with as it is implementation in poco
HTTPSClientSession::connect(address);
}
StreamSocket HTTPSCustomClientSession::proxyConnect() { if(!m_intf.empty()) { ProxyConfig emptyProxyConfig; HTTPCustomClientSession proxySession(getProxyHost(), getProxyPort(), emptyProxyConfig,m_intf);//edited proxySession.setTimeout(getTimeout()); std::string targetAddress(getHost());//edited targetAddress.append(":"); NumberFormatter::append(targetAddress, getPort());//edited HTTPRequest proxyRequest(HTTPRequest::HTTP_CONNECT, targetAddress, HTTPMessage::HTTP_1_1); HTTPResponse proxyResponse; proxyRequest.set("Proxy-Connection", "keep-alive"); proxyRequest.set("Host", getHost()); proxyAuthenticateImpl(proxyRequest); proxySession.setKeepAlive(true); proxySession.sendRequest(proxyRequest); proxySession.receiveResponse(proxyResponse); if (proxyResponse.getStatus() != HTTPResponse::HTTP_OK) throw HTTPException("Cannot establish proxy connection", proxyResponse.getReason()); return proxySession.detachSocket(); }else return HTTPClientSession::proxyConnect(); }
This issue is stale because it has been open for 365 days with no activity.
This issue is stale because it has been open for 365 days with no activity.