/src/freeradius-server/src/lib/util/socket.c
Line | Count | Source |
1 | | /* |
2 | | * This program is is free software; you can redistribute it and/or modify |
3 | | * it under the terms of the GNU General Public License as published by |
4 | | * the Free Software Foundation; either version 2 of the License, or (at |
5 | | * 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, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
15 | | */ |
16 | | |
17 | | /** Functions for establishing and managing low level sockets |
18 | | * |
19 | | * @file src/lib/util/socket.c |
20 | | * |
21 | | * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org) |
22 | | * @author Alan DeKok (aland@freeradius.org) |
23 | | * |
24 | | * @copyright 2015 The FreeRADIUS project |
25 | | */ |
26 | | |
27 | | #include <freeradius-devel/util/debug.h> |
28 | | #include <freeradius-devel/util/misc.h> |
29 | | #include <freeradius-devel/util/socket.h> |
30 | | #include <freeradius-devel/util/syserror.h> |
31 | | #include <freeradius-devel/util/udpfromto.h> |
32 | | #include <freeradius-devel/util/value.h> |
33 | | #include <freeradius-devel/util/cap.h> |
34 | | |
35 | | #include <fcntl.h> |
36 | | #include <ifaddrs.h> |
37 | | |
38 | | /** Resolve a named service to a port |
39 | | * |
40 | | * @param[in] proto The protocol. Either IPPROTO_TCP or IPPROTO_UDP. |
41 | | * @param[in] port_name The service name, i.e. "radius". |
42 | | * @return |
43 | | * - > 0 the port port_name resolves to. |
44 | | * - < 0 on error. |
45 | | */ |
46 | | static int socket_port_from_service(int proto, char const *port_name) |
47 | 0 | { |
48 | 0 | struct servent *service; |
49 | 0 | char const *proto_name; |
50 | |
|
51 | 0 | if (!port_name) { |
52 | 0 | fr_strerror_const("No port specified"); |
53 | 0 | return -1; |
54 | 0 | } |
55 | | |
56 | 0 | switch (proto) { |
57 | 0 | case IPPROTO_UDP: |
58 | 0 | proto_name = "udp"; |
59 | 0 | break; |
60 | | |
61 | 0 | case IPPROTO_TCP: |
62 | 0 | proto_name = "tcp"; |
63 | 0 | break; |
64 | | |
65 | 0 | #ifdef IPPROTO_SCTP |
66 | 0 | case IPPROTO_SCTP: |
67 | 0 | proto_name = "sctp"; |
68 | 0 | break; |
69 | 0 | #endif |
70 | | |
71 | 0 | default: |
72 | 0 | fr_strerror_printf("Unrecognised proto %i", proto); |
73 | 0 | return -1; |
74 | 0 | } |
75 | | |
76 | 0 | service = getservbyname(port_name, proto_name); |
77 | 0 | if (!service) { |
78 | 0 | fr_strerror_printf("Unknown service %s", port_name); |
79 | 0 | return -1; |
80 | 0 | } |
81 | | |
82 | 0 | return ntohs(service->s_port); |
83 | 0 | } |
84 | | |
85 | | #ifdef FD_CLOEXEC |
86 | | static int socket_dont_inherit(int sockfd) |
87 | 0 | { |
88 | 0 | int ret; |
89 | | |
90 | | /* |
91 | | * We don't want child processes inheriting these |
92 | | * file descriptors. |
93 | | */ |
94 | 0 | ret = fcntl(sockfd, F_GETFD); |
95 | 0 | if (ret >= 0) { |
96 | 0 | if (fcntl(sockfd, F_SETFD, ret | FD_CLOEXEC) < 0) { |
97 | 0 | fr_strerror_printf("Failed setting close on exec: %s", fr_syserror(errno)); |
98 | 0 | return -1; |
99 | 0 | } |
100 | 0 | } |
101 | | |
102 | 0 | return 0; |
103 | 0 | } |
104 | | #else |
105 | | static socket_dont_inherit(UNUSED int sockfd) |
106 | | { |
107 | | return 0; |
108 | | } |
109 | | #endif |
110 | | |
111 | | #ifdef HAVE_STRUCT_SOCKADDR_IN6 |
112 | | /** Restrict wildcard sockets to v6 only |
113 | | * |
114 | | * If we don't do this we get v4 and v6 packets coming in on the same |
115 | | * socket, which is weird. |
116 | | * |
117 | | * @param[in] sockfd to modify. |
118 | | * @param[in] ipaddr we will be binding to. |
119 | | * @return |
120 | | * - 0 on success. |
121 | | * - -1 on failure. |
122 | | */ |
123 | | static int socket_inaddr_any_v6only(int sockfd, fr_ipaddr_t const *ipaddr) |
124 | 0 | { |
125 | | /* |
126 | | * Listening on '::' does NOT get you IPv4 to |
127 | | * IPv6 mapping. You've got to listen on an IPv4 |
128 | | * address, too. This makes the rest of the server |
129 | | * design a little simpler. |
130 | | */ |
131 | 0 | if (ipaddr->af == AF_INET6) { |
132 | 0 | # ifdef IPV6_V6ONLY |
133 | | /* unconst for emscripten/musl */ |
134 | 0 | if (IN6_IS_ADDR_UNSPECIFIED(UNCONST(struct in6_addr *, &ipaddr->addr.v6))) { |
135 | 0 | int on = 1; |
136 | |
|
137 | 0 | if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, |
138 | 0 | (char *)&on, sizeof(on)) < 0) { |
139 | 0 | fr_strerror_printf("Failed setting socket to IPv6 only: %s", fr_syserror(errno)); |
140 | 0 | close(sockfd); |
141 | 0 | return -1; |
142 | 0 | } |
143 | 0 | } |
144 | 0 | # endif /* IPV6_V6ONLY */ |
145 | 0 | } |
146 | 0 | return 0; |
147 | 0 | } |
148 | | #else |
149 | | static int socket_inaddr_any_v6only(UNUSED int sockfd, UNUSED fr_ipaddr_t const *ipaddr) |
150 | | { |
151 | | return 0; |
152 | | } |
153 | | #endif |
154 | | |
155 | | #if (defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)) || defined(IP_DONTFRAG) |
156 | | /** Set the don't fragment bit |
157 | | * |
158 | | * @param[in] sockfd to set don't fragment bit for. |
159 | | * @param[in] af of the socket. |
160 | | * @return |
161 | | * - 0 on success. |
162 | | * - -1 on failure. |
163 | | */ |
164 | | static int socket_dont_fragment(int sockfd, int af) |
165 | 0 | { |
166 | | /* |
167 | | * Set the "don't fragment" flag on UDP sockets. Most |
168 | | * routers don't have good support for fragmented UDP |
169 | | * packets. |
170 | | */ |
171 | 0 | if (af == AF_INET) { |
172 | 0 | int flag; |
173 | |
|
174 | 0 | # if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) |
175 | | /* |
176 | | * Disable PMTU discovery. On Linux, this |
177 | | * also makes sure that the "don't fragment" |
178 | | * flag is zero. |
179 | | */ |
180 | 0 | flag = IP_PMTUDISC_DONT; |
181 | |
|
182 | 0 | if (setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &flag, sizeof(flag)) < 0) { |
183 | 0 | fr_strerror_printf("Failed disabling PMTU discovery: %s", fr_syserror(errno)); |
184 | 0 | return -1; |
185 | 0 | } |
186 | 0 | # endif |
187 | |
|
188 | | # if defined(IP_DONTFRAG) |
189 | | /* |
190 | | * Ensure that the "don't fragment" flag is zero. |
191 | | */ |
192 | | flag = 0; |
193 | | |
194 | | if (setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG, &flag, sizeof(flag)) < 0) { |
195 | | fr_strerror_printf("Failed setting don't fragment flag: %s", fr_syserror(errno)); |
196 | | return -1; |
197 | | } |
198 | | # endif |
199 | 0 | } |
200 | | |
201 | 0 | return 0; |
202 | 0 | } |
203 | | #else |
204 | | static int socket_dont_fragment(UNUSED int sockfd, UNUSED int af) |
205 | | { |
206 | | return 0; |
207 | | } |
208 | | #endif /* lots of things */ |
209 | | |
210 | | /** Bind a UDP/TCP v4/v6 socket to a given ipaddr src port, and interface. |
211 | | * |
212 | | * Use one of: |
213 | | * - fr_socket_server_udp - for non-connected socket. |
214 | | * - fr_socket_server_tcp |
215 | | * ...to open a file descriptor, then call this function to bind the socket to an IP address. |
216 | | * |
217 | | * @param[in] sockfd the socket which opened by fr_socket_server_*. |
218 | | * @param[in] ifname to bind to. |
219 | | * @param[in,out] src_ipaddr The IP address to bind to. Will be updated to the IP address |
220 | | * that was actually bound to. Pass NULL to just bind to an interface. |
221 | | * @param[in] src_port the port to bind to. NULL if any port is allowed. |
222 | | |
223 | | * @return |
224 | | * - 0 on success |
225 | | * - -1 on failure. |
226 | | */ |
227 | | int fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port) |
228 | 0 | { |
229 | 0 | int ret; |
230 | 0 | uint16_t my_port = 0; |
231 | 0 | fr_ipaddr_t my_ipaddr; |
232 | 0 | struct sockaddr_storage salocal; |
233 | 0 | socklen_t salen; |
234 | 0 | #ifdef HAVE_NET_IF_H |
235 | 0 | unsigned int scope_id = 0; |
236 | 0 | #endif |
237 | | |
238 | | /* |
239 | | * Clear the thread local error stack as we may |
240 | | * push multiple errors onto the stack, and this |
241 | | * is likely to be the function which returns |
242 | | * the "original" error. |
243 | | */ |
244 | 0 | fr_strerror_clear(); |
245 | |
|
246 | 0 | if (src_port) my_port = *src_port; |
247 | 0 | if (src_ipaddr) { |
248 | 0 | my_ipaddr = *src_ipaddr; |
249 | 0 | } else { |
250 | 0 | my_ipaddr = (fr_ipaddr_t) { |
251 | 0 | .af = AF_UNSPEC |
252 | 0 | }; |
253 | 0 | } |
254 | |
|
255 | | #ifdef HAVE_CAPABILITY_H |
256 | | /* |
257 | | * If we're binding to a special port as non-root, then |
258 | | * check capabilities. If we're root, we already have |
259 | | * equivalent capabilities so we don't need to check. |
260 | | */ |
261 | | if (src_port && (*src_port < 1024) && (geteuid() != 0)) { |
262 | | (void)fr_cap_enable(CAP_NET_BIND_SERVICE, CAP_EFFECTIVE); /* Sets error on failure, which will be seen if the bind fails */ |
263 | | } |
264 | | #endif |
265 | | |
266 | | /* |
267 | | * Bind to a device BEFORE touching IP addresses. |
268 | | */ |
269 | 0 | if (ifname) { |
270 | 0 | #ifdef HAVE_NET_IF_H |
271 | 0 | scope_id = if_nametoindex(ifname); |
272 | 0 | if (!scope_id) { |
273 | 0 | fr_strerror_printf_push("Failed finding interface %s: %s", ifname, fr_syserror(errno)); |
274 | 0 | return -1; |
275 | 0 | } |
276 | | |
277 | | /* |
278 | | * If the scope ID hasn't already been set, then |
279 | | * set it. This allows us to get the scope from the interface name. |
280 | | */ |
281 | 0 | if ((my_ipaddr.scope_id != 0) && (scope_id != my_ipaddr.scope_id)) { |
282 | 0 | fr_strerror_printf_push("Cannot bind to interface %s: Socket is already bound " |
283 | 0 | "to another interface", ifname); |
284 | 0 | return -1; |
285 | 0 | } |
286 | 0 | #endif |
287 | | |
288 | 0 | #ifdef SO_BINDTODEVICE |
289 | | /* |
290 | | * The caller didn't specify a scope_id, but we |
291 | | * have one from above. Call "bind to device", |
292 | | * and set the scope_id. |
293 | | */ |
294 | 0 | if (!my_ipaddr.scope_id) { |
295 | | /* |
296 | | * The internet hints that CAP_NET_RAW |
297 | | * is required to use SO_BINDTODEVICE. |
298 | | * |
299 | | * This function also sets fr_strerror() |
300 | | * on failure, which will be seen if the |
301 | | * bind fails. If the bind succeeds, |
302 | | * then we don't really care that the |
303 | | * capability change has failed. We must |
304 | | * already have that capability. |
305 | | */ |
306 | | #ifdef HAVE_CAPABILITY_H |
307 | | (void)fr_cap_enable(CAP_NET_RAW, CAP_EFFECTIVE); |
308 | | #endif |
309 | 0 | ret = setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)); |
310 | 0 | if (ret < 0) { |
311 | 0 | fr_strerror_printf_push("Failed binding socket to interface %s: %s", |
312 | 0 | ifname, fr_syserror(errno)); |
313 | 0 | return -1; |
314 | 0 | } /* else it worked. */ |
315 | | |
316 | | /* |
317 | | * Set the scope ID. |
318 | | */ |
319 | 0 | my_ipaddr.scope_id = scope_id; |
320 | 0 | } |
321 | | |
322 | | /* |
323 | | * SO_BINDTODEVICE succeeded, so we're always |
324 | | * bound to the socket. |
325 | | */ |
326 | |
|
327 | | #elif defined(IP_BOUND_IF) || defined(IPV6_BOUND_IF) |
328 | | { |
329 | | int idx = scope_id; |
330 | | |
331 | | if (my_ipaddr.af == AF_INET) { |
332 | | if (unlikely(setsockopt(sockfd, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx)) < 0)) { |
333 | | error: |
334 | | fr_strerror_printf_push("Failed binding socket to interface %s: %s", |
335 | | ifname, fr_syserror(errno)); |
336 | | return -1; |
337 | | } |
338 | | |
339 | | } else if (my_ipaddr.af == AF_INET6) { |
340 | | if (unlikely(setsockopt(sockfd, IPPROTO_IPV6, IPV6_BOUND_IF, &idx, sizeof(idx)) < 0)) goto error; |
341 | | |
342 | | } else { |
343 | | fr_strerror_printf("Invalid address family for 'interface = ...'"); |
344 | | return -1; |
345 | | } |
346 | | |
347 | | my_ipaddr.scope_id = scope_id; |
348 | | } |
349 | | |
350 | | #else |
351 | | { |
352 | | struct ifaddrs *list = NULL; |
353 | | bool bound = false; |
354 | | |
355 | | /* |
356 | | * Troll through all interfaces to see if there's |
357 | | */ |
358 | | if (getifaddrs(&list) == 0) { |
359 | | struct ifaddrs *i; |
360 | | |
361 | | for (i = list; i != NULL; i = i->ifa_next) { |
362 | | if (i->ifa_addr && i->ifa_name && (strcmp(i->ifa_name, ifname) == 0)) { |
363 | | /* |
364 | | * IPv4, and there's either no src_ip, OR src_ip is INADDR_ANY, |
365 | | * it's a match. |
366 | | * |
367 | | * We also update my_ipaddr to point to this particular IP, |
368 | | * so that we can later bind() to it. This gets us the same |
369 | | * effect as SO_BINDTODEVICE. |
370 | | */ |
371 | | if ((i->ifa_addr->sa_family == AF_INET) && |
372 | | (!src_ipaddr || fr_ipaddr_is_inaddr_any(src_ipaddr))) { |
373 | | (void) fr_ipaddr_from_sockaddr(&my_ipaddr, NULL, |
374 | | (struct sockaddr_storage *) i->ifa_addr, |
375 | | sizeof(struct sockaddr_in)); |
376 | | my_ipaddr.scope_id = scope_id; |
377 | | bound = true; |
378 | | break; |
379 | | } |
380 | | |
381 | | /* |
382 | | * The caller specified a source IP, and we find a matching |
383 | | * address family. Allow it. |
384 | | * |
385 | | * Note that we do NOT check for matching IPs here. If we did, |
386 | | * then binding to an interface and the *wrong* IP would get us |
387 | | * a "bind to device is unsupported" message. |
388 | | * |
389 | | * Instead we say "yes, we found a matching interface", and then |
390 | | * allow the bind() call below to run. If that fails, we get a |
391 | | * "Can't assign requested address" error, which is more informative. |
392 | | */ |
393 | | if (src_ipaddr && (src_ipaddr->af == i->ifa_addr->sa_family)) { |
394 | | my_ipaddr.scope_id = scope_id; |
395 | | bound = true; |
396 | | break; |
397 | | } |
398 | | } |
399 | | } |
400 | | |
401 | | freeifaddrs(list); |
402 | | |
403 | | if (!bound) { |
404 | | /* |
405 | | * IPv4: no link local addresses, |
406 | | * and no bind to device. |
407 | | */ |
408 | | fr_strerror_printf_push("Bind to interface %s failed: Unable to match " |
409 | | "interface with the given IP address.", ifname); |
410 | | return -1; |
411 | | } |
412 | | } else { |
413 | | fr_strerror_printf_push("Bind to interface %s failed, unable to get list of interfaces: %s", |
414 | | ifname, fr_syserror(errno)); |
415 | | return -1; |
416 | | } |
417 | | } |
418 | | #endif |
419 | 0 | } /* else no interface was passed in */ |
420 | | |
421 | | /* |
422 | | * Don't bind to an IP address if there's no src IP address. |
423 | | */ |
424 | 0 | if (my_ipaddr.af == AF_UNSPEC) goto done; |
425 | | |
426 | | /* |
427 | | * Set up sockaddr stuff. |
428 | | */ |
429 | 0 | if (fr_ipaddr_to_sockaddr(&salocal, &salen, &my_ipaddr, my_port) < 0) return -1; |
430 | | |
431 | 0 | ret = bind(sockfd, (struct sockaddr *) &salocal, salen); |
432 | 0 | if (ret < 0) { |
433 | 0 | fr_strerror_printf_push("Bind failed with source address %pV:%pV on interface %s: %s", |
434 | 0 | src_ipaddr ? fr_box_ipaddr(*src_ipaddr) : fr_box_strvalue("*"), |
435 | 0 | src_port ? fr_box_int16(*src_port) : fr_box_strvalue("*"), |
436 | 0 | ifname ? ifname : "*", |
437 | 0 | fr_syserror(errno)); |
438 | 0 | return ret; |
439 | 0 | } |
440 | | |
441 | 0 | if (!src_port) goto done; |
442 | | |
443 | | /* |
444 | | * FreeBSD jail issues. We bind to 0.0.0.0, but the |
445 | | * kernel instead binds us to a 1.2.3.4. So once the |
446 | | * socket is bound, ask it what it's IP address is. |
447 | | */ |
448 | 0 | salen = sizeof(salocal); |
449 | 0 | memset(&salocal, 0, salen); |
450 | 0 | if (getsockname(sockfd, (struct sockaddr *) &salocal, &salen) < 0) { |
451 | 0 | fr_strerror_printf_push("Failed getting socket name: %s", fr_syserror(errno)); |
452 | 0 | return -1; |
453 | 0 | } |
454 | | |
455 | 0 | if (fr_ipaddr_from_sockaddr(&my_ipaddr, &my_port, &salocal, salen) < 0) return -1; |
456 | | |
457 | 0 | #ifdef HAVE_NET_IF_H |
458 | | /* |
459 | | * fr_ipaddr_from_sockaddr clears scope_id for IPv4 |
460 | | */ |
461 | 0 | if (ifname && scope_id && (my_ipaddr.af == AF_INET)) my_ipaddr.scope_id = scope_id; |
462 | 0 | #endif |
463 | 0 | *src_port = my_port; |
464 | 0 | *src_ipaddr = my_ipaddr; |
465 | |
|
466 | 0 | done: |
467 | | #ifdef HAVE_CAPABILITY_H |
468 | | /* |
469 | | * Clear any errors we may have produced in the |
470 | | * capabilities check. |
471 | | */ |
472 | | fr_strerror_clear(); |
473 | | #endif |
474 | 0 | return 0; |
475 | 0 | } |
476 | | |
477 | | #ifdef HAVE_SYS_UN_H |
478 | | /** Open a Unix socket |
479 | | * |
480 | | * @note If the file doesn't exist then errno will be set to ENOENT. |
481 | | * |
482 | | * The following code demonstrates using this function with a connection timeout: |
483 | | @code {.c} |
484 | | sockfd = fr_socket_client_unix(path, true); |
485 | | if (sockfd < 0) { |
486 | | fr_perror(); |
487 | | fr_exit_now(1); |
488 | | } |
489 | | if ((errno == EINPROGRESS) && (fr_socket_wait_for_connect(sockfd, timeout) < 0)) { |
490 | | error: |
491 | | fr_perror(); |
492 | | close(sockfd); |
493 | | goto error; |
494 | | } |
495 | | //Optionally, if blocking operation is required |
496 | | if (fr_blocking(sockfd) < 0) goto error; |
497 | | @endcode |
498 | | * |
499 | | * @param path to the file bound to the unix socket. |
500 | | * @param async Whether to set the socket to nonblocking, allowing use of |
501 | | * #fr_socket_wait_for_connect. |
502 | | * @return |
503 | | * - Socket FD on success. |
504 | | * - -1 on failure. |
505 | | */ |
506 | | int fr_socket_client_unix(char const *path, bool async) |
507 | 0 | { |
508 | 0 | int sockfd = -1; |
509 | 0 | size_t len; |
510 | 0 | socklen_t socklen; |
511 | 0 | struct sockaddr_un saremote; |
512 | |
|
513 | 0 | len = strlen(path); |
514 | 0 | if (len >= sizeof(saremote.sun_path)) { |
515 | 0 | fr_strerror_printf("Path too long, maximum length is %zu", sizeof(saremote.sun_path) - 1); |
516 | 0 | errno = EINVAL; |
517 | 0 | return -1; |
518 | 0 | } |
519 | | |
520 | 0 | sockfd = socket(AF_UNIX, SOCK_STREAM, 0); |
521 | 0 | if (sockfd < 0) { |
522 | 0 | fr_strerror_printf("Failed creating UNIX socket: %s", fr_syserror(errno)); |
523 | 0 | return -1; |
524 | 0 | } |
525 | | |
526 | 0 | if (async && (fr_nonblock(sockfd) < 0)) { |
527 | 0 | close(sockfd); |
528 | 0 | return -1; |
529 | 0 | } |
530 | | |
531 | 0 | saremote.sun_family = AF_UNIX; |
532 | 0 | memcpy(saremote.sun_path, path, len + 1); /* SUN_LEN does strlen */ |
533 | |
|
534 | 0 | socklen = SUN_LEN(&saremote); |
535 | | |
536 | | /* |
537 | | * Although we ignore SIGPIPE, some operating systems |
538 | | * like BSD and OSX ignore the ignoring. |
539 | | * |
540 | | * Fortunately, those operating systems usually support |
541 | | * SO_NOSIGPIPE, to prevent them raising the signal in |
542 | | * the first place. |
543 | | */ |
544 | | #ifdef SO_NOSIGPIPE |
545 | | { |
546 | | int set = 1; |
547 | | |
548 | | setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); |
549 | | } |
550 | | #endif |
551 | |
|
552 | 0 | if (connect(sockfd, (struct sockaddr *)&saremote, socklen) < 0) { |
553 | | /* |
554 | | * POSIX says the only time we will get this, |
555 | | * is if the socket has been marked as |
556 | | * nonblocking. This is not an error, the caller |
557 | | * must check the state of errno, and wait for |
558 | | * the connection to complete. |
559 | | */ |
560 | 0 | if (errno == EINPROGRESS) return sockfd; |
561 | | |
562 | 0 | close(sockfd); |
563 | 0 | fr_strerror_printf("Failed connecting to %s: %s", path, fr_syserror(errno)); |
564 | |
|
565 | 0 | return -1; |
566 | 0 | } |
567 | 0 | return sockfd; |
568 | 0 | } |
569 | | #else |
570 | | int fr_socket_client_unix(UNUSED char const *path, UNUSED bool async) |
571 | | { |
572 | | fprintf(stderr, "Unix domain sockets not supported on this system"); |
573 | | return -1; |
574 | | } |
575 | | #endif /* WITH_SYS_UN_H */ |
576 | | |
577 | | #if defined SO_BINDTODEVICE || defined IP_BOUND_IF |
578 | | static inline CC_HINT(always_inline) int socket_bind_ifname(int sockfd, char const *ifname) |
579 | | #else |
580 | | static inline CC_HINT(always_inline) int socket_bind_ifname(UNUSED int sockfd, UNUSED char const *ifname) |
581 | | #endif |
582 | 0 | { |
583 | 0 | #if defined(SO_BINDTODEVICE) |
584 | 0 | if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0) { |
585 | 0 | fr_strerror_printf("Failed binding socket to %s: %s", ifname, fr_syserror(errno)); |
586 | 0 | return -1; |
587 | 0 | } |
588 | 0 | #elif defined(IP_BOUND_IF) |
589 | 0 | { |
590 | 0 | int idx = if_nametoindex(ifname); |
591 | 0 | if (idx == 0) { |
592 | 0 | error: |
593 | 0 | fr_strerror_printf("Failed binding socket to %s: %s", ifname, fr_syserror(errno)); |
594 | 0 | return -1; |
595 | 0 | } |
596 | 0 | if (unlikely(setsockopt(sockfd, IPPROTO_IP, IP_BOUND_IF, &idx, sizeof(idx)) < 0)) goto error; |
597 | 0 | } |
598 | 0 | #else |
599 | 0 | fr_strerror_const("Binding sockets to interfaces not supported on this platform"); |
600 | 0 | return -1; |
601 | 0 | #endif |
602 | 0 |
|
603 | 0 | return 0; |
604 | 0 | } |
605 | | |
606 | | /** Establish a connected UDP socket |
607 | | * |
608 | | * Connected UDP sockets can be used with write(), unlike unconnected sockets |
609 | | * which must be used with sendto and recvfrom. |
610 | | * |
611 | | * The following code demonstrates using this function with a connection timeout: |
612 | | @code {.c} |
613 | | sockfd = fr_socket_client_udp(NULL, NULL, NULL, ipaddr, port, true); |
614 | | if (sockfd < 0) { |
615 | | fr_perror(); |
616 | | fr_exit_now(1); |
617 | | } |
618 | | if ((errno == EINPROGRESS) && (fr_socket_wait_for_connect(sockfd, timeout) < 0)) { |
619 | | error: |
620 | | fr_perror(); |
621 | | close(sockfd); |
622 | | goto error; |
623 | | } |
624 | | //Optionally, if blocking operation is required |
625 | | if (fr_blocking(sockfd) < 0) goto error; |
626 | | @endcode |
627 | | * |
628 | | * @param[in] ifname If non-NULL, bind the socket to this interface. |
629 | | * @param[in,out] src_ipaddr to bind socket to, may be NULL if socket is not bound to any specific |
630 | | * address. If non-null, the bound IP is copied here, too. |
631 | | * @param[out] src_port The source port we were bound to, may be NULL. |
632 | | * @param[in] dst_ipaddr Where to send datagrams. |
633 | | * @param[in] dst_port Where to send datagrams. |
634 | | * @param[in] async Whether to set the socket to nonblocking, allowing use of |
635 | | * #fr_socket_wait_for_connect. |
636 | | * @return |
637 | | * - FD on success. |
638 | | * - -1 on failure. |
639 | | */ |
640 | | int fr_socket_client_udp(char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, |
641 | | fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async) |
642 | 0 | { |
643 | 0 | int sockfd; |
644 | 0 | struct sockaddr_storage salocal; |
645 | 0 | socklen_t salen; |
646 | |
|
647 | 0 | if (!dst_ipaddr) return -1; |
648 | | |
649 | 0 | sockfd = socket(dst_ipaddr->af, SOCK_DGRAM, 0); |
650 | 0 | if (sockfd < 0) { |
651 | 0 | fr_strerror_printf("Error creating UDP socket: %s", fr_syserror(errno)); |
652 | 0 | return -1; |
653 | 0 | } |
654 | | |
655 | 0 | if (async && (fr_nonblock(sockfd) < 0)) { |
656 | 0 | error: |
657 | 0 | close(sockfd); |
658 | 0 | return -1; |
659 | 0 | } |
660 | | |
661 | | /* |
662 | | * Although we ignore SIGPIPE, some operating systems |
663 | | * like BSD and OSX ignore the ignoring. |
664 | | * |
665 | | * Fortunately, those operating systems usually support |
666 | | * SO_NOSIGPIPE, to prevent them raising the signal in |
667 | | * the first place. |
668 | | */ |
669 | | #ifdef SO_NOSIGPIPE |
670 | | { |
671 | | int set = 1; |
672 | | |
673 | | setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); |
674 | | } |
675 | | #endif |
676 | | |
677 | 0 | if (unlikely(fr_socket_bind(sockfd, ifname, src_ipaddr, src_port) < 0)) goto error; |
678 | | |
679 | | /* |
680 | | * And now get our destination |
681 | | */ |
682 | 0 | if (fr_ipaddr_to_sockaddr(&salocal, &salen, dst_ipaddr, dst_port) < 0) { |
683 | 0 | close(sockfd); |
684 | 0 | return -1; |
685 | 0 | } |
686 | | |
687 | 0 | if (connect(sockfd, (struct sockaddr *) &salocal, salen) < 0) { |
688 | | /* |
689 | | * POSIX says the only time we will get this, |
690 | | * is if the socket has been marked as |
691 | | * nonblocking. This is not an error, the caller |
692 | | * must check the state of errno, and wait for |
693 | | * the connection to complete. |
694 | | */ |
695 | 0 | if (errno == EINPROGRESS) return sockfd; |
696 | | |
697 | 0 | fr_strerror_printf("Failed connecting socket: %s", fr_syserror(errno)); |
698 | 0 | close(sockfd); |
699 | 0 | return -1; |
700 | 0 | } |
701 | | |
702 | 0 | return sockfd; |
703 | 0 | } |
704 | | |
705 | | /** Establish a connected TCP socket |
706 | | * |
707 | | * The following code demonstrates using this function with a connection timeout: |
708 | | @code {.c} |
709 | | sockfd = fr_socket_client_tcp(NULL, NULL, ipaddr, port, true); |
710 | | if (sockfd < 0) { |
711 | | fr_perror(); |
712 | | fr_exit_now(1); |
713 | | } |
714 | | if ((errno == EINPROGRESS) && (fr_socket_wait_for_connect(sockfd, timeout) < 0)) { |
715 | | error: |
716 | | fr_perror(); |
717 | | close(sockfd); |
718 | | goto error; |
719 | | } |
720 | | //Optionally, if blocking operation is required |
721 | | if (fr_blocking(sockfd) < 0) goto error; |
722 | | @endcode |
723 | | * |
724 | | * @param[in] ifname If non-NULL, bind the socket to this interface. |
725 | | * @param src_ipaddr to bind socket to, may be NULL if socket is not bound to any specific |
726 | | * address. |
727 | | * @param dst_ipaddr Where to connect to. |
728 | | * @param dst_port Where to connect to. |
729 | | * @param async Whether to set the socket to nonblocking, allowing use of |
730 | | * #fr_socket_wait_for_connect. |
731 | | * @return |
732 | | * - FD on success |
733 | | * - -1 on failure. |
734 | | */ |
735 | | int fr_socket_client_tcp(char const *ifname, fr_ipaddr_t *src_ipaddr, |
736 | | fr_ipaddr_t const *dst_ipaddr, uint16_t dst_port, bool async) |
737 | 0 | { |
738 | 0 | int sockfd; |
739 | 0 | struct sockaddr_storage salocal; |
740 | 0 | socklen_t salen; |
741 | |
|
742 | 0 | if (!dst_ipaddr) return -1; |
743 | | |
744 | 0 | sockfd = socket(dst_ipaddr->af, SOCK_STREAM, 0); |
745 | 0 | if (sockfd < 0) { |
746 | 0 | fr_strerror_printf("Error creating TCP socket: %s", fr_syserror(errno)); |
747 | 0 | return sockfd; |
748 | 0 | } |
749 | | |
750 | 0 | if (async && (fr_nonblock(sockfd) < 0)) { |
751 | 0 | error: |
752 | 0 | close(sockfd); |
753 | 0 | return -1; |
754 | 0 | } |
755 | | |
756 | 0 | if (unlikely(fr_socket_bind(sockfd, ifname, src_ipaddr, NULL) < 0)) goto error; |
757 | | |
758 | 0 | if (fr_ipaddr_to_sockaddr(&salocal, &salen, dst_ipaddr, dst_port) < 0) { |
759 | 0 | close(sockfd); |
760 | 0 | return -1; |
761 | 0 | } |
762 | | |
763 | | /* |
764 | | * Although we ignore SIGPIPE, some operating systems |
765 | | * like BSD and OSX ignore the ignoring. |
766 | | * |
767 | | * Fortunately, those operating systems usually support |
768 | | * SO_NOSIGPIPE, to prevent them raising the signal in |
769 | | * the first place. |
770 | | */ |
771 | | #ifdef SO_NOSIGPIPE |
772 | | { |
773 | | int set = 1; |
774 | | |
775 | | setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); |
776 | | } |
777 | | #endif |
778 | | |
779 | 0 | if (connect(sockfd, (struct sockaddr *) &salocal, salen) < 0) { |
780 | | /* |
781 | | * POSIX says the only time we will get this, |
782 | | * is if the socket has been marked as |
783 | | * nonblocking. This is not an error, the caller |
784 | | * must check the state of errno, and wait for |
785 | | * the connection to complete. |
786 | | */ |
787 | 0 | if (errno == EINPROGRESS) return sockfd; |
788 | | |
789 | 0 | fr_strerror_printf("Failed connecting socket: %s", fr_syserror(errno)); |
790 | 0 | close(sockfd); |
791 | 0 | return -1; |
792 | 0 | } |
793 | | |
794 | 0 | return sockfd; |
795 | 0 | } |
796 | | |
797 | | /** Wait for a socket to be connected, with an optional timeout |
798 | | * |
799 | | * @note On error the caller is expected to ``close(sockfd)``. |
800 | | * |
801 | | * @param sockfd the socket to wait on. |
802 | | * @param timeout How long to wait for socket to open. |
803 | | * @return |
804 | | * - 0 on success. |
805 | | * - -1 on connection error. |
806 | | * - -2 on timeout. |
807 | | * - -3 on select error. |
808 | | */ |
809 | | int fr_socket_wait_for_connect(int sockfd, fr_time_delta_t timeout) |
810 | | { |
811 | | int ret; |
812 | | fd_set error_set; |
813 | | fd_set write_set; /* POSIX says sockets are open when they become writable */ |
814 | | |
815 | | FD_ZERO(&error_set); |
816 | | FD_ZERO(&write_set); |
817 | | |
818 | | FD_SET(sockfd, &error_set); |
819 | | FD_SET(sockfd, &write_set); |
820 | | |
821 | | /* Don't let signals mess up the select */ |
822 | | do { |
823 | | ret = select(sockfd + 1, NULL, &write_set, &error_set, &fr_time_delta_to_timeval(timeout)); |
824 | | } while ((ret == -1) && (errno == EINTR)); |
825 | | |
826 | | switch (ret) { |
827 | | case 1: /* ok (maybe) */ |
828 | | { |
829 | | int error; |
830 | | socklen_t socklen = sizeof(error); |
831 | | |
832 | | if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&error, &socklen)) { |
833 | | fr_strerror_printf("Failed connecting socket: %s", fr_syserror(errno)); |
834 | | return -1; |
835 | | } |
836 | | |
837 | | if (FD_ISSET(sockfd, &error_set)) { |
838 | | fr_strerror_const("Failed connecting socket: Unknown error"); |
839 | | return -1; |
840 | | } |
841 | | } |
842 | | return 0; |
843 | | |
844 | | case 0: /* timeout */ |
845 | | if (!fr_cond_assert(fr_time_delta_ispos(timeout))) return -1; |
846 | | fr_strerror_printf("Connection timed out after %pVs", fr_box_time_delta(timeout)); |
847 | | return -2; |
848 | | |
849 | | case -1: /* select error */ |
850 | | fr_strerror_printf("Failed waiting for connection: %s", fr_syserror(errno)); |
851 | | return -3; |
852 | | |
853 | | default: |
854 | | (void)fr_cond_assert(0); |
855 | | return -1; |
856 | | } |
857 | | } |
858 | | |
859 | | /** Open an IPv4/IPv6 unconnected UDP socket |
860 | | * |
861 | | * Function name is a bit of a misnomer as it can also be used to create client sockets too, |
862 | | * such is the nature of UDP. |
863 | | * |
864 | | * @param[in] src_ipaddr The IP address to listen on |
865 | | * @param[in,out] src_port the port to listen on. If *port == 0, the resolved |
866 | | * service port will be written here. |
867 | | * @param[in] port_name if *port == 0, the name of the port |
868 | | * @param[in] async whether we block or not on reads and writes |
869 | | * @return |
870 | | * - Socket FD on success. |
871 | | * - -1 on failure. |
872 | | */ |
873 | | int fr_socket_server_udp(fr_ipaddr_t const *src_ipaddr, uint16_t *src_port, char const *port_name, bool async) |
874 | 0 | { |
875 | 0 | int sockfd; |
876 | 0 | uint16_t my_port = 0; |
877 | |
|
878 | 0 | if (src_port) my_port = *src_port; |
879 | | |
880 | | /* |
881 | | * Check IP looks OK |
882 | | */ |
883 | 0 | if (!src_ipaddr || ((src_ipaddr->af != AF_INET) && (src_ipaddr->af != AF_INET6))) { |
884 | 0 | fr_strerror_const("No address specified"); |
885 | 0 | return -1; |
886 | 0 | } |
887 | | |
888 | | /* |
889 | | * Check we have a port value or stuff we can resolve to a port |
890 | | */ |
891 | 0 | if (!my_port && port_name) { |
892 | 0 | int ret; |
893 | |
|
894 | 0 | ret = socket_port_from_service(IPPROTO_UDP, port_name); |
895 | 0 | if (ret < 0) return -1; |
896 | | |
897 | 0 | my_port = ret; |
898 | 0 | } |
899 | | |
900 | | /* |
901 | | * Open the socket |
902 | | */ |
903 | 0 | sockfd = socket(src_ipaddr->af, SOCK_DGRAM, IPPROTO_UDP); |
904 | 0 | if (sockfd < 0) { |
905 | 0 | fr_strerror_printf("Failed creating UDP socket: %s", fr_syserror(errno)); |
906 | 0 | return -1; |
907 | 0 | } |
908 | | |
909 | | /* |
910 | | * Make it non-blocking if asked |
911 | | */ |
912 | 0 | if (async && (fr_nonblock(sockfd) < 0)) { |
913 | 0 | error: |
914 | 0 | close(sockfd); |
915 | 0 | return -1; |
916 | 0 | } |
917 | | |
918 | | /* |
919 | | * Don't allow child processes to inherit the socket |
920 | | */ |
921 | 0 | if (socket_dont_inherit(sockfd) < 0) goto error; |
922 | | |
923 | | /* |
924 | | * Initialize udpfromto for UDP sockets. |
925 | | */ |
926 | 0 | if (udpfromto_init(sockfd, src_ipaddr->af) != 0) { |
927 | 0 | fr_strerror_printf("Failed initializing udpfromto: %s", fr_syserror(errno)); |
928 | 0 | goto error; |
929 | 0 | } |
930 | | |
931 | | /* |
932 | | * Make sure we don't get v4 and v6 packets on inaddr_any sockets. |
933 | | */ |
934 | 0 | if (socket_inaddr_any_v6only(sockfd, src_ipaddr) < 0) goto error; |
935 | | |
936 | | /* |
937 | | * Ensure don't fragment bit is set |
938 | | */ |
939 | 0 | if (socket_dont_fragment(sockfd, src_ipaddr->af) < 0) goto error; |
940 | | |
941 | 0 | #ifdef SO_TIMESTAMP |
942 | 0 | { |
943 | 0 | int on = 1; |
944 | | |
945 | | /* |
946 | | * Enable receive timestamps, these should reflect |
947 | | * when the packet was received, not when it was read |
948 | | * from the socket. |
949 | | */ |
950 | 0 | if (setsockopt(sockfd, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(int)) < 0) { |
951 | 0 | close(sockfd); |
952 | 0 | fr_strerror_printf("Failed enabling socket timestamps: %s", fr_syserror(errno)); |
953 | 0 | return -1; |
954 | 0 | } |
955 | 0 | } |
956 | 0 | #endif |
957 | | |
958 | 0 | if (src_port) *src_port = my_port; |
959 | |
|
960 | 0 | return sockfd; |
961 | 0 | } |
962 | | |
963 | | /** Open an IPv4/IPv6 TCP socket |
964 | | * |
965 | | * @param[in] src_ipaddr The IP address to listen on |
966 | | * @param[in,out] src_port the port to listen on. If *port == 0, the resolved |
967 | | * service port will be written here. |
968 | | * NULL if any port is allowed. |
969 | | * @param[in] port_name if *port == 0, the name of the port |
970 | | * @param[in] async whether we block or not on reads and writes |
971 | | * @return |
972 | | * - Socket FD on success. |
973 | | * - -1 on failure. |
974 | | */ |
975 | | int fr_socket_server_tcp(fr_ipaddr_t const *src_ipaddr, uint16_t *src_port, char const *port_name, bool async) |
976 | 0 | { |
977 | 0 | int sockfd; |
978 | 0 | uint16_t my_port = 0; |
979 | |
|
980 | 0 | if (src_port) my_port = *src_port; |
981 | | |
982 | | /* |
983 | | * Check IP looks OK |
984 | | */ |
985 | 0 | if (!src_ipaddr || ((src_ipaddr->af != AF_INET) && (src_ipaddr->af != AF_INET6))) { |
986 | 0 | fr_strerror_const("No address specified"); |
987 | 0 | return -1; |
988 | 0 | } |
989 | | |
990 | | /* |
991 | | * Check we have a port value or stuff we can resolve to a port |
992 | | */ |
993 | 0 | if (!my_port && port_name) { |
994 | 0 | int ret; |
995 | |
|
996 | 0 | ret = socket_port_from_service(IPPROTO_TCP, port_name); |
997 | 0 | if (ret < 0) return -1; |
998 | | |
999 | 0 | my_port = ret; |
1000 | 0 | } |
1001 | | |
1002 | | /* |
1003 | | * Open the socket |
1004 | | */ |
1005 | 0 | sockfd = socket(src_ipaddr->af, SOCK_STREAM, IPPROTO_TCP); |
1006 | 0 | if (sockfd < 0) { |
1007 | 0 | fr_strerror_printf("Failed creating TCP socket: %s", fr_syserror(errno)); |
1008 | 0 | return -1; |
1009 | 0 | } |
1010 | | |
1011 | | /* |
1012 | | * Make it non-blocking if asked |
1013 | | */ |
1014 | 0 | if (async && (fr_nonblock(sockfd) < 0)) { |
1015 | 0 | error: |
1016 | 0 | close(sockfd); |
1017 | 0 | return -1; |
1018 | 0 | } |
1019 | | |
1020 | | /* |
1021 | | * Don't allow child processes to inherit the socket |
1022 | | */ |
1023 | 0 | if (socket_dont_inherit(sockfd) < 0) goto error; |
1024 | | |
1025 | | /* |
1026 | | * Make sure we don't get v4 and v6 packets on inaddr_any sockets. |
1027 | | */ |
1028 | 0 | if (socket_inaddr_any_v6only(sockfd, src_ipaddr) < 0) goto error; |
1029 | | |
1030 | 0 | { |
1031 | 0 | int on = 1; |
1032 | |
|
1033 | 0 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { |
1034 | 0 | close(sockfd); |
1035 | 0 | fr_strerror_printf("Failed to reuse address: %s", fr_syserror(errno)); |
1036 | 0 | return -1; |
1037 | 0 | } |
1038 | 0 | } |
1039 | | |
1040 | 0 | if (src_port) *src_port = my_port; |
1041 | |
|
1042 | 0 | return sockfd; |
1043 | 0 | } |