|
From: | Jeff Bailey |
Subject: | Re: [bug-inetutils] route |
Date: | Mon, 18 Aug 2008 22:04:47 -0700 |
Does the linux kernel guarantee those as v4 only addresses? If its easy, it would be nice to see a couple TODOs listed for v6 support.
V6 shouldn't block a commit, though.
On Aug 18, 2008 10:01 PM, "Jeff Bailey" <address@hidden> wrote:
Is there a
On Aug 18, 2008 9:25 PM, "Debarshi Ray" <address@hidden> wrote:
Here is a proof-of-concept for implementing route for Inetutils.
Unlike some route implementations for GNU/Linux, this does not indulge
in parsing /proc/net/... or using SIOCxxxx ioctl commands. Instead I
have used the PF_NETLINK socket interface provided by the Linux
kernel. I also plan to make this work with the *BSD kernels, since
atleast FreeBSD and NetBSD seem to have a similar socket driven
interface.
Please note that all uses of malloc and realloc will be replaced by
xmalloc and xrealloc once the code moves into Inetutils.
#include <errno.h>
#include <error.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h> // malloc, realloc, free
#include <string.h>
#include <unistd.h>
#include <asm/types.h>
#include <net/if.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
^L
struct _msghdr_t
{
struct nlmsghdr nlmsghdr;
struct rtmsg rtmsg;
};
typedef struct _msghdr_t msghdr_t;
struct _rtinfo_t
{
char dest[16];
char gateway[16];
char iface[IFNAMSIZ];
int metrics;
int ref;
int use;
};
typedef struct _rtinfo_t rtinfo_t;
uint32_t seqn = 0;
void print_header (void);
void print_route (const rtinfo_t *const rtinfo);
void rtinfo_init (rtinfo_t *const rtinfo);
void linux_route (void);
size_t linux_recvnl (int sockfd, void **buffer);
size_t linux_sendnl (int sockfd);
void linux_parsenl (void *buffer, size_t size);
size_t recvbuf (int sockfd, void **buffer, size_t *size);
int
main (int argc, char *argv[])
{
print_header ();
linux_route ();
return 0;
}
void
print_header (void)
{
puts ("Kernel IP routing table");
printf ("%-15s %-15s %-6s %-6s %-6s %-15s\n",
"Destination",
"Gateway",
"Metric",
"Ref",
"Use",
"Iface");
}
void
print_route (const rtinfo_t *const rtinfo)
{
printf ("%-15s %-15s %-6d %-6d %-6d %-15s\n",
rtinfo->dest,
rtinfo->gateway,
rtinfo->metrics,
rtinfo->ref,
rtinfo->use,
rtinfo->iface);
}
void rtinfo_init (rtinfo_t *const rtinfo)
{
strcpy (rtinfo->dest, "0.0.0.0");
strcpy (rtinfo->gateway, "0.0.0.0");
strcpy (rtinfo->iface, "");
rtinfo->metrics = 0;
rtinfo->ref = 0;
rtinfo->use = 0;
}
void
linux_route (void)
{
int sockfd;
size_t nread;
void *buffer = NULL;
sockfd = socket (PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
if (sockfd == -1)
error (EXIT_FAILURE, errno, "socket");
linux_sendnl (sockfd);
nread = linux_recvnl (sockfd, &buffer);
linux_parsenl (buffer, nread);
close (sockfd);
free (buffer);
}
void
linux_parsenl (void *buffer, size_t nread)
{
unsigned int size;
msghdr_t *msghdr;
rtinfo_t rtinfo;
struct rtattr *attr;
for (msghdr = (msghdr_t *) buffer;
NLMSG_OK (&msghdr->nlmsghdr, nread) != 0;
msghdr = (msghdr_t *) NLMSG_NEXT (&msghdr->nlmsghdr, nread))
{
if ((msghdr->rtmsg.rtm_family != AF_INET)
|| (msghdr->rtmsg.rtm_table != RT_TABLE_MAIN))
continue;
rtinfo_init (&rtinfo);
attr = (struct rtattr *) RTM_RTA (&msghdr->rtmsg);
size = RTM_PAYLOAD (&msghdr->nlmsghdr);
while (RTA_OK (attr, size))
{
switch(attr->rta_type)
{
case RTA_DST:
inet_ntop(AF_INET, RTA_DATA (attr), rtinfo.dest,
sizeof (rtinfo.dest));
break;
case RTA_GATEWAY:
inet_ntop(AF_INET, RTA_DATA (attr), rtinfo.gateway,
sizeof (rtinfo.gateway));
break;
case RTA_OIF:
if_indextoname (*(int *) RTA_DATA (attr), rtinfo.iface);
break;
case RTA_METRICS:
rtinfo.metrics = *(int *) RTA_DATA (attr);
break;
default:
break;
}
attr = RTA_NEXT (attr, size);
}
print_route (&rtinfo);
}
}
size_t
linux_recvnl (int sockfd, void **buffer)
{
msghdr_t *msghdr;
size_t nread = 0;
size_t size = 0;
if (*buffer != NULL)
return -1;
nread = recvbuf (sockfd, buffer, &size);
size = nread;
for (msghdr = (msghdr_t *) *buffer; NLMSG_OK (&msghdr->nlmsghdr, size);
msghdr = (msghdr_t *) NLMSG_NEXT (&msghdr->nlmsghdr, size))
{
if (msghdr->nlmsghdr.nlmsg_type == NLMSG_ERROR)
error (EXIT_FAILURE, 0,
"netlink message truncated and can not be parsed");
if (msghdr->nlmsghdr.nlmsg_type == NLMSG_DONE)
break;
if ((msghdr->nlmsghdr.nlmsg_flags & NLM_F_MULTI) == 0)
break;
}
return nread;
}
size_t
linux_sendnl (int sockfd)
{
size_t nsent;
msghdr_t msghdr;
memset ((void *) &msghdr, 0, sizeof (msghdr));
msghdr.nlmsghdr.nlmsg_len = NLMSG_LENGTH (sizeof (msghdr.rtmsg));
msghdr.nlmsghdr.nlmsg_type = RTM_GETROUTE;
msghdr.nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
msghdr.nlmsghdr.nlmsg_seq = seqn;
msghdr.nlmsghdr.nlmsg_pid = getpid();
nsent = send (sockfd, (void *) &msghdr, sizeof (msghdr), 0);
if (nsent == -1)
error (EXIT_FAILURE, errno, "send");
seqn++;
return nsent;
}
size_t
recvbuf (int sockfd, void **buffer, size_t *size)
{
size_t count = 0;
size_t nread;
if (*buffer == NULL)
*size = BUFSIZ;
for (;;)
{
*buffer = realloc (*buffer, *size);
nread = recv (sockfd, *buffer + count, BUFSIZ, 0);
if (nread == -1)
error (EXIT_FAILURE, errno, "recv");
count += nread;
if (nread < BUFSIZ)
break;
else
*size += BUFSIZ;
}
return count;
}
Comments?
Happy hacking,
Debarshi
_______________________________________________
bug-inetutils mailing list
address@hidden
http://lists.gnu.org/mailman/listinfo/bug-inetutils
[Prev in Thread] | Current Thread | [Next in Thread] |