Skip to content

Commit

Permalink
Merge pull request #395 from love04040202/master
Browse files Browse the repository at this point in the history
feat: support ipv6 address
  • Loading branch information
linfan authored Feb 9, 2023
2 parents 06aa986 + 9e85bfe commit d4c5544
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 33 deletions.
5 changes: 3 additions & 2 deletions pkg/common/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ package common

const (
// Localhost ip of localhost
Localhost = "127.0.0.1"
Localhost = "127.0.0.1"
LocalhostIp6 = "[::]"
// YyyyMmDdHhMmSs timestamp format
YyyyMmDdHhMmSs = "2006-01-02 15:04:05"
// StandardSshPort standard ssh port
Expand All @@ -16,4 +17,4 @@ const (
EnvVarDnsProtocol = "KT_DNS_PROTOCOL"
// EnvVarLogLevel environment variable for shadow pod log level
EnvVarLogLevel = "KT_LOG_LEVEL"
)
)
4 changes: 2 additions & 2 deletions pkg/kt/command/connect/tun2socks.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func setupTunRoute() error {
func startSocks5Connection(podIP, privateKey string, localSshPort int, isInitConnect bool) error {
var res = make(chan error)
var ticker *time.Ticker
sshAddress := fmt.Sprintf("%s:%d", common.Localhost, localSshPort)
sshAddress := fmt.Sprintf("%s:%d", common.LocalhostIp6, localSshPort)
socks5Address := fmt.Sprintf("%s:%d", opt.Get().Connect.ProxyAddr, opt.Get().Connect.ProxyPort)
gone := false
go func() {
Expand Down Expand Up @@ -128,7 +128,7 @@ func setupSocks5HeartBeat(podIP, socks5Address string) *time.Ticker {
for {
select {
case <-ticker.C:
if c, err2 := dialer.Dial("tcp", fmt.Sprintf("%s:%d", podIP, common.StandardSshPort)); err2 != nil {
if c, err2 := dialer.Dial("tcp", fmt.Sprintf("[%s]:%d", podIP, common.StandardSshPort)); err2 != nil {
log.Debug().Err(err2).Msgf("Socks proxy heartbeat interrupted")
} else {
_ = c.Close()
Expand Down
5 changes: 5 additions & 0 deletions pkg/kt/command/general/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"os/signal"
"runtime"
"syscall"
"strings"
)

// Prepare setup log level, time difference and kube config
Expand Down Expand Up @@ -117,6 +118,10 @@ func combineKubeOpts() (err error) {
opt.Store.Clientset = clientSet
opt.Store.RestConfig = restConfig

if opt.Get().Global.IpVersion == 6 || strings.Contains(restConfig.Host, "[") {
opt.Store.Ipv6Cluster = true
}

clusterName := "none"
for name, context := range config.Contexts {
if name == config.CurrentContext {
Expand Down
5 changes: 5 additions & 0 deletions pkg/kt/command/options/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ func GlobalFlags() []OptionConfig {
DefaultValue: "",
Description: "Specify resource limit for shadow and router pod, e.g. '0.5c,512m'",
},
{
Target: "IpVersion",
DefaultValue: 4,
Description: "network type connect local and remote,the value could be '4' or '6'",
},
}
return flags
}
1 change: 1 addition & 0 deletions pkg/kt/command/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ type GlobalOptions struct {
Context string
PodQuota string
ListenCheck bool
IpVersion int
}

// DaemonOptions cli options
Expand Down
2 changes: 2 additions & 0 deletions pkg/kt/command/options/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ type RuntimeStore struct {
Replicas int32
// Service exposed service name
Service string
// isIpv6Cluster
Ipv6Cluster bool
}
39 changes: 38 additions & 1 deletion pkg/kt/service/cluster/cidr.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,33 @@ func (k *Kubernetes) ClusterCidr(namespace string) ([]string, []string) {
ips := getServiceIps(k.Clientset, namespace)
log.Debug().Msgf("Found %d IPs", len(ips))
svcCidr := calculateMinimalIpRange(ips)
log.Debug().Msgf("Service ips are: %v", ips)
log.Debug().Msgf("Service CIDR are: %v", svcCidr)

var podCidr []string
if !opt.Get().Connect.DisablePodIp {
ips = getPodIps(k.Clientset, namespace)
log.Debug().Msgf("Found %d IPs", len(ips))
podCidr = calculateMinimalIpRange(ips)
log.Debug().Msgf("Pod ips are: %v", ips)
log.Debug().Msgf("Pod CIDR are: %v", podCidr)
}

apiServerIp := util.ExtractHostIp(opt.Store.RestConfig.Host)
log.Debug().Msgf("Using cluster IP %s", apiServerIp)

if opt.Store.Ipv6Cluster == true && strings.Contains(apiServerIp, ":"){
apiServerIp = strings.Split(strings.Split(opt.Store.RestConfig.Host, "[")[1], "]")[0]
}

cidr := mergeIpRange(svcCidr, podCidr, apiServerIp)
log.Debug().Msgf("Cluster CIDR are: %v", cidr)

excludeIps := strings.Split(opt.Get().Connect.ExcludeIps, ",")
var excludeCidr []string
if len(apiServerIp) > 0 {
excludeIps = append(excludeIps, apiServerIp+"/32")
log.Debug().Msgf("excludeIps are: %v", excludeIps)
}

if opt.Get().Connect.IncludeIps != "" {
Expand Down Expand Up @@ -74,6 +81,13 @@ func (k *Kubernetes) ClusterCidr(namespace string) ([]string, []string) {
if len(excludeCidr) > 0 {
log.Debug().Msgf("Non-cluster CIDR are: %v", excludeCidr)
}

// remove ipv6 api address
if opt.Store.Ipv6Cluster == true && strings.Contains(apiServerIp, ":") {
s := strings.Split(apiServerIp, ":")
ipmask := fmt.Sprintf("%s:%s::/32", s[0], s[1])
cidr = util.ArrayDelete(cidr, ipmask)
}
return cidr, excludeCidr
}

Expand All @@ -82,7 +96,7 @@ func mergeIpRange(svcCidr []string, podCidr []string, apiServerIp string) []stri
mergedCidr := make([]string, 0)
for _, r := range cidr {
if isPartOfRange(r, apiServerIp+"/32") {
mergedCidr = append(mergedCidr, excludeIpFromRange(r, apiServerIp)...)
mergedCidr = append(mergedCidr, excludeIpFromRange(r, apiServerIp+"/32")...)
} else {
mergedCidr = append(mergedCidr, r)
}
Expand Down Expand Up @@ -200,11 +214,34 @@ func getServiceIps(k kubernetes.Interface, namespace string) []string {
return ips
}

func calculateMinimalIpv6Range(ips []string) []string {
var miniRange []string
for _, ip := range ips {
if strings.Contains(ip, ".") {
continue
}
s := strings.Split(ip, ":")
ipmask := fmt.Sprintf("%s:%s::/32", s[0], s[1])
if !util.Contains(miniRange, ipmask) {
miniRange = append(miniRange, ipmask)
}

}
return miniRange
}

func calculateMinimalIpRange(ips []string) []string {
if opt.Store.Ipv6Cluster == true {
return calculateMinimalIpv6Range(ips)
}

var miniBins [][32]int
threshold := 16
withAlign := true
for _, ip := range ips {
if strings.Contains(ip, ":") {
continue
}
ipBin, err := ipToBin(ip)
if err != nil {
// skip invalid ip
Expand Down
117 changes: 89 additions & 28 deletions pkg/kt/service/tun/tun_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tun

import (
"fmt"
opt "github.com/alibaba/kt-connect/pkg/kt/command/options"
"github.com/alibaba/kt-connect/pkg/kt/util"
"github.com/rs/zerolog/log"
wintun "golang.zx2c4.com/wintun"
Expand All @@ -10,9 +11,9 @@ import (
)

type RouteRecord struct {
TargetRange string
TargetRange string
InterfaceIndex string
InterfaceName string
InterfaceName string
}

// CheckContext check everything needed for tun setup
Expand All @@ -33,53 +34,116 @@ func (s *Cli) CheckContext() (err error) {
func (s *Cli) SetRoute(ipRange []string, excludeIpRange []string) error {
var lastErr error
anyRouteOk := false
for i, r := range ipRange {
log.Info().Msgf("Adding route to %s", r)
_, mask, err := toIpAndMask(r)
tunIp := strings.Split(r, "/")[0]
if err != nil {
return AllRouteFailError{err}

// add by lichp, set ipv6 address
if opt.Store.Ipv6Cluster == true {
anyRouteOk, lastErr = s.setIPv6Route(ipRange, excludeIpRange)
} else {
for i, r := range ipRange {
log.Info().Msgf("Adding route to %s", r)
_, mask, err := toIpAndMask(r)
tunIp := strings.Split(r, "/")[0]
if err != nil {
return AllRouteFailError{err}
}
if i == 0 {
// run command: netsh interface ipv4 set address KtConnectTunnel static 172.20.0.1 255.255.0.0
_, _, err = util.RunAndWait(exec.Command("netsh",
"interface",
"ipv4",
"set",
"address",
s.GetName(),
"static",
tunIp,
mask,
))
} else {
// run command: netsh interface ipv4 add address KtConnectTunnel 172.21.0.1 255.255.0.0
_, _, err = util.RunAndWait(exec.Command("netsh",
"interface",
"ipv4",
"add",
"address",
s.GetName(),
tunIp,
mask,
))
}
if err != nil {
log.Warn().Msgf("Failed to add ip addr %s to tun device", tunIp)
lastErr = err
continue
} else {
anyRouteOk = true
}
// run command: netsh interface ipv4 add route 172.20.0.0/16 KtConnectTunnel 172.20.0.0
_, _, err = util.RunAndWait(exec.Command("netsh",
"interface",
"ipv4",
"add",
"route",
r,
s.GetName(),
tunIp,
))
if err != nil {
log.Warn().Msgf("Failed to set route %s to tun device", r)
lastErr = err
} else {
anyRouteOk = true
}
}
}
if !anyRouteOk {
return AllRouteFailError{lastErr}
}
return lastErr
}

func (s *Cli) setIPv6Route(ipRange []string, excludeIpRange []string) (bool, error) {
var lastErr error
anyRouteOk := false
// add by lichp, set ipv6 address
var err error
for i, r := range ipRange {
if i == 0 {
// run command: netsh interface ipv4 set address KtConnectTunnel static 172.20.0.1 255.255.0.0
// run command: netsh interface ipv6 set address EtConnectTunnel fd11:1111::/32
_, _, err = util.RunAndWait(exec.Command("netsh",
"interface",
"ipv4",
"ipv6",
"set",
"address",
s.GetName(),
"static",
tunIp,
mask,
r,
))
} else {
// run command: netsh interface ipv4 add address KtConnectTunnel 172.21.0.1 255.255.0.0
// run command: netsh interface ipv6 add address EtConnectTunnel fd11:1112::/32
_, _, err = util.RunAndWait(exec.Command("netsh",
"interface",
"ipv4",
"ipv6",
"add",
"address",
s.GetName(),
tunIp,
mask,
r,
))
}
if err != nil {
log.Warn().Msgf("Failed to add ip addr %s to tun device", tunIp)
log.Warn().Msgf("Failed to add ip addr %s to tun device", r)
lastErr = err
continue
} else {
anyRouteOk = true
}
// run command: netsh interface ipv4 add route 172.20.0.0/16 KtConnectTunnel 172.20.0.0
// run command: netsh interface ipv6 add route fd11:1112::/32 EtConnectTunnel fd11:1112::
_, _, err = util.RunAndWait(exec.Command("netsh",
"interface",
"ipv4",
"ipv6",
"add",
"route",
r,
s.GetName(),
tunIp,
strings.Split(r, "/")[0],
))
if err != nil {
log.Warn().Msgf("Failed to set route %s to tun device", r)
Expand All @@ -88,10 +152,7 @@ func (s *Cli) SetRoute(ipRange []string, excludeIpRange []string) error {
anyRouteOk = true
}
}
if !anyRouteOk {
return AllRouteFailError{lastErr}
}
return lastErr
return anyRouteOk, lastErr
}

// CheckRoute check whether all route rule setup properly
Expand All @@ -100,7 +161,7 @@ func (s *Cli) CheckRoute(ipRange []string) []string {

ktIdx, _, err := getInterfaceIndex(s)
if err != nil || ktIdx == "" {
log.Warn().Msgf("Failed to found kt network interface")
log.Warn().Msgf("Failed to found et network interface")
}

records, err := getKtRouteRecords(s)
Expand Down Expand Up @@ -253,9 +314,9 @@ func getKtRouteRecords(s *Cli) ([]RouteRecord, error) {
continue
}
records = append(records, RouteRecord{
TargetRange: ipRange,
TargetRange: ipRange,
InterfaceIndex: idx,
InterfaceName: iface,
InterfaceName: iface,
})
}
return records, nil
Expand Down
1 change: 1 addition & 0 deletions pkg/router/route.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ upstream {{$.Service}}-kt-stuntman-{{index $port 0}} {
{{range $port := .Ports}}
server {
listen {{index $port 1}};
listen [::]:{{index $port 1}};
server_name {{$.Service}};
underscores_in_headers on;
proxy_intercept_errors off;
Expand Down

0 comments on commit d4c5544

Please sign in to comment.