Skip to content

Commit e6bf2d4

Browse files
authored
[DHCPv6] add the NTP Server Option (#4113)
1 parent 06fc74b commit e6bf2d4

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed

scapy/layers/dhcp6.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ def _dhcp6_dispatcher(x, *args, **kargs):
116116
41: "OPTION_NEW_POSIX_TIMEZONE", # RFC4833
117117
42: "OPTION_NEW_TZDB_TIMEZONE", # RFC4833
118118
48: "OPTION_LQ_CLIENT_LINK", # RFC5007
119+
56: "OPTION_NTP_SERVER", # RFC5908
119120
59: "OPT_BOOTFILE_URL", # RFC5970
120121
60: "OPT_BOOTFILE_PARAM", # RFC5970
121122
61: "OPTION_CLIENT_ARCH_TYPE", # RFC5970
@@ -174,6 +175,7 @@ def _dhcp6_dispatcher(x, *args, **kargs):
174175
# 46: "DHCP6OptLQClientTime", #RFC5007
175176
# 47: "DHCP6OptLQRelayData", #RFC5007
176177
48: "DHCP6OptLQClientLink", # RFC5007
178+
56: "DHCP6OptNTPServer", # RFC5908
177179
59: "DHCP6OptBootFileUrl", # RFC5790
178180
60: "DHCP6OptBootFileParam", # RFC5970
179181
61: "DHCP6OptClientArchType", # RFC5970
@@ -961,6 +963,60 @@ class DHCP6OptLQClientLink(_DHCP6OptGuessPayload): # RFC5007
961963
length_from=lambda pkt: pkt.optlen)]
962964

963965

966+
class DHCP6NTPSubOptSrvAddr(Packet): # RFC5908 sect 4.1
967+
name = "DHCP6 NTP Server Address Suboption"
968+
fields_desc = [ShortField("optcode", 1),
969+
ShortField("optlen", 16),
970+
IP6Field("addr", "::")]
971+
972+
def extract_padding(self, s):
973+
return b"", s
974+
975+
976+
class DHCP6NTPSubOptMCAddr(Packet): # RFC5908 sect 4.2
977+
name = "DHCP6 NTP Multicast Address Suboption"
978+
fields_desc = [ShortField("optcode", 2),
979+
ShortField("optlen", 16),
980+
IP6Field("addr", "::")]
981+
982+
def extract_padding(self, s):
983+
return b"", s
984+
985+
986+
class DHCP6NTPSubOptSrvFQDN(Packet): # RFC5908 sect 4.3
987+
name = "DHCP6 NTP Server FQDN Suboption"
988+
fields_desc = [ShortField("optcode", 3),
989+
FieldLenField("optlen", None, length_of="fqdn"),
990+
DNSStrField("fqdn", "",
991+
length_from=lambda pkt: pkt.optlen)]
992+
993+
def extract_padding(self, s):
994+
return b"", s
995+
996+
997+
_ntp_subopts = {1: DHCP6NTPSubOptSrvAddr,
998+
2: DHCP6NTPSubOptMCAddr,
999+
3: DHCP6NTPSubOptSrvFQDN}
1000+
1001+
1002+
def _ntp_subopt_dispatcher(p, **kwargs):
1003+
cls = conf.raw_layer
1004+
if len(p) >= 2:
1005+
o = struct.unpack("!H", p[:2])[0]
1006+
cls = _ntp_subopts.get(o, conf.raw_layer)
1007+
return cls(p, **kwargs)
1008+
1009+
1010+
class DHCP6OptNTPServer(_DHCP6OptGuessPayload): # RFC5908
1011+
name = "DHCP6 NTP Server Option"
1012+
fields_desc = [ShortEnumField("optcode", 56, dhcp6opts),
1013+
FieldLenField("optlen", None, length_of="ntpserver",
1014+
fmt="!H"),
1015+
PacketListField("ntpserver", [],
1016+
_ntp_subopt_dispatcher,
1017+
length_from=lambda pkt: pkt.optlen)]
1018+
1019+
9641020
class DHCP6OptBootFileUrl(_DHCP6OptGuessPayload): # RFC5970
9651021
name = "DHCP6 Boot File URL Option"
9661022
fields_desc = [ShortEnumField("optcode", 59, dhcp6opts),

test/scapy/layers/dhcp6.uts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,81 @@ raw(DHCP6OptLQClientLink(linkaddress=["2001:db8::1", "2001:db8::2"])) == b'\x000
10541054
a = DHCP6OptLQClientLink(b'\x000\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02')
10551055
a.optcode == 48 and a.optlen == 32 and len(a.linkaddress) == 2 and a.linkaddress[0] == "2001:db8::1" and a.linkaddress[1] == "2001:db8::2"
10561056

1057+
1058+
############
1059+
############
1060+
+ Test DHCP6 Option - NTP Server
1061+
1062+
= DHCP6NTPSubOptSrvAddr - Basic dissection/instantiation
1063+
b = b'\x00\x01' + b'\x00\x10' + b'\x00' * 16
1064+
assert raw(DHCP6NTPSubOptSrvAddr()) == b
1065+
1066+
p = DHCP6NTPSubOptSrvAddr(b)
1067+
assert p.optcode == 1 and p.optlen == 16 and p.addr == '::'
1068+
1069+
= DHCP6NTPSubOptSrvAddr - Dissection/instantiation with specific values
1070+
b = b'\x00\x01' + b'\x00\x10' + b'\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'
1071+
assert raw(DHCP6NTPSubOptSrvAddr(addr='2001:db8::1')) == b
1072+
1073+
p = DHCP6NTPSubOptSrvAddr(b)
1074+
assert p.optcode == 1 and p.optlen == 16 and p.addr == '2001:db8::1'
1075+
1076+
= DHCP6NTPSubOptMCAddr - Basic dissection/instantiation
1077+
b = b'\x00\x02' + b'\x00\x10' + b'\x00' * 16
1078+
assert raw(DHCP6NTPSubOptMCAddr()) == b
1079+
1080+
p = DHCP6NTPSubOptMCAddr(b)
1081+
assert p.optcode == 2 and p.optlen == 16 and p.addr == '::'
1082+
1083+
= DHCP6NTPSubOptMCAddr - Dissection/instantiation with specific values
1084+
b = b'\x00\x02' + b'\x00\x10' + b'\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01'
1085+
assert raw(DHCP6NTPSubOptMCAddr(addr='ff02::101')) == b
1086+
1087+
p = DHCP6NTPSubOptMCAddr(b)
1088+
assert p.optcode == 2 and p.optlen == 16 and p.addr == 'ff02::101'
1089+
1090+
= DHCP6NTPSubOptSrvFQDN - Basic dissection/instantiation
1091+
b = b'\x00\x03' + b'\x00\x01' + b'\x00'
1092+
assert raw(DHCP6NTPSubOptSrvFQDN()) == b
1093+
1094+
p = DHCP6NTPSubOptSrvFQDN(b)
1095+
assert p.optcode == 3 and p.optlen == 1 and p.fqdn == b'.'
1096+
1097+
= DHCP6NTPSubOptSrvFQDN - Dissection/instantiation with specific values
1098+
b = b'\x00\x03' + b'\x00\x0d' + b'\x07example\x03com\x00'
1099+
assert raw(DHCP6NTPSubOptSrvFQDN(fqdn='example.com')) == b
1100+
1101+
p = DHCP6NTPSubOptSrvFQDN(b)
1102+
assert p.optcode == 3 and p.optlen == 13 and p.fqdn == b'example.com.'
1103+
1104+
= DHCP6OptNTPServer - Basic dissection/instantiation
1105+
b = b'\x00\x38' + b'\x00\x00'
1106+
assert raw(DHCP6OptNTPServer()) == b
1107+
1108+
p = DHCP6OptNTPServer(b)
1109+
assert p.optcode == 56 and p.optlen == 0 and p.ntpserver == []
1110+
1111+
= DHCP6OptNTPServer - Dissection/instantiation with specific values
1112+
srv_addr = b'\x00\x01' + b'\x00\x10' + b'\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'
1113+
mc_addr = b'\x00\x02' + b'\x00\x10' + b'\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01'
1114+
srv_fqdn = b'\x00\x03' + b'\x00\x0d' + b'\x07example\x03com\x00'
1115+
b = b'\x00\x38' + b'\x00\x39' + srv_addr + mc_addr + srv_fqdn
1116+
1117+
p = DHCP6OptNTPServer(
1118+
ntpserver=[DHCP6NTPSubOptSrvAddr(addr='2001:db8::1'),
1119+
DHCP6NTPSubOptMCAddr(addr='ff02::101'),
1120+
DHCP6NTPSubOptSrvFQDN(fqdn='example.com'),
1121+
]
1122+
)
1123+
assert raw(p) == b
1124+
1125+
p = DHCP6OptNTPServer(b)
1126+
assert p.optcode == 56 and p.optlen == 57 and len(p.ntpserver) == 3
1127+
assert p.ntpserver[0] == DHCP6NTPSubOptSrvAddr(srv_addr)
1128+
assert p.ntpserver[1] == DHCP6NTPSubOptMCAddr(mc_addr)
1129+
assert p.ntpserver[2] == DHCP6NTPSubOptSrvFQDN(srv_fqdn)
1130+
1131+
10571132
############
10581133
############
10591134
+ Test DHCP6 Option - Boot File URL

0 commit comments

Comments
 (0)