-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdhcp6.py
1820 lines (1460 loc) · 69.8 KB
/
dhcp6.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# This file is part of Scapy
# See http://www.secdev.org/projects/scapy for more information
# Copyright (C) Philippe Biondi <[email protected]>
# This program is published under a GPLv2 license
# Copyright (C) 2005 Guillaume Valadon <[email protected]>
# Arnaud Ebalard <[email protected]>
"""
DHCPv6: Dynamic Host Configuration Protocol for IPv6. [RFC 3315]
"""
from __future__ import print_function
import socket
import struct
import time
from scapy.ansmachine import AnsweringMachine
from scapy.arch import get_if_raw_hwaddr, in6_getifaddr
from scapy.config import conf
from scapy.data import EPOCH, ETHER_ANY
from scapy.compat import raw, orb, chb
from scapy.error import warning
from scapy.fields import BitField, ByteEnumField, ByteField, FieldLenField, \
FlagsField, IntEnumField, IntField, MACField, PacketField, \
PacketListField, ShortEnumField, ShortField, StrField, StrFixedLenField, \
StrLenField, UTCTimeField, X3BytesField, XIntField, XShortEnumField, \
PacketLenField
from scapy.layers.inet import UDP
from scapy.layers.inet6 import DomainNameListField, IP6Field, IP6ListField, \
IPv6
from scapy.packet import Packet, bind_bottom_up
from scapy.pton_ntop import inet_pton
from scapy.sendrecv import send
from scapy.themes import Color
from scapy.utils6 import in6_addrtovendor, in6_islladdr
import scapy.modules.six as six
#############################################################################
# Helpers ##
#############################################################################
def get_cls(name, fallback_cls):
return globals().get(name, fallback_cls)
dhcp6_cls_by_type = {1: "DHCP6_Solicit",
2: "DHCP6_Advertise",
3: "DHCP6_Request",
4: "DHCP6_Confirm",
5: "DHCP6_Renew",
6: "DHCP6_Rebind",
7: "DHCP6_Reply",
8: "DHCP6_Release",
9: "DHCP6_Decline",
10: "DHCP6_Reconf",
11: "DHCP6_InfoRequest",
12: "DHCP6_RelayForward",
13: "DHCP6_RelayReply"}
def _dhcp6_dispatcher(x, *args, **kargs):
cls = conf.raw_layer
if len(x) >= 2:
cls = get_cls(dhcp6_cls_by_type.get(orb(x[0]), "Raw"), conf.raw_layer)
return cls(x, *args, **kargs)
#############################################################################
#############################################################################
# DHCPv6 #
#############################################################################
#############################################################################
All_DHCP_Relay_Agents_and_Servers = "ff02::1:2"
All_DHCP_Servers = "ff05::1:3" # Site-Local scope : deprecated by 3879
dhcp6opts = {1: "CLIENTID",
2: "SERVERID",
3: "IA_NA",
4: "IA_TA",
5: "IAADDR",
6: "ORO",
7: "PREFERENCE",
8: "ELAPSED_TIME",
9: "RELAY_MSG",
11: "AUTH",
12: "UNICAST",
13: "STATUS_CODE",
14: "RAPID_COMMIT",
15: "USER_CLASS",
16: "VENDOR_CLASS",
17: "VENDOR_OPTS",
18: "INTERFACE_ID",
19: "RECONF_MSG",
20: "RECONF_ACCEPT",
21: "SIP Servers Domain Name List", # RFC3319
22: "SIP Servers IPv6 Address List", # RFC3319
23: "DNS Recursive Name Server Option", # RFC3646
24: "Domain Search List option", # RFC3646
25: "OPTION_IA_PD", # RFC3633
26: "OPTION_IAPREFIX", # RFC3633
27: "OPTION_NIS_SERVERS", # RFC3898
28: "OPTION_NISP_SERVERS", # RFC3898
29: "OPTION_NIS_DOMAIN_NAME", # RFC3898
30: "OPTION_NISP_DOMAIN_NAME", # RFC3898
31: "OPTION_SNTP_SERVERS", # RFC4075
32: "OPTION_INFORMATION_REFRESH_TIME", # RFC4242
33: "OPTION_BCMCS_SERVER_D", # RFC4280
34: "OPTION_BCMCS_SERVER_A", # RFC4280
36: "OPTION_GEOCONF_CIVIC", # RFC-ietf-geopriv-dhcp-civil-09.txt
37: "OPTION_REMOTE_ID", # RFC4649
38: "OPTION_SUBSCRIBER_ID", # RFC4580
39: "OPTION_CLIENT_FQDN", # RFC4704
68: "OPTION_VSS", # RFC6607
79: "OPTION_CLIENT_LINKLAYER_ADDR"} # RFC6939
dhcp6opts_by_code = {1: "DHCP6OptClientId",
2: "DHCP6OptServerId",
3: "DHCP6OptIA_NA",
4: "DHCP6OptIA_TA",
5: "DHCP6OptIAAddress",
6: "DHCP6OptOptReq",
7: "DHCP6OptPref",
8: "DHCP6OptElapsedTime",
9: "DHCP6OptRelayMsg",
11: "DHCP6OptAuth",
12: "DHCP6OptServerUnicast",
13: "DHCP6OptStatusCode",
14: "DHCP6OptRapidCommit",
15: "DHCP6OptUserClass",
16: "DHCP6OptVendorClass",
17: "DHCP6OptVendorSpecificInfo",
18: "DHCP6OptIfaceId",
19: "DHCP6OptReconfMsg",
20: "DHCP6OptReconfAccept",
21: "DHCP6OptSIPDomains", # RFC3319
22: "DHCP6OptSIPServers", # RFC3319
23: "DHCP6OptDNSServers", # RFC3646
24: "DHCP6OptDNSDomains", # RFC3646
25: "DHCP6OptIA_PD", # RFC3633
26: "DHCP6OptIAPrefix", # RFC3633
27: "DHCP6OptNISServers", # RFC3898
28: "DHCP6OptNISPServers", # RFC3898
29: "DHCP6OptNISDomain", # RFC3898
30: "DHCP6OptNISPDomain", # RFC3898
31: "DHCP6OptSNTPServers", # RFC4075
32: "DHCP6OptInfoRefreshTime", # RFC4242
33: "DHCP6OptBCMCSDomains", # RFC4280
34: "DHCP6OptBCMCSServers", # RFC4280
# 36: "DHCP6OptGeoConf", #RFC-ietf-geopriv-dhcp-civil-09.txt # noqa: E501
37: "DHCP6OptRemoteID", # RFC4649
38: "DHCP6OptSubscriberID", # RFC4580
39: "DHCP6OptClientFQDN", # RFC4704
# 40: "DHCP6OptPANAAgent", #RFC-ietf-dhc-paa-option-05.txt # noqa: E501
# 41: "DHCP6OptNewPOSIXTimeZone, #RFC4833
# 42: "DHCP6OptNewTZDBTimeZone, #RFC4833
43: "DHCP6OptRelayAgentERO", # RFC4994
# 44: "DHCP6OptLQQuery", #RFC5007
# 45: "DHCP6OptLQClientData", #RFC5007
# 46: "DHCP6OptLQClientTime", #RFC5007
# 47: "DHCP6OptLQRelayData", #RFC5007
# 48: "DHCP6OptLQClientLink", #RFC5007
68: "DHCP6OptVSS", # RFC6607
79: "DHCP6OptClientLinkLayerAddr", # RFC6939
}
# sect 5.3 RFC 3315 : DHCP6 Messages types
dhcp6types = {1: "SOLICIT",
2: "ADVERTISE",
3: "REQUEST",
4: "CONFIRM",
5: "RENEW",
6: "REBIND",
7: "REPLY",
8: "RELEASE",
9: "DECLINE",
10: "RECONFIGURE",
11: "INFORMATION-REQUEST",
12: "RELAY-FORW",
13: "RELAY-REPL"}
#####################################################################
# DHCPv6 DUID related stuff #
#####################################################################
duidtypes = {1: "Link-layer address plus time",
2: "Vendor-assigned unique ID based on Enterprise Number",
3: "Link-layer Address",
4: "UUID"}
# DUID hardware types - RFC 826 - Extracted from
# http://www.iana.org/assignments/arp-parameters on 31/10/06
# We should add the length of every kind of address.
duidhwtypes = {0: "NET/ROM pseudo", # Not referenced by IANA
1: "Ethernet (10Mb)",
2: "Experimental Ethernet (3Mb)",
3: "Amateur Radio AX.25",
4: "Proteon ProNET Token Ring",
5: "Chaos",
6: "IEEE 802 Networks",
7: "ARCNET",
8: "Hyperchannel",
9: "Lanstar",
10: "Autonet Short Address",
11: "LocalTalk",
12: "LocalNet (IBM PCNet or SYTEK LocalNET)",
13: "Ultra link",
14: "SMDS",
15: "Frame Relay",
16: "Asynchronous Transmission Mode (ATM)",
17: "HDLC",
18: "Fibre Channel",
19: "Asynchronous Transmission Mode (ATM)",
20: "Serial Line",
21: "Asynchronous Transmission Mode (ATM)",
22: "MIL-STD-188-220",
23: "Metricom",
24: "IEEE 1394.1995",
25: "MAPOS",
26: "Twinaxial",
27: "EUI-64",
28: "HIPARP",
29: "IP and ARP over ISO 7816-3",
30: "ARPSec",
31: "IPsec tunnel",
32: "InfiniBand (TM)",
33: "TIA-102 Project 25 Common Air Interface (CAI)"}
class _UTCTimeField(UTCTimeField):
def __init__(self, *args, **kargs):
epoch_2000 = (2000, 1, 1, 0, 0, 0, 5, 1, 0) # required Epoch
UTCTimeField.__init__(self, epoch=epoch_2000, *args, **kargs)
class _LLAddrField(MACField):
pass
# XXX We only support Ethernet addresses at the moment. _LLAddrField
# will be modified when needed. Ask us. --arno
class DUID_LLT(Packet): # sect 9.2 RFC 3315
name = "DUID - Link-layer address plus time"
fields_desc = [ShortEnumField("type", 1, duidtypes),
XShortEnumField("hwtype", 1, duidhwtypes),
_UTCTimeField("timeval", 0), # i.e. 01 Jan 2000
_LLAddrField("lladdr", ETHER_ANY)]
# In fact, IANA enterprise-numbers file available at
# http://www.iana.org/assignments/enterprise-numbers
# is simply huge (more than 2Mo and 600Ko in bz2). I'll
# add only most common vendors, and encountered values.
# -- arno
iana_enterprise_num = {9: "ciscoSystems",
35: "Nortel Networks",
43: "3Com",
311: "Microsoft",
2636: "Juniper Networks, Inc.",
4526: "Netgear",
5771: "Cisco Systems, Inc.",
5842: "Cisco Systems",
16885: "Nortel Networks"}
class DUID_EN(Packet): # sect 9.3 RFC 3315
name = "DUID - Assigned by Vendor Based on Enterprise Number"
fields_desc = [ShortEnumField("type", 2, duidtypes),
IntEnumField("enterprisenum", 311, iana_enterprise_num),
StrField("id", "")]
class DUID_LL(Packet): # sect 9.4 RFC 3315
name = "DUID - Based on Link-layer Address"
fields_desc = [ShortEnumField("type", 3, duidtypes),
XShortEnumField("hwtype", 1, duidhwtypes),
_LLAddrField("lladdr", ETHER_ANY)]
class DUID_UUID(Packet): # RFC 6355
name = "DUID - Based on UUID"
fields_desc = [ShortEnumField("type", 4, duidtypes),
StrFixedLenField("uuid", "", 16)]
duid_cls = {1: "DUID_LLT",
2: "DUID_EN",
3: "DUID_LL",
4: "DUID_UUID"}
#####################################################################
# DHCPv6 Options classes #
#####################################################################
class _DHCP6OptGuessPayload(Packet):
def guess_payload_class(self, payload):
cls = conf.raw_layer
if len(payload) > 2:
opt = struct.unpack("!H", payload[:2])[0]
cls = get_cls(dhcp6opts_by_code.get(opt, "DHCP6OptUnknown"), DHCP6OptUnknown) # noqa: E501
return cls
class DHCP6OptUnknown(_DHCP6OptGuessPayload): # A generic DHCPv6 Option
name = "Unknown DHCPv6 Option"
fields_desc = [ShortEnumField("optcode", 0, dhcp6opts),
FieldLenField("optlen", None, length_of="data", fmt="!H"),
StrLenField("data", "",
length_from=lambda pkt: pkt.optlen)]
class _DUIDField(PacketField):
__slots__ = ["length_from"]
def __init__(self, name, default, length_from=None):
StrField.__init__(self, name, default)
self.length_from = length_from
def i2m(self, pkt, i):
return raw(i)
def m2i(self, pkt, x):
cls = conf.raw_layer
if len(x) > 4:
o = struct.unpack("!H", x[:2])[0]
cls = get_cls(duid_cls.get(o, conf.raw_layer), conf.raw_layer)
return cls(x)
def getfield(self, pkt, s):
tmp_len = self.length_from(pkt)
return s[tmp_len:], self.m2i(pkt, s[:tmp_len])
class DHCP6OptClientId(_DHCP6OptGuessPayload): # RFC sect 22.2
name = "DHCP6 Client Identifier Option"
fields_desc = [ShortEnumField("optcode", 1, dhcp6opts),
FieldLenField("optlen", None, length_of="duid", fmt="!H"),
_DUIDField("duid", "",
length_from=lambda pkt: pkt.optlen)]
class DHCP6OptServerId(DHCP6OptClientId): # RFC sect 22.3
name = "DHCP6 Server Identifier Option"
optcode = 2
# Should be encapsulated in the option field of IA_NA or IA_TA options
# Can only appear at that location.
# TODO : last field IAaddr-options is not defined in the reference document
class DHCP6OptIAAddress(_DHCP6OptGuessPayload): # RFC sect 22.6
name = "DHCP6 IA Address Option (IA_TA or IA_NA suboption)"
fields_desc = [ShortEnumField("optcode", 5, dhcp6opts),
FieldLenField("optlen", None, length_of="iaaddropts",
fmt="!H", adjust=lambda pkt, x: x + 24),
IP6Field("addr", "::"),
IntField("preflft", 0),
IntField("validlft", 0),
StrLenField("iaaddropts", "",
length_from=lambda pkt: pkt.optlen - 24)]
def guess_payload_class(self, payload):
return conf.padding_layer
class _IANAOptField(PacketListField):
def i2len(self, pkt, z):
if z is None or z == []:
return 0
return sum(len(raw(x)) for x in z)
def getfield(self, pkt, s):
tmp_len = self.length_from(pkt)
lst = []
remain, payl = s[:tmp_len], s[tmp_len:]
while len(remain) > 0:
p = self.m2i(pkt, remain)
if conf.padding_layer in p:
pad = p[conf.padding_layer]
remain = pad.load
del(pad.underlayer.payload)
else:
remain = ""
lst.append(p)
return payl, lst
class DHCP6OptIA_NA(_DHCP6OptGuessPayload): # RFC sect 22.4
name = "DHCP6 Identity Association for Non-temporary Addresses Option"
fields_desc = [ShortEnumField("optcode", 3, dhcp6opts),
FieldLenField("optlen", None, length_of="ianaopts",
fmt="!H", adjust=lambda pkt, x: x + 12),
XIntField("iaid", None),
IntField("T1", None),
IntField("T2", None),
_IANAOptField("ianaopts", [], DHCP6OptIAAddress,
length_from=lambda pkt: pkt.optlen - 12)]
class _IATAOptField(_IANAOptField):
pass
class DHCP6OptIA_TA(_DHCP6OptGuessPayload): # RFC sect 22.5
name = "DHCP6 Identity Association for Temporary Addresses Option"
fields_desc = [ShortEnumField("optcode", 4, dhcp6opts),
FieldLenField("optlen", None, length_of="iataopts",
fmt="!H", adjust=lambda pkt, x: x + 4),
XIntField("iaid", None),
_IATAOptField("iataopts", [], DHCP6OptIAAddress,
length_from=lambda pkt: pkt.optlen - 4)]
# DHCPv6 Option Request Option #
class _OptReqListField(StrLenField):
islist = 1
def i2h(self, pkt, x):
if x is None:
return []
return x
def i2len(self, pkt, x):
return 2 * len(x)
def any2i(self, pkt, x):
return x
def i2repr(self, pkt, x):
s = []
for y in self.i2h(pkt, x):
if y in dhcp6opts:
s.append(dhcp6opts[y])
else:
s.append("%d" % y)
return "[%s]" % ", ".join(s)
def m2i(self, pkt, x):
r = []
while len(x) != 0:
if len(x) < 2:
warning("Odd length for requested option field. Rejecting last byte") # noqa: E501
return r
r.append(struct.unpack("!H", x[:2])[0])
x = x[2:]
return r
def i2m(self, pkt, x):
return b"".join(struct.pack('!H', y) for y in x)
# A client may include an ORO in a solicit, Request, Renew, Rebind,
# Confirm or Information-request
class DHCP6OptOptReq(_DHCP6OptGuessPayload): # RFC sect 22.7
name = "DHCP6 Option Request Option"
fields_desc = [ShortEnumField("optcode", 6, dhcp6opts),
FieldLenField("optlen", None, length_of="reqopts", fmt="!H"), # noqa: E501
_OptReqListField("reqopts", [23, 24],
length_from=lambda pkt: pkt.optlen)]
# DHCPv6 Preference Option #
# emise par un serveur pour affecter le choix fait par le client. Dans
# les messages Advertise, a priori
class DHCP6OptPref(_DHCP6OptGuessPayload): # RFC sect 22.8
name = "DHCP6 Preference Option"
fields_desc = [ShortEnumField("optcode", 7, dhcp6opts),
ShortField("optlen", 1),
ByteField("prefval", 255)]
# DHCPv6 Elapsed Time Option #
class _ElapsedTimeField(ShortField):
def i2repr(self, pkt, x):
if x == 0xffff:
return "infinity (0xffff)"
return "%.2f sec" % (self.i2h(pkt, x) / 100.)
class DHCP6OptElapsedTime(_DHCP6OptGuessPayload): # RFC sect 22.9
name = "DHCP6 Elapsed Time Option"
fields_desc = [ShortEnumField("optcode", 8, dhcp6opts),
ShortField("optlen", 2),
_ElapsedTimeField("elapsedtime", 0)]
# DHCPv6 Authentication Option #
# The following fields are set in an Authentication option for the
# Reconfigure Key Authentication Protocol:
#
# protocol 3
#
# algorithm 1
#
# RDM 0
#
# The format of the Authentication information for the Reconfigure Key
# Authentication Protocol is:
#
# 0 1 2 3
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# | Type | Value (128 bits) |
# +-+-+-+-+-+-+-+-+ |
# . .
# . .
# . +-+-+-+-+-+-+-+-+
# | |
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
#
# Type Type of data in Value field carried in this option:
#
# 1 Reconfigure Key value (used in Reply message).
#
# 2 HMAC-MD5 digest of the message (used in Reconfigure
# message).
#
# Value Data as defined by field.
# TODO : Decoding only at the moment
class DHCP6OptAuth(_DHCP6OptGuessPayload): # RFC sect 22.11
name = "DHCP6 Option - Authentication"
fields_desc = [ShortEnumField("optcode", 11, dhcp6opts),
FieldLenField("optlen", None, length_of="authinfo",
adjust=lambda pkt, x: x + 11),
ByteField("proto", 3), # TODO : XXX
ByteField("alg", 1), # TODO : XXX
ByteField("rdm", 0), # TODO : XXX
StrFixedLenField("replay", "A" * 8, 8), # TODO: XXX
StrLenField("authinfo", "",
length_from=lambda pkt: pkt.optlen - 11)]
# DHCPv6 Server Unicast Option #
class _SrvAddrField(IP6Field):
def i2h(self, pkt, x):
if x is None:
return "::"
return x
def i2m(self, pkt, x):
return inet_pton(socket.AF_INET6, self.i2h(pkt, x))
class DHCP6OptServerUnicast(_DHCP6OptGuessPayload): # RFC sect 22.12
name = "DHCP6 Server Unicast Option"
fields_desc = [ShortEnumField("optcode", 12, dhcp6opts),
ShortField("optlen", 16),
_SrvAddrField("srvaddr", None)]
# DHCPv6 Status Code Option #
dhcp6statuscodes = {0: "Success", # sect 24.4
1: "UnspecFail",
2: "NoAddrsAvail",
3: "NoBinding",
4: "NotOnLink",
5: "UseMulticast",
6: "NoPrefixAvail"} # From RFC3633
class DHCP6OptStatusCode(_DHCP6OptGuessPayload): # RFC sect 22.13
name = "DHCP6 Status Code Option"
fields_desc = [ShortEnumField("optcode", 13, dhcp6opts),
FieldLenField("optlen", None, length_of="statusmsg",
fmt="!H", adjust=lambda pkt, x:x + 2),
ShortEnumField("statuscode", None, dhcp6statuscodes),
StrLenField("statusmsg", "",
length_from=lambda pkt: pkt.optlen - 2)]
# DHCPv6 Rapid Commit Option #
class DHCP6OptRapidCommit(_DHCP6OptGuessPayload): # RFC sect 22.14
name = "DHCP6 Rapid Commit Option"
fields_desc = [ShortEnumField("optcode", 14, dhcp6opts),
ShortField("optlen", 0)]
# DHCPv6 User Class Option #
class _UserClassDataField(PacketListField):
def i2len(self, pkt, z):
if z is None or z == []:
return 0
return sum(len(raw(x)) for x in z)
def getfield(self, pkt, s):
tmp_len = self.length_from(pkt)
lst = []
remain, payl = s[:tmp_len], s[tmp_len:]
while len(remain) > 0:
p = self.m2i(pkt, remain)
if conf.padding_layer in p:
pad = p[conf.padding_layer]
remain = pad.load
del(pad.underlayer.payload)
else:
remain = ""
lst.append(p)
return payl, lst
class USER_CLASS_DATA(Packet):
name = "user class data"
fields_desc = [FieldLenField("len", None, length_of="data"),
StrLenField("data", "",
length_from=lambda pkt: pkt.len)]
def guess_payload_class(self, payload):
return conf.padding_layer
class DHCP6OptUserClass(_DHCP6OptGuessPayload): # RFC sect 22.15
name = "DHCP6 User Class Option"
fields_desc = [ShortEnumField("optcode", 15, dhcp6opts),
FieldLenField("optlen", None, fmt="!H",
length_of="userclassdata"),
_UserClassDataField("userclassdata", [], USER_CLASS_DATA,
length_from=lambda pkt: pkt.optlen)]
# DHCPv6 Vendor Class Option #
class _VendorClassDataField(_UserClassDataField):
pass
class VENDOR_CLASS_DATA(USER_CLASS_DATA):
name = "vendor class data"
class DHCP6OptVendorClass(_DHCP6OptGuessPayload): # RFC sect 22.16
name = "DHCP6 Vendor Class Option"
fields_desc = [ShortEnumField("optcode", 16, dhcp6opts),
FieldLenField("optlen", None, length_of="vcdata", fmt="!H",
adjust=lambda pkt, x: x + 4),
IntEnumField("enterprisenum", None, iana_enterprise_num),
_VendorClassDataField("vcdata", [], VENDOR_CLASS_DATA,
length_from=lambda pkt: pkt.optlen - 4)] # noqa: E501
# DHCPv6 Vendor-Specific Information Option #
class VENDOR_SPECIFIC_OPTION(_DHCP6OptGuessPayload):
name = "vendor specific option data"
fields_desc = [ShortField("optcode", None),
FieldLenField("optlen", None, length_of="optdata"),
StrLenField("optdata", "",
length_from=lambda pkt: pkt.optlen)]
def guess_payload_class(self, payload):
return conf.padding_layer
# The third one that will be used for nothing interesting
class DHCP6OptVendorSpecificInfo(_DHCP6OptGuessPayload): # RFC sect 22.17
name = "DHCP6 Vendor-specific Information Option"
fields_desc = [ShortEnumField("optcode", 17, dhcp6opts),
FieldLenField("optlen", None, length_of="vso", fmt="!H",
adjust=lambda pkt, x: x + 4),
IntEnumField("enterprisenum", None, iana_enterprise_num),
_VendorClassDataField("vso", [], VENDOR_SPECIFIC_OPTION,
length_from=lambda pkt: pkt.optlen - 4)] # noqa: E501
# DHCPv6 Interface-ID Option #
# Repasser sur cette option a la fin. Elle a pas l'air d'etre des
# masses critique.
class DHCP6OptIfaceId(_DHCP6OptGuessPayload): # RFC sect 22.18
name = "DHCP6 Interface-Id Option"
fields_desc = [ShortEnumField("optcode", 18, dhcp6opts),
FieldLenField("optlen", None, fmt="!H",
length_of="ifaceid"),
StrLenField("ifaceid", "",
length_from=lambda pkt: pkt.optlen)]
# DHCPv6 Reconfigure Message Option #
# A server includes a Reconfigure Message option in a Reconfigure
# message to indicate to the client whether the client responds with a
# renew message or an Information-request message.
class DHCP6OptReconfMsg(_DHCP6OptGuessPayload): # RFC sect 22.19
name = "DHCP6 Reconfigure Message Option"
fields_desc = [ShortEnumField("optcode", 19, dhcp6opts),
ShortField("optlen", 1),
ByteEnumField("msgtype", 11, {5: "Renew Message",
11: "Information Request"})]
# DHCPv6 Reconfigure Accept Option #
# A client uses the Reconfigure Accept option to announce to the
# server whether the client is willing to accept Recoonfigure
# messages, and a server uses this option to tell the client whether
# or not to accept Reconfigure messages. The default behavior in the
# absence of this option, means unwillingness to accept reconfigure
# messages, or instruction not to accept Reconfigure messages, for the
# client and server messages, respectively.
class DHCP6OptReconfAccept(_DHCP6OptGuessPayload): # RFC sect 22.20
name = "DHCP6 Reconfigure Accept Option"
fields_desc = [ShortEnumField("optcode", 20, dhcp6opts),
ShortField("optlen", 0)]
class DHCP6OptSIPDomains(_DHCP6OptGuessPayload): # RFC3319
name = "DHCP6 Option - SIP Servers Domain Name List"
fields_desc = [ShortEnumField("optcode", 21, dhcp6opts),
FieldLenField("optlen", None, length_of="sipdomains"),
DomainNameListField("sipdomains", [],
length_from=lambda pkt: pkt.optlen)]
class DHCP6OptSIPServers(_DHCP6OptGuessPayload): # RFC3319
name = "DHCP6 Option - SIP Servers IPv6 Address List"
fields_desc = [ShortEnumField("optcode", 22, dhcp6opts),
FieldLenField("optlen", None, length_of="sipservers"),
IP6ListField("sipservers", [],
length_from=lambda pkt: pkt.optlen)]
class DHCP6OptDNSServers(_DHCP6OptGuessPayload): # RFC3646
name = "DHCP6 Option - DNS Recursive Name Server"
fields_desc = [ShortEnumField("optcode", 23, dhcp6opts),
FieldLenField("optlen", None, length_of="dnsservers"),
IP6ListField("dnsservers", [],
length_from=lambda pkt: pkt.optlen)]
class DHCP6OptDNSDomains(_DHCP6OptGuessPayload): # RFC3646
name = "DHCP6 Option - Domain Search List option"
fields_desc = [ShortEnumField("optcode", 24, dhcp6opts),
FieldLenField("optlen", None, length_of="dnsdomains"),
DomainNameListField("dnsdomains", [],
length_from=lambda pkt: pkt.optlen)]
# TODO: Implement iaprefopts correctly when provided with more
# information about it.
class DHCP6OptIAPrefix(_DHCP6OptGuessPayload): # RFC3633
name = "DHCP6 Option - IA_PD Prefix option"
fields_desc = [ShortEnumField("optcode", 26, dhcp6opts),
FieldLenField("optlen", None, length_of="iaprefopts",
adjust=lambda pkt, x: x + 25),
IntField("preflft", 0),
IntField("validlft", 0),
ByteField("plen", 48), # TODO: Challenge that default value
IP6Field("prefix", "2001:db8::"), # At least, global and won't hurt # noqa: E501
StrLenField("iaprefopts", "",
length_from=lambda pkt: pkt.optlen - 25)]
class DHCP6OptIA_PD(_DHCP6OptGuessPayload): # RFC3633
name = "DHCP6 Option - Identity Association for Prefix Delegation"
fields_desc = [ShortEnumField("optcode", 25, dhcp6opts),
FieldLenField("optlen", None, length_of="iapdopt",
adjust=lambda pkt, x: x + 12),
IntField("iaid", 0),
IntField("T1", 0),
IntField("T2", 0),
PacketListField("iapdopt", [], DHCP6OptIAPrefix,
length_from=lambda pkt: pkt.optlen - 12)]
class DHCP6OptNISServers(_DHCP6OptGuessPayload): # RFC3898
name = "DHCP6 Option - NIS Servers"
fields_desc = [ShortEnumField("optcode", 27, dhcp6opts),
FieldLenField("optlen", None, length_of="nisservers"),
IP6ListField("nisservers", [],
length_from=lambda pkt: pkt.optlen)]
class DHCP6OptNISPServers(_DHCP6OptGuessPayload): # RFC3898
name = "DHCP6 Option - NIS+ Servers"
fields_desc = [ShortEnumField("optcode", 28, dhcp6opts),
FieldLenField("optlen", None, length_of="nispservers"),
IP6ListField("nispservers", [],
length_from=lambda pkt: pkt.optlen)]
class DomainNameField(StrLenField):
def getfield(self, pkt, s):
tmp_len = self.length_from(pkt)
return s[tmp_len:], self.m2i(pkt, s[:tmp_len])
def i2len(self, pkt, x):
return len(self.i2m(pkt, x))
def m2i(self, pkt, x):
cur = []
while x:
tmp_len = orb(x[0])
cur.append(x[1:1 + tmp_len])
x = x[tmp_len + 1:]
return b".".join(cur)
def i2m(self, pkt, x):
if not x:
return b""
return b"".join(chb(len(z)) + z for z in x.split(b'.'))
class DHCP6OptNISDomain(_DHCP6OptGuessPayload): # RFC3898
name = "DHCP6 Option - NIS Domain Name"
fields_desc = [ShortEnumField("optcode", 29, dhcp6opts),
FieldLenField("optlen", None, length_of="nisdomain"),
DomainNameField("nisdomain", "",
length_from=lambda pkt: pkt.optlen)]
class DHCP6OptNISPDomain(_DHCP6OptGuessPayload): # RFC3898
name = "DHCP6 Option - NIS+ Domain Name"
fields_desc = [ShortEnumField("optcode", 30, dhcp6opts),
FieldLenField("optlen", None, length_of="nispdomain"),
DomainNameField("nispdomain", "",
length_from=lambda pkt: pkt.optlen)]
class DHCP6OptSNTPServers(_DHCP6OptGuessPayload): # RFC4075
name = "DHCP6 option - SNTP Servers"
fields_desc = [ShortEnumField("optcode", 31, dhcp6opts),
FieldLenField("optlen", None, length_of="sntpservers"),
IP6ListField("sntpservers", [],
length_from=lambda pkt: pkt.optlen)]
IRT_DEFAULT = 86400
IRT_MINIMUM = 600
class DHCP6OptInfoRefreshTime(_DHCP6OptGuessPayload): # RFC4242
name = "DHCP6 Option - Information Refresh Time"
fields_desc = [ShortEnumField("optcode", 32, dhcp6opts),
ShortField("optlen", 4),
IntField("reftime", IRT_DEFAULT)] # One day
class DHCP6OptBCMCSDomains(_DHCP6OptGuessPayload): # RFC4280
name = "DHCP6 Option - BCMCS Domain Name List"
fields_desc = [ShortEnumField("optcode", 33, dhcp6opts),
FieldLenField("optlen", None, length_of="bcmcsdomains"),
DomainNameListField("bcmcsdomains", [],
length_from=lambda pkt: pkt.optlen)]
class DHCP6OptBCMCSServers(_DHCP6OptGuessPayload): # RFC4280
name = "DHCP6 Option - BCMCS Addresses List"
fields_desc = [ShortEnumField("optcode", 34, dhcp6opts),
FieldLenField("optlen", None, length_of="bcmcsservers"),
IP6ListField("bcmcsservers", [],
length_from=lambda pkt: pkt.optlen)]
# TODO : Does Nothing at the moment
class DHCP6OptGeoConf(_DHCP6OptGuessPayload): # RFC-ietf-geopriv-dhcp-civil-09.txt # noqa: E501
name = ""
fields_desc = [ShortEnumField("optcode", 36, dhcp6opts),
FieldLenField("optlen", None, length_of="optdata"),
StrLenField("optdata", "",
length_from=lambda pkt: pkt.optlen)]
# TODO: see if we encounter opaque values from vendor devices
class DHCP6OptRemoteID(_DHCP6OptGuessPayload): # RFC4649
name = "DHCP6 Option - Relay Agent Remote-ID"
fields_desc = [ShortEnumField("optcode", 37, dhcp6opts),
FieldLenField("optlen", None, length_of="remoteid",
adjust=lambda pkt, x: x + 4),
IntEnumField("enterprisenum", None, iana_enterprise_num),
StrLenField("remoteid", "",
length_from=lambda pkt: pkt.optlen - 4)]
# TODO : 'subscriberid' default value should be at least 1 byte long
class DHCP6OptSubscriberID(_DHCP6OptGuessPayload): # RFC4580
name = "DHCP6 Option - Subscriber ID"
fields_desc = [ShortEnumField("optcode", 38, dhcp6opts),
FieldLenField("optlen", None, length_of="subscriberid"),
StrLenField("subscriberid", "",
length_from=lambda pkt: pkt.optlen)]
# TODO : "The data in the Domain Name field MUST be encoded
# as described in Section 8 of [5]"
class DHCP6OptClientFQDN(_DHCP6OptGuessPayload): # RFC4704
name = "DHCP6 Option - Client FQDN"
fields_desc = [ShortEnumField("optcode", 39, dhcp6opts),
FieldLenField("optlen", None, length_of="fqdn",
adjust=lambda pkt, x: x + 1),
BitField("res", 0, 5),
FlagsField("flags", 0, 3, "SON"),
DomainNameField("fqdn", "",
length_from=lambda pkt: pkt.optlen - 1)]
class DHCP6OptRelayAgentERO(_DHCP6OptGuessPayload): # RFC4994
name = "DHCP6 Option - RelayRequest Option"
fields_desc = [ShortEnumField("optcode", 43, dhcp6opts),
FieldLenField("optlen", None, length_of="reqopts", fmt="!H"), # noqa: E501
_OptReqListField("reqopts", [23, 24],
length_from=lambda pkt: pkt.optlen)]
# "Client link-layer address type. The link-layer type MUST be a valid hardware # noqa: E501
# type assigned by the IANA, as described in [RFC0826]
class DHCP6OptClientLinkLayerAddr(_DHCP6OptGuessPayload): # RFC6939
name = "DHCP6 Option - Client Link Layer address"
fields_desc = [ShortEnumField("optcode", 79, dhcp6opts),
FieldLenField("optlen", None, length_of="clladdr",
adjust=lambda pkt, x: x + 2),
ShortField("lltype", 1), # ethernet
_LLAddrField("clladdr", ETHER_ANY)]
# Virtual Subnet selection
class DHCP6OptVSS(_DHCP6OptGuessPayload): # RFC6607
name = "DHCP6 Option - Virtual Subnet Selection"
fields_desc = [ShortEnumField("optcode", 68, dhcp6opts),
FieldLenField("optlen", None, length_of="data",
adjust=lambda pkt, x: x + 1),
ByteField("type", 255), # Default Global/default table
StrLenField("data", "",
length_from=lambda pkt: pkt.optlen)]
#####################################################################
# DHCPv6 messages #
#####################################################################
# Some state parameters of the protocols that should probably be
# useful to have in the configuration (and keep up-to-date)
DHCP6RelayAgentUnicastAddr = ""
DHCP6RelayHopCount = ""
DHCP6ServerUnicastAddr = ""
DHCP6ClientUnicastAddr = ""
DHCP6ClientIA_TA = ""
DHCP6ClientIA_NA = ""
DHCP6ClientIAID = ""
T1 = "" # Voir 2462
T2 = "" # Voir 2462
DHCP6ServerDUID = ""
DHCP6CurrentTransactionID = "" # devrait etre utilise pour matcher une
# reponse et mis a jour en mode client par une valeur aleatoire pour
# laquelle on attend un retour de la part d'un serveur.
DHCP6PrefVal = "" # la valeur de preference a utiliser dans
# les options preference
# Emitted by :
# - server : ADVERTISE, REPLY, RECONFIGURE, RELAY-REPL (vers relay)
# - client : SOLICIT, REQUEST, CONFIRM, RENEW, REBIND, RELEASE, DECLINE,
# INFORMATION REQUEST
# - relay : RELAY-FORW (toward server)
#####################################################################
# DHCPv6 messages sent between Clients and Servers (types 1 to 11)
# Comme specifie en section 15.1 de la RFC 3315, les valeurs de
# transaction id sont selectionnees de maniere aleatoire par le client
# a chaque emission et doivent matcher dans les reponses faites par
# les clients
class DHCP6(_DHCP6OptGuessPayload):
name = "DHCPv6 Generic Message"
fields_desc = [ByteEnumField("msgtype", None, dhcp6types),
X3BytesField("trid", 0x000000)]
overload_fields = {UDP: {"sport": 546, "dport": 547}}
def hashret(self):
return struct.pack("!I", self.trid)[1:4]
# DHCPv6 Relay Message Option #
# Relayed message is seen as a payload.