...

Source file src/github.com/mdlayher/arp/packet_test.go

Documentation: github.com/mdlayher/arp

     1  package arp
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"net"
     7  	"net/netip"
     8  	"reflect"
     9  	"testing"
    10  
    11  	"github.com/mdlayher/ethernet"
    12  )
    13  
    14  func TestNewPacket(t *testing.T) {
    15  	zeroHW := net.HardwareAddr{0, 0, 0, 0, 0, 0}
    16  
    17  	iboip1 := net.HardwareAddr(bytes.Repeat([]byte{0}, 20))
    18  
    19  	tests := []struct {
    20  		desc  string
    21  		op    Operation
    22  		srcHW net.HardwareAddr
    23  		srcIP netip.Addr
    24  		dstHW net.HardwareAddr
    25  		dstIP netip.Addr
    26  		p     *Packet
    27  		err   error
    28  	}{
    29  		{
    30  			desc:  "short source hardware address",
    31  			srcHW: net.HardwareAddr{0, 0, 0, 0, 0},
    32  			err:   ErrInvalidHardwareAddr,
    33  		},
    34  		{
    35  			desc:  "short destination hardware address",
    36  			srcHW: zeroHW,
    37  			dstHW: net.HardwareAddr{0, 0, 0, 0, 0},
    38  			err:   ErrInvalidHardwareAddr,
    39  		},
    40  		{
    41  			desc:  "hardware address length mismatch",
    42  			srcHW: zeroHW,
    43  			dstHW: net.HardwareAddr{0, 0, 0, 0, 0, 0, 0, 0},
    44  			err:   ErrInvalidHardwareAddr,
    45  		},
    46  		{
    47  			desc:  "IPv6 source IP address",
    48  			srcHW: zeroHW,
    49  			dstHW: zeroHW,
    50  			srcIP: netip.IPv6Unspecified(),
    51  			err:   ErrInvalidIP,
    52  		},
    53  		{
    54  			desc:  "IPv6 destination IP address",
    55  			srcHW: zeroHW,
    56  			dstHW: zeroHW,
    57  			srcIP: netip.IPv4Unspecified(),
    58  			dstIP: netip.IPv6Unspecified(),
    59  			err:   ErrInvalidIP,
    60  		},
    61  		{
    62  			desc:  "Gratuitous ARP request, IPoIB hardware addresses",
    63  			op:    OperationRequest,
    64  			srcHW: iboip1,
    65  			dstHW: ethernet.Broadcast,
    66  			srcIP: netip.IPv4Unspecified(),
    67  			dstIP: netip.IPv4Unspecified(),
    68  			p: &Packet{
    69  				HardwareType:       1,
    70  				ProtocolType:       uint16(ethernet.EtherTypeIPv4),
    71  				HardwareAddrLength: 20,
    72  				IPLength:           4,
    73  				Operation:          OperationRequest,
    74  				SenderHardwareAddr: iboip1,
    75  				SenderIP:           netip.IPv4Unspecified(),
    76  				TargetHardwareAddr: ethernet.Broadcast,
    77  				TargetIP:           netip.IPv4Unspecified(),
    78  			},
    79  		},
    80  		{
    81  			desc:  "OK",
    82  			op:    OperationRequest,
    83  			srcHW: zeroHW,
    84  			dstHW: zeroHW,
    85  			srcIP: netip.IPv4Unspecified(),
    86  			dstIP: netip.IPv4Unspecified(),
    87  			p: &Packet{
    88  				HardwareType:       1,
    89  				ProtocolType:       uint16(ethernet.EtherTypeIPv4),
    90  				HardwareAddrLength: 6,
    91  				IPLength:           4,
    92  				Operation:          OperationRequest,
    93  				SenderHardwareAddr: zeroHW,
    94  				SenderIP:           netip.IPv4Unspecified(),
    95  				TargetHardwareAddr: zeroHW,
    96  				TargetIP:           netip.IPv4Unspecified(),
    97  			},
    98  		},
    99  	}
   100  
   101  	for i, tt := range tests {
   102  		p, err := NewPacket(tt.op, tt.srcHW, tt.srcIP, tt.dstHW, tt.dstIP)
   103  		if err != nil {
   104  			if want, got := tt.err, err; want != got {
   105  				t.Fatalf("[%02d] test %q, unexpected error: %v != %v",
   106  					i, tt.desc, want, got)
   107  			}
   108  
   109  			continue
   110  		}
   111  
   112  		if want, got := tt.p, p; !reflect.DeepEqual(want, got) {
   113  			t.Fatalf("[%02d] test %q, unexpected Packet:\n- want: %v\n-  got: %v",
   114  				i, tt.desc, want, got)
   115  		}
   116  	}
   117  }
   118  
   119  func TestPacketMarshalBinary(t *testing.T) {
   120  	zeroHW := net.HardwareAddr{0, 0, 0, 0, 0, 0}
   121  	ip1 := netip.MustParseAddr("192.168.1.10")
   122  	ip2 := netip.MustParseAddr("192.168.1.1")
   123  
   124  	iboip1 := net.HardwareAddr(bytes.Repeat([]byte{0}, 20))
   125  	iboip2 := net.HardwareAddr(bytes.Repeat([]byte{1}, 20))
   126  
   127  	tests := []struct {
   128  		desc string
   129  		p    *Packet
   130  		b    []byte
   131  	}{
   132  		{
   133  			desc: "ARP request to ethernet broadcast, 6 byte hardware addresses",
   134  			p: &Packet{
   135  				HardwareType:       1,
   136  				ProtocolType:       uint16(ethernet.EtherTypeIPv4),
   137  				HardwareAddrLength: 6,
   138  				IPLength:           4,
   139  				Operation:          OperationRequest,
   140  				SenderHardwareAddr: zeroHW,
   141  				SenderIP:           ip1,
   142  				TargetHardwareAddr: ethernet.Broadcast,
   143  				TargetIP:           ip2,
   144  			},
   145  			b: []byte{
   146  				0, 1,
   147  				8, 0,
   148  				6,
   149  				4,
   150  				0, 1,
   151  				0, 0, 0, 0, 0, 0,
   152  				192, 168, 1, 10,
   153  				255, 255, 255, 255, 255, 255,
   154  				192, 168, 1, 1,
   155  			},
   156  		},
   157  		{
   158  			desc: "ARP reply over infiniband, 20 byte hardware addresses",
   159  			p: &Packet{
   160  				HardwareType:       32,
   161  				ProtocolType:       uint16(ethernet.EtherTypeIPv4),
   162  				HardwareAddrLength: 20,
   163  				IPLength:           4,
   164  				Operation:          OperationReply,
   165  				SenderHardwareAddr: iboip1,
   166  				SenderIP:           ip1,
   167  				TargetHardwareAddr: iboip2,
   168  				TargetIP:           ip2,
   169  			},
   170  			b: []byte{
   171  				0, 32,
   172  				8, 0,
   173  				20,
   174  				4,
   175  				0, 2,
   176  				0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   177  				0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   178  				192, 168, 1, 10,
   179  				1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
   180  				1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
   181  				192, 168, 1, 1,
   182  			},
   183  		},
   184  	}
   185  
   186  	for i, tt := range tests {
   187  		b, err := tt.p.MarshalBinary()
   188  		if err != nil {
   189  			t.Fatal(err)
   190  		}
   191  
   192  		if want, got := tt.b, b; !bytes.Equal(want, got) {
   193  			t.Fatalf("[%02d] test %q, unexpected Packet bytes:\n- want: %v\n-  got: %v",
   194  				i, tt.desc, want, got)
   195  		}
   196  	}
   197  }
   198  
   199  func TestPacketUnmarshalBinary(t *testing.T) {
   200  	zeroHW := net.HardwareAddr{0, 0, 0, 0, 0, 0}
   201  	ip1 := netip.MustParseAddr("192.168.1.10")
   202  	ip2 := netip.MustParseAddr("192.168.1.1")
   203  
   204  	iboip1 := net.HardwareAddr(bytes.Repeat([]byte{0}, 20))
   205  	iboip2 := net.HardwareAddr(bytes.Repeat([]byte{1}, 20))
   206  
   207  	tests := []struct {
   208  		desc string
   209  		p    *Packet
   210  		b    []byte
   211  		err  error
   212  	}{
   213  		{
   214  			desc: "short buffer",
   215  			b:    bytes.Repeat([]byte{0}, 7),
   216  			err:  io.ErrUnexpectedEOF,
   217  		},
   218  		{
   219  			desc: "short buffer, too short for hardware addresses",
   220  			b: []byte{
   221  				0, 1,
   222  				8, 0,
   223  				255,
   224  				4,
   225  				0, 1,
   226  			},
   227  			err: io.ErrUnexpectedEOF,
   228  		},
   229  		{
   230  			desc: "short buffer, too short for IP addresses",
   231  			b: []byte{
   232  				0, 1,
   233  				8, 0,
   234  				6,
   235  				255,
   236  				0, 1,
   237  			},
   238  			err: io.ErrUnexpectedEOF,
   239  		},
   240  		{
   241  			desc: "ARP request to ethernet broadcast, 6 byte hardware addresses",
   242  			b: []byte{
   243  				0, 1,
   244  				8, 0,
   245  				6,
   246  				4,
   247  				0, 1,
   248  				0, 0, 0, 0, 0, 0,
   249  				192, 168, 1, 10,
   250  				255, 255, 255, 255, 255, 255,
   251  				192, 168, 1, 1,
   252  			},
   253  			p: &Packet{
   254  				HardwareType:       1,
   255  				ProtocolType:       uint16(ethernet.EtherTypeIPv4),
   256  				HardwareAddrLength: 6,
   257  				IPLength:           4,
   258  				Operation:          OperationRequest,
   259  				SenderHardwareAddr: zeroHW,
   260  				SenderIP:           ip1,
   261  				TargetHardwareAddr: ethernet.Broadcast,
   262  				TargetIP:           ip2,
   263  			},
   264  		},
   265  		{
   266  			desc: "ARP reply over infiniband, 20 byte hardware addresses",
   267  			b: []byte{
   268  				0, 32,
   269  				8, 0,
   270  				20,
   271  				4,
   272  				0, 2,
   273  				0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   274  				0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   275  				192, 168, 1, 10,
   276  				1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
   277  				1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
   278  				192, 168, 1, 1,
   279  			},
   280  			p: &Packet{
   281  				HardwareType:       32,
   282  				ProtocolType:       uint16(ethernet.EtherTypeIPv4),
   283  				HardwareAddrLength: 20,
   284  				IPLength:           4,
   285  				Operation:          OperationReply,
   286  				SenderHardwareAddr: iboip1,
   287  				SenderIP:           ip1,
   288  				TargetHardwareAddr: iboip2,
   289  				TargetIP:           ip2,
   290  			},
   291  		},
   292  	}
   293  
   294  	for i, tt := range tests {
   295  		p := new(Packet)
   296  		if err := p.UnmarshalBinary(tt.b); err != nil {
   297  			if want, got := tt.err, err; want != got {
   298  				t.Fatalf("[%02d] test %q, unexpected error: %v != %v",
   299  					i, tt.desc, want, got)
   300  			}
   301  
   302  			continue
   303  		}
   304  
   305  		if want, got := tt.p, p; !reflect.DeepEqual(want, got) {
   306  			t.Fatalf("[%02d] test %q, unexpected Packet bytes:\n- want: %v\n-  got: %v",
   307  				i, tt.desc, want, got)
   308  		}
   309  	}
   310  }
   311  
   312  func Test_parsePacket(t *testing.T) {
   313  	tests := []struct {
   314  		desc string
   315  		buf  []byte
   316  		p    *Packet
   317  		err  error
   318  	}{
   319  		{
   320  			desc: "invalid ethernet frame",
   321  			err:  io.ErrUnexpectedEOF,
   322  		},
   323  		{
   324  			desc: "non-ARP EtherType",
   325  			// Approximation of 14 byte ethernet frame header and
   326  			// 42 byte blank payload (EtherType 0x0000)
   327  			buf: make([]byte, 56),
   328  			err: errInvalidARPPacket,
   329  		},
   330  		{
   331  			desc: "invalid ARP packet",
   332  			buf: append([]byte{
   333  				// Ethernet frame
   334  				0, 0, 0, 0, 0, 0,
   335  				0, 0, 0, 0, 0, 0,
   336  				0x08, 0x06,
   337  				// ARP packet with misleading hardware address length
   338  				0, 0,
   339  				0, 0,
   340  				255, 255, // Misleading hardware address length
   341  			}, make([]byte, 40)...),
   342  			err: io.ErrUnexpectedEOF,
   343  		},
   344  		{
   345  			desc: "OK",
   346  			buf: append([]byte{
   347  				// Ethernet frame
   348  				0xde, 0xad, 0xbe, 0xef, 0xde, 0xad,
   349  				0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
   350  				0x08, 0x06,
   351  				// ARP Packet
   352  				0, 1,
   353  				0x08, 0x06,
   354  				6,
   355  				4,
   356  				0, 2,
   357  				0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
   358  				192, 168, 1, 10,
   359  				0xde, 0xad, 0xbe, 0xef, 0xde, 0xad,
   360  				192, 168, 1, 1,
   361  			}, make([]byte, 40)...),
   362  			p: &Packet{
   363  				HardwareType:       1,
   364  				ProtocolType:       2054,
   365  				HardwareAddrLength: 6,
   366  				IPLength:           4,
   367  				Operation:          OperationReply,
   368  				SenderHardwareAddr: net.HardwareAddr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
   369  				SenderIP:           netip.MustParseAddr("192.168.1.10"),
   370  				TargetHardwareAddr: net.HardwareAddr{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad},
   371  				TargetIP:           netip.MustParseAddr("192.168.1.1"),
   372  			},
   373  		},
   374  	}
   375  
   376  	for i, tt := range tests {
   377  		p, _, err := parsePacket(tt.buf)
   378  		if err != nil {
   379  			if want, got := tt.err, err; want != got {
   380  				t.Fatalf("[%02d] test %q, unexpected error: %v != %v",
   381  					i, tt.desc, want, got)
   382  			}
   383  
   384  			continue
   385  		}
   386  
   387  		if want, got := tt.p, p; !reflect.DeepEqual(want, got) {
   388  			t.Fatalf("[%02d] test %q, unexpected Packet:\n- want: %v\n-  got: %v",
   389  				i, tt.desc, want, got)
   390  		}
   391  	}
   392  }
   393  
   394  // Benchmarks for Packet.MarshalBinary
   395  
   396  func BenchmarkPacketMarshalBinary(b *testing.B) {
   397  	p, err := NewPacket(
   398  		OperationRequest,
   399  		net.HardwareAddr{0xad, 0xbe, 0xef, 0xde, 0xad, 0xde},
   400  		netip.MustParseAddr("192.168.1.10"),
   401  		net.HardwareAddr{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad},
   402  		netip.MustParseAddr("192.168.1.1"),
   403  	)
   404  	if err != nil {
   405  		b.Fatal(err)
   406  	}
   407  
   408  	benchmarkPacketMarshalBinary(b, p)
   409  }
   410  
   411  func benchmarkPacketMarshalBinary(b *testing.B, p *Packet) {
   412  	b.ResetTimer()
   413  	b.ReportAllocs()
   414  	for i := 0; i < b.N; i++ {
   415  		if _, err := p.MarshalBinary(); err != nil {
   416  			b.Fatal(err)
   417  		}
   418  	}
   419  }
   420  
   421  // Benchmarks for Packet.UnmarshalBinary
   422  
   423  func BenchmarkPacketUnmarshalBinary(b *testing.B) {
   424  	p, err := NewPacket(
   425  		OperationRequest,
   426  		net.HardwareAddr{0xad, 0xbe, 0xef, 0xde, 0xad, 0xde},
   427  		netip.MustParseAddr("192.168.1.10"),
   428  		net.HardwareAddr{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad},
   429  		netip.MustParseAddr("192.168.1.1"),
   430  	)
   431  	if err != nil {
   432  		b.Fatal(err)
   433  	}
   434  
   435  	benchmarkPacketUnmarshalBinary(b, p)
   436  }
   437  
   438  func benchmarkPacketUnmarshalBinary(b *testing.B, p *Packet) {
   439  	pb, err := p.MarshalBinary()
   440  	if err != nil {
   441  		b.Fatal(err)
   442  	}
   443  
   444  	b.ResetTimer()
   445  	b.ReportAllocs()
   446  	for i := 0; i < b.N; i++ {
   447  		if err := p.UnmarshalBinary(pb); err != nil {
   448  			b.Fatal(err)
   449  		}
   450  	}
   451  }
   452  

View as plain text