Comment 3 for bug 1012788

Revision history for this message
till (till-straumann) wrote :

Hi Jeff.

Thanks for your comments. If you don't mind, let's discuss the details
further:

Regarding your first bullet:
I don't think that having 'application-specific' proxies makes much sense.
After all, proxified connections exist at the TCP/transport level and the
application should be entirely agnostic.
I believe what you mean is that we should have *destination*-specific
proxies (which is what almost all other software dealing with SOCKS
and multiple proxies does: proxifiers like tsocks, dante, the eclipse
proxy selector etc. do it that way).

After all: if ASYN and CA happen to want to connect to the same subnet
then they can use the same proxy. If ASYN talks to a different subnet
then it should use a different proxy.

That is what the proxy selector is for. It should select a proxy for
the presented destination based on a set of rules.

E.g., you could have rules

asyn-subnet/24:1000-9999 -> proxy1
ca-subnet/22 -> proxy2

and any connection to 'asyn-subnet' with netmask 255.255.255.0 and within
port range 1000-9999 would go through 'proxy1'

any connection to 'ca-subnet' with netmask 255.255.252.0 (any port)
would go via 'proxy2'.

In practice, the 'proxies' are probably always SSH ports on 'localhost'
e.g.,

ssh -D1080 proxy1
ssh -D1081 proxy2

with the 'proxy1' and 'proxy2' settings in the 'rules' of the above
example then being 'localhost:1080' and 'localhost:1081', respectively.

The current 'default' proxy selector doesn't allow you to do that.
It just lets you define a single proxy which is used for all connections
or none at all.

However, it would not be not very hard to improve the default selector
(and already possible with the current patch for you to provide your
own selector).

This brings us to the second bullet:
The pointers returned by the proxy selector really point to static
objects which are created when the proxy selector parses it's rules
(the current default selector is initialized once and creates a
struct sockaddr using the info from EPICS_SOCKS_PROXY).

Therefore, I do not see any concurrency problems and thus
no need for locking or copying values. The objects referenced
by the pointer returned by the proxy selector are strictly
read-only and guaranteed to never change.

Finally - while I see that you can get away with a single
call to 'connect()' you still need a test (which then would be
a little bit more complicated) because you need to
skip the SOCKS negotiation if you have a direct connection.

Regarding the use of osiSockAddr - it would of course be
the first choice to use by the proxy selector but it would
require an OSI version of 'connect'. Since 'epicsConnectViaProxy()'
should be a 'plug-in' replacement for 'connect' the type of
object chosen is 'struct sockaddr'.

Summarizing, I still believe that the current API makes sense
(it is also not really my invention but as I said: several packages
implementing SOCKS use a similar approach) but I can see
that a more powerful (default) proxy selector could be desirable
(but I IMHO the current implementation is still much better
than nothing).

What would you think about an implementation which
would understand

EPICS_SOCKS_PROXY = rules

rules: rule [ ',' rules ]

rule: [ dest '>' ] proxy /* a rule w/o dest is a wildcard to *any* dest */

proxy: [ dns-or-ip ] ':' [ port ] /* dns-or-ip defaults to 'localhost' */
            | dns-or-ip /* 'port' defaults to '1080' */

dest: dns-or-ip [ '/' mask ] [ ':' range ] /* mask defaults to '32' */

range: port [ '-' port ]

This still allows a very simple configuration where you just have
a single proxy:

EPICS_SOCKS_PROXY=localhost

or even

EPICS_SOCKS_PROXY=:

The example above could be configured e.g.,

EPICS_SOCKS_PROXY=asyn-subnet/24:1000-9999>localhost:1080,ca-subnet/22>:1081

RFC

Thanks again
- Till