summaryrefslogtreecommitdiffstats
path: root/libdnet-stripped/src/route-win32.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdnet-stripped/src/route-win32.c')
-rw-r--r--libdnet-stripped/src/route-win32.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/libdnet-stripped/src/route-win32.c b/libdnet-stripped/src/route-win32.c
new file mode 100644
index 0000000..8a9d2bc
--- /dev/null
+++ b/libdnet-stripped/src/route-win32.c
@@ -0,0 +1,279 @@
+/*
+ * route-win32.c
+ *
+ * Copyright (c) 2002 Dug Song <dugsong@monkey.org>
+ *
+ * $Id: route-win32.c 589 2005-02-15 07:11:32Z dugsong $
+ */
+
+#ifdef _WIN32
+#include "dnet_winconfig.h"
+#else
+#include "config.h"
+#endif
+
+#include <ws2tcpip.h>
+#include <iphlpapi.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dnet.h"
+
+typedef DWORD (WINAPI *GETIPFORWARDTABLE2)(ADDRESS_FAMILY, PMIB_IPFORWARD_TABLE2 *);
+
+struct route_handle {
+ HINSTANCE iphlpapi;
+ MIB_IPFORWARDTABLE *ipftable;
+ MIB_IPFORWARD_TABLE2 *ipftable2;
+};
+
+route_t *
+route_open(void)
+{
+ route_t *r;
+
+ r = calloc(1, sizeof(route_t));
+ if (r == NULL)
+ return NULL;
+ r->iphlpapi = GetModuleHandle("iphlpapi.dll");
+
+ return r;
+}
+
+int
+route_add(route_t *route, const struct route_entry *entry)
+{
+ MIB_IPFORWARDROW ipfrow;
+ struct addr net;
+
+ memset(&ipfrow, 0, sizeof(ipfrow));
+
+ if (GetBestInterface(entry->route_gw.addr_ip,
+ &ipfrow.dwForwardIfIndex) != NO_ERROR)
+ return (-1);
+
+ if (addr_net(&entry->route_dst, &net) < 0 ||
+ net.addr_type != ADDR_TYPE_IP)
+ return (-1);
+
+ ipfrow.dwForwardDest = net.addr_ip;
+ addr_btom(entry->route_dst.addr_bits,
+ &ipfrow.dwForwardMask, IP_ADDR_LEN);
+ ipfrow.dwForwardNextHop = entry->route_gw.addr_ip;
+ ipfrow.dwForwardType = 4; /* XXX - next hop != final dest */
+ ipfrow.dwForwardProto = 3; /* XXX - MIB_PROTO_NETMGMT */
+
+ if (CreateIpForwardEntry(&ipfrow) != NO_ERROR)
+ return (-1);
+
+ return (0);
+}
+
+int
+route_delete(route_t *route, const struct route_entry *entry)
+{
+ MIB_IPFORWARDROW ipfrow;
+ DWORD mask;
+
+ if (entry->route_dst.addr_type != ADDR_TYPE_IP ||
+ GetBestRoute(entry->route_dst.addr_ip,
+ IP_ADDR_ANY, &ipfrow) != NO_ERROR)
+ return (-1);
+
+ addr_btom(entry->route_dst.addr_bits, &mask, IP_ADDR_LEN);
+
+ if (ipfrow.dwForwardDest != entry->route_dst.addr_ip ||
+ ipfrow.dwForwardMask != mask) {
+ errno = ENXIO;
+ SetLastError(ERROR_NO_DATA);
+ return (-1);
+ }
+ if (DeleteIpForwardEntry(&ipfrow) != NO_ERROR)
+ return (-1);
+
+ return (0);
+}
+
+int
+route_get(route_t *route, struct route_entry *entry)
+{
+ MIB_IPFORWARDROW ipfrow;
+ DWORD mask;
+ intf_t *intf;
+ struct intf_entry intf_entry;
+
+ if (entry->route_dst.addr_type != ADDR_TYPE_IP ||
+ GetBestRoute(entry->route_dst.addr_ip,
+ IP_ADDR_ANY, &ipfrow) != NO_ERROR)
+ return (-1);
+
+ if (ipfrow.dwForwardProto == 2 && /* XXX - MIB_IPPROTO_LOCAL */
+ (ipfrow.dwForwardNextHop|IP_CLASSA_NET) !=
+ (IP_ADDR_LOOPBACK|IP_CLASSA_NET) &&
+ !IP_LOCAL_GROUP(ipfrow.dwForwardNextHop)) {
+ errno = ENXIO;
+ SetLastError(ERROR_NO_DATA);
+ return (-1);
+ }
+ addr_btom(entry->route_dst.addr_bits, &mask, IP_ADDR_LEN);
+
+ entry->route_gw.addr_type = ADDR_TYPE_IP;
+ entry->route_gw.addr_bits = IP_ADDR_BITS;
+ entry->route_gw.addr_ip = ipfrow.dwForwardNextHop;
+ entry->metric = ipfrow.dwForwardMetric1;
+
+ entry->intf_name[0] = '\0';
+ intf = intf_open();
+ if (intf_get_index(intf, &intf_entry,
+ AF_INET, ipfrow.dwForwardIfIndex) == 0) {
+ strlcpy(entry->intf_name, intf_entry.intf_name, sizeof(entry->intf_name));
+ }
+ intf_close(intf);
+
+ return (0);
+}
+
+static int
+route_loop_getipforwardtable(route_t *r, route_handler callback, void *arg)
+{
+ struct route_entry entry;
+ intf_t *intf;
+ ULONG len;
+ int i, ret;
+
+ for (len = sizeof(r->ipftable[0]); ; ) {
+ if (r->ipftable)
+ free(r->ipftable);
+ r->ipftable = malloc(len);
+ if (r->ipftable == NULL)
+ return (-1);
+ ret = GetIpForwardTable(r->ipftable, &len, FALSE);
+ if (ret == NO_ERROR)
+ break;
+ else if (ret != ERROR_INSUFFICIENT_BUFFER)
+ return (-1);
+ }
+
+ intf = intf_open();
+
+ ret = 0;
+ for (i = 0; i < (int)r->ipftable->dwNumEntries; i++) {
+ struct intf_entry intf_entry;
+
+ entry.route_dst.addr_type = ADDR_TYPE_IP;
+ entry.route_dst.addr_bits = IP_ADDR_BITS;
+
+ entry.route_gw.addr_type = ADDR_TYPE_IP;
+ entry.route_gw.addr_bits = IP_ADDR_BITS;
+
+ entry.route_dst.addr_ip = r->ipftable->table[i].dwForwardDest;
+ addr_mtob(&r->ipftable->table[i].dwForwardMask, IP_ADDR_LEN,
+ &entry.route_dst.addr_bits);
+ entry.route_gw.addr_ip =
+ r->ipftable->table[i].dwForwardNextHop;
+ entry.metric = r->ipftable->table[i].dwForwardMetric1;
+
+ /* Look up the interface name. */
+ entry.intf_name[0] = '\0';
+ intf_entry.intf_len = sizeof(intf_entry);
+ if (intf_get_index(intf, &intf_entry,
+ AF_INET, r->ipftable->table[i].dwForwardIfIndex) == 0) {
+ strlcpy(entry.intf_name, intf_entry.intf_name, sizeof(entry.intf_name));
+ }
+
+ if ((ret = (*callback)(&entry, arg)) != 0)
+ break;
+ }
+
+ intf_close(intf);
+
+ return ret;
+}
+
+static int
+route_loop_getipforwardtable2(GETIPFORWARDTABLE2 GetIpForwardTable2,
+ route_t *r, route_handler callback, void *arg)
+{
+ struct route_entry entry;
+ intf_t *intf;
+ ULONG i;
+ int ret;
+
+ ret = GetIpForwardTable2(AF_UNSPEC, &r->ipftable2);
+ if (ret != NO_ERROR)
+ return (-1);
+
+ intf = intf_open();
+
+ ret = 0;
+ for (i = 0; i < r->ipftable2->NumEntries; i++) {
+ struct intf_entry intf_entry;
+ MIB_IPFORWARD_ROW2 *row;
+ MIB_IPINTERFACE_ROW ifrow;
+ ULONG metric;
+
+ row = &r->ipftable2->Table[i];
+ addr_ston((struct sockaddr *) &row->DestinationPrefix.Prefix, &entry.route_dst);
+ entry.route_dst.addr_bits = row->DestinationPrefix.PrefixLength;
+ addr_ston((struct sockaddr *) &row->NextHop, &entry.route_gw);
+
+ /* Look up the interface name. */
+ entry.intf_name[0] = '\0';
+ intf_entry.intf_len = sizeof(intf_entry);
+ if (intf_get_index(intf, &intf_entry,
+ row->DestinationPrefix.Prefix.si_family,
+ row->InterfaceIndex) == 0) {
+ strlcpy(entry.intf_name, intf_entry.intf_name, sizeof(entry.intf_name));
+ }
+
+ ifrow.Family = row->DestinationPrefix.Prefix.si_family;
+ ifrow.InterfaceLuid = row->InterfaceLuid;
+ ifrow.InterfaceIndex = row->InterfaceIndex;
+ if (GetIpInterfaceEntry(&ifrow) != NO_ERROR) {
+ return (-1);
+ }
+ metric = ifrow.Metric + row->Metric;
+ if (metric < INT_MAX)
+ entry.metric = metric;
+ else
+ entry.metric = INT_MAX;
+
+ if ((ret = (*callback)(&entry, arg)) != 0)
+ break;
+ }
+
+ intf_close(intf);
+
+ return ret;
+}
+
+int
+route_loop(route_t *r, route_handler callback, void *arg)
+{
+ GETIPFORWARDTABLE2 GetIpForwardTable2;
+
+ /* GetIpForwardTable2 is only available on Vista and later, dynamic load. */
+ GetIpForwardTable2 = NULL;
+ if (r->iphlpapi != NULL)
+ GetIpForwardTable2 = (GETIPFORWARDTABLE2) GetProcAddress(r->iphlpapi, "GetIpForwardTable2");
+
+ if (GetIpForwardTable2 == NULL)
+ return route_loop_getipforwardtable(r, callback, arg);
+ else
+ return route_loop_getipforwardtable2(GetIpForwardTable2, r, callback, arg);
+}
+
+route_t *
+route_close(route_t *r)
+{
+ if (r != NULL) {
+ if (r->ipftable != NULL)
+ free(r->ipftable);
+ if (r->ipftable2 != NULL)
+ FreeMibTable(r->ipftable2);
+ free(r);
+ }
+ return (NULL);
+}