26 RCSID(
"$Id: 5a8e92fb8fb6a3855f0d1dc30d321799b92ea81e $")
28 #include <freeradius-devel/util/udpfromto.h>
41 # define SOL_IP IPPROTO_IP
55 # ifdef IPV6_RECVPKTINFO
56 # include <linux/version.h>
57 # if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
58 # ifdef IPV6_2292PKTINFO
59 # undef IPV6_RECVPKTINFO
61 # define IPV6_RECVPKTINFO IPV6_2292PKTINFO
62 # define IPV6_PKTINFO IPV6_2292PKTINFO
66 # elif defined(IPV6_2292PKTINFO)
67 # define IPV6_RECVPKTINFO IPV6_2292PKTINFO
80 # if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
81 # define IPV6_RECVPKTINFO IPV6_PKTINFO
87 # elif !defined(IPV6_PKTINFO)
88 # undef IPV6_RECVPKTINFO
94 int proto = 0, flag = 0, opt = 1;
98 if (af == AF_UNSPEC) {
99 struct sockaddr_storage si;
100 socklen_t si_len =
sizeof(si);
106 #ifdef STATIC_ANALYZER
107 memset(&si, 0,
sizeof(si));
110 if (getsockname(s, (
struct sockaddr *) &si, &si_len) < 0) {
118 #ifdef HAVE_IP_PKTINFO
125 # ifdef IP_RECVDSTADDR
132 flag = IP_RECVDSTADDR;
138 #if defined(AF_INET6) && defined(IPV6_PKTINFO)
139 }
else if (af == AF_INET6) {
143 proto = IPPROTO_IPV6;
148 flag = IPV6_RECVPKTINFO;
155 # ifdef EPROTONOSUPPORT
156 errno = EPROTONOSUPPORT;
161 return setsockopt(s,
proto, flag, &opt,
sizeof(opt));
193 struct sockaddr *from, socklen_t *from_len,
194 struct sockaddr *to, socklen_t *to_len,
198 struct cmsghdr *cmsg;
202 struct sockaddr_storage si;
203 socklen_t si_len =
sizeof(si);
205 #if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR) && !defined(IPV6_PKTINFO)
216 if (!to || !to_len) {
218 return recvfrom(fd, buf, len, flags, from, from_len);
225 #ifdef STATIC_ANALYZER
226 memset(&si, 0,
sizeof(si));
233 if (getsockname(fd, (
struct sockaddr *)&si, &si_len) < 0) {
241 if (si.ss_family == AF_INET) {
242 #if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR)
243 return recvfrom(fd, buf, len, flags, from, from_len);
245 struct sockaddr_in *dst = (
struct sockaddr_in *) to;
246 struct sockaddr_in *src = (
struct sockaddr_in *) &si;
248 if (*to_len <
sizeof(*dst)) {
252 *to_len =
sizeof(*dst);
258 else if (si.ss_family == AF_INET6) {
259 #if !defined(IPV6_PKTINFO)
260 return recvfrom(fd, buf, len, flags, from, from_len);
262 struct sockaddr_in6 *dst = (
struct sockaddr_in6 *) to;
263 struct sockaddr_in6 *src = (
struct sockaddr_in6 *) &si;
265 if (*to_len <
sizeof(*dst)) {
269 *to_len =
sizeof(*dst);
283 memset(&cbuf, 0,
sizeof(cbuf));
284 memset(&msgh, 0,
sizeof(
struct msghdr));
287 msgh.msg_control = cbuf;
288 msgh.msg_controllen =
sizeof(cbuf);
289 msgh.msg_name = from;
290 msgh.msg_namelen = from_len ? *from_len : 0;
296 ret = recvmsg(fd, &msgh, flags);
297 if (ret < 0)
return ret;
299 if (from_len) *from_len = msgh.msg_namelen;
301 if (ifindex) *ifindex = 0;
309 for (cmsg = CMSG_FIRSTHDR(&msgh);
311 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
315 if ((cmsg->cmsg_level ==
SOL_IP) &&
316 (cmsg->cmsg_type == IP_PKTINFO)) {
317 struct in_pktinfo *i = (
struct in_pktinfo *) CMSG_DATA(cmsg);
319 ((
struct sockaddr_in *)to)->sin_addr = i->ipi_addr;
320 *to_len =
sizeof(
struct sockaddr_in);
322 if (ifindex) *ifindex = i->ipi_ifindex;
328 #ifdef IP_RECVDSTADDR
329 if ((cmsg->cmsg_level == IPPROTO_IP) &&
330 (cmsg->cmsg_type == IP_RECVDSTADDR)) {
331 struct in_addr *i = (
struct in_addr *) CMSG_DATA(cmsg);
333 ((
struct sockaddr_in *)to)->sin_addr = *i;
335 *to_len =
sizeof(
struct sockaddr_in);
342 if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
343 (cmsg->cmsg_type == IPV6_PKTINFO)) {
344 struct in6_pktinfo *i = (
struct in6_pktinfo *) CMSG_DATA(cmsg);
346 ((
struct sockaddr_in6 *)to)->sin6_addr = i->ipi6_addr;
347 *to_len =
sizeof(
struct sockaddr_in6);
349 if (ifindex) *ifindex = i->ipi6_ifindex;
356 if (when && (cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
361 #ifdef SO_TIMESTAMPNS
362 if (when && (cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
393 struct sockaddr *from, socklen_t from_len,
394 struct sockaddr *to, socklen_t to_len)
403 if (from && (from->sa_family != AF_INET) && (from->sa_family != AF_INET6)) {
416 struct sockaddr bound;
417 socklen_t bound_len =
sizeof(bound);
419 if (getsockname(fd, &bound, &bound_len) < 0) {
423 switch (bound.sa_family) {
425 if (((
struct sockaddr_in *) &bound)->sin_addr.s_addr != INADDR_ANY) {
431 if (!IN6_IS_ADDR_UNSPECIFIED(&((
struct sockaddr_in6 *) &bound)->sin6_addr)) {
445 # if !defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR)
446 if (from && from->sa_family == AF_INET) from = NULL;
449 # if !defined(IPV6_PKTINFO)
450 if (from && from->sa_family == AF_INET6) from = NULL;
457 if (!from || (from_len == 0) ||
459 ((from->sa_family == AF_INET &&
460 (((
struct sockaddr_in *) from)->sin_addr.s_addr == INADDR_ANY)) ||
461 (from->sa_family == AF_INET6 &&
462 IN6_IS_ADDR_UNSPECIFIED(&((
struct sockaddr_in6 *) from)->sin6_addr))))) {
463 return sendto(fd, buf, len, flags, to, to_len);
467 memset(&cbuf, 0,
sizeof(cbuf));
468 memset(&msgh, 0,
sizeof(msgh));
469 memset(&iov, 0,
sizeof(iov));
476 msgh.msg_namelen = to_len;
478 # if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR)
479 if (from->sa_family == AF_INET) {
480 struct sockaddr_in *s4 = (
struct sockaddr_in *) from;
483 struct cmsghdr *cmsg;
484 struct in_pktinfo *pkt;
486 msgh.msg_control = cbuf;
487 msgh.msg_controllen = CMSG_SPACE(
sizeof(*pkt));
489 cmsg = CMSG_FIRSTHDR(&msgh);
490 cmsg->cmsg_level =
SOL_IP;
491 cmsg->cmsg_type = IP_PKTINFO;
492 cmsg->cmsg_len = CMSG_LEN(
sizeof(*pkt));
494 pkt = (
struct in_pktinfo *) CMSG_DATA(cmsg);
495 memset(pkt, 0,
sizeof(*pkt));
496 pkt->ipi_spec_dst = s4->sin_addr;
497 pkt->ipi_ifindex = ifindex;
499 # elif defined(IP_SENDSRCADDR)
500 struct cmsghdr *cmsg;
503 msgh.msg_control = cbuf;
504 msgh.msg_controllen = CMSG_SPACE(
sizeof(*
in));
506 cmsg = CMSG_FIRSTHDR(&msgh);
507 cmsg->cmsg_level = IPPROTO_IP;
508 cmsg->cmsg_type = IP_SENDSRCADDR;
509 cmsg->cmsg_len = CMSG_LEN(
sizeof(*
in));
511 in = (
struct in_addr *) CMSG_DATA(cmsg);
517 # if defined(IPV6_PKTINFO)
518 if (from->sa_family == AF_INET6) {
519 struct sockaddr_in6 *s6 = (
struct sockaddr_in6 *) from;
521 struct cmsghdr *cmsg;
522 struct in6_pktinfo *pkt;
524 msgh.msg_control = cbuf;
525 msgh.msg_controllen = CMSG_SPACE(
sizeof(*pkt));
527 cmsg = CMSG_FIRSTHDR(&msgh);
528 cmsg->cmsg_level = IPPROTO_IPV6;
529 cmsg->cmsg_type = IPV6_PKTINFO;
530 cmsg->cmsg_len = CMSG_LEN(
sizeof(*pkt));
532 pkt = (
struct in6_pktinfo *) CMSG_DATA(cmsg);
533 memset(pkt, 0,
sizeof(*pkt));
534 pkt->ipi6_addr = s6->sin6_addr;
535 pkt->ipi6_ifindex = ifindex;
539 return sendmsg(fd, &msgh, flags);
552 # include <sys/wait.h>
554 # define DEF_PORT 20000
555 # define DESTIP "127.0.0.1"
556 # define TESTSTRING "foo"
559 int main(
int argc,
char **argv)
561 struct sockaddr_in from, to,
in;
563 char *destip = DESTIP;
569 if (argc > 1) destip = argv[1];
570 if (argc > 2) port = atoi(argv[2]);
572 in.sin_family = AF_INET;
573 in.sin_addr.s_addr = INADDR_ANY;
574 in.sin_port = htons(port);
575 fl = tl =
sizeof(
struct sockaddr_in);
576 memset(&from, 0,
sizeof(from));
577 memset(&to, 0,
sizeof(to));
579 switch (pid = fork()) {
590 server_socket = socket(PF_INET, SOCK_DGRAM, 0);
592 perror(
"udpfromto_init\n");
597 if (bind(server_socket, (
struct sockaddr *)&
in,
sizeof(
in)) < 0) {
598 perror(
"server: bind");
603 printf(
"server: waiting for packets on INADDR_ANY:%d\n", port);
604 if ((
n =
recvfromto(server_socket, buf,
sizeof(buf), 0,
605 (
struct sockaddr *)&from, &fl,
606 (
struct sockaddr *)&to, &tl, &ifindex, &when)) < 0) {
607 perror(
"server: recvfromto");
612 printf(
"server: received a packet of %d bytes [%s] ",
n, buf);
613 printf(
"(src ip:port %s:%d ",
614 inet_ntoa(from.sin_addr), ntohs(from.sin_port));
615 printf(
" dst ip:port %s:%d) via if %i\n",
616 inet_ntoa(to.sin_addr), ntohs(to.sin_port), ifindex);
618 printf(
"server: replying from address packet was received on to source address\n");
622 (
struct sockaddr *)&to, tl,
623 (
struct sockaddr *)&from, fl)) < 0) {
624 perror(
"server: sendfromto");
631 close(server_socket);
636 in.sin_port = htons(port+1);
640 in.sin_port = htons(port);
641 in.sin_addr.s_addr = inet_addr(destip);
643 printf(
"client: sending packet to %s:%d\n", destip, port);
644 fr_assert_fatal_msg(sendto(
client_socket, TESTSTRING, TESTLEN, 0, (
struct sockaddr *)&
in,
sizeof(
in)) < 0,
647 printf(
"client: waiting for reply from server on INADDR_ANY:%d\n", port+1);
650 (
struct sockaddr *)&from, &fl,
651 (
struct sockaddr *)&to, &tl, &ifindex, NULL)) < 0,
654 printf(
"client: received a packet of %d bytes [%s] ",
n, buf);
655 printf(
"(src ip:port %s:%d",
656 inet_ntoa(from.sin_addr), ntohs(from.sin_port));
657 printf(
" dst ip:port %s:%d) via if %i\n",
658 inet_ntoa(to.sin_addr), ntohs(to.sin_port), ifindex);
int main(int argc, char **argv)
waitpid(reap->pid_ev->pid, &status, 0)
static int client_socket(char const *server)
static char const * proto(int id, int porttype)
#define fr_time()
Allow us to arbitrarily manipulate time.
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
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)
#define fr_time_wrap(_time)
#define fr_time_eq(_a, _b)
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)
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.
int udpfromto_init(int s, int af)
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.