secdev / scapy

Scapy: the Python-based interactive packet manipulation program & library.
https://scapy.net
GNU General Public License v2.0
10.75k stars 2.03k forks source link

sprintf IP.proto problem #1657

Closed b-x closed 6 years ago

b-x commented 6 years ago

Brief description

sprintf IP.proto does not always prints correct value, sometimes the value is not mapped to the string

Environment

How to reproduce

# b = bytes(IP(proto=6))
b = b'E\x00\x00\x14\x00\x01\x00\x00@\x06|\xe1\x7f\x00\x00\x01\x7f\x00\x00\x01'
assert IP(b).sprintf('%proto%') == 'tcp'

In 99% cases it passes but in remaining 1% I've got '6' instead of 'tcp'. I can reproduce it only on some servers, problem never happens on my laptop with Ubuntu.

gpotter2 commented 6 years ago

You’ll notice that when it fails, IP_PROTOS is empty (or missing tcp) This happen when /etc/protocols is not available or missing some entries

b-x commented 6 years ago

I've changed my test to check IP_PROTOS:

...
if ret != 'tcp':
            print(ret)
            print('all ' + str(IP_PROTOS))
            print('tcp ' + str(IP_PROTOS['tcp']))

and the result:

6
all </etc/protocols/ tcp vrrp udplite ipcomp ax_25 ipv6_frag manet ipencap ipv6_route mpls_in_ip vmtp ipv6_nonxt skip mobility_header st isis icmp dccp pup hip xtp rsvp ip eigrp ipv6 hopopt encap egp ospf rdp iso_tp4 ddp etherip wesp rohc gre xns_idp idrp esp ggp sctp ipip l2tp hmp igp pim rspf fc ah udp idpr_cmtp ipv6_opts igmp shim6 ipv6_icmp>
tcp 6

so the problem is somewhere else, or IP_PROTOS was empty during initialization of class IP

gpotter2 commented 6 years ago

sprintf is using the dictionary in [the_ip_packet].get_field("proto").i2s to convert the proto ID to its name. E.g:

>>> IP().get_field("proto").i2s
{0: 'ip',
 1: 'icmp',
 3: 'ggp',
 6: 'tcp',
 8: 'egp',
 12: 'pup',
 17: 'udp',
 20: 'hmp',
 22: 'xns_idp',
 27: 'rdp',
 41: 'ipv6',
 43: 'ipv6_route',
 44: 'ipv6_frag',
 50: 'esp',
 51: 'ah',
 58: 'ipv6_icmp',
 59: 'ipv6_nonxt',
 60: 'ipv6_opts',
 66: 'rvd'}

Are you sure that on the computer you are checking that IP_PROTOS is ok, you also have the wrong result ?

b-x commented 6 years ago

Weird... print(IP().get_field("proto").i2s) gives:

{0: 'ip', 1: 'icmp', 2: 'igmp', 3: 'ggp', 132: 'sctp', 133: 'fc', 135: 'mobility_header', 136: 'udplite', 137: 'mpls_in_ip', 138: 'manet', 139: 'hip', 12: 'pup', 141: 'wesp', 142: 'rohc', 17: 'udp', 20: 'hmp', 22: 'xns_idp', 4: 'ipencap', 27: 'rdp', 29: 'iso_tp4', 5: 'st', 33: 'dccp', 36: 'xtp', 37: 'ddp', 38: 'idpr_cmtp', 41: 'ipv6', 43: 'ipv6_route', 44: 'ipv6_frag', 45: 'idrp', 46: 'rsvp', 47: 'gre', 8: 'egp', 50: 'esp', 51: 'ah', 9: 'igp', 57: 'skip', 58: 'ipv6_icmp', 59: 'ipv6_nonxt', 60: 'ipv6_opts', 73: 'rspf', 81: 'vmtp', 88: 'eigrp', 89: 'ospf', 93: 'ax_25', 94: 'ipip', 97: 'etherip', 98: 'encap', 103: 'pim', 108: 'ipcomp', 112: 'vrrp', 140: 'shim6', 115: 'l2tp', 124: 'isis'}

(notice no 'tcp' entry) but there is 'tcp' entry in IP_PROTOS (printed in the same time one line earlier).

And this is not only about 'tcp', other protos disappears as well if I change my assert.

gpotter2 commented 6 years ago

Hmm, I'm sorry I can't replicate :/ Could you retry using the latest github version ? before we get into a deeper analysis

b-x commented 6 years ago

Complete testcase:

$ cat issue.py 
from scapy.all import *

# print(scapy.VERSION)
b = bytes(IP(proto=6))
ret = IP(b).sprintf('%proto%')
if ret != 'tcp':
    print(ret)
    sys.exit(1)

and the execute command: while PYTHONPATH=scapy_git python3 issue.py; do :; done

I can't reproduce it with the latest version from git, only with official 2.4.0 version.

guedou commented 6 years ago

I cannot reproduce either. Let's close this issue as it is fixed.