1// Copyright 2012 Google, Inc. All rights reserved. 2// 3// Use of this source code is governed by a BSD-style license 4// that can be found in the LICENSE file in the root of the source 5// tree. 6 7// This file tests some of the functionality provided in the ip4.go 8 9package layers 10 11import ( 12 "bytes" 13 "encoding/binary" 14 "encoding/hex" 15 "net" 16 "reflect" 17 "testing" 18 19 "github.com/google/gopacket" 20) 21 22// Test the function getIPv4OptionSize when the ipv4 has no options 23func TestGetIPOptLengthNoOpt(t *testing.T) { 24 ip := IPv4{} 25 length := ip.getIPv4OptionSize() 26 if length != 0 { 27 t.Fatalf("Empty option list should have 0 length. Actual %d", length) 28 } 29} 30 31// Test the function getIPv4OptionSize when the ipv4 has end of list option 32func TestGetIPOptLengthEndOfList(t *testing.T) { 33 ip := IPv4{} 34 ip.Options = append(ip.Options, IPv4Option{OptionType: 0, OptionLength: 1}) 35 length := ip.getIPv4OptionSize() 36 if length != 4 { 37 t.Fatalf("After padding, the list should have 4 length. Actual %d", length) 38 } 39} 40 41// Test the function getIPv4OptionSize when the ipv4 has padding and end of list option 42func TestGetIPOptLengthPaddingEndOfList(t *testing.T) { 43 ip := IPv4{} 44 ip.Options = append(ip.Options, IPv4Option{OptionType: 1, OptionLength: 1}) 45 ip.Options = append(ip.Options, IPv4Option{OptionType: 0, OptionLength: 1}) 46 length := ip.getIPv4OptionSize() 47 if length != 4 { 48 t.Fatalf("After padding, the list should have 4 length. Actual %d", length) 49 } 50} 51 52// Test the function getIPv4OptionSize when the ipv4 has some non-trivial option and end of list option 53func TestGetIPOptLengthOptionEndOfList(t *testing.T) { 54 ip := IPv4{} 55 someByte := make([]byte, 8) 56 ip.Options = append(ip.Options, IPv4Option{OptionType: 2, OptionLength: 10, OptionData: someByte}) 57 ip.Options = append(ip.Options, IPv4Option{OptionType: 0, OptionLength: 1}) 58 length := ip.getIPv4OptionSize() 59 if length != 12 { 60 t.Fatalf("The list should have 12 length. Actual %d", length) 61 } 62} 63 64// Tests that the Options slice is properly reset before parsing new data 65func TestIPOptResetDuringDecoding(t *testing.T) { 66 ip := &IPv4{ 67 Options: []IPv4Option{{OptionType: 42, OptionLength: 4, OptionData: make([]byte, 2)}}, 68 } 69 70 ipWithoutOptions := &IPv4{ 71 SrcIP: net.IPv4(192, 168, 1, 1), 72 DstIP: net.IPv4(192, 168, 1, 1), 73 Protocol: IPProtocolTCP, 74 } 75 76 ipBytes, err := serialize(ipWithoutOptions) 77 78 if err != nil { 79 t.Fatalf("Failed to serialize ip layer: %v", err) 80 } 81 82 err = ip.DecodeFromBytes(ipBytes, gopacket.NilDecodeFeedback) 83 84 if err != nil { 85 t.Fatalf("Failed to deserialize ip layer: %v", err) 86 } 87 88 if len(ip.Options) > 0 { 89 t.Fatalf("Options slice has stale data from previous packet") 90 } 91 92} 93 94func serialize(ip *IPv4) ([]byte, error) { 95 buffer := gopacket.NewSerializeBuffer() 96 err := ip.SerializeTo(buffer, gopacket.SerializeOptions{ 97 FixLengths: true, 98 ComputeChecksums: true, 99 }) 100 return buffer.Bytes(), err 101} 102 103// Test the function checksum 104func TestChecksum(t *testing.T) { 105 testData := []struct { 106 name string 107 header string 108 want string 109 }{{ 110 name: "sum has two carries", 111 header: "4540005800000000ff11ffff0aeb1d070aed8877", 112 want: "fffe", 113 }, { 114 name: "wikipedia case", 115 header: "45000073000040004011b861c0a80001c0a800c7", 116 want: "b861", 117 }} 118 119 for _, test := range testData { 120 bytes, err := hex.DecodeString(test.header) 121 if err != nil { 122 t.Fatalf("Failed to Decode header: %v", err) 123 } 124 wantBytes, err := hex.DecodeString(test.want) 125 if err != nil { 126 t.Fatalf("Failed to decode want checksum: %v", err) 127 } 128 129 if got, want := checksum(bytes), binary.BigEndian.Uint16(wantBytes); got != want { 130 t.Errorf("In test %q, got incorrect checksum: got(%x), want(%x)", test.name, got, want) 131 } 132 } 133} 134 135func TestIPv4InvalidOptionLength(t *testing.T) { 136 // ip4 Packet with option 136 length set to zero 137 b, err := hex.DecodeString("460000705f5b0000ff114e02af2db00295ab7e0f88001234") 138 if err != nil { 139 t.Fatalf("Failed to Decode header: %v", err) 140 } 141 var ip4 IPv4 142 err = ip4.DecodeFromBytes(b, gopacket.NilDecodeFeedback) 143 if err == nil { 144 t.Fatal("Expected 'invalid IP option length' error, but got none.") 145 } 146} 147 148func TestIPv4Options(t *testing.T) { 149 var ip4 IPv4 // reuse ip4 to test reset 150 for _, test := range []struct { 151 packet string 152 options []IPv4Option 153 padding []byte 154 }{ 155 { 156 packet: "4800002803040000fe01c1e0af2db00095ab7e0b820b00000000000000000000", 157 options: []IPv4Option{ 158 { 159 OptionType: 130, 160 OptionData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0}, 161 OptionLength: 11, 162 }, 163 { 164 OptionType: 0, 165 OptionLength: 1, 166 }, 167 }, 168 }, 169 { 170 packet: "4900002803040000fe01c1e0af2db00095ab7e0b01820b00000000000000000000010203", 171 options: []IPv4Option{ 172 { 173 OptionType: 1, 174 OptionLength: 1, 175 }, 176 { 177 OptionType: 130, 178 OptionData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0}, 179 OptionLength: 11, 180 }, 181 { 182 OptionType: 0, 183 OptionLength: 1, 184 }, 185 }, 186 padding: []byte{1, 2, 3}, 187 }, 188 { 189 packet: "4800002803040000fe01c1e0af2db00095ab7e0b820c00000000000000000000", 190 options: []IPv4Option{ 191 { 192 OptionType: 130, 193 OptionData: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 194 OptionLength: 12, 195 }, 196 }, 197 }, 198 { 199 packet: "4900002803040000fe01c1e0af2db00095ab7e0b00820b00000000000000000000010203", 200 options: []IPv4Option{ 201 { 202 OptionType: 0, 203 OptionLength: 1, 204 }, 205 }, 206 padding: []byte{0x82, 0x0b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3}, 207 }, 208 } { 209 b, err := hex.DecodeString(test.packet) 210 if err != nil { 211 t.Fatalf("Failed to Decode header: %v", err) 212 } 213 err = ip4.DecodeFromBytes(b, gopacket.NilDecodeFeedback) 214 if err != nil { 215 t.Fatal("Unexpected error during decoding:", err) 216 } 217 if !reflect.DeepEqual(ip4.Options, test.options) { 218 t.Fatalf("Options mismatch.\nGot:\n%#v\nExpected:\n%#v\n", ip4.Options, test.options) 219 } 220 if !bytes.Equal(ip4.Padding, test.padding) { 221 t.Fatalf("Padding mismatch.\nGot:\n%#v\nExpected:\n%#v\n", ip4.Padding, test.padding) 222 } 223 } 224} 225