Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Windows to allow selecting between multiple tap0901 adapters on the same system #59

Merged
merged 3 commits into from
Mar 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ ajee cai <ajee.cai@gmail.com>
yinheli <hi@yinheli.com>
Paul Querna <pquerna@apache.org>
Cuong Manh Le <cuong.manhle.vn@gmail.com>
Neil Alexander <neilalexander@users.noreply.github.com>
soffokl marked this conversation as resolved.
Show resolved Hide resolved
Dmitry Shihovtsev <soffokulus@gmail.com>
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,21 @@ ping 10.1.0.255

You'll see output containing the IPv4 ICMP frame same as the Linux version.

#### Specifying interface name

If you are going to use multiple TAP devices on the Windows, there is a way to specify an interface name to select the exact device that you need:

```go
ifce, err := water.New(water.Config{
DeviceType: water.TAP,
PlatformSpecificParams: water.PlatformSpecificParams{
ComponentID: "tap0901",
InterfaceName: "Ethernet 3",
Network: "192.168.1.10/24",
},
})
```

## TODO
* tuntaposx for TAP on Darwin

Expand Down
4 changes: 4 additions & 0 deletions params_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ type PlatformSpecificParams struct {
// use the default ComponentId. The default ComponentId is set to tap0901,
// the one used by OpenVPN.
ComponentID string
// InterfaceName is a friendly name of the network adapter as set in Control Panel.
// Of course, you may have multiple tap0901 adapters on the system, in which
// case we need a friendlier way to identify them.
InterfaceName 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
Expand Down
33 changes: 26 additions & 7 deletions syscalls_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ import (
// or just install OpenVPN
// https://github.com/OpenVPN/openvpn

const (
// tapDriverKey is a location of the TAP driver key.
tapDriverKey = `SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}`
)

var (
errIfceNameNotFound = errors.New("Failed to find the name of interface")
// Device Control Codes
Expand Down Expand Up @@ -139,10 +144,8 @@ 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.
func getdeviceid(componentID string) (deviceid string, err error) {
// TAP driver key location
regkey := `SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}`
k, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey, registry.READ)
func getdeviceid(componentID string, interfaceName string) (deviceid string, err error) {
k, err := registry.OpenKey(registry.LOCAL_MACHINE, tapDriverKey, registry.READ)
if err != nil {
return "", fmt.Errorf("Failed to open the adapter registry, TAP driver may be not installed, %v", err)
}
Expand All @@ -154,7 +157,7 @@ func getdeviceid(componentID string) (deviceid string, err error) {
}
// find the one matched ComponentId
for _, v := range keys {
key, err := registry.OpenKey(registry.LOCAL_MACHINE, regkey+"\\"+v, registry.READ)
key, err := registry.OpenKey(registry.LOCAL_MACHINE, tapDriverKey+"\\"+v, registry.READ)
if err != nil {
continue
}
Expand All @@ -169,12 +172,28 @@ func getdeviceid(componentID string) (deviceid string, err error) {
key.Close()
continue
}
if len(interfaceName) > 0 {
key2 := fmt.Sprintf("%s\\%s\\Connection", tapDriverKey, val)
k2, err := registry.OpenKey(registry.LOCAL_MACHINE, key2, registry.READ)
if err != nil {
continue
}
defer k2.Close()
val, _, err := k2.GetStringValue("Name")
if err != nil || val != interfaceName {
continue
}
}
key.Close()
return val, nil
}
key.Close()
}
return "", fmt.Errorf("Failed to find the tap device in registry with specified ComponentId(%s), TAP driver may be not installed", componentID)
if len(interfaceName) > 0 {
return "", fmt.Errorf("Failed to find the tap device in registry with specified ComponentId '%s' and InterfaceName '%s', TAP driver may be not installed or you may have specified an interface name that doesn't exist", componentID, interfaceName)
}

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
Expand Down Expand Up @@ -216,7 +235,7 @@ func setTUN(fd syscall.Handle, network string) error {
// openDev find and open an interface.
func openDev(config Config) (ifce *Interface, err error) {
// find the device in registry.
deviceid, err := getdeviceid(config.PlatformSpecificParams.ComponentID)
deviceid, err := getdeviceid(config.PlatformSpecificParams.ComponentID, config.PlatformSpecificParams.InterfaceName)
if err != nil {
return nil, err
}
Expand Down