1
2 #include <errno.h>
3 #include <netdb.h>
4 #include <net/if.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/ioctl.h>
9 #include <sys/socket.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 #include <initializer_list>
14
usage(const char * program)15 static void usage(const char* program) {
16 fprintf(stderr, "Usage: %s [-s|-c|-b] <ip> <port>\n", program);
17 }
18
19 enum class Mode {
20 Bridge,
21 Client,
22 Server,
23 };
24
resolve(const char * name,const char * port,struct addrinfo ** addrs)25 bool resolve(const char* name, const char* port, struct addrinfo** addrs) {
26 struct addrinfo hints;
27 memset(&hints, 0, sizeof(hints));
28 hints.ai_family = AF_UNSPEC;
29 hints.ai_socktype = SOCK_DGRAM;
30
31 int res = ::getaddrinfo(name, port, &hints, addrs);
32 if (res != 0) {
33 fprintf(stderr, "ERROR: Unable to resolve '%s' and port '%s': %s\n",
34 name, port, gai_strerror(res));
35 return false;
36 }
37 return true;
38 }
39
runClient(struct addrinfo * addrs)40 int runClient(struct addrinfo* addrs) {
41 int fd = -1;
42 for (struct addrinfo* addr = addrs; addr != nullptr; addr = addr->ai_next) {
43 fd = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
44 if (fd < 0) {
45 continue;
46 }
47 if (::connect(fd, addr->ai_addr, addr->ai_addrlen) == 0) {
48 break;
49 }
50 ::close(fd);
51 }
52 ::freeaddrinfo(addrs);
53 if (fd < 0) {
54 fprintf(stderr, "Unable to connect to server\n");
55 return 1;
56 }
57 if (::send(fd, "boop", 4, 0) != 4) {
58 ::close(fd);
59 fprintf(stderr, "Failed to send message to server\n");
60 return 1;
61 }
62 ::close(fd);
63 return 0;
64 }
65
runServer(struct addrinfo * addrs)66 int runServer(struct addrinfo* addrs) {
67 int fd = -1;
68 for (struct addrinfo* addr = addrs; addr != nullptr; addr = addr->ai_next) {
69 fd = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
70 if (fd < 0) {
71 continue;
72 }
73 if (::bind(fd, addr->ai_addr, addr->ai_addrlen) == 0) {
74 break;
75 }
76 ::close(fd);
77 }
78 ::freeaddrinfo(addrs);
79 if (fd < 0) {
80 fprintf(stderr, "Unable to bind to address\n");
81 return 1;
82 }
83 char buffer[1024];
84 for (;;) {
85 struct sockaddr_storage addr;
86 socklen_t addrSize = sizeof(addr);
87 ssize_t bytesRead = recvfrom(fd, buffer, sizeof(buffer), 0,
88 reinterpret_cast<struct sockaddr*>(&addr),
89 &addrSize);
90 if (bytesRead < 0) {
91 if (errno == EINTR) {
92 continue;
93 }
94 fprintf(stderr, "Error receiving on socket: %s\n", strerror(errno));
95 ::close(fd);
96 return 1;
97 } else if (bytesRead == 0) {
98 fprintf(stderr, "Socket unexpectedly closed\n");
99 ::close(fd);
100 return 1;
101 }
102 printf("Received message from client '%*s'\n",
103 static_cast<int>(bytesRead), buffer);
104 }
105 }
106
107 static const char kBridgeName[] = "br0";
108
configureBridge()109 static int configureBridge() {
110 int fd = ::socket(AF_LOCAL, SOCK_STREAM, 0);
111 if (fd < 0) {
112 fprintf(stderr, "ERROR: Could not open bridge socket: %s\n",
113 strerror(errno));
114 return 1;
115 }
116
117 int res = ::ioctl(fd, SIOCBRADDBR, kBridgeName);
118 if (res < 0) {
119 fprintf(stderr, "ERROR: cannot create bridge: %s\n", strerror(errno));
120 ::close(fd);
121 return 1;
122 }
123
124 for (const auto& ifName : { "eth0", "wlan1", "radio0-peer" }) {
125 struct ifreq request;
126 memset(&request, 0, sizeof(request));
127 request.ifr_ifindex = if_nametoindex(ifName);
128 if (request.ifr_ifindex == 0) {
129 fprintf(stderr, "ERROR: Unable to get interface index for %s\n",
130 ifName);
131 ::close(fd);
132 return 1;
133 }
134 strlcpy(request.ifr_name, kBridgeName, sizeof(request.ifr_name));
135 res = ::ioctl(fd, SIOCBRADDIF, &request);
136 if (res < 0) {
137 fprintf(stderr, "ERROR: cannot add if %s to bridge: %s\n",
138 ifName, strerror(errno));
139 ::close(fd);
140 return 1;
141 }
142 }
143
144 struct ifreq request;
145 memset(&request, 0, sizeof(request));
146 request.ifr_ifindex = if_nametoindex(kBridgeName);
147 if (request.ifr_ifindex == 0) {
148 fprintf(stderr, "ERROR: Unable to get interface index for %s\n",
149 kBridgeName);
150 ::close(fd);
151 return 1;
152 }
153 strlcpy(request.ifr_name, kBridgeName, sizeof(request.ifr_name));
154 res = ::ioctl(fd, SIOCGIFFLAGS, &request);
155 if (res != 0) {
156 fprintf(stderr, "ERROR: Unable to get interface index for %s\n",
157 kBridgeName);
158 ::close(fd);
159 return 1;
160 }
161 if ((request.ifr_flags & IFF_UP) == 0) {
162 // Bridge is not up, it needs to be up to work
163 request.ifr_flags |= IFF_UP;
164 res = ::ioctl(fd, SIOCSIFFLAGS, &request);
165 if (res != 0) {
166 fprintf(stderr, "ERROR: Unable to set interface flags for %s\n",
167 kBridgeName);
168 ::close(fd);
169 return 1;
170 }
171 }
172
173 ::close(fd);
174 return 0;
175 }
176
main(int argc,char * argv[])177 int main(int argc, char* argv[]) {
178 if (argc < 2) {
179 usage(argv[0]);
180 return 1;
181 }
182
183 Mode mode;
184 if (strcmp("-b", argv[1]) == 0) {
185 mode = Mode::Bridge;
186 } else if (strcmp("-c", argv[1]) == 0) {
187 mode = Mode::Client;
188 } else if (strcmp("-s", argv[1]) == 0) {
189 mode = Mode::Server;
190 } else {
191 fprintf(stderr, "ERROR: Invalid option '%s'\n", argv[1]);
192 usage(argv[0]);
193 return 1;
194 }
195
196 struct addrinfo* addrs = nullptr;
197 if (mode == Mode::Client || mode == Mode::Server) {
198 if (argc != 4) {
199 usage(argv[0]);
200 return 1;
201 }
202 if (!resolve(argv[2], argv[3], &addrs)) {
203 usage(argv[0]);
204 return 1;
205 }
206 }
207
208 switch (mode) {
209 case Mode::Bridge:
210 return configureBridge();
211 case Mode::Client:
212 return runClient(addrs);
213 case Mode::Server:
214 return runServer(addrs);
215 }
216 }
217
218