480 lines
12 KiB
C
480 lines
12 KiB
C
/* wrnad_route.c - Wind River network acceleration daemon (NAD) */
|
|
|
|
/*
|
|
* Copyright (c) 2010 Wind River Systems, Inc.
|
|
*
|
|
* The right to copy, distribute or otherwise make use of this software
|
|
* may be licensed only pursuant to the terms of an applicable Wind River
|
|
* license agreement.
|
|
*/
|
|
|
|
/* includes */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <syslog.h>
|
|
#include <string.h>
|
|
|
|
#include "wrnad.h"
|
|
|
|
/* defines */
|
|
|
|
/* typedefs */
|
|
|
|
/* imports */
|
|
|
|
/* globals */
|
|
|
|
/* locals */
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_route_flagsstr - find rtnetlink route flags in string format
|
|
*
|
|
* This routine returns the rtnetlink route flags as a string
|
|
*
|
|
* RETURNS: string representation of rtnetlink route flags.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
static const char *
|
|
wrnad_rtnl_route_flagsstr(int flags)
|
|
{
|
|
static char flagsstr[256];
|
|
int i;
|
|
|
|
flagsstr[0] = '<';
|
|
i = 1;
|
|
if (flags == 0)
|
|
i += sprintf(&flagsstr[i], "%s", "0,");
|
|
if (flags & RTM_F_NOTIFY)
|
|
i += sprintf(&flagsstr[i], "%s", "NOTIFY,");
|
|
if (flags & RTM_F_CLONED)
|
|
i += sprintf(&flagsstr[i], "%s", "CLONED,");
|
|
if (flags & RTM_F_EQUALIZE)
|
|
i += sprintf(&flagsstr[i], "%s", "EQUALIZE,");
|
|
if (flags & RTM_F_PREFIX)
|
|
i += sprintf(&flagsstr[i], "%s", "PREFIX,");
|
|
|
|
flagsstr[i-1] = '>'; /* remove last comma */
|
|
return flagsstr;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_route_tablestr - find rtnetlink route table in string format
|
|
*
|
|
* This routine returns the rtnetlink route table as a string
|
|
*
|
|
* RETURNS: string representation of rtnetlink route table.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
static const char *
|
|
wrnad_rtnl_route_tablestr(int table)
|
|
{
|
|
static char tablestr[32];
|
|
|
|
switch (table)
|
|
{
|
|
case RT_TABLE_UNSPEC:
|
|
return "UNSPEC";
|
|
#if 0
|
|
case RT_TABLE_COMPAT:
|
|
return "COMPAT";
|
|
#endif
|
|
case RT_TABLE_DEFAULT:
|
|
return "DEFAULT";
|
|
case RT_TABLE_MAIN:
|
|
return "MAIN";
|
|
case RT_TABLE_LOCAL:
|
|
return "LOCAL";
|
|
default:
|
|
sprintf(tablestr, "%d", table);
|
|
return tablestr;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_route_protocolstr - find rtnetlink route protocol in string format
|
|
*
|
|
* This routine returns the rtnetlink route protocol as a string
|
|
*
|
|
* RETURNS: string representation of rtnetlink route protocol.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
static const char *
|
|
wrnad_rtnl_route_protocolstr(int protocol)
|
|
{
|
|
static char protocolstr[32];
|
|
|
|
switch (protocol)
|
|
{
|
|
case RTPROT_UNSPEC:
|
|
return "UNSPEC";
|
|
case RTPROT_REDIRECT:
|
|
return "REDIRECT";
|
|
case RTPROT_KERNEL:
|
|
return "KERNEL";
|
|
case RTPROT_BOOT:
|
|
return "BOOT";
|
|
case RTPROT_STATIC:
|
|
return "STATIC";
|
|
default:
|
|
sprintf(protocolstr, "%d", protocol);
|
|
return protocolstr;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_route_scopestr - find rtnetlink route scope in string format
|
|
*
|
|
* This routine returns the rtnetlink route scope as a string
|
|
*
|
|
* RETURNS: string representation of rtnetlink route scope.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
static const char *
|
|
wrnad_rtnl_route_scopestr(int scope)
|
|
{
|
|
static char scopestr[32];
|
|
|
|
switch (scope)
|
|
{
|
|
case RT_SCOPE_UNIVERSE:
|
|
return "UNIVERSE";
|
|
case RT_SCOPE_SITE:
|
|
return "SITE";
|
|
case RT_SCOPE_LINK:
|
|
return "LINK";
|
|
case RT_SCOPE_HOST:
|
|
return "HOST";
|
|
case RT_SCOPE_NOWHERE:
|
|
return "NOWHERE";
|
|
default:
|
|
sprintf(scopestr, "%d", scope);
|
|
return scopestr;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_route_typestr - find rtnetlink route type in string format
|
|
*
|
|
* This routine returns the rtnetlink route type as a string
|
|
*
|
|
* RETURNS: string representation of rtnetlink route type.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
static const char *
|
|
wrnad_rtnl_route_typestr(int type)
|
|
{
|
|
static char typestr[32];
|
|
|
|
switch (type)
|
|
{
|
|
case RTN_UNSPEC:
|
|
return "UNSPEC";
|
|
case RTN_UNICAST:
|
|
return "UNICAST";
|
|
case RTN_LOCAL:
|
|
return "LOCAL";
|
|
case RTN_BROADCAST:
|
|
return "BROADCAST";
|
|
case RTN_ANYCAST:
|
|
return "ANYCAST";
|
|
case RTN_MULTICAST:
|
|
return "MULTICAST";
|
|
case RTN_BLACKHOLE:
|
|
return "BLACKHOLE";
|
|
case RTN_UNREACHABLE:
|
|
return "UNREACHABLE";
|
|
case RTN_PROHIBIT:
|
|
return "PROHIBIT";
|
|
case RTN_THROW:
|
|
return "THROW";
|
|
case RTN_NAT:
|
|
return "NAT";
|
|
case RTN_XRESOLVE:
|
|
return "XRESOLVE";
|
|
default:
|
|
sprintf(typestr, "%d", type);
|
|
return typestr;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_route_attrstr - find rtnetlink route attribute in string format
|
|
*
|
|
* This routine returns the rtnetlink route attribute as a string
|
|
*
|
|
* RETURNS: string representation of rtnetlink route attribute.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
static const char *
|
|
wrnad_rtnl_route_attrstr(int attr)
|
|
{
|
|
static char attrstr[32];
|
|
|
|
switch (attr)
|
|
{
|
|
case RTA_UNSPEC:
|
|
return "RTA_UNSPEC";
|
|
case RTA_DST:
|
|
return "RTA_DST";
|
|
case RTA_SRC:
|
|
return "RTA_SRC";
|
|
case RTA_IIF:
|
|
return "RTA_IIF";
|
|
case RTA_OIF:
|
|
return "RTA_OIF";
|
|
case RTA_GATEWAY:
|
|
return "RTA_GATEWAY";
|
|
case RTA_PRIORITY:
|
|
return "RTA_PRIORITY";
|
|
case RTA_PREFSRC:
|
|
return "RTA_PREFSRC";
|
|
case RTA_METRICS:
|
|
return "RTA_METRICS";
|
|
case RTA_MULTIPATH:
|
|
return "RTA_MULTIPATH";
|
|
case RTA_PROTOINFO:
|
|
return "RTA_PROTOINFO";
|
|
case RTA_FLOW:
|
|
return "RTA_FLOW";
|
|
case RTA_CACHEINFO:
|
|
return "RTA_CACHEINFO";
|
|
case RTA_SESSION:
|
|
return "RTA_SESSION";
|
|
#ifdef RTA_MP_ALGO
|
|
case RTA_MP_ALGO:
|
|
return "RTA_MP_ALGO";
|
|
#endif
|
|
#ifdef RTA_TABLE
|
|
case RTA_TABLE:
|
|
return "RTA_TABLE";
|
|
#endif
|
|
default:
|
|
sprintf(attrstr, "%d", attr);
|
|
return attrstr;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_route_scan - scan rtnetlink socket for route messages
|
|
*
|
|
* This routine scans route messages received on a rtnetlink socket
|
|
*
|
|
* RETURNS: 0 if exited normally, else -1.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
static int
|
|
wrnad_rtnl_route_scan(struct rtmsg *rtm, int len, int *ifindex,
|
|
uint32_t **ppgwaddr, uint32_t **ppdstaddr)
|
|
{
|
|
struct rtattr *rta;
|
|
char buf[64];
|
|
|
|
rta = (struct rtattr *)((char *)rtm + NLMSG_ALIGN(sizeof(struct rtmsg)));
|
|
while (RTA_OK(rta, len))
|
|
{
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink ROUTE rtattr: rta_len=%d, rta_type=%s.",
|
|
rta->rta_len, wrnad_rtnl_route_attrstr(rta->rta_type));
|
|
|
|
#ifdef RTA_TABLE
|
|
if (rta->rta_type == RTA_TABLE)
|
|
{
|
|
}
|
|
else
|
|
#endif
|
|
if (rta->rta_type == RTA_DST)
|
|
{
|
|
if (inet_ntop(rtm->rtm_family, RTA_DATA(rta), buf, sizeof(buf)) != NULL)
|
|
{
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink ROUTE attribute RTA_DST: %s", buf);
|
|
}
|
|
*ppdstaddr = RTA_DATA(rta);
|
|
}
|
|
else if (rta->rta_type == RTA_GATEWAY)
|
|
{
|
|
if (inet_ntop(rtm->rtm_family, RTA_DATA(rta), buf, sizeof(buf)) != NULL)
|
|
{
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink ROUTE attribute RTA_GATEWAY: %s", buf);
|
|
}
|
|
*ppgwaddr = RTA_DATA(rta);
|
|
}
|
|
else if (rta->rta_type == RTA_OIF)
|
|
{
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink ROUTE attribute RTA_OIF: %d", *(int *)RTA_DATA(rta));
|
|
|
|
/* Save interface index */
|
|
*ifindex = *(int *)RTA_DATA(rta);
|
|
}
|
|
else if (rta->rta_type == RTA_PREFSRC)
|
|
{
|
|
if (inet_ntop(rtm->rtm_family, RTA_DATA(rta), buf, sizeof(buf)) != NULL)
|
|
{
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink ROUTE attribute RTA_PREFSRC: %s", buf);
|
|
}
|
|
}
|
|
|
|
rta = RTA_NEXT(rta, len);
|
|
}
|
|
|
|
if (len)
|
|
{
|
|
wrnad_log(LOG_WARNING, "Rtnetlink ROUTE attribute malformed! len=%d rta_len=%d", len, rta->rta_len);
|
|
return -1;
|
|
}
|
|
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink ROUTE message scanned ok.");
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_route_handler - rtnetlink handler for route messages
|
|
*
|
|
* This routine handles rtnetlink route messages.
|
|
*
|
|
* RETURNS: -1 = failed
|
|
* 0 = skip
|
|
* 1 = action
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
int
|
|
wrnad_rtnl_route_handler(struct nlmsghdr *nlh)
|
|
{
|
|
struct rtmsg *rtm;
|
|
int len, ret;
|
|
int ifindex = 0;
|
|
Wrnad_proxy_interface *proxy;
|
|
uint32_t *pgwaddr = NULL;
|
|
uint32_t *pdstaddr = NULL;
|
|
|
|
rtm = NLMSG_DATA(nlh);
|
|
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
|
|
if (len < 0)
|
|
{
|
|
wrnad_log(LOG_WARNING, "Rtnetlink message type %s has wrong nlmsg length %d!",
|
|
wrnad_rtnl_typestr(nlh->nlmsg_type), nlh->nlmsg_len);
|
|
return -1;
|
|
}
|
|
|
|
wrnad_log(LOG_WARNING,
|
|
"Rtnetlink ROUTE operation header: family=%s, dst_len=%d, src_len=%d, "
|
|
"tos=%d, table=%s, protocol=%s, scope=%s, type=%s, flags=%s",
|
|
wrnad_rtnl_familystr(rtm->rtm_family),
|
|
rtm->rtm_dst_len,
|
|
rtm->rtm_src_len,
|
|
rtm->rtm_tos,
|
|
wrnad_rtnl_route_tablestr(rtm->rtm_table),
|
|
wrnad_rtnl_route_protocolstr(rtm->rtm_protocol),
|
|
wrnad_rtnl_route_scopestr(rtm->rtm_scope),
|
|
wrnad_rtnl_route_typestr(rtm->rtm_type),
|
|
wrnad_rtnl_route_flagsstr(rtm->rtm_flags));
|
|
|
|
ret = wrnad_rtnl_route_scan(rtm, len, &ifindex, &pgwaddr, &pdstaddr);
|
|
if (ret == 0)
|
|
{
|
|
proxy = wrnad_rtnl_check_proxy_interface(ifindex);
|
|
if (proxy == NULL)
|
|
{
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink message type %s skipped on interface %d",
|
|
wrnad_rtnl_typestr(nlh->nlmsg_type), ifindex);
|
|
return 0;
|
|
}
|
|
|
|
if (rtm->rtm_table != RT_TABLE_MAIN)
|
|
{
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink message type %s skipped on table %d",
|
|
wrnad_rtnl_typestr(nlh->nlmsg_type), rtm->rtm_table);
|
|
return 0;
|
|
}
|
|
else if (rtm->rtm_type == RTN_LOCAL)
|
|
{
|
|
wrnad_log(LOG_WARNING, "Rtnetlink message type %s skipped on table %d due to RTN_LOCAL",
|
|
wrnad_rtnl_typestr(nlh->nlmsg_type), rtm->rtm_table);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef WRNAD_IDENTIFY_ROUTERS
|
|
if (pdstaddr != NULL && pgwaddr != NULL)
|
|
{
|
|
if (rtm->rtm_family == AF_INET)
|
|
{
|
|
if (rtm->rtm_dst_len == 32 &&
|
|
pdstaddr[0] == pgwaddr[0])
|
|
{
|
|
#ifdef WRNAD_SELF_GATEWAY_SKIP
|
|
return 0;
|
|
#endif
|
|
}
|
|
else
|
|
hash_insert_ip4addr(&proxy->v4_routers, pgwaddr);
|
|
}
|
|
if (rtm->rtm_family == AF_INET6)
|
|
{
|
|
if (rtm->rtm_dst_len == 128 &&
|
|
pdstaddr[0] == pgwaddr[0] &&
|
|
pdstaddr[1] == pgwaddr[1] &&
|
|
pdstaddr[2] == pgwaddr[2] &&
|
|
pdstaddr[3] == pgwaddr[3])
|
|
{
|
|
#ifdef WRNAD_SELF_GATEWAY_SKIP
|
|
/*
|
|
* A host route in which the destination and gateway
|
|
* addresses are the same is not a route that tells
|
|
* us anything we need to know on the NAP 1.1
|
|
* NAE side (which only has a forwarding cache).
|
|
*/
|
|
return 0;
|
|
#endif
|
|
}
|
|
else
|
|
hash_insert_ip6addr(&proxy->v6_routers, pgwaddr);
|
|
}
|
|
}
|
|
#endif
|
|
/* Accept message */
|
|
wrnad_log(LOG_INFO, "Rtnetlink message type %s accepted on interface %s",
|
|
wrnad_rtnl_typestr(nlh->nlmsg_type), proxy->ifname);
|
|
|
|
/* AF_INET6 has a different value in VxWorks */
|
|
rtm->rtm_family = wrnad_af_xlat(rtm->rtm_family);
|
|
|
|
/* Change into request */
|
|
nlh->nlmsg_flags = NLM_F_REQUEST;
|
|
if (nlh->nlmsg_type == RTM_NEWROUTE)
|
|
nlh->nlmsg_flags |= NLM_F_CREATE;
|
|
return 1;
|
|
}
|
|
return ret;
|
|
}
|