I have some code like this:
InetAddress bind = InetAddress.getByName("192.168.0.1")
MulticastSocket socket = new MulticastSocket(new InetSocketAddress(bind,0));
socket.setInterface(bind);
On windows 7 and windows XP with JDK6u17,I got a SocketException: Socket operation on non socket.
But if I change the line 2 to :
MulticastSocket socket = new MulticastSocket(0);
It's ok, and works find too with jdk6u14.
Why? thanks.
EDIT:
Why port 0 should be the matter?
MulticastSocket socket = new MulticastSocket(0);
Everything goes well with this code.But not
MulticastSocket socket = new MulticastSocket(new InetSocketAddress(bind,port));
Whatever the port is.
As you are binding to a specific interface, calling setInterface() to the same interface is redundant. Remove it. It's only needed when you bind to INADDR_ANY, or in Java an InetAddress of null (or unspecified as a parameter).
To address errors in some of the other answers, and their implications:
Port zero is legal. It means a system-assigned port.
You only need a MulticastSocket for receiving multicasts. For sending, you can just use a DatagramSocket.
If the multicast interface needs to be specified, which it doesn't in this case, it can be done either via MulticastSocket.setInterface() or when calling joinGroup() or leaveGroup(). The latter option gives you granularity at the group level, but both techniques work. That's why they're both provided.
If you don't bind to a specific interface you should definitely call setInterface(). If you are on a multi-homed host you must to call joinGroup()/leaveGroup() once per interface, if you want to receive via all of them.
And a question: is 192.168.0.1 an IP address of an NIC on the local machine? It needs to be.
According to the documentation, you are supposed to instantiate it with a port number (thus 0 would be valid).
I am not so sure.
What's the constructor MulticastSocket(SocketAddress bindaddr) for.
And why it works fine with jdk6u14,but not jdk6u17?
And why it ok on windows 2003 server with jdk6u17?
On RHEL5.2 jdk1.4+
http://www.sockets.com/err_lst1.htm
Berkeley description: An operation was attempted on something that is not a socket. The specified socket parameter refers to a file, not a socket.
WinSock description: Same as Berkeley. The socket input parameter is not a valid socket handle (either it never was valid, it's a file handle (not a socket handle), or if it was a socket handle, it has been closed).
Detailed description:
select(): fails with WSAENOTSOCK if any socket in an fd_set is an invalid socket handle.
Developer suggestions: Did you close a socket inadvertently in one part of an application without keeping another part notified? Use socket state in an application and/or handle this error gracefully as a non-fatal error.
when the MulticastSocket created,socket.isClosed()==true
I haven't used these classes before, but the Exception occurs on line 3 when you call the setInterface method.
I would guess it's something to the effect that you're using the same reference twice or something.
I found a snippet of code that looked like this, maybe this is how you should be doing it:
MulticastSocket ms = new MulticastSocket(new InetSocketAddress(0));
ms.setInterface(InetAddress.getByName("192.168.0.1"));
You should first create the Multicast socket with a well known port - something higher than 1024 and less than 65535 - as already stated 0 means the operating system will choose a port for you (but then its going to be kinda random - which I guess you don't want).
For multicast - you generally need to set the interface to use on joinGroup() not on creation - e.g:
MulticastSocket socket = new MulticastSocket(2121);
InetSocketAddress socketAddress = new InetSocketAddress("localhost", 2121);
if (networkInterfaceName != null){
NetworkInterface ni = NetworkInterface.getByName(networkInterfaceName);
socket.joinGroup(this.socketAddress, ni);
}else {
socket.joinGroup(socketAddress.getAddress());
}
According to the MulticastSocket documentation you should use
Class D IP addresses in the range
224.0.0.0 to 239.255.255.255, inclusive
to bind a MulticastSocket. Apparently, the "192.168.0.1" is out of the multicast range.
Related
I have been testing the SCTP support on Java + lksctp.
I wrote a simple client in order to see just the inital setup of a SCTP association which is basically the "INIT" and "INIT ACK".
I have tested 2 ways for a Client to send the "INIT" to a SERVER which is basically:
create the SctpChannel object with "open(SocketAddress)"
try {
InetSocketAddress socketAddress = new InetSocketAddress("192.168.52.197", 2905);
SctpChannel sctpChannel = SctpChannel.open(socketAddress,1,1);
sctpChannel.bind(new InetSocketAddress("192.168.1.251",2906));
sctpChannel.connect(socketAddress, 1 ,1);
so in this way, I can see in Wireshark that I have the "IPv4 Address parameter" for all my network interfaces (3 as you can see bellow), but the Source Port is getting a aleatory port number instead the 2906 as I would like to have and it's in the bind.
So... once the bind of local IP/Port is happening after the "open"... so I have changed the code to:
create the SctpChannel object which just "open()"
binding the local client IP and Port
"connect" to the remote Server IP and Port
try {
InetSocketAddress socketAddress = new InetSocketAddress("192.168.52.197", 2905);
SctpChannel sctpChannel = SctpChannel.open();
sctpChannel.bind(new InetSocketAddress("192.168.1.251",2906));
sctpChannel.connect(socketAddress, 1 ,1);
In this way, I can see in wireshark that Source/Destination ports are expected (2906/2905), but the INIT does not have the "IPv4 Address parameter".
So does anyone know why the 2nd code I'm missing the "IPv4 address parameter" in the INIT ? Do I miss something?
Any help would be really welcome.
Thanks.
IP addresses within INIT/INIT_ACK chunks are optional parameters. In case your endpoints are signglehomed IP address might not be included in the INIT/INIT_ACK chunk. The remote end still can retrieve information about peer address from the IP header.
Fundamentally the reason of this behaviour is what parameters you pass to open(). Open() without any parameters and open() with remote address specified works in a different way.
If you call SctpChannel.open(socketAddress,1,1) with socket address for the remote end it effectively open channel and connects to remote end (see open documentation. Your bind() and connect() calls in this case are pretty useless. So since there were no bind() call prior to establishing the connection you are sort of using "default" endpoint with random port (56044) and IP addresses of all available interfaces.
In second case, when you don't specify socketAddress for open() it just open the channel but does not connect to remote end at this stage. So your bind() call successfully specify endpoint details (port and IP address) and when you call connect() it is actually using the endpoint you just created (192.168.1.251:2906) to setup connection with remote end.
I have a ServerSocket object that is listening with accept method. How do I accept connections only coming from the same network and not outside?
If your system has multiple network interfaces and one of them is receiving local connections only while others should be ignored, you can set up a ServerSocket with the IP-address of the netork interface to bind it only to that particular interface:
ServerSocket ssocket = new ServerSocket(1234, 10, InetAddress.getByAddress("192.168.1.1"));
With IPv4 and IPv6 you obviously need two ServerSockets.
If local and remote connections are received from the same network interface, you have to check the remote peer yourself. This can be done in different ways:
You can set a SecurityManager that implements checkAccept and throws a SecurityException if the connection attempts comes from the wrong place. This is a global setting, so with this you can't set up a ServerSocket at some other part of the application that should accept connections from there.
You can check the IP and port of the Socket being returned from ServerSocket to be local and close the socket if it's not instead of continuing with the request
You can create a subclass of ServerSocket overriding the method checkAccept where call super.accept, do the corresponding check as described in option 2 and only return the retrieved connection if it fit to your criterias or otherwise close it and call the super-method again.
Create the ServerSocket via the constructor that accepts a local IP address, and supply 127.0.0.1 as that IP address.
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 don't find any information on this topic on the internet and asked here. For example I have server with IP 1.1.1.1 and 2.2.2.2 and two domain names pointing to it one.example.com and example2.net, and socke listening on port 1234 for incoming connections.
For example:
C/C++:
listenfd=socket(AF_INET, SOCK_STREAM, 0);
bind(...);
listen(...);
while(...) accept(...);
or Java:
ServerSocket socket = new ServerSocket(1234);
while(...) {
Socket connectionSocket = welcomeSocket.accept();
...
}
When client accepted on my socket I need to know what domain name/IP is used by the client to connect. It may be one.example.com or example2.net and/or IP 1.1.1.1 or 2.2.2.2 (if connected using IP only).
Apache somehow determined ip/domain of incoming reques, and I need to do such thing in pure socket code. C++ (main) or Java (or any other) accepted, I need to know mechaniics of this.
The IP is stored inside the IP packet header and you can read it from there. In order to get the host, you'll probably have to ask a DNS server by sending a request (or use a function which does it for you). You can find examples for both of the problems, even on this site
I'm writing a piece of UDP networking program (client - server), and I've run into some trouble.
I want to use streams to I/O data, so I googled "udp inputstream" and found UDPInputStream and UDPOutputStream. When I try to use these, however, the program gets stuck when trying to initialize the UDPOutputStream.
This is the line in my code that freezes:
outStream = new UDPOutputStream(InetAddress.getByName("127.0.0.1"), port);
System.out.println("UDP output stream initialized."); // <-- doesn't get called
I checked out the source of the UDPOutputStream, the code gets stuck on this line:
dsock = new DatagramSocket();
Why does the execution hang up on this line? On the server side, I still use my "old", non-stream version of a simple UDP code, and it works. The socket is initialized the same way and it doesn't hang up. I tried to put a port number to the initialization, but it doesn't solve the problem.
Host machines have more than one network interface (for example, 127.0.0.1 for the loopback interface and some other address for the network card; there may be more than one network card).
If you bind to the loopback address 127.0.0.1 then you'll only be able to receive packets sent locally. If want to receive packets sent over the network from a remote machine you must bind to the local IP address (e.g. 192.168.1.100).
Try following:
InetAddress addr = InetAddress.InetAddress.getLocalHost();
outStream = new UDPOutputStream(addr, port);