mirror of
https://github.com/yggdrasil-network/water.git
synced 2025-05-20 00:45:09 +03:00
Support new config method.
Refined code.
This commit is contained in:
parent
cde943e7d7
commit
933e95c058
3 changed files with 81 additions and 27 deletions
12
if_windows.go
Normal file
12
if_windows.go
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package water
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
func newDev(config Config) (ifce *Interface, err error) {
|
||||||
|
if config.DeviceType != TAP && config.DeviceType != TUN {
|
||||||
|
return nil, errors.New("unknown device type")
|
||||||
|
}
|
||||||
|
return openDev(config)
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
// +build windows
|
||||||
|
|
||||||
package water
|
package water
|
||||||
|
|
||||||
// PlatformSpecificParams defines parameters in Config that are specific to
|
// PlatformSpecificParams defines parameters in Config that are specific to
|
||||||
|
@ -9,10 +11,22 @@ type PlatformSpecificParams struct {
|
||||||
// use the default ComponentId. The default ComponentId is set to tap0901,
|
// use the default ComponentId. The default ComponentId is set to tap0901,
|
||||||
// the one used by OpenVPN.
|
// the one used by OpenVPN.
|
||||||
ComponentID string
|
ComponentID string
|
||||||
|
// Network is required when creating a TUN interface. The library will call
|
||||||
|
// net.ParseCIDR() to parse this string into LocalIP, RemoteNetaddr,
|
||||||
|
// RemoteNetmask. The underlying driver will need those to generate ARP
|
||||||
|
// response to Windows kernel, to emulate an TUN interface.
|
||||||
|
// Please note that it cannot perceive the IP changes caused by DHCP, user
|
||||||
|
// configuration to the adapter and etc,. If IP changed, please reconfigure
|
||||||
|
// the adapter using syscall, just like openDev().
|
||||||
|
// For detail, please refer
|
||||||
|
// https://github.com/OpenVPN/tap-windows6/blob/master/src/device.c#L431
|
||||||
|
// and https://github.com/songgao/water/pull/13#issuecomment-270341777
|
||||||
|
Network string
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultPlatformSpecificParams() PlatformSpecificParams {
|
func defaultPlatformSpecificParams() PlatformSpecificParams {
|
||||||
return PlatformSpecificParams{
|
return PlatformSpecificParams{
|
||||||
ComponentId: "tap0901",
|
ComponentID: "tap0901",
|
||||||
|
Network: "192.168.1.10/24",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,6 @@ var (
|
||||||
tap_ioctl_config_tun = tap_control_code(10, 0)
|
tap_ioctl_config_tun = tap_control_code(10, 0)
|
||||||
// w32 api
|
// w32 api
|
||||||
file_device_unknown = uint32(0x00000022)
|
file_device_unknown = uint32(0x00000022)
|
||||||
// Driver maker specified ComponentId
|
|
||||||
// ComponentId is defined here: https://github.com/OpenVPN/tap-windows6/blob/master/version.m4#L5
|
|
||||||
componentId = "tap0901"
|
|
||||||
nCreateEvent,
|
nCreateEvent,
|
||||||
nResetEvent,
|
nResetEvent,
|
||||||
nGetOverlappedResult uintptr
|
nGetOverlappedResult uintptr
|
||||||
|
@ -143,7 +140,7 @@ func tap_control_code(request, method uint32) uint32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getdeviceid finds out a TAP device from registry, it *may* requires privileged right to prevent some weird issue.
|
// getdeviceid finds out a TAP device from registry, it *may* requires privileged right to prevent some weird issue.
|
||||||
func getdeviceid() (string, error) {
|
func getdeviceid(componentID string) (deviceid string, err error) {
|
||||||
// TAP driver key location
|
// TAP driver key location
|
||||||
regkey := `SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}`
|
regkey := `SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}`
|
||||||
k, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey, registry.READ)
|
k, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey, registry.READ)
|
||||||
|
@ -167,7 +164,7 @@ func getdeviceid() (string, error) {
|
||||||
key.Close()
|
key.Close()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if val == componentId {
|
if val == componentID {
|
||||||
val, _, err = key.GetStringValue("NetCfgInstanceId")
|
val, _, err = key.GetStringValue("NetCfgInstanceId")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
key.Close()
|
key.Close()
|
||||||
|
@ -178,14 +175,49 @@ func getdeviceid() (string, error) {
|
||||||
}
|
}
|
||||||
key.Close()
|
key.Close()
|
||||||
}
|
}
|
||||||
return "", fmt.Errorf("Failed to find the tap device in registry with specified ComponentId(%s), TAP driver may be not installed", componentId)
|
return "", fmt.Errorf("Failed to find the tap device in registry with specified ComponentId(%s), TAP driver may be not installed", componentID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setStatus is used to bring up or bring down the interface
|
||||||
|
func setStatus(fd syscall.Handle, status bool) error {
|
||||||
|
var bytesReturned uint32
|
||||||
|
rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
|
||||||
|
code := []byte{0x00, 0x00, 0x00, 0x00}
|
||||||
|
if status {
|
||||||
|
code[0] = 0x01
|
||||||
|
}
|
||||||
|
return syscall.DeviceIoControl(fd, tap_ioctl_set_media_status, &code[0], uint32(4), &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setTUN is used to configure the IP address in the underlying driver when using TUN
|
||||||
|
func setTUN(fd syscall.Handle, network string) error {
|
||||||
|
var bytesReturned uint32
|
||||||
|
rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
|
||||||
|
|
||||||
|
localIP, remoteNet, err := net.ParseCIDR(network)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Failed to parse network CIDR in config, %v", err)
|
||||||
|
}
|
||||||
|
if localIP.To4() == nil {
|
||||||
|
return fmt.Errorf("Provided network(%s) is not a valid IPv4 address", network)
|
||||||
|
}
|
||||||
|
code2 := make([]byte, 0, 12)
|
||||||
|
code2 = append(code2, localIP.To4()[:4]...)
|
||||||
|
code2 = append(code2, remoteNet.IP.To4()[:4]...)
|
||||||
|
code2 = append(code2, remoteNet.Mask[:4]...)
|
||||||
|
if len(code2) != 12 {
|
||||||
|
return fmt.Errorf("Provided network(%s) is not valid", network)
|
||||||
|
}
|
||||||
|
if err := syscall.DeviceIoControl(fd, tap_ioctl_config_tun, &code2[0], uint32(12), &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// openDev find and open an interface.
|
// openDev find and open an interface.
|
||||||
func openDev(isTAP bool) (ifce *Interface, err error) {
|
func openDev(config Config) (ifce *Interface, err error) {
|
||||||
// ifName won't work
|
|
||||||
// find the device in registry.
|
// find the device in registry.
|
||||||
deviceid, err := getdeviceid()
|
deviceid, err := getdeviceid(config.PlatformSpecificParams.ComponentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -209,7 +241,6 @@ func openDev(isTAP bool) (ifce *Interface, err error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var bytesReturned uint32
|
var bytesReturned uint32
|
||||||
rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
|
|
||||||
|
|
||||||
// find the mac address of tap device, use this to find the name of interface
|
// find the mac address of tap device, use this to find the name of interface
|
||||||
mac := make([]byte, 6)
|
mac := make([]byte, 6)
|
||||||
|
@ -228,21 +259,17 @@ func openDev(isTAP bool) (ifce *Interface, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fd := &wfile{fd: file, ro: ro, wo: wo}
|
fd := &wfile{fd: file, ro: ro, wo: wo}
|
||||||
ifce = &Interface{isTAP: isTAP, ReadWriteCloser: fd}
|
ifce = &Interface{isTAP: (config.DeviceType == TAP), ReadWriteCloser: fd}
|
||||||
|
|
||||||
// bring up device.
|
// bring up device.
|
||||||
code := []byte{0x01, 0x00, 0x00, 0x00}
|
if err := setStatus(file, true); err != nil {
|
||||||
err = syscall.DeviceIoControl(file, tap_ioctl_set_media_status, &code[0], uint32(4), &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
|
return nil, err
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TUN
|
//TUN
|
||||||
if !isTAP {
|
if config.DeviceType == TUN {
|
||||||
code2 := []byte{0x0a, 0x03, 0x00, 0x01, 0x0a, 0x03, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00}
|
if err := setTUN(file, config.PlatformSpecificParams.Network); err != nil {
|
||||||
err = syscall.DeviceIoControl(file, tap_ioctl_config_tun, &code2[0], uint32(12), &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
|
return nil, err
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,16 +286,17 @@ func openDev(isTAP bool) (ifce *Interface, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = errIfceNameNotFound
|
return nil, errIfceNameNotFound
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTAP(ifName string) (ifce *Interface, err error) {
|
func newTAP(ifName string) (ifce *Interface, err error) {
|
||||||
// ifName won't work
|
config := defaultConfig()
|
||||||
return openDev(true)
|
config.DeviceType = TAP
|
||||||
|
return openDev(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTUN(ifName string) (ifce *Interface, err error) {
|
func newTUN(ifName string) (ifce *Interface, err error) {
|
||||||
// ifName won't work
|
config := defaultConfig()
|
||||||
return openDev(false)
|
config.DeviceType = TUN
|
||||||
|
return openDev(config)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue