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:
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
testc.exe: cyginet.c
test.exe: cyginet.c
$(CC) $(CFLAGS) $(LDFLAGS) -DTEST_CYGINET -o $@ $< $(LDLIBS)
......@@ -46,7 +46,97 @@ Control Panel -> Network Connections.
You should see all the connections like "Local Area Connection
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
=====
......@@ -66,22 +156,31 @@ Notes
5. Ipv6 option "IPV6_V6ONLY" only works in the Windows Vista later.
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
that you can set both of options for Ipv4 in the registry:
"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"
?
that you can set both of options in the registry:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\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
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
A: It's not OK actually for ipv4. 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
......@@ -92,3 +191,8 @@ Notes
9. IN6_LINKLOCAL_IFINDEX && SET_IN6_LINKLOCAL_IFINDEX, do both of them
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
* implementation allows select to function normally when given
* different types of file descriptors (sockets, pipes, handles,
......@@ -58,7 +43,7 @@ void do_debugf(int level, const char *format, ...);
static HRESULT (WINAPI *ws_guidfromstring)(LPCTSTR psz, LPGUID pguid) = NULL;
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 void
......@@ -111,39 +96,64 @@ mask2len(const unsigned char *p, const int size)
}
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;
char cmdbuf[MAX_BUFFER_SIZE];
int result;
HKEY hKey;
unsigned long type;
unsigned long size;
unsigned long old;
struct if_nameindex * p;
struct if_nameindex * ptr;
if (NULL == (ptr = (struct if_nameindex *)if_nameindex()))
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WRITE, &hKey) !=
ERROR_SUCCESS)
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 ++;
size = sizeof(old);
if (RegQueryValueEx(hKey, name, NULL, &type, (unsigned char *)&old, &size) !=
ERROR_SUCCESS || type != REG_DWORD)
old = defvalue;
if (RegSetValueEx(hKey,
name,
0,
REG_DWORD,
(unsigned char *)&value,
sizeof(value)
)) {
RegCloseKey(hKey);
return -1;
}
result = ! (p -> if_index);
if_freenameindex(ptr);
return result;
RegCloseKey(hKey);
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
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;
while (p) {
if ( p -> AdapterName )
......@@ -154,7 +164,22 @@ libwinet_free_interface_map_table()
p = p -> next;
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
......@@ -191,13 +216,13 @@ libwinet_refresh_interface_map_table()
if (NO_ERROR == dwRet) {
if (interface_map_table)
if (g_interface_map_table)
libwinet_free_interface_map_table();
PLIBWINET_INTERFACE_MAP_TABLE p;
size_t len;
interface_map_table = NULL;
g_interface_map_table = NULL;
pTmpAdaptAddr = pAdaptAddr;
while (pTmpAdaptAddr) {
......@@ -206,8 +231,10 @@ libwinet_refresh_interface_map_table()
dwRet = ERROR_BUFFER_OVERFLOW;
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,
0,
pTmpAdaptAddr -> FriendlyName,
......@@ -250,9 +277,8 @@ libwinet_refresh_interface_map_table()
pTmpAdaptAddr -> PhysicalAddress,
p -> PhysicalAddressLength
);
pTmpAdaptAddr = pTmpAdaptAddr->Next;
interface_map_table = p;
g_interface_map_table = p;
}
if (ERROR_BUFFER_OVERFLOW == dwRet)
......@@ -270,62 +296,32 @@ libwinet_refresh_interface_map_table()
Return 0, if the interface only binds one ip version.
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
libwinet_map_ifindex(int family, int ifindex)
{
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_UNICAST \
| 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_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);
/* Loopback Interface */
if (ifindex == 1)
return 1;
if (g_interface_map_table == NULL)
if (!libwinet_refresh_interface_map_table())
return -1;
PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) {
if (family == AF_INET && ifindex == p -> IfIndex && p -> Ipv6IfIndex)
return p -> Ipv6IfIndex;
else if (family == AF_INET6 && ifindex == p -> Ipv6IfIndex && p -> IfIndex)
return p -> IfIndex;
p = p -> next;
}
return dwReturn;
return 0;
}
static int
......@@ -526,7 +522,7 @@ libwinet_dump_ipv6_route_table(struct cyginet_route *routes,
if (ignored)
ignored = 0;
else if (!ignored) {
route.proto = MIB_IPPROTO_OTHER; /* ?? */
route.proto = MIB_IPPROTO_NETMGMT; /* ?? */
if ((maxroutes > count) && (proute != NULL)) {
memcpy(proute, &route, sizeof(struct cyginet_route));
proute ++;
......@@ -816,8 +812,7 @@ cyginet_blackhole_index(struct in6_addr* addr6, char * addr)
dwRet = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER \
| GAA_FLAG_SKIP_FRIENDLY_NAME,
| GAA_FLAG_SKIP_DNS_SERVER,
NULL,
pAdaptAddr,
&dwSize
......@@ -829,8 +824,7 @@ cyginet_blackhole_index(struct in6_addr* addr6, char * addr)
dwRet = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER \
| GAA_FLAG_SKIP_FRIENDLY_NAME,
| GAA_FLAG_SKIP_DNS_SERVER,
NULL,
pAdaptAddr,
&dwSize
......@@ -843,16 +837,21 @@ cyginet_blackhole_index(struct in6_addr* addr6, char * addr)
if (pTmpAdaptAddr -> IfIndex
&& pTmpAdaptAddr -> Ipv6IfIndex
&& (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;
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);
if (s -> sa_family == AF_INET) {
if (addr)
memcpy(addr, &(((struct sockaddr_in *)s) -> sin_addr), 4);
}
else if (s -> sa_family == AF_INET6) {
if (addr6)
memcpy(addr6, &(((struct sockaddr_in6 *)s) -> sin6_addr), 16);
}
p = p -> Next;
}
dwReturn = pTmpAdaptAddr -> Ipv6IfIndex;
......@@ -876,15 +875,15 @@ cyginet_blackhole_index(struct in6_addr* addr6, char * addr)
* 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
......@@ -918,7 +917,7 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
const int MAX_BUFFER_SIZE = 1024;
const char * cmdformat = "netsh interface ipv6 %s route "
"prefix=%s/%d interface=%d "
"%s%s %s%d";
"nexthop=%s %cmetric=%d";
char cmdbuf[MAX_BUFFER_SIZE];
char sdest[INET6_ADDRSTRLEN];
char sgate[INET6_ADDRSTRLEN];
......@@ -935,7 +934,8 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
INET6_ADDRSTRLEN
))
return -1;
/* metric clause results delete route command failed, so we add
'#' to commet this clause when delete route. */
if (snprintf(cmdbuf,
MAX_BUFFER_SIZE,
cmdformat,
......@@ -944,9 +944,8 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
sdest,
plen,
ifindex,
strcmp(sgate, "::") == 0 ? "" : "nexthop=",
strcmp(sgate, "::") == 0 ? "" : sgate,
cmdflag == RTM_DELETE ? "#" : "metric=",
sgate,
cmdflag == RTM_DELETE ? '#' : ' ',
metric
) >= MAX_BUFFER_SIZE)
return -1;
......@@ -956,23 +955,29 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
}
/* Add ipv4 route before Windows Vista */
else if (0) {
/* Add ipv4 route before Windows Vista, use IP Helper API */
else {
MIB_IPFORWARDROW Row;
unsigned long Res;
struct in_addr mask;
plen2mask(plen, &mask);
memset(&Row, 0, sizeof(MIB_IPFORWARDROW));
Row.dwForwardDest = (((SOCKADDR_IN*)dest) -> sin_addr).S_un.S_addr;
Row.dwForwardPolicy = 0;
Row.dwForwardNextHop = (((SOCKADDR_IN*)gate) -> sin_addr).S_un.S_addr;
Row.dwForwardIfIndex = libwinet_map_ifindex(AF_INET6, ifindex);
Row.dwForwardMask = mask.S_un.S_addr;
/*
* 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
*/
Row.dwForwardType = Row.dwForwardNextHop == Row.dwForwardDest ? \
MIB_IPROUTE_TYPE_DIRECT : MIB_IPROUTE_TYPE_INDIRECT;
Row.dwForwardType = MIB_IPROUTE_TYPE_INDIRECT;
Row.dwForwardProto = MIB_IPPROTO_NETMGMT;
Row.dwForwardAge = 0;
Row.dwForwardNextHopAS = 0;
......@@ -999,7 +1004,7 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
return -1;
}
/* Use route command */
#if 0 /* Use route command */
else {
/* route ADD dest MASK mask gate METRIC n IF index */
/* route CHANGE dest MASK mask gate METRIC n IF index */
......@@ -1036,7 +1041,7 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
MAX_BUFFER_SIZE,
"route %s %s MASK %s %s METRIC %d IF %d",
cmdflag == RTM_ADD ? "add" :
cmdflag == RTM_DELETE ? "delete" : "change",
cmdflag == RTM_DELETE ? "delete" : "change",
sdest,
smask,
sgate,
......@@ -1048,6 +1053,7 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
if (libwinet_run_command(cmdbuf) != 0)
return -1;
}
#endif /* if 0 */
#else
/* Add route entry after Windows Vista */
......@@ -1098,75 +1104,118 @@ libwinet_edit_route_entry(const struct sockaddr *dest,
return 1;
}
static int
libwinet_set_registry_key(char *key, char * name, int value, int defvalue)
int
cyginet_set_interface_forwards(const char * ifname, int value)
{
HKEY hKey;
unsigned long type;
unsigned long size;
unsigned long old;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ | KEY_WRITE, &hKey) !=
ERROR_SUCCESS)
return -1;
size = sizeof(old);
/* For ipv4 */
/* netsh routing add interface ifname enabled/disabled */
char cmdbuf[255];
if (snprintf(cmdbuf,
255,
"netsh interface ipv6 set interface \"%s\" "
"forwarding=%s > /dev/null",
ifname,
value ? "enabled" : "disabled"
) > 0)
return system(cmdbuf);
return -1;
}
if (RegQueryValueEx(hKey, name, NULL, &type, (unsigned char *)&old, &size) !=
ERROR_SUCCESS || type != REG_DWORD)
old = defvalue;
int
cyginet_set_icmp6_redirect_accept(int value)
{
char * key = "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters";
char * name = "EnableICMPRedirect";
return libwinet_set_registry_key(key,
name,
value,
1
);
}
if (RegSetValueEx(hKey,
name,
0,
REG_DWORD,
(unsigned char *)&value,
sizeof(value)
)) {
RegCloseKey(hKey);
return -1;
static void
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;
}
RegCloseKey(hKey);
return old;
}
#if 0
int
cyginet_set_ipv6_forwards(int value)
{
char * key = "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters";
/*
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;
}
*/
char * name = "IPEnableRouter";
return libwinet_set_registry_key(key,
"IPEnableRouter",
name,
value,
0
);
}
int
cyginet_set_icmp6_redirect_accept(int value)
static int
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,
"EnableICMPRedirect",
value,
1
);
struct if_nameindex * p;
struct if_nameindex * ptr;
if (NULL == (ptr = (struct if_nameindex *)if_nameindex()))
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
......@@ -1411,58 +1460,6 @@ cyginet_loopback_index(int family)
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:
*
......@@ -1632,12 +1629,17 @@ cyginet_read_route_socket(void *buffer, size_t size)
return 0;
}
int
cyginet_refresh_interface_table()
{
return libwinet_refresh_interface_map_table();
}
int
cyginet_startup()
{
WORD wVersionRequested;
WSADATA wsaData;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
return WSAStartup(wVersionRequested, &wsaData);
......@@ -1646,6 +1648,8 @@ cyginet_startup()
void
cyginet_cleanup()
{
libwinet_restore_ipv6_interface();
libwinet_free_interface_map_table();
WSACleanup();
}
......@@ -1653,10 +1657,10 @@ char *
cyginet_guidname(const char * ifname)
{
PLIBWINET_INTERFACE_MAP_TABLE p;
if (!interface_map_table)
if (!g_interface_map_table)
libwinet_refresh_interface_map_table();
p = interface_map_table;
p = g_interface_map_table;
while (p) {
if (strcmp(ifname, p -> FriendlyName) == 0)
return p -> AdapterName;
......@@ -1669,10 +1673,10 @@ char *
cyginet_ifname(const char * guidname)
{
PLIBWINET_INTERFACE_MAP_TABLE p;
if (!interface_map_table)
if (!g_interface_map_table)
libwinet_refresh_interface_map_table();
p = interface_map_table;
p = g_interface_map_table;
while (p) {
if (strcmp(guidname, p -> AdapterName) == 0)
return p -> FriendlyName;
......@@ -1681,9 +1685,89 @@ cyginet_ifname(const char * guidname)
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. */
#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
libwinet_get_loopback_index(int family)
{
......@@ -2282,7 +2366,7 @@ DWORD GetInterfaceIndexForAddress(SOCKADDR *pAddr)
FREE(pAdaptAddr);
}
return dwReturn;
}
......@@ -2498,7 +2582,7 @@ runTestCases()
if_freenameindex(ptr);
}
}
/*
printf("\n\nTest cyginet_ipv4_index2ifname:\n\n");
{
int ifindex = 1;
......@@ -2507,10 +2591,10 @@ runTestCases()
cyginet_ipv4_index2ifname(ifindex)
);
}
*/
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) {
printf("%s:\t\t%s\n",
p -> FriendlyName,
......@@ -2546,7 +2630,7 @@ runTestCases()
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) {
printf("%s is wireless netcard: %d\n",
p -> FriendlyName,
......@@ -2585,6 +2669,7 @@ runTestCases()
}
}
/*
printf("\n\nTest cyginet_set_ipv6_forwards:\n\n");
{
printf("cyginet_set_ipv6_forwards(1) return %d\n",
......@@ -2604,11 +2689,12 @@ runTestCases()
cyginet_set_icmp6_redirect_accept(1)
);
}
*/
printf("\n\nTest cyginet_interface_wireless:\n\n");
{
int n;
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table;
PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) {
n = cyginet_interface_wireless(p -> FriendlyName, 1);
printf("%s is wireless netcard: %d\n", p -> FriendlyName, n);
......@@ -2619,7 +2705,7 @@ runTestCases()
printf("\n\nTest cyginet_interface_mtu:\n\n");
{
int n;
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table;
PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) {
n = cyginet_interface_mtu(p -> FriendlyName, 1);
printf("mtu of %s is : %d\n", p -> FriendlyName, n);
......@@ -2630,7 +2716,7 @@ runTestCases()
printf("\n\nTest cyginet_interface_operational:\n\n");
{
int n;
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table;
PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) {
n = cyginet_interface_operational(p -> FriendlyName, 1);
printf("%s is up: %d\n", p -> FriendlyName, n);
......@@ -2642,7 +2728,7 @@ runTestCases()
{
struct sockaddr_in sa;
int n;
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table;
PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) {
memset(&sa, 0, sizeof(sa));
n = cyginet_interface_ipv4(p -> FriendlyName, 1, (unsigned char*)&sa);
......@@ -2655,7 +2741,7 @@ runTestCases()
{
int n;
struct sockaddr_dl sdl;
PLIBWINET_INTERFACE_MAP_TABLE p = interface_map_table;
PLIBWINET_INTERFACE_MAP_TABLE p = g_interface_map_table;
while (p) {
memset(&sdl, 0, sizeof(struct sockaddr_dl));
n = cyginet_interface_sdl(&sdl, p -> FriendlyName);
......@@ -2767,9 +2853,9 @@ runTestCases()
if (inet_pton(AF_INET, "192.168.128.119", &dest4.sin_addr) != 1)
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;
ifindex = 2;
ifindex = 5;
metric = 3;
prefix = 32;
......@@ -2877,10 +2963,11 @@ int main(int argc, char* argv[])
printf("\n\nTest libwinet_refresh_interface_map_table:\n\n");
{
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) {
printf("Friendly Name:\t %s\n", p -> FriendlyName);
printf("Adapter Name:\t %s\n", p -> AdapterName);
printf("Forward flag:\t %d\n", p -> RouteFlags);
printf("IfType:\t %ld\n", p -> IfType);
p = p -> next;
}
......@@ -2891,8 +2978,15 @@ int main(int argc, char* argv[])
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");
libwinet_free_interface_map_table();
printf("\n\nTest Finished.\n\n");
WSACleanup();
return 0;
......
......@@ -46,15 +46,50 @@
IPv6 RFCs and Standards Working Groups
http://www.ipv6now.com.au/RFC.php
Routing Table Manager Version 2
Routing Table Manager Version 2
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
This section contains sample code that can be used when developing
clients such as routing protocols.
An introduction to the IPv6 protocol along with overviews on
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__
......@@ -112,12 +147,15 @@ struct if_nameindex {
char *if_name;
};
typedef struct _LIBWINET_INTERFACE_MAP_TABLE {
PCHAR FriendlyName;
typedef struct _LIBWINET_INTERFACE_MAP_TABLE {
PCHAR FriendlyName;
PCHAR AdapterName;
BYTE PhysicalAddress[MAX_ADAPTER_ADDRESS_LENGTH];
DWORD PhysicalAddressLength;
DWORD IfType;
int RouteFlags;
DWORD IfIndex;
DWORD Ipv6IfIndex;
VOID *next;
} LIBWINET_INTERFACE_MAP_TABLE, *PLIBWINET_INTERFACE_MAP_TABLE;
......@@ -163,8 +201,8 @@ void cyginet_cleanup();
int cyginet_start_monitor_route_changes(int);
int cyginet_stop_monitor_route_changes();
int cyginet_set_ipv6_forwards(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_wireless(const char *, int);
......@@ -182,10 +220,9 @@ int cyginet_delete_route_entry(const struct sockaddr *, unsigned short,
int cyginet_update_route_entry(const struct sockaddr *, unsigned short,
const struct sockaddr *, int , unsigned int);
int cyginet_add_ipentry(int, struct sockaddr*);
char * cyginet_ifname(const char *);
char * cyginet_guidname(const char *);
char * cyginet_ipv4_index2ifname(int);
int cyginet_blackhole_index(struct in6_addr*, char *);
int cyginet_refresh_interface_table();
#endif /* __CYGIFNET_H__ */
......@@ -43,38 +43,15 @@ THE SOFTWARE.
#include "neighbour.h"
#include "kernel.h"
#include "util.h"
#include "interface.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 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
......@@ -110,113 +87,98 @@ get_sdl(struct sockaddr_dl *sdl, char *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_accept_redirects = -1;
static int ifindex_lo = 1;
static int kernel_pipe_handles[2];
/* It enables ip6.forwarding and disable ip6.redirect.
*
* Option 1:
*
* IPV6CTL_FORWARDING (ip6.forwarding) Boolean: enable/disable
* forward- ing of IPv6 packets. Also, identify if the node is
* acting as a router. Defaults to off.
*
* ==> In the Windows, MSDN says in the registry
*
* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
*
* Value Name: IPEnableRouter
* Value type: REG_DWORD
* Value Data: 1
*
* A value of 1 enables TCP/IP forwarding for all network
* connections that are installed and used by this computer.
*
* 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:
*
* ICMPV6CTL_REDIRACCEPT
*
* IPV6CTL_SENDREDIRECTS (ip6.redirect) Boolean: enable/disable
* sending of ICMPv6 redirects in response to unforwardable IPv6
* packets. This option is ignored unless the node is routing
* IPv6 packets, and should normally be enabled on all systems.
* Defaults to on.
*
* ==> MSDN says in the registry
*
* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
*
* EnableICMPRedirect = 0
*
* Regarding ipv6, it's in the registry
*
* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters
*
* Refer to:
* 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 rc = 0;
int forwarding = 1;
int accept_redirects = 0;
int reboot = 0;
/* It enables ip6.forwarding and disable ip6.redirect.
*
* Option 1:
*
* IPV6CTL_FORWARDING (ip6.forwarding) Boolean: enable/disable
* forward- ing of IPv6 packets. Also, identify if the node is
* acting as a router. Defaults to off.
*
* ==> command line:
*
* 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
*
* Value Name: IPEnableRouter
* Value type: REG_DWORD
* Value Data: 1
*
* A value of 1 enables TCP/IP forwarding for all network
* connections that are installed and used by this computer.
*
* Refer to: http://support.microsoft.com/kb/315236/en-us
*
* Option 2:
*
* ICMPV6CTL_REDIRACCEPT
*
* IPV6CTL_SENDREDIRECTS (ip6.redirect) Boolean: enable/disable
* sending of ICMPv6 redirects in response to unforwardable IPv6
* packets. This option is ignored unless the node is routing
* IPv6 packets, and should normally be enabled on all systems.
* Defaults to on.
*
* ==> MSDN says in the registry
*
* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
*
* EnableICMPRedirect = 0
*
* Refer to:
*
* 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
*
* Maybe later Window VISTA its corresponding APIs are
* WSAEnumProtocols, WSCUpdateProvider.
*
*/
int flags=0;
struct interface *ifp;
if (setup) {
int flags;
if (0 != cyginet_startup())
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;
}
old_forwarding = rc;
reboot = (rc == forwarding) ? reboot : 1;
if ((rc = cyginet_set_icmp6_redirect_accept(accept_redirects)) == -1) {
fprintf(stderr, "Cannot disable ICMPv6 redirect.\n");
if (reboot)
cyginet_set_ipv6_forwards(old_forwarding);
if (rc) {
fprintf(stderr,
"Disable ICMPv6 redirect successfully. Reboot computer "
"to take it effect now.\n\n"
);
return -1;
}
old_accept_redirects = rc;
reboot = (rc == accept_redirects) ? reboot : 1;
*/
FOR_ALL_INTERFACES(ifp) {
if (cyginet_set_interface_forwards(ifp->name, 1) == -1) {
fprintf(stderr, "Cannot enable IPv6 forwarding.\n");
return -1;
}
}
if (pipe(kernel_pipe_handles) == -1)
return -1;
if ((flags = fcntl(kernel_pipe_handles[0], F_GETFL, 0)) < 0)
......@@ -225,34 +187,14 @@ kernel_setup(int setup)
goto error;
}
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[1]);
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;
error: {
if (reboot) {
cyginet_set_ipv6_forwards(old_forwarding);
cyginet_set_icmp6_redirect_accept(old_accept_redirects);
}
return -1;
}
error:
return -1;
}
int
......@@ -363,12 +305,13 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
const unsigned char *newgate, int newifindex,
unsigned int newmetric)
{
char blackhole_addr6[1][1][16] = {{{0}}};
char blackhole_addr[1][1][16] = {{{0}}};
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 prefix_len;
struct sockaddr_storage destination = {0};
struct sockaddr_storage gateway = {0};
/* Check that the protocol family is consistent. */
if(plen >= 96 && v4mapped(dest)) {
......@@ -377,16 +320,12 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
return -1;
}
ipv4 = 1;
destination = (struct sockaddr*)&ipv4_destnation;
gateway = (struct sockaddr*)&ipv4_gateway;
} else {
if(v4mapped(gate)) {
errno = EINVAL;
return -1;
}
ipv4 = 0;
destination = (struct sockaddr*)&ipv6_destnation;
gateway = (struct sockaddr*)&ipv6_gateway;
}
if(operation == ROUTE_MODIFY && newmetric == metric &&
......@@ -394,9 +333,8 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
return 0;
if(operation == ROUTE_MODIFY) {
/* Do not use ROUTE_MODIFY when changing to a neighbour.
It is the only way to remove the "gateway" flag. */
if(ipv4 && plen == 128 && memcmp(dest, newgate, 16) == 0) {
if((metric == KERNEL_INFINITY) ||
(ipv4 && plen == 128 && memcmp(dest, newgate, 16) == 0)) {
kernel_route(ROUTE_FLUSH, dest, plen,
gate, ifindex, metric,
NULL, 0, 0);
......@@ -409,6 +347,13 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
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",
operation == ROUTE_ADD ? "add" :
......@@ -423,70 +368,70 @@ kernel_route(int operation, const unsigned char *dest, unsigned short plen,
if(metric == KERNEL_INFINITY) {
/* It means this route has property: RTF_BLACKHOLE */
if (ifindex_blackhole < 0) {
/* ifindex_blackhole = cyginet_blackhole_index(&blackhole_addr6, */
/* blackhole_addr[0][0]+12 */
/* ); */
ifindex_blackhole = 1;
if(ifindex_blackhole <= 0)
if(ifindex_lo < 0) {
ifindex_lo = cyginet_loopback_index(AF_UNSPEC);
if(ifindex_lo <= 0)
return -1;
}
route_ifindex = ifindex_blackhole;
route_ifindex = ifindex_lo;
}
#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; \
memcpy(&sin->sin_addr, (src) + 12, 4); \
} while (0)
#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; \
memcpy(&sin6->sin6_addr, (src), 16); \
if(IN6_IS_ADDR_LINKLOCAL (&sin6->sin6_addr)) \
SET_IN6_LINKLOCAL_IFINDEX (sin6->sin6_addr, ifindex); \
} while (0)
if(ipv4) {
PUSHADDR(destination, dest);
if (metric == KERNEL_INFINITY)
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
PUSHADDR(gateway, gate);
} else {
PUSHADDR6(destination, dest);
if (metric == KERNEL_INFINITY)
PUSHADDR6(gateway, &blackhole_addr6);
else
PUSHADDR6(gateway, **blackhole_addr6);
else
PUSHADDR6(gateway, gate);
}
#undef PUSHADDR
#undef PUSHADDR6
/* What if route_ifindex == 0 */
/* what if route_ifindex == 0 */
switch(operation) {
case ROUTE_FLUSH:
rc = cyginet_delete_route_entry(destination,
rc = cyginet_delete_route_entry((struct sockaddr*)&destination,
prefix_len,
gateway,
(struct sockaddr*)&gateway,
route_ifindex,
metric
);
break;
case ROUTE_ADD:
rc = cyginet_add_route_entry(destination,
rc = cyginet_add_route_entry((struct sockaddr*)&destination,
prefix_len,
gateway,
(struct sockaddr*)&gateway,
route_ifindex,
metric
);
break;
case ROUTE_MODIFY:
rc = cyginet_update_route_entry(destination,
rc = cyginet_update_route_entry((struct sockaddr*)&destination,
prefix_len,
gateway,
(struct sockaddr*)&gateway,
route_ifindex,
metric
);
......@@ -564,10 +509,6 @@ parse_kernel_route(struct cyginet_route *src, struct kernel_route *route)
if(sa->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
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) {
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
v4tov6(route->gw, (unsigned char *)&sin->sin_addr);
......@@ -661,11 +602,6 @@ kernel_addresses(char *ifname, int ifindex, int ll,
if(!!ll != !!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
goto next;
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].metric = 0;
routes[i].ifindex = ifindex;
......@@ -705,8 +641,9 @@ kernel_callback(int (*fn)(int, void*), void *closure)
/* In the Windows, we can't get the exact changed route, but the
route table is really changed. */
kdebugf("Kernel table changed.\n");
cyginet_refresh_interface_table();
clear_kernel_socket_event();
return fn(~0, closure);
}
......
......@@ -49,6 +49,11 @@ babel_socket(int port)
if(s < 0)
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
rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
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