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 }