Skip to content

Commit

Permalink
hotfix: fix can not ping itself tun IP on windows
Browse files Browse the repository at this point in the history
  • Loading branch information
wencaiwulue committed Nov 18, 2024
1 parent a1212f5 commit d9a9000
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 22 deletions.
4 changes: 4 additions & 0 deletions pkg/daemon/action/quit.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package action

import (
"context"
"io"
"io/fs"
"os"
Expand Down Expand Up @@ -45,6 +46,9 @@ func (svr *Server) Quit(req *rpc.QuitRequest, resp rpc.Daemon_QuitServer) error
if svr.IsSudo {
_ = dns.CleanupHosts()
_ = os.RemoveAll("/etc/resolver")
if util.FindAllowFirewallRule(context.Background()) {
util.DeleteAllowFirewallRule(context.Background())
}
}

// last step is to quit GRPC server
Expand Down
24 changes: 21 additions & 3 deletions pkg/handler/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,15 @@ func (c *ConnectOptions) startLocalTunServer(ctx context.Context, forwardAddress

var cidrList []*net.IPNet
if !lite {
cidrList = append(cidrList, config.CIDR)
cidrList = append(cidrList, config.CIDR, config.CIDR6)
} else {
// windows needs to add tun IP self to route table, but linux and macOS not need
if util.IsWindows() {
cidrList = append(cidrList,
&net.IPNet{IP: c.localTunIPv4.IP, Mask: net.CIDRMask(32, 32)},
&net.IPNet{IP: c.localTunIPv6.IP, Mask: net.CIDRMask(128, 128)},
)
}
}
for _, ipNet := range c.cidrs {
cidrList = append(cidrList, ipNet)
Expand All @@ -357,11 +365,11 @@ func (c *ConnectOptions) startLocalTunServer(ctx context.Context, forwardAddress
}

tunConfig := tun.Config{
Addr: c.localTunIPv4.String(),
Addr: (&net.IPNet{IP: c.localTunIPv4.IP, Mask: net.CIDRMask(32, 32)}).String(),
Routes: routes,
}
if enable, _ := util.IsIPv6Enabled(); enable {
tunConfig.Addr6 = c.localTunIPv6.String()
tunConfig.Addr6 = (&net.IPNet{IP: c.localTunIPv6.IP, Mask: net.CIDRMask(128, 128)}).String()
}

localNode := fmt.Sprintf("tun:/127.0.0.1:8422")
Expand Down Expand Up @@ -507,6 +515,16 @@ func (c *ConnectOptions) addRouteDynamic(ctx context.Context) error {
}

func (c *ConnectOptions) deleteFirewallRule(ctx context.Context) {
if !util.IsWindows() {
return
}
// The reason why delete firewall rule is:
// On windows ping local tun IPv4/v6 not works
// so needs to add firewall rule to allow this
if !util.FindAllowFirewallRule(ctx) {
util.AddAllowFirewallRule(ctx)
}

// The reason why delete firewall rule is:
// On windows use 'kubevpn proxy deploy/authors -H user=windows'
// Open terminal 'curl localhost:9080' ok
Expand Down
35 changes: 17 additions & 18 deletions pkg/tun/tun_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net"
"net/netip"
"reflect"
"syscall"
"time"

"github.com/containernetworking/cni/pkg/types"
Expand All @@ -24,18 +25,18 @@ func createTun(cfg Config) (conn net.Conn, itf *net.Interface, err error) {
return
}

interfaceName := "KubeVPN"
tunName := "KubeVPN"
if len(cfg.Name) != 0 {
interfaceName = cfg.Name
tunName = cfg.Name
}
wireguardtun.WintunTunnelType = "KubeVPN"
tunDevice, err := wireguardtun.CreateTUN(interfaceName, cfg.MTU)
tunDevice, err := wireguardtun.CreateTUN(tunName, cfg.MTU)
if err != nil {
err = fmt.Errorf("failed to create TUN device: %w", err)
return
}

ifName := winipcfg.LUID(tunDevice.(*wireguardtun.NativeTun).LUID())
ifUID := winipcfg.LUID(tunDevice.(*wireguardtun.NativeTun).LUID())

var ipv4, ipv6 net.IP
if cfg.Addr != "" {
Expand All @@ -46,7 +47,8 @@ func createTun(cfg Config) (conn net.Conn, itf *net.Interface, err error) {
if prefix, err = netip.ParsePrefix(cfg.Addr); err != nil {
return
}
if err = ifName.AddIPAddress(prefix); err != nil {
if err = ifUID.AddIPAddress(prefix); err != nil {
err = fmt.Errorf("can not setup IPv4 address %s to device %s : %v", prefix.String(), tunName, err)
return
}
}
Expand All @@ -59,25 +61,25 @@ func createTun(cfg Config) (conn net.Conn, itf *net.Interface, err error) {
if prefix, err = netip.ParsePrefix(cfg.Addr6); err != nil {
return
}
if err = ifName.AddIPAddress(prefix); err != nil {
if err = ifUID.AddIPAddress(prefix); err != nil && !errors.Is(err, syscall.ERROR_NOT_FOUND) {
err = fmt.Errorf("can not setup IPv6 address %s to device %s : %v", prefix.String(), tunName, err)
return
}
}

var tunName string
tunName, err = tunDevice.Name()
if err != nil {
return nil, nil, err
}

_ = ifName.FlushRoutes(windows.AF_INET)
_ = ifName.FlushRoutes(windows.AF_INET6)
_ = ifUID.FlushRoutes(windows.AF_INET)
_ = ifUID.FlushRoutes(windows.AF_INET6)

if err = addTunRoutes(tunName /*cfg.Gateway,*/, cfg.Routes...); err != nil {
return
}
var row *winipcfg.MibIfRow2
if row, err = ifName.Interface(); err != nil {
if row, err = ifUID.Interface(); err != nil {
return
}
if itf, err = net.InterfaceByIndex(int(row.InterfaceIndex)); err != nil {
Expand All @@ -87,7 +89,7 @@ func createTun(cfg Config) (conn net.Conn, itf *net.Interface, err error) {
// windows,macOS,linux connect to same cluster
// macOS and linux can ping each other, but macOS and linux can not ping windows
var ipInterface *winipcfg.MibIPInterfaceRow
ipInterface, err = ifName.IPInterface(windows.AF_INET)
ipInterface, err = ifUID.IPInterface(windows.AF_INET)
if err != nil {
return
}
Expand All @@ -105,18 +107,15 @@ func addTunRoutes(tunName string, routes ...types.Route) error {
if err2 != nil {
return err2
}
ifName, err := winipcfg.LUIDFromIndex(uint32(name.Index))
ifUID, err := winipcfg.LUIDFromIndex(uint32(name.Index))
if err != nil {
return err
}
for _, route := range routes {
if route.Dst.String() == "" {
continue
}
var gw string
if gw != "" {
route.GW = net.ParseIP(gw)
} else {
if route.GW == nil {
if route.Dst.IP.To4() != nil {
route.GW = net.IPv4zero
} else {
Expand All @@ -133,8 +132,8 @@ func addTunRoutes(tunName string, routes ...types.Route) error {
if err != nil {
return err
}
err = ifName.AddRoute(prefix, addr.Unmap(), 0)
if err != nil && err != windows.ERROR_OBJECT_ALREADY_EXISTS {
err = ifUID.AddRoute(prefix, addr.Unmap(), 0)
if err != nil && !errors.Is(err, windows.ERROR_OBJECT_ALREADY_EXISTS) && !errors.Is(err, syscall.ERROR_NOT_FOUND) {
return err
}
}
Expand Down
5 changes: 4 additions & 1 deletion pkg/util/networkpolicy_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ import (
"context"
)

func DeleteBlockFirewallRule(ctx context.Context) {}
func DeleteBlockFirewallRule(ctx context.Context) {}
func DeleteAllowFirewallRule(ctx context.Context) {}
func FindAllowFirewallRule(ctx context.Context) bool { return false }
func AddAllowFirewallRule(ctx context.Context) {}
78 changes: 78 additions & 0 deletions pkg/util/networkpolicy_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ package util
import (
"context"
"os/exec"
"strings"
"syscall"
"time"

log "github.com/sirupsen/logrus"
"golang.org/x/text/encoding/simplifiedchinese"

"github.com/wencaiwulue/kubevpn/v2/pkg/config"
)

/**
Expand Down Expand Up @@ -88,3 +92,77 @@ func decode(in []byte) ([]byte, error) {
}
return nil, err
}

// AddAllowFirewallRule
// for ping local tun device ip, if not add this firewall, can not ping local tun IP on windows
func AddAllowFirewallRule(ctx context.Context) {
// netsh advfirewall firewall add rule name=kubevpn-traffic-manager dir=in action=allow enable=yes remoteip=223.254.0.100/16,efff:ffff:ffff:ffff:ffff:ffff:ffff:9999/64,LocalSubnet
cmd := exec.CommandContext(ctx, "netsh", []string{
"advfirewall",
"firewall",
"add",
"rule",
"name=" + config.ConfigMapPodTrafficManager,
"dir=in",
"action=allow",
"enable=yes",
"remoteip=" + strings.Join([]string{config.CIDR.String(), config.CIDR6.String(), config.DockerCIDR.String(), "LocalSubnet"}, ","),
}...)
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
if out, err := cmd.CombinedOutput(); err != nil {
var s string
var b []byte
if b, err = decode(out); err == nil {
s = string(b)
} else {
s = string(out)
}
log.Infof("Failed to exec command: %s, output: %s", cmd.Args, s)
}
}

func DeleteAllowFirewallRule(ctx context.Context) {
// netsh advfirewall firewall delete rule name=kubevpn-traffic-manager
cmd := exec.CommandContext(ctx, "netsh", []string{
"advfirewall",
"firewall",
"delete",
"rule",
"name=" + config.ConfigMapPodTrafficManager,
}...)
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
if out, err := cmd.CombinedOutput(); err != nil {
var s string
var b []byte
if b, err = decode(out); err == nil {
s = string(b)
} else {
s = string(out)
}
log.Errorf("Failed to exec command: %s, output: %s", cmd.Args, s)
}
}

func FindAllowFirewallRule(ctx context.Context) bool {
// netsh advfirewall firewall show rule name=kubevpn-traffic-manager
cmd := exec.CommandContext(ctx, "netsh", []string{
"advfirewall",
"firewall",
"show",
"rule",
"name=" + config.ConfigMapPodTrafficManager,
}...)
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
out, err := cmd.CombinedOutput()
if err != nil {
s := string(out)
var b []byte
if b, err = decode(out); err == nil {
s = string(b)
}
log.Debugf("Find firewall %s, output: %s", config.ConfigMapPodTrafficManager, s)
return false
} else {
return true
}
}

0 comments on commit d9a9000

Please sign in to comment.