Serenity Operating System
1/*
2 * Copyright (c) 2020, the SerenityOS developers
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 are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/Function.h>
28#include <AK/IPv4Address.h>
29#include <net/if.h>
30#include <netinet/in.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <sys/socket.h>
35
36void test_invalid(int);
37void test_no_route(int);
38void test_valid(int);
39void test_send(int);
40
41void test(AK::Function<void(int)> test_fn)
42{
43
44 int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
45 if (fd < 0) {
46 perror("socket");
47 return;
48 }
49
50 test_fn(fd);
51
52 // be a responsible boi
53 close(fd);
54}
55
56auto main() -> int
57{
58 test(test_invalid);
59 test(test_valid);
60 test(test_no_route);
61 test(test_send);
62}
63
64void test_invalid(int fd)
65{
66 // bind to an interface that does not exist
67 char buf[IFNAMSIZ];
68 socklen_t buflen = IFNAMSIZ;
69 memcpy(buf, "foodev", 7);
70
71 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, buf, buflen) < 0) {
72 perror("setsockopt(SO_BINDTODEVICE) :: invalid (Should fail with ENODEV)");
73 puts("PASS invalid");
74 } else {
75 puts("FAIL invalid");
76 }
77}
78
79void test_valid(int fd)
80{
81 // bind to an interface that exists
82 char buf[IFNAMSIZ];
83 socklen_t buflen = IFNAMSIZ;
84 memcpy(buf, "loop0", 6);
85
86 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, buf, buflen) < 0) {
87 perror("setsockopt(SO_BINDTODEVICE) :: valid");
88 puts("FAIL valid");
89 } else {
90 puts("PASS valid");
91 }
92}
93
94void test_no_route(int fd)
95{
96 // bind to an interface that cannot deliver
97 char buf[IFNAMSIZ];
98 socklen_t buflen = IFNAMSIZ;
99 memcpy(buf, "loop0", 6);
100
101 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, buf, buflen) < 0) {
102 perror("setsockopt(SO_BINDTODEVICE) :: no_route");
103 puts("FAIL no_route");
104 return;
105 }
106 sockaddr_in sin;
107 memset(&sin, 0, sizeof(sin));
108
109 sin.sin_addr.s_addr = IPv4Address { 10, 0, 2, 15 }.to_u32();
110 sin.sin_port = 8080;
111 sin.sin_family = AF_INET;
112
113 if (bind(fd, (sockaddr*)&sin, sizeof(sin)) < 0) {
114 perror("bind() :: no_route");
115 puts("FAIL no_route");
116 return;
117 }
118
119 if (sendto(fd, "TEST", 4, 0, (sockaddr*)&sin, sizeof(sin)) < 0) {
120 perror("sendto() :: no_route (Should fail with EHOSTUNREACH)");
121 puts("PASS no_route");
122 } else
123 puts("FAIL no_route");
124}
125
126void test_send(int fd)
127{
128 // bind to an interface that cannot deliver
129 char buf[IFNAMSIZ];
130 socklen_t buflen = IFNAMSIZ;
131 memcpy(buf, "e1k0", 5);
132
133 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, buf, buflen) < 0) {
134 perror("setsockopt(SO_BINDTODEVICE) :: send");
135 puts("FAIL send");
136 return;
137 }
138 sockaddr_in sin;
139 memset(&sin, 0, sizeof(sin));
140
141 sin.sin_addr.s_addr = IPv4Address { 10, 0, 2, 15 }.to_u32();
142 sin.sin_port = 8080;
143 sin.sin_family = AF_INET;
144
145 if (bind(fd, (sockaddr*)&sin, sizeof(sin)) < 0) {
146 perror("bind() :: send");
147 puts("FAIL send");
148 return;
149 }
150
151 if (sendto(fd, "TEST", 4, 0, (sockaddr*)&sin, sizeof(sin)) < 0) {
152 perror("sendto() :: send");
153 puts("FAIL send");
154 return;
155 }
156 puts("PASS send");
157}