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