github.com/gopacket/gopacket@v1.1.0/layers/ip4_test.go (about)

     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  
     9  package layers
    10  
    11  import (
    12  	"bytes"
    13  	"encoding/binary"
    14  	"encoding/hex"
    15  	"net"
    16  	"reflect"
    17  	"testing"
    18  
    19  	"github.com/gopacket/gopacket"
    20  )
    21  
    22  // Test the function getIPv4OptionSize when the ipv4 has no options
    23  func 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
    32  func 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
    42  func 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
    53  func 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
    65  func 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  
    94  func 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
   104  func 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  
   135  func 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  
   148  func 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  }