26RCSID(
"$Id: 3fabd1c3c33967bf5924f252e854fc4f9216145c $")
28#include <freeradius-devel/util/udpfromto.h>
33#ifdef HAVE_NET_IF_DL_H
34# include <net/if_dl.h>
44# define SOL_IP IPPROTO_IP
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
64# define IPV6_RECVPKTINFO IPV6_2292PKTINFO
65# define IPV6_PKTINFO IPV6_2292PKTINFO
69# elif defined(IPV6_2292PKTINFO)
70# define IPV6_RECVPKTINFO IPV6_2292PKTINFO
83# if !defined(IPV6_RECVPKTINFO) && defined(IPV6_PKTINFO)
84# define IPV6_RECVPKTINFO IPV6_PKTINFO
90# elif !defined(IPV6_PKTINFO)
91# undef IPV6_RECVPKTINFO
97 int proto = 0, flag = 0, opt = 1;
101 if (af == AF_UNSPEC) {
102 struct sockaddr_storage si;
103 socklen_t si_len =
sizeof(si);
109#ifdef STATIC_ANALYZER
110 memset(&si, 0,
sizeof(si));
113 if (getsockname(s, (
struct sockaddr *) &si, &si_len) < 0) {
121#ifdef HAVE_IP_PKTINFO
128# ifdef IP_RECVDSTADDR
135 flag = IP_RECVDSTADDR;
142 if (setsockopt(s, proto, IP_RECVIF, &opt,
sizeof(opt)) != 0)
return -1;
149#if defined(AF_INET6) && defined(IPV6_PKTINFO)
150 }
else if (af == AF_INET6) {
154 proto = IPPROTO_IPV6;
159 flag = IPV6_RECVPKTINFO;
166# ifdef EPROTONOSUPPORT
167 errno = EPROTONOSUPPORT;
172 return setsockopt(s, proto, flag, &opt,
sizeof(opt));
204 struct sockaddr *from, socklen_t *from_len,
205 struct sockaddr *to, socklen_t *to_len,
209 struct cmsghdr *cmsg;
213 struct sockaddr_storage si;
214 socklen_t si_len =
sizeof(si);
216#if !defined(IP_PKTINFO) && !defined(IP_RECVDSTADDR) && !defined(IPV6_PKTINFO)
227 if (!to || !to_len) {
229 return recvfrom(fd, buf, len, flags, from, from_len);
236#ifdef STATIC_ANALYZER
237 memset(&si, 0,
sizeof(si));
244 if (getsockname(fd, (
struct sockaddr *)&si, &si_len) < 0) {
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);
256 struct sockaddr_in *dst = (
struct sockaddr_in *) to;
257 struct sockaddr_in *src = (
struct sockaddr_in *) &si;
259 if (*to_len <
sizeof(*dst)) {
263 *to_len =
sizeof(*dst);
269 else if (si.ss_family == AF_INET6) {
270#if !defined(IPV6_PKTINFO)
271 return recvfrom(fd, buf, len, flags, from, from_len);
273 struct sockaddr_in6 *dst = (
struct sockaddr_in6 *) to;
274 struct sockaddr_in6 *src = (
struct sockaddr_in6 *) &si;
276 if (*to_len <
sizeof(*dst)) {
280 *to_len =
sizeof(*dst);
294 memset(&cbuf, 0,
sizeof(cbuf));
295 memset(&msgh, 0,
sizeof(
struct msghdr));
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;
307 ret = recvmsg(fd, &msgh, flags);
308 if (ret < 0)
return ret;
310 if (from_len) *from_len = msgh.msg_namelen;
312 if (ifindex) *ifindex = 0;
320 for (cmsg = CMSG_FIRSTHDR(&msgh);
322 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
326 if ((cmsg->cmsg_level ==
SOL_IP) &&
327 (cmsg->cmsg_type == IP_PKTINFO)) {
328 struct in_pktinfo *i = (
struct in_pktinfo *) CMSG_DATA(cmsg);
330 ((
struct sockaddr_in *)to)->sin_addr = i->ipi_addr;
331 *to_len =
sizeof(
struct sockaddr_in);
333 if (ifindex) *ifindex = i->ipi_ifindex;
340 if ((cmsg->cmsg_level == IPPROTO_IP) &&
341 (cmsg->cmsg_type == IP_RECVDSTADDR)) {
342 struct in_addr *i = (
struct in_addr *) CMSG_DATA(cmsg);
344 ((
struct sockaddr_in *)to)->sin_addr = *i;
346 *to_len =
sizeof(
struct sockaddr_in);
357 if ((cmsg->cmsg_level == IPPROTO_IP) &&
358 (cmsg->cmsg_type == IP_RECVIF)) {
359 struct sockaddr_dl *sd = (
struct sockaddr_dl *) CMSG_DATA(cmsg);
361 if (ifindex) *ifindex = sd->sdl_index;
372 if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
373 (cmsg->cmsg_type == IPV6_PKTINFO)) {
374 struct in6_pktinfo *i = (
struct in6_pktinfo *) CMSG_DATA(cmsg);
376 ((
struct sockaddr_in6 *)to)->sin6_addr = i->ipi6_addr;
377 *to_len =
sizeof(
struct sockaddr_in6);
379 if (ifindex) *ifindex = i->ipi6_ifindex;
386 if (when && (cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMP)) {
392 if (when && (cmsg->cmsg_level ==
SOL_IP) && (cmsg->cmsg_type == SO_TIMESTAMPNS)) {
423 struct sockaddr *from, socklen_t from_len,
424 struct sockaddr *to, socklen_t to_len)
433 if (from && (from->sa_family != AF_INET) && (from->sa_family != AF_INET6)) {
446 struct sockaddr bound;
447 socklen_t bound_len =
sizeof(bound);
449 if (getsockname(fd, &bound, &bound_len) < 0) {
453 switch (bound.sa_family) {
455 if (((
struct sockaddr_in *) &bound)->sin_addr.s_addr != INADDR_ANY) {
461 if (!IN6_IS_ADDR_UNSPECIFIED(&((
struct sockaddr_in6 *) &bound)->sin6_addr)) {
475# if !defined(IP_PKTINFO) && !defined(IP_SENDSRCADDR)
476 if (from && from->sa_family == AF_INET) from = NULL;
479# if !defined(IPV6_PKTINFO)
480 if (from && from->sa_family == AF_INET6) from = NULL;
487 if (!from || (from_len == 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);
497 memset(&cbuf, 0,
sizeof(cbuf));
498 memset(&msgh, 0,
sizeof(msgh));
499 memset(&iov, 0,
sizeof(iov));
506 msgh.msg_namelen = to_len;
508# if defined(IP_PKTINFO) || defined(IP_SENDSRCADDR)
509 if (from->sa_family == AF_INET) {
510 struct sockaddr_in *s4 = (
struct sockaddr_in *) from;
513 struct cmsghdr *cmsg;
514 struct in_pktinfo *pkt;
516 msgh.msg_control = cbuf;
517 msgh.msg_controllen = CMSG_SPACE(
sizeof(*pkt));
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));
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;
529# elif defined(IP_SENDSRCADDR)
530 struct cmsghdr *cmsg;
533 msgh.msg_control = cbuf;
534 msgh.msg_controllen = CMSG_SPACE(
sizeof(*
in));
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));
541 in = (
struct in_addr *) CMSG_DATA(cmsg);
547# if defined(IPV6_PKTINFO)
548 if (from->sa_family == AF_INET6) {
549 struct sockaddr_in6 *s6 = (
struct sockaddr_in6 *) from;
551 struct cmsghdr *cmsg;
552 struct in6_pktinfo *pkt;
554 msgh.msg_control = cbuf;
555 msgh.msg_controllen = CMSG_SPACE(
sizeof(*pkt));
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));
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;
569 return sendmsg(fd, &msgh, flags);
582# include <sys/wait.h>
584# define DEF_PORT 20000
585# define DESTIP "127.0.0.1"
586# define TESTSTRING "foo"
589int main(
int argc,
char **argv)
591 struct sockaddr_in from, to,
in;
593 char *destip = DESTIP;
599 if (argc > 1) destip = argv[1];
600 if (argc > 2) port = atoi(argv[2]);
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));
609 switch (pid = fork()) {
620 server_socket = socket(PF_INET, SOCK_DGRAM, 0);
622 perror(
"udpfromto_init\n");
627 if (bind(server_socket, (
struct sockaddr *)&
in,
sizeof(
in)) < 0) {
628 perror(
"server: bind");
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");
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);
648 printf(
"server: replying from address packet was received on to source address\n");
652 (
struct sockaddr *)&to, tl,
653 (
struct sockaddr *)&from, fl)) < 0) {
654 perror(
"server: sendfromto");
661 close(server_socket);
666 in.sin_port = htons(port+1);
670 in.sin_port = htons(port);
671 in.sin_addr.s_addr = inet_addr(destip);
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,
677 printf(
"client: waiting for reply from server on INADDR_ANY:%d\n", port+1);
680 (
struct sockaddr *)&from, &fl,
681 (
struct sockaddr *)&to, &tl, &ifindex, NULL)) < 0,
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);
int main(int argc, char **argv)
waitpid(reap->pid_ev->pid, &status, 0)
static int client_socket(char const *server)
#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.