Commit 4f0e3348 authored by Jondy Zhao's avatar Jondy Zhao

Use other interface instead loopback interface in the blackhole route entry.

parent 0f224483
......@@ -68,4 +68,23 @@ Notes
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters",
but says nothing for Ipv6. Does it work for ipv6 in the registry:
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters"
?
\ No newline at end of file
?
8. There is no RTM_BLACKHOLE, RTM_REJECT, NULLROUTE in the windows, in
the kernel_cygwin.c!kernel_route, we only use local address as
gateway in the BLACKHOLE route entry. Is it OK?
A: It's not OK actually. In the Windows, you can't use 127.0.0.1 as
gateway when add route entry. So the solution is find one
interface other than loopback interface, then use its
uni-address as gateway, it will be a blackhole route entry. For
example, if you have an interface which ip addr is
192.168.128.100, and ifindex is 5, then
$ route add 100.28.0.0 mask 255.255.0.0 192.168.128.100 if 5
Destination network 100.28.0.0/16 will be unreachable.
9. IN6_LINKLOCAL_IFINDEX && SET_IN6_LINKLOCAL_IFINDEX, do both of them
work in the Windows?
\ No newline at end of file
......@@ -229,6 +229,15 @@ libwinet_refresh_interface_map_table()
return (NO_ERROR == dwRet);
}
/* Map ifindex belong to family to index of another family,
Ipv4 -> Ipv6 or
Ipv6 -> Ipv4
Return 0, if the interface only binds one ip version.
Special case:
If the interface is loopback, it will always return 1.
*/
static int
libwinet_map_ifindex(int family, int ifindex)
{
......@@ -239,7 +248,8 @@ libwinet_map_ifindex(int family, int ifindex)
DWORD dwReturn = 0;
dwRet = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST \
GAA_FLAG_SKIP_UNICAST \
| GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER \
| GAA_FLAG_SKIP_FRIENDLY_NAME,
......@@ -252,7 +262,8 @@ libwinet_map_ifindex(int family, int ifindex)
if (NULL == (pAdaptAddr = (IP_ADAPTER_ADDRESSES*)MALLOC(dwSize)))
return 0;
dwRet = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST \
GAA_FLAG_SKIP_UNICAST \
| GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER \
| GAA_FLAG_SKIP_FRIENDLY_NAME,
......@@ -268,7 +279,8 @@ libwinet_map_ifindex(int family, int ifindex)
while (pTmpAdaptAddr) {
if (family == AF_INET ? pTmpAdaptAddr -> IfIndex == ifindex
: pTmpAdaptAddr -> Ipv6IfIndex == ifindex) {
dwReturn = family == AF_INET ?
dwReturn = (pTmpAdaptAddr -> IfType == IF_TYPE_SOFTWARE_LOOPBACK) ?
1 : (family == AF_INET) ?
pTmpAdaptAddr -> Ipv6IfIndex : pTmpAdaptAddr -> IfIndex;
break;
}
......@@ -750,6 +762,76 @@ int cyginet_stop_monitor_route_changes()
return rc;
}
/* Find an interface which binds both of ipv4 and ipv6, and configured
with at least one unicast address.
Return ipv6 ifindex of this interface, set addr6 and addr as the
ipv4 and ipv6 address respectively.
Return 0 if there is no matched interface found.
*/
int
cyginet_blackhole_index(struct in6_addr* addr6, char * addr)
{
IP_ADAPTER_ADDRESSES *pAdaptAddr = NULL;
IP_ADAPTER_ADDRESSES *pTmpAdaptAddr = NULL;
DWORD dwRet = 0;
DWORD dwSize = 0x10000;
DWORD dwReturn = 0;
dwRet = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER \
| GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
pAdaptAddr,
&dwSize
);
if (ERROR_BUFFER_OVERFLOW == dwRet) {
FREE(pAdaptAddr);
if (NULL == (pAdaptAddr = (IP_ADAPTER_ADDRESSES*)MALLOC(dwSize)))
return 0;
dwRet = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER \
| GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
pAdaptAddr,
&dwSize
);
}
if (NO_ERROR == dwRet) {
pTmpAdaptAddr = pAdaptAddr;
while (pTmpAdaptAddr) {
if (pTmpAdaptAddr -> IfIndex
&& pTmpAdaptAddr -> Ipv6IfIndex
&& (pTmpAdaptAddr -> OperStatus == IfOperStatusUp)
&& (pTmpAdaptAddr -> IfType != IF_TYPE_SOFTWARE_LOOPBACK)) {
PIP_ADAPTER_UNICAST_ADDRESS p = pTmpAdaptAddr -> FirstUnicastAddress;
while (p) {
SOCKADDR *s;
s = (p -> Address).lpSockaddr;
if (s -> sa_family == AF_INET)
memcpy(addr, &(((struct sockaddr_in *)s) -> sin_addr), 4);
else if (s -> sa_family == AF_INET6)
memcpy(addr6, &(((struct sockaddr_in6 *)s) -> sin6_addr), 16);
p = p -> Next;
}
dwReturn = pTmpAdaptAddr -> Ipv6IfIndex;
break;
}
pTmpAdaptAddr = pTmpAdaptAddr->Next;
}
FREE(pAdaptAddr);
}
return dwReturn;
}
/*
* There are 3 ways to change a route:
*
......@@ -759,6 +841,16 @@ int cyginet_stop_monitor_route_changes()
* DeleteIpForwardEntry
* SetIpForwardEntry
*
* Or route command
*
* Or netsh routing add persistentroute
*
* Or netsh routing add rtmroute
*
* it need "Routing and Remote Access Service" running on the local
* machine. Use 'net start remoteaccess' on the local machine to
* start the service.
*
* 2. IPv6 route: command "netsh"
*
* C:/> netsh interface ipv6 add route
......@@ -2366,6 +2458,15 @@ runTestCases()
}
}
printf("\n\nTest cyginet_blackhole_index:\n\n");
{
struct in6_addr addr6;
char addr[4];
printf("The blackhole ifindex is %d\n",
cyginet_blackhole_index(&addr6, addr)
);
}
#if _WIN32_WINNT < _WIN32_WINNT_VISTA
printf("\n\nTest libwinet_dump_ipv6_route_table:\n\n");
......
......@@ -176,4 +176,6 @@ char * cyginet_ifname(const char *);
char * cyginet_guidname(const char *);
char * cyginet_ipv4_index2ifname(int);
int cyginet_blackhole_index(struct in6_addr*, char *);
#endif /* __CYGIFNET_H__ */
......@@ -69,6 +69,12 @@ static int get_sdl(struct sockaddr_dl *sdl, char *guidname);
static const unsigned char v4prefix[16] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
static int ifindex_blackhole = -1;
static struct in6_addr blackhole_addr6 = {{IN6ADDR_LOOPBACK_INIT}};
static char blackhole_addr[1][1][16] =
{{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x01 }}};
int export_table = -1, import_table = -1;
int
......@@ -355,11 +361,6 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
int route_ifindex;
int prefix_len;
struct in6_addr local6 = {{IN6ADDR_LOOPBACK_INIT}};
char local4[1][1][16] =
{{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x01 }}};
/* Check that the protocol family is consistent. */
if(plen >= 96 && v4mapped(dest)) {
if(!v4mapped(gate)) {
......@@ -413,11 +414,14 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
if(metric == KERNEL_INFINITY) {
/* RTF_BLACKHOLE; */
/* ==> Set gateway to an unused ip address in the Windows */
if (ifindex_lo < 0) {
ifindex_lo = cyginet_loopback_index(AF_UNSPEC);
if(ifindex_lo <= 0)
if (ifindex_blackhole < 0) {
ifindex_blackhole = cyginet_blackhole_index(&blackhole_addr6,
blackhole_addr[0][0]+12
);
if(ifindex_blackhole <= 0)
return -1;
}
route_ifindex = ifindex_blackhole;
}
#define PUSHADDR(dst, src) \
......@@ -438,20 +442,20 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
PUSHADDR(destination, dest);
if (metric == KERNEL_INFINITY)
PUSHADDR(gateway, **local4);
PUSHADDR(gateway, **blackhole_addr);
else
PUSHADDR(gateway, gate);
} else {
PUSHADDR6(destination, dest);
if (metric == KERNEL_INFINITY)
PUSHADDR6(gateway, &local6);
PUSHADDR6(gateway, &blackhole_addr6);
else
PUSHADDR6(gateway, gate);
}
#undef PUSHADDR
#undef PUSHADDR6
/* What if route_ifindex == 0 */
switch(operation) {
case ROUTE_FLUSH:
rc = cyginet_delete_route_entry(&destination,
......@@ -484,8 +488,8 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
/* Monitor thread will write data to kernel pipe when any change
in the route table is happened. Here it's babeld itself to
change the route table, so kernel pipe need to be clean. */
int ch;
while (read(kernel_pipe_handles[0], &ch, 1) > 0);
/* int ch; */
/* while (read(kernel_pipe_handles[0], &ch, 1) > 0); */
return rc;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment