github.com/contiv/libOpenflow@v0.0.0-20210609050114-d967b14cc688/protocol/ip.go (about) 1 package protocol 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "net" 7 8 "github.com/contiv/libOpenflow/util" 9 ) 10 11 const ( 12 Type_ICMP = 0x01 13 Type_TCP = 0x06 14 Type_UDP = 0x11 15 Type_IPv6 = 0x29 16 Type_IPv6ICMP = 0x3a 17 ) 18 19 type IPv4 struct { 20 Version uint8 //4-bits 21 IHL uint8 //4-bits 22 DSCP uint8 //6-bits 23 ECN uint8 //2-bits 24 Length uint16 25 Id uint16 26 Flags uint16 //3-bits 27 FragmentOffset uint16 //13-bits 28 TTL uint8 29 Protocol uint8 30 Checksum uint16 31 NWSrc net.IP 32 NWDst net.IP 33 Options util.Buffer 34 Data util.Message 35 } 36 37 func NewIPv4() *IPv4 { 38 ip := new(IPv4) 39 ip.NWSrc = make([]byte, 4) 40 ip.NWDst = make([]byte, 4) 41 ip.Options = *new(util.Buffer) 42 return ip 43 } 44 45 func (i *IPv4) Len() (n uint16) { 46 i.IHL = 5 47 if i.Data != nil { 48 return uint16(i.IHL*4) + i.Data.Len() 49 } 50 return uint16(i.IHL * 4) 51 } 52 53 func (i *IPv4) MarshalBinary() (data []byte, err error) { 54 data = make([]byte, int(i.Len())) 55 b := make([]byte, 0) 56 n := 0 57 58 var ihl uint8 = (i.Version << 4) + i.IHL 59 data[n] = ihl 60 n += 1 61 var ecn uint8 = (i.DSCP << 2) + i.ECN 62 data[n] = ecn 63 n += 1 64 binary.BigEndian.PutUint16(data[n:], i.Length) 65 n += 2 66 binary.BigEndian.PutUint16(data[n:], i.Id) 67 n += 2 68 var flg uint16 = (i.Flags << 13) + i.FragmentOffset 69 binary.BigEndian.PutUint16(data[n:], flg) 70 n += 2 71 data[n] = i.TTL 72 n += 1 73 data[n] = i.Protocol 74 n += 1 75 binary.BigEndian.PutUint16(data[n:], i.Checksum) 76 n += 2 77 78 copy(data[n:], i.NWSrc.To4()) 79 n += 4 // Underlying rep can be 16 bytes. 80 copy(data[n:], i.NWDst.To4()) 81 n += 4 // Underlying rep can be 16 bytes. 82 83 b, err = i.Options.MarshalBinary() 84 copy(data[n:], b) 85 n += len(b) 86 87 if i.Data != nil { 88 b, err = i.Data.MarshalBinary() 89 if err != nil { 90 return 91 } 92 copy(data[n:], b) 93 n += len(b) 94 } 95 return 96 } 97 98 func (i *IPv4) UnmarshalBinary(data []byte) error { 99 if len(data) < 20 { 100 return errors.New("The []byte is too short to unmarshal a full IPv4 message.") 101 } 102 n := 0 103 104 var ihl uint8 105 ihl = data[n] 106 i.Version = ihl >> 4 107 i.IHL = ihl & 0x0f 108 n += 1 109 110 var ecn uint8 111 ecn = data[n] 112 i.DSCP = ecn >> 2 113 i.ECN = ecn & 0x03 114 n += 1 115 116 i.Length = binary.BigEndian.Uint16(data[n:]) 117 n += 2 118 i.Id = binary.BigEndian.Uint16(data[n:]) 119 n += 2 120 121 var flg uint16 122 flg = binary.BigEndian.Uint16(data[n:]) 123 i.Flags = flg >> 13 124 i.FragmentOffset = flg & 0x1fff 125 n += 2 126 127 i.TTL = data[n] 128 n += 1 129 i.Protocol = data[n] 130 n += 1 131 i.Checksum = binary.BigEndian.Uint16(data[n:]) 132 n += 2 133 i.NWSrc = data[n : n+4] 134 n += 4 135 i.NWDst = data[n : n+4] 136 n += 4 137 138 err := i.Options.UnmarshalBinary(data[n:int(i.IHL*4)]) 139 if err != nil { 140 return err 141 } 142 n += int(i.IHL*4) - n 143 144 switch i.Protocol { 145 case Type_ICMP: 146 i.Data = NewICMP() 147 case Type_UDP: 148 i.Data = NewUDP() 149 default: 150 i.Data = new(util.Buffer) 151 } 152 return i.Data.UnmarshalBinary(data[n:]) 153 }