Skip to content

Commit 89a0771

Browse files
authored
Merge pull request #1088 from gpotter2/ipv6-fixes
SEND module fixes & Stuff
2 parents 1350ca2 + e5a285f commit 89a0771

6 files changed

Lines changed: 106 additions & 79 deletions

File tree

scapy/arch/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
SOLARIS, WINDOWS, BSD, IS_64BITS, LOOPBACK_NAME
1515
from scapy.error import *
1616
import scapy.config
17-
from scapy.pton_ntop import inet_pton
17+
from scapy.pton_ntop import inet_pton, inet_ntop
1818
from scapy.data import *
1919

2020
def str2mac(s):
@@ -25,7 +25,7 @@ def str2mac(s):
2525
from scapy.arch.bpf.core import get_if_raw_addr
2626

2727
def get_if_addr(iff):
28-
return socket.inet_ntoa(get_if_raw_addr(iff))
28+
return inet_ntop(socket.AF_INET, get_if_raw_addr(iff))
2929

3030
def get_if_hwaddr(iff):
3131
addrfamily, mac = get_if_raw_hwaddr(iff)

scapy/contrib/send.py

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -15,77 +15,67 @@
1515
# along with Scapy. If not, see <http://www.gnu.org/licenses/>.
1616

1717
## Copyright (C) 2009 Adline Stephane <adline.stephane@gmail.com>
18-
##
18+
## Copyright 2018 Gabriel Potter <gabriel@potter.fr>
1919

2020
# Partial support of RFC3971
21-
# scapy.contrib.description = SEND (ICMPv6)
21+
# scapy.contrib.description = Secure Neighbor Discovery (SEND) (ICMPv6)
2222
# scapy.contrib.status = loads
2323

2424
from __future__ import absolute_import
2525
import socket
2626

2727
from scapy.packet import *
2828
from scapy.fields import *
29-
from scapy.layers.inet6 import icmp6typescls, _ICMPv6NDGuessPayload, Net6
30-
31-
send_icmp6typescls = { 11: "ICMPv6NDOptCGA",
32-
12: "ICMPv6NDOptRsaSig",
33-
13: "ICMPv6NDOptTmstp",
34-
14: "ICMPv6NDOptNonce"
35-
}
36-
icmp6typescls.update(send_icmp6typescls)
37-
38-
class HashField(Field):
39-
def __init__(self, name, default):
40-
Field.__init__(self, name, default, "16s")
41-
def h2i(self, pkt, x):
42-
if isinstance(x, str):
43-
try:
44-
x = in6_ptop(x)
45-
except socket.error:
46-
x = Net6(x)
47-
elif isinstance(x, list):
48-
x = [Net6(e) for e in x]
49-
return x
50-
def i2m(self, pkt, x):
51-
return inet_pton(socket.AF_INET6, x)
52-
def m2i(self, pkt, x):
53-
return inet_ntop(socket.AF_INET6, x)
54-
def any2i(self, pkt, x):
55-
return self.h2i(pkt,x)
56-
def i2repr(self, pkt, x):
57-
return self.i2h(pkt, x) # No specific information to return
29+
from scapy.layers.x509 import X509_SubjectPublicKeyInfo
30+
from scapy.layers.inet6 import icmp6ndoptscls, _ICMPv6NDGuessPayload
5831

5932
class ICMPv6NDOptNonce(_ICMPv6NDGuessPayload, Packet):
6033
name = "ICMPv6NDOptNonce"
6134
fields_desc = [ ByteField("type",14),
62-
FieldLenField("len",None,length_of="data",fmt="B", adjust = lambda pkt,x: (x)/8),
63-
StrLenField("nonce","", length_from = lambda pkt: pkt.len*8-2) ]
35+
FieldLenField("len", None, length_of="nonce", fmt="B", adjust = lambda pkt,x: int(round((x+2)/8.))),
36+
StrLenField("nonce", "", length_from = lambda pkt: pkt.len*8-2) ]
6437

6538
class ICMPv6NDOptTmstp(_ICMPv6NDGuessPayload, Packet):
6639
name = "ICMPv6NDOptTmstp"
6740
fields_desc = [ ByteField("type",13),
68-
ByteField("len",2),
41+
ByteField("len", 2),
6942
BitField("reserved",0, 48),
70-
LongField("timestamp", None) ]
43+
UTCTimeField("timestamp", None) ]
7144

7245
class ICMPv6NDOptRsaSig(_ICMPv6NDGuessPayload, Packet):
7346
name = "ICMPv6NDOptRsaSig"
7447
fields_desc = [ ByteField("type",12),
75-
FieldLenField("len",None,length_of="data",fmt="B", adjust = lambda pkt,x: (x)/8),
48+
FieldLenField("len", None, length_of="signature_pad", fmt="B", adjust = lambda pkt,x: (x+20)//8),
7649
ShortField("reserved",0),
77-
HashField("key_hash",None),
50+
StrFixedLenField("key_hash", "", length=16),
7851
StrLenField("signature_pad", "", length_from = lambda pkt: pkt.len*8-20) ]
7952

53+
class CGA_Params(Packet):
54+
name = "CGA Parameters data structure"
55+
fields_desc = [ StrFixedLenField("modifier", RandBin(size=16), length=16),
56+
StrFixedLenField("subprefix", "", length=8),
57+
ByteField("cc", 0),
58+
PacketField("pubkey", X509_SubjectPublicKeyInfo(),
59+
X509_SubjectPublicKeyInfo) ]
60+
8061
class ICMPv6NDOptCGA(_ICMPv6NDGuessPayload, Packet):
8162
name = "ICMPv6NDOptCGA"
8263
fields_desc = [ ByteField("type",11),
83-
FieldLenField("len",None,length_of="data",fmt="B", adjust = lambda pkt,x: (x)/8),
84-
ByteField("padlength",0),
64+
FieldLenField("len", None, length_of="CGA_PARAMS", fmt="B", adjust = lambda pkt,x: (x+pkt.padlength+4)//8),
65+
FieldLenField("padlength", 0, length_of="padding", fmt="B"),
8566
ByteField("reserved",0),
86-
StrLenField("CGA_PARAMS", "", length_from = lambda pkt: pkt.len*8 - pkt.padlength - 4),
87-
StrLenField("padding", None, length_from = lambda pkt: pkt.padlength) ]
67+
PacketLenField("CGA_PARAMS", "", CGA_Params, length_from = lambda pkt: pkt.len*8 - pkt.padlength - 4),
68+
StrLenField("padding", "", length_from = lambda pkt: pkt.padlength) ]
69+
70+
def post_build(self, p, pay):
71+
l_ = len(self.CGA_PARAMS)
72+
l = -(4+l_) % 8 # Pad to 8 bytes
73+
p = p[:1] + chb((4+l_+l)//8) + chb(l) + p[3:4+l_] + b"\x00" * l + pay
74+
return p
8875

89-
if __name__ == "__main__":
90-
from scapy.all import *
91-
interact(mydict=globals(), mybanner="SEND add-on")
76+
send_icmp6ndoptscls = { 11: ICMPv6NDOptCGA,
77+
12: ICMPv6NDOptRsaSig,
78+
13: ICMPv6NDOptTmstp,
79+
14: ICMPv6NDOptNonce
80+
}
81+
icmp6ndoptscls.update(send_icmp6ndoptscls)

scapy/contrib/send.uts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
+ SEND (IPv6) tests
2+
3+
= ICMPv6NDOptRsaSig build and dissection
4+
5+
pkt = Ether()/IPv6()/ICMPv6ND_NS()/ICMPv6NDOptRsaSig(signature_pad = b"\x01" * 12)
6+
pkt = Ether(raw(pkt))
7+
8+
assert ICMPv6NDOptRsaSig in pkt
9+
assert pkt[ICMPv6NDOptRsaSig].signature_pad == b"\x01" * 12
10+
11+
= ICMPv6NDOptCGA build and dissection
12+
13+
pkt = Ether()/IPv6()/ICMPv6ND_NS()/ICMPv6NDOptCGA(CGA_PARAMS=CGA_Params())
14+
pkt = Ether(raw(pkt))
15+
16+
assert ICMPv6NDOptCGA in pkt
17+
assert isinstance(pkt[ICMPv6NDOptCGA].CGA_PARAMS.pubkey, X509_SubjectPublicKeyInfo)
18+
assert len(pkt) == 142
19+
20+
= ICMPv6NDOptTmstp build and dissection
21+
22+
pkt = Ether()/IPv6()/ICMPv6ND_NS()/ICMPv6NDOptTmstp(timestamp=int(time.mktime(time.gmtime())))
23+
pkt = Ether(raw(pkt))
24+
pkt.show()
25+
26+
assert ICMPv6NDOptTmstp in pkt
27+
assert pkt[ICMPv6NDOptTmstp].len == 2
28+
29+
= ICMPv6NDOptNonce build and dissection
30+
31+
pkt = Ether()/IPv6()/ICMPv6ND_NS()/ICMPv6NDOptNonce(nonce=b"\x31\x32\x33\x34\x35\x36")
32+
pkt = Ether(raw(pkt))
33+
34+
assert ICMPv6NDOptNonce in pkt
35+
assert raw(ICMPv6NDOptNonce(nonce=b"\x31\x32\x33\x34\x35\x36")) == b'\x0e\x01123456'

scapy/layers/inet6.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,6 @@
7575
# unused import, only to initialize conf.route6
7676
import scapy.route6
7777

78-
79-
#############################################################################
80-
# Helpers ##
81-
#############################################################################
82-
83-
def get_cls(name, fallback_cls):
84-
return globals().get(name, fallback_cls)
85-
86-
8778
##########################
8879
## Neighbor cache stuff ##
8980
##########################
@@ -403,13 +394,13 @@ def default_payload_class(self,p):
403394
if t == 130 and len(p) >= 28:
404395
# RFC 3810 - 8.1. Query Version Distinctions
405396
return ICMPv6MLQuery2
406-
return get_cls(icmp6typescls.get(t, "Raw"), "Raw")
397+
return icmp6typescls.get(t,Raw)
407398
return Raw
408399
elif self.nh == 135 and len(p) > 3: # Mobile IPv6
409400
return _mip6_mhtype2cls.get(orb(p[2]), MIP6MH_Generic)
410401
elif self.nh == 43 and orb(p[2]) == 4: # Segment Routing header
411402
return IPv6ExtHdrSegmentRouting
412-
return get_cls(ipv6nhcls.get(self.nh, "Raw"), "Raw")
403+
return ipv6nhcls.get(self.nh, Raw)
413404

414405
class IPv6(_IPv6GuessPayload, Packet, IPTools):
415406
name = "IPv6"
@@ -1747,10 +1738,10 @@ def extract_padding(self, s):
17471738
8: "ICMPv6NDOptHAInfo",
17481739
9: "ICMPv6NDOptSrcAddrList",
17491740
10: "ICMPv6NDOptTgtAddrList",
1750-
#11: Do Me,
1751-
#12: Do Me,
1752-
#13: Do Me,
1753-
#14: Do Me,
1741+
#11: ICMPv6NDOptCGA, RFC3971 - contrib/send.py
1742+
#12: ICMPv6NDOptRsaSig, RFC3971 - contrib/send.py
1743+
#13: ICMPv6NDOptTmstp, RFC3971 - contrib/send.py
1744+
#14: ICMPv6NDOptNonce, RFC3971 - contrib/send.py
17541745
#15: Do Me,
17551746
#16: Do Me,
17561747
17: "ICMPv6NDOptIPAddr",
@@ -1772,7 +1763,7 @@ class _ICMPv6NDGuessPayload:
17721763
name = "Dummy ND class that implements guess_payload_class()"
17731764
def guess_payload_class(self,p):
17741765
if len(p) > 1:
1775-
return get_cls(icmp6ndoptscls.get(orb(p[0]),"Raw"), "Raw") # s/Raw/ICMPv6NDOptUnknown/g ?
1766+
return icmp6ndoptscls.get(orb(p[0]), Raw) # s/Raw/ICMPv6NDOptUnknown/g ?
17761767

17771768

17781769
# Beginning of ICMPv6 Neighbor Discovery Options.
@@ -4006,6 +3997,20 @@ def ra_reply_callback(req, iface):
40063997
prn=lambda x: ra_reply_callback(x, iface),
40073998
iface=iface)
40083999

4000+
#############################################################################
4001+
# Pre-load classes ##
4002+
#############################################################################
4003+
4004+
def _get_cls(name):
4005+
return globals().get(name, Raw)
4006+
4007+
def _load_dict(d):
4008+
for k, v in d.items():
4009+
d[k] = _get_cls(v)
4010+
4011+
_load_dict(icmp6ndoptscls)
4012+
_load_dict(icmp6typescls)
4013+
_load_dict(ipv6nhcls)
40094014

40104015
#############################################################################
40114016
#############################################################################

scapy/volatile.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def next(self):
7070
__next__ = next
7171

7272

73-
class VolatileValue:
73+
class VolatileValue(object):
7474
def __repr__(self):
7575
return "<%s>" % self.__class__.__name__
7676
def __eq__(self, other):
@@ -266,36 +266,33 @@ def _fix(self):
266266
return random.choice(self._choice)
267267

268268
class RandString(RandField):
269-
def __init__(self, size=None, chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"):
269+
def __init__(self, size=None, chars=b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"):
270270
if size is None:
271271
size = RandNumExpo(0.01)
272272
self.size = size
273273
self.chars = chars
274274
def _fix(self):
275-
s = ""
275+
s = b""
276276
for _ in range(self.size):
277-
s += random.choice(self.chars)
277+
s += chb(random.choice(self.chars))
278278
return s
279+
def __str__(self):
280+
return plain_str(self._fix())
281+
def __bytes__(self):
282+
return raw(self._fix())
279283
def __mul__(self, n):
280284
return self._fix()*n
281285

282286
class RandBin(RandString):
283287
def __init__(self, size=None):
284-
RandString.__init__(self, size, "".join(map(chr, range(256))))
288+
super(RandBin, self).__init__(size=size, chars=b"".join(chb(c) for c in range(256)))
285289

286-
287-
class RandTermString(RandString):
290+
class RandTermString(RandBin):
288291
def __init__(self, size, term):
289-
RandString.__init__(self, size, "".join(map(chr, range(1,256))))
290-
self.term = term
292+
self.term = raw(term)
293+
super(RandTermString, self).__init__(size=size)
291294
def _fix(self):
292-
return RandString._fix(self)+self.term
293-
294-
def __str__(self):
295-
return str(self._fix())
296-
297-
def __bytes__(self):
298-
return raw(self._fix())
295+
return RandBin._fix(self)+self.term
299296

300297

301298
class RandIP(RandString):

test/regression.uts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9008,7 +9008,7 @@ assert(rss == ("CON:" if six.PY2 else "foo.exe:"))
90089008

90099009
random.seed(0x2807)
90109010
rts = RandTermString(4, "scapy")
9011-
assert(sane(raw(rts)) in ["...[scapy", "......scapy"])
9011+
assert(sane(raw(rts)) in ["...Zscapy", "$#..scapy"])
90129012

90139013

90149014
############

0 commit comments

Comments
 (0)