Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
slapos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Lorenzo Martinico
slapos
Commits
0e633e88
Commit
0e633e88
authored
Feb 05, 2013
by
Jondy Zhao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Patch babeld for supporting Cygwin.
parent
696b2f2a
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
2578 additions
and
4 deletions
+2578
-4
component/babeld/Makefile
component/babeld/Makefile
+4
-4
component/babeld/cyginet.c
component/babeld/cyginet.c
+2403
-0
component/babeld/cyginet.h
component/babeld/cyginet.h
+169
-0
component/babeld/kernel.c
component/babeld/kernel.c
+2
-0
No files found.
component/babeld/Makefile
View file @
0e633e88
...
...
@@ -6,13 +6,13 @@ DEFINES = $(PLATFORM_DEFINES)
CFLAGS
=
$(CDEBUGFLAGS)
$(DEFINES)
$(EXTRA_DEFINES)
LDLIBS
=
-lrt
LDLIBS
=
-lrt
-liphlpapi
-lws2_32
-lwlanapi
-lole32
-lsetupapi
SRCS
=
babeld.c net.c kernel.c util.c interface.c source.c neighbour.c
\
route.c xroute.c message.c resend.c configuration.c local.c
route.c xroute.c message.c resend.c configuration.c local.c
cyginet.c
OBJS
=
babeld.o net.o kernel.o util.o interface.o source.o neighbour.o
\
route.o xroute.o message.o resend.o configuration.o local.o
route.o xroute.o message.o resend.o configuration.o local.o
cyginet.o
babeld
:
$(OBJS)
$(CC)
$(CFLAGS)
$(LDFLAGS)
-o
babeld
$(OBJS)
$(LDLIBS)
...
...
@@ -48,4 +48,4 @@ uninstall:
clean
:
-
rm
-f
babeld babeld.html
*
.o
*
~ core TAGS gmon.out
kernel.o
:
kernel_netlink.c kernel_socket.c
kernel.o
:
kernel_netlink.c kernel_socket.c
kernel_cygwin.c
component/babeld/cyginet.c
0 → 100644
View file @
0e633e88
/*
* 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,
* etc.).
*/
#if !defined(__INSIDE_CYGWIN__)
#define __INSIDE_CYGWIN__
#define USE_SYS_TYPES_FD_SET
#endif
#include <sys/select.h>
#include <sys/fcntl.h>
/* Headers in the /usr/include/w32api */
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <wlanapi.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <wchar.h>
#define INSIDE_CYGINET
#include "cyginet.h"
#undef INSIDE_CYGINET
static
HRESULT
(
WINAPI
*
ws_guidfromstring
)(
LPCTSTR
psz
,
LPGUID
pguid
)
=
NULL
;
static
HANDLE
event_notify_monitor_thread
=
WSA_INVALID_EVENT
;
static
void
plen2mask
(
int
n
,
struct
in_addr
*
dest
)
{
unsigned
char
*
p
;
int
i
;
static
const
int
pl2m
[
9
]
=
{
0x00
,
0x80
,
0xc0
,
0xe0
,
0xf0
,
0xf8
,
0xfc
,
0xfe
,
0xff
};
memset
(
dest
,
0
,
sizeof
(
struct
in_addr
));
p
=
(
u_char
*
)
dest
;
for
(
i
=
0
;
i
<
4
;
i
++
,
p
++
,
n
-=
8
)
{
if
(
n
>=
8
)
{
*
p
=
0xff
;
continue
;
}
*
p
=
pl2m
[
n
];
break
;
}
return
;
}
static
int
mask2len
(
const
unsigned
char
*
p
,
const
int
size
)
{
int
i
=
0
,
j
;
for
(
j
=
0
;
j
<
size
;
j
++
,
p
++
)
{
if
(
*
p
!=
0xff
)
break
;
i
+=
8
;
}
if
(
j
<
size
)
{
switch
(
*
p
)
{
#define MASKLEN(m, l) case m: do { i += l; break; } while (0)
MASKLEN
(
0xfe
,
7
);
break
;
MASKLEN
(
0xfc
,
6
);
break
;
MASKLEN
(
0xf8
,
5
);
break
;
MASKLEN
(
0xf0
,
4
);
break
;
MASKLEN
(
0xe0
,
3
);
break
;
MASKLEN
(
0xc0
,
2
);
break
;
MASKLEN
(
0x80
,
1
);
break
;
#undef MASKLEN
}
}
return
i
;
}
static
int
libwinet_get_interface_info
(
const
char
*
ifname
,
int
family
,
int
ifindex
,
PLIBWINET_INTERFACE
pinfo
)
{
IP_ADAPTER_ADDRESSES
*
pAdaptAddr
=
NULL
;
IP_ADAPTER_ADDRESSES
*
pTmpAdaptAddr
=
NULL
;
DWORD
dwRet
=
0
;
DWORD
dwSize
=
0x10000
;
DWORD
dwReturn
=
0
;
dwRet
=
GetAdaptersAddresses
(
family
,
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
-
1
;
dwRet
=
GetAdaptersAddresses
(
family
,
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
)
{
/* For ipv4, two contidions:
AdapterName equals ifname and IfIndex is nonzero.
For ipv6, only judge Ipv6IfIndex
*/
if
(
family
==
AF_INET6
?
pTmpAdaptAddr
->
Ipv6IfIndex
==
ifindex
\
:
(
pTmpAdaptAddr
->
IfIndex
!=
0
)
\
&&
(
strcmp
(
ifname
,
pTmpAdaptAddr
->
AdapterName
)
==
0
)
)
{
memset
(
pinfo
,
0
,
sizeof
(
pinfo
));
pinfo
->
IfType
=
pTmpAdaptAddr
->
IfType
;
pinfo
->
Mtu
=
pTmpAdaptAddr
->
Mtu
;
pinfo
->
OperStatus
=
pTmpAdaptAddr
->
OperStatus
;
/* Copy first unicast address */
if
(
pTmpAdaptAddr
->
FirstUnicastAddress
)
memcpy
(
&
(
pinfo
->
Address
),
(
pTmpAdaptAddr
->
FirstUnicastAddress
->
Address
).
lpSockaddr
,
sizeof
(
pinfo
->
Address
)
);
dwReturn
=
1
;
break
;
}
pTmpAdaptAddr
=
pTmpAdaptAddr
->
Next
;
}
}
FREE
(
pAdaptAddr
);
return
dwReturn
;
}
static
int
libwinet_run_command
(
const
char
*
command
)
{
FILE
*
output
;
output
=
popen
(
command
,
"r"
);
if
(
!
output
)
return
-
1
;
/* Waiting for subprocess exit and return exit code */
return
pclose
(
output
);
}
#if _WIN32_WINNT < _WIN32_WINNT_VISTA
/*
* Before Windows Vista, use netsh command to get ipv6 route table
*
* C:\> netsh interface ipv6 show routes verbose
*
* It will print the following route entries:
*
* Prefix : fe80::1/128
* Interface 1 : Loopback Pseudo-Interface
* Gateway : fe80::1
* Metric : 4
* Publish : no
* Type : System
* Valid Lifetime : infinite
* Preferred Lifetime: infinite
* Site Prefix Length: 0
*
* ....
*
* Type System means that routes used for loopback.
*
* Gateway could be an address or interface name.
*
*/
static
int
libwinet_dump_ipv6_route_table
(
struct
kernel_route
*
routes
,
int
maxroutes
)
{
#define MAX_LINE_SIZE 80
const
char
*
command
=
"netsh interface ipv6 show routes verbose"
;
FILE
*
output
;
char
buffer
[
MAX_LINE_SIZE
];
char
*
s
,
*
p
;
int
count
=
0
;
int
ignored
=
0
;
IN6_ADDR
*
sin6
;
struct
kernel_route
*
proute
=
routes
;
output
=
popen
(
command
,
"r"
);
if
(
!
output
)
return
-
1
;
/* Ignore the first line */
fgets
(
buffer
,
MAX_LINE_SIZE
,
output
);
/* Read the output until EOF */
while
(
fgets
(
buffer
,
MAX_LINE_SIZE
,
output
))
{
if
((
'\n'
==
buffer
[
0
])
||
(
'\r'
==
buffer
[
0
]))
continue
;
if
(
NULL
==
(
s
=
strchr
(
buffer
,
':'
)))
break
;
*
s
++
=
0
;
/* Split the string */
s
++
;
/* Skip space */
/* The first field of route entry */
if
(
strncmp
(
buffer
,
"Prefix"
,
6
)
==
0
)
{
sin6
=
(
IN6_ADDR
*
)
&
(
proute
->
prefix
);
if
(
NULL
==
(
p
=
strchr
(
s
,
'/'
)))
break
;
*
p
++
=
0
;
/*
* Maybe it will be "fe80::5efe:10.85.0.127", ignore it
*/
if
(
inet_pton
(
AF_INET6
,
s
,
sin6
)
!=
1
)
ignored
=
1
;
proute
->
plen
=
strtol
(
p
,
NULL
,
10
);
}
else
if
(
strncmp
(
buffer
,
"Interface"
,
9
)
==
0
)
proute
->
ifindex
=
strtol
(
buffer
+
9
,
NULL
,
10
);
else
if
(
strncmp
(
buffer
,
"Gateway"
,
7
)
==
0
)
{
sin6
=
(
IN6_ADDR
*
)
&
(
proute
->
gw
);
if
(
inet_pton
(
AF_INET6
,
s
,
sin6
)
!=
1
)
memset
(
sin6
,
0
,
sizeof
(
IN6_ADDR
));
}
else
if
(
strncmp
(
buffer
,
"Metric"
,
6
)
==
0
)
proute
->
metric
=
strtol
(
s
,
NULL
,
10
);
/* Last field of the route entry */
else
if
(
strncmp
(
buffer
,
"Site Prefix Length"
,
18
)
==
0
)
{
if
(
ignored
)
ignored
=
0
;
else
if
(
!
ignored
)
{
proute
->
proto
=
MIB_IPPROTO_OTHER
;
/* ?? */
count
++
;
proute
++
;
if
(
count
>
maxroutes
)
break
;
}
}
else
{
/* Immortal: persistent entry */
/* Age */
/* ... */
}
}
pclose
(
output
);
return
count
;
}
/* Tell the interface is wireless or not. First we list all wireless
* interfaces in the machine, then search the designated one.
*/
static
int
libwinet_is_wireless_interface
(
const
char
*
ifname
)
{
GUID
ifguid
;
HANDLE
hClient
=
NULL
;
DWORD
dwMaxClient
=
1
;
/* 1 Client version for Windows XP with SP3 and Wireless LAN API for
Windows XP with SP2. */
/* 2 Client version for Windows Vista and Windows Server 2008 */
DWORD
dwCurVersion
=
1
;
DWORD
dwResult
=
0
;
int
iRet
=
0
;
int
i
;
if
(
NULL
==
ws_guidfromstring
)
{
HMODULE
lib
;
if
((
lib
=
LoadLibraryW
(
L"shell32.dll"
)))
{
ws_guidfromstring
=
(
HRESULT
(
WINAPI
*
)(
LPCTSTR
,
LPGUID
))
GetProcAddress
(
lib
,
(
LPCSTR
)
703
);
/* GUIDFromStringA */
FreeLibrary
(
lib
);
}
}
if
(
NULL
==
ws_guidfromstring
)
return
-
1
;
if
(
!
(
*
ws_guidfromstring
)(
ifname
,
&
ifguid
))
return
-
1
;
/* variables used for WlanEnumInterfaces */
PWLAN_INTERFACE_INFO_LIST
pIfList
=
NULL
;
PWLAN_INTERFACE_INFO
pIfInfo
=
NULL
;
dwResult
=
WlanOpenHandle
(
dwMaxClient
,
NULL
,
&
dwCurVersion
,
&
hClient
);
if
(
dwResult
!=
ERROR_SUCCESS
)
return
-
1
;
dwResult
=
WlanEnumInterfaces
(
hClient
,
NULL
,
&
pIfList
);
if
(
dwResult
!=
ERROR_SUCCESS
)
return
-
1
;
for
(
i
=
0
;
i
<
(
int
)
pIfList
->
dwNumberOfItems
;
i
++
)
{
pIfInfo
=
(
WLAN_INTERFACE_INFO
*
)
&
pIfList
->
InterfaceInfo
[
i
];
if
(
0
==
memcmp
(
&
pIfInfo
->
InterfaceGuid
,
&
ifguid
,
sizeof
(
GUID
)))
{
iRet
=
1
;
break
;
}
}
if
(
pIfList
!=
NULL
)
{
WlanFreeMemory
(
pIfList
);
pIfList
=
NULL
;
}
return
iRet
;
}
#endif
/* _WIN32_WINNT < _WIN32_WINNT_VISTA */
static
DWORD
WINAPI
libwinet_monitor_route_thread_proc
(
LPVOID
lpParam
)
{
#define EVENT_COUNT 4
DWORD
dwBytesReturned
=
0
;
DWORD
dwReturn
=
0
;
SOCKET
s
[
2
]
=
{
INVALID_SOCKET
,
INVALID_SOCKET
};
WSAOVERLAPPED
hOverLappeds
[
EVENT_COUNT
];
WSAEVENT
hEvents
[
EVENT_COUNT
+
1
];
SOCKADDR_IN6
IPv6Addr
=
{
AF_INET6
,
0
,
0
,
{{
IN6ADDR_ANY_INIT
}}
};
SOCKADDR_IN
IPv4Addr
=
{
AF_INET
,
0
,
{{{
INADDR_ANY
}}},
{
0
}
};
int
mypipe
=
(
int
)
lpParam
;
BOOL
bResult
=
TRUE
;
int
i
;
memset
(
hOverLappeds
,
0
,
sizeof
(
WSAOVERLAPPED
)
*
EVENT_COUNT
);
memset
(
hEvents
,
0
,
sizeof
(
WSAEVENT
)
*
EVENT_COUNT
);
hEvents
[
EVENT_COUNT
]
=
event_notify_monitor_thread
;
if
(
bResult
)
{
s
[
0
]
=
socket
(
AF_INET
,
SOCK_DGRAM
,
0
);
s
[
1
]
=
socket
(
AF_INET6
,
SOCK_DGRAM
,
0
);
if
((
INVALID_SOCKET
==
s
[
0
])
||
(
INVALID_SOCKET
==
s
[
1
]))
{
SOCKETERR
(
"socket"
);
bResult
=
FALSE
;
}
}
if
(
bResult
)
for
(
i
=
0
;
i
<
EVENT_COUNT
;
i
++
)
if
(
WSA_INVALID_EVENT
==
(
hEvents
[
i
]
=
WSACreateEvent
()))
{
SOCKETERR
(
"WSACreateEvent"
);
bResult
=
FALSE
;
break
;
}
/* DestAddrs[0].sa_family = AF_INET; */
/* ((SOCKADDR_IN*)&DestAddrs[0])->sin_addr.S_un.S_addr =
htonl(INADDR_ANY); */
/* DestAddrs[1].sa_family = AF_INET6; */
/* ((SOCKADDR_IN6*)&DestAddrs[1])->sin6_addr = IN6ADDR_ANY_INIT; */
/* Waiting for route and interface changed */
DWORD
dwWaitResult
;
while
(
bResult
)
{
memset
(
hOverLappeds
,
0
,
sizeof
(
WSAOVERLAPPED
)
*
EVENT_COUNT
);
for
(
i
=
0
;
i
<
EVENT_COUNT
;
i
++
)
hOverLappeds
[
i
].
hEvent
=
hEvents
[
i
];
for
(
i
=
0
;
i
<
2
;
i
++
)
{
if
(
bResult
)
{
if
(
SOCKET_ERROR
==
WSAIoctl
(
s
[
i
],
SIO_ROUTING_INTERFACE_CHANGE
,
i
?
(
LPVOID
)
&
IPv6Addr
:
(
LPVOID
)
&
IPv4Addr
,
i
?
sizeof
(
SOCKADDR_IN6
)
:
sizeof
(
SOCKADDR_IN
),
NULL
,
0
,
&
dwBytesReturned
,
&
hOverLappeds
[
i
*
2
],
NULL
))
{
if
(
WSA_IO_PENDING
!=
WSAGetLastError
())
{
SOCKETERR
(
"WSAIoctl"
);
bResult
=
FALSE
;
}
}
}
if
(
bResult
)
{
if
(
SOCKET_ERROR
==
WSAIoctl
(
s
[
i
],
SIO_ADDRESS_LIST_CHANGE
,
NULL
,
0
,
NULL
,
0
,
&
dwBytesReturned
,
&
hOverLappeds
[
i
*
2
+
1
],
NULL
))
{
if
(
WSA_IO_PENDING
!=
WSAGetLastError
())
{
SOCKETERR
(
"WSAIoctl"
);
bResult
=
FALSE
;
}
}
}
}
if
(
bResult
)
{
dwWaitResult
=
WSAWaitForMultipleEvents
(
EVENT_COUNT
+
1
,
hEvents
,
FALSE
,
WSA_INFINITE
,
FALSE
);
switch
(
dwWaitResult
)
{
case
WSA_WAIT_TIMEOUT
:
break
;
case
WSA_WAIT_EVENT_0
:
WSAResetEvent
(
hEvents
[
0
]);
if
(
write
(
mypipe
,
&
"0"
,
1
)
==
-
1
)
bResult
=
FALSE
;
break
;
case
WSA_WAIT_EVENT_0
+
1
:
WSAResetEvent
(
hEvents
[
1
]);
if
(
write
(
mypipe
,
&
"1"
,
1
)
==
-
1
)
bResult
=
FALSE
;
break
;
case
WSA_WAIT_EVENT_0
+
2
:
WSAResetEvent
(
hEvents
[
2
]);
if
(
write
(
mypipe
,
&
"2"
,
1
)
==
-
1
)
bResult
=
FALSE
;
break
;
case
WSA_WAIT_EVENT_0
+
3
:
WSAResetEvent
(
hEvents
[
3
]);
if
(
write
(
mypipe
,
&
"3"
,
1
)
==
-
1
)
bResult
=
FALSE
;
break
;
case
WSA_WAIT_EVENT_0
+
4
:
WSAResetEvent
(
hEvents
[
4
]);
bResult
=
FALSE
;
break
;
case
WSA_WAIT_IO_COMPLETION
:
break
;
default:
SOCKETERR
(
"WSAWaitForMultipleEvents"
);
bResult
=
FALSE
;
}
}
}
for
(
i
=
0
;
i
<
EVENT_COUNT
;
i
++
)
CLOSESOCKEVENT
(
hEvents
[
i
]);
CLOSESOCKET
(
s
[
0
]);
CLOSESOCKET
(
s
[
1
]);
return
dwReturn
;
}
int
cyginet_start_monitor_route_changes
(
int
mypipe
)
{
if
(
WSA_INVALID_EVENT
==
event_notify_monitor_thread
)
event_notify_monitor_thread
=
WSACreateEvent
();
if
(
WSA_INVALID_EVENT
==
event_notify_monitor_thread
)
return
-
1
;
HANDLE
hthread
;
hthread
=
CreateThread
(
NULL
,
// default security
0
,
// stack size
libwinet_monitor_route_thread_proc
,
(
LPVOID
)
mypipe
,
0
,
// startup flags
NULL
);
if
(
hthread
==
NULL
)
{
CLOSESOCKEVENT
(
event_notify_monitor_thread
);
event_notify_monitor_thread
=
WSA_INVALID_EVENT
;
return
-
1
;
}
return
0
;
}
int
cyginet_stop_monitor_route_changes
()
{
int
rc
=
0
;
/* Notify thread to quit */
WSASetEvent
(
event_notify_monitor_thread
);
CLOSESOCKEVENT
(
event_notify_monitor_thread
);
event_notify_monitor_thread
=
WSA_INVALID_EVENT
;
return
rc
;
}
/*
* There are 3 ways to change a route:
*
* Before Windows Vista
*
* 1. IPv4 route: CreateIpForwardEntry
* DeleteIpForwardEntry
* SetIpForwardEntry
*
* 2. IPv6 route: command "netsh"
*
* C:/> netsh interface ipv6 add route
* prefix=<IPv6 address>/<integer>
* interface=]<string>
* nexthop=<IPv6 address>
* metric=<integer>
*
* Example:
*
* add route prefix=3ffe::/16 interface=1 nexthop=fe80::1
*
* In Windows Vista and later
*
* 3. API: CreateIpForwardEntry2
* DeleteIpForwardEntry2
* SetIpForwardEntry2
*
*/
static
int
libwinet_edit_route_entry
(
const
struct
sockaddr
*
dest
,
unsigned
short
plen
,
const
struct
sockaddr
*
gate
,
int
ifindex
,
unsigned
int
metric
,
int
cmdflag
)
{
#if _WIN32_WINNT < _WIN32_WINNT_VISTA
/* Add ipv6 route before Windows Vista */
if
(
dest
->
sa_family
==
AF_INET6
)
{
const
int
MAX_BUFFER_SIZE
=
1024
;
const
char
*
cmdformat
=
"netsh interface ipv6 %s route "
"prefix=%s/%d interface=%d "
"nexthop=%s %s%d"
;
char
cmdbuf
[
MAX_BUFFER_SIZE
];
char
sdest
[
INET6_ADDRSTRLEN
];
char
sgate
[
INET6_ADDRSTRLEN
];
if
(
NULL
==
inet_ntop
(
AF_INET6
,
(
const
void
*
)(
&
(((
SOCKADDR_IN6
*
)
dest
)
->
sin6_addr
)),
sdest
,
INET6_ADDRSTRLEN
))
return
-
1
;
if
(
NULL
==
inet_ntop
(
AF_INET6
,
(
const
void
*
)(
&
(((
SOCKADDR_IN6
*
)
gate
)
->
sin6_addr
)),
sgate
,
INET6_ADDRSTRLEN
))
return
-
1
;
if
(
snprintf
(
cmdbuf
,
MAX_BUFFER_SIZE
,
cmdformat
,
cmdflag
==
RTM_ADD
?
"add"
:
cmdflag
==
RTM_DELETE
?
"delete"
:
"set"
,
sdest
,
plen
,
ifindex
,
sgate
,
cmdflag
==
RTM_DELETE
?
"#"
:
"metric="
,
metric
)
>=
MAX_BUFFER_SIZE
)
return
-
1
;
if
(
libwinet_run_command
(
cmdbuf
)
!=
0
)
return
-
1
;
}
/* Add ipv4 route before Windows Vista */
else
if
(
1
)
{
MIB_IPFORWARDROW
Row
;
unsigned
long
Res
;
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
=
ifindex
;
/*
* MIB_IPROUTE_TYPE_DIRECT <==> dwForwardNextHop == dwForwardDest
* MIB_IPROUTE_TYPE_LOCAL <==> dwForwardNextHop == Ip of the interface
* MIB_IPROUTE_TYPE_INDIRECT all the others
*/
Row
.
dwForwardType
=
Row
.
dwForwardNextHop
==
Row
.
dwForwardDest
?
\
MIB_IPROUTE_TYPE_DIRECT
:
MIB_IPROUTE_TYPE_INDIRECT
;
Row
.
dwForwardProto
=
MIB_IPPROTO_NETMGMT
;
Row
.
dwForwardAge
=
0
;
Row
.
dwForwardNextHopAS
=
0
;
Row
.
dwForwardMetric1
=
metric
;
Row
.
dwForwardMetric2
=
-
1
;
Row
.
dwForwardMetric3
=
-
1
;
Row
.
dwForwardMetric4
=
-
1
;
Row
.
dwForwardMetric5
=
-
1
;
switch
(
cmdflag
)
{
case
RTM_ADD
:
Res
=
CreateIpForwardEntry
(
&
Row
);
break
;
case
RTM_DELETE
:
Res
=
DeleteIpForwardEntry
(
&
Row
);
break
;
case
RTM_CHANGE
:
Res
=
SetIpForwardEntry
(
&
Row
);
break
;
default:
Res
=
-
1
;
break
;
}
if
(
Res
!=
NO_ERROR
)
return
-
1
;
}
/* Use route command */
else
{
/* route ADD dest MASK mask gate METRIC n IF index */
/* route CHANGE dest MASK mask gate METRIC n IF index */
/* route DELETE dest MASK mask gate METRIC n IF index */
const
int
MAX_BUFFER_SIZE
=
1024
;
char
cmdbuf
[
MAX_BUFFER_SIZE
];
char
sdest
[
INET_ADDRSTRLEN
];
char
sgate
[
INET_ADDRSTRLEN
];
char
smask
[
INET_ADDRSTRLEN
];
struct
in_addr
mask
;
plen2mask
(
plen
,
&
mask
);
if
(
NULL
==
inet_ntop
(
AF_INET
,
(
const
void
*
)(
&
(((
SOCKADDR_IN
*
)
dest
)
->
sin_addr
)),
sdest
,
INET_ADDRSTRLEN
))
return
-
1
;
if
(
NULL
==
inet_ntop
(
AF_INET
,
(
const
void
*
)(
&
(((
SOCKADDR_IN
*
)
gate
)
->
sin_addr
)),
sgate
,
INET_ADDRSTRLEN
))
return
-
1
;
if
(
NULL
==
inet_ntop
(
AF_INET
,
(
const
void
*
)(
&
mask
),
smask
,
INET_ADDRSTRLEN
))
return
-
1
;
if
(
snprintf
(
cmdbuf
,
MAX_BUFFER_SIZE
,
"route %s %s MASK %s %s METRIC %d IF %d"
,
cmdflag
==
RTM_ADD
?
"add"
:
cmdflag
==
RTM_DELETE
?
"delete"
:
"change"
,
sdest
,
smask
,
sgate
,
metric
,
ifindex
)
>=
MAX_BUFFER_SIZE
)
return
-
1
;
if
(
libwinet_run_command
(
cmdbuf
)
!=
0
)
return
-
1
;
}
#else
/* Add route entry after Windows Vista */
MIB_IPFORWARDROW2
Row2
;
unsigned
long
Res
;
memset
(
&
Row2
,
0
,
sizeof
(
MIB_IPFORWARDROW2
));
Row2
.
InterfaceLuid
=
NULL
;
Row2
.
InterfaceIndex
=
ifindex
;
Row2
.
DestinationPrefix
.
PrefixLength
=
plen
;
memcpy
(
&
Row2
.
DestinationPrefix
.
Prefix
,
dest
,
sizeof
(
SOCKADDR_INET
));
memcpy
(
&
Row2
.
NextHop
,
gate
,
sizeof
(
SOCKADDR_INET
))
;
Row2
.
SitePrefixLength
=
255
;
/* INVALID */
Row2
.
ValidLifetime
=
WSA_INFINITE
;;
Row2
.
PreferredLifetime
=
WSA_INFINITE
;
Row2
.
Metric
=
metric
;
Row2
.
Protocol
=
MIB_IPPROTO_NETMGMT
;
Row2
.
Loopback
=
gate
->
sa_family
==
AF_INET6
?
IN6_IS_ADDR_LOOPBACK
(
&
(((
SOCKADDR_IN6
*
)
gate
)
->
sin6_addr
))
:
IN_LOOPBACK
(
ntohl
(((
SOCKADDR_IN
*
)
gate
)
->
sin_addr
.
S_un
.
S_addr
));
Row2
.
AutoconfigureAddress
=
FALSE
;
Row2
.
Publish
=
FALSE
;
Row2
.
Immortal
=
0
;
Row2
.
Age
=
0
;
Row2
.
Origin
=
0
;
/* NlroManual */
switch
(
cmdflag
)
{
case
0
:
Res
=
CreateIpForwardEntry2
(
&
Row
);
break
;
case
1
:
Res
=
SetIpForwardEntry2
(
&
Row
);
break
;
case
2
:
Res
=
DeleteIpForwardEntry2
(
&
Row
);
break
;
}
if
(
Res
!=
NO_ERROR
)
return
-
1
;
}
#endif
/* _WIN32_WINNT < _WIN32_WINNT_VISTA */
return
1
;
}
static
int
libwinet_set_registry_key
(
char
*
key
,
char
*
name
,
int
value
,
int
defvalue
)
{
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
);
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
;
}
RegCloseKey
(
hKey
);
return
old
;
}
static
int
libwinet_get_loopback_index
(
int
family
)
{
IP_ADAPTER_ADDRESSES
*
pAdaptAddr
=
NULL
;
IP_ADAPTER_ADDRESSES
*
pTmpAdaptAddr
=
NULL
;
DWORD
dwRet
=
0
;
DWORD
dwSize
=
0x10000
;
DWORD
dwReturn
=
0
;
dwRet
=
GetAdaptersAddresses
(
family
,
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
(
family
,
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
(
IF_TYPE_SOFTWARE_LOOPBACK
==
pTmpAdaptAddr
->
IfType
)
{
dwReturn
=
family
==
AF_INET
?
pTmpAdaptAddr
->
IfIndex
:
pTmpAdaptAddr
->
Ipv6IfIndex
;
break
;
}
pTmpAdaptAddr
=
pTmpAdaptAddr
->
Next
;
}
}
FREE
(
pAdaptAddr
);
return
dwReturn
;
}
int
cyginet_set_ipv6_forwards
(
int
value
)
{
char
*
key
=
"SYSTEM
\\
CurrentControlSet
\\
Services
\\
Tcpip6
\\
Parameters"
;
return
libwinet_set_registry_key
(
key
,
"IPEnableRouter"
,
value
,
0
);
}
int
cyginet_set_icmp6_redirect_accept
(
int
value
)
{
char
*
key
=
"SYSTEM
\\
CurrentControlSet
\\
Services
\\
Tcpip6
\\
Parameters"
;
return
libwinet_set_registry_key
(
key
,
"EnableICMPRedirect"
,
value
,
1
);
}
/*
* On Windows Vista and later, wireless network cards are reported as
* IF_TYPE_IEEE80211 by the GetAdaptersAddresses function.
*
* On earlier versions of Windows, wireless network cards are reported
* as IF_TYPE_ETHERNET_CSMACD. On Windows XP with SP3 and on Windows
* XP with SP2 x86 with the Wireless LAN API for Windows XP with SP2
* installed, the WlanEnumInterfaces function can be used to enumerate
* wireless interfaces on the local computer.
*/
int
cyginet_interface_wireless
(
const
char
*
ifname
,
int
ifindex
)
{
LIBWINET_INTERFACE
winf
;
if
(
1
==
libwinet_get_interface_info
(
ifname
,
AF_INET6
,
ifindex
,
&
winf
))
{
if
(
IF_TYPE_IEEE80211
==
winf
.
IfType
)
return
1
;
#if _WIN32_WINNT < _WIN32_WINNT_VISTA
if
(
IF_TYPE_ETHERNET_CSMACD
==
winf
.
IfType
)
{
return
libwinet_is_wireless_interface
(
ifname
);
}
#endif
return
0
;
}
return
-
1
;
}
int
cyginet_interface_mtu
(
const
char
*
ifname
,
int
ifindex
)
{
LIBWINET_INTERFACE
winf
;
if
(
1
==
libwinet_get_interface_info
(
ifname
,
AF_INET6
,
ifindex
,
&
winf
))
return
winf
.
Mtu
;
return
-
1
;
}
int
cyginet_interface_operational
(
const
char
*
ifname
,
int
ifindex
)
{
LIBWINET_INTERFACE
winf
;
if
(
1
==
libwinet_get_interface_info
(
ifname
,
AF_INET6
,
ifindex
,
&
winf
))
return
winf
.
OperStatus
;
return
-
1
;
}
int
cyginet_interface_ipv4
(
const
char
*
ifname
,
int
ifindex
,
unsigned
char
*
addr_r
)
{
LIBWINET_INTERFACE
winf
;
if
(
1
==
libwinet_get_interface_info
(
ifname
,
AF_INET
,
ifindex
,
&
winf
))
{
memcpy
(
addr_r
,
&
((
struct
sockaddr_in
*
)
&
winf
.
Address
)
->
sin_addr
,
4
);
return
1
;
}
return
-
1
;
}
int
cyginet_interface_sdl
(
struct
sockaddr_dl
*
sdl
,
char
*
ifname
)
{
IP_ADAPTER_ADDRESSES
*
pAdaptAddr
=
NULL
;
IP_ADAPTER_ADDRESSES
*
pTmpAdaptAddr
=
NULL
;
DWORD
dwRet
=
0
;
DWORD
dwSize
=
0x10000
;
DWORD
dwReturn
=
-
1
;
DWORD
dwFamily
=
AF_UNSPEC
;
size_t
size
;
int
ifindex
;
if
(
0
==
(
ifindex
=
if_nametoindex
(
ifname
)))
return
-
1
;
dwRet
=
GetAdaptersAddresses
(
dwFamily
,
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
-
1
;
dwRet
=
GetAdaptersAddresses
(
dwFamily
,
GAA_FLAG_SKIP_ANYCAST
\
|
GAA_FLAG_SKIP_MULTICAST
\
|
GAA_FLAG_SKIP_DNS_SERVER
\
|
GAA_FLAG_SKIP_FRIENDLY_NAME
,
NULL
,
pAdaptAddr
,
&
dwSize
);
}
if
(
NO_ERROR
==
dwRet
)
{
pTmpAdaptAddr
=
pAdaptAddr
;
while
(
pTmpAdaptAddr
)
{
if
(
pTmpAdaptAddr
->
Ipv6IfIndex
==
ifindex
)
{
size
=
strlen
(
ifname
);
sdl
->
sdl_family
=
0
;
sdl
->
sdl_index
=
pTmpAdaptAddr
->
Ipv6IfIndex
;
sdl
->
sdl_type
=
pTmpAdaptAddr
->
IfType
;
sdl
->
sdl_nlen
=
size
;
sdl
->
sdl_alen
=
pTmpAdaptAddr
->
PhysicalAddressLength
;
sdl
->
sdl_slen
=
0
;
memcpy
(
sdl
->
sdl_data
,
ifname
,
size
);
memcpy
(
sdl
->
sdl_data
+
size
,
pTmpAdaptAddr
->
PhysicalAddress
,
pTmpAdaptAddr
->
PhysicalAddressLength
);
sdl
->
sdl_len
=
((
void
*
)(
sdl
->
sdl_data
)
-
(
void
*
)
sdl
)
+
size
\
+
pTmpAdaptAddr
->
PhysicalAddressLength
;
dwReturn
=
0
;
break
;
}
pTmpAdaptAddr
=
pTmpAdaptAddr
->
Next
;
}
}
FREE
(
pAdaptAddr
);
return
dwReturn
;
}
int
cyginet_loopback_index
(
int
family
)
{
return
libwinet_get_loopback_index
(
family
);
}
static
PMIB_IPFORWARDTABLE
libwinet_get_ipforward_table
(
int
forder
)
{
DWORD
dwSize
=
0
;
PMIB_IPFORWARDTABLE
pIpForwardTable
;
pIpForwardTable
=
(
PMIB_IPFORWARDTABLE
)
MALLOC
(
sizeof
(
MIB_IPFORWARDTABLE
));
if
(
NULL
==
pIpForwardTable
)
return
NULL
;
if
(
ERROR_INSUFFICIENT_BUFFER
==
GetIpForwardTable
(
pIpForwardTable
,
&
dwSize
,
forder
))
{
FREE
(
pIpForwardTable
);
pIpForwardTable
=
(
PMIB_IPFORWARDTABLE
)
MALLOC
(
dwSize
);
if
(
pIpForwardTable
==
NULL
)
return
NULL
;
}
if
(
NO_ERROR
==
GetIpForwardTable
(
pIpForwardTable
,
&
dwSize
,
forder
))
return
pIpForwardTable
;
return
NULL
;
}
/*
* There are 3 ways to dump route table in the Windows:
*
* Before Windows Vista
*
* 1. IPv4 route: GetIpForwardTable
*
* 2. IPv6 route: command "netsh"
*
* C:/> netsh interface ipv6 show route verbose
*
* In Windows Vista and later
*
* 3. API: GetIpForwardTable2
*
*/
int
cyginet_dump_route_table
(
struct
kernel_route
*
routes
,
int
maxroutes
)
{
ULONG
NumEntries
=
-
1
;
struct
kernel_route
*
proute
;
int
i
;
#if _WIN32_WINNT < _WIN32_WINNT_VISTA
/* First dump ipv6 route */
NumEntries
=
libwinet_dump_ipv6_route_table
(
routes
,
maxroutes
);
if
(
NumEntries
<
0
)
return
-
1
;
/* Then ipv4 route table */
SOCKADDR_IN
*
paddr
;
PMIB_IPFORWARDTABLE
pIpForwardTable
;
PMIB_IPFORWARDROW
pRow
;
if
(
NULL
==
(
pIpForwardTable
=
libwinet_get_ipforward_table
(
0
)))
return
-
1
;
{
proute
=
routes
+
NumEntries
;
NumEntries
+=
pIpForwardTable
->
dwNumEntries
;
if
(
NumEntries
>
maxroutes
)
{
FREE
(
pIpForwardTable
);
return
-
1
;
}
pRow
=
pIpForwardTable
->
table
;
for
(
i
=
0
;
i
<
(
int
)
pIpForwardTable
->
dwNumEntries
;
i
++
,
proute
++
,
pRow
++
)
{
/* libwinet_map_ifindex_to_ipv6ifindex */
proute
->
ifindex
=
pRow
->
dwForwardIfIndex
;
proute
->
metric
=
pRow
->
dwForwardMetric1
;
proute
->
proto
=
pRow
->
dwForwardProto
;
proute
->
plen
=
mask2len
((
unsigned
char
*
)
&
(
pRow
->
dwForwardMask
),
4
);
/* Note that the IPv4 addresses returned in GetIpForwardTable
* entries are in network byte order
*/
paddr
=
(
SOCKADDR_IN
*
)
proute
->
prefix
;
paddr
->
sin_family
=
AF_INET
;
(
paddr
->
sin_addr
).
S_un
.
S_addr
=
pRow
->
dwForwardDest
;
paddr
=
(
SOCKADDR_IN
*
)
proute
->
gw
;
paddr
->
sin_family
=
AF_INET
;
(
paddr
->
sin_addr
).
S_un
.
S_addr
=
pRow
->
dwForwardNextHop
;
}
FREE
(
pIpForwardTable
);
}
#else
PMIB_IPFORWARD_TABLE2
pIpForwardTable2
;
PMIB_IPFORWARD_ROW2
pRow2
;
/* From Windows Vista later, use GetIpForwardTable2 instead */
if
(
NO_ERROR
==
GetIpForwardTable2
(
family
,
pIpForwardTable2
0
))
{
if
(
pIpForwardTable2
->
NumEntries
<
maxroutes
)
{
proute
=
routes
+
NumEntries
;
NumEntries
=
pIpForwardTable2
->
dwNumEntries
;
pRow2
=
pIpForwardTable2
->
Table
;
for
(
i
=
0
;
i
<
NumEntries
;
i
++
,
proute
++
,
pRow2
++
)
{
proute
->
ifindex
=
pRow2
->
InterfaceIndex
;
proute
->
metric
=
pRow2
->
Metric
;
proute
->
proto
=
pRow2
->
Protocol
;
proute
->
plen
=
(
pRow2
->
DestinationPrefix
).
PrefixLength
;
memcpy
(
proute
->
prefix
,
(
pRow2
->
DestinationPrefix
).
DestinationPrefix
,
sizeof
(
SOCKADDR_INET
)
);
memcpy
(
proute
->
gw
,
pRow2
->
NextHop
,
sizeof
(
SOCKADDR_INET
)
);
}
}
FreeMibTable
(
pIpForwardTable2
);
}
#endif
return
NumEntries
;
}
int
cyginet_add_route_entry
(
const
struct
sockaddr
*
dest
,
unsigned
short
plen
,
const
struct
sockaddr
*
gate
,
int
ifindex
,
unsigned
int
metric
)
{
return
libwinet_edit_route_entry
(
dest
,
plen
,
gate
,
ifindex
,
metric
,
1
);
}
int
cyginet_delete_route_entry
(
const
struct
sockaddr
*
dest
,
unsigned
short
plen
,
const
struct
sockaddr
*
gate
,
int
ifindex
,
unsigned
int
metric
)
{
return
libwinet_edit_route_entry
(
dest
,
plen
,
gate
,
ifindex
,
metric
,
2
);
}
int
cyginet_update_route_entry
(
const
struct
sockaddr
*
dest
,
unsigned
short
plen
,
const
struct
sockaddr
*
gate
,
int
ifindex
,
unsigned
int
metric
)
{
return
libwinet_edit_route_entry
(
dest
,
plen
,
gate
,
ifindex
,
metric
,
3
);
}
/*
* This function is used to read route socket to get changes of route
* table, and return a struct rt_msghdr in the buffer. However I can't
* find windows API to implement it.
*/
int
cyginet_read_route_socket
(
void
*
buffer
,
size_t
size
)
{
/* TODO */
return
0
;
}
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
);
}
void
cyginet_cleanup
()
{
WSACleanup
();
}
/* The following functions are reserved. */
#if 0
static int
convert_ipv6_route_table2()
{
const MAX_LINE_SIZE = 80;
const char * command = "netsh interface ipv6 show route verbose";
/* One example entry of netsh output
Prefix : fe80::1/128
Interface 1 : Loopback Pseudo-Interface
Gateway : fe80::1
Metric : 4
Publish : no
Type : System
Valid Lifetime : infinite
Preferred Lifetime: infinite
Site Prefix Length: 0
*/
FILE *output;
char buffer[MAX_LINE_SIZE];
int index = -1;
size_t size;
char *s, *p;
int ifindex;
MIB_IPFORWARD_ROW2 iprow;
MIB_IPFORWARD_ROW2 *piprow = &iprow;
output = popen (command, "r");
if (!output)
return -1;
/* Ignore the first line */
fgets(buffer, MAX_LINE_SIZE, output);
memset(piprow, 0, sizeof(MIB_IPFORWARD_ROW2));
piprow -> Protocol = MIB_IPPROTO_OTHER;
/* Read the output until EOF */
while (fgets(buffer, MAX_LINE_SIZE, output)) {
if (('\n' == buffer[0]) || ('\r' == buffer[0]))
continue;
if (NULL == (s = strchr(buffer, ':')))
break;
*s ++ = 0;
s ++;
if (strncmp(buffer, "Prefix", 6) == 0) {
index ++;
if (NULL == (p = strchr(s, '/')))
break;
*p ++ = 0;
if (WSAStringToAddress(s,
AF_INET6,
NULL,
(LPSOCKADDR)(&(piprow -> DestinationPrefix.Prefix)),
&size
) == SOCKET_ERROR)
break;
piprow -> DestinationPrefix.PrefixLength = strtol(p, NULL, 10);
}
else if (strncmp(buffer, "Interface", 9) == 0) {
ifindex = strtol(buffer + 9, NULL, 10);
piprow -> InterfaceIndex = ifindex;
}
else if (strncmp(buffer, "Gateway", 7) == 0) {
/* NextHop */
/* Loopback: A value that specifies if the route is a loopback
route (the gateway is on the local host). */
}
else if (strncmp(buffer, "Metric", 6) == 0)
piprow -> Metric = strtol(s, NULL, 10);
else if (strncmp(buffer, "Publish", 7) == 0)
piprow -> Publish = (strncmp("yes", s, 3) == 0);
else if (strncmp(buffer, "Type", 4) == 0) {
if (strncmp("Manual", s, 6) == 0) {
piprow -> Origin = NlroManual;
}
else if (strncmp("System", s, 6) == 0) {
piprow -> Origin = NlroDHCP;
}
else if (strncmp("Autoconf", s, 8) == 0) {
piprow -> Origin = Nlro6to4;
piprow -> AutoconfigureAddress = 1;
}
}
else if (strncmp(buffer, "Valid Lifetime", 14) == 0)
piprow -> ValidLifetime = convert_time_from_string_to_ulong(s);
else if (strncmp(buffer, "Preferred Lifetime", 18) == 0)
piprow -> PreferredLifetime = convert_time_from_string_to_ulong(s);
else if (strncmp(buffer, "Site Prefix Length", 18) == 0)
piprow -> SitePrefixLength = (UCHAR)strtol(s, NULL, 10);
else {
/* Immortal: persistent entry */
/* Age */
break;
}
}
/* Return the exit code of command */
return pclose (output);
}
/*
* Output format: struct rt_msghdr
*
* rtm_msglen
*
* rtm_type = RTM_GET
*
* rtm_index = IfIndex for Ipv4
* Ipv6IfIndex for Ipv6
*
* rtm_flags = RTF_HOST: All netmask bits are 1.
* RTF_GATEWAY: Destination is a gateway.
*
* rtm_addrs = RTA_DST RTA_GATEWAY RTA_NETMASK
* rtm_errno Set when failed.
*
* RTF_HOST: Set when all netmask bits are 1
*
* RTF_GATEWAY: Set when gateway is not local address.
* dwForwardNextHop is not
*
*/
static int
convert_ipv6_route_table_to_rtm(struct rt_msghdr *rtm,
int maxroutes)
{
const MAX_LINE_SIZE = 80;
const char * command = "netsh interface ipv6 show route verbose";
/* One example entry of netsh output
Prefix : fe80::1/128
Interface 1 : Loopback Pseudo-Interface
Gateway : fe80::1
Metric : 4
Publish : no
Type : System
Valid Lifetime : infinite
Preferred Lifetime: infinite
Site Prefix Length: 0
*/
FILE *output;
char buffer[MAX_LINE_SIZE];
int index = -1;
size_t size;
char *s, *p;
int ifindex;
int start = 0;
SOCKADDR *sa;
int msg_len = sizeof(struct rt_msghdr) + 3 * sizeof(SOCKADDR);
output = popen (command, "r");
if (!output)
return -1;
/* Ignore the first line */
fgets(buffer, MAX_LINE_SIZE, output);
/* Read the output until EOF */
while (fgets(buffer, MAX_LINE_SIZE, output)) {
if (('\n' == buffer[0]) || ('\r' == buffer[0]))
continue;
if (NULL == (s = strchr(buffer, ':')))
break;
*s ++ = 0;
s ++;
if (strncmp(buffer, "Prefix", 6) == 0) {
rtm -> rtm_msglen = msg_len;
rtm -> rtm_version = RTM_VERSION;
rtm -> rtm_type = RTM_GET;
rtm -> rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
sa = (SOCKADDR*)(rtm + 1);
if (NULL == (p = strchr(s, '/')))
break;
*p ++ = 0;
if (WSAStringToAddress(s,
AF_INET6,
NULL,
sa,
&size
) == SOCKET_ERROR)
break;
// PrefixLength = strtol(p, NULL, 10);
sa ++;
}
else if (strncmp(buffer, "Interface", 9) == 0)
rtm -> rtm_index = strtol(buffer + 9, NULL, 10);
else if (strncmp(buffer, "Gateway", 7) == 0) {
/* NextHop */
/* Loopback: A value that specifies if the route is a loopback
route (the gateway is on the local host). */
if (WSAStringToAddress(s,
AF_INET6,
NULL,
sa,
&size
) == SOCKET_ERROR)
break;
sa ++;
/* Netmask */
}
else if (strncmp(buffer, "Site Prefix Length", 18) == 0) {
rtm = (struct rt_msghdr*)((void*)rtm + msg_len);
start ++;
if (start > maxroutes)
break;
}
else {
/* Immortal: persistent entry */
/* Age */
}
}
pclose (output);
return start;
}
static int
libwinet_map_ifindex_to_ipv6ifindex(int ifindex)
{
IP_ADAPTER_ADDRESSES *pAdaptAddr = NULL;
IP_ADAPTER_ADDRESSES *pTmpAdaptAddr = NULL;
DWORD dwRet = 0;
DWORD dwSize = 0x10000;
DWORD dwReturn = 0;
DWORD Family = AF_UNSPEC;
dwRet = GetAdaptersAddresses(Family,
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(Family,
GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
| GAA_FLAG_SKIP_DNS_SERVER \
| GAA_FLAG_SKIP_FRIENDLY_NAME,
NULL,
pAdaptAddr,
&dwSize
);
}
if (NO_ERROR == dwRet) {
pTmpAdaptAddr = pAdaptAddr;
while (pTmpAdaptAddr) {
if (pTmpAdaptAddr -> IfIndex == ifindex) {
dwReturn = pTmpAdaptAddr -> Ipv6IfIndex;
break;
}
pTmpAdaptAddr = pTmpAdaptAddr->Next;
}
}
FREE(pAdaptAddr);
return dwReturn;
}
static ULONG
convert_time_from_string_to_ulong(const char * stime)
{
char *s;
long k;
long result;
if (strncmp(stime, "infinite", 8) == 0)
return WSA_INFINITE;
result = 0;
s = (char*)stime;
do {
k = strtol(s, &s, 10);
if (*s == 's') {
result += k;
s = NULL;
}
else if (*s == 'm') {
result += 60 * k;
s ++;
}
else if (*s == 'h') {
result += 3600 * k;
s ++;
}
else if (*s == 'd') {
result += 3600 * 24 * k;
s ++;
}
else s = NULL;
} while (s);
return result;
}
/*
* It's another way to tell wireless netcard, query device status by
* DeviceIoControl.
*
*/
#if !defined OID_802_11_CONFIGURATION
#define OID_802_11_CONFIGURATION 0x0d010211
#endif
#if !defined IOCTL_NDIS_QUERY_GLOBAL_STATS
#define IOCTL_NDIS_QUERY_GLOBAL_STATS 0x00170002
#endif
static int
libwinet_is_wireless_device(const wchar_t *pszwAdapterName)
{
const int MAX_DEV_NAME_LEN = 45;
const int MAX_OUT_BUF_SIZE = 100;
wchar_t DevName[MAX_DEV_NAME_LEN];
HANDLE DevHand;
unsigned int ErrNo;
unsigned int Oid;
unsigned char OutBuff[MAX_OUT_BUF_SIZE];
unsigned long OutBytes;
if (swprintf(DevName,
MAX_DEV_NAME_LEN,
L"\\\\.\\%ls",
pszwAdapterName
) >= MAX_DEV_NAME_LEN)
return -1;
DevHand = CreateFileW(DevName,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (DevHand == INVALID_HANDLE_VALUE) {
ErrNo = GetLastError();
return -1;
}
Oid = OID_802_11_CONFIGURATION;
if (!DeviceIoControl(DevHand,
IOCTL_NDIS_QUERY_GLOBAL_STATS,
&Oid,
sizeof(Oid),
OutBuff,
sizeof(OutBuff),
&OutBytes,
NULL
)) {
ErrNo = GetLastError();
CloseHandle(DevHand);
/* OID not supported. Device probably not wireless. */
if ((ErrNo == ERROR_GEN_FAILURE)
|| (ErrNo == ERROR_INVALID_PARAMETER)
|| ErrNo == ERROR_NOT_SUPPORTED) {
return 0;
}
/* DeviceIoControl() Error */
return -1;
}
CloseHandle(DevHand);
return 1;
}
static int
libwinet_ipv6_interfaces_forwards(int forward)
{
const int MAX_BUFFER_SIZE = 80;
char cmdbuf[MAX_BUFFER_SIZE];
int result;
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,
"ipv6 ifc %d %cforward",
p -> if_index,
forward ? ' ' : '-'
) >= MAX_BUFFER_SIZE)
break;
if (libwinet_run_command(cmdbuf) != 0)
break;
p ++;
}
result = ! (p -> if_index);
if_freenameindex(ptr);
return result;
}
BOOL RouteLookup(SOCKADDR *destAddr,
int destLen,
SOCKADDR *localAddr,
int localLen)
{
DWORD dwBytes = 0;
BOOL bRet = TRUE;
CHAR szAddr[MAX_PATH] = {0};
SOCKET s = INVALID_SOCKET;
if (INVALID_SOCKET == (s = socket(destAddr->sa_family,SOCK_DGRAM,0)))
{
SOCKETERR("socket");
return FALSE;
}
if (SOCKET_ERROR == WSAIoctl(s,
SIO_ROUTING_INTERFACE_QUERY,
destAddr,
destLen,
localAddr,
localLen,
&dwBytes,
NULL,
NULL
))
{
SOCKETERR("WSAIoctl");
bRet = FALSE;
}
if (bRet)
{
dwBytes = sizeof(szAddr);
ZeroMemory(szAddr,dwBytes);
WSAAddressToStringA(destAddr,
(DWORD)destLen,
NULL,
szAddr,
&dwBytes
);
dwBytes = sizeof(szAddr);
ZeroMemory(szAddr,dwBytes);
WSAAddressToStringA(localAddr,
(DWORD)localLen,
NULL,
szAddr,
&dwBytes
);
}
CLOSESOCKET(s);
return bRet;
}
DWORD GetInterfaceIndexForAddress(SOCKADDR *pAddr)
{
IP_ADAPTER_UNICAST_ADDRESS *pTmpUniAddr = NULL;
IP_ADAPTER_ADDRESSES *pAdaptAddr = NULL;
IP_ADAPTER_ADDRESSES *pTmpAdaptAddr = NULL;
BOOL bFound = FALSE;
DWORD dwRet = 0;
DWORD dwReturn = (DWORD) SOCKET_ERROR;
DWORD dwSize = 0x10000;
DWORD Family = AF_UNSPEC;
switch (pAddr->sa_family) {
case AF_INET:
Family = AF_INET;
break;
case AF_INET6:
Family = AF_INET6;
break;
default:
WSASetLastError(WSAEAFNOSUPPORT);
break;
}
if (NULL == (pAdaptAddr = (IP_ADAPTER_ADDRESSES*)MALLOC(dwSize)))
return -1;
dwRet = GetAdaptersAddresses(Family,
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 -1;
dwRet = GetAdaptersAddresses(Family,
GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
|GAA_FLAG_SKIP_DNS_SERVER,
NULL,
pAdaptAddr,
&dwSize
);
}
if (NO_ERROR == dwRet) {
pTmpAdaptAddr = pAdaptAddr;
while (pTmpAdaptAddr) {
//look at each IP_ADAPTER_UNICAST_ADDRESS node
pTmpUniAddr = pTmpAdaptAddr->FirstUnicastAddress;
while (pTmpUniAddr) {
if (AF_INET == pTmpUniAddr->Address.lpSockaddr->sa_family) {
/* IN4_ADDR_EQUAL */
if (memcmp(&((SOCKADDR_IN*)pAddr)->sin_addr,
&((SOCKADDR_IN*)pTmpUniAddr->Address.lpSockaddr)->sin_addr,
sizeof(SOCKADDR_IN)
) == 0)
{
dwReturn = pTmpAdaptAddr->IfIndex;
bFound = TRUE;
break;
}
}
else {
/* IN6_ADDR_EQUAL */
if (memcmp(&((SOCKADDR_IN6*)pAddr)->sin6_addr,
&((SOCKADDR_IN6*)pTmpUniAddr->Address.lpSockaddr)->sin6_addr,
sizeof(SOCKADDR_IN6)
) == 0)
{
dwReturn = pTmpAdaptAddr->Ipv6IfIndex;
bFound = TRUE;
break;
}
}
pTmpUniAddr = pTmpUniAddr->Next;
}
if (bFound)
break;
pTmpAdaptAddr = pTmpAdaptAddr->Next;
}
}
FREE(pAdaptAddr);
return dwReturn;
}
VOID PrintAllInterfaces()
{
IP_ADAPTER_ADDRESSES *pAdaptAddr = NULL;
IP_ADAPTER_ADDRESSES *pTmpAdaptAddr = NULL;
DWORD dwRet = 0;
DWORD dwSize = 0x10000;
DWORD Family = AF_UNSPEC;
if (NULL == (pAdaptAddr = (IP_ADAPTER_ADDRESSES*)MALLOC(dwSize))) {
printf("Memory error.\n");
return ;
}
dwRet = GetAdaptersAddresses(Family,
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))) {
printf("Memory error.\n");
return ;
}
dwRet = GetAdaptersAddresses(Family,
GAA_FLAG_SKIP_ANYCAST \
| GAA_FLAG_SKIP_MULTICAST \
|GAA_FLAG_SKIP_DNS_SERVER,
NULL,
pAdaptAddr,
&dwSize
);
}
if (NO_ERROR == dwRet) {
pTmpAdaptAddr = pAdaptAddr;
while (pTmpAdaptAddr) {
printf("If6Index:\t %ld\n", pTmpAdaptAddr -> Ipv6IfIndex);
printf("If4Index:\t %ld\n", pTmpAdaptAddr -> IfIndex);
printf("Friendly Name:\t %S\n", pTmpAdaptAddr -> FriendlyName);
printf("Adapter Name:\t %s\n", pTmpAdaptAddr -> AdapterName);
printf("IfType:\t %ld\n", pTmpAdaptAddr -> IfType);
printf("Oper Status:\t %d\n", pTmpAdaptAddr -> OperStatus);
printf("\n\n");
pTmpAdaptAddr = pTmpAdaptAddr->Next;
}
}
else
printf("GetAdaptersAddresses failed.\n");
FREE(pAdaptAddr);
}
void WaitForNetworkChnages()
{
WSAQUERYSET querySet = {0};
querySet.dwSize = sizeof(WSAQUERYSET);
querySet.dwNameSpace = NS_NLA;
HANDLE LookupHandle = NULL;
WSALookupServiceBegin(&querySet, LUP_RETURN_ALL, &LookupHandle);
DWORD BytesReturned = 0;
WSANSPIoctl(LookupHandle,
SIO_NSP_NOTIFY_CHANGE,
NULL,
0,
NULL,
0,
&BytesReturned,
NULL
);
WSALookupServiceEnd(LookupHandle);
}
DWORD GetConnectedNetworks()
{
WSAQUERYSET qsRestrictions;
DWORD dwControlFlags;
HANDLE hLookup;
DWORD dwCount = 0;
ZeroMemory(&qsRestrictions, sizeof(WSAQUERYSET));
qsRestrictions.dwSize = sizeof(WSAQUERYSET);
qsRestrictions.dwNameSpace = NS_ALL;
dwControlFlags = LUP_RETURN_ALL;
int result = WSALookupServiceBegin(&qsRestrictions,
dwControlFlags, &hLookup);
DWORD dwBufferLength;
WSAQUERYSET qsResult;
while (0 == result)
{
ZeroMemory(&qsResult, sizeof(WSAQUERYSET));
result = WSALookupServiceNext(hLookup,
LUP_RETURN_NAME,
&dwBufferLength,
&qsResult
);
dwCount ++;
}
result = WSALookupServiceEnd(hLookup);
return dwCount;
}
#endif /* Unused */
/* ------------------------------------------------------------- */
/* */
/* The following functions are used to test or verify something. */
/* */
/* ------------------------------------------------------------- */
#ifdef TEST_CYGINET
static
int
libwinet_set_forward_entry
(
char
*
pszDest
,
char
*
pszNetMask
,
char
*
pszGateway
,
DWORD
dwIfIndex
,
DWORD
dwMetric
)
{
DWORD
dwStatus
;
MIB_IPFORWARDROW
routeEntry
;
// Ip routing table row entry
memset
(
&
routeEntry
,
0
,
sizeof
(
MIB_IPFORWARDROW
));
// converting and checking input arguments...
if
(
pszDest
==
NULL
||
pszNetMask
==
NULL
||
pszGateway
==
NULL
)
{
printf
(
"IpRoute: Bad Argument
\n
"
);
return
-
1
;
}
routeEntry
.
dwForwardDest
=
inet_addr
(
pszDest
);
// convert dotted ip addr. to ip addr.
if
(
routeEntry
.
dwForwardDest
==
INADDR_NONE
)
{
printf
(
"IpRoute: Bad Destination %s
\n
"
,
pszDest
);
return
-
1
;
}
routeEntry
.
dwForwardMask
=
inet_addr
(
pszNetMask
);
if
(
(
routeEntry
.
dwForwardMask
==
INADDR_NONE
)
&&
(
strcmp
(
"255.255.255.255"
,
pszNetMask
)
!=
0
)
)
{
printf
(
"IpRoute: Bad Mask %s
\n
"
,
pszNetMask
);
return
-
1
;
}
routeEntry
.
dwForwardNextHop
=
inet_addr
(
pszGateway
);
if
(
routeEntry
.
dwForwardNextHop
==
INADDR_NONE
)
{
printf
(
"IpRoute: Bad Gateway %s
\n
"
,
pszGateway
);
return
-
1
;
}
if
(
(
routeEntry
.
dwForwardDest
&
routeEntry
.
dwForwardMask
)
!=
routeEntry
.
dwForwardDest
)
{
printf
(
"IpRoute: Invalid Mask %s
\n
"
,
pszNetMask
);
return
-
1
;
}
routeEntry
.
dwForwardIfIndex
=
dwIfIndex
;
routeEntry
.
dwForwardMetric1
=
dwMetric
;
// some default values
routeEntry
.
dwForwardProto
=
MIB_IPPROTO_NETMGMT
;
routeEntry
.
dwForwardMetric2
=
(
DWORD
)
-
1
;
routeEntry
.
dwForwardMetric3
=
(
DWORD
)
-
1
;
routeEntry
.
dwForwardMetric4
=
(
DWORD
)
-
1
;
dwStatus
=
SetIpForwardEntry
(
&
routeEntry
);
if
(
dwStatus
!=
NO_ERROR
)
{
printf
(
"IpRoute: couldn't add (%s), dwStatus = %lu.
\n
"
,
pszDest
,
dwStatus
);
return
-
1
;
}
return
0
;
}
static
void
runTestCases
()
{
printf
(
"
\n\n
Test getifaddrs works in the Cygwin:
\n\n
"
);
{
struct
ifaddrs
*
piftable
,
*
pif
;
getifaddrs
(
&
piftable
);
for
(
pif
=
piftable
;
pif
!=
NULL
;
pif
=
pif
->
ifa_next
)
printf
(
"Iterface name is %s
\n
"
,
pif
->
ifa_name
);
freeifaddrs
(
piftable
);
}
printf
(
"
\n\n
Test if_indexname works in the Cygwin:
\n\n
"
);
{
struct
if_nameindex
*
ptr
=
(
struct
if_nameindex
*
)
if_nameindex
();
if
(
ptr
)
{
struct
if_nameindex
*
p
=
ptr
;
while
(
p
->
if_index
)
{
printf
(
"%d
\t\t
%s
\n
"
,
p
->
if_index
,
p
->
if_name
);
p
++
;
}
if_freenameindex
(
ptr
);
}
}
printf
(
"
\n\n
Test if_indextoname works in the Cygwin:
\n\n
"
);
{
CHAR
ifname
[
256
];
if
(
if_indextoname
(
1
,
ifname
))
printf
(
"Interface Index 1: %s
\n
"
,
ifname
);
else
printf
(
"if_indextoname failed
\n
"
);
}
#if _WIN32_WINNT < _WIN32_WINNT_VISTA
printf
(
"
\n\n
Test libwinet_dump_ipv6_route_table:
\n\n
"
);
{
struct
kernel_route
routes
[
100
];
memset
(
routes
,
0
,
sizeof
(
struct
kernel_route
)
*
100
);
int
n
=
libwinet_dump_ipv6_route_table
(
routes
,
100
);
printf
(
"Get route numbers: %d
\n
"
,
n
);
}
printf
(
"
\n\n
Test libwinet_run_command:
\n\n
"
);
{
printf
(
"ls command return %d
\n
"
,
libwinet_run_command
(
"ls"
));
}
printf
(
"
\n\n
Test libwinet_is_wireless_interface:
\n\n
"
);
{
struct
if_nameindex
*
ptr
=
(
struct
if_nameindex
*
)
if_nameindex
();
if
(
ptr
)
{
struct
if_nameindex
*
p
=
ptr
;
while
(
p
->
if_index
)
{
printf
(
"%s is wireless netcard: %d
\n
"
,
p
->
if_name
,
libwinet_is_wireless_interface
(
p
->
if_name
)
);
p
++
;
}
if_freenameindex
(
ptr
);
}
}
#endif
/* _WIN32_WINNT < _WIN32_WINNT_VISTA */
printf
(
"
\n\n
Test libwinet_get_loopback_index:
\n\n
"
);
{
printf
(
"Ipv4 loopback ifindex is %d
\n
"
,
libwinet_get_loopback_index
(
AF_INET
)
);
printf
(
"Ipv6 loopback ifindex is %d
\n
"
,
libwinet_get_loopback_index
(
AF_INET6
)
);
}
printf
(
"
\n\n
Test cyginet_set_ipv6_forwards:
\n\n
"
);
{
printf
(
"cyginet_set_ipv6_forwards(1) return %d
\n
"
,
cyginet_set_ipv6_forwards
(
1
)
);
printf
(
"cyginet_set_ipv6_forwards(0) return %d
\n
"
,
cyginet_set_ipv6_forwards
(
0
)
);
}
printf
(
"
\n\n
Test cyginet_set_icmp6_redirect_accept:
\n\n
"
);
{
printf
(
"cyginet_set_icmp6_redirect_accept(0) return %d
\n
"
,
cyginet_set_icmp6_redirect_accept
(
0
)
);
printf
(
"cyginet_set_icmp6_redirect_accept(1) return %d
\n
"
,
cyginet_set_icmp6_redirect_accept
(
1
)
);
}
printf
(
"
\n\n
Test cyginet_interface_wireless:
\n\n
"
);
{
struct
if_nameindex
*
ptr
=
(
struct
if_nameindex
*
)
if_nameindex
();
if
(
ptr
)
{
struct
if_nameindex
*
p
=
ptr
;
int
n
;
while
(
p
->
if_index
)
{
n
=
cyginet_interface_wireless
(
p
->
if_name
,
p
->
if_index
);
printf
(
"%s is wireless netcard: %d
\n
"
,
p
->
if_name
,
n
);
p
++
;
}
if_freenameindex
(
ptr
);
}
}
printf
(
"
\n\n
Test cyginet_interface_mtu:
\n\n
"
);
{
struct
if_nameindex
*
ptr
=
(
struct
if_nameindex
*
)
if_nameindex
();
if
(
ptr
)
{
struct
if_nameindex
*
p
=
ptr
;
int
n
;
while
(
p
->
if_index
)
{
n
=
cyginet_interface_mtu
(
p
->
if_name
,
p
->
if_index
);
printf
(
"mtu of %s is : %d
\n
"
,
p
->
if_name
,
n
);
p
++
;
}
if_freenameindex
(
ptr
);
}
}
printf
(
"
\n\n
Test cyginet_interface_operational:
\n\n
"
);
{
struct
if_nameindex
*
ptr
=
(
struct
if_nameindex
*
)
if_nameindex
();
if
(
ptr
)
{
struct
if_nameindex
*
p
=
ptr
;
int
n
;
while
(
p
->
if_index
)
{
n
=
cyginet_interface_operational
(
p
->
if_name
,
p
->
if_index
);
printf
(
"%s is up: %d
\n
"
,
p
->
if_name
,
n
);
p
++
;
}
if_freenameindex
(
ptr
);
}
}
printf
(
"
\n\n
Test cyginet_interface_ipv4:
\n\n
"
);
{
struct
sockaddr_in
sa
;
struct
if_nameindex
*
ptr
=
(
struct
if_nameindex
*
)
if_nameindex
();
if
(
ptr
)
{
struct
if_nameindex
*
p
=
ptr
;
int
n
;
while
(
p
->
if_index
)
{
memset
(
&
sa
,
0
,
sizeof
(
sa
));
n
=
cyginet_interface_ipv4
(
p
->
if_name
,
p
->
if_index
,
(
unsigned
char
*
)
&
sa
);
printf
(
"get ipv4 from %s: %d
\n
"
,
p
->
if_name
,
n
);
p
++
;
}
if_freenameindex
(
ptr
);
}
}
printf
(
"
\n\n
Test cyginet_interface_sdl:
\n\n
"
);
{
struct
sockaddr_dl
sdl
;
struct
if_nameindex
*
ptr
=
(
struct
if_nameindex
*
)
if_nameindex
();
if
(
ptr
)
{
struct
if_nameindex
*
p
=
ptr
;
int
n
;
while
(
p
->
if_index
)
{
memset
(
&
sdl
,
0
,
sizeof
(
struct
sockaddr_dl
));
n
=
cyginet_interface_sdl
(
&
sdl
,
p
->
if_name
);
printf
(
"get sdl from %s: %d
\n
"
,
p
->
if_name
,
n
);
if
(
0
==
n
)
{
printf
(
"sdl_len is %d
\n
"
,
sdl
.
sdl_len
);
printf
(
"sdl_nlen is %d
\n
"
,
sdl
.
sdl_nlen
);
printf
(
"sdl_alen is %d
\n
"
,
sdl
.
sdl_alen
);
}
p
++
;
}
if_freenameindex
(
ptr
);
}
}
printf
(
"
\n\n
Test libwinet_monitor_route_thread_proc:
\n\n
"
);
do
{
int
mypipes
[
2
];
int
n
;
char
*
cmd1
=
"netsh interface ipv6 add route 3ffe::/16 1 fe80::1"
;
char
*
cmd2
=
"netsh interface ipv6 delete route 3ffe::/16 1 fe80::1"
;
// char *cmd3 = "netsh interface ipv6 update route 3ffe::/16 1 fe80::1";
if
(
-
1
==
pipe
(
mypipes
))
break
;
n
=
cyginet_start_monitor_route_changes
(
mypipes
[
1
]);
if
(
n
==
0
)
{
char
ch
=
' '
;
printf
(
"Run command: %s
\n
"
,
cmd1
);
libwinet_run_command
(
cmd1
);
Sleep
(
100
);
if
(
read
(
mypipes
[
0
],
&
ch
,
1
)
==
1
)
printf
(
"Event number is %c
\n
"
,
ch
);
printf
(
"Run command: %s
\n
"
,
cmd2
);
libwinet_run_command
(
cmd2
);
Sleep
(
100
);
if
(
read
(
mypipes
[
0
],
&
ch
,
1
)
==
1
)
printf
(
"Event number is %c
\n
"
,
ch
);
cyginet_stop_monitor_route_changes
();
}
close
(
mypipes
[
0
]);
close
(
mypipes
[
1
]);
}
while
(
0
);
printf
(
"
\n\n
Test select and pipe with
\n
"
);
printf
(
"
\t
cyginet_start_monitor_route_changes
\n
"
);
printf
(
"
\t
cyginet_stop_monitor_route_changes
\n\n
"
);
do
{
break
;
/* We don't run it beacuse it need
manual intervention. */
int
mypipes
[
2
];
int
n
;
fd_set
readfds
;
char
buf
[
16
];
if
(
-
1
==
pipe
(
mypipes
))
break
;
if
(
fcntl
(
mypipes
[
0
],
F_SETFL
,
O_NONBLOCK
)
<
0
)
printf
(
"Error set NONBLOCK
\n
"
);
FD_ZERO
(
&
readfds
);
n
=
cyginet_start_monitor_route_changes
(
mypipes
[
1
]);
if
(
n
==
0
)
{
FD_SET
(
mypipes
[
0
],
&
readfds
);
printf
(
"Please disable/enable your netcard or plug/unplug "
"netting wire so as to change route table.
\n
"
);
fflush
(
NULL
);
printf
(
"select return: %d
\n
"
,
select
(
FD_SETSIZE
,
&
readfds
,
NULL
,
NULL
,
NULL
)
);
memset
(
buf
,
0
,
16
);
printf
(
"read pipe, return %d
\n
"
,
read
(
mypipes
[
0
],
buf
,
16
));
printf
(
"Event number is %s
\n
"
,
buf
);
cyginet_stop_monitor_route_changes
();
}
close
(
mypipes
[
0
]);
close
(
mypipes
[
1
]);
}
while
(
0
);
printf
(
"
\n\n
Test cyginet_dump_route_table:
\n\n
"
);
do
{
#define MAX_ROUTES 120
struct
kernel_route
routes
[
MAX_ROUTES
];
memset
(
routes
,
0
,
sizeof
(
struct
kernel_route
)
*
MAX_ROUTES
);
int
n
=
cyginet_dump_route_table
(
routes
,
MAX_ROUTES
);
printf
(
"Get route numbers: %d
\n
"
,
n
);
}
while
(
0
);
printf
(
"
\n\n
Test libwinet_edit_route_entry:
\n\n
"
);
do
{
SOCKADDR
*
dest
;
SOCKADDR
*
gate
;
SOCKADDR_IN
dest4
=
{
AF_INET
,
0
,
{{{
INADDR_ANY
}}},
{
0
}
};
SOCKADDR_IN
gate4
=
{
AF_INET
,
0
,
{{{
INADDR_ANY
}}},
{
0
}
};
SOCKADDR_IN6
dest6
=
{
AF_INET6
,
0
,
0
,
{{
IN6ADDR_ANY_INIT
}}
};
SOCKADDR_IN6
gate6
=
{
AF_INET6
,
0
,
0
,
{{
IN6ADDR_ANY_INIT
}}
};
int
prefix
;
unsigned
int
metric
;
int
ifindex
;
int
n
;
printf
(
"libwinet_set_forward_entry return %d
\n
"
,
libwinet_set_forward_entry
(
"192.168.128.250"
,
"255.255.255.255"
,
"192.168.128.200"
,
2
,
20
)
);
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
)
break
;
ifindex
=
2
;
metric
=
3
;
prefix
=
32
;
dest
=
(
SOCKADDR
*
)
&
dest4
;
gate
=
(
SOCKADDR
*
)
&
gate4
;
n
=
libwinet_edit_route_entry
(
dest
,
prefix
,
gate
,
ifindex
,
metric
,
RTM_ADD
);
printf
(
"Add Ipv4 route return %d
\n
"
,
n
);
n
=
libwinet_edit_route_entry
(
dest
,
prefix
,
gate
,
ifindex
,
metric
,
RTM_CHANGE
);
printf
(
"Change Ipv4 route return %d
\n
"
,
n
);
metric
=
15
;
n
=
libwinet_edit_route_entry
(
dest
,
prefix
,
gate
,
ifindex
,
metric
,
RTM_DELETE
);
printf
(
"Delete Ipv4 route return %d
\n
"
,
n
);
if
(
inet_pton
(
AF_INET6
,
"3ffe::"
,
&
dest6
.
sin6_addr
)
!=
1
)
break
;
if
(
inet_pton
(
AF_INET6
,
"fe80::1"
,
&
gate6
.
sin6_addr
)
!=
1
)
break
;
prefix
=
112
;
metric
=
1200
;
ifindex
=
1
;
dest
=
(
SOCKADDR
*
)
&
dest6
;
gate
=
(
SOCKADDR
*
)
&
gate6
;
n
=
libwinet_edit_route_entry
(
dest
,
prefix
,
gate
,
ifindex
,
metric
,
RTM_ADD
);
printf
(
"Add Ipv6 route return %d
\n
"
,
n
);
metric
=
1100
;
n
=
libwinet_edit_route_entry
(
dest
,
prefix
,
gate
,
ifindex
,
metric
,
RTM_CHANGE
);
printf
(
"Change Ipv6 route return %d
\n
"
,
n
);
n
=
libwinet_edit_route_entry
(
dest
,
prefix
,
gate
,
ifindex
,
metric
,
RTM_DELETE
);
printf
(
"Delete Ipv6 route return %d
\n
"
,
n
);
}
while
(
0
);
}
int
main
(
int
argc
,
char
*
argv
[])
{
WORD
wVersionRequested
;
WSADATA
wsaData
;
int
err
;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested
=
MAKEWORD
(
2
,
2
);
err
=
WSAStartup
(
wVersionRequested
,
&
wsaData
);
if
(
err
!=
0
)
{
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf
(
"WSAStartup failed with error: %d
\n
"
,
err
);
return
1
;
}
/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we */
/* requested. */
if
(
LOBYTE
(
wsaData
.
wVersion
)
!=
2
||
HIBYTE
(
wsaData
.
wVersion
)
!=
2
)
{
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf
(
"Could not find a usable version of Winsock.dll
\n
"
);
WSACleanup
();
return
1
;
}
else
printf
(
"The Winsock 2.2 dll was found okay
\n
"
);
runTestCases
();
WSACleanup
();
return
0
;
}
#endif
/* TEST_CYGINET */
component/babeld/cyginet.h
0 → 100755
View file @
0e633e88
/*
Reference List in the MSDN.
NDIS 6.0 Interfaces for Window Vista later
http://msdn.microsoft.com/en-us/library/windows/hardware/ff565740(v=vs.85).aspx
NDIS Versions in Network Drivers (Windows Drivers)
http://msdn.microsoft.com/en-us/library/windows/hardware/ff567893(v=vs.85).aspx
For Windows XP, NDIS 5.0
http://msdn.microsoft.com/en-us/library/windows/hardware/ff565849(v=vs.85).aspx
NDIS General-use Interfaces (NDIS 5.1) (Windows Drivers)
http://msdn.microsoft.com/en-us/library/windows/hardware/ff556983(v=vs.85).aspx
Routing Protocol Interface Functions (Windows)
http://msdn.microsoft.com/en-us/library/windows/desktop/aa446772(v=vs.85).aspx
Networking (Windows)
http://msdn.microsoft.com/en-us/library/windows/desktop/ee663286(v=vs.85).aspx
NDIS Protocol Drivers (NDIS 5.1) (Windows Drivers)
http://msdn.microsoft.com/en-us/library/windows/hardware/ff557149(v=vs.85).aspx
Winsock IOCTLs (Windows)
http://msdn.microsoft.com/zh-cn/library/windows/desktop/bb736550(v=vs.85).aspx
Creating a Basic IP Helper Application (Windows)
http://msdn.microsoft.com/zh-cn/library/windows/desktop/aa365872(v=vs.85).aspx
Network Awareness in Windows XP
http://msdn.microsoft.com/en-us/library/ms700657(v=vs.85).aspx
System-Defined Device Setup Classes (Windows Drivers)
http://msdn.microsoft.com/en-us/library/windows/hardware/ff553419(v=vs.85).aspx
Device Information Sets (Windows Drivers)
http://msdn.microsoft.com/en-us/library/windows/hardware/ff541247(v=vs.85).aspx
Accessing Device Instance SPDRP_Xxx Properties (Windows Drivers)
http://msdn.microsoft.com/en-us/library/windows/hardware/ff537737(v=vs.85).aspx
IOCTL_NDIS_QUERY_GLOBAL_STATS (Windows Drivers)
http://msdn.microsoft.com/en-us/library/windows/hardware/ff548975(v=vs.85).aspx
IPv6 RFCs and Standards Working Groups
http://www.ipv6now.com.au/RFC.php
*/
#ifndef __CYGIFNET_H__
#define __CYGIFNET_H__
#ifndef IN_LOOPBACK
#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000)
#endif
/* Missing defines in the Cygwin */
#define RTM_ADD 0x1
/* Add Route */
#define RTM_DELETE 0x2
/* Delete Route */
#define RTM_CHANGE 0x3
/* Change Metrics or flags */
#define RTM_GET 0x4
/* Report Metrics */
/*
* Structure of a Link-Level sockaddr:
*/
struct
sockaddr_dl
{
u_char
sdl_len
;
/* Total length of sockaddr */
u_char
sdl_family
;
/* AF_LINK */
u_short
sdl_index
;
/* if != 0, system given index for interface */
u_char
sdl_type
;
/* interface type */
u_char
sdl_nlen
;
/* interface name length, no trailing 0 reqd. */
u_char
sdl_alen
;
/* link level address length */
u_char
sdl_slen
;
/* link layer selector length */
char
sdl_data
[
46
];
/* minimum work area, can be larger;
contains both if name and ll address */
};
#if defined(INSIDE_CYGINET)
/* Copy from babeld/kernel.h */
#define RTPROT_BABEL_LOCAL -2
#define KERNEL_INFINITY 0xFFFF
struct
kernel_route
{
unsigned
char
prefix
[
16
];
int
plen
;
int
metric
;
unsigned
int
ifindex
;
int
proto
;
unsigned
char
gw
[
16
];
};
/* End of Copy */
struct
ifaddrs
{
struct
ifaddrs
*
ifa_next
;
char
*
ifa_name
;
unsigned
int
ifa_flags
;
struct
sockaddr
*
ifa_addr
;
struct
sockaddr
*
ifa_netmask
;
struct
sockaddr
*
ifa_dstaddr
;
void
*
ifa_data
;
};
struct
if_nameindex
{
unsigned
if_index
;
char
*
if_name
;
};
typedef
struct
_LIBWINET_INTERFACE
{
DWORD
IfType
;
IF_OPER_STATUS
OperStatus
;
DWORD
Mtu
;
SOCKADDR
Address
;
}
LIBWINET_INTERFACE
,
*
PLIBWINET_INTERFACE
;
extern
unsigned
if_nametoindex
(
const
char
*
);
extern
char
*
if_indextoname
(
unsigned
,
char
*
);
extern
struct
if_nameindex
*
if_nameindex
(
void
);
extern
void
if_freenameindex
(
struct
if_nameindex
*
);
extern
const
char
*
inet_ntop
(
int
,
const
void
*
,
char
*
,
socklen_t
);
extern
int
inet_pton
(
int
,
const
char
*
,
void
*
);
extern
int
getifaddrs
(
struct
ifaddrs
**
);
extern
void
freeifaddrs
(
struct
ifaddrs
*
);
#define MALLOC(x) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,x)
#define FREE(p) \
if
(
NULL
!=
p
)
{
HeapFree
(
GetProcessHeap
(),
0
,
p
);
p
=
NULL
;}
#define CLOSESOCKET(s) \
if
(
INVALID_SOCKET
!=
s
)
{
closesocket
(
s
);
s
=
INVALID_SOCKET
;}
#define CLOSESOCKEVENT(h) \
if
(
WSA_INVALID_EVENT
!=
h
)
{
WSACloseEvent
(
h
);
h
=
WSA_INVALID_EVENT
;}
#define SOCKETERR(e) \
{
\
printf
(
"%s:%s failed: %d [%s@%d]
\n
"
,
\
__FUNCTION__
,
\
e
,
\
WSAGetLastError
(),
\
__FILE__
,
\
__LINE__
\
);
\
}
#endif
/* INSIDE_CYGINET */
/* Export functions from cyginet */
int
cyginet_startup
();
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_interface_sdl
(
struct
sockaddr_dl
*
,
char
*
);
int
cyginet_interface_wireless
(
const
char
*
,
int
);
int
cyginet_interface_mtu
(
const
char
*
,
int
);
int
cyginet_interface_operational
(
const
char
*
,
int
);
int
cyginet_interface_ipv4
(
const
char
*
,
int
,
unsigned
char
*
);
int
cyginet_dump_route_table
(
struct
kernel_route
*
,
int
);
int
cyginet_loopback_index
(
int
);
int
cyginet_add_route_entry
(
const
struct
sockaddr
*
,
unsigned
short
,
const
struct
sockaddr
*
,
int
,
unsigned
int
);
int
cyginet_delete_route_entry
(
const
struct
sockaddr
*
,
unsigned
short
,
const
struct
sockaddr
*
,
int
,
unsigned
int
);
int
cyginet_update_route_entry
(
const
struct
sockaddr
*
,
unsigned
short
,
const
struct
sockaddr
*
,
int
,
unsigned
int
);
#endif
/* __CYGIFNET_H__ */
component/babeld/kernel.c
View file @
0e633e88
...
...
@@ -28,6 +28,8 @@ THE SOFTWARE.
#ifdef __linux
#include "kernel_netlink.c"
#elif defined(__CYGWIN__)
#include "kernel_cygwin.c"
#else
#include "kernel_socket.c"
#endif
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment