mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-26 13:01:39 +00:00
Document ICMPv6 and TUN/TAP
This commit is contained in:
parent
ad6ea59049
commit
8e2c2aa977
@ -1,8 +1,13 @@
|
|||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
// The NDP functions are needed when you are running with a
|
// The ICMPv6 module implements functions to easily create ICMPv6
|
||||||
// TAP adapter - as the operating system expects neighbor solicitations
|
// packets. These functions, when mixed with the built-in Go IPv6
|
||||||
// for on-link traffic, this goroutine provides them
|
// and ICMP libraries, can be used to send control messages back
|
||||||
|
// to the host. Examples include:
|
||||||
|
// - NDP messages, when running in TAP mode
|
||||||
|
// - Packet Too Big messages, when packets exceed the session MTU
|
||||||
|
// - Destination Unreachable messages, when a session prohibits
|
||||||
|
// incoming traffic
|
||||||
|
|
||||||
import "net"
|
import "net"
|
||||||
import "golang.org/x/net/ipv6"
|
import "golang.org/x/net/ipv6"
|
||||||
@ -39,6 +44,9 @@ func ipv6Header_Marshal(h *ipv6.Header) ([]byte, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialises the ICMPv6 module by assigning our link-local IPv6 address and
|
||||||
|
// our MAC address. ICMPv6 messages will always appear to originate from these
|
||||||
|
// addresses.
|
||||||
func (i *icmpv6) init(t *tunDevice) {
|
func (i *icmpv6) init(t *tunDevice) {
|
||||||
i.tun = t
|
i.tun = t
|
||||||
|
|
||||||
@ -50,6 +58,10 @@ func (i *icmpv6) init(t *tunDevice) {
|
|||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFE}
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFE}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parses an incoming ICMPv6 packet. The packet provided may be either an
|
||||||
|
// ethernet frame containing an IP packet, or the IP packet alone. This is
|
||||||
|
// determined by whether the TUN/TAP adapter is running in TUN (layer 3) or
|
||||||
|
// TAP (layer 2) mode.
|
||||||
func (i *icmpv6) parse_packet(datain []byte) {
|
func (i *icmpv6) parse_packet(datain []byte) {
|
||||||
var response []byte
|
var response []byte
|
||||||
var err error
|
var err error
|
||||||
@ -69,6 +81,10 @@ func (i *icmpv6) parse_packet(datain []byte) {
|
|||||||
i.tun.iface.Write(response)
|
i.tun.iface.Write(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unwraps the ethernet headers of an incoming ICMPv6 packet and hands off
|
||||||
|
// the IP packet to the parse_packet_tun function for further processing.
|
||||||
|
// A response buffer is also created for the response message, also complete
|
||||||
|
// with ethernet headers.
|
||||||
func (i *icmpv6) parse_packet_tap(datain []byte) ([]byte, error) {
|
func (i *icmpv6) parse_packet_tap(datain []byte) ([]byte, error) {
|
||||||
// Store the peer MAC address
|
// Store the peer MAC address
|
||||||
copy(i.peermac[:6], datain[6:12])
|
copy(i.peermac[:6], datain[6:12])
|
||||||
@ -97,6 +113,10 @@ func (i *icmpv6) parse_packet_tap(datain []byte) ([]byte, error) {
|
|||||||
return dataout, nil
|
return dataout, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unwraps the IP headers of an incoming IPv6 packet and performs various
|
||||||
|
// sanity checks on the packet - i.e. is the packet an ICMPv6 packet, does the
|
||||||
|
// ICMPv6 message match a known expected type. The relevant handler function
|
||||||
|
// is then called and a response packet may be returned.
|
||||||
func (i *icmpv6) parse_packet_tun(datain []byte) ([]byte, error) {
|
func (i *icmpv6) parse_packet_tun(datain []byte) ([]byte, error) {
|
||||||
// Parse the IPv6 packet headers
|
// Parse the IPv6 packet headers
|
||||||
ipv6Header, err := ipv6.ParseHeader(datain[:ipv6.HeaderLen])
|
ipv6Header, err := ipv6.ParseHeader(datain[:ipv6.HeaderLen])
|
||||||
@ -149,6 +169,9 @@ func (i *icmpv6) parse_packet_tun(datain []byte) ([]byte, error) {
|
|||||||
return nil, errors.New("ICMPv6 type not matched")
|
return nil, errors.New("ICMPv6 type not matched")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates an ICMPv6 packet based on the given icmp.MessageBody and other
|
||||||
|
// parameters, complete with ethernet and IP headers, which can be written
|
||||||
|
// directly to a TAP adapter.
|
||||||
func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
|
func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
|
||||||
// Pass through to create_icmpv6_tun
|
// Pass through to create_icmpv6_tun
|
||||||
ipv6packet, err := i.create_icmpv6_tun(dst, src, mtype, mcode, mbody)
|
ipv6packet, err := i.create_icmpv6_tun(dst, src, mtype, mcode, mbody)
|
||||||
@ -169,6 +192,10 @@ func (i *icmpv6) create_icmpv6_tap(dstmac macAddress, dst net.IP, src net.IP, mt
|
|||||||
return dataout, nil
|
return dataout, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates an ICMPv6 packet based on the given icmp.MessageBody and other
|
||||||
|
// parameters, complete with IP headers only, which can be written directly to
|
||||||
|
// a TUN adapter, or called directly by the create_icmpv6_tap function when
|
||||||
|
// generating a message for TAP adapters.
|
||||||
func (i *icmpv6) create_icmpv6_tun(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
|
func (i *icmpv6) create_icmpv6_tun(dst net.IP, src net.IP, mtype ipv6.ICMPType, mcode int, mbody icmp.MessageBody) ([]byte, error) {
|
||||||
// Create the ICMPv6 message
|
// Create the ICMPv6 message
|
||||||
icmpMessage := icmp.Message{
|
icmpMessage := icmp.Message{
|
||||||
@ -208,6 +235,11 @@ func (i *icmpv6) create_icmpv6_tun(dst net.IP, src net.IP, mtype ipv6.ICMPType,
|
|||||||
return responsePacket, nil
|
return responsePacket, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generates a response to an NDP discovery packet. This is effectively called
|
||||||
|
// when the host operating system generates an NDP request for any address in
|
||||||
|
// the fd00::/8 range, so that the operating system knows to route that traffic
|
||||||
|
// to the Yggdrasil TAP adapter.
|
||||||
|
// TODO: Make this respect the value of address_prefix in address.go
|
||||||
func (i *icmpv6) handle_ndp(in []byte) ([]byte, error) {
|
func (i *icmpv6) handle_ndp(in []byte) ([]byte, error) {
|
||||||
// Ignore NDP requests for anything outside of fd00::/8
|
// Ignore NDP requests for anything outside of fd00::/8
|
||||||
if in[8] != 0xFD {
|
if in[8] != 0xFD {
|
||||||
|
@ -8,6 +8,7 @@ import "github.com/yggdrasil-network/water"
|
|||||||
const tun_IPv6_HEADER_LENGTH = 40
|
const tun_IPv6_HEADER_LENGTH = 40
|
||||||
const tun_ETHER_HEADER_LENGTH = 14
|
const tun_ETHER_HEADER_LENGTH = 14
|
||||||
|
|
||||||
|
// Represents a running TUN/TAP interface.
|
||||||
type tunDevice struct {
|
type tunDevice struct {
|
||||||
core *Core
|
core *Core
|
||||||
icmpv6 icmpv6
|
icmpv6 icmpv6
|
||||||
@ -17,6 +18,9 @@ type tunDevice struct {
|
|||||||
iface *water.Interface
|
iface *water.Interface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defines which parameters are expected by default for a TUN/TAP adapter on a
|
||||||
|
// specific platform. These values are populated in the relevant tun_*.go for
|
||||||
|
// the platform being targeted. They must be set.
|
||||||
type tunDefaultParameters struct {
|
type tunDefaultParameters struct {
|
||||||
maximumIfMTU int
|
maximumIfMTU int
|
||||||
defaultIfMTU int
|
defaultIfMTU int
|
||||||
@ -24,6 +28,8 @@ type tunDefaultParameters struct {
|
|||||||
defaultIfTAPMode bool
|
defaultIfTAPMode bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gets the maximum supported MTU for the platform based on the defaults in
|
||||||
|
// getDefaults().
|
||||||
func getSupportedMTU(mtu int) int {
|
func getSupportedMTU(mtu int) int {
|
||||||
if mtu > getDefaults().maximumIfMTU {
|
if mtu > getDefaults().maximumIfMTU {
|
||||||
return getDefaults().maximumIfMTU
|
return getDefaults().maximumIfMTU
|
||||||
@ -31,11 +37,14 @@ func getSupportedMTU(mtu int) int {
|
|||||||
return mtu
|
return mtu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialises the TUN/TAP adapter.
|
||||||
func (tun *tunDevice) init(core *Core) {
|
func (tun *tunDevice) init(core *Core) {
|
||||||
tun.core = core
|
tun.core = core
|
||||||
tun.icmpv6.init(tun)
|
tun.icmpv6.init(tun)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Starts the setup process for the TUN/TAP adapter, and if successful, starts
|
||||||
|
// the read/write goroutines to handle packets on that interface.
|
||||||
func (tun *tunDevice) start(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *tunDevice) start(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
if ifname == "none" {
|
if ifname == "none" {
|
||||||
return nil
|
return nil
|
||||||
@ -48,6 +57,9 @@ func (tun *tunDevice) start(ifname string, iftapmode bool, addr string, mtu int)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Writes a packet to the TUN/TAP adapter. If the adapter is running in TAP
|
||||||
|
// mode then additional ethernet encapsulation is added for the benefit of the
|
||||||
|
// host operating system.
|
||||||
func (tun *tunDevice) write() error {
|
func (tun *tunDevice) write() error {
|
||||||
for {
|
for {
|
||||||
data := <-tun.recv
|
data := <-tun.recv
|
||||||
@ -75,6 +87,10 @@ func (tun *tunDevice) write() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reads any packets that are waiting on the TUN/TAP adapter. If the adapter
|
||||||
|
// is running in TAP mode then the ethernet headers will automatically be
|
||||||
|
// processed and stripped if necessary. If an ICMPv6 packet is found, then
|
||||||
|
// the relevant helper functions in icmpv6.go are called.
|
||||||
func (tun *tunDevice) read() error {
|
func (tun *tunDevice) read() error {
|
||||||
mtu := tun.mtu
|
mtu := tun.mtu
|
||||||
if tun.iface.IsTAP() {
|
if tun.iface.IsTAP() {
|
||||||
@ -109,6 +125,9 @@ func (tun *tunDevice) read() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Closes the TUN/TAP adapter. This is only usually called when the Yggdrasil
|
||||||
|
// process stops. Typically this operation will happen quickly, but on macOS
|
||||||
|
// it can block until a read operation is completed.
|
||||||
func (tun *tunDevice) close() error {
|
func (tun *tunDevice) close() error {
|
||||||
if tun.iface == nil {
|
if tun.iface == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -70,6 +70,11 @@ type in6_ifreq_lifetime struct {
|
|||||||
ifru_addrlifetime in6_addrlifetime
|
ifru_addrlifetime in6_addrlifetime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the IPv6 address of the utun adapter. On all BSD platforms (FreeBSD,
|
||||||
|
// OpenBSD, NetBSD) an attempt is made to set the adapter properties by using
|
||||||
|
// a system socket and making syscalls to the kernel. This is not refined though
|
||||||
|
// and often doesn't work (if at all), therefore if a call fails, it resorts
|
||||||
|
// to calling "ifconfig" instead.
|
||||||
func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
var config water.Config
|
var config water.Config
|
||||||
if ifname[:4] == "auto" {
|
if ifname[:4] == "auto" {
|
||||||
|
@ -10,6 +10,8 @@ import "golang.org/x/sys/unix"
|
|||||||
|
|
||||||
import water "github.com/yggdrasil-network/water"
|
import water "github.com/yggdrasil-network/water"
|
||||||
|
|
||||||
|
// Sane defaults for the Darwin/macOS platform. The "default" options may be
|
||||||
|
// may be replaced by the running configuration.
|
||||||
func getDefaults() tunDefaultParameters {
|
func getDefaults() tunDefaultParameters {
|
||||||
return tunDefaultParameters{
|
return tunDefaultParameters{
|
||||||
maximumIfMTU: 65535,
|
maximumIfMTU: 65535,
|
||||||
@ -19,6 +21,7 @@ func getDefaults() tunDefaultParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configures the "utun" adapter with the correct IPv6 address and MTU.
|
||||||
func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
if iftapmode {
|
if iftapmode {
|
||||||
tun.core.log.Printf("TAP mode is not supported on this platform, defaulting to TUN")
|
tun.core.log.Printf("TAP mode is not supported on this platform, defaulting to TUN")
|
||||||
@ -65,6 +68,8 @@ type ifreq struct {
|
|||||||
ifru_mtu uint32
|
ifru_mtu uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the IPv6 address of the utun adapter. On Darwin/macOS this is done using
|
||||||
|
// a system socket and making direct syscalls to the kernel.
|
||||||
func (tun *tunDevice) setupAddress(addr string) error {
|
func (tun *tunDevice) setupAddress(addr string) error {
|
||||||
var fd int
|
var fd int
|
||||||
var err error
|
var err error
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
|
// Sane defaults for the FreeBSD platform. The "default" options may be
|
||||||
|
// may be replaced by the running configuration.
|
||||||
func getDefaults() tunDefaultParameters {
|
func getDefaults() tunDefaultParameters {
|
||||||
return tunDefaultParameters{
|
return tunDefaultParameters{
|
||||||
maximumIfMTU: 32767,
|
maximumIfMTU: 32767,
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
// The linux platform specific tun parts
|
// The linux platform specific tun parts
|
||||||
// It depends on iproute2 being installed to set things on the tun device
|
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
import "fmt"
|
import "fmt"
|
||||||
@ -11,6 +10,8 @@ import water "github.com/yggdrasil-network/water"
|
|||||||
|
|
||||||
import "github.com/docker/libcontainer/netlink"
|
import "github.com/docker/libcontainer/netlink"
|
||||||
|
|
||||||
|
// Sane defaults for the Linux platform. The "default" options may be
|
||||||
|
// may be replaced by the running configuration.
|
||||||
func getDefaults() tunDefaultParameters {
|
func getDefaults() tunDefaultParameters {
|
||||||
return tunDefaultParameters{
|
return tunDefaultParameters{
|
||||||
maximumIfMTU: 65535,
|
maximumIfMTU: 65535,
|
||||||
@ -20,6 +21,7 @@ func getDefaults() tunDefaultParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configures the TAP adapter with the correct IPv6 address and MTU.
|
||||||
func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
var config water.Config
|
var config water.Config
|
||||||
if iftapmode {
|
if iftapmode {
|
||||||
@ -39,6 +41,10 @@ func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int)
|
|||||||
return tun.setupAddress(addr)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configures the TAP adapter with the correct IPv6 address and MTU. Netlink
|
||||||
|
// is used to do this, so there is not a hard requirement on "ip" or "ifconfig"
|
||||||
|
// to exist on the system, but this will fail if Netlink is not present in the
|
||||||
|
// kernel (it nearly always is).
|
||||||
func (tun *tunDevice) setupAddress(addr string) error {
|
func (tun *tunDevice) setupAddress(addr string) error {
|
||||||
// Set address
|
// Set address
|
||||||
var netIF *net.Interface
|
var netIF *net.Interface
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
|
// Sane defaults for the NetBSD platform. The "default" options may be
|
||||||
|
// may be replaced by the running configuration.
|
||||||
func getDefaults() tunDefaultParameters {
|
func getDefaults() tunDefaultParameters {
|
||||||
return tunDefaultParameters{
|
return tunDefaultParameters{
|
||||||
maximumIfMTU: 9000,
|
maximumIfMTU: 9000,
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
|
// Sane defaults for the OpenBSD platform. The "default" options may be
|
||||||
|
// may be replaced by the running configuration.
|
||||||
func getDefaults() tunDefaultParameters {
|
func getDefaults() tunDefaultParameters {
|
||||||
return tunDefaultParameters{
|
return tunDefaultParameters{
|
||||||
maximumIfMTU: 16384,
|
maximumIfMTU: 16384,
|
||||||
|
@ -7,6 +7,8 @@ import water "github.com/yggdrasil-network/water"
|
|||||||
// This is to catch unsupported platforms
|
// This is to catch unsupported platforms
|
||||||
// If your platform supports tun devices, you could try configuring it manually
|
// If your platform supports tun devices, you could try configuring it manually
|
||||||
|
|
||||||
|
// These are sane defaults for any platform that has not been matched by one of
|
||||||
|
// the other tun_*.go files.
|
||||||
func getDefaults() tunDefaultParameters {
|
func getDefaults() tunDefaultParameters {
|
||||||
return tunDefaultParameters{
|
return tunDefaultParameters{
|
||||||
maximumIfMTU: 65535,
|
maximumIfMTU: 65535,
|
||||||
@ -16,6 +18,8 @@ func getDefaults() tunDefaultParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates the TUN/TAP adapter, if supported by the Water library. Note that
|
||||||
|
// no guarantees are made at this point on an unsupported platform.
|
||||||
func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
var config water.Config
|
var config water.Config
|
||||||
if iftapmode {
|
if iftapmode {
|
||||||
@ -32,6 +36,8 @@ func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int)
|
|||||||
return tun.setupAddress(addr)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't know how to set the IPv6 address on an unknown platform, therefore
|
||||||
|
// write about it to stdout and don't try to do anything further.
|
||||||
func (tun *tunDevice) setupAddress(addr string) error {
|
func (tun *tunDevice) setupAddress(addr string) error {
|
||||||
tun.core.log.Println("Platform not supported, you must set the address of", tun.iface.Name(), "to", addr)
|
tun.core.log.Println("Platform not supported, you must set the address of", tun.iface.Name(), "to", addr)
|
||||||
return nil
|
return nil
|
||||||
|
@ -7,6 +7,8 @@ import "fmt"
|
|||||||
|
|
||||||
// This is to catch Windows platforms
|
// This is to catch Windows platforms
|
||||||
|
|
||||||
|
// Sane defaults for the Windows platform. The "default" options may be
|
||||||
|
// may be replaced by the running configuration.
|
||||||
func getDefaults() tunDefaultParameters {
|
func getDefaults() tunDefaultParameters {
|
||||||
return tunDefaultParameters{
|
return tunDefaultParameters{
|
||||||
maximumIfMTU: 65535,
|
maximumIfMTU: 65535,
|
||||||
@ -16,6 +18,9 @@ func getDefaults() tunDefaultParameters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configures the TAP adapter with the correct IPv6 address and MTU. On Windows
|
||||||
|
// we don't make use of a direct operating system API to do this - we instead
|
||||||
|
// delegate the hard work to "netsh".
|
||||||
func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int) error {
|
||||||
if !iftapmode {
|
if !iftapmode {
|
||||||
tun.core.log.Printf("TUN mode is not supported on this platform, defaulting to TAP")
|
tun.core.log.Printf("TUN mode is not supported on this platform, defaulting to TAP")
|
||||||
@ -63,6 +68,7 @@ func (tun *tunDevice) setup(ifname string, iftapmode bool, addr string, mtu int)
|
|||||||
return tun.setupAddress(addr)
|
return tun.setupAddress(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the MTU of the TAP adapter.
|
||||||
func (tun *tunDevice) setupMTU(mtu int) error {
|
func (tun *tunDevice) setupMTU(mtu int) error {
|
||||||
// Set MTU
|
// Set MTU
|
||||||
cmd := exec.Command("netsh", "interface", "ipv6", "set", "subinterface",
|
cmd := exec.Command("netsh", "interface", "ipv6", "set", "subinterface",
|
||||||
@ -79,6 +85,7 @@ func (tun *tunDevice) setupMTU(mtu int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the IPv6 address of the TAP adapter.
|
||||||
func (tun *tunDevice) setupAddress(addr string) error {
|
func (tun *tunDevice) setupAddress(addr string) error {
|
||||||
// Set address
|
// Set address
|
||||||
cmd := exec.Command("netsh", "interface", "ipv6", "add", "address",
|
cmd := exec.Command("netsh", "interface", "ipv6", "add", "address",
|
||||||
|
Loading…
Reference in New Issue
Block a user