1 /* vim: set expandtab ts=4 sw=4: */
2 /*
3 * You may redistribute this program and/or modify it under the terms of
4 * the GNU General Public License as published by the Free Software Foundation,
5 * either version 3 of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <https://www.gnu.org/licenses/>.
14 */
15 #include "util/events/libuv/UvWrapper.h"
16 #include "benc/StringList.h"
17 #include "interface/UDPInterface.h"
18 #include "wire/Message.h"
19 #include "util/events/UDPAddrIface.h"
20 #include "util/GlobalConfig.h"
21
22 #define ArrayList_TYPE struct Sockaddr
23 #define ArrayList_NAME Sockaddr
24 #include "util/ArrayList.h"
25
26 struct UDPInterface_pvt
27 {
28 struct UDPInterface pub;
29 struct Log* log;
30 struct Allocator* allocator;
31
32 struct Allocator* bcastAddrAlloc;
33 struct ArrayList_Sockaddr* bcastAddrs;
34
35 struct Allocator* bcastIfaceAlloc;
36 struct StringList* bcastIfaces;
37
38 struct UDPAddrIface* commIf;
39 struct UDPAddrIface* bcastIf;
40
41 struct GlobalConfig* globalConf;
42
43 struct Iface commSock;
44 struct Iface bcastSock;
45 uint16_t beaconPort_be;
46 uint16_t commPort_be;
47
48 Identity
49 };
50
mkBcastAddr(uint16_t beaconPort_be,uv_interface_address_t * iface,struct Allocator * alloc)51 static struct Sockaddr* mkBcastAddr(
52 uint16_t beaconPort_be,
53 uv_interface_address_t* iface,
54 struct Allocator* alloc)
55 {
56 struct sockaddr_in bcast4 = {
57 .sin_family = AF_INET,
58 .sin_port = beaconPort_be,
59 .sin_addr = {
60 .s_addr =
61 (
62 iface->address.address4.sin_addr.s_addr &
63 iface->netmask.netmask4.sin_addr.s_addr
64 ) | ~iface->netmask.netmask4.sin_addr.s_addr
65 }
66 };
67 return Sockaddr_fromNative(&bcast4, sizeof(struct sockaddr_in), alloc);
68 }
69
updateBcastAddrs(struct UDPInterface_pvt * ctx)70 static int updateBcastAddrs(struct UDPInterface_pvt* ctx)
71 {
72 bool all = false;
73 for (int i = 0; ctx->bcastIfaces && i < ctx->bcastIfaces->length; i++) {
74 String* iface = StringList_get(ctx->bcastIfaces, i);
75 if (String_equals(iface, String_CONST("all"))) { all = true; }
76 }
77 uv_interface_address_t* interfaces;
78 int count;
79 int res = uv_interface_addresses(&interfaces, &count);
80 if (res) {
81 Log_info(ctx->log, "uv_interface_addresses failed [%s]", uv_strerror(-res));
82 return -1;
83 }
84
85 if (ctx->bcastAddrAlloc) { Allocator_free(ctx->bcastAddrAlloc); }
86 struct Allocator* alloc = ctx->bcastAddrAlloc = Allocator_child(ctx->allocator);
87 ctx->bcastAddrs = ArrayList_Sockaddr_new(alloc);
88
89 String* tunDev = GlobalConfig_getTunName(ctx->globalConf);
90
91 for (int i = 0; i < count; i++) {
92 if (interfaces[i].is_internal) { continue; }
93 if (interfaces[i].address.address4.sin_family != AF_INET) { continue; }
94 if (tunDev && !CString_strncmp(interfaces[i].name, tunDev->bytes, tunDev->len)) {
95 continue;
96 }
97 struct Sockaddr* addr = mkBcastAddr(ctx->beaconPort_be, &interfaces[i], alloc);
98 if (!all) {
99 String* addrStr = String_new(Sockaddr_print(addr, alloc), alloc);
100 bool found = false;
101 for (int j = 0; ctx->bcastIfaces && j < ctx->bcastIfaces->length; j++) {
102 String* iface = StringList_get(ctx->bcastIfaces, j);
103 if (String_equals(iface, addrStr)) { found = true; }
104 if (String_equals(iface, String_CONST(interfaces[i].name))) { found = true; }
105 }
106 if (!found) { continue; }
107 }
108 ArrayList_Sockaddr_add(ctx->bcastAddrs, addr);
109 }
110 uv_free_interface_addresses(interfaces, count);
111 return 0;
112 }
113
sendPacket(struct Message * m,struct Iface * iface)114 static Iface_DEFUN sendPacket(struct Message* m, struct Iface* iface)
115 {
116 struct UDPInterface_pvt* ctx =
117 Identity_containerOf(iface, struct UDPInterface_pvt, pub.generic.iface);
118
119 Assert_true(m->length > Sockaddr_OVERHEAD);
120 struct Sockaddr* sa = (struct Sockaddr*) m->bytes;
121 Assert_true(m->length > sa->addrLen);
122
123 // Regular traffic
124 if (!(sa->flags & Sockaddr_flags_BCAST)) { return Iface_next(&ctx->commSock, m); }
125
126 if (updateBcastAddrs(ctx)) {
127 return NULL;
128 }
129
130 // bcast
131 struct UDPInterface_BroadcastHeader hdr = {
132 .fffffffc_be = Endian_hostToBigEndian32(0xfffffffc),
133 .version = UDPInterface_CURRENT_VERSION,
134 .zero = 0,
135 .commPort_be = ctx->commPort_be
136 };
137 Er_assert(Message_eshift(m, -sa->addrLen));
138 Er_assert(Message_epush(m, &hdr, UDPInterface_BroadcastHeader_SIZE));
139
140 for (int i = 0; i < ctx->bcastAddrs->length; i++) {
141 struct Allocator* tmpAlloc = Allocator_child(ctx->allocator);
142 struct Message* mm = Message_clone(m, tmpAlloc);
143 struct Sockaddr* addr = ArrayList_Sockaddr_get(ctx->bcastAddrs, i);
144 Er_assert(Message_epush(mm, addr, addr->addrLen));
145 Iface_send(&ctx->bcastSock, mm);
146 Allocator_free(tmpAlloc);
147 }
148
149 return NULL;
150 }
151
fromCommSock(struct Message * m,struct Iface * iface)152 static Iface_DEFUN fromCommSock(struct Message* m, struct Iface* iface)
153 {
154 struct UDPInterface_pvt* ctx =
155 Identity_containerOf(iface, struct UDPInterface_pvt, commSock);
156 return Iface_next(&ctx->pub.generic.iface, m);
157 }
158
fromBcastSock(struct Message * m,struct Iface * iface)159 static Iface_DEFUN fromBcastSock(struct Message* m, struct Iface* iface)
160 {
161 struct UDPInterface_pvt* ctx =
162 Identity_containerOf(iface, struct UDPInterface_pvt, bcastSock);
163
164 if (m->length < UDPInterface_BroadcastHeader_SIZE + Sockaddr_OVERHEAD) {
165 Log_debug(ctx->log, "DROP runt bcast");
166 return NULL;
167 }
168
169 struct Sockaddr_storage ss;
170 Er_assert(Message_epop(m, &ss, Sockaddr_OVERHEAD));
171 if (m->length < UDPInterface_BroadcastHeader_SIZE + ss.addr.addrLen - Sockaddr_OVERHEAD) {
172 Log_debug(ctx->log, "DROP runt bcast");
173 return NULL;
174 }
175 Er_assert(Message_epop(m, &ss.nativeAddr, ss.addr.addrLen - Sockaddr_OVERHEAD));
176
177 struct UDPInterface_BroadcastHeader hdr;
178 Er_assert(Message_epop(m, &hdr, UDPInterface_BroadcastHeader_SIZE));
179
180 if (hdr.fffffffc_be != Endian_hostToBigEndian32(0xfffffffc)) {
181 Log_debug(ctx->log, "DROP bcast bad magic, expected 0xfffffffc got [%08x]",
182 Endian_bigEndianToHost32(hdr.fffffffc_be));
183 return NULL;
184 }
185
186 if (hdr.version != UDPInterface_CURRENT_VERSION) {
187 Log_debug(ctx->log, "DROP bcast bad version [%u]", hdr.version);
188 return NULL;
189 }
190
191 if (hdr.zero) {
192 Log_debug(ctx->log, "DROP bcast malformed (zero not zero)");
193 return NULL;
194 }
195
196 uint16_t commPort = Endian_bigEndianToHost16(hdr.commPort_be);
197
198 // Fake that it came from the communication port
199 Sockaddr_setPort(&ss.addr, commPort);
200 ss.addr.flags |= Sockaddr_flags_BCAST;
201
202 Er_assert(Message_epush(m, &ss.addr, ss.addr.addrLen));
203
204 return Iface_next(&ctx->pub.generic.iface, m);
205 }
206
Er_DEFUN(struct UDPInterface * UDPInterface_new (struct EventBase * eventBase,struct Sockaddr * bindAddr,uint16_t beaconPort,struct Allocator * alloc,struct Log * logger,struct GlobalConfig * globalConf))207 Er_DEFUN(struct UDPInterface* UDPInterface_new(struct EventBase* eventBase,
208 struct Sockaddr* bindAddr,
209 uint16_t beaconPort,
210 struct Allocator* alloc,
211 struct Log* logger,
212 struct GlobalConfig* globalConf))
213 {
214 if (beaconPort && Sockaddr_getFamily(bindAddr) != Sockaddr_AF_INET) {
215 Er_raise(alloc, "UDP broadcast only supported by ipv4.");
216 }
217 if (beaconPort && Sockaddr_getPort(bindAddr) == beaconPort) {
218 Er_raise(alloc, "UDP broadcast port must be different from communication port.");
219 }
220
221 struct UDPAddrIface* uai = Er(UDPAddrIface_new(eventBase, bindAddr, alloc, logger));
222
223 uint16_t commPort = Sockaddr_getPort(uai->generic.addr);
224
225 struct UDPInterface_pvt* context = Allocator_calloc(alloc, sizeof(struct UDPInterface_pvt), 1);
226 Identity_set(context);
227 context->log = logger;
228 context->allocator = alloc;
229 context->beaconPort_be = Endian_hostToBigEndian16(beaconPort);
230 context->commPort_be = Endian_hostToBigEndian16(commPort);
231 context->pub.generic.addr = uai->generic.addr;
232 context->pub.generic.alloc = alloc;
233 context->pub.generic.iface.send = sendPacket;
234 context->commSock.send = fromCommSock;
235 context->bcastSock.send = fromBcastSock;
236 context->commIf = uai;
237 context->globalConf = globalConf;
238 Iface_plumb(&uai->generic.iface, &context->commSock);
239
240 if (beaconPort) {
241 struct Sockaddr* bcastAddr = Sockaddr_clone(bindAddr, alloc);
242 Sockaddr_setPort(bcastAddr, beaconPort);
243 struct UDPAddrIface* bcast =
244 Er(UDPAddrIface_new(eventBase, bcastAddr, alloc, logger));
245 UDPAddrIface_setBroadcast(bcast, 1);
246 Iface_plumb(&bcast->generic.iface, &context->bcastSock);
247 context->bcastIf = bcast;
248 }
249
250 Er_ret(&context->pub);
251 }
252
Er_DEFUN(List * UDPInterface_listDevices (struct Allocator * alloc))253 Er_DEFUN(List* UDPInterface_listDevices(struct Allocator* alloc))
254 {
255 List* out = List_new(alloc);
256 uv_interface_address_t* interfaces;
257 int count;
258 int res = uv_interface_addresses(&interfaces, &count);
259 if (res) { Er_raise(alloc, "uv_interface_addresses failed [%s]", uv_strerror(-res)); }
260
261 for (int i = 0; i < count; i++) {
262 if (interfaces[i].is_internal) { continue; }
263 if (interfaces[i].address.address4.sin_family != AF_INET) { continue; }
264 List_addString(out, String_new(interfaces[i].name, alloc), alloc);
265 }
266 uv_free_interface_addresses(interfaces, count);
267 Er_ret(out);
268 }
269
UDPInterface_setBroadcastDevices(struct UDPInterface * udpif,List * devices)270 void UDPInterface_setBroadcastDevices(struct UDPInterface* udpif, List* devices)
271 {
272 struct UDPInterface_pvt* ctx = Identity_check((struct UDPInterface_pvt*) udpif);
273 if (ctx->bcastIfaceAlloc) { Allocator_free(ctx->bcastIfaceAlloc); }
274 struct Allocator* alloc = ctx->bcastIfaceAlloc = Allocator_child(ctx->allocator);
275 struct StringList* bcastIfaces = ctx->bcastIfaces = StringList_new(alloc);
276 int len = List_size(devices);
277 for (uint32_t i = 0; i < (unsigned) len; i++) {
278 String* dev = List_getString(devices, i);
279 StringList_add(bcastIfaces, String_clone(dev, alloc));
280 }
281 }
282
UDPInterface_getBroadcastDevices(struct UDPInterface * udpif,struct Allocator * alloc)283 List* UDPInterface_getBroadcastDevices(struct UDPInterface* udpif, struct Allocator* alloc)
284 {
285 struct UDPInterface_pvt* ctx = Identity_check((struct UDPInterface_pvt*) udpif);
286 List* out = List_new(alloc);
287 for (int i = 0; ctx->bcastIfaces && i < ctx->bcastIfaces->length; i++) {
288 List_addString(out, StringList_get(ctx->bcastIfaces, i), alloc);
289 }
290 return out;
291 }
292
UDPInterface_getBroadcastAddrs(struct UDPInterface * udpif,struct Allocator * alloc)293 List* UDPInterface_getBroadcastAddrs(struct UDPInterface* udpif, struct Allocator* alloc)
294 {
295 struct UDPInterface_pvt* ctx = Identity_check((struct UDPInterface_pvt*) udpif);
296 List* out = List_new(alloc);
297 if (updateBcastAddrs(ctx)) {
298 // TODO(cjd): There should be some way to return the fact that there was an error
299 return out;
300 }
301 for (int i = 0; i < ctx->bcastAddrs->length; i++) {
302 char* addr = Sockaddr_print(ArrayList_Sockaddr_get(ctx->bcastAddrs, i), alloc);
303 List_addStringC(out, addr, alloc);
304 }
305 return out;
306 }
307
UDPInterface_setDSCP(struct UDPInterface * udpif,uint8_t dscp)308 int UDPInterface_setDSCP(struct UDPInterface* udpif, uint8_t dscp)
309 {
310 struct UDPInterface_pvt* ctx = Identity_check((struct UDPInterface_pvt*) udpif);
311 int res = UDPAddrIface_setDSCP(ctx->commIf, dscp);
312 if (res) { return res; }
313 if (ctx->bcastIf) { return UDPAddrIface_setDSCP(ctx->bcastIf, dscp); }
314 return 0;
315 }
316
UDPInterface_getFd(struct UDPInterface * udpif)317 int UDPInterface_getFd(struct UDPInterface* udpif)
318 {
319 struct UDPInterface_pvt* ctx = Identity_check((struct UDPInterface_pvt*) udpif);
320 return UDPAddrIface_getFd(ctx->commIf);
321 }