Pcap4j TCP packets being dropped after showing on Wireshark - java

For educational purposes I'm trying to perform a SYN flood attack on a Ubuntu 18.04 VM. I have enabled bridge mode in my VM settings and set up a web server (10.0.0.10) I can reach on my host pc (10.0.0.3) and vice versa with pings. Pinging from host to server shows Wireshark traffic on the server (request and response), pinging from server to host also shows Wireshark traffic on the server, but not on the host, even though the ping packets are correctly built.
The way I build my attack is to generate random IPs, construct TCP SYN packet and send it to the web server from my host through port 80 (open), which should send a TCP SYN/ACK packet back (I used iptables to route it back to my host pc).
If I construct a TCP packet through Pcap4J (Pcap library for Java) and subsequently send it through the handler, I see it pop up on the host Wireshark.
However, if I check the Wireshark on my VM, the packets do not arrive. The handler does not give an error and the program exits correctly and I am therefore unsure how to fix this problem.
Where is the packet dropped and what can I do to fix it? I need the packets to reach the web server VM (and the server to send them back).
Code:
Pcaphandle send_handle;
//nif_address is a constant of my ethernet connection defined in the file
try {
PcapNetworkInterface nif = Pcaps.getDevByAddress(nif_address);
if (nif == null) {
System.out.println("Networkinterface is null");
return;
}
// Open the device and get a send_handle
int snapshotLength = 65536; // in bytes
int readTimeout = 50; // in milliseconds
send_handle = nif.openLive(snapshotLength, PcapNetworkInterface.PromiscuousMode.PROMISCUOUS, readTimeout);
} catch (PcapNativeException e) {
System.out.println("Cannot bind NIF to variable from localhost");
e.printStackTrace();
return;
}
//Send packets, e.g. 1 packet by 5 different IPs
for (int i = 0; i < 5; i++) {
//generateIP() function not shown here, but is simply a randomizer and format to IP
InetAddress src_ip = generateIP();
Packet tcpPacket = constructSYNPacket(i, src_ip);
try {
send_handle.sendPacket(tcpPacket);
System.out.println(send_handle.getError());
} catch (PcapNativeException | NotOpenException e) {
e.printStackTrace();
}
}
private Packet constructSYNPacket(int packetNr, InetAddress src_address) {
TcpPacket.Builder tcpBuilder = new TcpPacket.Builder();
tcpBuilder
.syn(true)
.ack(false)
.rst(false)
.psh(false)
.urg(false)
.srcAddr(src_address)
.srcPort(TcpPort.getInstance((short) srcPort))
.dstAddr(dst_address)
.dstPort(TcpPort.getInstance((short) dstPort))
.correctLengthAtBuild(true)
.correctChecksumAtBuild(true)
.sequenceNumber(100000 + (packetNr*50));
IpV4Packet.Builder ipv4Builder = new IpV4Packet.Builder();
ipv4Builder
.srcAddr((Inet4Address)src_address)
.dstAddr((Inet4Address)dst_address)
.dontFragmentFlag(true)
.fragmentOffset((short)0)
.ihl((byte)5)
.correctLengthAtBuild(true)
.correctChecksumAtBuild(true)
.protocol(IpNumber.TCP)
.version(IpVersion.IPV4)
.tos((IpV4Packet.IpV4Tos) () -> (byte)0)
.ttl((byte)100)
.payloadBuilder(tcpBuilder);
EthernetPacket.Builder ethBuilder = new EthernetPacket.Builder();
ethBuilder
.srcAddr(nif_mac)
.dstAddr(dst_mac)
.type(EtherType.IPV4)
.payloadBuilder(ipv4Builder)
.paddingAtBuild(true);
Packet p = ethBuilder.build();
Note: I already disabled SYN cookies in the Ubuntu sysctl.

Even though I have not found out why bridging mode did not work, I managed to make it work using a host-only adapter. Pings and packets were received both ways when I used it.

Related

Java Broadcasting: throw BindException

I want that my client application is able to connect to a Server application.
The problem is that my Client doesn't know the Server ip (in LAN).
So I tried to use java object MulticastSocket. Luckily Oracle have a page with an example of Broadcasting.
Here I have rearranged it for my use.
Server code:
long FIVE_SECONDS = 5000;
int port = 4445;
DatagramSocket socket = new DatagramSocket(port);
while (true) {
System.out.println("Server running...");
try {
// message for client
String dString = "Hello Client";
byte[] buf = dString.getBytes();
// send
InetAddress group = InetAddress.getByName("230.0.0.1");
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, port);
socket.send(packet);
// sleep for a while
try {
Thread.sleep((long)(Math.random() * FIVE_SECONDS));
}
catch (InterruptedException e) {
System.err.println("Interrupted Exception");
}
} catch (IOException e) {
System.err.println("IOException");
}
}
Client code:
MulticastSocket socket = new MulticastSocket(4445);
InetAddress address = InetAddress.getByName("230.0.0.1");
socket.joinGroup(address);
// receive the message
byte[] buf = new byte[256];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String received = new String(packet.getData(), 0, packet.getLength());
System.out.println("Received: " + received);
socket.leaveGroup(address);
socket.close();
When I run Srver: no problem, but when I try running client it throw java.net.BindException: Address already in use cause both client and server are listening/sending information on port 4445.
But isn't it right? To connect each other they must have the same port number, or they'll never 'meet'.
Can I solve this problem? How?
Are the port number correct?
Is this a right resolution to the problem about the unknown server ip?
Thanks!
As Warren mentioned in his answer, your client and server can't bind to the same port on the same machine. The Oracle example is not doing that.
The client should bind to port 4446 and the server should bind to port 4445. When the server create a DatagramPacket it should do so with the client's port which is 4446.
If you do this and the client still can't receive, you may need to set the outgoing interface for multicast on the server. You can do this with either the setInterface or setNetworkInterface methods.
For example, suppose your serverhas IP addresses 192.168.1.1 and 192.168.2.1. If you want your sender to send from 192.168.1.1, you would call:
multicastSocket.setInterface(InetAddress.getByName("192.168.1.1"));
You are getting this exception because you are trying to run your server application and your client application on the same machine. When you start your client, your server has already bound to port 4445, so it is already in use - and thus unavailable - when your client tries to bind to it.
Running your server and your client on different machines would get around that particular error. However, you could also get around it by choosing different ports for your server and your client.
For example if you ran your server on port 4445, and your client on port 4446, you could do the following. On the server, you would add a variable for the client port, and use the client port as the destination port when sending your DatagramPacket:
int clientPort = 4446;
...
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, clientPort);
instead of
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, port);
On the client, you would simply bind to the client port instead of the server port:
MulticastSocket socket = new MulticastSocket(4446);
instead of
MulticastSocket socket = new MulticastSocket(4445);
Using different port numbers for the server and for the client would allow you to run both the server application and the client application on the same machine and get you past this particular issue.

UDP socket multicast

I will start by saying that I'm not absolutely a network expert.
I'm trying to create a UDP multicast socket system with four RaspBerry Pi model B.
Into each Rpi is running a listening script (I will call it "listen.py") socket client.
Case 1 - I'm perfectly able to send datagram if I run the socket server (I will call it "server.py") directly inside of the Rpi (by SSH, with my laptop as well).
I have:
-listen.py on boot of the Rpi (here I create a socket client);
-I run the server.py (the server.py is obviously into the Rpi)
In this case I receive answer from all 4 Rpi that joined the multicast group (224.1.1.1)
Case 2 - I created a socket server java and a socket client python in my laptop and everything works perfectly (same code, same multicast group, same multicast port).I tried also without multicast using just 'localhost' and everything works as well. With netstat I can see multicast group and port.
netstat -lu
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
udp 0 0 224.1.1.1:21581 *:* //MulticastGroupIp:Port
udp 0 0 192.168.1.103:ntp *:* //Static ip of one Rpi
udp 0 0 *:ntp *:*
My problem is that if I run the server.py from my laptop (no SSH) I have no answer from the listen.py, socket client, which is running into the Rpi. I absolutely need to send datagram from my laptop (I want a java class) to the 4 Rpi.
I have excluded the possibilities of bad code, wrong multicast ip group, wrong multicast port group. Firewall is off in my laptop and in the router as well.
The parameter net.ipv4.ip_forward on the Rpi is 1.
I know that UDP is unreliable but here I'm speaking about 100% of the datagram lost.
IGMP is enabled on my D-Link router.
I have the same problem with Ethernet and WiFi configuration.
I really need other ideas.....So I tried to write here.
Sorry, this is my first post and I'm newbie a bit of everything.
I will appreciate any suggestion.
Probably it's something stupid that I can't understand.
Maybe some problems with the routing table???? This is mine:
route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default D-Link.Home 0.0.0.0 UG 0 0 0 wlan0
192.168.1.0 * 255.255.255.0 U 0 0 0 wlan0
Thanks in advance
For me the code works well and the problem is not there but if can be useful to understand better the situation.....
Code of server.py (useless to say that I have python installed in my machine with Windows 7):
import socket
import sys
# import time
print 'message:'
n = sys.stdin.readline()
n = n.strip('\n')
MCAST_GRP = '224.1.1.1'
MCAST_PORT = 21581
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2)
sock.sendto(n, (MCAST_GRP, MCAST_PORT))
or with java (It's exactly what I want...a server socket java but at the moment it's not the priority):
public class PythonScriptScan {
private static int portMulticasting = 21581;
// private boolean broadcast = true;
private DatagramSocket socket;
private String groupMulticast = "224.1.1.1"; // group address
private int delay = 3000;
public PythonScriptScan() {
try {
socket = new DatagramSocket();
} catch (SocketException e) {
e.printStackTrace();
System.exit(1);
}
}
public void start(String agentName) {
try {
InetAddress group = InetAddress.getByName(groupMulticast);
#SuppressWarnings("resource")
MulticastSocket s = new MulticastSocket(portMulticasting);
s.joinGroup(group);
// while (broadcast) {
byte[] buf = new byte[10240];
buf = agentName.getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, portMulticasting);
System.out.println(packet);
socket.send(packet);
// OK, I'm done talking - leave the group...
s.leaveGroup(group);
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
System.exit(0);
}
// }
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
System.out.println("Insert Message");
#SuppressWarnings("resource")
Scanner sc = new Scanner(System.in);
String agentName = sc.nextLine();
PythonScriptScan agent = new PythonScriptScan();
agent.start(agentName);
}
and listen.py (It's running on boot in each Rpis, the configuration that I want is with Ethernet, each Rpis has a static ip and they are connected properly with my D-link router):
#!/usr/bin/python
import socket
import struct
import fcntl
import subprocess
import sys
import errno
import time
import os
# Create the socket
MCAST_GRP = "224.1.1.1"
MCAST_PORT = 21581
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
except socket.error, msg:
print 'Could not create socket. Error code: ' + str(msg[0]) + ' , Error message : ' + msg[1]
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Bind to the server address
# sock.bind(('', MCAST_PORT))
sock.bind((MCAST_GRP, MCAST_PORT))
# Tell the operating system to add the socket to the multicast group on all interfaces
mreq = struct.pack('4sl', socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
# Receive loop
try:
while True:
print >>sys.stderr, '\nWAITING TO RECEIVE MESSAGE'
d = sock.recvfrom(10240)
data = d[0]
addr = d[1]
print data.strip(), addr
finally:
print >>sys.stderr, 'closing socket'
sock.close()

UDP hole punching can't connect externally

I have previously made a simple peer to peer chat program using UDP hole punching that worked and now I am trying to do something similar but within a game made using libGDX. The game itself runs fine and the connections work on a LAN but I have difficult trying with external connections. I understand how UDP hole punching works as follows:
If both person A and B know each other's IP addresses and ports then:
A sends a UDP packet to B which punches a hole in A's NAT but is dropped by B's firewall
A waits for a reply
B sends a UDP packet to A which punches a hole in its own NAT and goes through A's firewall
B waits for a reply
A receives B's initial message and sends a second message to B
B receives A's message
My networking code is in one class:
private boolean connected;
private DatagramSocket socket;
private DatagramPacket packet;
private InetAddress peerIP;
public NetworkManager(InetAddress peerIP){
this.peerIP = peerIP;
log("Created with peer ip: " + peerIP.getHostAddress());
connected = false;
}
#Override
public void run(){
try{
log("Setting up socket");
socket = new DatagramSocket(Constants.CLIENT_PORT);
log("Socket successfully setup");
//Punch hole
log("Punching UDP Hole");
sendBytes("one");
//Receive
log("Waiting for peer reply");
receiveBytes(3);
//Send second message
if(Arrays.equals(packet.getData(), "one".getBytes()) ){
sendBytes("two");
}
}catch(Exception e){
log("Error connecting to peer");
return;
}
log("Successfully connected");
connected = true;
}
private synchronized void receiveBytes(int length) throws Exception {
packet = new DatagramPacket(new byte[length], length);
log("Receiving " + length + " bytes...");
socket.receive(packet);
log("Received bytes " + packet.getData()+ " from " + packet.getAddress());
}
private synchronized void sendBytes(String s) throws Exception {
byte[] sendBytes = s.getBytes();
packet = new DatagramPacket(sendBytes, sendBytes.length, peerIP, Constants.CLIENT_PORT);
log("Sending " + sendBytes.length + " bytes...");
socket.send(packet);
log("Bytes sent");
}
If both A and B are in the same network, i.e if they are in the same LAN, A can connect to B and vice versa. You don't need UDP Hole punching here.
But if they are in different networks, or behind different NATs, you can try to achieve a direct connection using UDP hole punching. Here you need a mediator server. And A and B need to ping mediator server, which will pass the IP and port number to the other corresponding clients.
Most important point to note here is that not all NATs supports hole punching. It is upto the NAT implementation, which is mostly not available in public domain. So even if you use UDP Hole Punching, you need a relay server as a fallback. In case it doesn't get hole punched, the relay server can pass the messages to each other.
http://www.brynosaurus.com/pub/net/p2pnat/
This link explains UDP Hole Punching architecture.

Multicasting message from Android app to local server

I'm developing an Android app that at some points, sends a multicast message. I'm running this on an emulator device so far.
On the same machine, I have a server (not Android, a plain Java app) that is expecting the multicast message, but it never gets it. When I start the server, since it is on my local machine, I start it the loopback interface (127.0.0.1). I must say that I've done this with regular Java apps and it works perfectly.
Here's the code for the Android App:
try {
InetAddress group = InetAddress.getByName(MULTICAST_HOST);
byte[] data = DISCOVER_MESSAGE.getBytes();
DatagramSocket ds = new DatagramSocket();
ds.setSoTimeout(60000);
DatagramPacket dp = new DatagramPacket(data, data.length, group, TcpipSIBDiscoverer.PORT);
ds.send(dp);
byte[] buf = new byte[1024];
dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
if (dp.getLength() > 0) {
byte[] tmp = new byte[dp.getLength()];
System.arraycopy(dp.getData(), 0, tmp, 0, tmp.length);
String received = new String(tmp);
Logger.debug(this, "Received from SIB: " + received);
SIBDescriptor sibDescriptor = createSIBDescriptor(received);
this.discoveryListener.connectorSIBDiscovered(sibDescriptor);
}
} catch (SocketTimeoutException e) {
Logger.error("Socket time excedeed while waiting a response when discovering SIBs. Trying again");
} catch (IOException e) {
Logger.error("There was some kind of IO error while waiting for a response when discovering SIBs. Trying again");
}
As you can see, I'm using a regular DatagramSocket instead of MulticastSocket. This works in plain Java apps, since the listening server address is 235.0.0.1:5555.
Not really sure if the code is not working or I have to do something in the emulator device so it can truly reach my loopback interface... Any ideas?
Thanks!
Alex
127.0.0.1 on android refers to the device's localhost (or the emulators).
To reach localhost of your 'local machine' you should use 10.0.2.2.
This is discussed in a lot of topics.

Java: Receiving an UDP datgram packet with multiple DatagramSockets

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));

Categories