blob: b81a8b633f5619d0f2dec7ce88dc91a5de2a9d5b [file] [log] [blame]
Matt Layherbfb29a62021-08-06 16:48:53 -04001// 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
8package unix
9
10import (
Matt Layher41cdb872021-08-18 11:18:44 -040011 "bytes"
12 "net"
Matt Layherbfb29a62021-08-06 16:48:53 -040013 "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.
19type ifreqUnion = [len(ifreq{}.Ifru)]byte
20
21func 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
28func 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
41func TestIfreqName(t *testing.T) {
Matt Layherbfb29a62021-08-06 16:48:53 -040042 // 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
49func 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 Layher41cdb872021-08-18 11:18:44 -040068func 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 Layherbfb29a62021-08-06 16:48:53 -0400110func 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
134func 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.
163const ifreqName = "eth0"
164
165// testIfreq returns an Ifreq with a populated interface name.
166func 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}