1/*
2 * socket_ce.c
3 *
4 * Copyright (C) 2016-2018 Aerospike, Inc.
5 *
6 * Portions may be licensed to Aerospike, Inc. under one or more contributor
7 * license agreements.
8 *
9 * This program is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU Affero General Public License as published by the Free
11 * Software Foundation, either version 3 of the License, or (at your option) any
12 * later version.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see http://www.gnu.org/licenses/
21 */
22
23#define CF_SOCKET_PRIVATE
24#include "socket.h"
25
26#include <errno.h>
27#include <netdb.h>
28#include <stdbool.h>
29#include <stddef.h>
30#include <stdint.h>
31#include <string.h>
32
33#include <arpa/inet.h>
34#include <netinet/in.h>
35#include <sys/socket.h>
36#include <sys/types.h>
37
38#include "bits.h"
39#include "dns.h"
40#include "fault.h"
41
42#include "citrusleaf/alloc.h"
43
44addrinfo g_cf_ip_addr_dns_hints = { .ai_flags = 0, .ai_family = AF_INET };
45
46static char *
47safe_strndup(const char *string, size_t length)
48{
49 char *res = cf_strndup(string, length);
50
51 if (res == NULL) {
52 cf_crash(CF_SOCKET, "Out of memory");
53 }
54
55 return res;
56}
57
58void
59cf_socket_set_advertise_ipv6(bool advertise)
60{
61 cf_warning(CF_SOCKET, "'advertise-ipv6' is relevant for enterprise only");
62}
63
64bool
65cf_socket_advertises_ipv6(void)
66{
67 return false;
68}
69
70int32_t
71cf_ip_addr_from_addrinfo(const char *name, const addrinfo *info,
72 cf_ip_addr *addrs, uint32_t *n_addrs)
73{
74 uint32_t i = 0;
75
76 for (const addrinfo *walker = info; walker != NULL;
77 walker = walker->ai_next) {
78 if (walker->ai_socktype == SOCK_STREAM) {
79 if (i >= *n_addrs) {
80 cf_warning(CF_SOCKET, "Too many IP addresses for '%s'", name);
81 return -1;
82 }
83
84 struct sockaddr_in *sai = (struct sockaddr_in *)walker->ai_addr;
85 addrs[i].v4 = sai->sin_addr;
86 ++i;
87 }
88 }
89
90 if (i == 0) {
91 cf_warning(CF_SOCKET, "No valid addresses for '%s'", name);
92 return -1;
93 }
94
95 cf_ip_addr_sort(addrs, i);
96 *n_addrs = i;
97 return 0;
98}
99
100bool
101cf_ip_addr_str_is_legacy(const char *string)
102{
103 (void)string;
104 return true;
105}
106
107bool
108cf_ip_addr_is_legacy(const cf_ip_addr* addr)
109{
110 (void)addr;
111 return true;
112}
113
114bool
115cf_ip_addr_legacy_only(void)
116{
117 return true;
118}
119
120int32_t
121cf_ip_addr_to_string(const cf_ip_addr *addr, char *string, size_t size)
122{
123 if (inet_ntop(AF_INET, &addr->v4, string, size) == NULL) {
124 cf_warning(CF_SOCKET, "Output buffer overflow");
125 return -1;
126 }
127
128 return strlen(string);
129}
130
131int32_t
132cf_ip_addr_from_binary(const uint8_t *binary, size_t size, cf_ip_addr *addr)
133{
134 if (size != 4) {
135 cf_debug(CF_SOCKET, "Input buffer size incorrect.");
136 return -1;
137 }
138
139 memcpy(&addr->v4, binary, 4);
140 return 4;
141}
142
143int32_t
144cf_ip_addr_to_binary(const cf_ip_addr *addr, uint8_t *binary, size_t size)
145{
146 if (size < 4) {
147 cf_warning(CF_SOCKET, "Output buffer overflow");
148 return -1;
149 }
150
151 memcpy(binary, &addr->v4, 4);
152 return 4;
153}
154
155void
156cf_ip_addr_to_rack_aware_id(const cf_ip_addr *addr, uint32_t *id)
157{
158 *id = ntohl(addr->v4.s_addr);
159}
160
161int32_t
162cf_ip_addr_compare(const cf_ip_addr *lhs, const cf_ip_addr *rhs)
163{
164 return memcmp(&lhs->v4, &rhs->v4, 4);
165}
166
167void
168cf_ip_addr_copy(const cf_ip_addr *from, cf_ip_addr *to)
169{
170 to->v4 = from->v4;
171}
172
173void
174cf_ip_addr_set_local(cf_ip_addr *addr)
175{
176 addr->v4.s_addr = htonl(0x7f000001);
177}
178
179bool
180cf_ip_addr_is_local(const cf_ip_addr *addr)
181{
182 return (ntohl(addr->v4.s_addr) & 0xff000000) == 0x7f000000;
183}
184
185void
186cf_ip_addr_set_any(cf_ip_addr *addr)
187{
188 addr->v4.s_addr = 0;
189}
190
191bool
192cf_ip_addr_is_any(const cf_ip_addr *addr)
193{
194 return addr->v4.s_addr == 0;
195}
196
197int32_t
198cf_ip_net_from_string(const char *string, cf_ip_net *net)
199{
200 size_t len = strlen(string);
201 char net_string[len + 1];
202
203 strcpy(net_string, string);
204
205 char *slash = strchr(net_string, '/');
206
207 if (slash != NULL) {
208 *slash = 0;
209 }
210
211 if (inet_pton(AF_INET, net_string, &net->addr.v4) != 1) {
212 cf_warning(CF_SOCKET, "Invalid IP address %s", net_string);
213 return -1;
214 }
215
216 net->family = AF_INET;
217
218 uint32_t prefix_bits;
219
220 if (slash == NULL) {
221 prefix_bits = 32;
222 }
223 else {
224 char *end;
225 prefix_bits = strtoul(slash + 1, &end, 10);
226
227 if (*end != 0 || prefix_bits > 32) {
228 cf_warning(CF_SOCKET, "Invalid network address %s", string);
229 return -1;
230 }
231 }
232
233 uint8_t *mask = (uint8_t *)&net->mask;
234
235 memset(mask, 0, sizeof(cf_ip_addr));
236
237 while (prefix_bits >= 8) {
238 *mask++ = 0xff;
239 prefix_bits -= 8;
240 }
241
242 *mask = (uint8_t)(0xff << (8 - prefix_bits));
243
244 if ((net->addr.v4.s_addr & ~net->mask.v4.s_addr) != 0) {
245 cf_warning(CF_SOCKET, "Invalid network address %s", string);
246 return -1;
247 }
248
249 return 0;
250}
251
252int32_t
253cf_ip_net_to_string(const cf_ip_net *net, char *string, size_t size)
254{
255 if (inet_ntop(AF_INET, &net->addr.v4, string, size) == NULL) {
256 cf_warning(CF_SOCKET, "Output buffer overflow");
257 return -1;
258 }
259
260 size_t len = strlen(string);
261 uint32_t prefix_bits = cf_bit_count64(net->mask.v4.s_addr);
262
263 if (prefix_bits < 32) {
264 size_t room = size - len;
265 int added = snprintf(string + len, room, "/%u", prefix_bits);
266
267 if (added >= room) {
268 cf_warning(CF_SOCKET, "Output buffer overflow");
269 return -1;
270 }
271
272 len += added;
273 }
274
275 return (int32_t)len;
276}
277
278bool
279cf_ip_net_contains(const cf_ip_net *net, const cf_ip_addr *addr)
280{
281 return (addr->v4.s_addr & net->mask.v4.s_addr) == net->addr.v4.s_addr;
282}
283
284int32_t
285cf_sock_addr_to_string(const cf_sock_addr *addr, char *string, size_t size)
286{
287 int32_t total = 0;
288 int32_t count = cf_ip_addr_to_string(&addr->addr, string, size);
289
290 if (count < 0) {
291 return -1;
292 }
293
294 total += count;
295
296 if (size - total < 2) {
297 cf_warning(CF_SOCKET, "Output buffer overflow");
298 return -1;
299 }
300
301 string[total++] = ':';
302 string[total] = 0;
303
304 count = cf_ip_port_to_string(addr->port, string + total, size - total);
305
306 if (count < 0) {
307 return -1;
308 }
309
310 total += count;
311 return total;
312}
313
314int32_t
315cf_sock_addr_from_string(const char *string, cf_sock_addr *addr)
316{
317 int32_t res = -1;
318 const char *colon = strchr(string, ':');
319
320 if (colon == NULL) {
321 cf_warning(CF_SOCKET, "Missing ':' in socket address '%s'", string);
322 goto cleanup0;
323 }
324
325 const char *host = safe_strndup(string, colon - string);
326
327 if (cf_ip_addr_from_string(host, &addr->addr) < 0) {
328 cf_warning(CF_SOCKET, "Invalid host address '%s' in socket address '%s'", host, string);
329 goto cleanup1;
330 }
331
332 if (cf_ip_port_from_string(colon + 1, &addr->port) < 0) {
333 cf_warning(CF_SOCKET, "Invalid port '%s' in socket address '%s'", colon + 1, string);
334 goto cleanup1;
335 }
336
337 res = 0;
338
339cleanup1:
340 cf_free((void *)host);
341
342cleanup0:
343 return res;
344}
345
346void
347cf_sock_addr_from_native(const struct sockaddr *native, cf_sock_addr *addr)
348{
349 if (native->sa_family != AF_INET) {
350 cf_crash(CF_SOCKET, "Invalid address family: %d", native->sa_family);
351 }
352
353 struct sockaddr_in *sai = (struct sockaddr_in *)native;
354 addr->addr.v4 = sai->sin_addr;
355 addr->port = ntohs(sai->sin_port);
356}
357
358void
359cf_sock_addr_to_native(const cf_sock_addr *addr, struct sockaddr *native)
360{
361 struct sockaddr_in *sai = (struct sockaddr_in *)native;
362 memset(sai, 0, sizeof(struct sockaddr_in));
363 sai->sin_family = AF_INET;
364 sai->sin_addr = addr->addr.v4;
365 sai->sin_port = htons(addr->port);
366}
367
368int32_t
369cf_mserv_cfg_add_combo(cf_mserv_cfg *serv_cfg, cf_sock_owner owner, cf_ip_port port,
370 cf_ip_addr *addr, cf_ip_addr *if_addr, uint8_t ttl)
371{
372 cf_msock_cfg sock_cfg;
373 cf_msock_cfg_init(&sock_cfg, owner);
374 sock_cfg.port = port;
375 cf_ip_addr_copy(addr, &sock_cfg.addr);
376 cf_ip_addr_copy(if_addr, &sock_cfg.if_addr);
377 sock_cfg.ttl = ttl;
378
379 return cf_mserv_cfg_add_msock_cfg(serv_cfg, &sock_cfg);
380}
381
382int32_t
383cf_socket_mcast_set_inter(cf_socket *sock, const cf_ip_addr *iaddr)
384{
385 struct ip_mreqn mr;
386 memset(&mr, 0, sizeof(mr));
387 mr.imr_address = iaddr->v4;
388
389 if (setsockopt(sock->fd, IPPROTO_IP, IP_MULTICAST_IF, &mr, sizeof(mr)) < 0) {
390 cf_warning(CF_SOCKET, "setsockopt(IP_MULTICAST_IF) failed on FD %d: %d (%s)",
391 sock->fd, errno, cf_strerror(errno));
392 return -1;
393 }
394
395 return 0;
396}
397
398int32_t
399cf_socket_mcast_set_ttl(cf_socket *sock, int32_t ttl)
400{
401 if (setsockopt(sock->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
402 cf_warning(CF_SOCKET, "setsockopt(IP_MULTICAST_TTL) failed on FD %d: %d (%s)",
403 sock->fd, errno, cf_strerror(errno));
404 return -1;
405 }
406
407 return 0;
408}
409
410int32_t
411cf_socket_mcast_join_group(cf_socket *sock, const cf_ip_addr *iaddr, const cf_ip_addr *gaddr)
412{
413 struct ip_mreqn mr;
414 memset(&mr, 0, sizeof(mr));
415
416 if (!cf_ip_addr_is_any(iaddr)) {
417 mr.imr_address = iaddr->v4;
418 }
419
420 mr.imr_multiaddr = gaddr->v4;
421
422 if (setsockopt(sock->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0) {
423 cf_warning(CF_SOCKET, "setsockopt(IP_ADD_MEMBERSHIP) failed on FD %d: %d (%s)",
424 sock->fd, errno, cf_strerror(errno));
425 return -1;
426 }
427
428#ifdef IP_MULTICAST_ALL
429 // Only receive traffic from multicast groups this socket actually joins.
430 // Note: Bind address filtering takes precedence, so this is simply an extra level of
431 // restriction.
432 static const int32_t no = 0;
433
434 if (setsockopt(sock->fd, IPPROTO_IP, IP_MULTICAST_ALL, &no, sizeof(no)) < 0) {
435 cf_warning(CF_SOCKET, "setsockopt(IP_MULTICAST_ALL) failed on FD %d: %d (%s)",
436 sock->fd, errno, cf_strerror(errno));
437 return -1;
438 }
439#endif
440
441 return 0;
442}
443
444size_t
445cf_socket_addr_len(const struct sockaddr *sa)
446{
447 switch (sa->sa_family) {
448 case AF_INET:
449 return sizeof(struct sockaddr_in);
450
451 default:
452 cf_crash(CF_SOCKET, "Invalid address family: %d", sa->sa_family);
453 return 0;
454 }
455}
456
457int32_t
458cf_socket_parse_netlink(bool allow_ipv6, uint32_t family, uint32_t flags,
459 const void *data, size_t len, cf_ip_addr *addr)
460{
461 (void)allow_ipv6;
462 (void)flags;
463
464 if (family != AF_INET || len != 4) {
465 return -1;
466 }
467
468 memcpy(&addr->v4, data, 4);
469 return 0;
470}
471
472void
473cf_socket_fix_client(cf_socket *sock)
474{
475 (void)sock;
476}
477
478void
479cf_socket_fix_bind(cf_serv_cfg *serv_cfg)
480{
481 (void)serv_cfg;
482}
483
484void
485cf_socket_fix_server(cf_socket *sock)
486{
487 (void)sock;
488}
489