backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / lib / packet / bfd.py
1 # Copyright (C) 2014 Xinguard, Inc.
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 BFD Control packet parser/serializer
18
19 [RFC 5880] BFD Control packet format::
20
21     0                   1                   2                   3
22     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
23    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24    |Vers |  Diag   |Sta|P|F|C|A|D|M|  Detect Mult  |    Length     |
25    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
26    |                       My Discriminator                        |
27    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28    |                      Your Discriminator                       |
29    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30    |                    Desired Min TX Interval                    |
31    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32    |                   Required Min RX Interval                    |
33    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34    |                 Required Min Echo RX Interval                 |
35    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36
37 An optional Authentication Section MAY be present in the following
38 format of types:
39
40 1. Format of Simple Password Authentication Section::
41
42         0                   1                   2                   3
43         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
44        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45        |   Auth Type   |   Auth Len    |  Auth Key ID  |  Password...  |
46        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47        |                              ...                              |
48        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49
50 2. Format of Keyed MD5 and Meticulous Keyed MD5 Authentication Section::
51
52         0                   1                   2                   3
53         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
54        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55        |   Auth Type   |   Auth Len    |  Auth Key ID  |   Reserved    |
56        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57        |                        Sequence Number                        |
58        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59        |                      Auth Key/Digest...                       |
60        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61        |                              ...                              |
62        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63
64 3. Format of Keyed SHA1 and Meticulous Keyed SHA1 Authentication Section::
65
66         0                   1                   2                   3
67         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
68        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69        |   Auth Type   |   Auth Len    |  Auth Key ID  |   Reserved    |
70        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71        |                        Sequence Number                        |
72        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73        |                       Auth Key/Hash...                        |
74        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75        |                              ...                              |
76        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
77 """
78 import binascii
79 import hashlib
80 import random
81 import six
82 import struct
83
84 from . import packet_base
85 from ryu.lib import addrconv
86 from ryu.lib import stringify
87
88 BFD_STATE_ADMIN_DOWN = 0
89 BFD_STATE_DOWN = 1
90 BFD_STATE_INIT = 2
91 BFD_STATE_UP = 3
92
93 BFD_STATE_NAME = {0: "AdminDown",
94                   1: "Down",
95                   2: "Init",
96                   3: "Up"}
97
98 BFD_FLAG_POLL = 1 << 5
99 BFD_FLAG_FINAL = 1 << 4
100 BFD_FLAG_CTRL_PLANE_INDEP = 1 << 3
101 BFD_FLAG_AUTH_PRESENT = 1 << 2
102 BFD_FLAG_DEMAND = 1 << 1
103 BFD_FLAG_MULTIPOINT = 1
104
105 BFD_DIAG_NO_DIAG = 0
106 BFD_DIAG_CTRL_DETECT_TIME_EXPIRED = 1
107 BFD_DIAG_ECHO_FUNC_FAILED = 2
108 BFD_DIAG_NEIG_SIG_SESS_DOWN = 3
109 BFD_DIAG_FWD_PLANE_RESET = 4
110 BFD_DIAG_PATH_DOWN = 5
111 BFD_DIAG_CONCAT_PATH_DOWN = 6
112 BFD_DIAG_ADMIN_DOWN = 7
113 BFD_DIAG_REV_CONCAT_PATH_DOWN = 8
114
115 BFD_DIAG_CODE_NAME = {0: "No Diagnostic",
116                       1: "Control Detection Time Expired",
117                       2: "Echo Function Failed",
118                       3: "Neighbor Signaled Session Down",
119                       4: "Forwarding Plane Reset",
120                       5: "Path Down",
121                       6: "Concatenated Path Down",
122                       7: "Administratively Down",
123                       8: "Reverse Concatenated Path Down"}
124
125 BFD_AUTH_RESERVED = 0
126 BFD_AUTH_SIMPLE_PASS = 1
127 BFD_AUTH_KEYED_MD5 = 2
128 BFD_AUTH_METICULOUS_KEYED_MD5 = 3
129 BFD_AUTH_KEYED_SHA1 = 4
130 BFD_AUTH_METICULOUS_KEYED_SHA1 = 5
131
132 BFD_AUTH_TYPE_NAME = {0: "Reserved",
133                       1: "Simple Password",
134                       2: "Keyed MD5",
135                       3: "Meticulous Keyed MD5",
136                       4: "Keyed SHA1",
137                       5: "Meticulous Keyed SHA1"}
138
139
140 class bfd(packet_base.PacketBase):
141     """BFD (RFC 5880) Control packet encoder/decoder class.
142
143     The serialized packet would looks like the ones described
144     in the following sections.
145
146     * RFC 5880 Generic BFD Control Packet Format
147
148     An instance has the following attributes at least.
149     Most of them are same to the on-wire counterparts but in host byte order.
150
151     __init__ takes the corresponding args in this order.
152
153     .. tabularcolumns:: |l|L|
154
155     ============================== ============================================
156     Attribute                      Description
157     ============================== ============================================
158     ver                            The version number of the protocol.
159                                    This class implements protocol version 1.
160     diag                           A diagnostic code specifying the local
161                                    system's reason for the last change in
162                                    session state.
163     state                          The current BFD session state as seen by
164                                    the transmitting system.
165     flags                          Bitmap of the following flags.
166
167                                    | BFD_FLAG_POLL
168                                    | BFD_FLAG_FINAL
169                                    | BFD_FLAG_CTRL_PLANE_INDEP
170                                    | BFD_FLAG_AUTH_PRESENT
171                                    | BFD_FLAG_DEMAND
172                                    | BFD_FLAG_MULTIPOINT
173     detect_mult                    Detection time multiplier.
174     my_discr                       My Discriminator.
175     your_discr                     Your Discriminator.
176     desired_min_tx_interval        Desired Min TX Interval. (in microseconds)
177     required_min_rx_interval       Required Min RX Interval. (in microseconds)
178     required_min_echo_rx_interval  Required Min Echo RX Interval.
179                                    (in microseconds)
180     auth_cls                       (Optional) Authentication Section instance.
181                                    It's defined only when the Authentication
182                                    Present (A) bit is set in flags.
183                                    Assign an instance of the following classes:
184                                    ``SimplePassword``, ``KeyedMD5``,
185                                    ``MeticulousKeyedMD5``, ``KeyedSHA1``, and
186                                    ``MeticulousKeyedSHA1``.
187     length                         (Optional) Length of the BFD Control packet,
188                                    in bytes.
189     ============================== ============================================
190     """
191
192     _PACK_STR = '!BBBBIIIII'
193     _PACK_STR_LEN = struct.calcsize(_PACK_STR)
194
195     _TYPE = {
196         'ascii': []
197     }
198
199     _auth_parsers = {}
200
201     def __init__(self, ver=1, diag=0, state=0, flags=0, detect_mult=0,
202                  my_discr=0, your_discr=0, desired_min_tx_interval=0,
203                  required_min_rx_interval=0, required_min_echo_rx_interval=0,
204                  auth_cls=None, length=None):
205         super(bfd, self).__init__()
206
207         self.ver = ver
208         self.diag = diag
209         self.state = state
210         self.flags = flags
211         self.detect_mult = detect_mult
212         self.my_discr = my_discr
213         self.your_discr = your_discr
214         self.desired_min_tx_interval = desired_min_tx_interval
215         self.required_min_rx_interval = required_min_rx_interval
216         self.required_min_echo_rx_interval = required_min_echo_rx_interval
217         self.auth_cls = auth_cls
218         if isinstance(length, int):
219             self.length = length
220         else:
221             self.length = len(self)
222
223     def __len__(self):
224         if self.flags & BFD_FLAG_AUTH_PRESENT and self.auth_cls is not None:
225             return self._PACK_STR_LEN + len(self.auth_cls)
226         else:
227             return self._PACK_STR_LEN
228
229     @classmethod
230     def parser(cls, buf):
231         (diag, flags, detect_mult, length, my_discr, your_discr,
232          desired_min_tx_interval, required_min_rx_interval,
233          required_min_echo_rx_interval) = \
234             struct.unpack_from(cls._PACK_STR, buf[:cls._PACK_STR_LEN])
235
236         ver = diag >> 5
237         diag = diag & 0x1f
238         state = flags >> 6
239         flags = flags & 0x3f
240
241         if flags & BFD_FLAG_AUTH_PRESENT:
242             auth_type = six.indexbytes(buf, cls._PACK_STR_LEN)
243             auth_cls = cls._auth_parsers[auth_type].\
244                 parser(buf[cls._PACK_STR_LEN:])[0]
245         else:
246             auth_cls = None
247
248         msg = cls(ver, diag, state, flags, detect_mult,
249                   my_discr, your_discr, desired_min_tx_interval,
250                   required_min_rx_interval, required_min_echo_rx_interval,
251                   auth_cls)
252
253         return msg, None, None
254
255     def serialize(self, payload, prev):
256         if self.flags & BFD_FLAG_AUTH_PRESENT and self.auth_cls is not None:
257             return self.pack() + \
258                 self.auth_cls.serialize(payload=None, prev=self)
259         else:
260             return self.pack()
261
262     def pack(self):
263         """
264         Encode a BFD Control packet without authentication section.
265         """
266         diag = (self.ver << 5) + self.diag
267         flags = (self.state << 6) + self.flags
268         length = len(self)
269
270         return struct.pack(self._PACK_STR, diag, flags, self.detect_mult,
271                            length, self.my_discr, self.your_discr,
272                            self.desired_min_tx_interval,
273                            self.required_min_rx_interval,
274                            self.required_min_echo_rx_interval)
275
276     def authenticate(self, *args, **kwargs):
277         """Authenticate this packet.
278
279         Returns a boolean indicates whether the packet can be authenticated
280         or not.
281
282         Returns ``False`` if the Authentication Present (A) is not set in the
283         flag of this packet.
284
285         Returns ``False`` if the Authentication Section for this packet is not
286         present.
287
288         For the description of the arguemnts of this method, refer to the
289         authentication method of the Authentication Section classes.
290         """
291         if not self.flags & BFD_FLAG_AUTH_PRESENT or \
292                 not issubclass(self.auth_cls.__class__, BFDAuth):
293             return False
294
295         return self.auth_cls.authenticate(self, *args, **kwargs)
296
297     @classmethod
298     def set_auth_parser(cls, auth_cls):
299         cls._auth_parsers[auth_cls.auth_type] = auth_cls
300
301     @classmethod
302     def register_auth_type(cls, auth_type):
303         def _set_type(auth_cls):
304             auth_cls.set_type(auth_cls, auth_type)
305             cls.set_auth_parser(auth_cls)
306             return auth_cls
307         return _set_type
308
309
310 class BFDAuth(stringify.StringifyMixin):
311     """Base class of BFD (RFC 5880) Authentication Section
312
313     An instance has the following attributes at least.
314     Most of them are same to the on-wire counterparts but in host byte order.
315
316     .. tabularcolumns:: |l|L|
317
318     =========== ============================================
319     Attribute   Description
320     =========== ============================================
321     auth_type   The authentication type in use.
322     auth_len    The length, in bytes, of the authentication
323                 section, including the ``auth_type`` and
324                 ``auth_len`` fields.
325     =========== ============================================
326     """
327     _PACK_HDR_STR = '!BB'
328     _PACK_HDR_STR_LEN = struct.calcsize(_PACK_HDR_STR)
329
330     auth_type = None
331
332     def __init__(self, auth_len=None):
333         super(BFDAuth, self).__init__()
334         if isinstance(auth_len, int):
335             self.auth_len = auth_len
336         else:
337             self.auth_len = len(self)
338
339     @staticmethod
340     def set_type(subcls, auth_type):
341         assert issubclass(subcls, BFDAuth)
342         subcls.auth_type = auth_type
343
344     @classmethod
345     def parser_hdr(cls, buf):
346         """
347         Parser for common part of authentication section.
348         """
349         return struct.unpack_from(cls._PACK_HDR_STR,
350                                   buf[:cls._PACK_HDR_STR_LEN])
351
352     def serialize_hdr(self):
353         """
354         Serialization function for common part of authentication section.
355         """
356         return struct.pack(self._PACK_HDR_STR, self.auth_type, self.auth_len)
357
358
359 @bfd.register_auth_type(BFD_AUTH_SIMPLE_PASS)
360 class SimplePassword(BFDAuth):
361     """ BFD (RFC 5880) Simple Password Authentication Section class
362
363     An instance has the following attributes.
364     Most of them are same to the on-wire counterparts but in host byte order.
365
366     .. tabularcolumns:: |l|L|
367
368     =========== ============================================
369     Attribute   Description
370     =========== ============================================
371     auth_type   (Fixed) The authentication type in use.
372     auth_key_id The authentication Key ID in use.
373     password    The simple password in use on this session.
374                 The password is a binary string, and MUST be
375                 from 1 to 16 bytes in length.
376     auth_len    The length, in bytes, of the authentication
377                 section, including the ``auth_type`` and
378                 ``auth_len`` fields.
379     =========== ============================================
380     """
381     _PACK_STR = '!B'
382     _PACK_STR_LEN = struct.calcsize(_PACK_STR)
383
384     def __init__(self, auth_key_id, password, auth_len=None):
385         assert len(password) >= 1 and len(password) <= 16
386         self.auth_key_id = auth_key_id
387         self.password = password
388         super(SimplePassword, self).__init__(auth_len)
389
390     def __len__(self):
391         return self._PACK_HDR_STR_LEN + self._PACK_STR_LEN + len(self.password)
392
393     @classmethod
394     def parser(cls, buf):
395         (auth_type, auth_len) = cls.parser_hdr(buf)
396         assert auth_type == cls.auth_type
397
398         auth_key_id = six.indexbytes(buf, cls._PACK_HDR_STR_LEN)
399
400         password = buf[cls._PACK_HDR_STR_LEN + cls._PACK_STR_LEN:auth_len]
401
402         msg = cls(auth_key_id, password, auth_len)
403
404         return msg, None, None
405
406     def serialize(self, payload, prev):
407         """Encode a Simple Password Authentication Section.
408
409         ``payload`` is the rest of the packet which will immediately follow
410         this section.
411
412         ``prev`` is a ``bfd`` instance for the BFD Control header. It's not
413         necessary for encoding only the Simple Password section.
414         """
415         return self.serialize_hdr() + \
416             struct.pack(self._PACK_STR, self.auth_key_id) + self.password
417
418     def authenticate(self, prev=None, auth_keys=None):
419         """Authenticate the password for this packet.
420
421         This method can be invoked only when ``self.password`` is defined.
422
423         Returns a boolean indicates whether the password can be authenticated
424         or not.
425
426         ``prev`` is a ``bfd`` instance for the BFD Control header. It's not
427         necessary for authenticating the Simple Password.
428
429         ``auth_keys`` is a dictionary of authentication key chain which
430         key is an integer of *Auth Key ID* and value is a string of *Password*.
431         """
432         auth_keys = auth_keys if auth_keys else {}
433         assert isinstance(prev, bfd)
434         if self.auth_key_id in auth_keys and \
435                 self.password == auth_keys[self.auth_key_id]:
436             return True
437         else:
438             return False
439
440
441 @bfd.register_auth_type(BFD_AUTH_KEYED_MD5)
442 class KeyedMD5(BFDAuth):
443     """ BFD (RFC 5880) Keyed MD5 Authentication Section class
444
445     An instance has the following attributes.
446     Most of them are same to the on-wire counterparts but in host byte order.
447
448     .. tabularcolumns:: |l|L|
449
450     =========== =================================================
451     Attribute   Description
452     =========== =================================================
453     auth_type   (Fixed) The authentication type in use.
454     auth_key_id The authentication Key ID in use.
455     seq         The sequence number for this packet.
456                 This value is incremented occasionally.
457     auth_key    The shared MD5 key for this packet.
458     digest      (Optional) The 16-byte MD5 digest for the packet.
459     auth_len    (Fixed) The length of the authentication section
460                 is 24 bytes.
461     =========== =================================================
462     """
463     _PACK_STR = '!BBL16s'
464     _PACK_STR_LEN = struct.calcsize(_PACK_STR)
465
466     def __init__(self, auth_key_id, seq, auth_key=None, digest=None,
467                  auth_len=None):
468         self.auth_key_id = auth_key_id
469         self.seq = seq
470         self.auth_key = auth_key
471         self.digest = digest
472         super(KeyedMD5, self).__init__(auth_len)
473
474     def __len__(self):
475         # Defined in RFC5880 Section 4.3.
476         return 24
477
478     @classmethod
479     def parser(cls, buf):
480         (auth_type, auth_len) = cls.parser_hdr(buf)
481         assert auth_type == cls.auth_type
482         assert auth_len == 24
483
484         (auth_key_id, reserved, seq, digest) = \
485             struct.unpack_from(cls._PACK_STR, buf[cls._PACK_HDR_STR_LEN:])
486         assert reserved == 0
487
488         msg = cls(auth_key_id=auth_key_id, seq=seq, auth_key=None,
489                   digest=digest)
490
491         return msg, None, None
492
493     def serialize(self, payload, prev):
494         """Encode a Keyed MD5 Authentication Section.
495
496         This method is used only when encoding an BFD Control packet.
497
498         ``payload`` is the rest of the packet which will immediately follow
499         this section.
500
501         ``prev`` is a ``bfd`` instance for the BFD Control header which this
502         authentication section belongs to. It's necessary to be assigned
503         because an MD5 digest must be calculated over the entire BFD Control
504         packet.
505         """
506         assert self.auth_key is not None and len(self.auth_key) <= 16
507         assert isinstance(prev, bfd)
508
509         bfd_bin = prev.pack()
510         auth_hdr_bin = self.serialize_hdr()
511         auth_data_bin = struct.pack(self._PACK_STR, self.auth_key_id, 0,
512                                     self.seq, self.auth_key +
513                                     (b'\x00' * (len(self.auth_key) - 16)))
514
515         h = hashlib.md5()
516         h.update(bfd_bin + auth_hdr_bin + auth_data_bin)
517         self.digest = h.digest()
518
519         return auth_hdr_bin + struct.pack(self._PACK_STR, self.auth_key_id, 0,
520                                           self.seq, self.digest)
521
522     def authenticate(self, prev, auth_keys=None):
523         """Authenticate the MD5 digest for this packet.
524
525         This method can be invoked only when ``self.digest`` is defined.
526
527         Returns a boolean indicates whether the digest can be authenticated
528         by the correspondent Auth Key or not.
529
530         ``prev`` is a ``bfd`` instance for the BFD Control header which this
531         authentication section belongs to. It's necessary to be assigned
532         because an MD5 digest must be calculated over the entire BFD Control
533         packet.
534
535         ``auth_keys`` is a dictionary of authentication key chain which
536         key is an integer of *Auth Key ID* and value is a string of *Auth Key*.
537         """
538         auth_keys = auth_keys if auth_keys else {}
539         assert isinstance(prev, bfd)
540
541         if self.digest is None:
542             return False
543
544         if self.auth_key_id not in auth_keys:
545             return False
546
547         auth_key = auth_keys[self.auth_key_id]
548
549         bfd_bin = prev.pack()
550         auth_hdr_bin = self.serialize_hdr()
551         auth_data_bin = struct.pack(self._PACK_STR, self.auth_key_id, 0,
552                                     self.seq, auth_key +
553                                     (b'\x00' * (len(auth_key) - 16)))
554
555         h = hashlib.md5()
556         h.update(bfd_bin + auth_hdr_bin + auth_data_bin)
557
558         if self.digest == h.digest():
559             return True
560         else:
561             return False
562
563
564 @bfd.register_auth_type(BFD_AUTH_METICULOUS_KEYED_MD5)
565 class MeticulousKeyedMD5(KeyedMD5):
566     """ BFD (RFC 5880) Meticulous Keyed MD5 Authentication Section class
567
568     All methods of this class are inherited from ``KeyedMD5``.
569
570     An instance has the following attributes.
571     Most of them are same to the on-wire counterparts but in host byte order.
572
573     .. tabularcolumns:: |l|L|
574
575     =========== =================================================
576     Attribute   Description
577     =========== =================================================
578     auth_type   (Fixed) The authentication type in use.
579     auth_key_id The authentication Key ID in use.
580     seq         The sequence number for this packet.
581                 This value is incremented for each
582                 successive packet transmitted for a session.
583     auth_key    The shared MD5 key for this packet.
584     digest      (Optional) The 16-byte MD5 digest for the packet.
585     auth_len    (Fixed) The length of the authentication section
586                 is 24 bytes.
587     =========== =================================================
588     """
589     pass
590
591
592 @bfd.register_auth_type(BFD_AUTH_KEYED_SHA1)
593 class KeyedSHA1(BFDAuth):
594     """ BFD (RFC 5880) Keyed SHA1 Authentication Section class
595
596     An instance has the following attributes.
597     Most of them are same to the on-wire counterparts but in host byte order.
598
599     .. tabularcolumns:: |l|L|
600
601     =========== ================================================
602     Attribute   Description
603     =========== ================================================
604     auth_type   (Fixed) The authentication type in use.
605     auth_key_id The authentication Key ID in use.
606     seq         The sequence number for this packet.
607                 This value is incremented occasionally.
608     auth_key    The shared SHA1 key for this packet.
609     auth_hash   (Optional) The 20-byte SHA1 hash for the packet.
610     auth_len    (Fixed) The length of the authentication section
611                 is 28 bytes.
612     =========== ================================================
613     """
614     _PACK_STR = '!BBL20s'
615     _PACK_STR_LEN = struct.calcsize(_PACK_STR)
616
617     def __init__(self, auth_key_id, seq, auth_key=None, auth_hash=None,
618                  auth_len=None):
619         self.auth_key_id = auth_key_id
620         self.seq = seq
621         self.auth_key = auth_key
622         self.auth_hash = auth_hash
623         super(KeyedSHA1, self).__init__(auth_len)
624
625     def __len__(self):
626         # Defined in RFC5880 Section 4.4.
627         return 28
628
629     @classmethod
630     def parser(cls, buf):
631         (auth_type, auth_len) = cls.parser_hdr(buf)
632         assert auth_type == cls.auth_type
633         assert auth_len == 28
634
635         (auth_key_id, reserved, seq, auth_hash) = \
636             struct.unpack_from(cls._PACK_STR, buf[cls._PACK_HDR_STR_LEN:])
637         assert reserved == 0
638
639         msg = cls(auth_key_id=auth_key_id, seq=seq, auth_key=None,
640                   auth_hash=auth_hash)
641
642         return msg, None, None
643
644     def serialize(self, payload, prev):
645         """Encode a Keyed SHA1 Authentication Section.
646
647         This method is used only when encoding an BFD Control packet.
648
649         ``payload`` is the rest of the packet which will immediately follow
650         this section.
651
652         ``prev`` is a ``bfd`` instance for the BFD Control header which this
653         authentication section belongs to. It's necessary to be assigned
654         because an SHA1 hash must be calculated over the entire BFD Control
655         packet.
656         """
657         assert self.auth_key is not None and len(self.auth_key) <= 20
658         assert isinstance(prev, bfd)
659
660         bfd_bin = prev.pack()
661         auth_hdr_bin = self.serialize_hdr()
662         auth_data_bin = struct.pack(self._PACK_STR, self.auth_key_id, 0,
663                                     self.seq, self.auth_key +
664                                     (b'\x00' * (len(self.auth_key) - 20)))
665
666         h = hashlib.sha1()
667         h.update(bfd_bin + auth_hdr_bin + auth_data_bin)
668         self.auth_hash = h.digest()
669
670         return auth_hdr_bin + struct.pack(self._PACK_STR, self.auth_key_id, 0,
671                                           self.seq, self.auth_hash)
672
673     def authenticate(self, prev, auth_keys=None):
674         """Authenticate the SHA1 hash for this packet.
675
676         This method can be invoked only when ``self.auth_hash`` is defined.
677
678         Returns a boolean indicates whether the hash can be authenticated
679         by the correspondent Auth Key or not.
680
681         ``prev`` is a ``bfd`` instance for the BFD Control header which this
682         authentication section belongs to. It's necessary to be assigned
683         because an SHA1 hash must be calculated over the entire BFD Control
684         packet.
685
686         ``auth_keys`` is a dictionary of authentication key chain which
687         key is an integer of *Auth Key ID* and value is a string of *Auth Key*.
688         """
689         auth_keys = auth_keys if auth_keys else {}
690         assert isinstance(prev, bfd)
691
692         if self.auth_hash is None:
693             return False
694
695         if self.auth_key_id not in auth_keys:
696             return False
697
698         auth_key = auth_keys[self.auth_key_id]
699
700         bfd_bin = prev.pack()
701         auth_hdr_bin = self.serialize_hdr()
702         auth_data_bin = struct.pack(self._PACK_STR, self.auth_key_id, 0,
703                                     self.seq, auth_key +
704                                     (b'\x00' * (len(auth_key) - 20)))
705
706         h = hashlib.sha1()
707         h.update(bfd_bin + auth_hdr_bin + auth_data_bin)
708
709         if self.auth_hash == h.digest():
710             return True
711         else:
712             return False
713
714
715 @bfd.register_auth_type(BFD_AUTH_METICULOUS_KEYED_SHA1)
716 class MeticulousKeyedSHA1(KeyedSHA1):
717     """ BFD (RFC 5880) Meticulous Keyed SHA1 Authentication Section class
718
719     All methods of this class are inherited from ``KeyedSHA1``.
720
721     An instance has the following attributes.
722     Most of them are same to the on-wire counterparts but in host byte order.
723
724     .. tabularcolumns:: |l|L|
725
726     =========== ================================================
727     Attribute   Description
728     =========== ================================================
729     auth_type   (Fixed) The authentication type in use.
730     auth_key_id The authentication Key ID in use.
731     seq         The sequence number for this packet.
732                 This value is incremented for each
733                 successive packet transmitted for a session.
734     auth_key    The shared SHA1 key for this packet.
735     auth_hash   (Optional) The 20-byte SHA1 hash for the packet.
736     auth_len    (Fixed) The length of the authentication section
737                 is 28 bytes.
738     =========== ================================================
739     """
740     pass
741
742
743 bfd.set_classes(bfd._auth_parsers)