I have a java application that pulls information from network interface and I'm using NetworkInterface class to iterate through the gazillion of interfaces I have in my computer. "I have installed virtualbox" and this create many virtual interface. But I need to get info from my wireless or ethernet interface as those are the only option to connect to the network. The problem is that I want to be able to sort through all these interfaces and get only the relevant. What approach you guys suggest? doing a search through the NetworkInteface collection looking for eth0 or wlan1. any ideas appreciated. Here's the code that deals with network interface in my application.
//displaying all network interface
Enumeration<NetworkInterface> nets = null;
try {
nets = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e3) {
e3.printStackTrace();
}
for (NetworkInterface netint : Collections.list(nets)) {
displayInterfaceInformation(netint);
}
static void displayInterfaceInformation(NetworkInterface netint) throws SocketException {
Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
System.out.printf(count + " Display name: %s\n", netint.getDisplayName());
System.out.printf("Name: %s\n", netint.getName());
for (InetAddress inetAddress : Collections.list(inetAddresses)) {
System.out.printf("InetAddress: %s\n", inetAddress);
}
System.out.println("\n");
}
There could be a more straightforward way, but if you're just looking for the interface that connects to the internet, there's a simple trick you can use that doesn't involve reading routing tables - just create a socket, connect it to an address that exists on the internet, then get that socket's local address. It's better to use a UDP socket since its connect doesn't do any actual IO:
DatagramSocket s = new DatagramSocket();
s.connect(InetAddress.getByName("1.1.1.1"), 53);
System.out.println(s.getLocalAddress());
The operating system will bind the socket to an appropriate interface for the outbound connection using the routing table. Once you have the IP address, you can find the interface with that IP address.
Related
My router has three network interfaces:
Ethernet;
2.4GHz antenna;
5GHz antenna;
I have a program that sends and receives packets on a multicast address (I set it to 239.5.6.7) on port 10468.
For my tests I have two devices (one sender and one receiver) that exchange information.
If both devices are connected to the same interface of the router (let's say, both connected to the 5GHz WiFi) then the devices will be able to communicate.
On the other hand, if the devices are on two different interfaces (one 5GHz and one Ethernet), packets will not be exchanged (as if the router does not forward multicast traffic to one interface to the others).
All three interfaces support multicast (examining traffic with WireShark shows that every host is able to join the multicast group), but it seems like the router is blocking this cross-interface exchange.
It really is a shitty router issue? Or I did something wrong on my end?
Both the sender and receiver communicate with the multicast group with all their interfaces (as long as they have a link-local IP address).
getActiveInterfaces() is a method that gathers such interfaces and saves them in an array list.
Sender snippet (getActiveInterfaces() returns only the ethernet connection):
static final int port = 10468;
public static void main(String[] args) {
try {
ArrayList<NetworkInterface> interfaces = getActiveInterfaces();
// Initialize sockets
ArrayList<MulticastSocket> sockets = new ArrayList<>(interfaces.size());
for (NetworkInterface networkInterface : interfaces) {
MulticastSocket socket = new MulticastSocket();
socket.setOption(StandardSocketOptions.IP_MULTICAST_TTL, 1);
socket.setNetworkInterface(networkInterface);
sockets.add(socket);
}
InetSocketAddress group = new InetSocketAddress(InetAddress.getByName("239.5.6.7"), port);
byte[] buf = new byte[128];
String msg = "Hello";
DatagramPacket toSend = new DatagramPacket(msg.getBytes(), msg.getBytes().length, group);
while (true) {
Thread.sleep(1000);
for (MulticastSocket socket : sockets)
socket.send(toSend);
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
Receiver snippet (getActiveInterfaces() returns only the 2.4GHz wireless connection):
static final int port = 10468;
public static void main(String[] args) {
try(MulticastSocket s = new MulticastSocket(port)) {
InetSocketAddress group = new InetSocketAddress(InetAddress.getByName("239.5.6.7"), port);
ArrayList<NetworkInterface> activeInterfaces = getActiveInterfaces();
for (NetworkInterface networkInterface : activeInterfaces) {
s.joinGroup(group, networkInterface);
}
DatagramPacket rec = new DatagramPacket(new byte[128], 128);
while(true) {
s.receive(rec);
System.out.println(new String(rec.getData(), StandardCharsets.UTF_8).replaceAll("\0", ""));
}
}catch (Exception e) {
e.printStackTrace();
}
}
After some investigations, I came to a conclusion that this is a router issue.
It seems that there is some sort of whitelisting going on.
For example, packets sent to the reserved Local Control Block multicast addresses (224.0.0.1-224.0.0.255) do not have this issue. Well-known multicast IPs are also whitelisted (like 239.255.255.250, used for SSDP).
Even changing to the next multicast address (239.255.255.249 or 239.255.255.251) leads to the same issue.
The only solution I could come up with is to use one of these whitelisted addresses and to use a different port number (not one linked with the actual address).
you may want to up your ttl to 3,
each time a multicast packet is received by a router the ttl is decremented by 1, when the ttl is 0 the packet is dropped.
Does it work with the sender and receiver on the same machine?
If it does, next as root, run
tcpdump multicast
on both machines
you should see something like
16:26:22.085822 IP debian.attlocal.net.51429 > 239.35.3.5.3535: UDP, length 1316
I am developing a web application which acts as a server. In this application I have implimented ServerSocket for two way communication between server application and wi-fi device which acts as client. I am not connecting to my server directly, I am connecting to my router which port forwards to my system and two way communication is successful. All I want now is to find the MAC address of Wi-fi device which is connected.I have done some research and tried to get the MAC address but failed.Can anyone help me on this.Below is the part of my code.
public class ScheduleJob extends ServletApp implements Job{
private int port = 1717;
public static String number;
String ReceivedData = "";
public void execute(JobExecutionContext context)throws JobExecutionException {
System.out.println("Starting ... ");
ServerSocket Sersocket = null;
System.out.println("Starting the socket server at port:" +port);
boolean listeningSocket = true;
try {
Sersocket = new ServerSocket(port);
System.out.println("Waiting for clients...");
} catch (IOException e) {
System.err.println("Could not listen on port: 1717");
}
try {
while (listeningSocket) {
Socket scokt = Sersocket.accept();
InetAddress MachineAdd = scokt.getInetAddress();
System.out.println("Response-----:" +MachineAdd);
InetAddress ip = InetAddress.getLocalHost();
System.out.println("current ip : "+ip);
NetworkInterface network = NetworkInterface.getByInetAddress(ip);
byte[] mac = network.getHardwareAddress();
System.out.print("Current MAC address : ");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mac.length; i++) {
sb.append(String.format("%02X%s", mac[i], (i < mac.length - 1) ? "-" : ""));
}
System.out.println(sb.toString());
MAC address is piece of information which belongs to layer 2 of OSI model.
In other words it's not preserved whenever you are communicating using L3 protocol (until you are communicating directly via cross cable or via L2 switch).
I would recommend you to send MAC address as a part of your application communication from client to your server, so it will not be lost when your router will do port forwarding.
Some of already asked questions on this topic:
Why can't the server get the client MAC address, like the client IP?
How can I get the MAC and the IP address of a connected client in PHP?
how to get a client's MAC address from HttpServlet?
Currently I am using URL()
public boolean isInternetAvailable(){
try {
URL url = new URL("http://www.google.com");
HttpURLConnection urlConnect = (HttpURLConnection)url.openConnection();
urlConnect.setConnectTimeout(5000);
Object objData = urlConnect.getContent();
return true;
} catch (Exception e) {}
return false;
}
But In the requirement, we don't want to use any URL. We want to ping localhost if connection is available than return true otherwise flase.
For nslookup I am using
try
{
InetAddress inetAddress = InetAddress.getByName("localhost");
System.out.println("Host: " +inetAddress.getHostName());
System.out.println("IP Address: " +inetAddress.getHostAddress());
System.out.println("IP Address: " +inetAddress.isSiteLocalAddress());
}
catch (UnknownHostException e)
{
e.printStackTrace();
}
But I am not understand how to check the connection availability with nslookup.
Please suggest best approach for it. Thanks
There are several catches to this question:
Starting with the most specific one - connecting to localhost: even if your computer does not have a network card, it will be able to resolve localhost on a loopback interface and connect to itself (if there is an open port).
Your DNS may be down/misconfigured, so you cannot resolve example.com but you can connect to it by IP (93.184.216.34) - does that mean than "internet is not available"?
The firewall in your company may be blocking certain sites, but allowing other - does that mean than "internet is not available"?
The server of example.com is down while all the other sites in the world work fine. Does that mean than "internet is available" or not?
The firewall in your company may be allowing HTTP connections only on standard ports 80 and 443 and disallowing other. Thus, http://example.com connects, but http://example.com:12345 does not. Does that mean than "internet is available" or not?
So the only question you can actually ask is whether you can connect to a particular host on a particular port using its domain name and/or its IP address.
Figured out a final solution using NetworkInterface:
Enumeration<NetworkInterface> eni = NetworkInterface.getNetworkInterfaces();
while(eni.hasMoreElements()) {
Enumeration<InetAddress> eia = eni.nextElement().getInetAddresses();
while(eia.hasMoreElements()) {
InetAddress ia = eia.nextElement();
if (!ia.isAnyLocalAddress() && !ia.isLoopbackAddress() && !ia.isSiteLocalAddress()) {
if (!ia.getHostName().equals(ia.getHostAddress()))
return true;
}
}
}
I have got solution from here:- Java Quickly check for network connection
I built an application which has a service and it contains sockets to receive messages in LAN.It work fine when WiFi is ON, but when I start the application with WiFi OFF state it gives an error of socket bind failed and it don't work even if I turn the WiFi ON.
Is there any way to get notified in the app when the WiFi is turned on so that I can start that particular service again, or any other method to bind the socket so that it may bind correctly with the WiFi OFF state.
My current code is:
socket = new DatagramSocket(port, broadcastIP);
DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
socket.receive(packet);
If WiFi is OFF you are probably getting a SocketException when creating the DatagramSocket instance because the socket cannot be bound to the IP address passed. Moreover, if the network interface is down it doesn't have any IP address.
Maybe you should ask first for the network interfaces in your device and then check the status of each interface. If the interface is up then you get the IP address and then you can create a socket bound to it.
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netIf : Collections.list(nets))
{
System.out.println("Display name: " + netIf.getDisplayName());
System.out.println("Name: " + netIf.getName());
if (netIf.isUp()) //Is the interface up
{
Enumeration<InetAddress> inetAddresses = netIf.getInetAddresses();
for (InetAddress inetAddress : Collections.list(inetAddresses))
{
System.out.println("InetAddress: " + inetAddress);
}
}
}
Look here:
http://docs.oracle.com/javase/tutorial/networking/nifs/retrieving.html
and here:
http://docs.oracle.com/javase/6/docs/api/java/net/NetworkInterface.html
I am trying to implement a method that sends an UDP packet to multiple receivers. I thought that this should be doable setting setReuseAddress(true) on the receiving DatagramSocket instances.
My problem is that in certain conditions I need to limit the communication to the local computer - hence the localhost interface (useLocalhost=true in the demo code below). In such a case suddenly only the first receiver socket gets the incoming packet, the two other don't see anything.
I tested this on Windows (oracle 64bit) and Linux (OpenJDK 64bit), therefore I only see three possibilities:
This is an intended and known behavior (and I don't understand the whole mechanism - aka "bug in my brain")
There is a bug in the Java JRE
There is a bug in my code.
Does somebody have any experience on that topic and can me help to identify where the problem is located?
See below a minimal working example that demonstrates this. Note that I am using the broadcast address for simulating network packets that come from a real external host.
If everything goes right you should see three lines at the end (in this or a different order):
Thread-0 - packet received
Thread-1 - packet received
Thread-2 - packet received
public static void main(String[] args) throws Exception {
boolean useLocalhost = true;
InetSocketAddress addr;
String sendPacketTo = "192.168.1.255"; // we use broadcast so that packet comes from an real external address
if (useLocalhost)
sendPacketTo = "localhost"; // does not work (only listener 1 received packet)
addr = new InetSocketAddress(15002);
new MyThread(addr).start(); // Datagram socket listener 1
new MyThread(addr).start(); // Datagram socket listener 2
new MyThread(addr).start(); // Datagram socket listener 3
DatagramSocket so = new DatagramSocket();
so.setBroadcast(true); // does not change anything
so.connect(new InetSocketAddress(sendPacketTo, 15002));
so.send(new DatagramPacket("test".getBytes(), 4));
Thread.sleep(1000);
System.exit(0);
}
public static class MyThread extends Thread {
DatagramSocket socket;
public MyThread(InetSocketAddress addr) throws SocketException {
super();
setDaemon(true);
socket = new DatagramSocket(null);
socket.setReuseAddress(true);
socket.setBroadcast(true); // does not change anything
socket.bind(addr);
System.out.println("Listener started: " + socket.getLocalAddress());
}
public void run() {
byte[] buf = new byte[10];
DatagramPacket p = new DatagramPacket(buf, buf.length);
try {
socket.receive(p);
System.out.println(Thread.currentThread().getName() + " - packet received");
} catch (IOException e) {
e.printStackTrace();
}
}
}
192.168.1.255 is a broadcast address, so the datagram is broadcast, under the rules for UDP broadcast. 127.0.0.1 is a unicast address, so the packet is unicast. So you get different behaviour.
As #DavidSchwartz commented, your code is a mixture. Connecting to a broadcast address for example doesn't have a lot of meaning, and neither does binding to it. I think what you are looking for is multicast.
You can use multicast on localhost
However, there are several things you need to be careful of to make it work.
example:
lo0 (127.0.0.1)
en0 (192.168.0.111)
en1 (10.1.0.111)
for each interface 2 separate sockets, one for receiving, one for
sending. In the above example this means creating a total of 6
sockets.
Never bind() a socket that will send multicast UDP packets.
Always bind() a socket that will receive multicast UDP packets.
Never try to setsockopt() or reconfigure multicast sockets after you call bind()
Instead, when machine's interfaces change due to cables being unplugged/plugged,
destroy all send/receive multicast sockets and recreate them.
sample code:
iMulticastSocketInterfaceIPAddress would be one of the three interfaces
/* use setsockopt() to request that the kernel join a multicast group */
struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr=inet_addr( "239.192.0.133" );
myAddress.sin_addr.s_addr = mreq.imr_multiaddr.s_addr;
mreq.imr_interface.s_addr=( htonl(iMulticastSocketInterfaceIPAddress) );
theErr = setsockopt( CFSocketGetNative( mSocketBroadcast ) ,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));