github.com/neonyo/sys@v0.0.0-20230720094341-b1ee14be3ce8/unix/ifreq_linux_test.go (about)

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build linux
     6  // +build linux
     7  
     8  package unix
     9  
    10  import (
    11  	"bytes"
    12  	"net"
    13  	"testing"
    14  	"unsafe"
    15  )
    16  
    17  // An ifreqUnion is shorthand for a byte array matching the
    18  // architecture-dependent size of an ifreq's union field.
    19  type ifreqUnion = [len(ifreq{}.Ifru)]byte
    20  
    21  func TestNewIfreq(t *testing.T) {
    22  	// Interface name too long.
    23  	if _, err := NewIfreq("abcdefghijklmnop"); err != EINVAL {
    24  		t.Fatalf("expected error EINVAL, but got: %v", err)
    25  	}
    26  }
    27  
    28  func TestIfreqSize(t *testing.T) {
    29  	// Ensure ifreq (generated) and Ifreq/ifreqData (hand-written to create a
    30  	// safe wrapper and store a pointer field) are identical in size.
    31  	want := unsafe.Sizeof(ifreq{})
    32  	if got := unsafe.Sizeof(Ifreq{}); want != got {
    33  		t.Fatalf("unexpected Ifreq size: got: %d, want: %d", got, want)
    34  	}
    35  
    36  	if got := unsafe.Sizeof(ifreqData{}); want != got {
    37  		t.Fatalf("unexpected IfreqData size: got: %d, want: %d", got, want)
    38  	}
    39  }
    40  
    41  func TestIfreqName(t *testing.T) {
    42  	// Valid ifreq, expect the hard-coded testIfreq name.
    43  	ifr := testIfreq(t)
    44  	if want, got := ifreqName, ifr.Name(); want != got {
    45  		t.Fatalf("unexpected ifreq name: got: %q, want: %q", got, want)
    46  	}
    47  }
    48  
    49  func TestIfreqWithData(t *testing.T) {
    50  	ifr := testIfreq(t)
    51  
    52  	// Store pointer data in the ifreq so we can retrieve it and cast back later
    53  	// for comparison.
    54  	want := [5]byte{'h', 'e', 'l', 'l', 'o'}
    55  	ifrd := ifr.withData(unsafe.Pointer(&want[0]))
    56  
    57  	// Ensure the memory of the original Ifreq was not modified by SetData.
    58  	if ifr.raw.Ifru != (ifreqUnion{}) {
    59  		t.Fatalf("ifreq was unexpectedly modified: % #x", ifr.raw.Ifru)
    60  	}
    61  
    62  	got := *(*[5]byte)(ifrd.data)
    63  	if want != got {
    64  		t.Fatalf("unexpected ifreq data bytes:\n got: % #x\nwant: % #x", got, want)
    65  	}
    66  }
    67  
    68  func TestIfreqInet4Addr(t *testing.T) {
    69  	ifr := testIfreq(t)
    70  	in := net.IPv4(192, 0, 2, 1).To4()
    71  	if err := ifr.SetInet4Addr(in); err != nil {
    72  		t.Fatalf("failed to set ifreq IPv4 address: %v", err)
    73  	}
    74  
    75  	// Store fixed offset data (AF_INET, IPv4 address) within underlying
    76  	// sockaddr bytes. Everything else should be zeroed.
    77  	want := ifreqUnion{4: 192, 5: 0, 6: 2, 7: 1}
    78  	if isBigEndian {
    79  		want[0] = 0x00
    80  		want[1] = 0x02
    81  	} else {
    82  		want[0] = 0x02
    83  		want[1] = 0x00
    84  	}
    85  
    86  	if got := ifr.raw.Ifru; want != got {
    87  		t.Fatalf("unexpected ifreq sockaddr bytes:\n got: % #x\nwant: % #x", got, want)
    88  	}
    89  
    90  	got, err := ifr.Inet4Addr()
    91  	if err != nil {
    92  		t.Fatalf("failed to get ifreq IPv4 address: %v", err)
    93  	}
    94  	if !bytes.Equal(in, got) {
    95  		t.Fatalf("unexpected ifreq IPv4 address:\n got: % #x\nwant: % #x", got, in)
    96  	}
    97  
    98  	// Invalid input, wrong length.
    99  	if err := ifr.SetInet4Addr([]byte{0xff}); err == nil {
   100  		t.Fatal("expected an error setting invalid IPv4 address, but none occurred")
   101  	}
   102  
   103  	// Invalid output, AF_INET is only set by SetInet4Addr input.
   104  	ifr.SetUint32(0xffffffff)
   105  	if _, err := ifr.Inet4Addr(); err == nil {
   106  		t.Fatal("expected an error getting invalid IPv4 address, but none occurred")
   107  	}
   108  }
   109  
   110  func TestIfreqUint16(t *testing.T) {
   111  	ifr := testIfreq(t)
   112  	const in = 0x0102
   113  	ifr.SetUint16(in)
   114  
   115  	// The layout of the bytes depends on the machine's endianness.
   116  	var want ifreqUnion
   117  	if isBigEndian {
   118  		want[0] = 0x01
   119  		want[1] = 0x02
   120  	} else {
   121  		want[0] = 0x02
   122  		want[1] = 0x01
   123  	}
   124  
   125  	if got := ifr.raw.Ifru; want != got {
   126  		t.Fatalf("unexpected ifreq uint16 bytes:\n got: % #x\nwant: % #x", got, want)
   127  	}
   128  
   129  	if got := ifr.Uint16(); in != got {
   130  		t.Fatalf("unexpected ifreq uint16: got: %d, want: %d", got, in)
   131  	}
   132  }
   133  
   134  func TestIfreqUint32(t *testing.T) {
   135  	ifr := testIfreq(t)
   136  	const in = 0x01020304
   137  	ifr.SetUint32(in)
   138  
   139  	// The layout of the bytes depends on the machine's endianness.
   140  	var want ifreqUnion
   141  	if isBigEndian {
   142  		want[0] = 0x01
   143  		want[1] = 0x02
   144  		want[2] = 0x03
   145  		want[3] = 0x04
   146  	} else {
   147  		want[0] = 0x04
   148  		want[1] = 0x03
   149  		want[2] = 0x02
   150  		want[3] = 0x01
   151  	}
   152  
   153  	if got := ifr.raw.Ifru; want != got {
   154  		t.Fatalf("unexpected ifreq uint32 bytes:\n got: % #x\nwant: % #x", got, want)
   155  	}
   156  
   157  	if got := ifr.Uint32(); in != got {
   158  		t.Fatalf("unexpected ifreq uint32: got: %d, want: %d", got, in)
   159  	}
   160  }
   161  
   162  // ifreqName is a hard-coded name for testIfreq.
   163  const ifreqName = "eth0"
   164  
   165  // testIfreq returns an Ifreq with a populated interface name.
   166  func testIfreq(t *testing.T) *Ifreq {
   167  	t.Helper()
   168  
   169  	ifr, err := NewIfreq(ifreqName)
   170  	if err != nil {
   171  		t.Fatalf("failed to create ifreq: %v", err)
   172  	}
   173  
   174  	return ifr
   175  }