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 }