Delaying incoming traffic using tc affects the host as well as VM - python

I wish to demonstrate a DNS cache poisoning attack. For this, I have configured a DNS server on a VM. I am trying to delay incoming traffic from the following IP addresses to the VM: 199.43.133.53 and 199.43.132.53 using tc and the following commands:
modprobe ifb
ip link set dev ifb0 up
tc qdisc add dev eth0 ingress
tc filter add dev eth0 parent ffff: protocol ip u32 \
match ip src 199.43.132.53/16 flowid 1:1 action mirred egress redirect dev ifb0\
tc qdisc add dev ifb0 root netem delay 5000ms
The two IP addresses correspond to the nameservers of a domain. When I ping these two nameservers from the VM after adding these rules, it does get a delayed response which is fine. What I wish to delay is the DNS response from these nameservers. And this is still pretty fast.
I am also running a python script on the host machine which sends packets to this VM. When these rules are added to the VM, the python script ( uses Scapy and sendp to write packets) also experiences a delay. Though when I ping the VM from host machine, the ping response is pretty fast. Why does Python's sendp experience a delay when the host machine's IP is not a part of the filter. And in that case, why is the ping response (ping request from host to VM) normal and not delayed. What am I missing here?

Related

How to capture martian packets without letting the linux kernel to drop them and then catching them using raw sockets

I'm trying to setup a network to simulate an Edge computing scenario with LTE. But the question here is more pertaining to IP tables and raw sockets on the server.
I have the following setup:
PC-A is the Tower, PC-C is the LTE Core, PC-B is acting as intermediary and routing data using proxy ARPs
Cell phone wants to connect to a TCP server on PC-B(IP: 172.17.1.3)
Cell phone(IP:192.172.0.2) sends packets to PC-A(IP: 172.17.1.1)
The data from PC-A(172.17.1.1) generally has to reach LTE-EPC on 172.17.1.4 which is connected via PC-B(172.17.1.2 - 172.17.1.3 with proxy ARPs). And the data comes in the form of UDP packets to PC-B(IP: 172.17.1.2)
I use NAT table and python script with raw sockets to send all of these UDP packets to a local port, do some filtering, decapsulate the GTP headers and send the TCP/IP packet to the TCP server on PC-B interface(172.17.1.3). I use the below iptables settings to do this
iptables -t nat -A PREROUTING -p udp -d 172.17.1.4 --dport 2152 -j DNAT --to-destination 172.17.1.2:7000
Until here everything works, the extracted TCP/IP packet also reaches the TCP server on 172.17.1.3. The server responds to these packets. For example, for the SYN packet from the cell phone, the server now sends out SYN, ACK. However, the server responds to the original source address 192.172.0.2.
I want to catch these response TCP/IP packets from the TCP server 172.17.1.3 to 192.172.0.2 and do some GTP encapsulation before sending them back to PC-A.
Can anyone tell me how I can use the iptables to tell the kernel to stop dropping these martian packets with destination address 192.172.0.2, but instead forward to a local ip and port, so I can read the same.
I can see the SYN, ACK responses from the server on wireshark. But I assume that these are dropped as I already tried to route it to local ip:port using a similar iptables rule from above.
Any help is much appreciated, Thank you.
It sounds like a tun/tap interface could be useful here. Here's the official Linux kernel documentation.
Both these interface types allow a program to create a virtual network interface. This is designed for tunnels and VPNs and it seems like that is exactly what you are creating.
According to the linked documentation, you may create an interface by opening /dev/net/tun (O_RDWR) and issuing this ioctl to initialize it:
struct ifreq req;
memset(&req, 0, sizeof(req));
req.ifr_flags = IFF_TUN; // or IFF_TAP
strncpy(req.ifr_name, "tunnel%d", IFNAMSIZ); // optional; leave it blank to get a default name; you don't have to have a %d
ioctl(fd, TUNSETIFF, &req); // error check omitted for demonstration
// req.ifr_name now contains the name that was actually selected
After the ioctl you have a virtual network interface in your system. You can configure IP addresses, routes, whatever.
Any time the kernel sends a packet out through your interface it will go into a queue and you'll be able to read it. Any time you write to the interface the kernel will process it as if it's a real packet that just arrived.
You will need to configure networking like it's a real interface. Set up a static route so that 192.172.0.0/16 (or whatever your subnet is) is reached through the tunnel interface. I'm not sure if Linux will let you do this without giving it an address; you might have to give it a dummy address like 192.172.255.254. Or a completely unrelated address like 1.2.3.4 and then let Linux think there's another router in front of your cellphone subnet. Or maybe it will just work without an address - not sure.
The difference between "tun" and "tap" is whether Ethernet processing happens or not (IP tunnel vs Ethernet tap). I expect tun is right for your application. If you choose tap then Linux will also use ARP and so on, and the interface will certainly need an address.
You might find it convenient to use the tunnel interface in both directions, or just one. IP packets aren't required to take the same route in both directions. This is the "correct" way to implement a tunnel, so you might find that a lot of mysterious bugs go away by using it.

Python sockets google dns server

I need my own IP in a small script and in order not to hardcode it, I`ve found a piece of code from here(stackoverflow) that works.
This--
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
s.connect(("8.8.8.8", 80))
print(s.getsockname()[0])
--
What is not clear for me is why it only works on UDP and not TCP? It has something to do with the google dns server? Thanks in advance.
This has nothing to do with Google and nothing to do with DNS.
All what this code does is to "connect" a UDP socket to an external IP, so that the OS kernel figures out which local IP address it needs to use in order to reach this external system. This is no real connection, i.e. there is no traffic involved but the OS kernel is only checking routing tables and local interfaces in order to decide which IP address to use as source in case one would actually use the socket to send data.
One could do the same with TCP. But in this case a real TCP connection would be established which means that actual traffic would be exchanged and that the connect would fail if the external system would not be reachable on this port (i.e. no listener, firewall in between etc).
With UDP instead connect will not produce any traffic and would fail only if no route to the destination IP address could be determined. This also means that an arbitrary external IP address and port could be used, i.e. ('1.1.1.1',11) would work the same as ('8.8.8.8',80).

Vagrant: Getting connecting clients real ip

I have a simple Apache+Flask website running inside a basic Vagrant+VirtualBox environment. I can access my site fine at 127.0.0.1:8080.
The question & problem is, how do I configure Vagrant to pass the real clients IP address to Apache+Flask?
request.remote_addr always returns 10.0.2.2 no matter what client is connecting from within my LAN.
For example the machine running Vagrants IP is 192.168.1.5. From a client i.e. another laptop on my LAN with IP of 192.168.1.7, would hit the site # 192.168.1.5:8080, but 192.168.1.7 is not the remote_addr in vagrant/flask+apache, its always 10.0.2.2
Thanks!
The most easy way to do that would be a bridged network. The VM will receive an IP address in your (outside) network, e.g. 192.168.1.10.
See https://docs.vagrantup.com/v2/networking/public_network.html on how to configure that.

Get an available IP address from DHCP server via bash script?

I have 3 servers A, B and C that already have IP addresses assigned by the DHCP server.
I wanted to request a fourth IP from the DHCP server that I can use as a floating IP between my service.
Is there a simple way to do this via python or bash/shell commands? Everything I've read is always talking about renewing the machines IP address not pooling another available IP.

Sending a http get request to a server with known public ip

I have a server running by using python's base http server. The host name used is '127.0.0.1' the local host, and the port number is set to 8000. I have the public ip address of the computer operating this server.
If I wanted to send a http get request to this from another computer, what would I type into my browser?
Sounds like you've got your server process running on the wrong interface. 127.0.0.1 is not a hostname but an IP address, specifically the local loopback address. It is not reachable from any other machine (unless something's gone tragically wrong with your network configuration).
You can run anything you like on the 127.0.0.1 interface, and no one else can directly connect to it from a remote machine. That's pretty much the point --- it's for testing programs that use the Internet Protocol, and (in recent years) for starting single-user servers without worrying about security. (Python 2's SimpleHTTPServer does this, as do some personal wikis, and I think iPython Notebook.)
The public address for the host running your Web server is a completely unrelated network interface, with its own hardware and its own port 8000. It doesn't know or care that you've got something listening on some other interface's port 8000, so it should refuse attempts to connect to that port.
Since you didn't post any code, I have no idea what you need to change to get your server running on the correct interface. Assuming you've more or less followed the example in the BaseHTTPServer.HTTPServer docs:
def run(
server_class=BaseHTTPServer.HTTPServer,
handler_class=BaseHTTPServer.BaseHTTPRequestHandler,
):
server_address = ('', 8000) # <----= Replace the string.
httpd = server_class(server_address, handler_class)
httpd.serve_forever()
That server_address tuple is a string containing the IP address ('1.2.101.202' or whatever), followed by an integer port number. So replace the string with your host machine's public-facing IP address.
Note that port 8000 is outside the reserved range (0 up to but not including 1024), so it's possible that some unrelated service is already using that port. (Numerous applications are already squatting port 8000.) If so, you'll just have to choose another port number. You can chose anything from 1024 up to but not including 65536, but as with 8000, someone else might already be using it.
Depending on your operating system and its security setup, you might not have permission to open a socket that listens on an arbitrary port number. If so, that's between you and your ISP or sysadmin.
http://yourip:port/func
yourip is your public ip.
port is 8080
func is your registered function.
and also make sure you port is opened

Categories

Resources