Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tools/regression/ethernet/ethermulti/ethermulti.c
48253 views
1
/*-
2
* Copyright (c) 2007 Bruce M. Simpson
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
#include <sys/types.h>
28
#include <sys/socket.h>
29
#include <sys/time.h>
30
#include <sys/ioctl.h>
31
32
#include <net/if.h>
33
#include <net/if_dl.h>
34
#include <net/if_types.h>
35
#include <net/ethernet.h>
36
37
#include <err.h>
38
#include <errno.h>
39
#include <getopt.h>
40
#include <stdio.h>
41
#include <stdlib.h>
42
#include <string.h>
43
#include <unistd.h>
44
45
#include <ifaddrs.h>
46
47
static int dorandom = 0;
48
static int verbose = 0;
49
static char *ifname = NULL;
50
51
/*
52
* The test tool exercises IP-level socket options by interrogating the
53
* getsockopt()/setsockopt() APIs. It does not currently test that the
54
* intended semantics of each option are implemented (i.e., that setting IP
55
* options on the socket results in packets with the desired IP options in
56
* it).
57
*/
58
59
/*
60
* get_socket() is a wrapper function that returns a socket of the specified
61
* type, and created with or without restored root privilege (if running
62
* with a real uid of root and an effective uid of some other user). This
63
* us to test whether the same rights are granted using a socket with a
64
* privileged cached credential vs. a socket with a regular credential.
65
*/
66
#define PRIV_ASIS 0
67
#define PRIV_GETROOT 1
68
static int
69
get_socket_unpriv(int type)
70
{
71
72
return (socket(PF_INET, type, 0));
73
}
74
75
static int
76
get_socket_priv(int type)
77
{
78
uid_t olduid;
79
int sock;
80
81
if (getuid() != 0)
82
errx(-1, "get_sock_priv: running without real uid 0");
83
84
olduid = geteuid();
85
if (seteuid(0) < 0)
86
err(-1, "get_sock_priv: seteuid(0)");
87
88
sock = socket(PF_INET, type, 0);
89
90
if (seteuid(olduid) < 0)
91
err(-1, "get_sock_priv: seteuid(%d)", olduid);
92
93
return (sock);
94
}
95
96
static int
97
get_socket(int type, int priv)
98
{
99
100
if (priv)
101
return (get_socket_priv(type));
102
else
103
return (get_socket_unpriv(type));
104
}
105
106
union sockunion {
107
struct sockaddr_storage ss;
108
struct sockaddr sa;
109
struct sockaddr_dl sdl;
110
};
111
typedef union sockunion sockunion_t;
112
113
static void
114
test_ether_multi(int sock)
115
{
116
struct ifreq ifr;
117
struct sockaddr_dl *dlp;
118
struct ether_addr ea;
119
struct ifmaddrs *ifma, *ifmap;
120
int found;
121
122
/* Choose an 802 multicast address. */
123
if (dorandom) {
124
uint32_t mac4;
125
126
srandomdev();
127
mac4 = random();
128
ea.octet[0] = 0x01;
129
ea.octet[1] = 0x80;
130
ea.octet[2] = ((mac4 >> 24 & 0xFF));
131
ea.octet[3] = ((mac4 >> 16 & 0xFF));
132
ea.octet[4] = ((mac4 >> 8 & 0xFF));
133
ea.octet[5] = (mac4 & 0xFF);
134
} else {
135
struct ether_addr *nep = ether_aton("01:80:DE:FA:CA:7E");
136
ea = *nep;
137
}
138
139
/* Fill out ifreq, and fill out 802 group address. */
140
memset(&ifr, 0, sizeof(struct ifreq));
141
strlcpy(&ifr.ifr_name[0], ifname, IFNAMSIZ);
142
dlp = (struct sockaddr_dl *)&ifr.ifr_addr;
143
memset(dlp, 0, sizeof(struct sockaddr_dl));
144
dlp->sdl_len = sizeof(struct sockaddr_dl);
145
dlp->sdl_family = AF_LINK;
146
dlp->sdl_alen = sizeof(struct ether_addr);
147
memcpy(LLADDR(dlp), &ea, sizeof(struct ether_addr));
148
149
/* Join an 802 group. */
150
if (ioctl(sock, SIOCADDMULTI, &ifr) < 0) {
151
warn("can't add ethernet multicast membership");
152
return;
153
}
154
155
/* Check that we joined the group by calling getifmaddrs(). */
156
found = 0;
157
if (getifmaddrs(&ifmap) != 0) {
158
warn("getifmaddrs()");
159
} else {
160
for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
161
sockunion_t *psa = (sockunion_t *)ifma->ifma_addr;
162
if (ifma->ifma_name == NULL || psa == NULL)
163
continue;
164
165
if (psa->sa.sa_family != AF_LINK ||
166
psa->sdl.sdl_alen != ETHER_ADDR_LEN)
167
continue;
168
169
if (bcmp(LLADDR(&psa->sdl), LLADDR(dlp),
170
ETHER_ADDR_LEN) == 0) {
171
found = 1;
172
break;
173
}
174
}
175
freeifmaddrs(ifmap);
176
}
177
if (!found) {
178
warnx("group membership for %s not returned by getifmaddrs()",
179
ether_ntoa(&ea));
180
}
181
182
/* Fill out ifreq, and fill out 802 group address. */
183
memset(&ifr, 0, sizeof(struct ifreq));
184
strlcpy(&ifr.ifr_name[0], ifname, IFNAMSIZ);
185
dlp = (struct sockaddr_dl *)&ifr.ifr_addr;
186
memset(dlp, 0, sizeof(struct sockaddr_dl));
187
dlp->sdl_len = sizeof(struct sockaddr_dl);
188
dlp->sdl_family = AF_LINK;
189
dlp->sdl_alen = sizeof(struct ether_addr);
190
memcpy(LLADDR(dlp), &ea, sizeof(struct ether_addr));
191
192
/* Leave an 802 group. */
193
if (ioctl(sock, SIOCDELMULTI, &ifr) < 0)
194
warn("can't delete ethernet multicast membership");
195
196
}
197
198
static void
199
testsuite(int priv)
200
{
201
int sock;
202
203
sock = get_socket(SOCK_DGRAM, 0);
204
if (sock == -1)
205
err(-1, "get_socket(SOCK_DGRAM) for test_ether_multi()", priv);
206
test_ether_multi(sock);
207
close(sock);
208
}
209
210
static void
211
usage()
212
{
213
214
fprintf(stderr, "usage: ethermulti -i ifname [-r] [-v]\n");
215
exit(EXIT_FAILURE);
216
}
217
218
int
219
main(int argc, char *argv[])
220
{
221
int ch;
222
223
while ((ch = getopt(argc, argv, "i:rv")) != -1) {
224
switch (ch) {
225
case 'i':
226
ifname = optarg;
227
break;
228
case 'r':
229
dorandom = 1; /* introduce non-determinism */
230
break;
231
case 'v':
232
verbose = 1;
233
break;
234
default:
235
usage();
236
}
237
}
238
if (ifname == NULL)
239
usage();
240
241
printf("1..1\n");
242
if (geteuid() != 0) {
243
errx(1, "Not running as root, can't run tests as non-root");
244
/*NOTREACHED*/
245
} else {
246
fprintf(stderr,
247
"Running tests with ruid %d euid %d sock uid 0\n",
248
getuid(), geteuid());
249
testsuite(PRIV_ASIS);
250
}
251
printf("ok 1 - ethermulti\n");
252
exit(0);
253
}
254
255