backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / lib / packet / dhcp6.py
1 # Copyright (C) 2016 Bouygues Telecom.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #    http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12 # implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 """
17 DHCPv6 packet parser/serializer
18
19 [RFC 3315] DHCPv6 packet format:
20
21 The following diagram illustrates the format of DHCP messages sent
22 between clients and servers::
23
24      0                   1                   2                   3
25      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
26     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27     |    msg_type   |               transaction_id                  |
28     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29     |                                                               |
30     .                            options                            .
31     .                           (variable)                          .
32     |                                                               |
33     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34
35 There are two relay agent messages, which share the following format::
36
37      0                   1                   2                   3
38      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
39     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40     |    msg_type   |   hop_count   |                               |
41     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
42     |                                                               |
43     |                         link_address                          |
44     |                                                               |
45     |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
46     |                               |                               |
47     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
48     |                                                               |
49     |                         peer_address                          |
50     |                                                               |
51     |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-|
52     |                               |                               |
53     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
54     .                                                               .
55     .            options (variable number and length)   ....        .
56     |                                                               |
57     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58 """
59 import random
60 import struct
61
62 from . import packet_base
63 from ryu.lib import addrconv
64 from ryu.lib import stringify
65
66 # DHCPv6 message types
67 DHCPV6_SOLICIT = 1
68 DHCPV6_ADVERTISE = 2
69 DHCPV6_REQUEST = 3
70 DHCPV6_CONFIRM = 4
71 DHCPV6_RENEW = 5
72 DHCPV6_REBIND = 6
73 DHCPV6_REPLY = 7
74 DHCPV6_RELEASE = 8
75 DHCPV6_DECLINE = 9
76 DHCPV6_RECONFIGURE = 10
77 DHCPV6_INFORMATION_REQUEST = 11
78 DHCPV6_RELAY_FORW = 12
79 DHCPV6_RELAY_REPL = 13
80
81 # DHCPv6 option-codes
82 DHCPV6_OPTION_CLIENTID = 1
83 DHCPV6_OPTION_SERVERID = 2
84 DHCPV6_OPTION_IA_NA = 3
85 DHCPV6_OPTION_IA_TA = 4
86 DHCPV6_OPTION_IAADDR = 5
87 DHCPV6_OPTION_ORO = 6
88 DHCPV6_OPTION_PREFERENCE = 7
89 DHCPV6_OPTION_ELAPSED_TIME = 8
90 DHCPV6_OPTION_RELAY_MSG = 9
91 DHCPV6_OPTION_AUTH = 11
92 DHCPV6_OPTION_UNICAST = 12
93 DHCPV6_OPTION_STATUS_CODE = 13
94 DHCPV6_OPTION_RAPID_COMMIT = 14
95 DHCPV6_OPTION_USER_CLASS = 15
96 DHCPV6_OPTION_VENDOR_CLASS = 16
97 DHCPV6_OPTION_VENDOR_OPTS = 17
98 DHCPV6_OPTION_INTERFACE_ID = 18
99 DHCPV6_OPTION_RECONF_MSG = 19
100 DHCPV6_OPTION_RECONF_ACCEPT = 20
101
102
103 class dhcp6(packet_base.PacketBase):
104     """DHCPv6 (RFC 3315) header encoder/decoder class.
105
106     The serialized packet would looks like the ones described
107     in the following sections.
108
109     * RFC 3315 DHCP packet format
110
111     An instance has the following attributes at least.
112     Most of them are same to the on-wire counterparts but in host byte order.
113     __init__ takes the corresponding args in this order.
114
115
116     ============== ====================
117     Attribute      Description
118     ============== ====================
119     msg_type       Identifies the DHCP message type
120     transaction_id For unrelayed messages only: the transaction ID for\
121                    this message exchange.
122     hop_count      For relayed messages only: number of relay agents that\
123                    have relayed this message.
124     link_address   For relayed messages only: a global or site-local address\
125                    that will be used by the server to identify the link on\
126                    which the client is located.
127     peer_address   For relayed messages only: the address of the client or\
128                    relay agent from which the message to be relayed was\
129                    received.
130     options        Options carried in this message
131     ============== ====================
132     """
133     _MIN_LEN = 8
134     _DHCPV6_UNPACK_STR = '!I'
135     _DHCPV6_RELAY_UNPACK_STR = '!H16s16s'
136     _DHCPV6_UNPACK_STR_LEN = struct.calcsize(_DHCPV6_UNPACK_STR)
137     _DHCPV6_RELAY_UNPACK_STR_LEN = struct.calcsize(_DHCPV6_RELAY_UNPACK_STR)
138     _DHCPV6_PACK_STR = '!I'
139     _DHCPV6_RELAY_PACK_STR = '!H16s16s'
140
141     def __init__(self, msg_type, options, transaction_id=None, hop_count=0,
142                  link_address='::', peer_address='::'):
143         super(dhcp6, self).__init__()
144         self.msg_type = msg_type
145         self.options = options
146         if transaction_id is None:
147             self.transaction_id = random.randint(0, 0xffffff)
148         else:
149             self.transaction_id = transaction_id
150         self.hop_count = hop_count
151         self.link_address = link_address
152         self.peer_address = peer_address
153
154     @classmethod
155     def parser(cls, buf):
156         (msg_type, ) = struct.unpack_from('!B', buf)
157
158         buf = b'\x00' + buf[1:]  # unpack xid as a 4-byte integer
159         if msg_type == DHCPV6_RELAY_FORW or msg_type == DHCPV6_RELAY_REPL:
160             (hop_count, link_address, peer_address) \
161                 = struct.unpack_from(cls._DHCPV6_RELAY_UNPACK_STR, buf)
162             length = struct.calcsize(cls._DHCPV6_RELAY_UNPACK_STR)
163         else:
164             (transaction_id, ) \
165                 = struct.unpack_from(cls._DHCPV6_UNPACK_STR, buf)
166             length = struct.calcsize(cls._DHCPV6_UNPACK_STR)
167
168         if len(buf) > length:
169             parse_opt = options.parser(buf[length:])
170             length += parse_opt.options_len
171             if msg_type == DHCPV6_RELAY_FORW or msg_type == DHCPV6_RELAY_REPL:
172                 return (cls(msg_type, parse_opt, 0, hop_count,
173                             addrconv.ipv6.bin_to_text(link_address),
174                             addrconv.ipv6.bin_to_text(peer_address)),
175                         None, buf[length:])
176             else:
177                 return (cls(msg_type, parse_opt, transaction_id),
178                         None, buf[length:])
179         else:
180             return None, None, buf
181
182     def serialize(self, payload=None, prev=None):
183         seri_opt = self.options.serialize()
184         if (self.msg_type == DHCPV6_RELAY_FORW or
185                 self.msg_type == DHCPV6_RELAY_REPL):
186             pack_str = '%s%ds' % (self._DHCPV6_RELAY_PACK_STR,
187                                   self.options.options_len)
188             buf = struct.pack(pack_str, self.hop_count,
189                               addrconv.ipv6.text_to_bin(self.link_address),
190                               addrconv.ipv6.text_to_bin(self.peer_address),
191                               seri_opt)
192         else:
193             pack_str = '%s%ds' % (self._DHCPV6_PACK_STR,
194                                   self.options.options_len)
195             buf = struct.pack(pack_str, self.transaction_id, seri_opt)
196         return struct.pack('!B', self.msg_type) + buf[1:]
197
198
199 class options(stringify.StringifyMixin):
200     """DHCP (RFC 3315) options encoder/decoder class.
201
202     This is used with ryu.lib.packet.dhcp6.dhcp6.
203     """
204
205     def __init__(self, option_list=None, options_len=0):
206         super(options, self).__init__()
207         if option_list is None:
208             self.option_list = []
209         else:
210             self.option_list = option_list
211         self.options_len = options_len
212
213     @classmethod
214     def parser(cls, buf):
215         opt_parse_list = []
216         offset = 0
217         while len(buf) > offset:
218             opt_buf = buf[offset:]
219             opt = option.parser(opt_buf)
220             opt_parse_list.append(opt)
221             offset += opt.length + 4
222         return cls(opt_parse_list, len(buf))
223
224     def serialize(self):
225         seri_opt = bytes()
226         for opt in self.option_list:
227             seri_opt += opt.serialize()
228         if self.options_len == 0:
229             self.options_len = len(seri_opt)
230         return seri_opt
231
232
233 class option(stringify.StringifyMixin):
234     """DHCP (RFC 3315) options encoder/decoder class.
235
236     This is used with ryu.lib.packet.dhcp6.dhcp6.options.
237
238     An instance has the following attributes at least.
239     Most of them are same to the on-wire counterparts but in host byte order.
240     __init__ takes the corresponding args in this order.
241
242     The format of DHCP options is::
243
244          0                   1                   2                   3
245          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
246         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
247         |          option-code          |           option-len          |
248         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
249         |                          option-data                          |
250         |                      (option-len octets)                      |
251         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
252
253     ============== ====================
254     Attribute      Description
255     ============== ====================
256     option-code    An unsigned integer identifying the specific option\
257                    type carried in this option.
258     option-len     An unsigned integer giving the length of the\
259                    option-data field in this option in octets.
260     option-data    The data for the option; the format of this data\
261                    depends on the definition of the option.
262     ============== ====================
263     """
264     _UNPACK_STR = '!H'
265     _UNPACK_STR_LEN = struct.calcsize(_UNPACK_STR)
266     _PACK_STR = '!HH%ds'
267
268     def __init__(self, code, data, length=0):
269         super(option, self).__init__()
270         self.code = code
271         self.data = data
272         self.length = length
273
274     @classmethod
275     def parser(cls, buf):
276         code = struct.unpack_from(cls._UNPACK_STR, buf)[0]
277         buf = buf[cls._UNPACK_STR_LEN:]
278         length = struct.unpack_from(cls._UNPACK_STR, buf)[0]
279         buf = buf[cls._UNPACK_STR_LEN:]
280         value_unpack_str = '%ds' % length
281         data = struct.unpack_from(value_unpack_str, buf)[0]
282         return cls(code, data, length)
283
284     def serialize(self):
285         if self.length == 0:
286             self.length = len(self.data)
287         options_pack_str = self._PACK_STR % self.length
288         return struct.pack(options_pack_str, self.code, self.length, self.data)