How to calculate a packet checksum without sending it?
Asked Answered
S

5

22

I'm using scapy, and I want to create a packet and calculate its' checksum without sending it. Is there a way to do it?

Thanks.

Shuman answered 10/5, 2011 at 16:37 Comment(0)
S
14

You need to delete the .chksum value from the packet after you create it; then call .show2()

>>> from scapy.layers.inet import IP
>>> from scapy.layers.inet import ICMP
>>> from scapy.layers.inet import TCP
>>> target = "10.9.8.7"
>>> ttl = 64
>>> id = 32711
>>> sport = 2927
>>> dport = 80
>>> pak = IP(dst=target, src = "100.99.98.97", ttl=ttl, flags="DF", id=id, len=1200, chksum = 0)/TCP(flags="S", sport=sport, dport=int(dport), options=[('Timestamp',(0,0))], chksum = 0)
>>> del pak[IP].chksum
>>> del pak[TCP].chksum
>>> pak.show2()
###[ IP ]###
  version   = 4L
  ihl       = 5L
  tos       = 0x0
  len       = 1200
  id        = 32711
  flags     = DF
  frag      = 0L
  ttl       = 64
  proto     = tcp
  chksum    = 0x9afd
  src       = 100.99.98.97
  dst       = 10.9.8.7
  \options   \
###[ TCP ]###
     sport     = 2927
     dport     = www
     seq       = 0
     ack       = 0
     dataofs   = 8L
     reserved  = 0L
     flags     = S
     window    = 8192
     chksum    = 0x2c0e
     urgptr    = 0
     options   = [('Timestamp', (0, 0)), ('EOL', None)]
>>>
Senate answered 20/5, 2011 at 3:51 Comment(5)
Thanks. I found another option- convert the packet to string, and re-create it using that string.Shuman
@Dima, thanks for the suggestion. I wanted to avoid show2() because all the output was unnecessary. Perhaps there should just be a recalc packet function.Boudreau
@Mr. Shickadance, you can easily silence stdout for a moment by reassigning it... i.e. stdout, null = sys.stdout, open('/dev/null', 'w'); sys.stdout = null. When you are done reassign again with sys.stdout = stdoutSenate
It seems that I've actually commented with a very similar solution. No silencing or anything...Egin
Is there a way I could just get the new chksum field instead of the whole show2() output?Mestas
E
44

I've also tried to avoid show2() because it print the packet. I've found in the source a better solution:

del packet.chksum
packet = packet.__class__(bytes(packet))

This code regenerate the packet with the correct checksum without any print and actually is what show2() run in the background before printing.

Egin answered 25/7, 2012 at 10:51 Comment(2)
Real and best answer, by far. Don’t try to extract data from a print, which may change over timeTonita
Great answer, thanks! just adding that the second line caused a significant and unexplained delay for me, but because I wanted to send the packets I just removed it, and in the send process recalculated the checksum itself. So I used del ret_packet.chksum and del ret_packet[UDP].chksum for UDPBiggs
S
14

You need to delete the .chksum value from the packet after you create it; then call .show2()

>>> from scapy.layers.inet import IP
>>> from scapy.layers.inet import ICMP
>>> from scapy.layers.inet import TCP
>>> target = "10.9.8.7"
>>> ttl = 64
>>> id = 32711
>>> sport = 2927
>>> dport = 80
>>> pak = IP(dst=target, src = "100.99.98.97", ttl=ttl, flags="DF", id=id, len=1200, chksum = 0)/TCP(flags="S", sport=sport, dport=int(dport), options=[('Timestamp',(0,0))], chksum = 0)
>>> del pak[IP].chksum
>>> del pak[TCP].chksum
>>> pak.show2()
###[ IP ]###
  version   = 4L
  ihl       = 5L
  tos       = 0x0
  len       = 1200
  id        = 32711
  flags     = DF
  frag      = 0L
  ttl       = 64
  proto     = tcp
  chksum    = 0x9afd
  src       = 100.99.98.97
  dst       = 10.9.8.7
  \options   \
###[ TCP ]###
     sport     = 2927
     dport     = www
     seq       = 0
     ack       = 0
     dataofs   = 8L
     reserved  = 0L
     flags     = S
     window    = 8192
     chksum    = 0x2c0e
     urgptr    = 0
     options   = [('Timestamp', (0, 0)), ('EOL', None)]
>>>
Senate answered 20/5, 2011 at 3:51 Comment(5)
Thanks. I found another option- convert the packet to string, and re-create it using that string.Shuman
@Dima, thanks for the suggestion. I wanted to avoid show2() because all the output was unnecessary. Perhaps there should just be a recalc packet function.Boudreau
@Mr. Shickadance, you can easily silence stdout for a moment by reassigning it... i.e. stdout, null = sys.stdout, open('/dev/null', 'w'); sys.stdout = null. When you are done reassign again with sys.stdout = stdoutSenate
It seems that I've actually commented with a very similar solution. No silencing or anything...Egin
Is there a way I could just get the new chksum field instead of the whole show2() output?Mestas
N
2

Add this patch to scapy/packet.py:

+    def checksum_silent(self):
+        """
+        Internal method that recalcs checksum without the annoying prints
+        **AFTER old checksums are deleted.**
+        """
+
+        for f in self.fields_desc:
+            if isinstance(f, ConditionalField) and not f._evalcond(self):
+                continue
+            fvalue = self.getfieldval(f.name)
+            if isinstance(fvalue, Packet) or (f.islist and f.holds_packets and type(fvalue) is list):
+                fvalue_gen = SetGen(fvalue,_iterpacket=0)
+                for fvalue in fvalue_gen:
+                    fvalue.checksum_silent()
+        if self.payload:
+            self.payload.checksum_silent()

Then instead of calling pkt.show2(), just call this function pkt.checksum_silent(). (Remember to first do del pkt[IP].chksum and del pkt[UDP].chksum, etc.) as shown in the previous answer.

This function should be faster and be silent. (There may be additional things to trim as well; I hacked this code together and only tested to make sure it was silent with correct checksum.)

Neonate answered 24/5, 2017 at 23:17 Comment(0)
V
0

Indeed, the show2() function calculates the checksum for you, but it also prints the contents of the packet once it is finished with its work. However, show2() has a helpful little parameter named dump. The source describes it as such:

:param dump: determine if it prints or returns the string value

So by setting dump=True, you can avoid the pesky output that the function provides by default, and still get the calculations that you want.

Vilify answered 10/7, 2018 at 14:24 Comment(1)
Don’t try to extract data from the print: it’s not a stable API at all and may be changed without further noticeTonita
L
0

You can also use packet.build() which returns raw bytes with correct checksum. Then convert the bytes to a packet.

>>> import scapy.all as sp
>>> packet = sp.IP(src='127.0.0.1', dst='8.8.8.8')
>>> packet
<IP  src=127.0.0.1 dst=8.8.8.8 |>
>>> sp.IP(packet.build())
<IP  version=4 ihl=5 tos=0x0 len=20 id=1 flags= frag=0 ttl=64 
proto=hopopt chksum=0xebd8 src=127.0.0.1 dst=8.8.8.8 |>
Liz answered 7/7, 2019 at 12:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.