>From 00fc1df9598f1de727051a6e1dd263837293af43 Mon Sep 17 00:00:00 2001
From: Ashish Shukla
Date: Tue, 7 Oct 2008 16:24:56 +0530
Subject: [PATCH] 2008-10-07 Ashish Shukla
* libroute/route_bsd.h: Removed flags parameter from 'bsd_add'
function prototype.
* libroute/route_bsd.c (bsd_add): Implemented.
* libroute/bsd_add.c, libroute/bsd_delete.c, libroute/bsd_show.c:
Merged into libroute/route_bsd.c and removed.
* libroute/Makefile.am: Updated.
---
ChangeLog | 12 ++
libroute/Makefile.am | 3 +-
libroute/bsd_add.c | 33 ----
libroute/bsd_delete.c | 28 ---
libroute/bsd_show.c | 310 -------------------------------
libroute/route_bsd.c | 484 +++++++++++++++++++++++++++++++++++++++++++++++++
libroute/route_bsd.h | 3 +-
7 files changed, 498 insertions(+), 375 deletions(-)
delete mode 100644 libroute/bsd_add.c
delete mode 100644 libroute/bsd_delete.c
delete mode 100644 libroute/bsd_show.c
diff --git a/ChangeLog b/ChangeLog
index 3173ccd..bdd00db 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
2008-10-07 Ashish Shukla
+ * libroute/route_bsd.h: Removed flags parameter from 'bsd_add'
+ function prototype.
+
+ * libroute/route_bsd.c (bsd_add): Implemented.
+
+ * libroute/bsd_add.c, libroute/bsd_delete.c, libroute/bsd_show.c:
+ Merged into libroute/route_bsd.c and removed.
+
+ * libroute/Makefile.am: Updated.
+
+2008-10-07 Ashish Shukla
+
* libroute/route_common.c (conv_name_to_addr): Support IPv6
addresses. Use `gethostbyname2' instead of `gethostbyname'.
diff --git a/libroute/Makefile.am b/libroute/Makefile.am
index 52c5216..33c1b48 100644
--- a/libroute/Makefile.am
+++ b/libroute/Makefile.am
@@ -22,8 +22,7 @@ EXTRA_LTLIBRARIES = libroute.la
libroute_la_SOURCES = route_backend.c route_common.c route_$(KERNEL).c
-EXTRA_libroute_la_SOURCES = bsd_add.c bsd_delete.c bsd_show.c route_bsd.c \
- route_linux.c
+EXTRA_libroute_la_SOURCES = route_bsd.c route_linux.c
noinst_HEADERS = route.h route_bsd.h route_linux.h
diff --git a/libroute/bsd_add.c b/libroute/bsd_add.c
deleted file mode 100644
index 299d9c9..0000000
--- a/libroute/bsd_add.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Copyright (C) 2008 Free Software Foundation, Inc.
-
- This file is part of Netutils.
-
- Netutils is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
-
- Netutils is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Netutils; see the file COPYING. If not, write
- to the Free Software Foundation, Inc., 51 Franklin Street,
- Fifth Floor, Boston, MA 02110-1301 USA. */
-
-#include
-#include
-
-void
-bsd_add (const int format,
- const uint16_t flags,
- const void *const dest_addr,
- const size_t dest_addr_size,
- const unsigned char dest_addr_len,
- const void *const gw_addr,
- const size_t gw_addr_size,
- const unsigned int iface)
-{
-}
diff --git a/libroute/bsd_delete.c b/libroute/bsd_delete.c
deleted file mode 100644
index 2c88055..0000000
--- a/libroute/bsd_delete.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Copyright (C) 2008 Free Software Foundation, Inc.
-
- This file is part of Netutils.
-
- Netutils is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
-
- Netutils is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Netutils; see the file COPYING. If not, write
- to the Free Software Foundation, Inc., 51 Franklin Street,
- Fifth Floor, Boston, MA 02110-1301 USA. */
-
-#include
-
-void
-bsd_delete (const int format,
- const void *const dest_addr,
- const size_t dest_addr_size,
- const unsigned char dest_len)
-{
-}
diff --git a/libroute/bsd_show.c b/libroute/bsd_show.c
deleted file mode 100644
index 327a691..0000000
--- a/libroute/bsd_show.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/* Copyright (C) 2008 Free Software Foundation, Inc.
-
- This file is part of Netutils.
-
- Netutils is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
-
- Netutils is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Netutils; see the file COPYING. If not, write
- to the Free Software Foundation, Inc., 51 Franklin Street,
- Fifth Floor, Boston, MA 02110-1301 USA. */
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "route.h"
-#include "xalloc.h"
-
-enum
-{
- K_INET = 20,
- K_INET6 = 21
-};
-
-struct flag
-{
- int mask;
- char * str;
-};
-typedef struct flag flag_t;
-
-void bsd_conv_addr_to_name (const struct sockaddr *const sock,
- char *const buffer, const size_t buffer_size,
- const short int resolve_names);
-void bsd_flags (const int field, char *const buffer, size_t size);
-const route_info_t * bsd_parse_msg (const sa_family_t sa_family,
- const struct rt_msghdr *msg, size_t nread,
- const short int resolve_names);
-size_t bsd_sysctl (void ** buffer, size_t *const size);
-struct rt_msghdr * rt_msg_next (const struct rt_msghdr *rtm,
- size_t *const length);
-
-void
-bsd_conv_addr_to_name (const struct sockaddr *const sock,
- char *const buffer, const size_t buffer_size,
- const short int resolve_names)
-{
- if (sock->sa_family == AF_LINK)
- conv_link_addr_to_name (sock, sock->sa_len, buffer, buffer_size,
- resolve_names);
- else if (sock->sa_family == AF_INET || sock->sa_family == AF_INET6)
- {
- void *addr;
- size_t addr_size;
-
- if (sock->sa_family == AF_INET)
- {
- addr = &(((struct sockaddr_in *) sock)->sin_addr);
- addr_size = sizeof (struct in_addr);
- }
- else /* AF_INET */
- {
- addr = &(((struct sockaddr_in6 *) sock)->sin6_addr);
- addr_size = sizeof (struct in6_addr);
- }
-
- conv_inet_addr_to_name (sock->sa_family, addr, addr_size,
- buffer, buffer_size, resolve_names);
- }
- else
- printf ("%u\n", sock->sa_family);
-}
-
-void
-bsd_flags (const int field, char *const buffer, size_t size)
-{
- const flag_t flags[] = {
- {RTF_UP, "U"},
- {RTF_GATEWAY, "G"},
- {RTF_HOST, "H"},
- {RTF_REJECT, "R"},
- {RTF_DYNAMIC, "D"},
- {RTF_LLINFO, "L"},
- {RTF_STATIC, "S"},
- {RTF_WASCLONED, "W"},
- };
- int i;
-
- memset ((void*) buffer, 0, size);
- for (i = 0; i < sizeof (flags) / sizeof (flags[0]); i++)
- {
- if ((field & flags[i].mask) != 0)
- {
- strncat (buffer, flags[i].str, size - 1);
- size -= strlen (flags[i].str);
- }
- }
-}
-
-const route_info_t *
-bsd_show (const sa_family_t sa_family, const short int resolve_names)
-{
- const route_info_t *list;
- size_t nread;
- size_t size;
- struct rt_msghdr *msg;
-
- nread = bsd_sysctl ((void **) &msg, &size);
- list = bsd_parse_msg (sa_family, msg, nread, resolve_names);
- free (msg);
- return list;
-}
-
-const route_info_t *
-bsd_parse_msg (const sa_family_t sa_family,
- const struct rt_msghdr *msg, size_t nread,
- const short int resolve_names)
-{
- const route_info_t *list = NULL;
- route_info_t *route_info = NULL;
- const struct sockaddr *sock_addr;
-
- while (msg != NULL)
- {
- sock_addr = (struct sockaddr *) (msg + 1);
- if (sock_addr->sa_family != sa_family)
- goto next;
-
- route_info = route_info_append (route_info);
- if (list == NULL)
- list = route_info;
- route_info_init (route_info, resolve_names);
-
- if_indextoname (msg->rtm_index, route_info->oif_name);
- bsd_flags (msg->rtm_flags, route_info->flag_str,
- sizeof (route_info->flag_str));
-
- if ((msg->rtm_addrs & RTA_DST) != 0)
- {
-#ifdef __KAME__
- /* Remove embedded scope id-field added by KAME implementation. */
- if(sa_family == AF_INET6)
- {
- struct in6_addr *addr_6
- = &(((struct sockaddr_in6 *) sock_addr)->sin6_addr);
-
- if((IN6_IS_ADDR_LINKLOCAL (addr_6)
- || IN6_IS_ADDR_MC_LINKLOCAL (addr_6))
- && ((struct sockaddr_in6 *) sock_addr)->sin6_scope_id == 0)
- {
- addr_6->s6_addr[2] = 0;
- addr_6->s6_addr[3] = 0;
- }
- }
-#endif /* __KAME__ */
- route_info->dest_present = 1;
- bsd_conv_addr_to_name (sock_addr, route_info->dest,
- sizeof (route_info->dest), resolve_names);
- }
-
- sock_addr = (struct sockaddr *) ((char *) sock_addr
- + SA_SIZE(sock_addr));
-
- if ((msg->rtm_addrs & RTA_GATEWAY) != 0)
- {
-#ifdef __KAME__
- /* Remove embedded scope id-field added by KAME implementation. */
- if(sa_family == AF_INET6)
- {
- struct in6_addr *addr_6
- = &(((struct sockaddr_in6 *) sock_addr)->sin6_addr);
-
- if((IN6_IS_ADDR_LINKLOCAL (addr_6)
- || IN6_IS_ADDR_MC_LINKLOCAL(addr_6))
- && ((struct sockaddr_in6 *)sock_addr)->sin6_scope_id == 0)
- {
- addr_6->s6_addr[2] = 0;
- addr_6->s6_addr[3] = 0;
- }
- }
-#endif /* __KAME__ */
- route_info->gateway_present = 1;
- bsd_conv_addr_to_name (sock_addr, route_info->gateway,
- sizeof (route_info->gateway), resolve_names);
- }
-
- sock_addr = (struct sockaddr *) ((char *) sock_addr
- + SA_SIZE(sock_addr));
- if ((msg->rtm_addrs & RTA_NETMASK) != 0)
- {
- char buffer[sizeof (struct sockaddr_in6)];
- unsigned char* s_addr;
- socklen_t s_len;
-
- memset (buffer, 0, sizeof (struct sockaddr_in6));
- strncpy (buffer, (char *) sock_addr, sock_addr->sa_len);
- ((struct sockaddr *) buffer)->sa_family = sa_family;
-
- s_addr = &(sock_addr->sa_data[2]);
- s_len = sock_addr->sa_len;
- route_info->dest_len = 0;
-
- if (s_len != 0)
- {
- /* Figure out the length of address in the sockaddr structure,
- * by subtracting the offset portion of the address (in
- * sockaddr structure) from the length of sockaddr structure.
- * NOTE: the length will be dynamic as this is a netmask
- * represented in a sockaddr.
- */
- s_len -= (sa_family == AF_INET) ?
- (socklen_t) ((char *) (&((struct sockaddr_in *)
- sock_addr)->sin_addr) - (char *) sock_addr):
- (socklen_t) ((char *) (&((struct sockaddr_in6 *)
- sock_addr)->sin6_addr) - (char *) sock_addr);
- }
-
- bsd_conv_addr_to_name ((struct sockaddr *) buffer,
- route_info->dest_mask,
- sizeof(route_info->dest_mask), 0);
-
- while (s_len != 0)
- {
- while ((*s_addr & 0x80) != 0)
- {
- route_info->dest_len++;
- *s_addr <<= 1;
- }
- s_addr++;
- s_len--;
- }
- }
-
- next:
- msg = rt_msg_next (msg, &nread);
- }
-
- return list;
-}
-
-size_t
-bsd_sysctl (void ** buffer, size_t *const size)
-{
- int mib[6];
- int status;
- size_t length;
-
- mib[0] = CTL_NET;
- mib[1] = PF_ROUTE;
- mib[2] = 0;
- mib[3] = 0;
- mib[4] = NET_RT_DUMP;
- mib[5] = 0;
-
- status = sysctl (mib, 6, NULL, &length, NULL, 0);
- if (status == -1 || length == 0)
- error (EXIT_FAILURE, errno, "sysctl");
-
- *buffer = xmalloc (length);
- *size = length;
-
- status = sysctl (mib, 6, *buffer, &length, NULL, 0);
- if (status == -1)
- error (EXIT_FAILURE, errno, "sysctl");
-
- return length;
-}
-
-struct rt_msghdr *
-rt_msg_next (const struct rt_msghdr *rtm, size_t *const length)
-{
- struct rt_msghdr * next
- = (struct rt_msghdr *) ((char *) rtm + rtm->rtm_msglen);
-
- *length -= rtm->rtm_msglen;
- if (*length <= 0)
- return NULL;
- else if (*length < next->rtm_msglen)
- return NULL;
-
- return next;
-}
diff --git a/libroute/route_bsd.c b/libroute/route_bsd.c
index 86b9da9..c660d81 100644
--- a/libroute/route_bsd.c
+++ b/libroute/route_bsd.c
@@ -17,8 +17,37 @@
to the Free Software Foundation, Inc., 51 Franklin Street,
Fifth Floor, Boston, MA 02110-1301 USA. */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
#include "route.h"
#include "route_bsd.h"
+#include "xalloc.h"
const route_backend_t bsd_backend =
{
@@ -30,3 +59,458 @@ const route_backend_t bsd_backend =
bsd_add,
bsd_show
};
+
+#define RT_HDR_BUFFER_SIZE 512
+
+/** TODO: find a better way to track sequence no.s */
+int seq_rtm = 0;
+
+typedef struct pf_route_message {
+ struct sockaddr* addr[RTAX_MAX];
+} pf_route_message_t;
+
+typedef struct flag
+{
+ int mask;
+ char * str;
+} flag_t;
+
+/* empty sockaddr */
+const struct sockaddr sa_empty = {
+ sizeof(struct sockaddr),
+};
+
+static void bsd_rt_msg_send(int msg_type,
+ int msg_iface,
+ int msg_seq,
+ int msg_flags,
+ pf_route_message_t* message);
+static void bsd_conv_addr_to_name (const struct sockaddr *const sock,
+ char *const buffer, const size_t buffer_size,
+ const short int resolve_names);
+static void bsd_flags (const int field, char *const buffer, size_t size);
+static const route_info_t * bsd_parse_msg (const sa_family_t sa_family,
+ const struct rt_msghdr *msg, size_t nread,
+ const short int resolve_names);
+static size_t bsd_sysctl (void ** buffer, size_t *const size);
+static struct rt_msghdr * bsd_rt_msg_next (const struct rt_msghdr *rtm,
+ size_t *const length);
+
+void
+bsd_add (const int address_family,
+ const void *const dest_addr,
+ const size_t dest_addr_size,
+ const unsigned char dest_addr_len,
+ const void *const gw_addr,
+ const size_t gw_addr_size,
+ const unsigned int iface)
+{
+ pf_route_message_t msg;
+ struct ifaddrs* ifas;
+ int i;
+ int flags = RTF_STATIC;
+
+ memset(&msg, 0, sizeof(pf_route_message_t));
+
+ if(iface)
+ if(getifaddrs(&ifas) == -1)
+ return;
+
+ if(address_family == AF_INET)
+ {
+ char* p;
+ int len = dest_addr_len;
+
+ msg.addr[RTAX_NETMASK] = (struct sockaddr*)xcalloc(1, sizeof(struct sockaddr_in));
+ ((struct sockaddr_in*)msg.addr[RTAX_NETMASK])->sin_family = AF_INET;
+ ((struct sockaddr_in*)msg.addr[RTAX_NETMASK])->sin_len = sizeof(struct sockaddr_in);
+ p = (char*)&((struct sockaddr_in*)msg.addr[RTAX_NETMASK])->sin_addr;
+
+ for(i = 1; i <= len; i++)
+ {
+ *p >>= 1;
+ *p |= 0x80;
+
+ if(!(i & 7))
+ p++;
+ }
+
+ if(dest_addr)
+ {
+ msg.addr[RTAX_DST] = (struct sockaddr*)xcalloc(1, sizeof(struct sockaddr_in));
+ ((struct sockaddr_in*)msg.addr[RTAX_DST])->sin_family = AF_INET;
+ ((struct sockaddr_in*)msg.addr[RTAX_DST])->sin_len = sizeof(struct sockaddr_in);
+ memcpy(&((struct sockaddr_in*)msg.addr[RTAX_DST])->sin_addr, dest_addr, dest_addr_size);
+ }
+
+ if(gw_addr)
+ {
+ msg.addr[RTAX_GATEWAY] = (struct sockaddr*)xcalloc(1, sizeof(struct sockaddr_in));
+ ((struct sockaddr_in*)msg.addr[RTAX_GATEWAY])->sin_family = AF_INET;
+ ((struct sockaddr_in*)msg.addr[RTAX_GATEWAY])->sin_len = sizeof(struct sockaddr_in);
+ memcpy(&((struct sockaddr_in*)msg.addr[RTAX_GATEWAY])->sin_addr, gw_addr, gw_addr_size);
+ flags |= RTF_GATEWAY;
+ }
+ }
+ else if(address_family == AF_INET6)
+ {
+ char* p;
+ int len = dest_addr_len;
+
+ msg.addr[RTAX_NETMASK] = (struct sockaddr*)xcalloc(1, sizeof(struct sockaddr_in6));
+ ((struct sockaddr_in6*)msg.addr[RTAX_NETMASK])->sin6_family = AF_INET6;
+ ((struct sockaddr_in6*)msg.addr[RTAX_NETMASK])->sin6_len = sizeof(struct sockaddr_in6);
+ p = (char*)&((struct sockaddr_in6*)msg.addr[RTAX_NETMASK])->sin6_addr;
+
+ for(i = 1; i <= len; i++)
+ {
+ *p >>= 1;
+ *p |= 0x80;
+
+ if(!(i & 7))
+ p++;
+ }
+
+ if(dest_addr)
+ {
+ msg.addr[RTAX_DST] = (struct sockaddr*)xcalloc(1, sizeof(struct sockaddr_in6));
+ ((struct sockaddr_in6*)msg.addr[RTAX_DST])->sin6_family = AF_INET6;
+ ((struct sockaddr_in6*)msg.addr[RTAX_DST])->sin6_len = sizeof(struct sockaddr_in6);
+ memcpy(&((struct sockaddr_in6*)msg.addr[RTAX_DST])->sin6_addr, dest_addr, dest_addr_size);
+ }
+
+ if(gw_addr)
+ {
+ msg.addr[RTAX_GATEWAY] = (struct sockaddr*)xcalloc(1, sizeof(struct sockaddr_in6));
+ ((struct sockaddr_in6*)msg.addr[RTAX_GATEWAY])->sin6_family = AF_INET6;
+ ((struct sockaddr_in6*)msg.addr[RTAX_GATEWAY])->sin6_len = sizeof(struct sockaddr_in6);
+ memcpy(&((struct sockaddr_in6*)msg.addr[RTAX_GATEWAY])->sin6_addr, gw_addr, gw_addr_size);
+ flags |= RTF_GATEWAY;
+ }
+ }
+
+ if(iface)
+ {
+ struct ifaddrs* ifa = ifas;
+ while(ifa)
+ {
+ if(((struct sockaddr_dl*)ifa->ifa_addr)->sdl_index == iface)
+ {
+ msg.addr[RTAX_GATEWAY] = xmalloc(SA_SIZE(ifa->ifa_addr));
+ memcpy(msg.addr[RTAX_GATEWAY], ifa->ifa_addr, SA_SIZE(ifa->ifa_addr));
+ break;
+ }
+ ifa = ifa->ifa_next;
+ }
+ flags &= ~RTF_GATEWAY;
+ }
+
+ bsd_rt_msg_send(RTM_ADD, iface, 0, flags, &msg);
+
+ for(i = 0; i < RTAX_MAX; i++)
+ if(msg.addr[i])
+ {
+ free(msg.addr[i]);
+ msg.addr[i] = NULL;
+ }
+
+ if(iface)
+ freeifaddrs(ifas);
+
+ return;
+}
+
+static void
+bsd_rt_msg_send(int msg_type, int msg_iface, int msg_seq,
+ int msg_flags, pf_route_message_t* message)
+{
+ char* buffer;
+ struct rt_msghdr* rtm;
+ struct sockaddr* addr;
+ int i;
+ int len = sizeof(struct rt_msghdr);
+ int fd;
+
+ buffer = xcalloc(1, RT_HDR_BUFFER_SIZE);
+ rtm = (struct rt_msghdr*)buffer;
+
+ rtm->rtm_version = RTM_VERSION;
+ rtm->rtm_type = msg_type;
+ rtm->rtm_index = msg_iface;
+ rtm->rtm_pid = getpid();
+ rtm->rtm_seq = msg_seq;
+ rtm->rtm_flags = msg_flags;
+
+ addr = (struct sockaddr*)(rtm+1);
+
+ for(i = 0; i < RTAX_MAX; i++)
+ {
+ if(message->addr[i])
+ {
+ memcpy(addr, message->addr[i], SA_SIZE(message->addr[i]));
+ rtm->rtm_addrs |= (1 << i);
+ }
+ else
+ memcpy(addr, &sa_empty, SA_SIZE(&sa_empty));
+ len += SA_SIZE(addr);
+ addr = (struct sockaddr*)(((char*)addr) + SA_SIZE(addr));
+ }
+
+ rtm->rtm_msglen = len;
+
+ if((fd = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
+ return;
+
+ if(write(fd, rtm, rtm->rtm_msglen) == -1)
+ return;
+
+ close(fd);
+ free(rtm);
+}
+
+static void
+bsd_conv_addr_to_name (const struct sockaddr *const sock,
+ char *const buffer, const size_t buffer_size,
+ const short int resolve_names)
+{
+ if (sock->sa_family == AF_LINK)
+ conv_link_addr_to_name (sock, sock->sa_len, buffer, buffer_size,
+ resolve_names);
+ else if (sock->sa_family == AF_INET || sock->sa_family == AF_INET6)
+ {
+ void *addr;
+ size_t addr_size;
+
+ if (sock->sa_family == AF_INET)
+ {
+ addr = &(((struct sockaddr_in *) sock)->sin_addr);
+ addr_size = sizeof (struct in_addr);
+ }
+ else /* AF_INET */
+ {
+ addr = &(((struct sockaddr_in6 *) sock)->sin6_addr);
+ addr_size = sizeof (struct in6_addr);
+ }
+
+ conv_inet_addr_to_name (sock->sa_family, addr, addr_size,
+ buffer, buffer_size, resolve_names);
+ }
+ else
+ printf ("%u\n", sock->sa_family);
+}
+
+static void
+bsd_flags (const int field, char *const buffer, size_t size)
+{
+ const flag_t flags[] = {
+ {RTF_UP, "U"},
+ {RTF_GATEWAY, "G"},
+ {RTF_HOST, "H"},
+ {RTF_REJECT, "R"},
+ {RTF_DYNAMIC, "D"},
+ {RTF_LLINFO, "L"},
+ {RTF_STATIC, "S"},
+ {RTF_WASCLONED, "W"},
+ };
+ int i;
+
+ memset ((void*) buffer, 0, size);
+ for (i = 0; i < sizeof (flags) / sizeof (flags[0]); i++)
+ {
+ if ((field & flags[i].mask) != 0)
+ {
+ strncat (buffer, flags[i].str, size - 1);
+ size -= strlen (flags[i].str);
+ }
+ }
+}
+
+const route_info_t *
+bsd_show (const sa_family_t sa_family, const short int resolve_names)
+{
+ const route_info_t *list;
+ size_t nread;
+ size_t size;
+ struct rt_msghdr *msg;
+
+ nread = bsd_sysctl ((void **) &msg, &size);
+ list = bsd_parse_msg (sa_family, msg, nread, resolve_names);
+ free (msg);
+ return list;
+}
+
+static const route_info_t *
+bsd_parse_msg (const sa_family_t sa_family,
+ const struct rt_msghdr *msg, size_t nread,
+ const short int resolve_names)
+{
+ const route_info_t *list = NULL;
+ route_info_t *route_info = NULL;
+ const struct sockaddr *sock_addr;
+
+ while (msg != NULL)
+ {
+ sock_addr = (struct sockaddr *) (msg + 1);
+ if (sock_addr->sa_family != sa_family)
+ goto next;
+
+ route_info = route_info_append (route_info);
+ if (list == NULL)
+ list = route_info;
+ route_info_init (route_info, resolve_names);
+
+ if_indextoname (msg->rtm_index, route_info->oif_name);
+ bsd_flags (msg->rtm_flags, route_info->flag_str,
+ sizeof (route_info->flag_str));
+
+ if ((msg->rtm_addrs & RTA_DST) != 0)
+ {
+#ifdef __KAME__
+ /* Remove embedded scope id-field added by KAME implementation. */
+ if(sa_family == AF_INET6)
+ {
+ struct in6_addr *addr_6
+ = &(((struct sockaddr_in6 *) sock_addr)->sin6_addr);
+
+ if((IN6_IS_ADDR_LINKLOCAL (addr_6)
+ || IN6_IS_ADDR_MC_LINKLOCAL (addr_6))
+ && ((struct sockaddr_in6 *) sock_addr)->sin6_scope_id == 0)
+ {
+ addr_6->s6_addr[2] = 0;
+ addr_6->s6_addr[3] = 0;
+ }
+ }
+#endif /* __KAME__ */
+ route_info->dest_present = 1;
+ bsd_conv_addr_to_name (sock_addr, route_info->dest,
+ sizeof (route_info->dest), resolve_names);
+ }
+
+ sock_addr = (struct sockaddr *) ((char *) sock_addr
+ + SA_SIZE(sock_addr));
+
+ if ((msg->rtm_addrs & RTA_GATEWAY) != 0)
+ {
+#ifdef __KAME__
+ /* Remove embedded scope id-field added by KAME implementation. */
+ if(sa_family == AF_INET6)
+ {
+ struct in6_addr *addr_6
+ = &(((struct sockaddr_in6 *) sock_addr)->sin6_addr);
+
+ if((IN6_IS_ADDR_LINKLOCAL (addr_6)
+ || IN6_IS_ADDR_MC_LINKLOCAL(addr_6))
+ && ((struct sockaddr_in6 *)sock_addr)->sin6_scope_id == 0)
+ {
+ addr_6->s6_addr[2] = 0;
+ addr_6->s6_addr[3] = 0;
+ }
+ }
+#endif /* __KAME__ */
+ route_info->gateway_present = 1;
+ bsd_conv_addr_to_name (sock_addr, route_info->gateway,
+ sizeof (route_info->gateway), resolve_names);
+ }
+
+ sock_addr = (struct sockaddr *) ((char *) sock_addr
+ + SA_SIZE(sock_addr));
+ if ((msg->rtm_addrs & RTA_NETMASK) != 0)
+ {
+ char buffer[sizeof(struct sockaddr_in6)];
+ unsigned char* s_addr;
+ socklen_t s_len;
+
+ memset (buffer, 0, sizeof(struct sockaddr_in6));
+ strncpy (buffer, (char *) sock_addr, sock_addr->sa_len);
+ ((struct sockaddr *) buffer)->sa_family = sa_family;
+
+ s_addr = ((sa_family == AF_INET) ?
+ (unsigned char*)&((struct sockaddr_in*)sock_addr)->sin_addr:
+ (unsigned char*)&((struct sockaddr_in6*)sock_addr)->sin6_addr);
+
+ s_len = sock_addr->sa_len;
+ route_info->dest_len = 0;
+
+ if(s_len)
+ {
+ /* Figure out the length of address in the sockaddr structure, by subtracting
+ * the offset portion of the address (in sockaddr structure) from the length
+ * of sockaddr structure.
+ * NOTE: the length will be dynamic as this is a netmask represented in a sockaddr.
+ */
+ s_len -= (socklen_t)((char*)s_addr - (char*)sock_addr);
+ }
+
+ bsd_conv_addr_to_name ((struct sockaddr *) buffer,
+ route_info->dest_mask,
+ sizeof(route_info->dest_mask), 0);
+
+ while(s_len--)
+ {
+ while(*s_addr & 0x80)
+ {
+ route_info->dest_len++;
+ *s_addr <<= 1;
+ }
+ s_addr++;
+ }
+ }
+
+ next:
+ msg = bsd_rt_msg_next (msg, &nread);
+ }
+
+ return list;
+}
+
+static size_t
+bsd_sysctl (void ** buffer, size_t *const size)
+{
+ int mib[6];
+ int status;
+ size_t length;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_DUMP;
+ mib[5] = 0;
+
+ status = sysctl (mib, 6, NULL, &length, NULL, 0);
+ if (status == -1 || length == 0)
+ error (EXIT_FAILURE, errno, "sysctl");
+
+ *buffer = xmalloc (length);
+ *size = length;
+
+ status = sysctl (mib, 6, *buffer, &length, NULL, 0);
+ if (status == -1)
+ error (EXIT_FAILURE, errno, "sysctl");
+
+ return length;
+}
+
+static struct rt_msghdr *
+bsd_rt_msg_next (const struct rt_msghdr *rtm, size_t *const length)
+{
+ struct rt_msghdr * next
+ = (struct rt_msghdr *) ((char *) rtm + rtm->rtm_msglen);
+
+ *length -= rtm->rtm_msglen;
+ if (*length <= 0)
+ return NULL;
+ else if (*length < next->rtm_msglen)
+ return NULL;
+
+ return next;
+}
+
+void
+bsd_delete (const int format,
+ const void *const dest_addr,
+ const size_t dest_addr_size,
+ const unsigned char dest_len)
+{
+ /* TODO */
+}
diff --git a/libroute/route_bsd.h b/libroute/route_bsd.h
index 6ef1a45..8a38f79 100644
--- a/libroute/route_bsd.h
+++ b/libroute/route_bsd.h
@@ -24,8 +24,7 @@
#include "route.h"
-extern void bsd_add (const int format,
- const uint16_t flags,
+extern void bsd_add (const int address_family,
const void *const dest_addr,
const size_t dest_addr_size,
const unsigned char dest_addr_len,
--
1.6.0.2