Java: Specifying the local address for an outgoing connection

1.2k Views Asked by At

We've many servers which host multiple IP addresses. The additional ones are so-called Virtual IPs ("VIPs").

We'd like to enable a Java app to make an outgoing connection which lists as source address a designated Virtual IP rather than the host ip address.

Here's what we've tried. The ip address listed in InetAddress#getByAddress is the virtual ip address. The property url is a user-specified target url to connect to.

public void attemptConnection() {
  try {
    Proxy proxy = new Proxy(Proxy.Type.HTTP,
        new InetSocketAddress(InetAddress.getByAddress(new byte[]{(byte)10,(byte)252,(byte)47,(byte)33}), 0));
    final URL _url = new URL(url);
    final URLConnection conn = _url.openConnection(proxy);
    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String inputLine;
    while ((inputLine = in.readLine()) != null) {
      System.out.println(inputLine);
      in.close();
    }
  } catch (Exception e) {
    e.printStackTrace();
  }
}

The code above was modelled on this answer

We're testing this with Python's SimpleHTTPServer, simply running python -m SimpleHTTPServer then trying to connect.

If we use no proxy in our Java code then the connection works correctly.

However, as soon as the VIP proxy is defined we get connection refused:

java.net.ConnectException: Connection refused
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:327)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:193)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:180)
        at java.net.Socket.connect(Socket.java:546)
        at java.net.Socket.connect(Socket.java:495)
        at sun.net.NetworkClient.doConnect(NetworkClient.java:178)
        at sun.net.www.http.HttpClient.openServer(HttpClient.java:409)
        at sun.net.www.http.HttpClient$2.run(HttpClient.java:457)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.net.www.http.HttpClient.privilegedOpenServer(HttpClient.java:454)
        at sun.net.www.http.HttpClient.openServer(HttpClient.java:521)
        at sun.net.www.http.HttpClient.<init>(HttpClient.java:240)
        at sun.net.www.http.HttpClient.New(HttpClient.java:321)
        at sun.net.www.http.HttpClient.New(HttpClient.java:338)
        at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:935)
        at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:914)
        at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:801)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1139)
        at com.ocado.dsi.ConnectToUrl.attemptConnection(ConnectToUrl.java:38)
        at com.ocado.dsi.ConnectToUrl.run(ConnectToUrl.java:56)
        at com.ocado.dsi.ConnectToUrl.main(ConnectToUrl.java:64)

Any ideas why?

Update

When specifying the local address on a socket directly the process works fine.

I setup a Python simple socket server listening on port 8000 just as the SimpleHTTPServer used above does. Connecting to this from Java using a socket with the desired local address worked as expected: the python server recognised the incoming connection source address as that defined by the user.

Socket s = new Socket(InetAddress.getByAddress(new byte[]{(byte)10,(byte)252,(byte)47,(byte)33}), 8000, InetAddress.getByAddress(new byte[]{(byte)10,(byte)97,(byte)5,(byte)147}), 0);
s.close();

I'm going to dig into Socket#setSocketImplFactory to see whether the problem can be resolved by customising every created socket.

The problem is that both Socket#setSocketImplFactory and URL.setURLStreamHandlerFactory enable you to override the default implementation but do not give you access to the default implementation, so they seem to be very much all-or-nothing overrides. This is very annoying when you only wish tor add logic on top.

0

There are 0 best solutions below