fix(listener): configure all TUN addresses for dual-stack IPv6 on Windows
Only the first entry of config.Net was installed on the wintun adapter, so dual-stack setups (e.g. net=192.168.123.1/24,fd::2/64) silently dropped the IPv6 address and IPv6 traffic never worked. Iterate every configured address and select the netsh context by family (ip for IPv4, ipv6 for IPv6). A failing address is logged and skipped so one bad entry no longer aborts the rest or triggers the listenLoop's infinite recreate-retry. If no address can be configured, return an error instead of a nil peer IP. Refs: go-gost/gost#624
This commit is contained in:
@@ -52,8 +52,17 @@ func (l *tunListener) createTun() (ifce io.ReadWriteCloser, name string, ip net.
|
||||
}
|
||||
}
|
||||
|
||||
if len(l.md.config.Net) > 0 {
|
||||
ipNet := l.md.config.Net[0]
|
||||
// Loop over every configured address so dual-stack (IPv4+IPv6) setups
|
||||
// install both addresses, selecting the netsh context by family: "ip"
|
||||
// for IPv4, "ipv6" for IPv6. A failing address is logged and skipped so
|
||||
// one bad entry doesn't prevent the rest from being applied; the first
|
||||
// successfully installed address is reported as the interface IP.
|
||||
//
|
||||
// Caveat: unlike Linux's netlink.AddrAdd, "netsh interface ip set
|
||||
// address" replaces rather than adds, so only a single IPv4 address is
|
||||
// supported (one IPv4 + one IPv6 works; multiple IPv4 addresses
|
||||
// silently overwrite).
|
||||
for _, ipNet := range l.md.config.Net {
|
||||
cmd := fmt.Sprintf("netsh interface ip set address name=%s "+
|
||||
"source=static addr=%s mask=%s gateway=none",
|
||||
name, ipNet.IP.String(), ipMask(ipNet.Mask))
|
||||
@@ -65,10 +74,19 @@ func (l *tunListener) createTun() (ifce io.ReadWriteCloser, name string, ip net.
|
||||
|
||||
args := strings.Split(cmd, " ")
|
||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||
err = fmt.Errorf("%s: %v", cmd, er)
|
||||
return
|
||||
l.log.Errorf("%s: %v", cmd, er)
|
||||
continue
|
||||
}
|
||||
ip = ipNet.IP
|
||||
if ip == nil {
|
||||
ip = ipNet.IP
|
||||
}
|
||||
}
|
||||
|
||||
// If not a single address could be configured, surface an error rather
|
||||
// than returning a nil IP (and thus a nil peer address) to the caller.
|
||||
if ip == nil && len(l.md.config.Net) > 0 {
|
||||
err = fmt.Errorf("failed to configure any address on interface %s", name)
|
||||
return
|
||||
}
|
||||
|
||||
if err = l.addRoutes(name, l.md.config.Gateway); err != nil {
|
||||
|
||||
@@ -56,8 +56,17 @@ func (l *tunListener) createTun() (ifce io.ReadWriteCloser, name string, ip net.
|
||||
}
|
||||
}
|
||||
|
||||
if len(l.md.config.Net) > 0 {
|
||||
ipNet := l.md.config.Net[0]
|
||||
// Loop over every configured address so dual-stack (IPv4+IPv6) setups
|
||||
// install both addresses, selecting the netsh context by family: "ip"
|
||||
// for IPv4, "ipv6" for IPv6. A failing address is logged and skipped so
|
||||
// one bad entry doesn't prevent the rest from being applied; the first
|
||||
// successfully installed address is reported as the interface IP.
|
||||
//
|
||||
// Caveat: unlike Linux's netlink.AddrAdd, "netsh interface ip set
|
||||
// address" replaces rather than adds, so only a single IPv4 address is
|
||||
// supported (one IPv4 + one IPv6 works; multiple IPv4 addresses
|
||||
// silently overwrite).
|
||||
for _, ipNet := range l.md.config.Net {
|
||||
cmd := fmt.Sprintf("netsh interface ip set address name=%s "+
|
||||
"source=static addr=%s mask=%s",
|
||||
name, ipNet.IP.String(), ipMask(ipNet.Mask))
|
||||
@@ -73,10 +82,19 @@ func (l *tunListener) createTun() (ifce io.ReadWriteCloser, name string, ip net.
|
||||
l.log.Debugf("%s: %s", cmd, windows.ByteSliceToString(output))
|
||||
}
|
||||
if er != nil {
|
||||
err = fmt.Errorf("%s: %v", cmd, er)
|
||||
return
|
||||
l.log.Errorf("%s: %v", cmd, er)
|
||||
continue
|
||||
}
|
||||
ip = ipNet.IP
|
||||
if ip == nil {
|
||||
ip = ipNet.IP
|
||||
}
|
||||
}
|
||||
|
||||
// If not a single address could be configured, surface an error rather
|
||||
// than returning a nil IP (and thus a nil peer address) to the caller.
|
||||
if ip == nil && len(l.md.config.Net) > 0 {
|
||||
err = fmt.Errorf("failed to configure any address on interface %s", name)
|
||||
return
|
||||
}
|
||||
|
||||
if err = l.addRoutes(name, l.md.config.Gateway); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user