1025 lines
26 KiB
C
1025 lines
26 KiB
C
/* wrnad_mon.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 <unistd.h>
|
|
#include <sys/socket.h>
|
|
|
|
#include "wrnad.h"
|
|
|
|
/* for VLAN stacking */
|
|
#include "wrnad_svconfig.h"
|
|
|
|
/* defines */
|
|
|
|
/*
|
|
* FIXME: The stdlib.h at ipxinc/include/stdlib.h doesn't define
|
|
* EXIT_FAILURE or EXIT_SUCCESS.
|
|
*/
|
|
#ifndef EXIT_FAILURE
|
|
#define EXIT_FAILURE 1
|
|
#endif
|
|
#ifndef EXIT_SUCCESS
|
|
#define EXIT_SUCCESS 0
|
|
#endif
|
|
|
|
/* typedefs */
|
|
|
|
/* imports */
|
|
|
|
/* globals */
|
|
Wrnad_proxy_interface wrnad_proxy_ifs[WRNAD_MAX_IF];
|
|
|
|
int wrnad_rtfd = -1; /* for clean-up */
|
|
int wrnad_mipcfd = -1;
|
|
int wrnad_pfkeyfd = -1;
|
|
|
|
/* locals */
|
|
static int wrnad_seq = 0;
|
|
static int request_done = 0;
|
|
static char recvbuf[WRNAD_RECVBUF_SIZE];
|
|
|
|
int wrnad_mon_running = 0;
|
|
|
|
/*
|
|
* Table to translate Linux address family values
|
|
* to IPNET/VxWorks (NAE) address family values.
|
|
* Gotta love them family values!
|
|
*/
|
|
|
|
#if !defined IPWRNAD
|
|
/* In IPWRNAD case, we use ipxinc/include/sys/socket.h ... */
|
|
|
|
#define IP_AF_UNSPEC 0 /* Unspecified domain */
|
|
#define IP_AF_INET 2 /* IPv4 */
|
|
#define IP_AF_IPX 4 /* IPX */
|
|
#define IP_AF_NETLINK 16 /* Linux Netlink, RFC 3549 */
|
|
#define IP_AF_ROUTE 17 /* Internal routing Protocol */
|
|
#define IP_AF_LINK 18 /* Link layer address (used in route entries and ancillary data) */
|
|
#define IP_AF_PACKET 19 /* Linux packet family */
|
|
|
|
/* for VxWorks (NAE) case: */
|
|
#define IP_AF_INET6 28 /* Default family value of IP version 6 */
|
|
|
|
#define IP_AF_KEY 27 /* PFKEYv2 key-management socket API */
|
|
#define IP_AF_TIPC 33 /* Transparent Inter-Process Communic. */
|
|
#define IP_AF_MAX 35
|
|
|
|
static unsigned char af_xlat[AF_MAX] =
|
|
{
|
|
IP_AF_UNSPEC, /* 0, AF_UNSPEC */
|
|
255, /* 1, AF_LOCAL/AF_UNIX/AF_FILE */
|
|
IP_AF_INET, /* 2, AF_INET */
|
|
255, /* 3, AF_AX25 */
|
|
IP_AF_IPX, /* 4, AF_IPX */
|
|
255, /* 5, AF_APPLETALK */
|
|
255, /* 6, AF_NETROM */
|
|
255, /* 7, AF_BRIDGE */
|
|
255, /* 8, AF_ATMPVC */
|
|
255, /* 9, AF_X25 */
|
|
IP_AF_INET6, /* 10, AF_INET6 */
|
|
255, /* 11, AF_ROSE */
|
|
255, /* 12, AF_DECnet */
|
|
255, /* 13, AF_NETBEUI */
|
|
255, /* 14, AF_SECURITY */
|
|
IP_AF_KEY, /* 15, AF_KEY */
|
|
IP_AF_NETLINK, /* 16, AF_NETLINK (AF_ROUTE is an alias in linux) */
|
|
IP_AF_PACKET, /* 17, AF_PACKET */
|
|
255, /* 18, AF_ASH */
|
|
255, /* 19, AF_ECONET */
|
|
255, /* 20, AF_ATMSVC */
|
|
255, /* 21, AF_RDS */
|
|
255, /* 22, AF_SNA */
|
|
255, /* 23, AF_IRDA */
|
|
255, /* 24, AF_PPPOX */
|
|
255, /* 25, AF_WANPIPE */
|
|
255, /* 26, AF_LLC */
|
|
255, /* 27, unused */
|
|
255, /* 28, unused */
|
|
255, /* 29, AF_CAN */
|
|
IP_AF_TIPC, /* 30, AF_TIPC */
|
|
255, /* 31, AF_BLUETOOTH */
|
|
255, /* 32, AF_IUCV */
|
|
255, /* 33, AF_RXRPC */
|
|
255, /* 34, AF_ISDN */
|
|
255, /* 35, AF_PHONET */
|
|
255 /* 36, AF_IEEE802154 */
|
|
/* 37 --> AF_MAX */
|
|
};
|
|
#endif /* !defined(IPWRNAD) */
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_init - initialize wrnad monitoring
|
|
*
|
|
* This routine initializes wrnad monitoring
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
static void
|
|
wrnad_rtnl_init(void)
|
|
{
|
|
memset(&wrnad_proxy_ifs, 0, sizeof(wrnad_proxy_ifs));
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_control_handler - rtnetlink handler for control messages
|
|
*
|
|
* This routine handles rtnetlink control messages.
|
|
*
|
|
* RETURNS: -1 = failed
|
|
* 0 = skip
|
|
* 1 = action
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
static int
|
|
wrnad_rtnl_control_handler(struct nlmsghdr *nlh)
|
|
{
|
|
int len;
|
|
struct nlmsgerr *err;
|
|
|
|
if (nlh->nlmsg_type == NLMSG_ERROR)
|
|
{
|
|
err = NLMSG_DATA(nlh);
|
|
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(struct nlmsgerr));
|
|
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;
|
|
}
|
|
|
|
#ifndef IPWRNAD
|
|
/* Neighbour updates */
|
|
if (err->msg.nlmsg_type != RTM_NEWNEIGH)
|
|
#endif
|
|
wrnad_log(LOG_ERR, "Rtnetlink control message ERROR: error=%s (%d)", strerror(-err->error), -err->error);
|
|
}
|
|
else if (nlh->nlmsg_type == NLMSG_NOOP)
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink control message NOOP:");
|
|
else if (nlh->nlmsg_type == NLMSG_DONE)
|
|
{
|
|
request_done = 1;
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink control message DONE:");
|
|
}
|
|
else
|
|
wrnad_log(LOG_WARNING, "Rtnetlink control message %d:", nlh->nlmsg_type);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_handler - find rtnetlink handler
|
|
*
|
|
* This routine returns a handler form the rtnetlink message type.
|
|
*
|
|
* RETURNS: handler or NULL if not found
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
static wrnad_rtnl_handler
|
|
wrnad_rtnl_find_handler(struct nlmsghdr *nlh)
|
|
{
|
|
switch (nlh->nlmsg_type)
|
|
{
|
|
case NLMSG_ERROR:
|
|
case NLMSG_NOOP:
|
|
case NLMSG_DONE:
|
|
return wrnad_rtnl_control_handler;
|
|
case RTM_NEWNEIGH:
|
|
case RTM_DELNEIGH:
|
|
return wrnad_rtnl_neigh_handler;
|
|
case RTM_NEWLINK:
|
|
case RTM_DELLINK:
|
|
return wrnad_rtnl_link_handler;
|
|
case RTM_NEWADDR:
|
|
case RTM_DELADDR:
|
|
return wrnad_rtnl_addr_handler;
|
|
case RTM_NEWROUTE:
|
|
case RTM_DELROUTE:
|
|
return wrnad_rtnl_route_handler;
|
|
|
|
/* for VLAN stacking */
|
|
case RTM_SET_SVLAN:
|
|
case RTM_DEL_SVLAN:
|
|
return wrnad_rtnl_svlan_handler;
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_close - close rtnetlink socket
|
|
*
|
|
* This routine closes a rtnetlink socket
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
static void
|
|
wrnad_rtnl_close(int fd)
|
|
{
|
|
if (fd >= 0)
|
|
close(fd);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_open - open and bind rtnetlink socket
|
|
*
|
|
* This routine opens a rtnetlink socket and binds it.
|
|
*
|
|
* RETURNS: socket descriptor if exited normally, else -1.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
static int
|
|
wrnad_rtnl_open(int proto, unsigned int groups, struct sockaddr_nl *laddr)
|
|
{
|
|
int fd;
|
|
socklen_t addr_len;
|
|
int bufsize;
|
|
socklen_t slen;
|
|
|
|
fd = socket(AF_NETLINK, SOCK_RAW, proto);
|
|
if (fd < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to open rtnetlink socket!");
|
|
return -1;
|
|
}
|
|
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink socket %d created.", fd);
|
|
|
|
memset(laddr, 0, sizeof(laddr));
|
|
laddr->nl_family = AF_NETLINK;
|
|
laddr->nl_groups = groups;
|
|
/* associate the process's pid with netlink sock address */
|
|
laddr->nl_pid = getpid();
|
|
|
|
if (bind(fd, (struct sockaddr *)laddr, sizeof(struct sockaddr_nl)) < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to bind rtnetlink socket! errno=%s", strerror(errno));
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
addr_len = sizeof(struct sockaddr_nl);
|
|
if (getsockname(fd, (struct sockaddr *)laddr, &addr_len) < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to getsockname!");
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
bufsize = 0;
|
|
slen = (socklen_t)sizeof (bufsize);
|
|
if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, &slen) < 0)
|
|
wrnad_log(LOG_ERR, "Failed to get default netlink socket RCVBUF\n");
|
|
else
|
|
wrnad_log(LOG_INFO, "Default netlink socket RCVBUF is %u\n", bufsize);
|
|
|
|
bufsize = 64 * 1024 * 1024;
|
|
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Failed to set netlink socket RCVBUF to %u.\n", bufsize);
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink socket %d bound to pid %u.", fd, laddr->nl_pid);
|
|
|
|
return fd;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_parse - parse message received on rtnetlink socket
|
|
*
|
|
* This routine parses indivudual messages received on a rtnetlink socket
|
|
*
|
|
* RETURNS: 0 if exited normally, else -1.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
static int
|
|
wrnad_rtnl_parse(int fd, struct nlmsghdr *nlh)
|
|
{
|
|
wrnad_rtnl_handler f;
|
|
int ret;
|
|
|
|
/* Find handler */
|
|
if ((f = wrnad_rtnl_find_handler(nlh)))
|
|
{
|
|
ret = f(nlh);
|
|
if (ret == 1)
|
|
{
|
|
/* Send rtnetlink message over MIPC */
|
|
nlh->nlmsg_seq = 0;
|
|
nlh->nlmsg_pid = 0;
|
|
ret = wrnad_mipc_send_netlink(fd, nlh);
|
|
}
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
wrnad_log(LOG_INFO, "No handler found for rtnetlink type %d (%s)!",
|
|
nlh->nlmsg_type, wrnad_rtnl_typestr(nlh->nlmsg_type));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_scan - scan message received on rtnetlink socket
|
|
*
|
|
* This routine scans messages received on a rtnetlink socket
|
|
*
|
|
* RETURNS: 0 if exited normally, else -1.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
static int
|
|
wrnad_rtnl_scan(char *buf, int buflen, int fd)
|
|
{
|
|
struct nlmsghdr *nlh;
|
|
|
|
nlh = (struct nlmsghdr *)buf;
|
|
while (NLMSG_OK(nlh, (size_t)buflen))
|
|
{
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink message header: length=%d, type=%s, flags=%d, seq=%d, pid=%u.",
|
|
nlh->nlmsg_len,
|
|
wrnad_rtnl_typestr(nlh->nlmsg_type),
|
|
nlh->nlmsg_flags,
|
|
nlh->nlmsg_seq,
|
|
nlh->nlmsg_pid);
|
|
|
|
if (wrnad_rtnl_parse(fd, nlh) >= 0)
|
|
{
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink message type %s handled ok.",
|
|
wrnad_rtnl_typestr(nlh->nlmsg_type));
|
|
}
|
|
|
|
nlh = NLMSG_NEXT(nlh, buflen);
|
|
}
|
|
|
|
if (buflen)
|
|
{
|
|
wrnad_log(LOG_WARNING, "Rtnetlink message truncated! Found %d trailing bytes.", buflen);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_recvfrom - recv on rtnetlink socket
|
|
*
|
|
* This routine receives messages on a rtnetlink socket
|
|
*
|
|
* RETURNS: 0 if exited normally, else -1.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
static int
|
|
wrnad_rtnl_recvfrom(int rtfd, int mipc_fd)
|
|
{
|
|
int len;
|
|
struct sockaddr_nl raddr;
|
|
socklen_t addrlen;
|
|
|
|
memset(&raddr, 0, sizeof(raddr));
|
|
raddr.nl_family = AF_NETLINK;
|
|
raddr.nl_pid = 0;
|
|
raddr.nl_groups = 0;
|
|
addrlen = 0;
|
|
|
|
len = recvfrom(rtfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&raddr, &addrlen);
|
|
if (len < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Recvfrom on rtnetlink socket %d interrupted by error %s -> exit.", rtfd, strerror(errno));
|
|
return -1;
|
|
}
|
|
else if (len == 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "Recvfrom on rtnetlink socket %d interrupted by EOF.", rtfd);
|
|
return -1;
|
|
}
|
|
|
|
wrnad_log(LOG_DEBUG, "Recvfrom on rtnetlink socket %d returned %d bytes of data.", rtfd, len);
|
|
|
|
/* Verify that the message was received from the kernel.
|
|
Note: A message may also arrive from svconfig for VLAN stacking configuration (via the kernel).
|
|
*/
|
|
if (raddr.nl_pid)
|
|
{
|
|
wrnad_log(LOG_WARNING, "Skipped rtnetlink message received from pid %d!", raddr.nl_pid);
|
|
return 0;
|
|
}
|
|
|
|
/* Scan receive message */
|
|
if (wrnad_rtnl_scan(recvbuf, len, mipc_fd) < 0)
|
|
wrnad_log(LOG_WARNING, "Rtnetlink message failed scan!\n");
|
|
else
|
|
wrnad_log(LOG_DEBUG, "Rtnetlink message scanned ok.\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_get_request - set get rtnetlink get request
|
|
*
|
|
* This routine sends a request to retrieve all entries of a rtnetlink type.
|
|
*
|
|
* RETURNS: 0 if exited normally, else -1.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
static int
|
|
wrnad_rtnl_send_request(int fd, int family, int type)
|
|
{
|
|
struct sockaddr_nl raddr;
|
|
struct {
|
|
struct nlmsghdr nlh;
|
|
unsigned char family;
|
|
} req;
|
|
|
|
memset(&raddr, 0, sizeof(raddr));
|
|
raddr.nl_family = AF_NETLINK;
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
req.nlh.nlmsg_len = sizeof(req);
|
|
req.nlh.nlmsg_type = type;
|
|
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
|
|
req.nlh.nlmsg_seq = ++wrnad_seq;
|
|
req.family = family;
|
|
|
|
/* Send the request */
|
|
wrnad_log(LOG_DEBUG, "Sending rtnetlink %s request on socket %d", wrnad_rtnl_typestr(type), fd);
|
|
if (sendto(fd, (void *)&req, sizeof(req), 0, (struct sockaddr *)&raddr, sizeof(struct sockaddr_nl)) < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "send failed! errno=%s (%d)\n", strerror(errno), errno);
|
|
return -1;
|
|
}
|
|
|
|
request_done = 0;
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_proxyifstr - find proxy interfaces
|
|
*
|
|
* This routine returns the current proxy interfaces as a string
|
|
*
|
|
* RETURNS: string representation of procy interfaces.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
static char *
|
|
wrnad_rtnl_proxyifstr(char *ifstr)
|
|
{
|
|
int i, j;
|
|
|
|
ifstr[0] = '\0';
|
|
j = 0;
|
|
for (i = 0; i<WRNAD_MAX_IF; i++)
|
|
{
|
|
if (wrnad_proxy_ifs[i].ifname[0] != '\0')
|
|
{
|
|
if (j == 0)
|
|
j += sprintf(&ifstr[j], "%s (%d)", wrnad_proxy_ifs[i].ifname, wrnad_proxy_ifs[i].ifindex);
|
|
else
|
|
j += sprintf(&ifstr[j], ", %s (%d)", wrnad_proxy_ifs[i].ifname, wrnad_proxy_ifs[i].ifindex);
|
|
}
|
|
}
|
|
|
|
return ifstr;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_check_proxy_interface - check proxy interface
|
|
*
|
|
* This routine checks if an interface is a proxy inteface
|
|
*
|
|
* RETURNS: proxy interface name if found else NULL;
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
Wrnad_proxy_interface *
|
|
wrnad_rtnl_check_proxy_interface(int ifindex)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i<WRNAD_MAX_IF; i++)
|
|
{
|
|
if (wrnad_proxy_ifs[i].ifindex == ifindex)
|
|
{
|
|
return &wrnad_proxy_ifs[i];
|
|
}
|
|
}
|
|
|
|
/* Not found */
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_add_proxy_interface - add proxy interface
|
|
*
|
|
* This routine adds a proxy interface to the internal list
|
|
*
|
|
* RETURNS: 0 if exited normally, else -1.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
int
|
|
wrnad_rtnl_add_proxy_interface(int ifindex, char *ifname)
|
|
{
|
|
int i;
|
|
char proxyifs[512];
|
|
|
|
if (wrnad_rtnl_check_proxy_interface(ifindex))
|
|
{
|
|
wrnad_log(LOG_INFO, "Found proxy interface %s with index %d", ifname, ifindex);
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i<WRNAD_MAX_IF; i++)
|
|
{
|
|
if (wrnad_proxy_ifs[i].ifname[0] == '\0')
|
|
{
|
|
wrnad_proxy_ifs[i].ifindex = ifindex;
|
|
strcpy(wrnad_proxy_ifs[i].ifname, ifname);
|
|
#ifdef WRNAD_IDENTIFY_ROUTERS
|
|
if (hash_v4_init(&wrnad_proxy_ifs[i].v4_routers) != 0 ||
|
|
hash_v6_init(&wrnad_proxy_ifs[i].v6_routers) != 0)
|
|
{
|
|
wrnad_log(LOG_ERR,
|
|
"Failed allocating router hash table for "
|
|
"proxy interface %s\n", ifname);
|
|
wrnad_terminate(EXIT_FAILURE);
|
|
}
|
|
#endif
|
|
wrnad_log(LOG_INFO, "Added proxy interface %s with index %d at position %d",
|
|
ifname, ifindex, i);
|
|
wrnad_log(LOG_INFO, "Current proxy interfaces are: %s.", wrnad_rtnl_proxyifstr(proxyifs));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Reached maximum number of proxy interfaces */
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_del_proxy_interface - del proxy interface
|
|
*
|
|
* This routine deletes a proxy interface from the internal list
|
|
*
|
|
* RETURNS: 0 if exited normally, else -1.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
int
|
|
wrnad_rtnl_del_proxy_interface(int ifindex, char *ifname)
|
|
{
|
|
int i;
|
|
char proxyifs[512];
|
|
|
|
for (i = 0; i<WRNAD_MAX_IF; i++)
|
|
{
|
|
if (wrnad_proxy_ifs[i].ifindex == ifindex
|
|
&& strcmp(wrnad_proxy_ifs[i].ifname, ifname) == 0)
|
|
{
|
|
wrnad_proxy_ifs[i].ifindex = 0;
|
|
wrnad_proxy_ifs[i].ifname[0] = '\0';
|
|
wrnad_log(LOG_INFO, "Removed proxy interface %s with index %d from position %d",
|
|
ifname, ifindex, i);
|
|
wrnad_log(LOG_INFO, "Current proxy interfaces are: %s.", wrnad_rtnl_proxyifstr(proxyifs));
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* Not found */
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_familystr - find rtnetlink family in string format
|
|
*
|
|
* This routine returns the rtnetlink family as a string
|
|
*
|
|
* RETURNS: string representation of rtnetlink family.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
const char *
|
|
wrnad_rtnl_familystr(int family)
|
|
{
|
|
static char familystr[32];
|
|
|
|
switch (family)
|
|
{
|
|
case AF_UNSPEC:
|
|
return "AF_UNSPEC";
|
|
case AF_INET:
|
|
return "AF_INET";
|
|
case AF_INET6:
|
|
return "AF_INET6";
|
|
default:
|
|
sprintf(familystr, "%d", family);
|
|
return familystr;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_typestr - find rtnetlink type in string format
|
|
*
|
|
* This routine returns the rtnetlink message type as a string
|
|
*
|
|
* RETURNS: string representation of rtnetlink type.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
const char *
|
|
wrnad_rtnl_typestr(int type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case NLMSG_ERROR:
|
|
return "NLMSG_ERROR";
|
|
case NLMSG_NOOP:
|
|
return "NLMSG_NOOP";
|
|
case NLMSG_DONE:
|
|
return "NLMSG_DONE";
|
|
case RTM_NEWLINK:
|
|
return "RTM_NEWLINK";
|
|
case RTM_DELLINK:
|
|
return "RTM_DELLINK";
|
|
case RTM_GETLINK:
|
|
return "RTM_GETLINK";
|
|
case RTM_SETLINK:
|
|
return "RTM_SETLINK";
|
|
case RTM_NEWADDR:
|
|
return "RTM_NEWADDR";
|
|
case RTM_DELADDR:
|
|
return "RTM_DELADDR";
|
|
case RTM_GETADDR:
|
|
return "RTM_GETADDR";
|
|
case RTM_NEWROUTE:
|
|
return "RTM_NEWROUTE";
|
|
case RTM_DELROUTE:
|
|
return "RTM_DELROUTE";
|
|
case RTM_GETROUTE:
|
|
return "RTM_GETROUTE";
|
|
#ifdef RTM_NEWNEIGH
|
|
case RTM_NEWNEIGH:
|
|
return "RTM_NEWNEIGH";
|
|
case RTM_DELNEIGH:
|
|
return "RTM_DELNEIGH";
|
|
case RTM_GETNEIGH:
|
|
return "RTM_GETNEIGH";
|
|
#endif
|
|
case RTM_NEWRULE:
|
|
return "RTM_NEWRULE";
|
|
case RTM_DELRULE:
|
|
return "RTM_DELRULE";
|
|
case RTM_GETRULE:
|
|
return "RTM_GETRULE";
|
|
case RTM_NEWQDISC:
|
|
return "RTM_NEWQDISC";
|
|
case RTM_DELQDISC:
|
|
return "RTM_DELQDISC";
|
|
case RTM_GETQDISC:
|
|
return "RTM_GETQDISC";
|
|
case RTM_NEWTCLASS:
|
|
return "RTM_NEWTCLASS";
|
|
case RTM_DELTCLASS:
|
|
return "RTM_NEWTCLASS";
|
|
case RTM_GETTCLASS:
|
|
return "RTM_NEWTCLASS";
|
|
case RTM_NEWTFILTER:
|
|
return "RTM_NEWTFILTER";
|
|
case RTM_DELTFILTER:
|
|
return "RTM_DELTFILTER";
|
|
case RTM_GETTFILTER:
|
|
return "RTM_GETTFILTER";
|
|
case RTM_NEWACTION:
|
|
return "RTM_NEWACTION";
|
|
case RTM_DELACTION:
|
|
return "RTM_DELACTION";
|
|
case RTM_GETACTION:
|
|
return "RTM_GETACTION";
|
|
case RTM_NEWPREFIX:
|
|
return "RTM_NEWPREFIX";
|
|
case RTM_GETMULTICAST:
|
|
return "RTM_GETMULTICAST";
|
|
case RTM_GETANYCAST:
|
|
return "RTM_GETANYCAST";
|
|
#ifdef RTM_NEWNEIGHTBL
|
|
case RTM_NEWNEIGHTBL:
|
|
return "RTM_NEWNEIGHTBL";
|
|
case RTM_GETNEIGHTBL:
|
|
return "RTM_GETNEIGHTBL";
|
|
case RTM_SETNEIGHTBL:
|
|
return "RTM_SETNEIGHTBL";
|
|
#endif
|
|
case RTM_SET_SVLAN:
|
|
return "RTM_SET_SVLAN";
|
|
case RTM_DEL_SVLAN:
|
|
return "RTM_DEL_SVLAN";
|
|
#if 0
|
|
case RTM_NEWNDUSEROPT:
|
|
return "RTM_NEWNDUSEROPT";
|
|
case RTM_NEWADDRLABEL:
|
|
return "RTM_NEWADDRLABEL";
|
|
case RTM_DELADDRLABEL:
|
|
return "RTM_DELADDRLABEL";
|
|
case RTM_GETADDRLABEL:
|
|
return "RTM_GETADDRLABEL";
|
|
case RTM_GETDCB:
|
|
return "RTM_GETDCB";
|
|
case RTM_SETDCB:
|
|
return "RTM_SETDCB";
|
|
#endif
|
|
default:
|
|
return "RTM_UNKNOWN";
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_rtnl_eth_ntop - ethernet mac address in string format
|
|
*
|
|
* This routine returns the ethernet mac address as a string
|
|
*
|
|
* RETURNS: string representation of the ethernet mac address.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
void
|
|
wrnad_rtnl_eth_ntop(unsigned char *mac, char *buf)
|
|
{
|
|
sprintf(&buf[0], "%02x", mac[0]);
|
|
sprintf(&buf[2], ":%02x", mac[1]);
|
|
sprintf(&buf[5], ":%02x", mac[2]);
|
|
sprintf(&buf[8], ":%02x", mac[3]);
|
|
sprintf(&buf[11], ":%02x", mac[4]);
|
|
sprintf(&buf[14], ":%02x", mac[5]);
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* wrnad_monitor - wrnad monitor main loop
|
|
*
|
|
* This routine is the wrnad monitor main loop. It subscribes and listens to
|
|
* rtnetlink messages and acts upon them. Normally it never returns.
|
|
*
|
|
* RETURNS: 0 if exited normally, else -1.
|
|
*
|
|
* ERRNO: N/A
|
|
*/
|
|
|
|
int
|
|
wrnad_rtnl_monitor(int bus, int node, int port)
|
|
{
|
|
int rtfd, mipcfd, nfds, ret = 0;
|
|
unsigned int groups;
|
|
struct sockaddr_nl laddr;
|
|
fd_set rfds;
|
|
#if !defined(IPWRNAD) || defined(IPIPSEC2)
|
|
int pfkeyfd;
|
|
#endif /* !IPWRNAD || IPIPSEC2 */
|
|
#if !defined(IPWRNAD)
|
|
int ndp = -1;
|
|
#endif
|
|
|
|
/* Initialize */
|
|
wrnad_rtnl_init();
|
|
rtfd = mipcfd = -1;
|
|
|
|
#if !defined(IPWRNAD) || defined(IPIPSEC2)
|
|
/* Create the pfkey socket and set promiscuous mode */
|
|
pfkeyfd = wrnad_pfkey_open();
|
|
wrnad_pfkeyfd = pfkeyfd;
|
|
#ifdef IPIPSEC2
|
|
if (pfkeyfd < 0)
|
|
return -1;
|
|
#endif
|
|
#endif /* !IPWRNAD || IPIPSEC2 */
|
|
|
|
#if !defined(IPWRNAD)
|
|
ndp = wrnad_neigh_ndp_open();
|
|
#endif
|
|
|
|
/* Create the mipc socket and connect to peer */
|
|
mipcfd = wrnad_mipc_open(bus, node, port);
|
|
wrnad_mipcfd = mipcfd;
|
|
|
|
if (mipcfd < 0)
|
|
{
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
|
|
/* Create the rtnetlink socket and bind to multicast groups */
|
|
groups = (RTMGRP_LINK
|
|
| RTMGRP_NEIGH
|
|
| RTMGRP_IPV4_IFADDR
|
|
| RTMGRP_IPV4_ROUTE
|
|
| RTMGRP_IPV6_IFADDR
|
|
| RTMGRP_IPV6_ROUTE);
|
|
rtfd = wrnad_rtnl_open(NETLINK_ROUTE, groups, &laddr);
|
|
wrnad_rtfd = rtfd;
|
|
|
|
if (rtfd < 0)
|
|
{
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
|
|
/* Send a request to list all network interfaces */
|
|
wrnad_rtnl_send_request(rtfd, AF_UNSPEC, RTM_GETLINK);
|
|
while (!request_done)
|
|
wrnad_rtnl_recvfrom(rtfd, mipcfd);
|
|
|
|
/* Send a request to list all ip addresses */
|
|
wrnad_rtnl_send_request(rtfd, AF_UNSPEC, RTM_GETADDR);
|
|
while (!request_done)
|
|
wrnad_rtnl_recvfrom(rtfd, mipcfd);
|
|
|
|
/* Send a request to list all routes */
|
|
wrnad_rtnl_send_request(rtfd, AF_UNSPEC, RTM_GETROUTE);
|
|
while (!request_done)
|
|
wrnad_rtnl_recvfrom(rtfd, mipcfd);
|
|
|
|
/* Send a request to list all routes */
|
|
wrnad_rtnl_send_request(rtfd, AF_UNSPEC, RTM_GETNEIGH);
|
|
while (!request_done)
|
|
wrnad_rtnl_recvfrom(rtfd, mipcfd);
|
|
|
|
/* Enter main loop */
|
|
wrnad_log(LOG_INFO, "Entering monitoring loop.");
|
|
wrnad_mon_running = 1;
|
|
for (;;)
|
|
{
|
|
FD_ZERO(&rfds);
|
|
FD_SET(rtfd, &rfds);
|
|
#if !defined(IPWRNAD) || defined(IPIPSEC2)
|
|
if (pfkeyfd > 0)
|
|
FD_SET(pfkeyfd, &rfds);
|
|
#endif /* !IPWRNAD || IPIPSEC2 */
|
|
|
|
nfds = rtfd;
|
|
#if !defined(IPWRNAD) || defined(IPIPSEC2)
|
|
if (pfkeyfd > nfds)
|
|
nfds = pfkeyfd;
|
|
#endif
|
|
|
|
#if !defined(IPWRNAD)
|
|
if (-1 != ndp)
|
|
{
|
|
FD_SET(ndp, &rfds);
|
|
if (ndp > nfds)
|
|
nfds = ndp;
|
|
}
|
|
#endif
|
|
|
|
ret = select(nfds + 1, &rfds, NULL, NULL, NULL);
|
|
if (ret < 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "select interrupted by error %s.", strerror(errno));
|
|
if (errno == EINTR || errno == EAGAIN)
|
|
continue;
|
|
ret = 0;
|
|
break;
|
|
}
|
|
else if (ret == 0)
|
|
{
|
|
wrnad_log(LOG_ERR, "select returned unexpected timeout", strerror(errno));
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
|
|
if (FD_ISSET(rtfd, &rfds))
|
|
{
|
|
/* Receive messages on the rtnetlink socket */
|
|
if (wrnad_rtnl_recvfrom(rtfd, mipcfd) < 0)
|
|
{
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
#if !defined(IPWRNAD)
|
|
if (-1 != ndp && FD_ISSET(ndp, &rfds))
|
|
wrnad_neigh_ndp_read(ndp, rtfd, recvbuf, sizeof(recvbuf));
|
|
#endif
|
|
|
|
#if !defined(IPWRNAD) || defined(IPIPSEC2)
|
|
if (FD_ISSET(pfkeyfd, &rfds))
|
|
{
|
|
/* Receive messages on the pfkey socket */
|
|
if (wrnad_pfkey_recv(pfkeyfd, mipcfd) < 0)
|
|
{
|
|
ret = -1;
|
|
goto exit;
|
|
}
|
|
}
|
|
#endif /* !IPWRNAD || IPIPSEC2 */
|
|
}
|
|
|
|
exit:
|
|
wrnad_mon_running = 0;
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
wrnad_cleanup(void)
|
|
{
|
|
int i;
|
|
|
|
wrnad_mipc_close(wrnad_mipcfd);
|
|
wrnad_mipcfd = -1;
|
|
wrnad_rtnl_close(wrnad_rtfd);
|
|
wrnad_rtfd = -1;
|
|
#if !defined(IPWRNAD) || defined(IPIPSEC2)
|
|
wrnad_pfkey_close(wrnad_pfkeyfd);
|
|
wrnad_pfkeyfd = -1;
|
|
#endif /* !IPWRNAD || IPIPSEC2 */
|
|
|
|
#ifdef WRNAD_IDENTIFY_ROUTERS
|
|
for (i = 0; i<WRNAD_MAX_IF; i++)
|
|
{
|
|
if (wrnad_proxy_ifs[i].ifname[0] == '\0')
|
|
continue;
|
|
hash_table_destroy(&wrnad_proxy_ifs[i].v4_routers);
|
|
hash_table_destroy(&wrnad_proxy_ifs[i].v6_routers);
|
|
}
|
|
hash_item_pools_destroy();
|
|
#endif
|
|
}
|
|
|
|
#if !defined IPWRNAD
|
|
unsigned char
|
|
wrnad_af_xlat(unsigned int linux_af)
|
|
{
|
|
if (linux_af >= AF_MAX)
|
|
return (unsigned char)255;
|
|
return af_xlat[linux_af];
|
|
}
|
|
#endif /* !defined WRNAD */
|