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