If I bind to a specific interface using a specific hostname and then use ServerSocketChannel.getLocalAddress() to retreive the bound address, the hostname is longer there.
Is this by design or just undefined behavior? Is there any way to fix that?
InetSocketAddress bindTo = new InetSocketAddress("my-hostname", 9999);
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(bindTo);
InetSocketAddress localAddr = (InetSocketAddress) serverSocketChannel.getLocalAddress();
System.out.println(bindTo);
System.out.println(localAddr);
> my-hostname/10.20.200.201:9999
> /10.20.200.201:9999
"my-hostname" in the above example is one of several hostnames that will resolve to the local IP. It is, however, not the hostname to which the IP resolves to when doing a reverse lookup.
The reason I ask is that I use a framework which will bind and then publish the service information to a central registry. However, it retrieves the bound address using .getLocalAddress() which ultimately ends up publishing the wrong hostname.
the hostname is longer there
You mean "the hostname is longer there" in the String returned by InetAddress.toString(). There's nothing that obliges that behaviour. The local address to which a socket is bound is primarily an IP address. If you want to map it to a hostname, that's up to you.
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 programming a little Authentification System and I use this code to get the IP of the user:
DatagramSocket socket = new DatagramSocket(port);
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);
InetAddress address = packet.getAddress();
String ip = address.toString().replace("/", "");
My question is: Can we trust the value given with the string ip? Can somebody put a fake IP in a header of the packet?
It is very confusing, does a UDP header contain the IP of the sender of the UDP packet, if so can we change this header to modify with another IP?
In an established TCP connection, you can assume that the remote IP address is valid because otherwise you could not send anything back to the host (and the TCP handshake would not succeed -- see SYN flood).
However, you have no guarantee that the remote IP address actually belongs to your user, so it's a really bad way to perform authentication.
One of the commenters gave the example of a proxy. It doesn't have to be TOR: if you use the common practice of an NGINX or Apache server in front of your application, then you'll always get the IP address of that server (ie, your own server).
Also, we live in a world where most users are behind a NAT. Which means that you may have dozens or hundreds of distinct users that all appear to come from the same IP address.
And the IP address will potentially change. This is particularly common with connections made from cellphones
Is it possible to change TCP header in Java?
If it's possible, is there any [Change Header] method?
Answering the more narrow question from the title of your question ("How to change source ip in Java"), you can bind your socket to a local IP address and/or port before you connect it to a destination.
The IP address you bind to has to be an IP address that your machine has (otherwise, how could packets arrive back at your machine?). You can also take any unused, non-reserved port number to connect from.
Socket socket = new Socket();
socket.bind(new InetSocketAddress(9999));
// or: socket.bind(new InetSocketAddress(InetAddress.getByAddress(...), 9999));
socket.connect(new InetSocketAddress(InetAddress.getLocalHost(), 80));
More generally, the answer is no, you cannot just randomly change the TCP header. But there are plenty settings that you can do from Java that will affect what goes into the TCP header.
I'm wondering whether you'r thinking about to cheat the server by providing a random source ip. As far as I know, there's no way to do this in java.
And even if you have changed your ip address, i think you can not successfully "hand-shake" with the server, which means you can not establish a TCP connection with the server side.
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 want to create an InetSocketAddress but I want to do it right no matter if I get a host:port or a ip:port. I see it has two constructors, one for host (String) and another one for IP (InetAddress). Do I have to determine myself if I got an IP or HOST in order to choose between these two constructors? Am I missing something here?
You can infer from the Javadoc, and see in the source code, that new InetSocketAddress(String hostname, int port) calls InetAddress.getByName(hostname), which sorts all that out for you as documented.
So the problem you're posting about doesn't really exist. Just pass whatever string you get, whether host name or IP address.
I'm not entirely sure what it is your asking, but, I did this quick test on my PC without any issue
try {
String ipAddress = ""; // Add your own
String hostName = ""; // Add your own
int port = ...; // You'll need some sort of service to connect to
InetSocketAddress byAddress1 = new InetSocketAddress(ipAddress, port);
InetSocketAddress byAddress2 = new InetSocketAddress(InetAddress.getByName(ipAddress), port);
InetSocketAddress byName1 = new InetSocketAddress(hostName, port);
InetSocketAddress byName2 = new InetSocketAddress(InetAddress.getByName(hostName), port);
} catch (UnknownHostException unknownHostException) {
unknownHostException.printStackTrace();
}
The bigger question is, what are expected to get as input? IP address, host name or some other form??
You will have to determine whether the String passed to the constructor is an IP or a Host name. I'd do it with a Regex for the IP address. If that fails, it's probably a host name.
Both IP addresses and Host names are String, so you will how only one constructor.
Also it is worth to mention, if you don't know your dns name or ip, you can simple use constructor with port only.
new InetSocketAddress(8080)
it internally invokes InetAddress.anyLocalAddress()