Skip to content

Commit

Permalink
feat: implement route checking and always restore route when exiting
Browse files Browse the repository at this point in the history
  • Loading branch information
linfan committed May 26, 2022
1 parent 504e95d commit 3bd4d4f
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 48 deletions.
8 changes: 3 additions & 5 deletions pkg/kt/command/clean/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,9 @@ func TidyLocalResources() {
dns.DropHosts()
log.Debug().Msg("Cleaning DNS configuration")
dns.Ins().RestoreNameServer()
if opt.Get().Clean.SweepLocalRoute {
log.Info().Msgf("Cleaning route table")
if err := tun.Ins().RestoreRoute(); err != nil {
log.Warn().Err(err).Msgf("Unable to clean up route table")
}
log.Info().Msgf("Cleaning route table")
if err := tun.Ins().RestoreRoute(); err != nil {
log.Warn().Err(err).Msgf("Unable to clean up route table")
}
} else {
log.Info().Msgf("Not %s user, DNS cleanup skipped", util.GetAdminUserName())
Expand Down
6 changes: 6 additions & 0 deletions pkg/kt/command/general/teardown.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
opt "github.com/alibaba/kt-connect/pkg/kt/command/options"
"github.com/alibaba/kt-connect/pkg/kt/service/cluster"
"github.com/alibaba/kt-connect/pkg/kt/service/dns"
"github.com/alibaba/kt-connect/pkg/kt/service/tun"
"github.com/alibaba/kt-connect/pkg/kt/util"
"github.com/rs/zerolog/log"
"os"
Expand Down Expand Up @@ -38,6 +39,11 @@ func recoverGlobalHostsAndProxy() {
log.Debug().Msg("Dropping hosts records ...")
dns.DropHosts()
}
if strings.HasPrefix(opt.Get().Connect.DnsMode, util.DnsModeLocalDns) {
if err := tun.Ins().RestoreRoute(); err != nil {
log.Debug().Err(err).Msgf("Failed to restore route table")
}
}
}

func cleanLocalFiles() {
Expand Down
5 changes: 0 additions & 5 deletions pkg/kt/command/options/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ func CleanFlags() []OptionConfig {
DefaultValue: false,
Description: "Only check and restore local changes made by kt",
},
{
Target: "SweepLocalRoute",
DefaultValue: false,
Description: "(Beta) Also clean up local route table record created by kt",
},
}
return flags
}
1 change: 0 additions & 1 deletion pkg/kt/command/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ type CleanOptions struct {
DryRun bool
ThresholdInMinus int64
LocalOnly bool
SweepLocalRoute bool
}

// ConfigOptions ...
Expand Down
31 changes: 29 additions & 2 deletions pkg/kt/service/tun/tun_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

// CheckContext check everything needed for tun setup
func (s *Cli) CheckContext() error {
// TODO: check whether ifconfig and route command exists
// TODO: check whether ifconfig, route and netstat command exists
return nil
}

Expand Down Expand Up @@ -70,11 +70,38 @@ func (s *Cli) SetRoute(ipRange []string) error {

// CheckRoute check whether all route rule setup properly
func (s *Cli) CheckRoute(ipRange []string) []string {
return []string{}
var failedIpRange []string
// run command: netstat -rn
out, _, err := util.RunAndWait(exec.Command("netstat",
"-rn",
))
if err != nil {
log.Warn().Msgf("Failed to get route table")
return failedIpRange
}
util.BackgroundLogger.Write([]byte(">> Get route: " + out + util.Eol))

for _, ir := range ipRange {
found := false
for _, line := range strings.Split(out, util.Eol) {
ip := strings.Split(ir, "/")[0]
if strings.HasPrefix(line, ip) {
if strings.HasSuffix(line, s.GetName()) {
found = true
}
break
}
}
if !found {
failedIpRange = append(failedIpRange, ir)
}
}
return failedIpRange
}

// RestoreRoute delete route rules made by kt
func (s *Cli) RestoreRoute() error {
// Route will be auto removed when tun device destroyed
return nil
}

Expand Down
30 changes: 29 additions & 1 deletion pkg/kt/service/tun/tun_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/alibaba/kt-connect/pkg/kt/util"
"github.com/rs/zerolog/log"
"os/exec"
"strings"
)

// CheckContext check everything needed for tun setup
Expand Down Expand Up @@ -53,11 +54,38 @@ func (s *Cli) SetRoute(ipRange []string) error {

// CheckRoute check whether all route rule setup properly
func (s *Cli) CheckRoute(ipRange []string) []string {
return []string{}
var failedIpRange []string
// run command: ip route show
out, _, err := util.RunAndWait(exec.Command("ip",
"route",
"show",
))
if err != nil {
log.Warn().Msgf("Failed to get route table")
return failedIpRange
}
util.BackgroundLogger.Write([]byte(">> Get route: " + out + util.Eol))

for _, ir := range ipRange {
found := false
for _, line := range strings.Split(out, util.Eol) {
if strings.HasPrefix(line, ir) {
if strings.HasSuffix(line, s.GetName()) {
found = true
}
break
}
}
if !found {
failedIpRange = append(failedIpRange, ir)
}
}
return failedIpRange
}

// RestoreRoute delete route rules made by kt
func (s *Cli) RestoreRoute() error {
// Route will be auto removed when tun device destroyed
return nil
}

Expand Down
142 changes: 108 additions & 34 deletions pkg/kt/service/tun/tun_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import (
"strings"
)

type RouteRecord struct {
TargetRange string
InterfaceIndex string
InterfaceName string
}

// CheckContext check everything needed for tun setup
func (s *Cli) CheckContext() (err error) {
defer func() {
Expand Down Expand Up @@ -87,14 +93,92 @@ func (s *Cli) SetRoute(ipRange []string) error {

// CheckRoute check whether all route rule setup properly
func (s *Cli) CheckRoute(ipRange []string) []string {
return []string{}
var failedIpRange []string
records, err := getKtRouteRecords(s)
if err != nil {
log.Warn().Err(err).Msgf("Route check skipped")
return []string{}
}

for _, ir := range ipRange {
found := false
for _, r := range records {
if ir == r.TargetRange {
found = true
break
}
}
if !found {
failedIpRange = append(failedIpRange, ir)
}
}

return failedIpRange
}

// RestoreRoute delete route rules made by kt
func (s *Cli) RestoreRoute() error {
var lastErr error
// run command: netsh interface ipv4 show route store=persistent
records, err := getKtRouteRecords(s)
if err != nil {
return err
}

for _, r := range records {
// run command: netsh interface ipv4 delete route store=persistent 172.20.0.0/16 29 172.20.0.0
_, _, err = util.RunAndWait(exec.Command("netsh",
"interface",
"ipv4",
"delete",
"route",
"store=persistent",
r.TargetRange,
r.InterfaceIndex,
r.InterfaceName,
))
if err != nil {
log.Warn().Msgf("Failed to clean route to %s", r.TargetRange)
lastErr = err
} else {
log.Info().Msgf(" * %s", r.TargetRange)
}
}
return lastErr
}

func (s *Cli) GetName() string {
return util.TunNameWin
}

func getKtRouteRecords(s *Cli) ([]RouteRecord, error) {
records := []RouteRecord{}
var ktIdx string

// run command: netsh interface ipv4 show interfaces
out, _, err := util.RunAndWait(exec.Command("netsh",
"interface",
"ipv4",
"show",
"interfaces",
))
if err != nil {
log.Error().Msgf("failed to get network interfaces")
return nil, err
}
util.BackgroundLogger.Write([]byte(">> Get interfaces: " + out + util.Eol))

for _, line := range strings.Split(out, util.Eol) {
if strings.HasSuffix(line, s.GetName()) {
ktIdx = strings.SplitN(strings.TrimPrefix(line, " "), " ", 2)[0]
break
}
}
if ktIdx == "" {
return nil, fmt.Errorf("failed to found kt network interface")
}

// run command: netsh interface ipv4 show route store=persistent
out, _, err = util.RunAndWait(exec.Command("netsh",
"interface",
"ipv4",
"show",
Expand All @@ -103,57 +187,47 @@ func (s *Cli) RestoreRoute() error {
))
if err != nil {
log.Warn().Msgf("failed to get route table")
return err
return nil, err
}
util.BackgroundLogger.Write([]byte(">> Get route: " + out + util.Eol))

reachRecord := false
for _, line := range strings.Split(out, util.Eol) {
// Assume only kt using gateway address of x.x.x.0
if !strings.HasSuffix(line, ".0") {
if strings.HasPrefix(line, "--") && strings.HasSuffix(line, "--") {
reachRecord = true
continue
}
if !reachRecord {
continue
}
parts := strings.Split(line, " ")
ipRange := ""
idx := ""
iface := ""
gateway := ""
index := 0
for i := len(parts) - 1; i >= 0; i-- {
for i := 0; i < len(parts); i++ {
if parts[i] != "" {
index++
if index == 3 {
ipRange = parts[i]
break
} else if index == 2 {
} else if index == 4 {
idx = parts[i]
} else if index == 5 {
iface = parts[i]
} else if index == 1 {
gateway = parts[i]
} else if index > 5 {
iface = fmt.Sprintf("%s %s", iface, parts[i])
}
index++
}
}
if ipRange == "" {
if ktIdx != idx && ipRange != "" && iface != "" {
continue
}
// run command: netsh interface ipv4 delete route store=persistent 172.20.0.0/16 29 172.20.0.0
_, _, err = util.RunAndWait(exec.Command("netsh",
"interface",
"ipv4",
"delete",
"route",
"store=persistent",
ipRange,
iface,
gateway,
))
if err != nil {
log.Warn().Msgf("Failed to clean route to %s", ipRange)
lastErr = err
} else {
log.Info().Msgf(" * %s", ipRange)
}
records = append(records, RouteRecord{
TargetRange: ipRange,
InterfaceIndex: idx,
InterfaceName: iface,
})
}
return lastErr
}

func (s *Cli) GetName() string {
return util.TunNameWin
return records, nil
}

0 comments on commit 3bd4d4f

Please sign in to comment.