36#include <sys/socket.h>
40#include <linux/types.h>
41#include <linux/netlink.h>
42#include <linux/rtnetlink.h>
55#undef USE_SOCKET_ROUTE
65#if defined(__APPLE__) || defined(__FreeBSD__)
66#include <sys/sysctl.h>
68#define USE_SOCKET_ROUTE
74#ifdef USE_SOCKET_ROUTE
79#include <netinet/in.h>
82#if defined(BSD) || defined(__FreeBSD_kernel__)
83#define USE_SOCKET_ROUTE
87#if (defined(sun) && defined(__SVR4))
88#define USE_SOCKET_ROUTE
100#define USE_WIN32_CODE
103#define TO_IPV6MAPPED(x) S6_ADDR32(x)[3] = S6_ADDR32(x)[0];\
104 S6_ADDR32(x)[0] = 0;\
105 S6_ADDR32(x)[1] = 0;\
106 S6_ADDR32(x)[2] = htonl(0xFFFF);
112static ssize_t readNlSock(
int sockFd,
char *bufPtr,
unsigned seqNum,
115 struct nlmsghdr *nlHdr;
120 readLen=recv(sockFd, bufPtr, BUFSIZE - msgLen, 0);
128 nlHdr=(
struct nlmsghdr *)bufPtr;
131 if ((NLMSG_OK(nlHdr, (
unsigned)readLen) == 0)
132 || (nlHdr->nlmsg_type == NLMSG_ERROR)) {
138 if (nlHdr->nlmsg_type == NLMSG_DONE) {
147 if ((nlHdr->nlmsg_flags & NLM_F_MULTI) == 0) {
151 }
while ((nlHdr->nlmsg_seq != seqNum) || (nlHdr->nlmsg_pid != pId));
157 struct nlmsghdr *nlMsg;
158 char msgBuf[BUFSIZE];
169 sock=socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
176 memset(msgBuf, 0, BUFSIZE);
179 nlMsg=(
struct nlmsghdr *)msgBuf;
182 nlMsg->nlmsg_len=NLMSG_LENGTH(
sizeof(
struct rtmsg));
183 nlMsg->nlmsg_type=RTM_GETROUTE;
185 nlMsg->nlmsg_flags=NLM_F_DUMP | NLM_F_REQUEST;
186 nlMsg->nlmsg_seq=msgSeq++;
187 nlMsg->nlmsg_pid=
getpid();
190 len=
send(sock, nlMsg, nlMsg->nlmsg_len, 0);
198 len=readNlSock(sock, msgBuf, msgSeq,
getpid());
207 for (; NLMSG_OK(nlMsg,(
unsigned)len); nlMsg=NLMSG_NEXT(nlMsg,len)) {
209 struct rtattr *rtAttr;
211 unsigned int scope_id = 0;
212 struct in6_addr addr;
214 rtMsg=(
struct rtmsg *)NLMSG_DATA(nlMsg);
218 if (((rtMsg->rtm_family != AF_INET) && (rtMsg->rtm_family != AF_INET6))
219 || (rtMsg->rtm_table != RT_TABLE_MAIN)) {
224 rtAttr=(
struct rtattr *)RTM_RTA(rtMsg);
225 rtLen=RTM_PAYLOAD(nlMsg);
226 for (; RTA_OK(rtAttr,rtLen); rtAttr=RTA_NEXT(rtAttr,rtLen)) {
227 size_t rtaLen=RTA_PAYLOAD(rtAttr);
228 if (rtaLen >
sizeof(
struct in6_addr)) {
231 if (rtAttr->rta_type == RTA_OIF) {
232 memcpy(&scope_id, RTA_DATA(rtAttr),
sizeof(
unsigned int));
233 }
else if (rtAttr->rta_type == RTA_GATEWAY) {
234 memset(&addr, 0,
sizeof(
struct in6_addr));
235 memcpy(&addr, RTA_DATA(rtAttr), rtaLen);
236 if (rtMsg->rtm_family == AF_INET) {
243 struct sockaddr_in6 *tmp_gws;
244 tmp_gws=(
struct sockaddr_in6 *)realloc(*gws,
245 sizeof(
struct sockaddr_in6) * (ret + 1));
248 "Error allocating memory");
257 (*gws + ret)->sin6_family=AF_INET6;
258 memcpy(&((*gws + ret)->sin6_addr), &addr,
sizeof(addr));
259 (*gws + ret)->sin6_scope_id=scope_id;
260 SET_SA_LEN(*gws + ret,
sizeof(
struct sockaddr_in6))
273#if defined (USE_WIN32_CODE) && defined(WIN32)
278 PMIB_IPFORWARD_TABLE2 ipf_table;
285 if (GetIpForwardTable2(AF_UNSPEC, &ipf_table) != NO_ERROR) {
293 *gws=(
struct in6_addr *)calloc(ipf_table->NumEntries,
294 sizeof(
struct in6_addr));
300 for (i=0; i < ipf_table->NumEntries; ++i) {
301 if (ipf_table->Table[i].NextHop.si_family == AF_INET) {
303 ipf_table->Table[i].NextHop.Ipv4.sin_addr.s_addr;
306 if (ipf_table->Table[i].NextHop.si_family == AF_INET6) {
307 memcpy((*gws) + i, &ipf_table->Table[i].NextHop.Ipv6.sin6_addr,
308 sizeof(
struct in6_addr));
316 PMIB_IPFORWARDTABLE ipf_table;
324 ipf_table=(MIB_IPFORWARDTABLE *)malloc(
sizeof(MIB_IPFORWARDTABLE));
331 if (GetIpForwardTable(ipf_table, &ipft_size, 0)
332 == ERROR_INSUFFICIENT_BUFFER) {
333 MIB_IPFORWARDTABLE *new_ipf_table;
334 new_ipf_table=(MIB_IPFORWARDTABLE *)realloc(ipf_table, ipft_size);
335 if (!new_ipf_table) {
340 ipf_table=new_ipf_table;
343 if (GetIpForwardTable(ipf_table, &ipft_size, 0) != NO_ERROR) {
349 *gws=(
struct sockaddr_in6 *)calloc(ipf_table->dwNumEntries,
350 sizeof(
struct sockaddr_in6));
357 for (ret=0, i=0; i < (int)ipf_table->dwNumEntries; i++) {
358 if (ipf_table->table[i].dwForwardType == MIB_IPROUTE_TYPE_INDIRECT) {
359 (*gws)[ret].sin6_family = AF_INET6;
361 (
uint32_t)ipf_table->table[i].dwForwardNextHop;
376#ifdef USE_SOCKET_ROUTE
386#define ROUNDUP(a, size) (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
393#define NEXT_SA(ap) ap = (struct sockaddr *) \
394 ((caddr_t) ap + (ap->sa_len ? ROUNDUP(ap->sa_len, sizeof(uint32_t)) : \
398static void get_rtaddrs(
int addrs,
struct sockaddr *sa,
399 struct sockaddr **rti_info)
403 for (i=0; i < RTAX_MAX; i++) {
404 if (addrs & (1 << i)) {
416net_rt_dump(
int type,
int family,
int flags,
size_t *lenp)
427 if (sysctl(mib, 6, NULL, lenp, NULL, 0) < 0)
430 if ((buf=malloc(*lenp)) == NULL)
432 if (sysctl(mib, 6, buf, lenp, NULL, 0) < 0)
446 char *buf, *next, *
lim;
448 struct rt_msghdr *rtm;
449 struct sockaddr *sa, *rti_info[RTAX_MAX];
457 buf=net_rt_dump(NET_RT_FLAGS, 0, RTF_GATEWAY, &len);
461 for (next=buf; next <
lim; next+=rtm->rtm_msglen) {
462 rtm=(
struct rt_msghdr *)next;
463 sa=(
struct sockaddr *)(rtm + 1);
464 get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
466 if ((sa=rti_info[RTAX_GATEWAY]) != NULL)
468 if ((rtm->rtm_addrs & (RTA_DST | RTA_GATEWAY))
469 == (RTA_DST | RTA_GATEWAY)) {
470 struct sockaddr_in6 *in6=*gws;
472 *gws=(
struct sockaddr_in6 *)realloc(*gws,
473 sizeof(
struct sockaddr_in6) * (rtcount + 1));
482 in6=(*gws) + rtcount;
483 memset(in6, 0,
sizeof(
struct sockaddr_in6));
485 if (sa->sa_family == AF_INET) {
487 in6->sin6_family = AF_INET6;
489 ((
struct sockaddr_in *)(rti_info[RTAX_GATEWAY]))->sin_addr.s_addr;
491 }
else if (sa->sa_family == AF_INET6) {
493 (
struct sockaddr_in6 *)rti_info[RTAX_GATEWAY],
494 sizeof(
struct sockaddr_in6));
512typedef struct route_op {
513 struct sockaddr_in dst4;
514 struct sockaddr_in mask4;
515 struct sockaddr_in gw4;
516 struct sockaddr_in6 dst6;
517 struct sockaddr_in6 mask6;
518 struct sockaddr_in6 gw6;
524get_if_addr_from_name(
char *ifname,
struct sockaddr *ifsock,
int family);
526typedef route_op_t route_in_t;
527typedef route_op_t route_out_t;
529static int route_get(in_addr_t *dst, in_addr_t *mask, in_addr_t *gateway,
530 char *ifname, route_in_t *routein, route_out_t *routeout);
531static int route_add(in_addr_t dst, in_addr_t mask, in_addr_t gateway,
532 const char *ifname, route_in_t *routein, route_out_t *routeout);
533static int route_change(in_addr_t dst, in_addr_t mask, in_addr_t gateway,
534 const char *ifname, route_in_t *routein, route_out_t *routeout);
535static int route_delete(in_addr_t dst, in_addr_t mask, route_in_t *routein,
536 route_out_t *routeout);
537static int route_get_sa(
struct sockaddr *dst, in_addr_t *mask,
538 struct sockaddr *gateway,
char *ifname, route_in_t *routein,
539 route_out_t *routeout);
541static int find_if_with_name(
const char *iface,
struct sockaddr_dl *out)
543 struct ifaddrs *ifap, *ifa;
544 struct sockaddr_dl *sdl=NULL;
546 if (getifaddrs(&ifap)) {
553 for (ifa=ifap; ifa; ifa=ifa->ifa_next) {
554 if (ifa->ifa_addr->sa_family == AF_LINK &&
556 strcmp(iface, ifa->ifa_name) == 0) {
557 sdl=(
struct sockaddr_dl *)ifa->ifa_addr;
564 bcopy((
char *)sdl, (
char *)out, (
size_t)(sdl->sdl_len));
570 "interface %s not found or invalid(must be p-p)", iface);
576static int route_op(u_char op, in_addr_t *dst, in_addr_t *mask,
577 in_addr_t *gateway,
char *iface, route_in_t *routein,
578 route_out_t *routeout)
581#define ROUNDUP_CT(n) ((n) > 0 ? (1 + (((n) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
582#define ADVANCE_CT(x, n) (x += ROUNDUP_CT((n)->sa_len))
584#define NEXTADDR_CT(w, u) \
585 if (msg.msghdr.rtm_addrs & (w)) {\
586 len = ROUNDUP_CT(u.sa.sa_len); bcopy((char *)&(u), cp, len); cp += len;\
597 struct sockaddr_in
sin;
598 struct sockaddr_dl sdl;
599 struct sockaddr_storage ss;
603 struct rt_msghdr msghdr;
607 bzero(so_addr,
sizeof(so_addr));
608 bzero(&msg,
sizeof(msg));
614 msg.msghdr.rtm_version=RTM_VERSION;
616 msg.msghdr.rtm_index=0;
617 msg.msghdr.rtm_pid=pid;
618 msg.msghdr.rtm_addrs=0;
619 msg.msghdr.rtm_seq=++seq;
620 msg.msghdr.rtm_errno=0;
621 msg.msghdr.rtm_flags=0;
625 if (routein && routein->dst4.sin_addr.s_addr != 0xffffffff) {
626 msg.msghdr.rtm_addrs|=RTA_DST;
628 so_addr[RTAX_DST].sin.sin_len=
sizeof(
struct sockaddr_in);
629 so_addr[RTAX_DST].sin.sin_family=AF_INET;
630 so_addr[RTAX_DST].sin.sin_addr.s_addr=mask ? *dst & *mask : *dst;
637 if (mask && *mask != 0xffffffff) {
638 msg.msghdr.rtm_addrs|=RTA_NETMASK;
640 so_addr[RTAX_NETMASK].sin.sin_len=
sizeof(
struct sockaddr_in);
641 so_addr[RTAX_NETMASK].sin.sin_family=AF_INET;
642 so_addr[RTAX_NETMASK].sin.sin_addr.s_addr=*mask;
645 msg.msghdr.rtm_flags|=RTF_HOST;
650 msg.msghdr.rtm_type=op;
651 msg.msghdr.rtm_addrs|=RTA_GATEWAY;
652 msg.msghdr.rtm_flags|=RTF_UP;
655 if ((gateway && *gateway != 0x0 && *gateway != 0xffffffff)) {
656 msg.msghdr.rtm_flags|=RTF_GATEWAY;
658 so_addr[RTAX_GATEWAY].sin.sin_len=
sizeof(
struct sockaddr_in);
659 so_addr[RTAX_GATEWAY].sin.sin_family=AF_INET;
660 so_addr[RTAX_GATEWAY].sin.sin_addr.s_addr=*gateway;
663 msg.msghdr.rtm_addrs|=RTA_IFP;
664 so_addr[RTAX_IFP].sdl.sdl_family=AF_LINK;
667 if (find_if_with_name(iface, &so_addr[RTAX_IFP].sdl) < 0)
674 "Requir gateway or iface.");
678 if (find_if_with_name(iface, &so_addr[RTAX_GATEWAY].sdl) < 0)
683 msg.msghdr.rtm_type=op;
684 msg.msghdr.rtm_addrs|=RTA_GATEWAY;
685 msg.msghdr.rtm_flags|=RTF_GATEWAY;
688 msg.msghdr.rtm_type=op;
689 msg.msghdr.rtm_addrs|=RTA_IFP;
690 so_addr[RTAX_IFP].sa.sa_family=AF_LINK;
691 so_addr[RTAX_IFP].sa.sa_len=
sizeof(
struct sockaddr_dl);
697 NEXTADDR_CT(RTA_DST, so_addr[RTAX_DST]);
698 NEXTADDR_CT(RTA_GATEWAY, so_addr[RTAX_GATEWAY]);
699 NEXTADDR_CT(RTA_NETMASK, so_addr[RTAX_NETMASK]);
700 NEXTADDR_CT(RTA_GENMASK, so_addr[RTAX_GENMASK]);
701 NEXTADDR_CT(RTA_IFP, so_addr[RTAX_IFP]);
702 NEXTADDR_CT(RTA_IFA, so_addr[RTAX_IFA]);
704 msg.msghdr.rtm_msglen=len=cp - (
char *)&msg;
706 int sock=socket(PF_ROUTE, SOCK_RAW, AF_INET);
709 "socket(PF_ROUTE, SOCK_RAW, AF_INET) failed");
713 if (write(sock, (
char *)&msg, len) < 0) {
720 len=read(sock, (
char *)&msg,
sizeof(msg));
722 && (msg.msghdr.rtm_seq != seq || msg.msghdr.rtm_pid != pid));
726 "read from routing socket failed");
729 struct sockaddr *s_netmask=NULL;
730 struct sockaddr *s_gate=NULL;
731 struct sockaddr_dl *s_ifp=NULL;
733 struct sockaddr *rti_info[RTAX_MAX];
735 if (msg.msghdr.rtm_version != RTM_VERSION) {
737 "routing message version %d not understood",
738 msg.msghdr.rtm_version);
742 if (msg.msghdr.rtm_msglen > len) {
744 "message length mismatch, in packet %d, returned %lu",
745 msg.msghdr.rtm_msglen, (
unsigned long)len);
747 if (msg.msghdr.rtm_errno) {
749 msg.msghdr.rtm_errno, strerror(msg.msghdr.rtm_errno));
754 if (msg.msghdr.rtm_addrs) {
756 sa=(
struct sockaddr *)cp;
757 get_rtaddrs(msg.msghdr.rtm_addrs, sa, rti_info);
759 if ((sa=rti_info[RTAX_DST]) != NULL) {
760 if (sa->sa_family == AF_INET) {
761 char routeto4_str[INET_ADDRSTRLEN];
763 memcpy((
void *)&(routeout->dst4), (
void *)sa,
764 sizeof(
struct sockaddr_in));
765 inet_ntop(AF_INET, &(routein->dst4.sin_addr),
766 routeto4_str, INET_ADDRSTRLEN);
774 if (msg.msghdr.rtm_flags & RTF_WASCLONED) {
776 "Route to %s in the same subnet",
778 }
else if (msg.msghdr.rtm_flags & RTF_CLONING) {
780 "Route to %s in the same subnet but not up",
782 }
else if (msg.msghdr.rtm_flags & RTF_GATEWAY) {
784 "Route to %s not in the same subnet",
787 if (routeout->dst4.sin_addr.s_addr
788 == routein->dst4.sin_addr.s_addr) {
790 "Destination %s same as route to %s",
791 sock_ntop(sa, sa->sa_len), routeto4_str);
796 if ((sa=rti_info[RTAX_GATEWAY]) != NULL) {
800 if (msg.msghdr.rtm_flags & RTF_GATEWAY) {
802 ((
struct sockaddr_in *)s_gate)->sin_addr.s_addr;
803 routeout->gw4.sin_addr.s_addr=
804 ((
struct sockaddr_in *)s_gate)->sin_addr.s_addr;
811 if ((sa=rti_info[RTAX_IFP]) != NULL) {
813 "family: %d AF_LINK family : %d \n",
814 sa->sa_family, AF_LINK);
815 if ((sa->sa_family == AF_LINK)
816 && ((
struct sockaddr_dl *)sa)->sdl_nlen) {
818 s_ifp=(
struct sockaddr_dl *)sa;
819 slen=s_ifp->sdl_nlen < IFNAMSIZ ?
820 s_ifp->sdl_nlen : IFNAMSIZ;
821 strncpy(iface, s_ifp->sdl_data, slen);
822 strncpy(&(routeout->ifname[0]), s_ifp->sdl_data, slen);
823 routeout->ifname[slen]=
'\0';
826 "Interface name %s and type %d \n",
827 &(routeout->ifname[0]), s_ifp->sdl_type);
836 *mask=((
struct sockaddr_in *)s_netmask)->sin_addr.s_addr;
842 if (iface && s_ifp) {
843 strncpy(iface, s_ifp->sdl_data,
844 s_ifp->sdl_nlen < IFNAMSIZ ?
845 s_ifp->sdl_nlen : IFNAMSIZ);
846 iface[IFNAMSIZ - 1]=
'\0';
853 if (
close(sock) < 0) {
862static int route_get_sa(
struct sockaddr *dst, in_addr_t *mask,
863 struct sockaddr *gateway,
char *ifname, route_in_t *routein,
864 route_out_t *routeout)
866#if defined(__APPLE__) || defined(__FreeBSD__)
867 return route_op(RTM_GET, &(((
struct sockaddr_in *) dst)->sin_addr.s_addr), mask,
868 &(((
struct sockaddr_in *) gateway)->sin_addr.s_addr), ifname, routein, routeout);
875static int route_get(in_addr_t *dst, in_addr_t *mask, in_addr_t *gateway,
876 char iface[], route_in_t *routein, route_out_t *routeout)
878#if defined(__APPLE__) || defined(__FreeBSD__)
879 return route_op(RTM_GET, dst, mask, gateway, iface, routein, routeout);
886static int route_add(in_addr_t dst, in_addr_t mask, in_addr_t gateway,
887 const char *iface, route_in_t *routein, route_out_t *routeout)
889#if defined(__APPLE__) || defined(__FreeBSD__)
890 return route_op(RTM_ADD, &dst, &mask, &gateway, (
char *)iface, routein, routeout);
897static int route_change(in_addr_t dst, in_addr_t mask, in_addr_t gateway,
898 const char *iface, route_in_t *routein, route_out_t *routeout)
900#if defined(__APPLE__) || defined(__FreeBSD__)
901 return route_op(RTM_CHANGE, &dst, &mask, &gateway, (
char *)iface, routein, routeout);
908static int route_delete(in_addr_t dst, in_addr_t mask, route_in_t *routein,
909 route_out_t *routeout)
911#if defined(__APPLE__) || defined(__FreeBSD__)
912 return route_op(RTM_DELETE, &dst, &mask, 0, NULL, routein, routeout);
924static int get_if_addr_from_name(
char *ifname,
struct sockaddr *ifsock,
927 struct ifaddrs *ifaddr, *ifa;
929 if (getifaddrs(&ifaddr) == -1) {
939 for (ifa=ifaddr; ifa != NULL; ifa=ifa->ifa_next) {
940 if (ifa->ifa_addr == NULL)
944 if (!strcmp(ifname, ifa->ifa_name)
945 && (ifa->ifa_addr->sa_family == family)) {
946 memcpy(ifsock, ifa->ifa_addr,
sizeof(
struct sockaddr));
int getgateways(struct sockaddr_in6 **gws)
float sin(float x) noexcept
void send(sys::state &state, element_base *parent, T value)
void pcp_strerror(int errnum, char *buf, size_t buflen)
#define PCP_LOG_END(level)
#define PCP_LOG_BEGIN(level)
#define PCP_LOG(level, fmt,...)
char * sock_ntop(const struct sockaddr *sa, socklen_t salen)
void err_msg(const char *,...)