The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
udpfromto.c
Go to the documentation of this file.
1/*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2.1 of the License, or (at your option) any later version.
6 *
7 * This library 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 GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/** API for sending and receiving packets on unconnected UDP sockets
18 *
19 * Like recvfrom, but also stores the destination IP address. Useful on multihomed hosts.
20 *
21 * @file src/lib/util/udpfromto.c
22 *
23 * @copyright 2007 Alan DeKok (aland@deployingradius.com)
24 * @copyright 2002 Miquel van Smoorenburg
25 */
26RCSID("$Id: 3fabd1c3c33967bf5924f252e854fc4f9216145c $")
27
28#include <freeradius-devel/util/udpfromto.h>
29
30#ifdef HAVE_SYS_UIO_H
31# include <sys/uio.h>
32#endif
33#ifdef HAVE_NET_IF_DL_H
34# include <net/if_dl.h>
35#endif
36
37#include <fcntl.h>
38
39/*
40 * More portability idiocy
41 * Mac OSX Lion doesn't define SOL_IP. But IPPROTO_IP works.
42 */
43#ifndef SOL_IP
44# define SOL_IP IPPROTO_IP
45#endif
46
47/*
48 * glibc 2.4 and uClibc 0.9.29 introduce IPV6_RECVPKTINFO etc. and
49 * change IPV6_PKTINFO This is only supported in Linux kernel >=
50 * 2.6.14
51 *
52 * This is only an approximation because the kernel version that libc
53 * was compiled against could be older or newer than the one being
54 * run. But this should not be a problem -- we just keep using the
55 * old kernel interface.
56 */
57#ifdef __linux__
58# ifdef IPV6_RECVPKTINFO
59# include <linux/version.h>
60# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
61# ifdef IPV6_2292PKTINFO
62# undef IPV6_RECVPKTINFO
63# undef IPV6_PKTINFO
64# define IPV6_RECVPKTINFO IPV6_2292PKTINFO
65# define IPV6_PKTINFO IPV6_2292PKTINFO
66# endif
67# endif
68/* Fall back to the legacy socket option if IPV6_RECVPKTINFO isn't defined */
69# elif defined(IPV6_2292PKTINFO)
70# define IPV6_RECVPKTINFO IPV6_2292PKTINFO
71# endif
72#else
73
74/*
75 * For everything that's not Linux we assume RFC 3542 compliance
76 * - setsockopt() takes IPV6_RECVPKTINFO
77 * - cmsg_type is IPV6_PKTINFO (in sendmsg, recvmsg)
78 *
79 * If we don't have IPV6_RECVPKTINFO defined but do have IPV6_PKTINFO
80 * defined, chances are the API is RFC2292 compliant and we need to use
81 * IPV6_PKTINFO for both.
82 */
83# if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
84# define IPV6_RECVPKTINFO IPV6_PKTINFO
85
86/*
87 * Ensure IPV6_RECVPKTINFO is not defined somehow if we have we
88 * don't have IPV6_PKTINFO.
89 */
90# elif !defined(IPV6_PKTINFO)
91# undef IPV6_RECVPKTINFO
92# endif
93#endif
94
95int udpfromto_init(int s, int af)
96{
97 int proto = 0, flag = 0, opt = 1;
98
99 errno = ENOSYS;
100
101 if (af == AF_UNSPEC) {
102 struct sockaddr_storage si;
103 socklen_t si_len = sizeof(si);
104
105 /*
106 * Static analyzer doesn't see that getsockname initialises
107 * the memory passed to it.
108 */
109#ifdef STATIC_ANALYZER
110 memset(&si, 0, sizeof(si));
111#endif
112
113 if (getsockname(s, (struct sockaddr *) &si, &si_len) < 0) {
114 return -1;
115 }
116
117 af = si.ss_family;
118 }
119
120 if (af == AF_INET) {
121#ifdef HAVE_IP_PKTINFO
122 /*
123 * Linux
124 */
125 proto = SOL_IP;
126 flag = IP_PKTINFO;
127#else
128# ifdef IP_RECVDSTADDR
129
130 /*
131 * Set the IP_RECVDSTADDR option (BSD). Note:
132 * IP_RECVDSTADDR == IP_SENDSRCADDR
133 */
134 proto = IPPROTO_IP;
135 flag = IP_RECVDSTADDR;
136
137 /*
138 * Where Linux uses IP_PKTINFO for both IP and interface
139 * information, BSD uses IP_RECVDSTADDR and IP_RECVIF
140 */
141# ifdef IP_RECVIF
142 if (setsockopt(s, proto, IP_RECVIF, &opt, sizeof(opt)) != 0) return -1;
143# endif
144# else
145 return -1;
146# endif
147#endif
148
149#if defined(AF_INET6) && defined(IPV6_PKTINFO)
150 } else if (af == AF_INET6) {
151 /*
152 * This should actually be standard IPv6
153 */
154 proto = IPPROTO_IPV6;
155
156 /*
157 * Work around Linux-specific hackery.
158 */
159 flag = IPV6_RECVPKTINFO;
160 } else {
161#endif
162
163 /*
164 * Unknown AF. Return an error if possible.
165 */
166# ifdef EPROTONOSUPPORT
167 errno = EPROTONOSUPPORT;
168# endif
169 return -1;
170 }
171
172 return setsockopt(s, proto, flag, &opt, sizeof(opt));
173}
174
175/** Read a packet from a file descriptor, retrieving additional header information
176 *
177 * Abstracts away the complexity of using the complexity of using recvmsg().
178 *
179 * In addition to reading data from the file descriptor, the src and dst addresses
180 * and the receiving interface index are retrieved. This enables us to send
181 * replies using the correct IP interface, in the case where the server is multihomed.
182 * This is not normally possible on unconnected datagram sockets.
183 *
184 * @param[in] fd The file descriptor to read from.
185 * @param[out] buf Where to write the received datagram data.
186 * @param[in] len of buf.
187 * @param[in] flags passed unmolested to recvmsg.
188 * @param[out] ifindex The interface which received the datagram (may be NULL).
189 * Will only be populated if to is not NULL.
190 * @param[out] from Where to write the source address.
191 * @param[in] from_len Length of the structure pointed to by from.
192 * @param[out] to Where to write the destination address. If NULL recvmsg()
193 * will be used instead.
194 * @param[in] to_len Length of the structure pointed to by to.
195 * @param[out] when the packet was received (may be NULL). If SO_TIMESTAMP is
196 * not available or SO_TIMESTAMP Was not set on the socket,
197 * then another method will be used instead to get the time.
198 * @return
199 * - 0 on success.
200 * - -1 on failure.
201 */
202int recvfromto(int fd, void *buf, size_t len, int flags,
203 int *ifindex,
204 struct sockaddr *from, socklen_t *from_len,
205 struct sockaddr *to, socklen_t *to_len,
206 fr_time_t *when)
207{
208 struct msghdr msgh;
209 struct cmsghdr *cmsg;
210 struct iovec iov;
211 char cbuf[256];
212 int ret;
213 struct sockaddr_storage si;
214 socklen_t si_len = sizeof(si);
215
216#if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR) && !defined(IPV6_PKTINFO)
217 /*
218 * If the recvmsg() flags aren't defined, fall back to
219 * using recvfrom().
220 */
221 to = NULL:
222#endif
223
224 /*
225 * Catch the case where the caller passes invalid arguments.
226 */
227 if (!to || !to_len) {
228 if (when) *when = fr_time();
229 return recvfrom(fd, buf, len, flags, from, from_len);
230 }
231
232 /*
233 * Static analyzer doesn't see that getsockname initialises
234 * the memory passed to it.
235 */
236#ifdef STATIC_ANALYZER
237 memset(&si, 0, sizeof(si));
238#endif
239
240 /*
241 * recvmsg doesn't provide sin_port so we have to
242 * retrieve it using getsockname().
243 */
244 if (getsockname(fd, (struct sockaddr *)&si, &si_len) < 0) {
245 return -1;
246 }
247
248 /*
249 * Initialize the 'to' address. It may be INADDR_ANY here,
250 * with a more specific address given by recvmsg(), below.
251 */
252 if (si.ss_family == AF_INET) {
253#if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR)
254 return recvfrom(fd, buf, len, flags, from, from_len);
255#else
256 struct sockaddr_in *dst = (struct sockaddr_in *) to;
257 struct sockaddr_in *src = (struct sockaddr_in *) &si; //-V641
258
259 if (*to_len < sizeof(*dst)) {
260 errno = EINVAL;
261 return -1;
262 }
263 *to_len = sizeof(*dst);
264 *dst = *src;
265#endif
266 }
267
268#ifdef AF_INET6
269 else if (si.ss_family == AF_INET6) {
270#if !defined(IPV6_PKTINFO)
271 return recvfrom(fd, buf, len, flags, from, from_len);
272#else
273 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) to;
274 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &si; //-V641
275
276 if (*to_len < sizeof(*dst)) {
277 errno = EINVAL;
278 return -1;
279 }
280 *to_len = sizeof(*dst);
281 *dst = *src;
282#endif
283 }
284#endif
285 /*
286 * Unknown address family.
287 */
288 else {
289 errno = EINVAL;
290 return -1;
291 }
292
293 /* Set up iov and msgh structures. */
294 memset(&cbuf, 0, sizeof(cbuf));
295 memset(&msgh, 0, sizeof(struct msghdr));
296 iov.iov_base = buf;
297 iov.iov_len = len;
298 msgh.msg_control = cbuf;
299 msgh.msg_controllen = sizeof(cbuf);
300 msgh.msg_name = from;
301 msgh.msg_namelen = from_len ? *from_len : 0;
302 msgh.msg_iov = &iov;
303 msgh.msg_iovlen = 1;
304 msgh.msg_flags = 0;
305
306 /* Receive one packet. */
307 ret = recvmsg(fd, &msgh, flags);
308 if (ret < 0) return ret;
309
310 if (from_len) *from_len = msgh.msg_namelen;
311
312 if (ifindex) *ifindex = 0;
313 if (when) *when = fr_time_wrap(0);
314
315/*
316 * Needed for emscripten, seems to be an issue in CMSG_NXTHDR
317 */
318DIAG_OFF(sign-compare)
319 /* Process auxiliary received data in msgh */
320 for (cmsg = CMSG_FIRSTHDR(&msgh);
321 cmsg != NULL;
322 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
323DIAG_ON(sign-compare)
324
325#ifdef IP_PKTINFO
326 if ((cmsg->cmsg_level == SOL_IP) &&
327 (cmsg->cmsg_type == IP_PKTINFO)) {
328 struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg);
329
330 ((struct sockaddr_in *)to)->sin_addr = i->ipi_addr;
331 *to_len = sizeof(struct sockaddr_in);
332
333 if (ifindex) *ifindex = i->ipi_ifindex;
334
335 break;
336 }
337#endif
338
339#ifdef IP_RECVDSTADDR
340 if ((cmsg->cmsg_level == IPPROTO_IP) &&
341 (cmsg->cmsg_type == IP_RECVDSTADDR)) {
342 struct in_addr *i = (struct in_addr *) CMSG_DATA(cmsg);
343
344 ((struct sockaddr_in *)to)->sin_addr = *i;
345
346 *to_len = sizeof(struct sockaddr_in);
347
348#ifdef IP_RECVIF
349 continue;
350#else
351 break;
352#endif
353 }
354#endif
355
356#ifdef IP_RECVIF
357 if ((cmsg->cmsg_level == IPPROTO_IP) &&
358 (cmsg->cmsg_type == IP_RECVIF)) {
359 struct sockaddr_dl *sd = (struct sockaddr_dl *) CMSG_DATA(cmsg);
360
361 if (ifindex) *ifindex = sd->sdl_index;
362
363#ifdef IP_RECVDSTADDR
364 continue;
365#else
366 break;
367#endif
368 }
369#endif
370
371#ifdef IPV6_PKTINFO
372 if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
373 (cmsg->cmsg_type == IPV6_PKTINFO)) {
374 struct in6_pktinfo *i = (struct in6_pktinfo *) CMSG_DATA(cmsg);
375
376 ((struct sockaddr_in6 *)to)->sin6_addr = i->ipi6_addr;
377 *to_len = sizeof(struct sockaddr_in6);
378
379 if (ifindex) *ifindex = i->ipi6_ifindex;
380
381 break;
382 }
383#endif
384
385#ifdef SO_TIMESTAMP
386 if (when && (cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
387 *when = fr_time_from_timeval((struct timeval *)CMSG_DATA(cmsg));
388 }
389#endif
390
391#ifdef SO_TIMESTAMPNS
392 if (when && (cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
393 *when = fr_time_from_timespec((struct timespec *)CMSG_DATA(cmsg));
394 }
395#endif
396 }
397
398 if (when && fr_time_eq(*when, fr_time_wrap(0))) *when = fr_time();
399
400 return ret;
401}
402
403/** Send packet via a file descriptor, setting the src address and outbound interface
404 *
405 * Abstracts away the complexity of using the complexity of using sendmsg().
406 *
407 * @param[in] fd The file descriptor to write to.
408 * @param[in] buf Where to read datagram data from.
409 * @param[in] len of datagram data.
410 * @param[in] flags passed unmolested to sendmsg.
411 * @param[in] ifindex The interface on which to send the datagram.
412 * If automatic interface selection is desired, value should be 0.
413 * @param[in] from The source address.
414 * @param[in] from_len Length of the structure pointed to by from.
415 * @param[in] to The destination address.
416 * @param[in] to_len Length of the structure pointed to by to.
417 * @return
418 * - 0 on success.
419 * - -1 on failure.
420 */
421int sendfromto(int fd, void *buf, size_t len, int flags,
422 int ifindex,
423 struct sockaddr *from, socklen_t from_len,
424 struct sockaddr *to, socklen_t to_len)
425{
426 struct msghdr msgh;
427 struct iovec iov;
428 char cbuf[256];
429
430 /*
431 * Unknown address family, die.
432 */
433 if (from && (from->sa_family != AF_INET) && (from->sa_family != AF_INET6)) {
434 errno = EINVAL;
435 return -1;
436 }
437
438#ifdef __FreeBSD__
439 /*
440 * FreeBSD is extra pedantic about the use of IP_SENDSRCADDR,
441 * and sendmsg will fail with EINVAL if IP_SENDSRCADDR is used
442 * with a socket which is bound to something other than
443 * INADDR_ANY
444 */
445 {
446 struct sockaddr bound;
447 socklen_t bound_len = sizeof(bound);
448
449 if (getsockname(fd, &bound, &bound_len) < 0) {
450 return -1;
451 }
452
453 switch (bound.sa_family) {
454 case AF_INET:
455 if (((struct sockaddr_in *) &bound)->sin_addr.s_addr != INADDR_ANY) {
456 from = NULL;
457 }
458 break;
459
460 case AF_INET6:
461 if (!IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) &bound)->sin6_addr)) {
462 from = NULL;
463 }
464 break;
465 }
466 }
467#endif /* !__FreeBSD__ */
468
469 /*
470 * If the sendmsg() flags aren't defined, fall back to
471 * using sendto(). These flags are defined on FreeBSD,
472 * but laying it out this way simplifies the look of the
473 * code.
474 */
475# if !defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR)
476 if (from && from->sa_family == AF_INET) from = NULL;
477# endif
478
479# if !defined(IPV6_PKTINFO)
480 if (from && from->sa_family == AF_INET6) from = NULL;
481# endif
482
483 /*
484 * No "from" or "from" is 0.0.0.0 or ::/0, and there's no
485 * interface binding, just use regular sendto.
486 */
487 if (!from || (from_len == 0) ||
488 ((ifindex == 0) &&
489 ((from->sa_family == AF_INET &&
490 (((struct sockaddr_in *) from)->sin_addr.s_addr == INADDR_ANY)) ||
491 (from->sa_family == AF_INET6 &&
492 IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) from)->sin6_addr))))) {
493 return sendto(fd, buf, len, flags, to, to_len);
494 }
495
496 /* Set up control buffer iov and msgh structures. */
497 memset(&cbuf, 0, sizeof(cbuf));
498 memset(&msgh, 0, sizeof(msgh));
499 memset(&iov, 0, sizeof(iov));
500 iov.iov_base = buf;
501 iov.iov_len = len;
502
503 msgh.msg_iov = &iov;
504 msgh.msg_iovlen = 1;
505 msgh.msg_name = to;
506 msgh.msg_namelen = to_len;
507
508# if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR)
509 if (from->sa_family == AF_INET) {
510 struct sockaddr_in *s4 = (struct sockaddr_in *) from;
511
512# ifdef IP_PKTINFO
513 struct cmsghdr *cmsg;
514 struct in_pktinfo *pkt;
515
516 msgh.msg_control = cbuf;
517 msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));
518
519 cmsg = CMSG_FIRSTHDR(&msgh);
520 cmsg->cmsg_level = SOL_IP;
521 cmsg->cmsg_type = IP_PKTINFO;
522 cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
523
524 pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
525 memset(pkt, 0, sizeof(*pkt));
526 pkt->ipi_spec_dst = s4->sin_addr;
527 pkt->ipi_ifindex = ifindex;
528
529# elif defined(IP_SENDSRCADDR)
530 struct cmsghdr *cmsg;
531 struct in_addr *in;
532
533 msgh.msg_control = cbuf;
534 msgh.msg_controllen = CMSG_SPACE(sizeof(*in));
535
536 cmsg = CMSG_FIRSTHDR(&msgh);
537 cmsg->cmsg_level = IPPROTO_IP;
538 cmsg->cmsg_type = IP_SENDSRCADDR;
539 cmsg->cmsg_len = CMSG_LEN(sizeof(*in));
540
541 in = (struct in_addr *) CMSG_DATA(cmsg);
542 *in = s4->sin_addr;
543# endif
544 }
545#endif
546
547# if defined(IPV6_PKTINFO)
548 if (from->sa_family == AF_INET6) {
549 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) from;
550
551 struct cmsghdr *cmsg;
552 struct in6_pktinfo *pkt;
553
554 msgh.msg_control = cbuf;
555 msgh.msg_controllen = CMSG_SPACE(sizeof(*pkt));
556
557 cmsg = CMSG_FIRSTHDR(&msgh);
558 cmsg->cmsg_level = IPPROTO_IPV6;
559 cmsg->cmsg_type = IPV6_PKTINFO;
560 cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
561
562 pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg);
563 memset(pkt, 0, sizeof(*pkt));
564 pkt->ipi6_addr = s6->sin6_addr;
565 pkt->ipi6_ifindex = ifindex;
566 }
567# endif /* IPV6_PKTINFO */
568
569 return sendmsg(fd, &msgh, flags);
570}
571
572
573#ifdef TESTING
574/*
575 * Small test program to test recvfromto/sendfromto
576 *
577 * use a virtual IP address as first argument to test
578 *
579 * reply packet should originate from virtual IP and not
580 * from the default interface the alias is bound to
581 */
582# include <sys/wait.h>
583
584# define DEF_PORT 20000 /* default port to listen on */
585# define DESTIP "127.0.0.1" /* send packet to localhost per default */
586# define TESTSTRING "foo" /* what to send */
587# define TESTLEN 4 /* 4 bytes */
588
589int main(int argc, char **argv)
590{
591 struct sockaddr_in from, to, in;
592 char buf[TESTLEN];
593 char *destip = DESTIP;
594 uint16_t port = DEF_PORT;
595 int n, server_socket, client_socket, fl, tl, pid;
596 int ifindex;
597 fr_time_t when;
598
599 if (argc > 1) destip = argv[1];
600 if (argc > 2) port = atoi(argv[2]);
601
602 in.sin_family = AF_INET;
603 in.sin_addr.s_addr = INADDR_ANY;
604 in.sin_port = htons(port);
605 fl = tl = sizeof(struct sockaddr_in);
606 memset(&from, 0, sizeof(from));
607 memset(&to, 0, sizeof(to));
608
609 switch (pid = fork()) {
610 case -1:
611 perror("fork");
612 return 0;
613 case 0:
614 /* child */
615 usleep(100000);
616 goto client;
617 }
618
619 /* parent: server */
620 server_socket = socket(PF_INET, SOCK_DGRAM, 0);
621 if (udpfromto_init(server_socket, AF_INET) != 0) {
622 perror("udpfromto_init\n");
623 waitpid(pid, NULL, WNOHANG);
624 return 0;
625 }
626
627 if (bind(server_socket, (struct sockaddr *)&in, sizeof(in)) < 0) {
628 perror("server: bind");
629 waitpid(pid, NULL, WNOHANG);
630 return 0;
631 }
632
633 printf("server: waiting for packets on INADDR_ANY:%d\n", port);
634 if ((n = recvfromto(server_socket, buf, sizeof(buf), 0,
635 (struct sockaddr *)&from, &fl,
636 (struct sockaddr *)&to, &tl, &ifindex, &when)) < 0) {
637 perror("server: recvfromto");
638 waitpid(pid, NULL, WNOHANG);
639 return 0;
640 }
641
642 printf("server: received a packet of %d bytes [%s] ", n, buf);
643 printf("(src ip:port %s:%d ",
644 inet_ntoa(from.sin_addr), ntohs(from.sin_port));
645 printf(" dst ip:port %s:%d) via if %i\n",
646 inet_ntoa(to.sin_addr), ntohs(to.sin_port), ifindex);
647
648 printf("server: replying from address packet was received on to source address\n");
649
650 if ((n = sendfromto(server_socket, buf, n, 0,
651 0,
652 (struct sockaddr *)&to, tl,
653 (struct sockaddr *)&from, fl)) < 0) {
654 perror("server: sendfromto");
655 }
656
657 waitpid(pid, NULL, 0);
658 return 0;
659
660client:
661 close(server_socket);
662 client_socket = socket(PF_INET, SOCK_DGRAM, 0);
663 fr_assert_fatal_msg(udpfromto_init(client_socket, AF_INET) != 0, "udpfromto_init - %s", fr_syserror(errno));
664
665 /* bind client on different port */
666 in.sin_port = htons(port+1);
667 fr_assert_fatal_msg(bind(client_socket, (struct sockaddr *)&in, sizeof(in)) < 0,
668 "client: bind - %s", fr_syserror(errno));
669
670 in.sin_port = htons(port);
671 in.sin_addr.s_addr = inet_addr(destip);
672
673 printf("client: sending packet to %s:%d\n", destip, port);
674 fr_assert_fatal_msg(sendto(client_socket, TESTSTRING, TESTLEN, 0, (struct sockaddr *)&in, sizeof(in)) < 0,
675 "client: sendto");
676
677 printf("client: waiting for reply from server on INADDR_ANY:%d\n", port+1);
678
679 fr_assert_fatal_msg((n = recvfromto(client_socket, buf, sizeof(buf), 0,
680 (struct sockaddr *)&from, &fl,
681 (struct sockaddr *)&to, &tl, &ifindex, NULL)) < 0,
682 "client: recvfromto - %s", fr_syserror(errno));
683
684 printf("client: received a packet of %d bytes [%s] ", n, buf);
685 printf("(src ip:port %s:%d",
686 inet_ntoa(from.sin_addr), ntohs(from.sin_port));
687 printf(" dst ip:port %s:%d) via if %i\n",
688 inet_ntoa(to.sin_addr), ntohs(to.sin_port), ifindex);
689
690 return EXIT_SUCCESS;
691}
692
693#endif /* TESTING */
int n
Definition acutest.h:577
#define RCSID(id)
Definition build.h:485
#define DIAG_ON(_x)
Definition build.h:460
#define DIAG_OFF(_x)
Definition build.h:459
int main(int argc, char **argv)
Definition dhcpclient.c:531
static fr_slen_t in
Definition dict.h:841
waitpid(reap->pid_ev->pid, &status, 0)
static int client_socket(char const *server)
Definition radmin.c:183
unsigned short uint16_t
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
static fr_time_t fr_time_from_timeval(struct timeval const *when_tv)
Convert a timeval (wallclock time) to a fr_time_t (internal time)
Definition time.h:896
#define fr_time_wrap(_time)
Definition time.h:145
#define fr_time_eq(_a, _b)
Definition time.h:241
static fr_time_t fr_time_from_timespec(struct timespec const *when_ts)
Convert a timespec (wallclock time) to a fr_time_t (internal time)
Definition time.h:878
"server local" time.
Definition time.h:69
close(uq->fd)
int sendfromto(int fd, void *buf, size_t len, int flags, int ifindex, struct sockaddr *from, socklen_t from_len, struct sockaddr *to, socklen_t to_len)
Send packet via a file descriptor, setting the src address and outbound interface.
Definition udpfromto.c:421
#define SOL_IP
Definition udpfromto.c:44
int udpfromto_init(int s, int af)
Definition udpfromto.c:95
int recvfromto(int fd, void *buf, size_t len, int flags, int *ifindex, struct sockaddr *from, socklen_t *from_len, struct sockaddr *to, socklen_t *to_len, fr_time_t *when)
Read a packet from a file descriptor, retrieving additional header information.
Definition udpfromto.c:202