Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tools/regression/netinet/ipsockopt/ipsockopt.c
39491 views
1
/*-
2
* Copyright (c) 2004 Robert N. M. Watson
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
30
#include <netinet/in.h>
31
#include <netinet/in_systm.h>
32
#include <netinet/ip.h>
33
#include <arpa/inet.h>
34
35
#include <err.h>
36
#include <errno.h>
37
#include <getopt.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <unistd.h>
42
43
static int dorandom = 0;
44
static int nmcastgroups = IP_MAX_MEMBERSHIPS;
45
static int verbose = 0;
46
47
/*
48
* The test tool exercises IP-level socket options by interrogating the
49
* getsockopt()/setsockopt() APIs. It does not currently test that the
50
* intended semantics of each option are implemented (i.e., that setting IP
51
* options on the socket results in packets with the desired IP options in
52
* it).
53
*/
54
55
/*
56
* get_socket() is a wrapper function that returns a socket of the specified
57
* type, and created with or without restored root privilege (if running
58
* with a real uid of root and an effective uid of some other user). This
59
* us to test whether the same rights are granted using a socket with a
60
* privileged cached credential vs. a socket with a regular credential.
61
*/
62
#define PRIV_ASIS 0
63
#define PRIV_GETROOT 1
64
static int
65
get_socket_unpriv(int type)
66
{
67
68
return (socket(PF_INET, type, 0));
69
}
70
71
static int
72
get_socket_priv(int type)
73
{
74
uid_t olduid;
75
int sock;
76
77
if (getuid() != 0)
78
errx(-1, "get_sock_priv: running without real uid 0");
79
80
olduid = geteuid();
81
if (seteuid(0) < 0)
82
err(-1, "get_sock_priv: seteuid(0)");
83
84
sock = socket(PF_INET, type, 0);
85
86
if (seteuid(olduid) < 0)
87
err(-1, "get_sock_priv: seteuid(%d)", olduid);
88
89
return (sock);
90
}
91
92
static int
93
get_socket(int type, int priv)
94
{
95
96
if (priv)
97
return (get_socket_priv(type));
98
else
99
return (get_socket_unpriv(type));
100
}
101
102
/*
103
* Exercise the IP_OPTIONS socket option. Confirm the following properties:
104
*
105
* - That there is no initial set of options (length returned is 0).
106
* - That if we set a specific set of options, we can read it back.
107
* - That if we then reset the options, they go away.
108
*
109
* Use a UDP socket for this.
110
*/
111
static void
112
test_ip_options(int sock, const char *socktypename)
113
{
114
u_int32_t new_options, test_options[2];
115
socklen_t len;
116
117
/*
118
* Start off by confirming the default IP options on a socket are to
119
* have no options set.
120
*/
121
len = sizeof(test_options);
122
if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
123
err(-1, "test_ip_options(%s): initial getsockopt()",
124
socktypename);
125
126
if (len != 0)
127
errx(-1, "test_ip_options(%s): initial getsockopt() returned "
128
"%d bytes", socktypename, len);
129
130
#define TEST_MAGIC 0xc34e4212
131
#define NEW_OPTIONS htonl(IPOPT_EOL | (IPOPT_NOP << 8) | (IPOPT_NOP << 16) \
132
| (IPOPT_NOP << 24))
133
134
/*
135
* Write some new options into the socket.
136
*/
137
new_options = NEW_OPTIONS;
138
if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, &new_options,
139
sizeof(new_options)) < 0)
140
err(-1, "test_ip_options(%s): setsockopt(NOP|NOP|NOP|EOL)",
141
socktypename);
142
143
/*
144
* Store some random cruft in a local variable and retrieve the
145
* options to make sure they set. Note that we pass in an array
146
* of u_int32_t's so that if whatever ended up in the option was
147
* larger than what we put in, we find out about it here.
148
*/
149
test_options[0] = TEST_MAGIC;
150
test_options[1] = TEST_MAGIC;
151
len = sizeof(test_options);
152
if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
153
err(-1, "test_ip_options(%s): getsockopt() after set",
154
socktypename);
155
156
/*
157
* Getting the right amount back is important.
158
*/
159
if (len != sizeof(new_options))
160
errx(-1, "test_ip_options(%s): getsockopt() after set "
161
"returned %d bytes of data", socktypename, len);
162
163
/*
164
* One possible failure mode is that the call succeeds but neglects to
165
* copy out the data.
166
*/
167
if (test_options[0] == TEST_MAGIC)
168
errx(-1, "test_ip_options(%s): getsockopt() after set didn't "
169
"return data", socktypename);
170
171
/*
172
* Make sure we get back what we wrote on.
173
*/
174
if (new_options != test_options[0])
175
errx(-1, "test_ip_options(%s): getsockopt() after set "
176
"returned wrong options (%08x, %08x)", socktypename,
177
new_options, test_options[0]);
178
179
/*
180
* Now we reset the value to make sure clearing works.
181
*/
182
if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, NULL, 0) < 0)
183
err(-1, "test_ip_options(%s): setsockopt() to reset",
184
socktypename);
185
186
/*
187
* Make sure it was really cleared.
188
*/
189
test_options[0] = TEST_MAGIC;
190
test_options[1] = TEST_MAGIC;
191
len = sizeof(test_options);
192
if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
193
err(-1, "test_ip_options(%s): getsockopt() after reset",
194
socktypename);
195
196
if (len != 0)
197
errx(-1, "test_ip_options(%s): getsockopt() after reset "
198
"returned %d bytes", socktypename, len);
199
}
200
201
/*
202
* This test checks the behavior of the IP_HDRINCL socket option, which
203
* allows users with privilege to specify the full header on an IP raw
204
* socket. We test that the option can only be used with raw IP sockets, not
205
* with UDP or TCP sockets. We also confirm that the raw socket is only
206
* available to a privileged user (subject to the UID when called). We
207
* confirm that it defaults to off
208
*
209
* Unlike other tests, doesn't use caller-provided socket. Probably should
210
* be fixed.
211
*/
212
static void
213
test_ip_hdrincl(void)
214
{
215
int flag[2], sock;
216
socklen_t len;
217
218
/*
219
* Try to receive or set the IP_HDRINCL flag on a TCP socket.
220
*/
221
sock = socket(PF_INET, SOCK_STREAM, 0);
222
if (sock == -1)
223
err(-1, "test_ip_hdrincl(): socket(SOCK_STREAM)");
224
225
flag[0] = -1;
226
len = sizeof(flag[0]);
227
if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
228
err(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINCL)");
229
230
if (errno != ENOPROTOOPT)
231
errx(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINC) "
232
"returned %d (%s) not ENOPROTOOPT", errno,
233
strerror(errno));
234
235
flag[0] = 1;
236
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
237
== 0)
238
err(-1,"test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
239
"succeeded\n");
240
241
if (errno != ENOPROTOOPT)
242
errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
243
"returned %d (%s) not ENOPROTOOPT\n", errno,
244
strerror(errno));
245
246
close(sock);
247
248
/*
249
* Try to receive or set the IP_HDRINCL flag on a UDP socket.
250
*/
251
sock = socket(PF_INET, SOCK_DGRAM, 0);
252
if (sock == -1)
253
err(-1, "test_ip_hdrincl(): socket(SOCK_DGRAM");
254
255
flag[0] = -1;
256
len = sizeof(flag[0]);
257
if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
258
err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
259
"succeeded\n");
260
261
if (errno != ENOPROTOOPT)
262
errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
263
"returned %d (%s) not ENOPROTOOPT\n", errno,
264
strerror(errno));
265
266
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
267
== 0)
268
err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
269
"succeeded\n");
270
271
if (errno != ENOPROTOOPT)
272
errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
273
"returned %d (%s) not ENOPROTOOPT\n", errno,
274
strerror(errno));
275
276
close(sock);
277
278
/*
279
* Now try on a raw socket. Access ontrol should prevent non-root
280
* users from creating the raw socket, so check that here based on
281
* geteuid(). If we're non-root, we just return assuming the socket
282
* create fails since the remainder of the tests apply only on a raw
283
* socket.
284
*/
285
sock = socket(PF_INET, SOCK_RAW, 0);
286
if (geteuid() != 0) {
287
if (sock != -1)
288
errx(-1, "test_ip_hdrincl: created raw socket as "
289
"uid %d", geteuid());
290
return;
291
}
292
if (sock == -1)
293
err(-1, "test_ip_hdrincl(): socket(PF_INET, SOCK_RAW)");
294
295
/*
296
* Make sure the initial value of the flag is 0 (disabled).
297
*/
298
flag[0] = -1;
299
flag[1] = -1;
300
len = sizeof(flag);
301
if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
302
err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on raw "
303
"socket");
304
305
if (len != sizeof(flag[0]))
306
errx(-1, "test_ip_hdrincl(): %d bytes returned on "
307
"initial get\n", len);
308
309
if (flag[0] != 0)
310
errx(-1, "test_ip_hdrincl(): initial flag value of %d\n",
311
flag[0]);
312
313
/*
314
* Enable the IP_HDRINCL flag.
315
*/
316
flag[0] = 1;
317
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
318
< 0)
319
err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 1)");
320
321
/*
322
* Check that the IP_HDRINCL flag was set.
323
*/
324
flag[0] = -1;
325
flag[1] = -1;
326
len = sizeof(flag);
327
if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
328
err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "
329
"set");
330
331
if (flag[0] == 0)
332
errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "
333
"after set had flag of %d\n", flag[0]);
334
335
#define HISTORICAL_INP_HDRINCL 8
336
if (flag[0] != HISTORICAL_INP_HDRINCL)
337
warnx("test_ip_hdrincl(): WARNING: getsockopt(IP_H"
338
"DRINCL) after set had non-historical value of %d\n",
339
flag[0]);
340
341
/*
342
* Reset the IP_HDRINCL flag to 0.
343
*/
344
flag[0] = 0;
345
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
346
< 0)
347
err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 0)");
348
349
/*
350
* Check that the IP_HDRINCL flag was reset to 0.
351
*/
352
flag[0] = -1;
353
flag[1] = -1;
354
len = sizeof(flag);
355
if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
356
err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "
357
"reset");
358
359
if (flag[0] != 0)
360
errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "
361
"after set had flag of %d\n", flag[0]);
362
363
close(sock);
364
}
365
366
/*
367
* As with other non-int or larger sized socket options, the IP_TOS and
368
* IP_TTL fields in kernel is stored as an 8-bit value, reflecting the IP
369
* header fields, but useful I/O to the field occurs using 32-bit integers.
370
* The FreeBSD kernel will permit writes from variables at least an int in
371
* size (and ignore additional bytes), and will permit a read to buffers 1
372
* byte or larger (but depending on endianness, may truncate out useful
373
* values if the caller provides less room).
374
*
375
* Given the limitations of the API, use a UDP socket to confirm that the
376
* following are true:
377
*
378
* - We can read the IP_TOS/IP_TTL options.
379
* - The initial value of the TOS option is 0, TTL is 64.
380
* - That if we provide more than 32 bits of storage, we get back only 32
381
* bits of data.
382
* - When we set it to a non-zero value expressible with a u_char, we can
383
* read that value back.
384
* - When we reset it back to zero, we can read it as 0.
385
* - When we set it to a value >255, the value is truncated to something less
386
* than 255.
387
*/
388
static void
389
test_ip_uchar(int sock, const char *socktypename, int option,
390
const char *optionname, int initial)
391
{
392
int val[2];
393
socklen_t len;
394
395
/*
396
* Check that the initial value is 0, and that the size is one
397
* u_char;
398
*/
399
val[0] = -1;
400
val[1] = -1;
401
len = sizeof(val);
402
if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
403
err(-1, "test_ip_uchar(%s, %s): initial getsockopt()",
404
socktypename, optionname);
405
406
if (len != sizeof(val[0]))
407
errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "
408
"returned %d bytes", socktypename, optionname, len);
409
410
if (val[0] == -1)
411
errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() didn't "
412
"return data", socktypename, optionname);
413
414
if (val[0] != initial)
415
errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "
416
"returned value of %d, not %d", socktypename, optionname,
417
val[0], initial);
418
419
/*
420
* Set the field to a valid value.
421
*/
422
val[0] = 128;
423
val[1] = -1;
424
if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
425
err(-1, "test_ip_uchar(%s, %s): setsockopt(128)",
426
socktypename, optionname);
427
428
/*
429
* Check that when we read back the field, we get the same value.
430
*/
431
val[0] = -1;
432
val[1] = -1;
433
len = sizeof(val);
434
if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
435
err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
436
"128", socktypename, optionname);
437
438
if (len != sizeof(val[0]))
439
errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
440
"128 returned %d bytes", socktypename, optionname, len);
441
442
if (val[0] == -1)
443
errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
444
"128 didn't return data", socktypename, optionname);
445
446
if (val[0] != 128)
447
errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
448
"128 returned %d", socktypename, optionname, val[0]);
449
450
/*
451
* Reset the value to 0, check that it was reset.
452
*/
453
val[0] = 0;
454
val[1] = 0;
455
if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
456
err(-1, "test_ip_uchar(%s, %s): setsockopt() to reset from "
457
"128", socktypename, optionname);
458
459
if (len != sizeof(val[0]))
460
errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
461
"from 128 returned %d bytes", socktypename, optionname,
462
len);
463
464
if (val[0] == -1)
465
errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
466
"from 128 didn't return data", socktypename, optionname);
467
468
if (val[0] != 0)
469
errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
470
"from 128 returned %d", socktypename, optionname,
471
val[0]);
472
473
/*
474
* Set the value to something out of range and check that it comes
475
* back truncated, or that we get EINVAL back. Traditional u_char
476
* IP socket options truncate, but newer ones (such as multicast
477
* socket options) will return EINVAL.
478
*/
479
val[0] = 32000;
480
val[1] = -1;
481
if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0) {
482
/*
483
* EINVAL is a fine outcome, no need to run the truncation
484
* tests.
485
*/
486
if (errno == EINVAL)
487
return;
488
err(-1, "test_ip_uchar(%s, %s): getsockopt(32000)",
489
socktypename, optionname);
490
}
491
492
val[0] = -1;
493
val[1] = -1;
494
len = sizeof(val);
495
if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
496
err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
497
"32000", socktypename, optionname);
498
499
if (len != sizeof(val[0]))
500
errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
501
"32000 returned %d bytes", socktypename, optionname,
502
len);
503
504
if (val[0] == -1)
505
errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
506
"32000 didn't return data", socktypename, optionname);
507
508
if (val[0] == 32000)
509
errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
510
"32000 returned 32000: failed to truncate", socktypename,
511
optionname);
512
}
513
514
/*
515
* Generic test for a boolean socket option. Caller provides the option
516
* number, string name, expected default (initial) value, and whether or not
517
* the option is root-only. For each option, test:
518
*
519
* - That we can read the option.
520
* - That the initial value is as expected.
521
* - That we can modify the value.
522
* - That on modification, the new value can be read back.
523
* - That we can reset the value.
524
* - that on reset, the new value can be read back.
525
*/
526
#define BOOLEAN_ANYONE 1
527
#define BOOLEAN_ROOTONLY 1
528
static void
529
test_ip_boolean(int sock, const char *socktypename, int option,
530
char *optionname, int initial, int rootonly)
531
{
532
int newvalue, val[2];
533
socklen_t len;
534
535
/*
536
* The default for a boolean might be true or false. If it's false,
537
* we will try setting it to true (but using a non-1 value of true).
538
* If it's true, we'll set it to false.
539
*/
540
if (initial == 0)
541
newvalue = 0xff;
542
else
543
newvalue = 0;
544
545
val[0] = -1;
546
val[1] = -1;
547
len = sizeof(val);
548
if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
549
err(-1, "test_ip_boolean: initial getsockopt()");
550
551
if (len != sizeof(val[0]))
552
errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
553
"returned %d bytes", socktypename, optionname, len);
554
555
if (val[0] == -1)
556
errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
557
"didn't return data", socktypename, optionname);
558
559
if (val[0] != initial)
560
errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
561
"returned %d (expected %d)", socktypename, optionname,
562
val[0], initial);
563
564
/*
565
* Set the socket option to a new non-default value.
566
*/
567
if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
568
< 0)
569
err(-1, "test_ip_boolean(%s, %s): setsockopt() to %d",
570
socktypename, optionname, newvalue);
571
572
/*
573
* Read the value back and see if it is not the default (note: will
574
* not be what we set it to, as we set it to 0xff above).
575
*/
576
val[0] = -1;
577
val[1] = -1;
578
len = sizeof(val);
579
if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
580
err(-1, "test_ip_boolean(%s, %s): getsockopt() after set to "
581
"%d", socktypename, optionname, newvalue);
582
583
if (len != sizeof(val[0]))
584
errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
585
"to %d returned %d bytes", socktypename, optionname,
586
newvalue, len);
587
588
if (val[0] == -1)
589
errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
590
"to %d didn't return data", socktypename, optionname,
591
newvalue);
592
593
/*
594
* If we set it to true, check for '1', otherwise '0.
595
*/
596
if (val[0] != (newvalue ? 1 : 0))
597
errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
598
"to %d returned %d", socktypename, optionname, newvalue,
599
val[0]);
600
601
/*
602
* Reset to initial value.
603
*/
604
newvalue = initial;
605
if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
606
< 0)
607
err(-1, "test_ip_boolean(%s, %s): setsockopt() to reset",
608
socktypename, optionname);
609
610
/*
611
* Check reset version.
612
*/
613
val[0] = -1;
614
val[1] = -1;
615
len = sizeof(val);
616
if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
617
err(-1, "test_ip_boolean(%s, %s): getsockopt() after reset",
618
socktypename, optionname);
619
620
if (len != sizeof(val[0]))
621
errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
622
"returned %d bytes", socktypename, optionname, len);
623
624
if (val[0] == -1)
625
errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
626
"didn't return data", socktypename, optionname);
627
628
if (val[0] != newvalue)
629
errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
630
"returned %d", socktypename, optionname, newvalue);
631
}
632
633
/*
634
* Test the IP_ADD_MEMBERSHIP socket option, and the dynamic allocator
635
* for the imo_membership vector which now hangs off struct ip_moptions.
636
* We then call IP_DROP_MEMBERSHIP for each group so joined.
637
*/
638
static void
639
test_ip_multicast_membership(int sock, const char *socktypename)
640
{
641
char addrbuf[16];
642
struct ip_mreq mreq;
643
uint32_t basegroup;
644
uint16_t i;
645
int sotype;
646
socklen_t sotypelen;
647
648
sotypelen = sizeof(sotype);
649
if (getsockopt(sock, SOL_SOCKET, SO_TYPE, &sotype, &sotypelen) < 0)
650
err(-1, "test_ip_multicast_membership(%s): so_type getsockopt()",
651
socktypename);
652
/*
653
* Do not perform the test for SOCK_STREAM sockets, as this makes
654
* no sense.
655
*/
656
if (sotype == SOCK_STREAM)
657
return;
658
/*
659
* The 224/8 range is administratively scoped and has special meaning,
660
* therefore it is not used for this test.
661
* If we were not told to be non-deterministic:
662
* Join multicast groups from 238.1.1.0 up to nmcastgroups.
663
* Otherwise, pick a multicast group ID in subnet 238/5 with 11 random
664
* bits in the middle, and join groups in linear order up to nmcastgroups.
665
*/
666
if (dorandom) {
667
/* be non-deterministic (for interactive operation; a fuller test) */
668
srandomdev();
669
basegroup = 0xEE000000; /* 238.0.0.0 */
670
basegroup |= ((random() % ((1 << 11) - 1)) << 16); /* 11 bits */
671
} else {
672
/* be deterministic (for automated operation) */
673
basegroup = 0xEE010100; /* 238.1.1.0 */
674
}
675
/*
676
* Join the multicast group(s) on the default multicast interface;
677
* this usually maps to the interface to which the default
678
* route is pointing.
679
*/
680
for (i = 1; i < nmcastgroups+1; i++) {
681
mreq.imr_multiaddr.s_addr = htonl((basegroup + i));
682
mreq.imr_interface.s_addr = INADDR_ANY;
683
inet_ntop(AF_INET, &mreq.imr_multiaddr, addrbuf, sizeof(addrbuf));
684
if (verbose)
685
fprintf(stderr, "IP_ADD_MEMBERSHIP %s INADDR_ANY\n", addrbuf);
686
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
687
sizeof(mreq)) < 0) {
688
err(-1,
689
"test_ip_multicast_membership(%d, %s): failed IP_ADD_MEMBERSHIP (%s, %s)",
690
sock, socktypename, addrbuf, "INADDR_ANY");
691
}
692
}
693
for (i = 1; i < nmcastgroups+1; i++) {
694
mreq.imr_multiaddr.s_addr = htonl((basegroup + i));
695
mreq.imr_interface.s_addr = INADDR_ANY;
696
inet_ntop(AF_INET, &mreq.imr_multiaddr, addrbuf, sizeof(addrbuf));
697
if (verbose)
698
fprintf(stderr, "IP_DROP_MEMBERSHIP %s INADDR_ANY\n", addrbuf);
699
if (setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq,
700
sizeof(mreq)) < 0) {
701
err(-1,
702
"test_ip_multicast_membership(%d, %s): failed IP_DROP_MEMBERSHIP (%s, %s)",
703
sock, socktypename, addrbuf, "INADDR_ANY");
704
}
705
}
706
}
707
708
/*
709
* XXX: For now, nothing here.
710
*/
711
static void
712
test_ip_multicast_if(int sock, const char *socktypename)
713
{
714
715
/*
716
* It's probably worth trying INADDR_ANY and INADDR_LOOPBACK here
717
* to see what happens.
718
*/
719
}
720
721
/*
722
* XXX: For now, nothing here.
723
*/
724
static void
725
test_ip_multicast_vif(int sock, const char *socktypename)
726
{
727
728
/*
729
* This requires some knowledge of the number of virtual interfaces,
730
* and what is valid.
731
*/
732
}
733
734
static void
735
testsuite(int priv)
736
{
737
const char *socktypenameset[] = {"SOCK_DGRAM", "SOCK_STREAM",
738
"SOCK_RAW"};
739
int socktypeset[] = {SOCK_DGRAM, SOCK_STREAM, SOCK_RAW};
740
const char *socktypename;
741
int i, sock, socktype;
742
743
test_ip_hdrincl();
744
745
for (i = 0; i < sizeof(socktypeset)/sizeof(int); i++) {
746
socktype = socktypeset[i];
747
socktypename = socktypenameset[i];
748
749
/*
750
* If we can't acquire root privilege, we can't open raw
751
* sockets, so don't actually try.
752
*/
753
if (getuid() != 0 && socktype == SOCK_RAW)
754
continue;
755
if (geteuid() != 0 && !priv && socktype == SOCK_RAW)
756
continue;
757
758
/*
759
* XXXRW: On 5.3, this seems not to work for SOCK_RAW.
760
*/
761
sock = get_socket(socktype, priv);
762
if (sock == -1)
763
err(-1, "get_socket(%s, %d) for test_ip_uchar(IP_TOS)",
764
socktypename, priv);
765
test_ip_uchar(sock, socktypename, IP_TOS, "IP_TOS", 0);
766
close(sock);
767
768
sock = get_socket(socktype, priv);
769
if (sock == -1)
770
err(-1, "get_socket(%s %d) for test_ip_uchar(IP_TTL)",
771
socktypename, priv);
772
test_ip_uchar(sock, socktypename, IP_TTL, "IP_TTL", 64);
773
close(sock);
774
775
sock = get_socket(socktype, priv);
776
if (sock == -1)
777
err(-1, "get_socket(%s, %d) for test_ip_boolean"
778
"(IP_RECVOPTS)", socktypename, priv);
779
test_ip_boolean(sock, socktypename, IP_RECVOPTS,
780
"IP_RECVOPTS", 0, BOOLEAN_ANYONE);
781
close(sock);
782
783
sock = get_socket(socktype, priv);
784
if (sock == -1)
785
err(-1, "get_socket(%s, %d) for test_ip_boolean"
786
"(IP_RECVRETOPTS)", socktypename, priv);
787
test_ip_boolean(sock, socktypename, IP_RECVRETOPTS,
788
"IP_RECVRETOPTS", 0, BOOLEAN_ANYONE);
789
close(sock);
790
791
sock = get_socket(socktype, priv);
792
if (sock == -1)
793
err(-1, "get_socket(%s, %d) for test_ip_boolean"
794
"(IP_RECVDSTADDR)", socktypename, priv);
795
test_ip_boolean(sock, socktypename, IP_RECVDSTADDR,
796
"IP_RECVDSTADDR", 0, BOOLEAN_ANYONE);
797
close(sock);
798
799
sock = get_socket(socktype, priv);
800
if (sock == -1)
801
err(-1, "get_socket(%s, %d) for test_ip_boolean"
802
"(IP_RECVTTL)", socktypename, priv);
803
test_ip_boolean(sock, socktypename, IP_RECVTTL, "IP_RECVTTL",
804
0, BOOLEAN_ANYONE);
805
close(sock);
806
807
sock = get_socket(socktype, priv);
808
if (sock == -1)
809
err(-1, "get_socket(%s, %d) for test_ip_boolean"
810
"(IP_RECVIF)", socktypename, priv);
811
test_ip_boolean(sock, socktypename, IP_RECVIF, "IP_RECVIF",
812
0, BOOLEAN_ANYONE);
813
close(sock);
814
815
sock = get_socket(socktype, priv);
816
if (sock == -1)
817
err(-1, "get_socket(%s, %d) for test_ip_boolean"
818
"(IP_FAITH)", socktypename, priv);
819
test_ip_boolean(sock, socktypename, IP_FAITH, "IP_FAITH", 0,
820
BOOLEAN_ANYONE);
821
close(sock);
822
823
sock = get_socket(socktype, priv);
824
if (sock == -1)
825
err(-1, "get_socket(%s, %d) for test_ip_boolean"
826
"(IP_ONESBCAST)", socktypename, priv);
827
test_ip_boolean(sock, socktypename, IP_ONESBCAST,
828
"IP_ONESBCAST", 0, BOOLEAN_ANYONE);
829
close(sock);
830
831
/*
832
* Test the multicast TTL exactly as we would the regular
833
* TTL, only expect a different default.
834
*/
835
sock = get_socket(socktype, priv);
836
if (sock == -1)
837
err(-1, "get_socket(%s, %d) for IP_MULTICAST_TTL",
838
socktypename, priv);
839
test_ip_uchar(sock, socktypename, IP_MULTICAST_TTL,
840
"IP_MULTICAST_TTL", 1);
841
close(sock);
842
843
/*
844
* The multicast loopback flag can be tested using our
845
* boolean tester, but only because the FreeBSD API is a bit
846
* more flexible than earlir APIs and will accept an int as
847
* well as a u_char. Loopback is enabled by default.
848
*/
849
sock = get_socket(socktype, priv);
850
if (sock == -1)
851
err(-1, "get_socket(%s, %d) for IP_MULTICAST_LOOP",
852
socktypename, priv);
853
test_ip_boolean(sock, socktypename, IP_MULTICAST_LOOP,
854
"IP_MULTICAST_LOOP", 1, BOOLEAN_ANYONE);
855
close(sock);
856
857
sock = get_socket(socktype, priv);
858
if (sock == -1)
859
err(-1, "get_socket(%s, %d) for test_ip_options",
860
socktypename, priv);
861
//test_ip_options(sock, socktypename);
862
close(sock);
863
864
sock = get_socket(socktype, priv);
865
if (sock == -1)
866
err(-1, "get_socket(%s, %d) for test_ip_options",
867
socktypename, priv);
868
test_ip_multicast_membership(sock, socktypename);
869
close(sock);
870
871
test_ip_multicast_if(0, NULL);
872
test_ip_multicast_vif(0, NULL);
873
/*
874
* XXX: Still need to test:
875
* IP_PORTRANGE
876
* IP_IPSEC_POLICY?
877
*/
878
}
879
}
880
881
static void
882
usage()
883
{
884
885
fprintf(stderr, "usage: ipsockopt [-M ngroups] [-r] [-v]\n");
886
exit(EXIT_FAILURE);
887
}
888
889
/*
890
* Very simply exercise that we can get and set each option. If we're running
891
* as root, run it also as nobody. If not as root, complain about that.
892
*/
893
int
894
main(int argc, char *argv[])
895
{
896
int ch;
897
898
while ((ch = getopt(argc, argv, "M:rv")) != -1) {
899
switch (ch) {
900
case 'M':
901
nmcastgroups = atoi(optarg);
902
break;
903
case 'r':
904
dorandom = 1; /* introduce non-determinism */
905
break;
906
case 'v':
907
verbose = 1;
908
break;
909
default:
910
usage();
911
}
912
}
913
914
printf("1..1\n");
915
916
if (geteuid() != 0) {
917
warnx("Not running as root, can't run tests as root");
918
fprintf(stderr, "\n");
919
fprintf(stderr,
920
"Running tests with uid %d sock uid %d\n", geteuid(),
921
geteuid());
922
testsuite(PRIV_ASIS);
923
} else {
924
fprintf(stderr,
925
"Running tests with ruid %d euid %d sock uid 0\n",
926
getuid(), geteuid());
927
testsuite(PRIV_ASIS);
928
if (seteuid(65534) != 0)
929
err(-1, "seteuid(65534)");
930
fprintf(stderr,
931
"Running tests with ruid %d euid %d sock uid 65534\n",
932
getuid(), geteuid());
933
testsuite(PRIV_ASIS);
934
fprintf(stderr,
935
"Running tests with ruid %d euid %d sock uid 0\n",
936
getuid(), geteuid());
937
testsuite(PRIV_GETROOT);
938
}
939
printf("ok 1 - ipsockopt\n");
940
exit(0);
941
}
942
943