I'll like to computers/clients to connect directly to each other in the case where one or both of them haven't got a public IP. I guess this could be done with a server as a middle man. The connection established in the end must be direct traffic between the clients. How is this possible, and what is the technic called?
I'll really like to see some code fx in Java.
Thanks
If port forwarding is not an option, there is a mostly-reliable technique you can use with UDP traffic called NAT traversal. It requires a middle-man server to act as a rendezvous point, but after the initial set-up all traffic will be endpoint-to-endpoint.
This will not work in all cases; it depends on how the various NAT layers map external endpoints to internal entpoints.
TCP NAT traversal is very difficult to implement and has an extremely low chance of even working.
(I have successfully used UDP NAT traversal to establish an OpenVPN connection between two computers at different universities, both behind several NAT layers!)
You will propably have to use hole punching (TCP or UDP) if both parties are behind NAT. Something like this:
socket = new DatagramSocket(port);
volatile boolean connectionEstablished = false;
volatile boolean reveivedSomething = false;
Sender-Thread:
while (!connectionEstablished) {
byte[] buf = new byte[256];
buf[0]=reveivedSomething?1:0;
DatagramPacket packet = new DatagramPacket(buf, buf.length,
otherpcpublicaddr, otherpcsport);
socket.send(packet);
Thread.sleep(500);
}
Receiver-Thread:
while (true) {
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
reveivedSomething=true;
if (buf[0]==1) {
connectionEstablished=true;
break;
}
Thread.sleep(500);
}
(you would have to do this on both PCs and to exchange IPs and ports using some reachable server as long as they aren't static)
I don't know of a Java fix, but you could use a dynamic dns service to re-route the traffic into the non-public ip. I think they use a client that keeps track of the public client IP that is assigned by their ISP, and reports it to the service, which then updates their host table. There may also be some configuration needed on each system's routers, in order to forward the public request into the private ip.
There would be several techniques used to perform this, port forwarding, NAT, Dynamic DNS, etc
Related
I'm making a simple UDP chat program, and i would like the server to be able to send to the client without receiving data from it first. Normally, when it receives data from the client, the server gets the IP and port of the client, so it can communicate with it.
My server code:
package com.ageforce;
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class ChatServer {
DatagramSocket server;
byte[] receivedData = new byte[1024];
Scanner scanner = new Scanner(System.in);
byte[] sentData;
DatagramPacket dp2 = new DatagramPacket(receivedData, receivedData.length);
public ChatServer() throws SocketException {
server = new DatagramSocket(7000);
}
public static void main(String[] args) throws SocketException {
ChatServer cs = new ChatServer();
Thread receiveMessage = new Thread(() -> {
while (true) {
try {
cs.server.receive(cs.dp2);
} catch (IOException e) {
e.printStackTrace();
}
String storedData = new String(cs.dp2.getData());
System.out.println(storedData);
}
});
Thread sendMessage = new Thread(() -> {
while (true) {
String sentMessage = cs.scanner.nextLine();
cs.sentData = sentMessage.getBytes();
// This is the area of the code where the server gets IP and port of client from the received data. I'd like this to be changed.
InetAddress getIP = cs.dp2.getAddress();
int port = cs.dp2.getPort();
DatagramPacket dp3 = new DatagramPacket(cs.sentData, cs.sentData.length, getIP, port);
try {
cs.server.send(dp3);
} catch (IOException e) {
e.printStackTrace();
}
}
});
sendMessage.start();
receiveMessage.start();
}
}
Is it possible to do this? Any reply is greatly appreciated.
How do i get the port and address of client without receiving data from it first?
UDP does not afford that possibility. It is a connectionless protocol, so the server doesn't even know that there is a client until it receives a message from it.
You could conceivably create some kind of preliminary application-level protocol whereby the client announces itself to the server before sending it any chat data, but nothing of the sort is part of UDP itself, and if that's something you want then you should consider using TCP instead, which does have a built-in concept of establishing a connection before sending any data.
In order to send an UDP message to something, you need to know the IP and port number to send it to. How? Well, you tell me.
The way your protocol works right now is that the clients know your hostname (which they let their system turn into an IP automatically), and the port number is hardcoded in the client app. The server knows which IP and port to send data back to by checking the 'sender' IP/port when it receives a call.
If you don't like your current protocol you'll need to figure out a different way to answer this question.
Even if you find a way, you'll find that this is mostly useless. The vast majority of end-users intentionally do not have a so-called publically routable IP address. You cannot reach them by design. In your current protocol, that IP/port combo you send back to isn't really the sending computer at all. It's some router, for example the router in their home. That router saw the outgoing UDP packet and is remembering for a while: Any traffic coming in on that port is supposed to go to that computer in this house.
Short of completely crazy stuff such as 'hole punching' (which skype used for a while, not sure if they still do, it's a complicated hack that doesn't always work and is surely not what you want here - you can search the web for that term), there's simply nothing you can do here. end-user systems aren't servers and cannot be reached like this.
Your run-of-the-mill chat apps will always have clients ping the server and then just keep that connection open as long as they can.
If a Java application creates a ServerSocket that accepts TCP connections, is there a way to restrict which processes are allowed to connect to it?
For example, this is my current code:
ServerSocket serverSocket = new ServerSocket(1234);
Socket socket = serverSocket.accept();
and I want to make sure that other devices on my network and even other processes running on the same machine are not able to connect to it (it would be a security risk if they did). I was able to solve the former by binding serverSocket only to the loopback address (checking if socket.getRemoteAddress() points to the local host would work too) but I couldn't find a way to restrict it to my current process.
This is even more of a problem when doing it on Android. In my application, I want to create a WebView (owned by my process) and point it to serverSocket but I don't want others apps to be able to connect to it.
Is there a way to solve this problem?
You can bind it to 127.0.0.1,[1] which prevents any process outside the localhost from even seeing it. But any process in the localhost can connect to it. That being what it's for. If you want to restrict that to certain processes you will have to implement an authentication step in your protocol.
Hard to see why. If you can't trust other processes in the localhost you have a rather large problemm in general, not just here.
[1] Or indeed 127.0.0.x where 1 <= x <= 254. Using an obscure number like 200 might help by obscurity but it still isn't really secure.
I don't think that you can prevent other processes from connecting to the ServerSocket but you accept a connection you can definitely determine if it belongs to you or to some other process. The first step is figure out if the connection originated from localhost:
InetSocketAddress remoteAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
String hostname = remoteAddress.getHostName();
if (!hostname.equals("localhost")) { socket.close(); }
Alternatively you can bind the socket to a loopback address like 127.0.0.1 or 0.0.0.0 (like EJP mentioned) and skip this step. Once you know that the connection came from localhost all you have to do is find the remote port and figure out if your process owns it.
int remotePort = remoteAddress.getPort();
if (ownPort(remotePort) == 1) { socket.close(); }
As far as I know, Java doesn't have an API that you can use to list your process ports but you can definitely do that via JNI. On the Java side you would need something like:
private native int doOwnPort(int port);
And on the native side:
JNIEXPORT jint JNICALL Java_something_doOwnPort(JNIEnv *env, jobject object, jint port) {
long totalFDs = getdtablesize();
struct sockaddr_in sa;
struct stat sb;
// Iterate through all file descriptors
for (int i = 0; i < totalFDs; ++i) {
// Check if "i" is a valid FD
memset(&sb, 0, sizeof(sb));
if (fstat(i, &sb) < 0)
continue;
// Check if "i" is a socket
if (!S_ISSOCK(sb.st_mode))
continue;
// Get local address of socket with FD "i"
memset(&sa, 0, sizeof(sa));
socklen_t sa_len = sizeof(sa);
getsockname(i, (struct sockaddr*) &sa, &sa_len);
// Check if the port matches
if (sa.sin_port == port)
return 1; // We own the port
}
return -1; // We don't own the port
}
PS: This code is for Linux but should work on Android/Windows/OSX too.
Maybe there is a more direct/efficient way to check if the port is owned by the current process without having to iterate through the FD table but that's a separate problem. HTH!
You can get this type of security
using firewalls
implementing some kind of authentication yourself on your ServerSocket. Ask for username and password?
Sockets were not designed for restricting to distinct processes.
From Android Security Tips:
We have seen some applications use localhost network ports for handling sensitive IPC. We discourage this approach since these interfaces are accessible by other applications on the device. Instead, you should use an Android IPC mechanism where authentication is possible such as with a Service. (Even worse than using loopback is to bind to INADDR_ANY since then your application may receive requests from anywhere.)
I'm trying to make a basic datagram client/server program with Java.
I've made the server cling to port 9321 on my local computer.
I've made the client on port 9320 on my local computer,
then send the data over wireless router network (192.168.1.100) at port 9321
the program works!
then i try to send the packet over (via router)internet IP 139.195.12.183(my ip) at port 9321
but it didnt work!
there is this exception:
java.net.SocketException: Interrupted function call: Datagram send failed
i've set the router to forward any request for port 9321 to my computer
and then i've set exception for the firewall on my computer on that port
this is the source
String SERVER = "139.195.12.183";
sendString(SERVER, 9321, "Greetings"); <<
private void sendString(String IP, int port, String toSend) {
byte[] buf = toSend.getBytes();
DatagramPacket packet = null;
try {
packet = new DatagramPacket(buf, buf.length, InetAddress.getByName(SERVER), port);
ds.send(packet);<<
}catch(UnknownHostException e) {
System.out.println("unknownhostception");
}catch(IOException e) {
System.err.println("ioception "+e.getMessage());
}
}
i've had another answers from another forum it said:
"The way routers work, you can't see your external (WAN) internet address from your
internal network (LAN). If that's what you are trying to do, there's nothing wrong, it
just won't work.
Ian."
any explanation?
Some steps that you can take:
Check that the code works across two machines on your LAN.
Check that ping <target-ip> works on your machine.
If it does, check your local and LAN firewall settings for blocking on the port/protocol.
If the ports are unblocked change the port to something else. Some ISPs will block certain ports.
Some more reasons why this error could come up:
UDP (I Assume?) datagram too large.
Client side error that doesn't affect reception (Have seen similar things with some network stacks where the error was spurious.)
Post a link to your code from patsebin or something if you want more info.
I need to broadcast an UDP packet on every network interface. At first, I tried broadcasting to 255.255.255.255, with no results, and I later discovered that this "has been deprecated for about 20 years". So I tried iterating on every network interface in order to get the broadcast address of the interface and then send an UDP packet to that address.
Still, the following code:
public static Collection<InetAddress> getBroadcastAddresses() {
try {
Collection<InetAddress> result = new LinkedList<InetAddress>();
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netint : Collections.list(nets))
for (InterfaceAddress address : netint.getInterfaceAddresses()) {
InetAddress broadcastAddress = address.getBroadcast();
if (broadcastAddress != null)
result.add(broadcastAddress);
}
return result;
} catch (SocketException e) {
throw new RuntimeException(e);
}
}
public static void broadcast(int port, DatagramPacket packet,
DatagramSocket socket, PrintWriter logger) throws IOException {
packet.setPort(port);
for (InetAddress address : getBroadcastAddresses()) {
logger.println("Broadcasting to: "+address);
packet.setAddress(address);
socket.send(packet);
}
}
prints this stuff:
Broadcasting to: /0.255.255.255
Broadcasting to: /255.255.255.255
Broadcasting to: /255.255.255.255
Broadcasting to: /255.255.255.255
Broadcasting to: /255.255.255.255
which is really annoying. Am I supposed to grab the IP address and netmask for every network interface and perform bitwise operations to "build" the correct broadcast address? This seems to me like Unix socket programming in C... Is there a clean, Java way to neatly deliver a miserable UDP packet to all the buddies that crowd my network?
EDIT: searching the web, it turned out that this time my code is not broken. Instead, the JVM is. The data you get from InterfaceAddress.getBroadcast() is inconsistent, at least under Windows 7. See for example this and this: the solution seems to set a Java system property in order to make it prefer IPv4 over IPv6, but this doesn't work for me. Even with the suggested workaround, I get different results on every different run, and since the broadcast address I get is apparently random, I suspect I'm given data taken from undefined state memory locations.
You need to get the network IP and mark and use this for broadcast. That the simple part. Then you need to collect all the replies knowing that some servers may not have received the UDP packets and some of the replies could have been lost. You have to allow for the fact that UDP is designed to be unreliable.
I would parse ipconfig /all directly to get the IP and submask. Even ipconfig only has a submask for IPv4
I am running a simple UDP Java Server, which collects IP and Port of Client when connected, store information in Database.
Client is still listening to server. Server stops.
Later, server want to reuse the database information, to reach the client; and as the client is still listening to same port of server, I guess client should receive the communication.
I am new to UDP, please let me know the way to achieve the above objective. Thank you.
Let me rephrase the question as I did try the ways suggested by members of Stackoverflow.
The client can be contacted by server within a short timespan, but after say 10 mins the client is unreachable; although it appears client is ready to listen to server for all the time but the server cannot reach client even if tried for several time. What could be cause for this? please let me know the way to deal with this
I think you are a bit confused regarding the UDP protocol (RFC 768). I think it would be helpful to review the UDP protocol to understand the differences between UDP and TCP.
Regarding your specific problem, it is difficult to know what is your exact problem without any type of code. There is a Client-Server in UDP example available in the sun tutorials.
UDP is sessionless, so I guess it should indeed work.
It would go something like that:
// Client:
socket = new DatagramSocket();
DatagramPacket req = new DatagramPacket(data, data.length, serverAddress, serverPort);
socket.send(req);
DatagramPacket resp = new DatagramPacket(new byte[MAX_RESP_SIZE], MAX_RESP_SIZE);
socket.receive(resp);
// Server:
DatagramSocket socket = new DatagramSocket(port);
while (!stopped) {
DatagramPacket req = new DatagramPacket(new byte[MAX_REQ_SIZE], MAX_REQ_SIZE);
socket.receive(req);
saveToDatabase(req.getAddress(), req.getPort());
}
socket.close();
// Then later:
DatagramSocket socket = new DatagramSocket(port);
// retrieve clientAddr and clientPort from database
DatagramPacket resp = new DatagramPacket(data, data.length, clientAddress, clientPort);
socket.send(resp);
socket.close();