From 0d47952611198ef6b1163f366dc03922d20b1475 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 09:42:04 +0200 Subject: Adding upstream version 7.94+git20230807.3be01efb1+dfsg. Signed-off-by: Daniel Baumann --- libdnet-stripped/src/route-win32.c | 279 +++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 libdnet-stripped/src/route-win32.c (limited to 'libdnet-stripped/src/route-win32.c') 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 + * + * $Id: route-win32.c 589 2005-02-15 07:11:32Z dugsong $ + */ + +#ifdef _WIN32 +#include "dnet_winconfig.h" +#else +#include "config.h" +#endif + +#include +#include + +#include +#include +#include + +#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); +} -- cgit v1.2.3