Matt Layher | bfb29a6 | 2021-08-06 16:48:53 -0400 | [diff] [blame] | 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 ( |
Matt Layher | 41cdb87 | 2021-08-18 11:18:44 -0400 | [diff] [blame] | 11 | "bytes" |
| 12 | "net" |
Matt Layher | bfb29a6 | 2021-08-06 16:48:53 -0400 | [diff] [blame] | 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) { |
Matt Layher | bfb29a6 | 2021-08-06 16:48:53 -0400 | [diff] [blame] | 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 | |
Matt Layher | 41cdb87 | 2021-08-18 11:18:44 -0400 | [diff] [blame] | 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 | |
Matt Layher | bfb29a6 | 2021-08-06 16:48:53 -0400 | [diff] [blame] | 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 | } |