3

I have a pool of public ip addresses configured on my multiple NICs. In my JAVA project, which runs on a LINUX machine, I need to select a specific ip address from the pool and create an HttpURLConnecion using that ip. Further, I will cycle on the pool, using each time a different ip.

At the current stage, I was not able to find a solution using the java.net library. I have rather looked at the HttpClient from Apache. At the following link, http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html, it is said that such library can support the functionality I was looking for. A discussion on this can be found at Define source ip address using Apache HttpClient. Actually, the posted thread seems not conclusive, as users' experiences are very contrasting on the described use of the library.

Therefore, I don't think that SO community really succeeded in solving this issue. It is a matter of fact that several replayed questions/answers on this topic can be found on SO, but none of them seems to give an exhaustive analysis of the problem.

Moreover, the problem is not faced with the use of java.net library (as in my project) at all.

At the moment, a possible option that I have is to invoke some LINUX system commands (from java) to switch the NIC to use for the current connection. However, I have not figure it out yet.

Therefore, I would appreciate if any users, who had POSITIVE experiences in solving this issue, can address me to a solution/idea/method.

Thanks in advance,

Marcello

UPDATE:

I've currently implemented this test code. It gives me correct status code (200). However, it needs to be tested with multiple ip addresses.

public class test {

    public static void main(String[] args) {

        final String authUser = "admin";
        final String authPassword = "password";
        Authenticator.setDefault(
           new Authenticator() {
              public PasswordAuthentication getPasswordAuthentication() {
                 return new PasswordAuthentication(
                       authUser, authPassword.toCharArray());
              }
           }
        );

        System.setProperty("http.proxyUser", authUser);
        System.setProperty("http.proxyPassword", authPassword);

        try {

            Properties systemProperties = System.getProperties();
            URL url = new URL("yourURL");
            systemProperties.setProperty("http.proxyHost","localhost");
            systemProperties.setProperty("http.proxyPort", "8080");                         

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            int status = connection.getResponseCode();
            System.out.println(status);

        } catch (IOException e) {
            System.out.println("connection problems");
        }
    }

}

At this point, you should be able to configure the different TCP ports related to each NIC. Did anyone try something like this? I am looking forward to reading new ideas/comments.

UPDATE 2: To be precise, I've included authentication setup for those who needed it.

Community
  • 1
  • 1
m121212
  • 141
  • 1
  • 1
  • 10
  • I am not sure if this what are you asking about (really sorry if I am wrong) but... Have you tried something like this with HttpClient? `byte ip[] = new byte[] { (byte) 192, (byte) 168, 1, 105 }; client.getParams().setParameter(ConnRouteParams.LOCAL_ADDRESS, InetAddress.getByAddress(ip));` – Gooseman Oct 22 '13 at 11:46
  • Hi, thanks for the suggestion. This is the way I looked at when using the HttpClient library. Do you have any ideas with java.net? – m121212 Oct 22 '13 at 11:54
  • Sorry, no ideas with java.net. – Gooseman Oct 22 '13 at 12:13

4 Answers4

3

Why don't you just use org.apache.httpcomponents?

Here an example that works (using maven plugin org.apache.httpcomponents, version 4.3.1):

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

public class HttpClientExample {

    public void gogo() throws ClientProtocolException, IOException {

        CloseableHttpClient httpclient = HttpClients.createDefault();

        // Local interface1:
        byte ip1[] = new byte[] { (byte)192, (byte)168, (byte)100, (byte)32 };
        // Local interface2:
        byte ip2[] = new byte[] { (byte)192, (byte)168, (byte)100, (byte)33 };


        RequestConfig requestConfig = RequestConfig.custom().setLocalAddress(InetAddress.getByAddress(ip1)).build();
        try {
            HttpGet httpget = new HttpGet("http://server.com");
            httpget.setConfig(requestConfig);
            System.out.println("executing request" + httpget.getRequestLine());
            StringBuilder response = httpclient.execute(httpget,handler);
            System.out.println(response.toString());

            requestConfig = RequestConfig.custom().setLocalAddress(InetAddress.getByAddress(ip2)).build();
            httpget = new HttpGet("http://server.com");
            httpget.setConfig(requestConfig);
            System.out.println("executing request" + httpget.getRequestLine());
            response = httpclient.execute(httpget,handler);
            System.out.println(response.toString());
        } finally {
            httpclient.close();
        }
    }

    private final ResponseHandler<StringBuilder> handler = new ResponseHandler<StringBuilder>() {
        @Override
        public StringBuilder handleResponse(final HttpResponse response)
                throws ClientProtocolException, IOException {
            return sortResponse(response);
        }
    };

    private StringBuilder sortResponse(final HttpResponse httpResponse) throws IOException {
        StringBuilder builder = null;

        if (httpResponse != null) {
            switch (httpResponse.getStatusLine().getStatusCode()) {
                case HttpStatus.SC_OK:
                    final HttpEntity entity = httpResponse.getEntity();
                    if (entity != null) {

                        final InputStreamReader instream = new InputStreamReader(entity.getContent());
                        try {
                            final BufferedReader reader = new BufferedReader(instream);
                            builder = new StringBuilder();
                            String currentLine = null;
                            currentLine = reader.readLine();
                            while (currentLine != null) {
                                builder.append(currentLine).append("\n");
                                currentLine = reader.readLine();
                            }
                        } finally {
                            instream.close();
                        }
                    }
                    break;
                default:
                    throw new IllegalArgumentException("Error.");
            }
        }
        return builder;
    }
}
Gooseman
  • 2,102
  • 17
  • 16
  • @Krishna Right, it sends the same HTTP request using 2 different local interfaces (NICs). In my example eth0 could be 192.168.100.32 and eth1 192.168.100.33. [Socket.bind()](http://docs.oracle.com/javase/7/docs/api/java/net/Socket.html#bind%28java.net.SocketAddress%29) enables you to send data by means of your chosen local address (NIC) and not the one chosen by the system. – Gooseman Oct 23 '13 at 08:18
  • Thank you. I know that this is nicely handled with Apache library, but I'm trying to find a solution that works with native java.net. – m121212 Oct 23 '13 at 08:23
  • @m121212 You are welcome. I left this code for you just in case you finally give up trying to use java.net. :P – Gooseman Oct 23 '13 at 08:26
  • Guess it's not `byte ip1[]` , but `byte[] ip` , right? and thanks for the solution! still cant find good answer in SO community that uses only native java.net! – Sepehr GH Jan 29 '17 at 06:26
  • @SepehrGH `byte ip1[]` is also right. See: [JLS §10.2](https://docs.oracle.com/javase/specs/jls/se7/html/jls-10.html#jls-10.2) – Gooseman Jan 29 '17 at 06:57
  • oh! I see, tnx for the link – Sepehr GH Jan 30 '17 at 06:53
  • Sorry to bother. I'm testing this code on my machine which is connected to internet using both LAN and WIFI. `wlp3s0` has inet address: 192.168.1.6 , and `enp4s0f1` has 192.168.1.4 assigned to it (which should probably be my lan address). I can run this code when I set ip to `enp4s0f1` one (192.168.1.4) but doesnt work when I change to wifi one! can this be a valid test? I want to make sure when I run my app on server with multiple addresses, it works fine. – Sepehr GH Jan 30 '17 at 07:03
  • doesn't work for me. Says: java.net.BindException: Cannot assign requested address (Bind failed) – Nathan B Jun 30 '22 at 05:08
  • @NathanB `Bind failed` is due to some of these problems: EADDRINUSE, EADDRNOTAVAIL, EPERM or EACCES. For openjdk8 you can see the related code over [here](https://github.com/AdoptOpenJDK/openjdk-jdk8u/blob/master/jdk/src/solaris/native/java/net/PlainSocketImpl.c#L579-L582). If you are using Linux, the command `man bind` will explain you what those code errors mean. – Gooseman Jul 01 '22 at 16:11
  • Sorry @SepGH. I never saw your latest question until now. It should have worked also with the wifi interface. – Gooseman Jul 01 '22 at 16:15
0

java.net uses sun.net.www.protocol package to create HttpURLConnection.

sun.net.www.protocol.HttpURLConnection is implementation of java.net.HttpURLConnection interface.

Try extending sun.net.www.protocol.HttpURLConnection and other appropriate classes like NetworkClient and HttpClient and protocol handler classes from sun.www. packages.

nullptr
  • 3,320
  • 7
  • 35
  • 68
0

Use linux command "ip addr" which gives ouput similar to:

[root@user ~]# ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
    valid_lft forever preferred_lft forever
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:18:a5:97 brd ff:ff:ff:ff:ff:ff
    inet 100.10.52.15/24 brd 10.0.2.255 scope global eth1
    inet 100.10.52.16/24 brd 10.0.2.255 scope global secondary eth1
    inet6 fe80::a00:27ff:fe18:a597/64 scope link
       valid_lft forever preferred_lft forever
3: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:11:1f:0c brd ff:ff:ff:ff:ff:ff
    inet 158.17.47.19/24 brd 172.17.37.255 scope global eth2
    inet6 fe80::a00:27ff:fe11:1f0c/64 scope link
       valid_lft forever preferred_lft forever
4: eth3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 08:00:27:cf:96:2d brd ff:ff:ff:ff:ff:ff
    inet6 fe80::a00:27ff:fecf:962d/64 scope link
       valid_lft forever preferred_lft forever
  1. By default linux uses first ip address as source ip adress on perticular adapter. For example, for above system configuration linux will use "100.10.52.15/24" as source ip adress.

  2. You can write java program with "ProcessBuilder" to execute following commands change order of ip address. (commands: ip addr del 100.10.25.15/24 dev eth0

    ip addr add 100.10.25.15/24 dev eth0)

  3. Delete all ip addresses on perticular adapter, store it in memory. Add it in order you want (IP address which should use as source ip should add first)

  4. For example ip adress "100.10.52.16/24" should use as source ip adress then

    ip addr del 100.10.25.15/24 dev eth0
    ip addr del 100.10.25.16/24 dev eth0
    
    ip addr add 100.10.25.16/24 dev eth0
    ip addr add 100.10.25.15/24 dev eth0
    
nilesh.b
  • 486
  • 3
  • 9
-1

Well i dont have that particular answer for the same but ya u can try this may be i am not sure that will work or not but try once.

URL url = new URL(yourUrlHere);
Proxy proxy = new Proxy(Proxy.Type.DIRECT, 
    new InetSocketAddress( 
        InetAddress.getByAddress(
            new byte[]{your, ip, interface, here}), yourTcpPortHere));
URLConnection conn = url.openConnection(proxy);
Kishan Bheemajiyani
  • 3,429
  • 5
  • 34
  • 68
  • Hi. I've just implemented this method, and it does not work. Anyway, the proxy type should be HTTP and the connection a HttpURLConnection type. However, the proxy configuration does not work. When I try to establish normal connection without proxy usage, everything works fine. Therefore, the issue is still OPEN! – m121212 Oct 22 '13 at 12:19
  • Means issue about what you are trying to specify the particular address is that?? and then put that address as if default address then try to run again na.. try that once and ya even i am confuse about this thing its not working it. i am also working on same. – Kishan Bheemajiyani Oct 23 '13 at 06:25