Ticket #119 (closed defect: fixed)

Opened 3 months ago

Last modified 2 months ago

FloatField.addfield() and FloatField.getfield() fails

Reported by: wam@cisco.com Assigned to: pbi
Priority: major Milestone:
Component: Scapy Version:
Keywords: FloatField addfield Cc:

Description

I was getting an exception trying to write a pcap of some packets that had successfully been read from a pcap file and dug into the problem a bit. The problem appears to be that FloatField inherits the addfield method from BitField. This causes problems when the packet needs to be written out.

A good repeat-by for the problem is:

>>> from scapy import *
>>> VERSION
'1.2.0.2'
>>> pkt = NTP(delay=2.0, ref='None', precision=250L, dispersion=2.0, leap=3L, version=4L, mode=3L, stratum=0L, poll=4L, recv='None', id='0.0.0.0', sent='Mon, 19 May 2008 23:17:02 +0000', orig='None')
>>> str(pkt)
------------------------------------------------------------
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/wam/lib/python/scapy.py", line 5405, in __str__
    return self.build()
  File "/home/wam/lib/python/scapy.py", line 5449, in build
    pkt = self.do_build()
  File "/home/wam/lib/python/scapy.py", line 5436, in do_build
    p = f.addfield(self, p, self.getfieldval(f.name))
  File "/home/wam/lib/python/scapy.py", line 4271, in addfield
    v |= val & ((1L<<self.size) - 1)
<type 'exceptions.TypeError'>: unsupported operand type(s) for &: 'float' and 'long'

The FloatField class has it's own getfield() method for pulling a apart 32 bit float on 16 bit boundaries from a standard BitField value. A similar routine probably needs to be written for addfield which is specific to FloatField. I'll try working up a fix for the problem, but it may take me time to come back up to speed on the internals of scapy.

Attachments

ntp-client-nat.pcap (130 bytes) - added by wam@cisco.com on 07/25/08 16:56:17.
Testcase packet demonstrating the problem.
scapy-FloatField.patch (1.0 kB) - added by wam@cisco.com on 07/25/08 22:26:56.
patch for this bug

Change History

07/25/08 05:56:58 changed by wam@cisco.com

  • summary changed from FloatField.addfield() fails to FloatField.addfield() and FloatField.getfield() fails.

Looking into my problem a bit more, I came up with a patch, but in doing so I am pretty sure I found a bug in the getfield() method of the FloatField class as well.

In particular:

   def getfield(self, pkt, s):
        s,b = BitField.getfield(self, pkt, s)
        
        # fraction point between bits 15 and 16.
        sec = b >> 16
        frac = b & (1L << (32+1)) - 1
        frac /= 65536.0
        b = sec+frac
        return s,b    

Notice, that the fractional portion of this value (e.g. the delay field of an NTP packet) should be the lower 16 bits of the value returned from BitField.getfield(); however, the fractional portion here is masking against a full 32 bits. This has the effect of doubling the integer portion of the floating point number. This isn't generally noticeable on things like NTP objects since the integer portions are generally fairly small; however, if you have a pcap with a timer of 1.0, the scapy routine will read it as 2.0 (basically, 'integer' portion gets pulled off correctly, but the 'fractional' portion also includes the integer portion, and when added the timer is doubled.

Tomorrow I'll try do more testing of my fix, and will attach a patch when I'm happy that both routines are behaving properly.

07/25/08 16:55:16 changed by wam@cisco.com

Ok, as promised, I am attaching a pcap with an NTP packet that demonstrates the problem with FloatField?.getfield(). Wireshark shows:

 $ tshark  -r  ntp-client-nat.pcap  -V | sed -ne '/Network Time Protocol/,$ p'
Network Time Protocol
    Flags: 0xe3
        11.. .... = Leap Indicator: alarm condition (clock not synchronized) (3)
        ..10 0... = Version number: NTP Version 4 (4)
        .... .011 = Mode: client (3)
    Peer Clock Stratum: unspecified or unavailable (0)
    Peer Polling Interval: 4 (16 sec)
    Peer Clock Precision: 0.015625 sec
    Root Delay:    1.0000 sec
    Root Dispersion:    1.0000 sec
    Reference Clock ID: NULL
    Reference Clock Update Time: NULL
    Originate Time Stamp: NULL
    Receive Time Stamp: NULL
    Transmit Time Stamp: May 19, 2008 23:17:02.0550 UTC

The same packet when read by scapy (latest version from the main repository) shows:

>>> packet = scapy.rdpcap("ntp-client-nat.pcap")[0]
>>> packet.getlayer(scapy.NTP).show()
###[ NTP ]###
  leap= notsync
  version= 4L
  mode= client
  stratum= 0L
  poll= 4L
  precision= 250L
  delay= 2.0
  dispersion= 2.0
  id= 0.0.0.0
  ref= 'None'
  orig= 'None'
  recv= 'None'
  sent= 'Mon, 19 May 2008 23:17:02 +0000'

Notice that the delay of the packet as reported by wireshark (and confirmed with manual inspection of the bytes) shows a delay of 1.0 and scapy is reporting 2.0.

07/25/08 16:56:17 changed by wam@cisco.com

  • attachment ntp-client-nat.pcap added.

Testcase packet demonstrating the problem.

07/25/08 22:25:50 changed by wam@cisco.com

Attaching a patch to fix the FloatField issue. With the patch applied, I the delay (and the dispersion) values are now correct.

>>> packet = scapy.rdpcap("ntp-client.pcap")[0]
>>> packet.getlayer(scapy.NTP).show()
###[ NTP ]###
  leap= notsync
  version= 4L
  mode= client
  stratum= 0L
  poll= 4L
  precision= 250L
  delay= 1.0
  dispersion= 1.0
  id= 0.0.0.0
  ref= 'None'
  orig= 'None'
  recv= 'None'
  sent= 'Mon, 19 May 2008 23:17:02 +0000'

I still can't write this packet out (e.g. try str(packet), but that's due to a bug in the TimeStampField?() definition which I'll be filing later on.

07/25/08 22:26:56 changed by wam@cisco.com

  • attachment scapy-FloatField.patch added.

patch for this bug

08/14/08 02:11:11 changed by pbi

  • status changed from new to closed.
  • resolution set to fixed.

Fixed in [665fbb6f809c]


Add/Change #119 (FloatField.addfield() and FloatField.getfield() fails)




Change Properties
Action