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 16import struct 17 18from . import packet_base 19from . import packet_utils 20from . import icmp 21from . import igmp 22from . import udp 23from . import tcp 24from . import sctp 25from . import ospf 26from . import gre 27from . import in_proto as inet 28from ryu.lib import addrconv 29 30 31IPV4_ADDRESS_PACK_STR = '!I' 32IPV4_ADDRESS_LEN = struct.calcsize(IPV4_ADDRESS_PACK_STR) 33IPV4_PSEUDO_HEADER_PACK_STR = '!4s4s2xHH' 34 35 36class ipv4(packet_base.PacketBase): 37 """IPv4 (RFC 791) header encoder/decoder class. 38 39 NOTE: When decoding, this implementation tries to decode the upper 40 layer protocol even for a fragmented datagram. It isn't likely 41 what a user would want. 42 43 An instance has the following attributes at least. 44 Most of them are same to the on-wire counterparts but in host byte order. 45 IPv4 addresses are represented as a string like '192.0.2.1'. 46 __init__ takes the corresponding args in this order. 47 48 ============== ======================================== ================== 49 Attribute Description Example 50 ============== ======================================== ================== 51 version Version 52 header_length IHL 53 tos Type of Service 54 total_length Total Length 55 (0 means automatically-calculate 56 when encoding) 57 identification Identification 58 flags Flags 59 offset Fragment Offset 60 ttl Time to Live 61 proto Protocol 62 csum Header Checksum 63 (Ignored and automatically-calculated 64 when encoding) 65 src Source Address '192.0.2.1' 66 dst Destination Address '192.0.2.2' 67 option A bytearray which contains the entire 68 Options, or None for no Options 69 ============== ======================================== ================== 70 """ 71 72 _PACK_STR = '!BBHHHBBH4s4s' 73 _MIN_LEN = struct.calcsize(_PACK_STR) 74 _TYPE = { 75 'ascii': [ 76 'src', 'dst' 77 ] 78 } 79 80 def __init__(self, version=4, header_length=5, tos=0, 81 total_length=0, identification=0, flags=0, 82 offset=0, ttl=255, proto=0, csum=0, 83 src='10.0.0.1', 84 dst='10.0.0.2', 85 option=None): 86 super(ipv4, self).__init__() 87 self.version = version 88 self.header_length = header_length 89 self.tos = tos 90 self.total_length = total_length 91 self.identification = identification 92 self.flags = flags 93 self.offset = offset 94 self.ttl = ttl 95 self.proto = proto 96 self.csum = csum 97 self.src = src 98 self.dst = dst 99 self.option = option 100 101 def __len__(self): 102 return self.header_length * 4 103 104 @classmethod 105 def parser(cls, buf): 106 (version, tos, total_length, identification, flags, ttl, proto, csum, 107 src, dst) = struct.unpack_from(cls._PACK_STR, buf) 108 header_length = version & 0xf 109 version = version >> 4 110 offset = flags & ((1 << 13) - 1) 111 flags = flags >> 13 112 length = header_length * 4 113 if length > ipv4._MIN_LEN: 114 option = buf[ipv4._MIN_LEN:length] 115 else: 116 option = None 117 msg = cls(version, header_length, tos, total_length, identification, 118 flags, offset, ttl, proto, csum, 119 addrconv.ipv4.bin_to_text(src), 120 addrconv.ipv4.bin_to_text(dst), option) 121 122 return msg, ipv4.get_packet_type(proto), buf[length:total_length] 123 124 def serialize(self, payload, prev): 125 length = len(self) 126 hdr = bytearray(length) 127 version = self.version << 4 | self.header_length 128 flags = self.flags << 13 | self.offset 129 if self.total_length == 0: 130 self.total_length = self.header_length * 4 + len(payload) 131 struct.pack_into(ipv4._PACK_STR, hdr, 0, version, self.tos, 132 self.total_length, self.identification, flags, 133 self.ttl, self.proto, 0, 134 addrconv.ipv4.text_to_bin(self.src), 135 addrconv.ipv4.text_to_bin(self.dst)) 136 137 if self.option: 138 assert (length - ipv4._MIN_LEN) >= len(self.option) 139 hdr[ipv4._MIN_LEN:ipv4._MIN_LEN + len(self.option)] = self.option 140 141 self.csum = packet_utils.checksum(hdr) 142 struct.pack_into('!H', hdr, 10, self.csum) 143 return hdr 144 145 146ipv4.register_packet_type(icmp.icmp, inet.IPPROTO_ICMP) 147ipv4.register_packet_type(igmp.igmp, inet.IPPROTO_IGMP) 148ipv4.register_packet_type(tcp.tcp, inet.IPPROTO_TCP) 149ipv4.register_packet_type(udp.udp, inet.IPPROTO_UDP) 150ipv4.register_packet_type(sctp.sctp, inet.IPPROTO_SCTP) 151ipv4.register_packet_type(ospf.ospf, inet.IPPROTO_OSPF) 152ipv4.register_packet_type(gre.gre, inet.IPPROTO_GRE) 153