backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / lib / packet / tcp.py
1 # Copyright (C) 2012 Nippon Telegraph and Telephone Corporation.
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 import struct
17 import logging
18
19 import six
20
21 from ryu.lib import stringify
22 from . import packet_base
23 from . import packet_utils
24 from . import bgp
25 from . import openflow
26 from . import zebra
27
28
29 LOG = logging.getLogger(__name__)
30
31 # TCP Option Kind Numbers
32 TCP_OPTION_KIND_END_OF_OPTION_LIST = 0    # End of Option List
33 TCP_OPTION_KIND_NO_OPERATION = 1          # No-Operation
34 TCP_OPTION_KIND_MAXIMUM_SEGMENT_SIZE = 2  # Maximum Segment Size
35 TCP_OPTION_KIND_WINDOW_SCALE = 3          # Window Scale
36 TCP_OPTION_KIND_SACK_PERMITTED = 4        # SACK Permitted
37 TCP_OPTION_KIND_SACK = 5                  # SACK
38 TCP_OPTION_KIND_TIMESTAMPS = 8            # Timestamps
39 TCP_OPTION_KIND_USER_TIMEOUT = 28         # User Timeout Option
40 TCP_OPTION_KIND_AUTHENTICATION = 29       # TCP Authentication Option (TCP-AO)
41
42 TCP_FIN = 0x001
43 TCP_SYN = 0x002
44 TCP_RST = 0x004
45 TCP_PSH = 0x008
46 TCP_ACK = 0x010
47 TCP_URG = 0x020
48 TCP_ECE = 0x040
49 TCP_CWR = 0x080
50 TCP_NS = 0x100
51
52
53 class tcp(packet_base.PacketBase):
54     """TCP (RFC 793) header encoder/decoder class.
55
56     An instance has the following attributes at least.
57     Most of them are same to the on-wire counterparts but in host byte order.
58     __init__ takes the corresponding args in this order.
59
60     ============== ====================
61     Attribute      Description
62     ============== ====================
63     src_port       Source Port
64     dst_port       Destination Port
65     seq            Sequence Number
66     ack            Acknowledgement Number
67     offset         Data Offset \
68                    (0 means automatically-calculate when encoding)
69     bits           Control Bits
70     window_size    Window
71     csum           Checksum \
72                    (0 means automatically-calculate when encoding)
73     urgent         Urgent Pointer
74     option         List of ``TCPOption`` sub-classes or an bytearray
75                    containing options. \
76                    None if no options.
77     ============== ====================
78     """
79
80     _PACK_STR = '!HHIIBBHHH'
81     _MIN_LEN = struct.calcsize(_PACK_STR)
82
83     def __init__(self, src_port=1, dst_port=1, seq=0, ack=0, offset=0,
84                  bits=0, window_size=0, csum=0, urgent=0, option=None):
85         super(tcp, self).__init__()
86         self.src_port = src_port
87         self.dst_port = dst_port
88         self.seq = seq
89         self.ack = ack
90         self.offset = offset
91         self.bits = bits
92         self.window_size = window_size
93         self.csum = csum
94         self.urgent = urgent
95         self.option = option
96
97     def __len__(self):
98         return self.offset * 4
99
100     def has_flags(self, *flags):
101         """Check if flags are set on this packet.
102
103         returns boolean if all passed flags is set
104
105         Example::
106
107             >>> pkt = tcp.tcp(bits=(tcp.TCP_SYN | tcp.TCP_ACK))
108             >>> pkt.has_flags(tcp.TCP_SYN, tcp.TCP_ACK)
109             True
110         """
111
112         mask = sum(flags)
113         return (self.bits & mask) == mask
114
115     @staticmethod
116     def get_payload_type(src_port, dst_port):
117         from ryu.ofproto.ofproto_common import OFP_TCP_PORT, OFP_SSL_PORT_OLD
118         if bgp.TCP_SERVER_PORT in [src_port, dst_port]:
119             return bgp.BGPMessage
120         elif(src_port in [OFP_TCP_PORT, OFP_SSL_PORT_OLD] or
121              dst_port in [OFP_TCP_PORT, OFP_SSL_PORT_OLD]):
122             return openflow.openflow
123         elif src_port == zebra.ZEBRA_PORT:
124             return zebra._ZebraMessageFromZebra
125         elif dst_port == zebra.ZEBRA_PORT:
126             return zebra.ZebraMessage
127         else:
128             return None
129
130     @classmethod
131     def parser(cls, buf):
132         (src_port, dst_port, seq, ack, offset, bits, window_size,
133          csum, urgent) = struct.unpack_from(cls._PACK_STR, buf)
134         offset >>= 4
135         bits &= 0x3f
136         length = offset * 4
137         if length > tcp._MIN_LEN:
138             option_buf = buf[tcp._MIN_LEN:length]
139             try:
140                 option = []
141                 while option_buf:
142                     opt, option_buf = TCPOption.parser(option_buf)
143                     option.append(opt)
144             except struct.error:
145                 LOG.warning(
146                     'Encounter an error during parsing TCP option field.'
147                     'Skip parsing TCP option.')
148                 option = buf[tcp._MIN_LEN:length]
149         else:
150             option = None
151         msg = cls(src_port, dst_port, seq, ack, offset, bits,
152                   window_size, csum, urgent, option)
153
154         return msg, cls.get_payload_type(src_port, dst_port), buf[length:]
155
156     def serialize(self, payload, prev):
157         offset = self.offset << 4
158         h = bytearray(struct.pack(
159             tcp._PACK_STR, self.src_port, self.dst_port, self.seq,
160             self.ack, offset, self.bits, self.window_size, self.csum,
161             self.urgent))
162
163         if self.option:
164             if isinstance(self.option, (list, tuple)):
165                 option_buf = bytearray()
166                 for opt in self.option:
167                     option_buf.extend(opt.serialize())
168                 h.extend(option_buf)
169                 mod = len(option_buf) % 4
170             else:
171                 h.extend(self.option)
172                 mod = len(self.option) % 4
173             if mod:
174                 h.extend(bytearray(4 - mod))
175             if self.offset:
176                 offset = self.offset << 2
177                 if len(h) < offset:
178                     h.extend(bytearray(offset - len(h)))
179
180         if self.offset == 0:
181             self.offset = len(h) >> 2
182             offset = self.offset << 4
183             struct.pack_into('!B', h, 12, offset)
184
185         if self.csum == 0:
186             total_length = len(h) + len(payload)
187             self.csum = packet_utils.checksum_ip(prev, total_length,
188                                                  h + payload)
189             struct.pack_into('!H', h, 16, self.csum)
190         return six.binary_type(h)
191
192
193 class TCPOption(stringify.StringifyMixin):
194     _KINDS = {}
195     _KIND_PACK_STR = '!B'  # kind
196     NO_BODY_OFFSET = 1     # kind(1 byte)
197     WITH_BODY_OFFSET = 2   # kind(1 byte) + length(1 byte)
198     cls_kind = None
199     cls_length = None
200
201     def __init__(self, kind=None, length=None):
202         self.kind = self.cls_kind if kind is None else kind
203         self.length = self.cls_length if length is None else length
204
205     @classmethod
206     def register(cls, kind, length):
207         def _register(subcls):
208             subcls.cls_kind = kind
209             subcls.cls_length = length
210             cls._KINDS[kind] = subcls
211             return subcls
212         return _register
213
214     @classmethod
215     def parse(cls, buf):
216         # For no body TCP Options
217         return cls(cls.cls_kind, cls.cls_length), buf[cls.cls_length:]
218
219     @classmethod
220     def parser(cls, buf):
221         (kind,) = struct.unpack_from(cls._KIND_PACK_STR, buf)
222         subcls = cls._KINDS.get(kind)
223         if not subcls:
224             subcls = TCPOptionUnknown
225         return subcls.parse(buf)
226
227     def serialize(self):
228         # For no body TCP Options
229         return struct.pack(self._KIND_PACK_STR, self.cls_kind)
230
231
232 class TCPOptionUnknown(TCPOption):
233     _PACK_STR = '!BB'  # kind, length
234
235     def __init__(self, value, kind, length):
236         super(TCPOptionUnknown, self).__init__(kind, length)
237         self.value = value if value is not None else b''
238
239     @classmethod
240     def parse(cls, buf):
241         (kind, length) = struct.unpack_from(cls._PACK_STR, buf)
242         value = buf[2:length]
243         return cls(value, kind, length), buf[length:]
244
245     def serialize(self):
246         self.length = self.WITH_BODY_OFFSET + len(self.value)
247         return struct.pack(self._PACK_STR,
248                            self.kind, self.length) + self.value
249
250
251 @TCPOption.register(TCP_OPTION_KIND_END_OF_OPTION_LIST,
252                     TCPOption.NO_BODY_OFFSET)
253 class TCPOptionEndOfOptionList(TCPOption):
254     pass
255
256
257 @TCPOption.register(TCP_OPTION_KIND_NO_OPERATION,
258                     TCPOption.NO_BODY_OFFSET)
259 class TCPOptionNoOperation(TCPOption):
260     pass
261
262
263 @TCPOption.register(TCP_OPTION_KIND_MAXIMUM_SEGMENT_SIZE, 4)
264 class TCPOptionMaximumSegmentSize(TCPOption):
265     _PACK_STR = '!BBH'  # kind, length, max_seg_size
266
267     def __init__(self, max_seg_size, kind=None, length=None):
268         super(TCPOptionMaximumSegmentSize, self).__init__(kind, length)
269         self.max_seg_size = max_seg_size
270
271     @classmethod
272     def parse(cls, buf):
273         (_, _, max_seg_size) = struct.unpack_from(cls._PACK_STR, buf)
274         return cls(max_seg_size,
275                    cls.cls_kind, cls.cls_length), buf[cls.cls_length:]
276
277     def serialize(self):
278         return struct.pack(self._PACK_STR,
279                            self.kind, self.length, self.max_seg_size)
280
281
282 @TCPOption.register(TCP_OPTION_KIND_WINDOW_SCALE, 3)
283 class TCPOptionWindowScale(TCPOption):
284     _PACK_STR = '!BBB'  # kind, length, shift_cnt
285
286     def __init__(self, shift_cnt, kind=None, length=None):
287         super(TCPOptionWindowScale, self).__init__(kind, length)
288         self.shift_cnt = shift_cnt
289
290     @classmethod
291     def parse(cls, buf):
292         (_, _, shift_cnt) = struct.unpack_from(cls._PACK_STR, buf)
293         return cls(shift_cnt,
294                    cls.cls_kind, cls.cls_length), buf[cls.cls_length:]
295
296     def serialize(self):
297         return struct.pack(self._PACK_STR,
298                            self.kind, self.length, self.shift_cnt)
299
300
301 @TCPOption.register(TCP_OPTION_KIND_SACK_PERMITTED, 2)
302 class TCPOptionSACKPermitted(TCPOption):
303     _PACK_STR = '!BB'  # kind, length
304
305     def serialize(self):
306         return struct.pack(self._PACK_STR, self.kind, self.length)
307
308
309 @TCPOption.register(TCP_OPTION_KIND_SACK,
310                     2)  # variable length. 2 is the length except blocks.
311 class TCPOptionSACK(TCPOption):
312     _PACK_STR = '!BB'        # kind, length
313     _BLOCK_PACK_STR = '!II'  # Left Edge of Block, Right Edge of Block
314
315     def __init__(self, blocks, kind=None, length=None):
316         super(TCPOptionSACK, self).__init__(kind, length)
317         # blocks is a list of tuple as followings.
318         # self.blocks = [
319         #     ('Left Edge of 1st Block', 'Right Edge of 1st Block'),
320         #     ...
321         #     ('Left Edge of nth Block', 'Right Edge of nth Block')
322         # ]
323         self.blocks = blocks
324
325     @classmethod
326     def parse(cls, buf):
327         (_, length) = struct.unpack_from(cls._PACK_STR, buf)
328         blocks_buf = buf[2:length]
329         blocks = []
330         while blocks_buf:
331             lr_block = struct.unpack_from(cls._BLOCK_PACK_STR, blocks_buf)
332             blocks.append(lr_block)  # (left, right)
333             blocks_buf = blocks_buf[8:]
334         return cls(blocks, cls.cls_kind, length), buf[length:]
335
336     def serialize(self):
337         buf = bytearray()
338         for left, right in self.blocks:
339             buf += struct.pack(self._BLOCK_PACK_STR, left, right)
340         self.length = self.cls_length + len(buf)
341         return struct.pack(self._PACK_STR, self.kind, self.length) + buf
342
343
344 @TCPOption.register(TCP_OPTION_KIND_TIMESTAMPS, 10)
345 class TCPOptionTimestamps(TCPOption):
346     _PACK_STR = '!BBII'  # kind, length, ts_val, ts_ecr
347
348     def __init__(self, ts_val, ts_ecr, kind=None, length=None):
349         super(TCPOptionTimestamps, self).__init__(kind, length)
350         self.ts_val = ts_val
351         self.ts_ecr = ts_ecr
352
353     @classmethod
354     def parse(cls, buf):
355         (_, _, ts_val, ts_ecr) = struct.unpack_from(cls._PACK_STR, buf)
356         return cls(ts_val, ts_ecr,
357                    cls.cls_kind, cls.cls_length), buf[cls.cls_length:]
358
359     def serialize(self):
360         return struct.pack(self._PACK_STR,
361                            self.kind, self.length, self.ts_val, self.ts_ecr)
362
363
364 @TCPOption.register(TCP_OPTION_KIND_USER_TIMEOUT, 4)
365 class TCPOptionUserTimeout(TCPOption):
366     _PACK_STR = '!BBH'  # kind, length, granularity(1bit)|user_timeout(15bit)
367
368     def __init__(self, granularity, user_timeout, kind=None, length=None):
369         super(TCPOptionUserTimeout, self).__init__(kind, length)
370         self.granularity = granularity
371         self.user_timeout = user_timeout
372
373     @classmethod
374     def parse(cls, buf):
375         (_, _, body) = struct.unpack_from(cls._PACK_STR, buf)
376         granularity = body >> 15
377         user_timeout = body & 0x7fff
378         return cls(granularity, user_timeout,
379                    cls.cls_kind, cls.cls_length), buf[cls.cls_length:]
380
381     def serialize(self):
382         body = (self.granularity << 15) | self.user_timeout
383         return struct.pack(self._PACK_STR, self.kind, self.length, body)
384
385
386 @TCPOption.register(TCP_OPTION_KIND_AUTHENTICATION,
387                     4)  # variable length. 4 is the length except MAC.
388 class TCPOptionAuthentication(TCPOption):
389     _PACK_STR = '!BBBB'  # kind, length, key_id, r_next_key_id
390
391     def __init__(self, key_id, r_next_key_id, mac, kind=None, length=None):
392         super(TCPOptionAuthentication, self).__init__(kind, length)
393         self.key_id = key_id
394         self.r_next_key_id = r_next_key_id
395         self.mac = mac
396
397     @classmethod
398     def parse(cls, buf):
399         (_, length,
400          key_id, r_next_key_id) = struct.unpack_from(cls._PACK_STR, buf)
401         mac = buf[4:length]
402         return cls(key_id, r_next_key_id, mac,
403                    cls.cls_kind, length), buf[length:]
404
405     def serialize(self):
406         self.length = self.cls_length + len(self.mac)
407         return struct.pack(self._PACK_STR, self.kind, self.length,
408                            self.key_id, self.r_next_key_id) + self.mac