Commit 582eb114 authored by Jondy Zhao's avatar Jondy Zhao

Use API other than route command to add route entry for ipv4;

Refine the code;
List issues in the README.cygwin;
parent 055ff708
...@@ -64,7 +64,7 @@ clean: ...@@ -64,7 +64,7 @@ clean:
kernel.o: kernel_netlink.c kernel_socket.c kernel_cygwin.c kernel.o: kernel_netlink.c kernel_socket.c kernel_cygwin.c
# Usage: ./testc.exe # Usage: ./test.exe
# Verify most of the functions in the cyginet.c # Verify most of the functions in the cyginet.c
testc.exe: cyginet.c test.exe: cyginet.c
$(CC) $(CFLAGS) $(LDFLAGS) -DTEST_CYGINET -o $@ $< $(LDLIBS) $(CC) $(CFLAGS) $(LDFLAGS) -DTEST_CYGINET -o $@ $< $(LDLIBS)
...@@ -46,7 +46,97 @@ Control Panel -> Network Connections. ...@@ -46,7 +46,97 @@ Control Panel -> Network Connections.
You should see all the connections like "Local Area Connection You should see all the connections like "Local Area Connection
3". Right click and rename this to something shorter and without 3". Right click and rename this to something shorter and without
embedded spaces such as "my-tap". embedded spaces such as "tap1".
Or
$ netsh interface set interface name = "Local Area Connection 3" newname="tap1"
Test babeld in the Cygwin
=========================
We need 2 laptops, a wireless router, one laptop connects the router
by wireless netcard, another is wired.
Both of laptops install Openvpn for cygwin, enable ipv6 forwarding on
each tap interface
Laptop A:
lan Disconnect
wlan 192.168.121.100/24
2001::A1 (manual)
tap ifindex = 11, ipv6 forwarding=enabled
10.100.0.1/24
fe80::2ff:38ff:fed8:7d97 (auto link addr)
Laptop B:
lan 192.168.121.21/24
2001::B1 (manual)
tap ifindex = 7, ipv6 forwarding=enabled
10.200.0.1/24
fe80::2ff:17ff:fee4:8ed0 (auto link addr)
Router R:
192.168.121.1/24
In the laptop A, run the following command:
# Start openvpn server
$ cd C:/Program Files/OpenVPN/server
$ ../bin/openvpn.exe --config server.ovpn
# Startup babeld
$ babeld.exe -d 3 -h 15 -H 15 -s wlan tap
# Assign ipv6 unicast address to interfaces
# netsh interface ipv6 add address wlan 2001:A1
# netsh interface ipv6 set interface tap forwarding=enabled
In the laptop B, run the following command:
# Start openvpn client
$ cd C:/Program Files/OpenVPN/client
$ ../bin/openvpn.exe --config client.ovpn
# Startup babeld
$ babeld.exe -d 3 -h 15 -H 15 -s lan tap1
# Assign ipv6 unicast address to interfaces
# netsh interface ipv6 add address lan 2001:B1
# netsh interface ipv6 set interface tap forwarding=enabled
Then ping6 to each other ,
In laptop A,
$ ping6 2001::B1
In laptop B,
$ ping6 2001::A1
It should work.
Check kernel route:
$ netsh interface ipv6 show route
Example output of A
Publish Type Met Prefix Idx Gateway/Interface Name
------- -------- ---- ------------------------ --- ---------------------
no Manual 0 ::/0 11 fe80::2ff:17ff:fee4:8ed0
Example output of B
Publish Type Met Prefix Idx Gateway/Interface Name
------- -------- ---- ------------------------ --- ---------------------
no Manual 0 ::/0 7 fe80::2ff:38ff:fed8:7d97
Notes Notes
===== =====
...@@ -66,22 +156,31 @@ Notes ...@@ -66,22 +156,31 @@ Notes
5. Ipv6 option "IPV6_V6ONLY" only works in the Windows Vista later. 5. Ipv6 option "IPV6_V6ONLY" only works in the Windows Vista later.
6. If one connection is assigned more than one ipv4 address, babeld 6. If one connection is assigned more than one ipv4 address, babeld
returns the first one only, is it right? I'm not sure. returns the first one only to check whether ipv4 address changed,
is it right? I'm not sure.
7. Regarding IPV6CTL_FORWARDING and IPV6CTL_SENDREDIRECTS, MSDN says 7. Regarding IPV6CTL_FORWARDING and IPV6CTL_SENDREDIRECTS, MSDN says
that you can set both of options for Ipv4 in the registry: that you can set both of options in the registry:
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters", 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
"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters"
? IPEnableRouter, DWORD
EnableICMPRedirect, DWORD
Refers to:
http://support.microsoft.com/kb/315236/en-us
http://technet.microsoft.com/en-us/library/cc766102(v=ws.10).aspx
http://msdn.microsoft.com/en-us/library/aa915651.aspx
For Ipv6, FORWARDING is set per interface, not global setting.
8. There is no RTM_BLACKHOLE, RTM_REJECT, NULLROUTE in the windows, in 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 the kernel_cygwin.c!kernel_route, we only use local address as
gateway in the BLACKHOLE route entry. Is it OK? 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 A: It's not OK actually for ipv4. In the Windows, you can't use
gateway when add route entry. So the solution is find one 127.0.0.1 as gateway when add route entry. So the solution is
interface other than loopback interface, then use its find one interface other than loopback interface, then use its
uni-address as gateway, it will be a blackhole route entry. For uni-address as gateway, it will be a blackhole route entry. For
example, if you have an interface which ip addr is example, if you have an interface which ip addr is
192.168.128.100, and ifindex is 5, then 192.168.128.100, and ifindex is 5, then
...@@ -92,3 +191,8 @@ Notes ...@@ -92,3 +191,8 @@ Notes
9. IN6_LINKLOCAL_IFINDEX && SET_IN6_LINKLOCAL_IFINDEX, do both of them 9. IN6_LINKLOCAL_IFINDEX && SET_IN6_LINKLOCAL_IFINDEX, do both of them
work in the Windows? work in the Windows?
A: We can ignore both of them. In the windows, it use the following
format to specify interface index in the link local address:
fe80::2ff:38ff:fed8:7d97%11
/*
* Some issues:
*
* 1. libwinet_dump_ipv6_route_table
*
* Before Windows Vista, we have to use command "netsh" to get ipv6
* route table. But the output misses the value of route protocol.
*
* 2. libwinet_edit_route_entry
*
* What should be the value of protocol? MIB_IPPROTO_NETMGMT or
* RTPROT_BABEL_LOCAL
*
*/
/* The Win32 select only worked on socket handles. The Cygwin /* The Win32 select only worked on socket handles. The Cygwin
* implementation allows select to function normally when given * implementation allows select to function normally when given
* different types of file descriptors (sockets, pipes, handles, * different types of file descriptors (sockets, pipes, handles,
...@@ -58,7 +43,7 @@ void do_debugf(int level, const char *format, ...); ...@@ -58,7 +43,7 @@ void do_debugf(int level, const char *format, ...);
static HRESULT (WINAPI *ws_guidfromstring)(LPCTSTR psz, LPGUID pguid) = NULL; static HRESULT (WINAPI *ws_guidfromstring)(LPCTSTR psz, LPGUID pguid) = NULL;
static HANDLE event_notify_monitor_thread = WSA_INVALID_EVENT; static HANDLE event_notify_monitor_thread = WSA_INVALID_EVENT;
static PLIBWINET_INTERFACE_MAP_TABLE interface_map_table = NULL; static PLIBWINET_INTERFACE_MAP_TABLE g_interface_map_table = NULL;
static int libwinet_run_command(const char *); static int libwinet_run_command(const char *);
static void static void
...@@ -111,39 +96,64 @@ mask2len(const unsigned char *p, const int size) ...@@ -111,39 +96,64 @@ mask2len(const unsigned char *p, const int size)
} }
static int static int
libwinet_ipv6_interfaces_forwards(int forward) libwinet_set_registry_key(char *key, char * name, int value, int defvalue)
{ {
const int MAX_BUFFER_SIZE = 255; HKEY hKey;
char cmdbuf[MAX_BUFFER_SIZE]; unsigned long type;
int result; unsigned long size;
unsigned long old;
struct if_nameindex * p; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WRITE, &hKey) !=
struct if_nameindex * ptr; ERROR_SUCCESS)
if (NULL == (ptr = (struct if_nameindex *)if_nameindex()))
return -1; return -1;
p = ptr; size = sizeof(old);
while (p -> if_index) {
if (snprintf(cmdbuf, if (RegQueryValueEx(hKey, name, NULL, &type, (unsigned char *)&old, &size) !=
MAX_BUFFER_SIZE, ERROR_SUCCESS || type != REG_DWORD)
"netsh interface ipv6 set interface %d forwarding=%s", old = defvalue;
p -> if_index,
forward ? "enabled" : "disabled" if (RegSetValueEx(hKey,
) >= MAX_BUFFER_SIZE) name,
break; 0,
if (libwinet_run_command(cmdbuf) != 0) REG_DWORD,
break; (unsigned char *)&value,
p ++; sizeof(value)
)) {
RegCloseKey(hKey);
return -1;
} }
result = ! (p -> if_index);
if_freenameindex(ptr); RegCloseKey(hKey);
return result; return old;
}
/* return True if success */
static int
libwinet_get_registry_key(char *key, char * name, long * value)
{
HKEY hKey;
int rc;
unsigned long type;
unsigned long size;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hKey) !=
ERROR_SUCCESS)
return -1;
size = sizeof(*value);
rc = (RegQueryValueEx(hKey, name, NULL, &type, (unsigned char *)value, &size) ==
ERROR_SUCCESS && type == REG_DWORD);
RegCloseKey(hKey);
return rc;
} }
static void static void
libwinet_free_interface_map_table() libwinet_free_interface_map_table()
{ {
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table; PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
PLIBWINET_INTERFACE_MAP_TABLE s; PLIBWINET_INTERFACE_MAP_TABLE s;
while (p) { while (p) {
if ( p -> AdapterName ) if ( p -> AdapterName )
...@@ -154,7 +164,22 @@ libwinet_free_interface_map_table() ...@@ -154,7 +164,22 @@ libwinet_free_interface_map_table()
p = p -> next; p = p -> next;
FREE(s); FREE(s);
} }
interface_map_table = NULL; g_interface_map_table = NULL;
}
static int
get_interface_forwards(char * guid)
{
long value = 0;
/* Location in the Windows XP, not sure in Vista or Windows 7 */
char * key = "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters"
"\\Interfaces\\%s";
char * name = "Forwards";
char buf[256] = {0};
if (snprintf(buf, 255, key, guid) > 0)
if (libwinet_get_registry_key(buf, name, &value))
return value;
return -1;
} }
static int static int
...@@ -191,13 +216,13 @@ libwinet_refresh_interface_map_table() ...@@ -191,13 +216,13 @@ libwinet_refresh_interface_map_table()
if (NO_ERROR == dwRet) { if (NO_ERROR == dwRet) {
if (interface_map_table) if (g_interface_map_table)
libwinet_free_interface_map_table(); libwinet_free_interface_map_table();
PLIBWINET_INTERFACE_MAP_TABLE p; PLIBWINET_INTERFACE_MAP_TABLE p;
size_t len; size_t len;
interface_map_table = NULL; g_interface_map_table = NULL;
pTmpAdaptAddr = pAdaptAddr; pTmpAdaptAddr = pAdaptAddr;
while (pTmpAdaptAddr) { while (pTmpAdaptAddr) {
...@@ -206,8 +231,10 @@ libwinet_refresh_interface_map_table() ...@@ -206,8 +231,10 @@ libwinet_refresh_interface_map_table()
dwRet = ERROR_BUFFER_OVERFLOW; dwRet = ERROR_BUFFER_OVERFLOW;
break; break;
} }
p -> next = interface_map_table; p -> next = g_interface_map_table;
p -> IfIndex = pTmpAdaptAddr -> IfIndex;
p -> Ipv6IfIndex = pTmpAdaptAddr -> Ipv6IfIndex;
p -> RouteFlags = get_interface_forwards(pTmpAdaptAddr -> AdapterName);
len = WideCharToMultiByte(CP_ACP, len = WideCharToMultiByte(CP_ACP,
0, 0,
pTmpAdaptAddr -> FriendlyName, pTmpAdaptAddr -> FriendlyName,
...@@ -250,9 +277,8 @@ libwinet_refresh_interface_map_table() ...@@ -250,9 +277,8 @@ libwinet_refresh_interface_map_table()
pTmpAdaptAddr -> PhysicalAddress, pTmpAdaptAddr -> PhysicalAddress,
p -> PhysicalAddressLength p -> PhysicalAddressLength
); );
pTmpAdaptAddr = pTmpAdaptAddr->Next; pTmpAdaptAddr = pTmpAdaptAddr->Next;
interface_map_table = p; g_interface_map_table = p;
} }
if (ERROR_BUFFER_OVERFLOW == dwRet) if (ERROR_BUFFER_OVERFLOW == dwRet)
...@@ -271,61 +297,31 @@ libwinet_refresh_interface_map_table() ...@@ -271,61 +297,31 @@ libwinet_refresh_interface_map_table()
Special case: Special case:
If the interface is loopback, it will always return 1. If the interface is loopback, it will always return 1.
Notice the parameter family specify the familay of input ifindex,
not output family. Actually,
family == AF_INET, it will map ipv4 to ipv6,
family == AF_INET6, it will map ipv6 to ipv4,
*/ */
static int static int
libwinet_map_ifindex(int family, int ifindex) libwinet_map_ifindex(int family, int ifindex)
{ {
IP_ADAPTER_ADDRESSES *pAdaptAddr = NULL; /* Loopback Interface */
IP_ADAPTER_ADDRESSES *pTmpAdaptAddr = NULL; if (ifindex == 1)
DWORD dwRet = 0; return 1;
DWORD dwSize = 0x10000; if (g_interface_map_table == NULL)
DWORD dwReturn = 0; if (!libwinet_refresh_interface_map_table())
return -1;
dwRet = GetAdaptersAddresses(AF_UNSPEC, PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
GAA_FLAG_SKIP_UNICAST \ while (p) {
| GAA_FLAG_SKIP_ANYCAST \ if (family == AF_INET && ifindex == p -> IfIndex && p -> Ipv6IfIndex)
| GAA_FLAG_SKIP_MULTICAST \ return p -> Ipv6IfIndex;
| GAA_FLAG_SKIP_DNS_SERVER \ else if (family == AF_INET6 && ifindex == p -> Ipv6IfIndex && p -> IfIndex)
| GAA_FLAG_SKIP_FRIENDLY_NAME, return p -> IfIndex;
NULL, p = p -> next;
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_UNICAST \
| 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 (family == AF_INET ? pTmpAdaptAddr -> IfIndex == ifindex
: pTmpAdaptAddr -> Ipv6IfIndex == ifindex) {
dwReturn = (pTmpAdaptAddr -> IfType == IF_TYPE_SOFTWARE_LOOPBACK) ?
1 : (family == AF_INET) ?
pTmpAdaptAddr -> Ipv6IfIndex : pTmpAdaptAddr -> IfIndex;
break;
}
pTmpAdaptAddr = pTmpAdaptAddr->Next;
}
FREE(pAdaptAddr);
} }
return 0;
return dwReturn;
} }
static int static int
...@@ -526,7 +522,7 @@ libwinet_dump_ipv6_route_table(struct cyginet_route *routes, ...@@ -526,7 +522,7 @@ libwinet_dump_ipv6_route_table(struct cyginet_route *routes,
if (ignored) if (ignored)
ignored = 0; ignored = 0;
else if (!ignored) { else if (!ignored) {
route.proto = MIB_IPPROTO_OTHER; /* ?? */ route.proto = MIB_IPPROTO_NETMGMT; /* ?? */
if ((maxroutes > count) && (proute != NULL)) { if ((maxroutes > count) && (proute != NULL)) {
memcpy(proute, &route, sizeof(struct cyginet_route)); memcpy(proute, &route, sizeof(struct cyginet_route));
proute ++; proute ++;
...@@ -816,8 +812,7 @@ cyginet_blackhole_index(struct in6_addr* addr6, char * addr) ...@@ -816,8 +812,7 @@ cyginet_blackhole_index(struct in6_addr* addr6, char * addr)
dwRet = GetAdaptersAddresses(AF_UNSPEC, dwRet = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST \ GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \ | GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER \ | GAA_FLAG_SKIP_DNS_SERVER,
| GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL, NULL,
pAdaptAddr, pAdaptAddr,
&dwSize &dwSize
...@@ -829,8 +824,7 @@ cyginet_blackhole_index(struct in6_addr* addr6, char * addr) ...@@ -829,8 +824,7 @@ cyginet_blackhole_index(struct in6_addr* addr6, char * addr)
dwRet = GetAdaptersAddresses(AF_UNSPEC, dwRet = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST \ GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \ | GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER \ | GAA_FLAG_SKIP_DNS_SERVER,
| GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL, NULL,
pAdaptAddr, pAdaptAddr,
&dwSize &dwSize
...@@ -843,16 +837,21 @@ cyginet_blackhole_index(struct in6_addr* addr6, char * addr) ...@@ -843,16 +837,21 @@ cyginet_blackhole_index(struct in6_addr* addr6, char * addr)
if (pTmpAdaptAddr -> IfIndex if (pTmpAdaptAddr -> IfIndex
&& pTmpAdaptAddr -> Ipv6IfIndex && pTmpAdaptAddr -> Ipv6IfIndex
&& (pTmpAdaptAddr -> OperStatus == IfOperStatusUp) && (pTmpAdaptAddr -> OperStatus == IfOperStatusUp)
&& (pTmpAdaptAddr -> IfType != IF_TYPE_SOFTWARE_LOOPBACK)) { && (pTmpAdaptAddr -> IfType != IF_TYPE_SOFTWARE_LOOPBACK)
&& !wcscmp(pTmpAdaptAddr -> FriendlyName, L"blackhole")) {
PIP_ADAPTER_UNICAST_ADDRESS p = pTmpAdaptAddr -> FirstUnicastAddress; PIP_ADAPTER_UNICAST_ADDRESS p = pTmpAdaptAddr -> FirstUnicastAddress;
while (p) { while (p) {
SOCKADDR *s; SOCKADDR *s;
s = (p -> Address).lpSockaddr; s = (p -> Address).lpSockaddr;
if (s -> sa_family == AF_INET) if (s -> sa_family == AF_INET) {
if (addr)
memcpy(addr, &(((struct sockaddr_in *)s) -> sin_addr), 4); memcpy(addr, &(((struct sockaddr_in *)s) -> sin_addr), 4);
else if (s -> sa_family == AF_INET6) }
else if (s -> sa_family == AF_INET6) {
if (addr6)
memcpy(addr6, &(((struct sockaddr_in6 *)s) -> sin6_addr), 16); memcpy(addr6, &(((struct sockaddr_in6 *)s) -> sin6_addr), 16);
}
p = p -> Next; p = p -> Next;
} }
dwReturn = pTmpAdaptAddr -> Ipv6IfIndex; dwReturn = pTmpAdaptAddr -> Ipv6IfIndex;
...@@ -918,7 +917,7 @@ libwinet_edit_route_entry(const struct sockaddr *dest, ...@@ -918,7 +917,7 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
const int MAX_BUFFER_SIZE = 1024; const int MAX_BUFFER_SIZE = 1024;
const char * cmdformat = "netsh interface ipv6 %s route " const char * cmdformat = "netsh interface ipv6 %s route "
"prefix=%s/%d interface=%d " "prefix=%s/%d interface=%d "
"%s%s %s%d"; "nexthop=%s %cmetric=%d";
char cmdbuf[MAX_BUFFER_SIZE]; char cmdbuf[MAX_BUFFER_SIZE];
char sdest[INET6_ADDRSTRLEN]; char sdest[INET6_ADDRSTRLEN];
char sgate[INET6_ADDRSTRLEN]; char sgate[INET6_ADDRSTRLEN];
...@@ -935,7 +934,8 @@ libwinet_edit_route_entry(const struct sockaddr *dest, ...@@ -935,7 +934,8 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
INET6_ADDRSTRLEN INET6_ADDRSTRLEN
)) ))
return -1; return -1;
/* metric clause results delete route command failed, so we add
'#' to commet this clause when delete route. */
if (snprintf(cmdbuf, if (snprintf(cmdbuf,
MAX_BUFFER_SIZE, MAX_BUFFER_SIZE,
cmdformat, cmdformat,
...@@ -944,9 +944,8 @@ libwinet_edit_route_entry(const struct sockaddr *dest, ...@@ -944,9 +944,8 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
sdest, sdest,
plen, plen,
ifindex, ifindex,
strcmp(sgate, "::") == 0 ? "" : "nexthop=", sgate,
strcmp(sgate, "::") == 0 ? "" : sgate, cmdflag == RTM_DELETE ? '#' : ' ',
cmdflag == RTM_DELETE ? "#" : "metric=",
metric metric
) >= MAX_BUFFER_SIZE) ) >= MAX_BUFFER_SIZE)
return -1; return -1;
...@@ -956,23 +955,29 @@ libwinet_edit_route_entry(const struct sockaddr *dest, ...@@ -956,23 +955,29 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
} }
/* Add ipv4 route before Windows Vista */ /* Add ipv4 route before Windows Vista, use IP Helper API */
else if (0) { else {
MIB_IPFORWARDROW Row; MIB_IPFORWARDROW Row;
unsigned long Res; unsigned long Res;
struct in_addr mask;
plen2mask(plen, &mask);
memset(&Row, 0, sizeof(MIB_IPFORWARDROW)); memset(&Row, 0, sizeof(MIB_IPFORWARDROW));
Row.dwForwardDest = (((SOCKADDR_IN*)dest) -> sin_addr).S_un.S_addr; Row.dwForwardDest = (((SOCKADDR_IN*)dest) -> sin_addr).S_un.S_addr;
Row.dwForwardPolicy = 0; Row.dwForwardPolicy = 0;
Row.dwForwardNextHop = (((SOCKADDR_IN*)gate) -> sin_addr).S_un.S_addr; Row.dwForwardNextHop = (((SOCKADDR_IN*)gate) -> sin_addr).S_un.S_addr;
Row.dwForwardIfIndex = libwinet_map_ifindex(AF_INET6, ifindex); Row.dwForwardIfIndex = libwinet_map_ifindex(AF_INET6, ifindex);
Row.dwForwardMask = mask.S_un.S_addr;
/* /*
* MIB_IPROUTE_TYPE_DIRECT <==> dwForwardNextHop == dwForwardDest * MIB_IPROUTE_TYPE_DIRECT <==> dwForwardNextHop == dwForwardDest
* MIB_IPROUTE_TYPE_LOCAL <==> dwForwardNextHop == Ip of the interface * MIB_IPROUTE_TYPE_LOCAL <==> dwForwardNextHop in local interfaces
* MIB_IPROUTE_TYPE_INDIRECT all the others * MIB_IPROUTE_TYPE_INDIRECT all the others
*/ */
Row.dwForwardType = Row.dwForwardNextHop == Row.dwForwardDest ? \ Row.dwForwardType = Row.dwForwardNextHop == Row.dwForwardDest ? \
MIB_IPROUTE_TYPE_DIRECT : MIB_IPROUTE_TYPE_INDIRECT; MIB_IPROUTE_TYPE_DIRECT : MIB_IPROUTE_TYPE_INDIRECT;
Row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
Row.dwForwardProto = MIB_IPPROTO_NETMGMT; Row.dwForwardProto = MIB_IPPROTO_NETMGMT;
Row.dwForwardAge = 0; Row.dwForwardAge = 0;
Row.dwForwardNextHopAS = 0; Row.dwForwardNextHopAS = 0;
...@@ -999,7 +1004,7 @@ libwinet_edit_route_entry(const struct sockaddr *dest, ...@@ -999,7 +1004,7 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
return -1; return -1;
} }
/* Use route command */ #if 0 /* Use route command */
else { else {
/* route ADD dest MASK mask gate METRIC n IF index */ /* route ADD dest MASK mask gate METRIC n IF index */
/* route CHANGE dest MASK mask gate METRIC n IF index */ /* route CHANGE dest MASK mask gate METRIC n IF index */
...@@ -1048,6 +1053,7 @@ libwinet_edit_route_entry(const struct sockaddr *dest, ...@@ -1048,6 +1053,7 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
if (libwinet_run_command(cmdbuf) != 0) if (libwinet_run_command(cmdbuf) != 0)
return -1; return -1;
} }
#endif /* if 0 */
#else #else
/* Add route entry after Windows Vista */ /* Add route entry after Windows Vista */
...@@ -1098,76 +1104,119 @@ libwinet_edit_route_entry(const struct sockaddr *dest, ...@@ -1098,76 +1104,119 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
return 1; return 1;
} }
static int int
libwinet_set_registry_key(char *key, char * name, int value, int defvalue) cyginet_set_interface_forwards(const char * ifname, int value)
{ {
HKEY hKey; /* For ipv4 */
unsigned long type; /* netsh routing add interface ifname enabled/disabled */
unsigned long size; char cmdbuf[255];
unsigned long old; if (snprintf(cmdbuf,
255,
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WRITE, &hKey) != "netsh interface ipv6 set interface \"%s\" "
ERROR_SUCCESS) "forwarding=%s > /dev/null",
ifname,
value ? "enabled" : "disabled"
) > 0)
return system(cmdbuf);
return -1; return -1;
}
size = sizeof(old); int
cyginet_set_icmp6_redirect_accept(int value)
if (RegQueryValueEx(hKey, name, NULL, &type, (unsigned char *)&old, &size) != {
ERROR_SUCCESS || type != REG_DWORD) char * key = "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters";
old = defvalue; char * name = "EnableICMPRedirect";
return libwinet_set_registry_key(key,
if (RegSetValueEx(hKey,
name, name,
0, value,
REG_DWORD, 1
(unsigned char *)&value, );
sizeof(value) }
)) {
RegCloseKey(hKey);
return -1;
}
RegCloseKey(hKey); static void
return old; libwinet_restore_ipv6_interface()
{
char cmdbuf[255];
int rc=0;
PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) {
if (p -> RouteFlags != -1)
if (snprintf(cmdbuf,
255,
"netsh interface ipv6 set interface \"%s\" "
"forwarding=%s > /dev/null",
p -> FriendlyName,
p -> RouteFlags ? "enabled" : "disabled"
) > 0)
rc = system(cmdbuf);
p = p -> next;
}
} }
#if 0
int int
cyginet_set_ipv6_forwards(int value) cyginet_set_ipv6_forwards(int value)
{ {
char * key = "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters"; char * key = "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters";
/* char * name = "IPEnableRouter";
int rc;
rc = libwinet_ipv6_interfaces_forwards(value);
if (rc == -1)
return -1;
if (value) {
if (ERROR_IO_PENDING != EnableRouter(NULL, NULL))
return -1;
}
else {
if (NO_ERROR != UnenableRouter(NULL, NULL))
return -1;
}
*/
return libwinet_set_registry_key(key, return libwinet_set_registry_key(key,
"IPEnableRouter", name,
value, value,
0 0
); );
} }
int static int
cyginet_set_icmp6_redirect_accept(int value) libwinet_ipv6_interfaces_forwards(int forward)
{ {
char * key = "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters"; const int MAX_BUFFER_SIZE = 255;
char cmdbuf[MAX_BUFFER_SIZE];
int result;
return libwinet_set_registry_key(key, struct if_nameindex * p;
"EnableICMPRedirect", struct if_nameindex * ptr;
value, if (NULL == (ptr = (struct if_nameindex *)if_nameindex()))
1 return -1;
);
p = ptr;
while (p -> if_index) {
if (snprintf(cmdbuf,
MAX_BUFFER_SIZE,
"netsh interface ipv6 set interface %d forwarding=%s",
p -> if_index,
forward ? "enabled" : "disabled"
) >= MAX_BUFFER_SIZE)
break;
if (libwinet_run_command(cmdbuf) != 0)
break;
p ++;
}
result = ! (p -> if_index);
if_freenameindex(ptr);
return result;
} }
static void
libwinet_init_ipv6_interface()
{
char cmdbuf[255];
int rc=0;
PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) {
if (snprintf(cmdbuf,
255,
"netsh interface ipv6 set interface \"%s\" " \
"forwarding=enabled advertise=enabled > /dev/null",
p -> FriendlyName
) > 0) {
rc = system(cmdbuf);
}
p = p -> next;
}
}
#endif /* if 0 */
/* /*
* On Windows Vista and later, wireless network cards are reported as * On Windows Vista and later, wireless network cards are reported as
* IF_TYPE_IEEE80211 by the GetAdaptersAddresses function. * IF_TYPE_IEEE80211 by the GetAdaptersAddresses function.
...@@ -1411,58 +1460,6 @@ cyginet_loopback_index(int family) ...@@ -1411,58 +1460,6 @@ cyginet_loopback_index(int family)
return 1; return 1;
} }
char *
cyginet_ipv4_index2ifname(int ifindex)
{
IP_ADAPTER_ADDRESSES *pAdaptAddr = NULL;
IP_ADAPTER_ADDRESSES *pTmpAdaptAddr = NULL;
DWORD dwRet = 0;
DWORD dwSize = 0x10000;
DWORD dwFamily = AF_INET;
char * ifname = NULL;
dwRet = GetAdaptersAddresses(dwFamily,
GAA_FLAG_SKIP_UNICAST \
| GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER,
NULL,
pAdaptAddr,
&dwSize
);
if (ERROR_BUFFER_OVERFLOW == dwRet) {
FREE(pAdaptAddr);
if (NULL == (pAdaptAddr = (IP_ADAPTER_ADDRESSES*)MALLOC(dwSize)))
return NULL;
dwRet = GetAdaptersAddresses(dwFamily,
GAA_FLAG_SKIP_UNICAST \
| GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER,
NULL,
pAdaptAddr,
&dwSize
);
}
if (NO_ERROR == dwRet) {
pTmpAdaptAddr = pAdaptAddr;
while (pTmpAdaptAddr) {
if (pTmpAdaptAddr -> IfIndex == ifindex) {
ifname = cyginet_ifname(pTmpAdaptAddr -> AdapterName);
break;
}
pTmpAdaptAddr = pTmpAdaptAddr->Next;
}
FREE(pAdaptAddr);
}
return ifname;
}
/* /*
* There are 3 ways to dump route table in the Windows: * There are 3 ways to dump route table in the Windows:
* *
...@@ -1632,12 +1629,17 @@ cyginet_read_route_socket(void *buffer, size_t size) ...@@ -1632,12 +1629,17 @@ cyginet_read_route_socket(void *buffer, size_t size)
return 0; return 0;
} }
int
cyginet_refresh_interface_table()
{
return libwinet_refresh_interface_map_table();
}
int int
cyginet_startup() cyginet_startup()
{ {
WORD wVersionRequested; WORD wVersionRequested;
WSADATA wsaData; WSADATA wsaData;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */ /* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2); wVersionRequested = MAKEWORD(2, 2);
return WSAStartup(wVersionRequested, &wsaData); return WSAStartup(wVersionRequested, &wsaData);
...@@ -1646,6 +1648,8 @@ cyginet_startup() ...@@ -1646,6 +1648,8 @@ cyginet_startup()
void void
cyginet_cleanup() cyginet_cleanup()
{ {
libwinet_restore_ipv6_interface();
libwinet_free_interface_map_table();
WSACleanup(); WSACleanup();
} }
...@@ -1653,10 +1657,10 @@ char * ...@@ -1653,10 +1657,10 @@ char *
cyginet_guidname(const char * ifname) cyginet_guidname(const char * ifname)
{ {
PLIBWINET_INTERFACE_MAP_TABLE p; PLIBWINET_INTERFACE_MAP_TABLE p;
if (!interface_map_table) if (!g_interface_map_table)
libwinet_refresh_interface_map_table(); libwinet_refresh_interface_map_table();
p = interface_map_table; p = g_interface_map_table;
while (p) { while (p) {
if (strcmp(ifname, p -> FriendlyName) == 0) if (strcmp(ifname, p -> FriendlyName) == 0)
return p -> AdapterName; return p -> AdapterName;
...@@ -1669,10 +1673,10 @@ char * ...@@ -1669,10 +1673,10 @@ char *
cyginet_ifname(const char * guidname) cyginet_ifname(const char * guidname)
{ {
PLIBWINET_INTERFACE_MAP_TABLE p; PLIBWINET_INTERFACE_MAP_TABLE p;
if (!interface_map_table) if (!g_interface_map_table)
libwinet_refresh_interface_map_table(); libwinet_refresh_interface_map_table();
p = interface_map_table; p = g_interface_map_table;
while (p) { while (p) {
if (strcmp(guidname, p -> AdapterName) == 0) if (strcmp(guidname, p -> AdapterName) == 0)
return p -> FriendlyName; return p -> FriendlyName;
...@@ -1681,9 +1685,89 @@ cyginet_ifname(const char * guidname) ...@@ -1681,9 +1685,89 @@ cyginet_ifname(const char * guidname)
return NULL; return NULL;
} }
int
cyginet_add_ipentry(int ifindex, struct sockaddr *addr)
{
MIB_IPNETROW row;
PLIBWINET_INTERFACE_MAP_TABLE p;
if (!g_interface_map_table)
libwinet_refresh_interface_map_table();
p = g_interface_map_table;
while (p) {
if (p -> IfIndex == ifindex) {
row.dwPhysAddrLen = p -> PhysicalAddressLength;
if (row.dwPhysAddrLen > MAXLEN_PHYSADDR)
return -1;
memcpy(row.bPhysAddr, p -> PhysicalAddress, row.dwPhysAddrLen);
break;
}
p = p -> next;
}
if (row.dwPhysAddrLen) {
row.dwIndex = ifindex;
row.dwAddr = (((SOCKADDR_IN*)addr) -> sin_addr).S_un.S_addr;
row.dwType = MIB_IPNET_TYPE_DYNAMIC;
return CreateIpNetEntry ( &row );
}
return -1;
}
/* The following functions are reserved. */ /* The following functions are reserved. */
#if 0 #if 0
char *
cyginet_ipv4_index2ifname(int ifindex)
{
IP_ADAPTER_ADDRESSES *pAdaptAddr = NULL;
IP_ADAPTER_ADDRESSES *pTmpAdaptAddr = NULL;
DWORD dwRet = 0;
DWORD dwSize = 0x10000;
DWORD dwFamily = AF_INET;
char * ifname = NULL;
dwRet = GetAdaptersAddresses(dwFamily,
GAA_FLAG_SKIP_UNICAST \
| GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER,
NULL,
pAdaptAddr,
&dwSize
);
if (ERROR_BUFFER_OVERFLOW == dwRet) {
FREE(pAdaptAddr);
if (NULL == (pAdaptAddr = (IP_ADAPTER_ADDRESSES*)MALLOC(dwSize)))
return NULL;
dwRet = GetAdaptersAddresses(dwFamily,
GAA_FLAG_SKIP_UNICAST \
| GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER,
NULL,
pAdaptAddr,
&dwSize
);
}
if (NO_ERROR == dwRet) {
pTmpAdaptAddr = pAdaptAddr;
while (pTmpAdaptAddr) {
if (pTmpAdaptAddr -> IfIndex == ifindex) {
ifname = cyginet_ifname(pTmpAdaptAddr -> AdapterName);
break;
}
pTmpAdaptAddr = pTmpAdaptAddr->Next;
}
FREE(pAdaptAddr);
}
return ifname;
}
static int static int
libwinet_get_loopback_index(int family) libwinet_get_loopback_index(int family)
{ {
...@@ -2498,7 +2582,7 @@ runTestCases() ...@@ -2498,7 +2582,7 @@ runTestCases()
if_freenameindex(ptr); if_freenameindex(ptr);
} }
} }
/*
printf("\n\nTest cyginet_ipv4_index2ifname:\n\n"); printf("\n\nTest cyginet_ipv4_index2ifname:\n\n");
{ {
int ifindex = 1; int ifindex = 1;
...@@ -2507,10 +2591,10 @@ runTestCases() ...@@ -2507,10 +2591,10 @@ runTestCases()
cyginet_ipv4_index2ifname(ifindex) cyginet_ipv4_index2ifname(ifindex)
); );
} }
*/
printf("\n\nTest cyginet_guidname works in the Cygwin:\n\n"); printf("\n\nTest cyginet_guidname works in the Cygwin:\n\n");
{ {
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table; PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) { while (p) {
printf("%s:\t\t%s\n", printf("%s:\t\t%s\n",
p -> FriendlyName, p -> FriendlyName,
...@@ -2546,7 +2630,7 @@ runTestCases() ...@@ -2546,7 +2630,7 @@ runTestCases()
printf("\n\nTest libwinet_is_wireless_interface:\n\n"); printf("\n\nTest libwinet_is_wireless_interface:\n\n");
{ {
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table; PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) { while (p) {
printf("%s is wireless netcard: %d\n", printf("%s is wireless netcard: %d\n",
p -> FriendlyName, p -> FriendlyName,
...@@ -2585,6 +2669,7 @@ runTestCases() ...@@ -2585,6 +2669,7 @@ runTestCases()
} }
} }
/*
printf("\n\nTest cyginet_set_ipv6_forwards:\n\n"); printf("\n\nTest cyginet_set_ipv6_forwards:\n\n");
{ {
printf("cyginet_set_ipv6_forwards(1) return %d\n", printf("cyginet_set_ipv6_forwards(1) return %d\n",
...@@ -2604,11 +2689,12 @@ runTestCases() ...@@ -2604,11 +2689,12 @@ runTestCases()
cyginet_set_icmp6_redirect_accept(1) cyginet_set_icmp6_redirect_accept(1)
); );
} }
*/
printf("\n\nTest cyginet_interface_wireless:\n\n"); printf("\n\nTest cyginet_interface_wireless:\n\n");
{ {
int n; int n;
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table; PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) { while (p) {
n = cyginet_interface_wireless(p -> FriendlyName, 1); n = cyginet_interface_wireless(p -> FriendlyName, 1);
printf("%s is wireless netcard: %d\n", p -> FriendlyName, n); printf("%s is wireless netcard: %d\n", p -> FriendlyName, n);
...@@ -2619,7 +2705,7 @@ runTestCases() ...@@ -2619,7 +2705,7 @@ runTestCases()
printf("\n\nTest cyginet_interface_mtu:\n\n"); printf("\n\nTest cyginet_interface_mtu:\n\n");
{ {
int n; int n;
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table; PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) { while (p) {
n = cyginet_interface_mtu(p -> FriendlyName, 1); n = cyginet_interface_mtu(p -> FriendlyName, 1);
printf("mtu of %s is : %d\n", p -> FriendlyName, n); printf("mtu of %s is : %d\n", p -> FriendlyName, n);
...@@ -2630,7 +2716,7 @@ runTestCases() ...@@ -2630,7 +2716,7 @@ runTestCases()
printf("\n\nTest cyginet_interface_operational:\n\n"); printf("\n\nTest cyginet_interface_operational:\n\n");
{ {
int n; int n;
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table; PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) { while (p) {
n = cyginet_interface_operational(p -> FriendlyName, 1); n = cyginet_interface_operational(p -> FriendlyName, 1);
printf("%s is up: %d\n", p -> FriendlyName, n); printf("%s is up: %d\n", p -> FriendlyName, n);
...@@ -2642,7 +2728,7 @@ runTestCases() ...@@ -2642,7 +2728,7 @@ runTestCases()
{ {
struct sockaddr_in sa; struct sockaddr_in sa;
int n; int n;
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table; PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) { while (p) {
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
n = cyginet_interface_ipv4(p -> FriendlyName, 1, (unsigned char*)&sa); n = cyginet_interface_ipv4(p -> FriendlyName, 1, (unsigned char*)&sa);
...@@ -2655,7 +2741,7 @@ runTestCases() ...@@ -2655,7 +2741,7 @@ runTestCases()
{ {
int n; int n;
struct sockaddr_dl sdl; struct sockaddr_dl sdl;
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table; PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) { while (p) {
memset(&sdl, 0, sizeof(struct sockaddr_dl)); memset(&sdl, 0, sizeof(struct sockaddr_dl));
n = cyginet_interface_sdl(&sdl, p -> FriendlyName); n = cyginet_interface_sdl(&sdl, p -> FriendlyName);
...@@ -2767,9 +2853,9 @@ runTestCases() ...@@ -2767,9 +2853,9 @@ runTestCases()
if (inet_pton(AF_INET, "192.168.128.119", &dest4.sin_addr) != 1) if (inet_pton(AF_INET, "192.168.128.119", &dest4.sin_addr) != 1)
break; break;
if (inet_pton(AF_INET, "192.168.128.200", &gate4.sin_addr) != 1) if (inet_pton(AF_INET, "192.168.121.200", &gate4.sin_addr) != 1)
break; break;
ifindex = 2; ifindex = 5;
metric = 3; metric = 3;
prefix = 32; prefix = 32;
...@@ -2877,10 +2963,11 @@ int main(int argc, char* argv[]) ...@@ -2877,10 +2963,11 @@ int main(int argc, char* argv[])
printf("\n\nTest libwinet_refresh_interface_map_table:\n\n"); printf("\n\nTest libwinet_refresh_interface_map_table:\n\n");
{ {
if (libwinet_refresh_interface_map_table()) { if (libwinet_refresh_interface_map_table()) {
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table; PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) { while (p) {
printf("Friendly Name:\t %s\n", p -> FriendlyName); printf("Friendly Name:\t %s\n", p -> FriendlyName);
printf("Adapter Name:\t %s\n", p -> AdapterName); printf("Adapter Name:\t %s\n", p -> AdapterName);
printf("Forward flag:\t %d\n", p -> RouteFlags);
printf("IfType:\t %ld\n", p -> IfType); printf("IfType:\t %ld\n", p -> IfType);
p = p -> next; p = p -> next;
} }
...@@ -2891,8 +2978,15 @@ int main(int argc, char* argv[]) ...@@ -2891,8 +2978,15 @@ int main(int argc, char* argv[])
runTestCases(); runTestCases();
/* printf("\n\nTest libwinet_init_ipv6_interface:\n\n"); */
/* libwinet_init_ipv6_interface(); */
/* printf("\n\nTest libwinet_restore_ipv6_interface:\n\n"); */
/* libwinet_restore_ipv6_interface(); */
printf("\n\nTest libwinet_free_interface_map_table:\n\n"); printf("\n\nTest libwinet_free_interface_map_table:\n\n");
libwinet_free_interface_map_table(); libwinet_free_interface_map_table();
printf("\n\nTest Finished.\n\n");
WSACleanup(); WSACleanup();
return 0; return 0;
......
...@@ -49,12 +49,47 @@ ...@@ -49,12 +49,47 @@
Routing Table Manager Version 2 Routing Table Manager Version 2
http://msdn.microsoft.com/en-us/library/windows/desktop/bb404201(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/windows/desktop/bb404201(v=vs.85).aspx
Using Routing Table Manager Version 2 Using Routing Table Manager Version 2, this section contains sample
code that can be used when developing clients such as routing
protocols.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa382335(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/windows/desktop/aa382335(v=vs.85).aspx
This section contains sample code that can be used when developing An introduction to the IPv6 protocol along with overviews on
clients such as routing protocols. deployment and IPv6 transitioning technologies is available on
Technet at Microsoft Internet Protocol Version 6 (IPv6).
http://go.microsoft.com/fwlink/p/?linkid=194338
http://technet.microsoft.com/en-us/network/bb530961.aspx
Internet Protocol Version 6 (IPv6)
http://msdn.microsoft.com/en-us//library/windows/desktop/ms738570(v=vs.85).aspx
IPv6 Link-local and Site-local Addresses
http://msdn.microsoft.com/zh-cn/library/windows/desktop/ms739166(v=vs.85).aspx
Recommended Configurations for IPv6
http://msdn.microsoft.com/en-us/library/windows/desktop/ms740117(v=vs.85).aspx
IPv6 Support in Home Routers, It looks like a windows re6stnet.
http://msdn.microsoft.com/en-us/windows/hardware/gg463251.aspx
Neighbor Discovery in IPv6
http://tools.ietf.org/html/rfc4861
Default Address Selection for Internet Protocol version 6 (IPv6)
http://tools.ietf.org/html/rfc3484
Path MTU Discovery
http://tools.ietf.org/html/rfc1191
IPv6 Traffic Between Nodes on Different Subnets of an IPv4 Internetwork (6to4)
http://msdn.microsoft.com/zh-cn/library/windows/desktop/ms737598(v=vs.85).aspx
Multicast Listener Discovery (MLD)
http://msdn.microsoft.com/en-us/library/aa916334.aspx
IPv6 Addresses, it explains the relation between link-local address
and interface id
http://msdn.microsoft.com/en-us/library/aa921042.aspx
*/ */
#ifndef __CYGIFNET_H__ #ifndef __CYGIFNET_H__
...@@ -118,6 +153,9 @@ typedef struct _LIBWINET_INTERFACE_MAP_TABLE { ...@@ -118,6 +153,9 @@ typedef struct _LIBWINET_INTERFACE_MAP_TABLE {
BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH]; BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH];
DWORD PhysicalAddressLength; DWORD PhysicalAddressLength;
DWORD IfType; DWORD IfType;
int RouteFlags;
DWORD IfIndex;
DWORD Ipv6IfIndex;
VOID *next; VOID *next;
} LIBWINET_INTERFACE_MAP_TABLE, *PLIBWINET_INTERFACE_MAP_TABLE; } LIBWINET_INTERFACE_MAP_TABLE, *PLIBWINET_INTERFACE_MAP_TABLE;
...@@ -163,8 +201,8 @@ void cyginet_cleanup(); ...@@ -163,8 +201,8 @@ void cyginet_cleanup();
int cyginet_start_monitor_route_changes(int); int cyginet_start_monitor_route_changes(int);
int cyginet_stop_monitor_route_changes(); int cyginet_stop_monitor_route_changes();
int cyginet_set_ipv6_forwards(int);
int cyginet_set_icmp6_redirect_accept(int); int cyginet_set_icmp6_redirect_accept(int);
int cyginet_set_interface_forwards(const char * ifname, int value);
int cyginet_interface_sdl(struct sockaddr_dl *, char *); int cyginet_interface_sdl(struct sockaddr_dl *, char *);
int cyginet_interface_wireless(const char *, int); int cyginet_interface_wireless(const char *, int);
...@@ -182,10 +220,9 @@ int cyginet_delete_route_entry(const struct sockaddr *, unsigned short, ...@@ -182,10 +220,9 @@ int cyginet_delete_route_entry(const struct sockaddr *, unsigned short,
int cyginet_update_route_entry(const struct sockaddr *, unsigned short, int cyginet_update_route_entry(const struct sockaddr *, unsigned short,
const struct sockaddr *, int , unsigned int); const struct sockaddr *, int , unsigned int);
int cyginet_add_ipentry(int, struct sockaddr*);
char * cyginet_ifname(const char *); char * cyginet_ifname(const char *);
char * cyginet_guidname(const char *); char * cyginet_guidname(const char *);
char * cyginet_ipv4_index2ifname(int); int cyginet_refresh_interface_table();
int cyginet_blackhole_index(struct in6_addr*, char *);
#endif /* __CYGIFNET_H__ */ #endif /* __CYGIFNET_H__ */
...@@ -43,38 +43,15 @@ THE SOFTWARE. ...@@ -43,38 +43,15 @@ THE SOFTWARE.
#include "neighbour.h" #include "neighbour.h"
#include "kernel.h" #include "kernel.h"
#include "util.h" #include "util.h"
#include "interface.h"
#include "cyginet.h" #include "cyginet.h"
/*
* Some issues:
*
* 1. kernel_route
*
* RTM_BLACKHOLE, gateway will be set as loopback, is it right?
*
* 2. IN6_LINKLOCAL_IFINDEX && SET_IN6_LINKLOCAL_IFINDEX
*
* Do both of them work in the Windows?
*
* 3. kernel_interface_ipv4
*
* How to deal with many ipv4 address assigned in one interface,
* now only the first one returned.
*
*/
static int get_sdl(struct sockaddr_dl *sdl, char *guidname); static int get_sdl(struct sockaddr_dl *sdl, char *guidname);
static const unsigned char v4prefix[16] = static const unsigned char v4prefix[16] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; {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 export_table = -1, import_table = -1;
int int
...@@ -110,29 +87,13 @@ get_sdl(struct sockaddr_dl *sdl, char *ifname) ...@@ -110,29 +87,13 @@ get_sdl(struct sockaddr_dl *sdl, char *ifname)
return cyginet_interface_sdl(sdl, ifname); return cyginet_interface_sdl(sdl, ifname);
} }
/* KAME said : "Following two macros are highly depending on KAME Release" */
#define IN6_LINKLOCAL_IFINDEX(a) ((a).s6_addr[2] << 8 | (a).s6_addr[3])
#define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
do { \
(a).s6_addr[2] = ((i) >> 8) & 0xff; \
(a).s6_addr[3] = (i) & 0xff; \
} while (0)
static int old_forwarding = -1; static int old_forwarding = -1;
static int old_accept_redirects = -1; static int old_accept_redirects = -1;
static int ifindex_lo = 1; static int ifindex_lo = 1;
static int kernel_pipe_handles[2]; static int kernel_pipe_handles[2];
int /* It enables ip6.forwarding and disable ip6.redirect.
kernel_setup(int setup)
{
int rc = 0;
int forwarding = 1;
int accept_redirects = 0;
int reboot = 0;
/* It enables ip6.forwarding and disable ip6.redirect.
* *
* Option 1: * Option 1:
* *
...@@ -140,19 +101,7 @@ kernel_setup(int setup) ...@@ -140,19 +101,7 @@ kernel_setup(int setup)
* forward- ing of IPv6 packets. Also, identify if the node is * forward- ing of IPv6 packets. Also, identify if the node is
* acting as a router. Defaults to off. * acting as a router. Defaults to off.
* *
* ==> command line: * ==> In the Windows, MSDN says in the registry
*
* C:/> ipv6 ifc $If6Index forwards
*
* repeat this operation for all ipv6 interfaces
*
* List all ipv6 interface by the command:
*
* C:/> netsh interface ipv6 show interface
*
* ==> API: EnableRouter/DisableRouter (only for ipv4)
*
* ==> MSDN says in the registry
* *
* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
* *
...@@ -165,6 +114,9 @@ kernel_setup(int setup) ...@@ -165,6 +114,9 @@ kernel_setup(int setup)
* *
* Refer to: http://support.microsoft.com/kb/315236/en-us * Refer to: http://support.microsoft.com/kb/315236/en-us
* *
* For ipv6, no global options to enable forwarding, but for each
* interface respectively.
*
* Option 2: * Option 2:
* *
* ICMPV6CTL_REDIRACCEPT * ICMPV6CTL_REDIRACCEPT
...@@ -181,42 +133,52 @@ kernel_setup(int setup) ...@@ -181,42 +133,52 @@ kernel_setup(int setup)
* *
* EnableICMPRedirect = 0 * EnableICMPRedirect = 0
* *
* Refer to: * Regarding ipv6, it's in the registry
*
* http://technet.microsoft.com/en-us/library/cc766102(v=ws.10).aspx
*
* After change them, need to reboot machine.
*
* Notice:
*
* MSDN says nothing about ipv6, it should use the following key
* *
* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters
* *
* Maybe later Window VISTA its corresponding APIs are * Refer to:
* WSAEnumProtocols, WSCUpdateProvider. * http://technet.microsoft.com/en-us/library/cc766102(v=ws.10).aspx
* http://msdn.microsoft.com/en-us/library/aa915651.aspx
*
* Notice the msdn page of Windows CE, value is "EnableICMPRedirects",
* it's plural. But I'd rather use singluar form "EnableICMPRedirect".
* *
*/ */
int
kernel_setup(int setup)
{
int flags=0;
struct interface *ifp;
if (setup) { if (setup) {
int flags;
if (0 != cyginet_startup()) if (0 != cyginet_startup())
return -1; return -1;
if ((rc = cyginet_set_ipv6_forwards(forwarding)) == -1) {
fprintf(stderr, "Cannot enable IPv6 forwarding.\n"); /* We don't disable ICMPv6 redirect in the Windows */
/*
if ((rc = cyginet_set_icmp6_redirect_accept(0)) == -1) {
fprintf(stderr, "Cannot disable ICMPv6 redirect.\n");
return -1; return -1;
} }
old_forwarding = rc;
reboot = (rc == forwarding) ? reboot : 1;
if ((rc = cyginet_set_icmp6_redirect_accept(accept_redirects)) == -1) { if (rc) {
fprintf(stderr, "Cannot disable ICMPv6 redirect.\n"); fprintf(stderr,
if (reboot) "Disable ICMPv6 redirect successfully. Reboot computer "
cyginet_set_ipv6_forwards(old_forwarding); "to take it effect now.\n\n"
);
return -1;
}
*/
FOR_ALL_INTERFACES(ifp) {
if (cyginet_set_interface_forwards(ifp->name, 1) == -1) {
fprintf(stderr, "Cannot enable IPv6 forwarding.\n");
return -1; return -1;
} }
old_accept_redirects = rc; }
reboot = (rc == accept_redirects) ? reboot : 1;
if (pipe(kernel_pipe_handles) == -1) if (pipe(kernel_pipe_handles) == -1)
return -1; return -1;
if ((flags = fcntl(kernel_pipe_handles[0], F_GETFL, 0)) < 0) if ((flags = fcntl(kernel_pipe_handles[0], F_GETFL, 0)) < 0)
...@@ -225,34 +187,14 @@ kernel_setup(int setup) ...@@ -225,34 +187,14 @@ kernel_setup(int setup)
goto error; goto error;
} }
else { else {
if (-1 == (rc = cyginet_set_ipv6_forwards(old_forwarding)))
return -1;
reboot = (rc == forwarding) ? reboot : 1;
if (-1 ==
(rc = cyginet_set_icmp6_redirect_accept(old_accept_redirects)))
return -1;
reboot = (rc == accept_redirects) ? reboot : 1;
close(kernel_pipe_handles[0]); close(kernel_pipe_handles[0]);
close(kernel_pipe_handles[1]); close(kernel_pipe_handles[1]);
cyginet_cleanup(); cyginet_cleanup();
} }
if (reboot)
fprintf(stderr,
"%s IPv6 forwarding and %s ICMPv6 redirect successfully.\n"
"REBOOT NOW, so that these changes take effect.\n\n",
forwarding ? "Enable" : "Disable",
accept_redirects ? "enable" : "disable"
);
return 1; return 1;
error: { error:
if (reboot) {
cyginet_set_ipv6_forwards(old_forwarding);
cyginet_set_icmp6_redirect_accept(old_accept_redirects);
}
return -1; return -1;
}
} }
int int
...@@ -363,12 +305,13 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -363,12 +305,13 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *newgate, int newifindex, const unsigned char *newgate, int newifindex,
unsigned int newmetric) unsigned int newmetric)
{ {
char blackhole_addr6[1][1][16] = {{{0}}};
char blackhole_addr[1][1][16] = {{{0}}};
int rc, ipv4; int rc, ipv4;
struct sockaddr_in ipv4_destnation={0}, ipv4_gateway={0};
struct sockaddr_in6 ipv6_destnation={0}, ipv6_gateway={0};
struct sockaddr *destination, *gateway;
int route_ifindex; int route_ifindex;
int prefix_len; int prefix_len;
struct sockaddr_storage destination = {0};
struct sockaddr_storage gateway = {0};
/* Check that the protocol family is consistent. */ /* Check that the protocol family is consistent. */
if(plen >= 96 && v4mapped(dest)) { if(plen >= 96 && v4mapped(dest)) {
...@@ -377,16 +320,12 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -377,16 +320,12 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
return -1; return -1;
} }
ipv4 = 1; ipv4 = 1;
destination = (struct sockaddr*)&ipv4_destnation;
gateway = (struct sockaddr*)&ipv4_gateway;
} else { } else {
if(v4mapped(gate)) { if(v4mapped(gate)) {
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }
ipv4 = 0; ipv4 = 0;
destination = (struct sockaddr*)&ipv6_destnation;
gateway = (struct sockaddr*)&ipv6_gateway;
} }
if(operation == ROUTE_MODIFY && newmetric == metric && if(operation == ROUTE_MODIFY && newmetric == metric &&
...@@ -394,9 +333,8 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -394,9 +333,8 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
return 0; return 0;
if(operation == ROUTE_MODIFY) { if(operation == ROUTE_MODIFY) {
/* Do not use ROUTE_MODIFY when changing to a neighbour. if((metric == KERNEL_INFINITY) ||
It is the only way to remove the "gateway" flag. */ (ipv4 && plen == 128 && memcmp(dest, newgate, 16) == 0)) {
if(ipv4 && plen == 128 && memcmp(dest, newgate, 16) == 0) {
kernel_route(ROUTE_FLUSH, dest, plen, kernel_route(ROUTE_FLUSH, dest, plen,
gate, ifindex, metric, gate, ifindex, metric,
NULL, 0, 0); NULL, 0, 0);
...@@ -409,6 +347,13 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -409,6 +347,13 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
ifindex = newifindex; ifindex = newifindex;
} }
} }
/* We don't add/delete a blackhole for default route */
else if (newmetric == KERNEL_INFINITY &&
IN6_IS_ADDR_UNSPECIFIED(dest) &&
IN6_IS_ADDR_UNSPECIFIED(newgate))
return 0;
kdebugf("kernel_route: %s %s/%d metric %d dev %d nexthop %s\n", kdebugf("kernel_route: %s %s/%d metric %d dev %d nexthop %s\n",
operation == ROUTE_ADD ? "add" : operation == ROUTE_ADD ? "add" :
...@@ -423,70 +368,70 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen, ...@@ -423,70 +368,70 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
if(metric == KERNEL_INFINITY) { if(metric == KERNEL_INFINITY) {
/* It means this route has property: RTF_BLACKHOLE */ /* It means this route has property: RTF_BLACKHOLE */
if (ifindex_blackhole < 0) { if(ifindex_lo < 0) {
/* ifindex_blackhole = cyginet_blackhole_index(&blackhole_addr6, */ ifindex_lo = cyginet_loopback_index(AF_UNSPEC);
/* blackhole_addr[0][0]+12 */ if(ifindex_lo <= 0)
/* ); */
ifindex_blackhole = 1;
if(ifindex_blackhole <= 0)
return -1; return -1;
} }
route_ifindex = ifindex_blackhole; route_ifindex = ifindex_lo;
} }
#define PUSHADDR(dst, src) \ #define PUSHADDR(dst, src) \
do { struct sockaddr_in *sin = (struct sockaddr_in*)(dst); \ do { struct sockaddr_in *sin = (struct sockaddr_in*)&(dst); \
sin->sin_family = AF_INET; \ sin->sin_family = AF_INET; \
memcpy(&sin->sin_addr, (src) + 12, 4); \ memcpy(&sin->sin_addr, (src) + 12, 4); \
} while (0) } while (0)
#define PUSHADDR6(dst, src) \ #define PUSHADDR6(dst, src) \
do { struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)(dst); \ do { struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&(dst); \
sin6->sin6_family = AF_INET6; \ sin6->sin6_family = AF_INET6; \
memcpy(&sin6->sin6_addr, (src), 16); \ memcpy(&sin6->sin6_addr, (src), 16); \
if(IN6_IS_ADDR_LINKLOCAL (&sin6->sin6_addr)) \
SET_IN6_LINKLOCAL_IFINDEX (sin6->sin6_addr, ifindex); \
} while (0) } while (0)
if(ipv4) { if(ipv4) {
PUSHADDR(destination, dest); PUSHADDR(destination, dest);
if (metric == KERNEL_INFINITY) if (metric == KERNEL_INFINITY)
PUSHADDR(gateway, **blackhole_addr); PUSHADDR(gateway, **blackhole_addr);
else if(plen == 128 && memcmp(dest+12, gate+12, 4) == 0) {
/* It means add arp record, add dest ip to this interface */
if (cyginet_add_ipentry(ifindex,
(struct sockaddr*)&destination) != 0)
return -1;
}
else else
PUSHADDR(gateway, gate); PUSHADDR(gateway, gate);
} else { } else {
PUSHADDR6(destination, dest); PUSHADDR6(destination, dest);
if (metric == KERNEL_INFINITY) if (metric == KERNEL_INFINITY)
PUSHADDR6(gateway, &blackhole_addr6); PUSHADDR6(gateway, **blackhole_addr6);
else else
PUSHADDR6(gateway, gate); PUSHADDR6(gateway, gate);
} }
#undef PUSHADDR #undef PUSHADDR
#undef PUSHADDR6 #undef PUSHADDR6
/* What if route_ifindex == 0 */ /* what if route_ifindex == 0 */
switch(operation) { switch(operation) {
case ROUTE_FLUSH: case ROUTE_FLUSH:
rc = cyginet_delete_route_entry(destination, rc = cyginet_delete_route_entry((struct sockaddr*)&destination,
prefix_len, prefix_len,
gateway, (struct sockaddr*)&gateway,
route_ifindex, route_ifindex,
metric metric
); );
break; break;
case ROUTE_ADD: case ROUTE_ADD:
rc = cyginet_add_route_entry(destination, rc = cyginet_add_route_entry((struct sockaddr*)&destination,
prefix_len, prefix_len,
gateway, (struct sockaddr*)&gateway,
route_ifindex, route_ifindex,
metric metric
); );
break; break;
case ROUTE_MODIFY: case ROUTE_MODIFY:
rc = cyginet_update_route_entry(destination, rc = cyginet_update_route_entry((struct sockaddr*)&destination,
prefix_len, prefix_len,
gateway, (struct sockaddr*)&gateway,
route_ifindex, route_ifindex,
metric metric
); );
...@@ -564,10 +509,6 @@ parse_kernel_route(struct cyginet_route *src, struct kernel_route *route) ...@@ -564,10 +509,6 @@ parse_kernel_route(struct cyginet_route *src, struct kernel_route *route)
if(sa->sa_family == AF_INET6) { if(sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
memcpy(route->gw, &sin6->sin6_addr, 16); memcpy(route->gw, &sin6->sin6_addr, 16);
if(IN6_IS_ADDR_LINKLOCAL (&sin6->sin6_addr)) {
route->ifindex = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr);
SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0);
}
} else if(sa->sa_family == AF_INET) { } else if(sa->sa_family == AF_INET) {
struct sockaddr_in *sin = (struct sockaddr_in *)sa; struct sockaddr_in *sin = (struct sockaddr_in *)sa;
v4tov6(route->gw, (unsigned char *)&sin->sin_addr); v4tov6(route->gw, (unsigned char *)&sin->sin_addr);
...@@ -661,11 +602,6 @@ kernel_addresses(char *ifname, int ifindex, int ll, ...@@ -661,11 +602,6 @@ kernel_addresses(char *ifname, int ifindex, int ll,
if(!!ll != !!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) if(!!ll != !!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
goto next; goto next;
memcpy(routes[i].prefix, &sin6->sin6_addr, 16); memcpy(routes[i].prefix, &sin6->sin6_addr, 16);
if(ll)
/* This a perfect example of counter-productive optimisation :
KAME encodes interface index onto bytes 2 and 3, so we have to
reset those bytes to 0 before passing them to babeld. */
memset(routes[i].prefix + 2, 0, 2);
routes[i].plen = 128; routes[i].plen = 128;
routes[i].metric = 0; routes[i].metric = 0;
routes[i].ifindex = ifindex; routes[i].ifindex = ifindex;
...@@ -705,6 +641,7 @@ kernel_callback(int (*fn)(int, void*), void *closure) ...@@ -705,6 +641,7 @@ kernel_callback(int (*fn)(int, void*), void *closure)
/* In the Windows, we can't get the exact changed route, but the /* In the Windows, we can't get the exact changed route, but the
route table is really changed. */ route table is really changed. */
kdebugf("Kernel table changed.\n"); kdebugf("Kernel table changed.\n");
cyginet_refresh_interface_table();
clear_kernel_socket_event(); clear_kernel_socket_event();
return fn(~0, closure); return fn(~0, closure);
......
...@@ -49,6 +49,11 @@ babel_socket(int port) ...@@ -49,6 +49,11 @@ babel_socket(int port)
if(s < 0) if(s < 0)
return -1; return -1;
/* When this value is nonzero (the default on Windows), a socket
created for the AF_INET6 address family can be used to send and
receive IPv6 packets only. So it's not require to set in the
Windows XP. Actualy, this socket option is only supported on
Windows Vista or later. */
#if !defined(_WIN32_WINNT) || _WIN32_WINNT >= 0x0600 #if !defined(_WIN32_WINNT) || _WIN32_WINNT >= 0x0600
rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
if(rc < 0) if(rc < 0)
......
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