Add SOCKS support (for tunneling CA via ssh)
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
EPICS Base |
Incomplete
|
Wishlist
|
mdavidsaver |
Bug Description
The attached patch implements a new function (as promised at the collaboration
meeting last spring)
int epicsConnectVia
which is 'plug-in' compatible with ordinary 'connect'. However, if a SOCKS proxy
server is found for the destination address then this routine connects to
the proxy server and requests the proxy to establish the connection to the
real destination.
The proxy selector can itself be exchanged (global function pointer variable);
the default implementation simply checks if the environment variable EPICS_SOCKS_PROXY
is set to a valid address:
<host> [ ':' <port> ]
If it is then <host>:<port> (port defaults to 1080) is used as the proxy (for
all destinations). If no proxy is defined (i.e., if the proxy selector routine
returns NULL) then a direct connection is established. I.e., without a
proxy being defined 'epicsConnectVi
'connect()'.
The CA client library has been modified (by the patch) to use epicsConnectVia
instead of ::connect().
This feature is mainly of interest with SSH's SOCKS proxy server feature. It
then becomes easy to tunnel CA connections. E.g.,:
EPICS_CA_
EPICS_SOCKS_
ssh -D1080 some-machine.
caget SOME_PV
Where PV must be hosted on 'some-ioc'.
The patch is even more useful in combination with the 'caxy' program
which can proxy UDP search requests and CA beacons...
Hi Till,
Thanks for your efforts!
o I can imagine two programs using this facility in the same program simultaneously. For example, in the IOC
we might have both ca and asyn using it and need to configure the proxy address independently for both entities.
Perhaps what you should do is change the API so that the cac class constructor creates a proxy SOCKS_PROXY and
create agent using a global factory that requires the EPICS
environment variable as its sole parameter. That way we can have EPICS_CA_
ASYN_SOCKS_PROXY (or whatever the correct name is with asyn) in use at the same time. This approach would also
address my second bullet below. Once we we have created a proxy connect agent them it can be invoked in
tcpiiu.cpp each time that we connect w/o needing to pass in parameters.
(void) pProxyConnect- >connect( ); /* exception thrown on failure */
Of course the above API is C++. You can of course get the same thing in C as follows (if you prefer that).
extern NetworkProxy * epicsNetworkPro xyCreate ( const ENV_PARAM * ); xyConnect ( NetworkProxy * ); xyDestroy ( NetworkProxy * );
extern int epicsNetworkPro
extern void epicsNetworkPro
Of course we would probably need to pass in the address of the connect proxy when creating a tcpiiu, and
cache that address within tcpiiu, but only ~cac would destroy the connect proxy.
o The epicsDefaultSoc ksProxySelector API returns a pointer to a shared structure which isn't released by the caller. This can cause concurrency issues later on if this structure was changing and multiple threads are using it simultaneously? Its a little more overhead but IMHO a better option would be just to return the structure by value, or better yet have the caller pass the address of the destination structure for the proxy's address. Furthermore, if the epicsSocksProxy Select just wraps back the destination address, which is passed in, then when there is no proxy we can simplify the code below, and have no if test to see if the returned structure is nill and also only one call to connect. The ca client code currently uses the osiSockAddr union defined in osiSock.h to wrap socket addresses so that we can have some flexibility wrt to different address structures in the future.
+ if ( ! ( proxy = epicsSocksProxy Select( addr, &desVers) ) ) { ertErrnoToStrin g(buf, sizeof(buf)); "epicsConnectVi aProxy( ) -- Unable to connect to proxy: %s\n", buf);
+ return connect( sockfd, addr, addrlen );
+ }
+
+ /* Connect to proxy */
+ if ( (rval = connect( sockfd, proxy, sizeof(*proxy)) ) ) {
+ epicsSocketConv
+ errlogPrintf(
+ return rval;
+ }