diff --git a/.gitignore b/.gitignore index ab87bcf..fa329a2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,7 @@ .idea v2raya /kone +/my.ini +/kone.exe /coverage.txt cmd/kone/local.ini diff --git a/README.md b/README.md index 5bf1e40..880f8fa 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ By now, it supports: * linux * macosx -* windows (8 / Server 2012 and above) +* windows (10 and above) (refer to [use kone in windows](./misc/windows/README.md) for more information) ## Use diff --git a/cmd/kone/main.go b/cmd/kone/main.go index 0d1dbb8..b5b17ae 100644 --- a/cmd/kone/main.go +++ b/cmd/kone/main.go @@ -54,13 +54,13 @@ func main() { cfg, err := kone.ParseConfig(configFile) if err != nil { logger.Error(err.Error()) - os.Exit(1) + os.Exit(2) } one, err := kone.FromConfig(cfg) if err != nil { logger.Error(err.Error()) - os.Exit(1) + os.Exit(3) } one.Serve() } diff --git a/config.go b/config.go index bbd223a..462aca3 100644 --- a/config.go +++ b/config.go @@ -8,6 +8,7 @@ package kone import ( "os" "strings" + "unicode" "gopkg.in/ini.v1" ) @@ -41,7 +42,7 @@ type CoreConfig struct { } type RuleConfig struct { - Scheme string + Schema string Pattern string Proxy string } @@ -58,11 +59,16 @@ func (cfg *KoneConfig) parseRule(sec *ini.Section) (err error) { var ops []string for _, key := range keys { - ops = strings.Split(key, ",") - logger.Infof("%s %v", key, ops) + ops = strings.FieldsFunc(key, func(c rune) bool { + if c == ',' || unicode.IsSpace(c) { + return true + } + return false + }) + logger.Debugf("%s %v", key, ops) if len(ops) == 3 { // ignore invalid format cfg.Rule = append(cfg.Rule, RuleConfig{ - Scheme: ops[0], + Schema: ops[0], Pattern: ops[1], Proxy: ops[2], }) @@ -70,7 +76,7 @@ func (cfg *KoneConfig) parseRule(sec *ini.Section) (err error) { } if len(ops) == 2 { //final rule cfg.Rule = append(cfg.Rule, RuleConfig{ - Scheme: ops[0], + Schema: ops[0], Proxy: ops[1], }) } diff --git a/config_test.go b/config_test.go index 88dc0c4..6b980c3 100644 --- a/config_test.go +++ b/config_test.go @@ -43,8 +43,8 @@ const ( Proxy2 = socks5://127.0.0.1:9080 [Rule] - IP-CIDR,91.108.4.0/22,Proxy1 - IP-CIDR,91.108.56.0/22,Proxy1 + IP-CIDR, 91.108.4.0/22, Proxy1 # rule 0 + IP-CIDR,91.108.56.0/22,Proxy1 # rule 1 IP-CIDR,109.239.140.0/24,Proxy1 IP-CIDR,149.154.167.0/24,Proxy1 IP-CIDR,172.16.0.0/16,DIRECT @@ -53,7 +53,7 @@ const ( IP-CIDR6,2001:db8:abcd:8000::/50,DIRECT # match if the domain - DOMAIN,www.twitter.com,Proxy1 + DOMAIN, www.twitter.com, Proxy1 DOMAIN-SUFFIX,twitter.com,Proxy1 DOMAIN-SUFFIX,telegram.org,Proxy1 DOMAIN-KEYWORD,google,Proxy1 @@ -61,10 +61,11 @@ const ( DOMAIN-KEYWORD,baidu,REJECT # match if the GeoIP test result matches a specified country code - GEOIP,US,DIRECT + GEOIP,US,DIRECT # rule 13 # define default policy for requests which are not matched by any other rules - FINAL,DIRECT` + FINAL,DIRECT # rule 14 + ` ) func TestParseConfig(t *testing.T) { @@ -96,4 +97,15 @@ func TestParseConfig(t *testing.T) { assert.Equal(t, "socks5://127.0.0.1:9080", cfg.Proxy["Proxy2"]) assert.Len(t, cfg.Rule, 15) + assert.Equal(t, cfg.Rule[0].Schema, "IP-CIDR") + assert.Equal(t, cfg.Rule[0].Pattern, "91.108.4.0/22") + assert.Equal(t, cfg.Rule[0].Proxy, "Proxy1") + + assert.Equal(t, cfg.Rule[1].Schema, "IP-CIDR") + assert.Equal(t, cfg.Rule[1].Pattern, "91.108.56.0/22") + assert.Equal(t, cfg.Rule[1].Proxy, "Proxy1") + + assert.Equal(t, cfg.Rule[14].Schema, "FINAL") + assert.Equal(t, cfg.Rule[14].Pattern, "") + assert.Equal(t, cfg.Rule[14].Proxy, "DIRECT") } diff --git a/misc/windows/README.md b/misc/windows/README.md new file mode 100644 index 0000000..415d2a3 --- /dev/null +++ b/misc/windows/README.md @@ -0,0 +1,13 @@ +# use kone in Windows + +## 预设条件 +1. 安装 tap-windows (NDIS 6) +[tap-windows](https://community.openvpn.net/openvpn/wiki/GettingTapWindows) +[直接下载](https://build.openvpn.net/downloads/releases/tap-windows-9.21.0.exe) + +2. 配置防火墙,允许kone重定向连接 +使用管理员权限启动 PowerShell,执行`update-firewall-rules.ps1`。 + +>>> 请注意修改 `update-firewall-rules.ps1` 脚本中 Program 参数为kone实际路径。 + +3. 编译&运行kone方式同linux \ No newline at end of file diff --git a/misc/windows/check-firewall-rules.ps1 b/misc/windows/check-firewall-rules.ps1 new file mode 100644 index 0000000..5940731 --- /dev/null +++ b/misc/windows/check-firewall-rules.ps1 @@ -0,0 +1,19 @@ +#Requires -Version 3 +#Requires -Modules NetSecurity + +$List = Get-NetFirewallRule -Enabled True -Action Allow -Description 'Work with Kone.' | Where-Object { 'Kone' -eq $_.DisplayName } +$Report = foreach ($Rule in $List) +{ + $Program = (Get-NetFirewallApplicationFilter -AssociatedNetFirewallRule $Rule).Program + + @{ + Profile = $Rule.Profile + Enabled = $Rule.Enabled + Action = $Rule.Action + Protocol = (Get-NetFirewallPortFilter -AssociatedNetFirewallRule $Rule).Protocol + Program = $Program + IsPathValid = Test-Path -PathType Leaf -LiteralPath $Program + } +} +$Report +Pause \ No newline at end of file diff --git a/misc/windows/update-firewall-rules.ps1 b/misc/windows/update-firewall-rules.ps1 new file mode 100644 index 0000000..965640e --- /dev/null +++ b/misc/windows/update-firewall-rules.ps1 @@ -0,0 +1,13 @@ +# $Program should direct to execute file +Remove-NetFirewallRule -Description "Work with Kone." -ErrorAction SilentlyContinue +'TCP', 'UDP' | ForEach-Object { + New-NetFirewallRule ` + -DisplayName "Kone" ` + -Profile "Any" ` + -Description "Work with Kone." ` + -Direction Inbound ` + -Protocol $_ ` + -Action Allow ` + -Program "E:\go\github\kone\kone.exe" ` + | Out-Null +} \ No newline at end of file diff --git a/nat.go b/nat.go index 35812e3..f4ec33d 100644 --- a/nat.go +++ b/nat.go @@ -90,6 +90,10 @@ type Nat struct { } func (nat *Nat) getSession(port uint16) *NatSession { + if port < nat.tbl.from || port >= nat.tbl.to { + return nil + } + session := nat.sessions[port-nat.tbl.from] if session != nil { session.lastTouch = time.Now().Unix() @@ -139,6 +143,7 @@ func (nat *Nat) count() int { return nat.tbl.Count() } +// port range [from, to) func NewNat(from, to uint16) *Nat { count := to - from tbl := &NatTable{ diff --git a/pattern.go b/pattern.go index eb00b69..cc763ed 100644 --- a/pattern.go +++ b/pattern.go @@ -175,7 +175,7 @@ func NewFinalPattern(proxy string) FinalPattern { func CreatePattern(rc RuleConfig) Pattern { proxy := rc.Proxy pattern := rc.Pattern - schema := strings.ToUpper(rc.Scheme) + schema := strings.ToUpper(rc.Schema) switch schema { case "DOMAIN": @@ -188,7 +188,7 @@ func CreatePattern(rc RuleConfig) Pattern { fallthrough case "IP-CIDR6": if proxy == "DIRECT" { // all IPNet default proxy is DIRECT - logger.Debugf("skip DIRECT rule: %s,%s,%s", rc.Scheme, rc.Pattern, rc.Proxy) + logger.Debugf("skip DIRECT rule: %s,%s,%s", rc.Schema, rc.Pattern, rc.Proxy) return nil } _, ipNet, err := net.ParseCIDR(pattern) @@ -200,6 +200,6 @@ func CreatePattern(rc RuleConfig) Pattern { case "FINAL": return NewFinalPattern(proxy) } - logger.Errorf("invalid rule: %s,%s,%s", rc.Scheme, rc.Pattern, rc.Proxy) + logger.Errorf("invalid rule: %s,%s,%s", rc.Schema, rc.Pattern, rc.Proxy) return nil } diff --git a/tcp_relay.go b/tcp_relay.go index d6483ae..2b495c8 100644 --- a/tcp_relay.go +++ b/tcp_relay.go @@ -85,7 +85,7 @@ func (r *TCPRelay) handleConn(conn net.Conn) { return } - if proxy == "DIRECT" { + if proxy == "DIRECT" { // impossible conn.Close() logger.Errorf("[tcp] %s > %s traffic dead loop", conn.LocalAddr(), remoteAddr) return