Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending raw IP Traffic with Python: Detect MTU

Tags:

python

ip

mtu

How can I implement a manual MTU discovery with Python?

From: https://networkengineering.stackexchange.com/a/28988/23983

Send a ping to a target, in my example, I'll use Google's DNS server (8.8.8.8). Set your DF bit in your ping to on, to prevent your ping from being fragmented. Set your packet size to some large number, or the standard MTU of 1500. Note that some ping implementations set the size of just the payload, which means you have to account for the 8 byte ICMP header, and 20 byte IP header.

like image 616
guettli Avatar asked Apr 04 '16 11:04

guettli


2 Answers

I'd like to add that you could to this with raw sockets as well.
scapy is a nice abstraction layer that does much of the magic for you, but in all fairness if you're going to go low you could go all the way for the learning experience. (Note that raw sockets require elevated permissions in most modern OS'es, and as you go deeper implementations may vary from Windows and Linux.)

import socket
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003))

This will give you a raw packet based socket that literally delivers all the frames for you. It varies a bit between Windows and Linux but I'll stick to Linux in this answer. Also note that all outgoing packets might not get picked up by this socket, if you need that functionality (sniffing stuff) consider searching for promiscuous mode related hits.

All you need to do now is treat each packet as the segments they come or go in, for instance - unpacking a ethernet and IP frame would look something like this:

frame, meta = s.recvfrom(65565)
print(frame, meta)

ethernet = frame[0:14]
ethernet_segments = struct.unpack("!6s6s2s", ethernet)

mac_source, mac_dest = (binascii.hexlify(mac) for mac in ethernet_segments[:2])

ip = frame[14:34]
ip_segments = struct.unpack("!12s4s4s", ip)

ip_source, ip_dest = (socket.inet_ntoa(section) for section in ip_segments[1:3])

print('MAC Source:', b':'.join(mac_source[i:i+2] for i in range(0, len(mac_source), 2)))
print('MAC Dest:', b':'.join(mac_dest[i:i+2] for i in range(0, len(mac_dest), 2)))
print('IP Source:', ip_source)
print('IP Dest:', ip_dest)

Payloading would be "easy", considering you're building the packets yourself.
All be it not the most conventional of ways or the initially fastest way, but you'd be able to implement whatever you wanted.

Sending is just as easy, use struct and have a look at the many ICMP examples out there, including those with checksum calculations:

  • https://www.g-loaded.eu/2009/10/30/python-ping/
  • https://gist.github.com/pklaus/856268

Regarding MTU, this is logic you'd have to implement yourself because there's no pre-built library that does this that I'm aware of.

But this is my contribution to sending raw IP traffic with Python.

like image 110
Torxed Avatar answered Sep 20 '22 11:09

Torxed


Sending anything raw in python, you are looking at using at using scapy.

For info on how to send ping messages:

http://www.secdev.org/projects/scapy/doc/usage.html#icmp-ping

To set the DF Flag:

IP(flags='DF')

For how to adjust the particular size so that you can simulate fragmentation:

Adding payload in packet (scapy)

Putting it all together:

data = "x" * 1473
ans,unans = sr(IP(dst="<target_ip>", flags='DF' )/ICMP() / Raw(load=data))

If you aren't actually that interested in creating these things raw, this question is a dup of: How to find mtu value of network through code(in python)?

like image 24
Luke Exton Avatar answered Sep 23 '22 11:09

Luke Exton