├── .gitignore ├── start.sh ├── keys ├── demo ├── server.crt └── server.key ├── dogtunnel ├── BUG ├── TODO ├── scripts ├── doghole.sh ├── install_linux.sh └── install_ubuntu.sh ├── test.sh ├── Makefile ├── auth ├── auth.sql └── auth.go ├── common ├── cache_test.go ├── cache.go ├── common.go └── servercommon.go ├── doc └── docker.md ├── release.sh ├── LICENSE ├── README.md ├── ikcp ├── ikcp_h.go ├── ikcp_test_h.go ├── ikcp_test.go └── ikcp.go ├── nat ├── gather.go ├── nat.go ├── connection.go └── stun │ └── stun.go ├── admin └── admin.go ├── server.go └── client.go /.gitignore: -------------------------------------------------------------------------------- 1 | dtunnel 2 | dtunnel_s 3 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | nohup ./dtunnel_s -ssl -admin :8009 -dbuser dog -dbpass dog -cert keys/server.crt -key keys/server.key -https -addr :8008 > log.txt 2>&1 & 3 | -------------------------------------------------------------------------------- /keys/demo: -------------------------------------------------------------------------------- 1 | # server 2 | go run server.go -ssl -cert keys/server.crt -key keys/server.key 3 | # client A 4 | go run client.go -reg v -local :22 -ssl 5 | # client B 6 | go run client.go -link v -local :8888 -ssl 7 | -------------------------------------------------------------------------------- /dogtunnel: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BASE_DIR=`dirname $0` 4 | if [ -L $0 ] 5 | then 6 | BASE_DIR=`dirname $(readlink $0)` 7 | fi 8 | cd $BASE_DIR 9 | go run client.go -remote dog-tunnel.tk:8008 -key test -ssl -local :8888 -delay 2 -stun stun.l.google.com:19302 $@ 10 | -------------------------------------------------------------------------------- /BUG: -------------------------------------------------------------------------------- 1 | 2014-01-06:某些网络环境(A,B),要求穿透方向必须是A向B发起,否则会穿透失败。所以必须实现重试机制,双方互换顺序进行穿透,由tcp server控制(fixed) 2 | 2014-01-19:对外ip有多个的网络环境,提供手工指明ip列表和stun服务辅助检测ip的机制进行穿透(fixed) 3 | 2014-01-29:对于nat更改监听端口的情况没有处理,导致穿透失败(fixed) 4 | 2014-01-31:网络不好的情况下,重试机制出现问题,导致收发包混乱,并且超时机制也处理错误,断开连接后仍在尝试发送数据(fixed) 5 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | (%100)udp发包ack确认,失败自动重发,发包顺序简单校验 2 | (%100)客户端穿透失败自动换向重连 3 | (%80)服务端管理端口,广播,踢人,关服,限制人数,限制ip,限制服务名 4 | (%100)版本校验 5 | (%100)udp穿透失败后切换成c/s模式 6 | (%100)客户端会话支持打多个洞,备用洞用于内嵌shell功能 7 | (%80)账号数据存储,登录认证,登录次数,流量,时长限制(go-sql-driver) 8 | (%80)配置文件支持(账号密码读取,json file) 9 | (%100)客户端会话支持sock5 proxy 10 | (%0)nat类型检测 11 | (%0)新的分级日志(factorlog) 12 | 13 | -------------------------------------------------------------------------------- /scripts/doghole.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # move dtunnel to $HOME/bin/dtunnel 3 | # echo "mypassword" > $HOME/.ssh/pw 4 | 5 | cat $HOME/.ssh/pw | sudo -S killall -9 dtunnel 6 | sleep 2 7 | 8 | 9 | # the server side 10 | 11 | cat $HOME/.ssh/pw | sudo -S nice -n -10 $HOME/bin/dtunnel --reg node1.domain.com -local socks5 -clientkey verylongpasswd & 12 | 13 | # the client side 14 | 15 | cat $HOME/.ssh/pw | sudo -S nice -n -10 $HOME/bin/dtunnel --link node1.domain.com -local :7070 -clientkey verylongpasswd & 16 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # first run server,make client,and reg a,then run this bash to test 3 | declare -i i=0 4 | declare -i maxN=30 5 | 6 | while [ $i -lt $maxN ] 7 | do 8 | declare -i j=$i+10000 9 | ./dtunnel -link a -local :$j -pipen 4 -v > test_$j.log 2>&1 & 10 | i=$i+1 11 | done 12 | #maybe longer 13 | sleep 5 14 | declare -i n=`grep "service start success" test*.log|wc -l` 15 | if [ $n -eq $maxN ] 16 | then 17 | echo "test ok" 18 | else 19 | cat test*.log 20 | fi 21 | ps aux|grep "link a"|grep -v grep|awk '{print $2}'|xargs kill 22 | rm test*.log 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | @make release 4 | release: 5 | make client 6 | make server 7 | debug: 8 | make client_debug 9 | make server_debug 10 | client_debug: 11 | @go build -gcflags "-N -l" -o dtunnel_d client.go 12 | server_debug: 13 | @go build -gcflags "-N -l" -o dtunnel_s_d server.go 14 | client: 15 | @go build -ldflags "-s -w" -o dtunnel client.go 16 | server: 17 | @go build -ldflags "-s -w" -o dtunnel_s server.go 18 | clean: 19 | @rm -rf dtunnel dtunnel_d dtunnel_s_d dtunnel_s 20 | .PHONY: all debug release client_debug server_debug client server clean 21 | -------------------------------------------------------------------------------- /scripts/install_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # need run as root 3 | cd ~ 4 | yum install -y tar 5 | mkdir /root/goworkspace 6 | wget https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz 7 | tar zxvf go1.4.2.linux-amd64.tar.gz 8 | echo 'export GOROOT=/root/go' >> .bashrc 9 | echo 'export GOPATH=/root/goworkspace' >> .bashrc 10 | echo 'export PATH="/root/go/bin:/root/goworkspace/bin:"$PATH' >> .bashrc 11 | source ~/.bashrc 12 | yum install -y git 13 | git clone https://github.com/vzex/dog-tunnel.git 14 | cd dog-tunnel 15 | go get github.com/go-sql-driver/mysql 16 | make 17 | mv dtunnel /usr/bin/dtunnel 18 | -------------------------------------------------------------------------------- /auth/auth.sql: -------------------------------------------------------------------------------- 1 | use dogtunnel; 2 | 3 | DROP TABLE IF EXISTS users; 4 | CREATE TABLE users( 5 | UserName varchar(50) NOT NULL, 6 | Passwd varchar(50) NOT NULL, 7 | UserType tinyint NOT NULL DEFAULT 0, 8 | AuthKey varchar(40) NOT NULL DEFAULT "", 9 | LastLoginTime int(11) NOT NULL DEFAULT 0, 10 | LastLogoutTime int(11) NOT NULL DEFAULT 0, 11 | MaxOnlineServerNum int NOT NULL DEFAULT 2, 12 | MaxSessionNum int NOT NULL DEFAULT 2, 13 | MaxPipeNum int NOT NULL DEFAULT 2, 14 | MaxSameIPServers int NOT NULL DEFAULT 2, 15 | TodayCSModeData int NOT NULL DEFAULT 0, 16 | LimitDataSize int NOT NULL DEFAULT 0, 17 | PRIMARY KEY (UserName), 18 | UNIQUE KEY (AuthKey) 19 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 20 | -------------------------------------------------------------------------------- /scripts/install_ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # need run as root 3 | cd ~ 4 | apt-get update && apt-get dist-upgrade -y && echo 'Upgrade system ok' 5 | apt-get install tar wget curl git make gcc build-essential -y && echo 'package installed' 6 | mkdir /root/goworkspace 7 | wget https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz 8 | tar zxvf go1.4.2.linux-amd64.tar.gz 9 | echo 'export GOROOT=/root/go' >> .bashrc 10 | echo 'export GOPATH=/root/goworkspace' >> .bashrc 11 | echo 'export PATH="/root/go/bin:/root/goworkspace/bin:"$PATH' >> .bashrc 12 | source ~/.bashrc 13 | git clone https://github.com/vzex/dog-tunnel.git 14 | cd dog-tunnel 15 | go get github.com/go-sql-driver/mysql 16 | make 17 | mv dtunnel /usr/bin/dtunnel 18 | -------------------------------------------------------------------------------- /common/cache_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "testing" 4 | 5 | type m struct { 6 | T int 7 | w int 8 | } 9 | 10 | func (*m) IsAlive() bool { return true } 11 | func (*m) SetCacheTime(t int64) {} 12 | func (*m) DeInit() { println("deinit") } 13 | 14 | func TestCache(t *testing.T) { 15 | cache := GetCacheContainer("test") 16 | cache2 := GetCacheContainer("test2") 17 | println("addcache", "mmnn", "aabb") 18 | cache.AddCache("mm", &m{1, 2}, 0) 19 | cache.AddCache("nn", &m{3, 4}, 0) 20 | cache2.AddCache("aa", &m{1, 2}, 0) 21 | cache2.AddCache("bb", &m{3, 4}, 0) 22 | a := cache.GetCache("mm") 23 | b := cache.GetCache("mm") 24 | b.(*m).T = 12 25 | if (a.(*m)).T != 12 { 26 | t.Error("cache value copied!!") 27 | } 28 | if cache2.GetCache("novalue") != nil { 29 | t.Error("cache should be nil!!") 30 | } 31 | println("delcache", "mmnn", "aabb") 32 | DelAllCacheContainer() 33 | } 34 | -------------------------------------------------------------------------------- /doc/docker.md: -------------------------------------------------------------------------------- 1 | # Run dog tunnel with docker container 2 | 3 | First things, you need make sure you have installed docker on your linux environment. 4 | Following instruction was testing under ubuntu 14.04 or above. 5 | 6 | You need install docker on both your server side and client side 7 | 8 | ## server side 9 | 10 | 11 | ``` 12 | docker run -d --restart=always --name=dog-tunnel-server -p 0.0.0.0:8443:8443/udp netroby/alpine-dog-tunnel /usr/bin/dtunnel_lite -service 0.0.0.0:8443 -auth verystrongpassword2 13 | ``` 14 | 15 | ## client side 16 | 17 | Replace your service ip with your.remote.server, and run this command. 18 | 19 | ``` 20 | docker run -d --restart=always --name=dog-tunnel-client -p 0.0.0.0:8070:8070 netroby/alpine-dog-tunnel /usr/bin/dtunnel_lite -service your.remote.server:8443 -local :8070 -auth verystrongpassword2 21 | ``` 22 | If every thing ok, you will have socks5 proxy service listen on your local 0.0.0.0:8070 23 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | version=$1 3 | if [ $# -eq 0 ] 4 | then 5 | echo "Please input version, like \"./release.sh 0.60\"" 6 | exit 7 | fi 8 | rm -f dtunnel_*$1.tgz 9 | echo "Build ReleaseFile for version $version" 10 | 11 | echo "build linux_amd64" 12 | GOOS=linux GOARCH=amd64 make 13 | tar zcvf dtunnel_linux_x64_$1.tgz dtunnel dtunnel_s 14 | echo "build linux_386" 15 | GOOS=linux GOARCH=386 make 16 | tar zcvf dtunnel_linux_x86_$1.tgz dtunnel dtunnel_s 17 | echo "build mac_x64" 18 | GOOS=darwin GOARCH=amd64 make 19 | tar zcvf dtunnel_mac_x64_$1.tgz dtunnel dtunnel_s 20 | echo "build win32" 21 | GOOS=windows GOARCH=386 make && mv dtunnel dtunnel.exe && mv dtunnel_s dtunnel_s.exe 22 | tar zcvf dtunnel_win32_$1.tgz dtunnel.exe dtunnel_s.exe 23 | echo "build linux_arm" 24 | GOOS=linux GOARCH=arm make 25 | tar zcvf dtunnel_linux_arm_$1.tgz dtunnel dtunnel_s 26 | rm -f dtunnel dtunnel.exe dtunnel_s dtunnel_s.exe 27 | echo "Build Over" 28 | ls -l dtunnel_*$1.tgz 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 vzex 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /keys/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDdjCCAl4CCQDCMrV4+C2NPTANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJD 3 | TjERMA8GA1UECBMIWmhlSmlhbmcxETAPBgNVBAcTCEhhbmdaaG91MQ0wCwYDVQQK 4 | EwROb25lMQ0wCwYDVQQLEwROb25lMQ0wCwYDVQQDEwR2emV4MRswGQYJKoZIhvcN 5 | AQkBFgx2emV4QDE2My5jb20wHhcNMTQwMTAyMTY1NTQxWhcNMjMxMjMxMTY1NTQx 6 | WjB9MQswCQYDVQQGEwJDTjERMA8GA1UECBMIWmhlSmlhbmcxETAPBgNVBAcTCEhh 7 | bmdaaG91MQ0wCwYDVQQKEwROb25lMQ0wCwYDVQQLEwROb25lMQ0wCwYDVQQDEwR2 8 | emV4MRswGQYJKoZIhvcNAQkBFgx2emV4QDE2My5jb20wggEiMA0GCSqGSIb3DQEB 9 | AQUAA4IBDwAwggEKAoIBAQCd9TJzRMsSWfgfulF97a76kP5uQc/StVQZr34DSbMp 10 | ueFj6P1zG2TmEdIUFVh1Y34hAhhPzYSAdPWnpPjvQZ5pQFkr1b701qkOTJ4dYSc0 11 | cKv9/VxFYL0OmBaBPlNsIFJbEepEFww9zi3BGpSq1VyHXKA0quU/ToqfQaaKitR8 12 | U+ESgSxClogJxBFf2CnWhtHsMDUzizOTlH/CbZoYF8ezXTTN7MgvfJe4RT4BT6/i 13 | jwdjXJ/dm/eJY30VG7Eow9BVgG2yRH2blBd6EnzuyMwXKlBn78PYeX0VNrls2LP/ 14 | owFR86XFi0ZNKI0fN443APNEHndisH5npCVmc5yjfVnFAgMBAAEwDQYJKoZIhvcN 15 | AQEFBQADggEBABDxL6txncq0dMt2viMxeqmSOvKNjfSZcDvGOhJKFE5YRVntd0yf 16 | vHtLJIrzABapCsMoL+nCo01i2DRrOzhb8KOHrLDcp0WWB2/YUAg/bWgmoLXhwQ8L 17 | 1DOxF+6wQXpFPcWr9RybAmDReat0SO8pTHT4C+el/qW9iJZG0OZJ/vQQ7FETug6G 18 | UBenSyjWZsZM3D3rJdOUQZzUDc3HfNRgl11TJW9/79y1HT5UJysibgDFv083m3uN 19 | g9qMVhs3ORI6+TSUoRM3KIejvKPpl78j17taTAra4V3XC2ua01nT1WPw4wWy7U/p 20 | zwzaPKQqHZG8y+P1CqQ9l6C5pUWbtoinWwU= 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dog Tunnel 2 | 3 | ## Introduction 4 | 5 | Dog tunnel provide a P2P tunnel between your any two network, via UDP protocol on top of KCP. 6 | It's amazing fast and stable , gain better performance than other tunnel solution. 7 | It's written with pure golang by vzex. 8 | 9 | ## Installation 10 | ### Build From Source: 11 | 12 | go get -u -d github.com/vzex/dog-tunnel && cd $GOPATH/src/github.com/vzex/dog-tunnel/ && make 13 | 14 | ### [Run dog tunnel with docker container](doc/docker.md) 15 | 16 | 17 | 18 | ### Install dtunnel on Fedora 20/21 or CentOS 6/7 19 | 20 | We provided a bash scripts to install dtunnel on fresh linux box. 21 | 22 | see [scripts/install_linux.sh](scripts/install_linux.sh) 23 | 24 | ### Install dtunnel on Ubuntu/Kubuntu 14.04 and 14.10 25 | 26 | See [scripts/install_ubuntu.sh](scripts/install_ubuntu.sh) 27 | 28 | ## Specification 29 | 30 | 31 | ### udp make session flow : 32 | 33 | ``` 34 | s -> c1 : query_addrlist_a 35 | c1 -> s : report_addrlist 36 | s -> c2 : query_addrlist_b c2 have c1's addresses 37 | c2 -> s : report_addrlist 38 | s -> c1 : tell_bust_a c1 have c2's addresses 39 | c1 -> s : success_bust_a 40 | s -> c2 : tell_bust_b 41 | c2 -> s : makeholeok or makeholefail 42 | ``` 43 | ## Thanks 44 | 45 | [netroby](https://github.com/netroby) 46 | 47 | ## License 48 | 49 | [MIT License](LICENSE) 50 | 51 | ## Credits 52 | ![Welcome donate with Alipay && 欢迎使用支付宝对该项目进行捐赠](https://raw.githubusercontent.com/vzex/dog-tunnel/udpVersion/dog-tunnel.png) 53 | 54 | author: vzex@163.com 55 | -------------------------------------------------------------------------------- /keys/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAnfUyc0TLEln4H7pRfe2u+pD+bkHP0rVUGa9+A0mzKbnhY+j9 3 | cxtk5hHSFBVYdWN+IQIYT82EgHT1p6T470GeaUBZK9W+9NapDkyeHWEnNHCr/f1c 4 | RWC9DpgWgT5TbCBSWxHqRBcMPc4twRqUqtVch1ygNKrlP06Kn0GmiorUfFPhEoEs 5 | QpaICcQRX9gp1obR7DA1M4szk5R/wm2aGBfHs100zezIL3yXuEU+AU+v4o8HY1yf 6 | 3Zv3iWN9FRuxKMPQVYBtskR9m5QXehJ87sjMFypQZ+/D2Hl9FTa5bNiz/6MBUfOl 7 | xYtGTSiNHzeONwDzRB53YrB+Z6QlZnOco31ZxQIDAQABAoIBAC94E2w+nURrkzx9 8 | sqXEexRD5KJf1sO8yIRbj+QPDu+YM9rhluEzt1PIwThV3dqRRsNGrOW2nn44J+b0 9 | lfbY4nFA7EtXFebgZ7erYMz1eGGzBozyyfrzgn1TSVgX0dwprnY94QgLYRtlzaw9 10 | f7YDHqZzOJX7UZ9/y/rmMNVruUWPOqeQmf/YqL0aOK2AAu/+J5zB9nRJ7xHXsfDs 11 | 1HxgCiiLB/ubIMGt4g6RHr1JW61hXbSp+RP2x4xmXY0RSrIGOklxmcxVJM17kRWL 12 | 5DtQ6TqB0vL5or9WuwDMOtjJ6kKa31QmFv4X/e7c9JxzWZPDducquH1OtgRal9by 13 | e5/fjYECgYEAzu11eY3rx8fK2bqU7OwXSNMPVdtT4LaWjz0qqK04jn2yGXVnZMbC 14 | 3qk1+WASKp/bz9oZIiTCPJY32Re8Xa0Z8jC2UjQI/zs+nkk+DMJxZi34qIwdBAUs 15 | kSsU1YDVZ/uNN8Ne2jHVSFhB+q1bSqYn00zAUnXHMdITzWtX9+HSxaUCgYEAw2rK 16 | c+EmvxdJsTVkF35rVEmas7gjUJQWhaDLce2gk/6hpnhxeGdaM87l6rCaWrUwFvmp 17 | 16usEugSNCW74GSHF+zSEnkjSgmNjalWMHdaL4Vam29bxGauXWHXzhkAuP/R6VZb 18 | xSqe14KBN/9zV4eUclPrhHLyRtaSsZ9jaY7XSaECgYEAjdmeVEuDvBor5oHPIXLe 19 | q19z/ckygLLqFxs5KRRF1vg3pNgknqLaZ0Tb6S2AhpO7XYsG+67zMBFSC5IH4LeP 20 | N8VI1qUxHbYBQQS4corArekJspEKOv1JBeLgj1OX94Yr0nQti6npqYRHBo7cLBom 21 | 5uSQWna+rFp0lLbnQNgfYrkCgYBBNu9PUrEqjmwCXo4DpSXOYC3nkij+6BzIBYw/ 22 | fgzbtttdgc5kXyFkLsTd2If6g4MD99etaNYpDReeHYWgcgv/eQH2NkUHnT6HKx7f 23 | V8VaHIfLXZNjbNz9vvxVBFUQaBc2ZqKDnyCZTS0wceidKlro+Iadkfq2lz8nVcjI 24 | XmoMYQKBgQC9+51iodDemCmlMNnOU7e41dagrTiPCpuVvNm/AuWA5B/JKXWDatnV 25 | hnJG7PFwlcaeuqvteG2fQ3LVniuiSSXWrUmsE4mH4aqNj+1anop6FzejyNJeQEmM 26 | ielf2r1Ao0TKQJKWSnuPLDC3YuSU6GJZDBYYg+aEUxl/1tyE25J5UA== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /ikcp/ikcp_h.go: -------------------------------------------------------------------------------- 1 | package ikcp 2 | import "container/list" 3 | //===================================================================== 4 | // 5 | // KCP - A Better ARQ Protocol Implementation 6 | // skywind3000 (at) gmail.com, 2010-2011 7 | // 8 | // Features: 9 | // + Average RTT reduce 30% - 40% vs traditional ARQ like tcp. 10 | // + Maximum RTT reduce three times vs tcp. 11 | // + Lightweight, distributed as a single source file. 12 | // 13 | //===================================================================== 14 | //--------------------------------------------------------------------- 15 | // IKCPCB 16 | //--------------------------------------------------------------------- 17 | type IKCPCB struct { 18 | conv, mtu, mss, state uint32 19 | snd_una, snd_nxt, rcv_nxt uint32 20 | ts_recent, ts_lastack, ssthresh uint32 21 | rx_rttval, rx_srtt, rx_rto, rx_minrto uint32 22 | snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe uint32 23 | current, interval, ts_flush, xmit uint32 24 | nrcv_buf, nsnd_buf uint32 25 | nrcv_que, nsnd_que uint32 26 | nodelay, updated uint32 27 | ts_probe, probe_wait uint32 28 | dead_link, incr uint32 29 | snd_queue, rcv_queue, snd_buf, rcv_buf *list.List 30 | acklist []uint32 31 | ackcount uint32 32 | ackblock uint32 33 | user interface{} 34 | buffer []byte 35 | fastresend int32 36 | nocwnd int32 37 | logmask int32 38 | writelog func (log []byte, kcp *Ikcpcb, user []byte) 39 | 40 | Output func (buf []byte, _len int32, kcp *Ikcpcb, user interface{}) (int32) 41 | } 42 | 43 | 44 | type Ikcpcb struct {IKCPCB} 45 | 46 | const IKCP_LOG_OUTPUT = 1 47 | const IKCP_LOG_INPUT = 2 48 | const IKCP_LOG_SEND = 4 49 | const IKCP_LOG_RECV = 8 50 | const IKCP_LOG_IN_DATA = 16 51 | const IKCP_LOG_IN_ACK = 32 52 | const IKCP_LOG_IN_PROBE = 64 53 | const IKCP_LOG_IN_WIN = 128 54 | const IKCP_LOG_OUT_DATA =256 55 | const IKCP_LOG_OUT_ACK = 512 56 | const IKCP_LOG_OUT_PROBE = 1024 57 | const IKCP_LOG_OUT_WINS = 2048 58 | -------------------------------------------------------------------------------- /common/cache.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type cache interface { 8 | SetCacheTime(int64) //if arg < 0, just update alive time 9 | IsAlive() bool 10 | DeInit() 11 | } 12 | 13 | type cacheContainer struct { 14 | c map[string]cache 15 | } 16 | 17 | func (container *cacheContainer) UpdateCache(key string, c cache) { 18 | container.c[key] = c 19 | } 20 | 21 | func (container *cacheContainer) AddCache(key string, c cache, cacheTime int64) { 22 | container.DelCache(key) 23 | container.c[key] = c 24 | c.SetCacheTime(cacheTime) 25 | } 26 | 27 | func (container *cacheContainer) GetCache(key string) cache { 28 | v, bHave := container.c[key] 29 | if bHave { 30 | if v.IsAlive() { 31 | return v 32 | } else { 33 | container.DelCache(key) 34 | } 35 | } 36 | return nil 37 | } 38 | 39 | func (container *cacheContainer) DelCache(key string) bool { 40 | v, bHave := container.c[key] 41 | if bHave { 42 | v.DeInit() 43 | delete(container.c, key) 44 | return true 45 | } 46 | return false 47 | } 48 | 49 | func (container *cacheContainer) DelAllCache() { 50 | for key, _ := range container.c { 51 | container.DelCache(key) 52 | } 53 | } 54 | 55 | var g_CacheMgr map[string]*cacheContainer 56 | 57 | func init() { 58 | g_CacheMgr = make(map[string]*cacheContainer) 59 | go func() { 60 | c := time.Tick(time.Second * 30) 61 | for _ = range c { 62 | for k, cache := range g_CacheMgr { 63 | for key, info := range cache.c { 64 | if !info.IsAlive() { 65 | info.DeInit() 66 | delete(cache.c, key) 67 | } 68 | } 69 | if len(cache.c) == 0 { 70 | delete(g_CacheMgr, k) 71 | } 72 | } 73 | } 74 | }() 75 | } 76 | 77 | func GetCacheContainer(key string) *cacheContainer { 78 | c, bHave := g_CacheMgr[key] 79 | if bHave { 80 | return c 81 | } 82 | c = &cacheContainer{c: make(map[string]cache)} 83 | g_CacheMgr[key] = c 84 | return c 85 | } 86 | 87 | func DelCacheContainer(key string) { 88 | c, bHave := g_CacheMgr[key] 89 | if bHave { 90 | c.DelAllCache() 91 | } 92 | delete(g_CacheMgr, key) 93 | } 94 | 95 | func DelAllCacheContainer() { 96 | for key, c := range g_CacheMgr { 97 | c.DelAllCache() 98 | delete(g_CacheMgr, key) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /nat/gather.go: -------------------------------------------------------------------------------- 1 | package nat 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net" 7 | "strconv" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | var lanNets = []*net.IPNet{ 13 | {net.IPv4(10, 0, 0, 0), net.CIDRMask(8, 32)}, 14 | {net.IPv4(172, 16, 0, 0), net.CIDRMask(12, 32)}, 15 | {net.IPv4(192, 168, 0, 0), net.CIDRMask(16, 32)}, 16 | {net.ParseIP("fc00"), net.CIDRMask(7, 128)}, 17 | } 18 | 19 | type candidate struct { 20 | Addr *net.UDPAddr 21 | } 22 | 23 | func (c candidate) String() string { 24 | return fmt.Sprintf("%v", c.Addr) 25 | } 26 | 27 | func (c candidate) Equal(c2 candidate) bool { 28 | return c.Addr.IP.Equal(c2.Addr.IP) && c.Addr.Port == c2.Addr.Port 29 | } 30 | 31 | func pruneDups(cs []candidate) []candidate { 32 | ret := make([]candidate, 0, len(cs)) 33 | for _, c := range cs { 34 | unique := true 35 | for _, c2 := range ret { 36 | if c.Equal(c2) { 37 | unique = false 38 | break 39 | } 40 | } 41 | if unique { 42 | ret = append(ret, c) 43 | } 44 | } 45 | return ret 46 | } 47 | 48 | func GatherCandidates(sock *net.UDPConn, outIpList string, udpAddr string) ([]candidate, error) { 49 | laddr := sock.LocalAddr().(*net.UDPAddr) 50 | ret := []candidate{} 51 | switch { 52 | case laddr.IP.IsLoopback(): 53 | return nil, errors.New("Connecting over loopback not supported") 54 | case laddr.IP.IsUnspecified(): 55 | addrs, err := net.InterfaceAddrs() 56 | if err != nil { 57 | return nil, err 58 | } 59 | 60 | for _, addr := range addrs { 61 | ip, ok := addr.(*net.IPNet) 62 | if ok && ip.IP.IsGlobalUnicast() { 63 | ret = append(ret, candidate{&net.UDPAddr{IP: ip.IP, Port: laddr.Port}}) 64 | } 65 | } 66 | default: 67 | ret = append(ret, candidate{laddr}) 68 | } 69 | 70 | addip := func(ipStr string, port int) { 71 | ip := net.ParseIP(ipStr) 72 | if port == 0 { 73 | port = laddr.Port 74 | } 75 | bHave := false 76 | for _, info := range ret { 77 | if info.Addr.IP.Equal(ip) && info.Addr.Port == port { 78 | bHave = true 79 | break 80 | } 81 | } 82 | if !bHave { 83 | ret = append(ret, candidate{&net.UDPAddr{IP: ip, Port: port}}) 84 | } 85 | } 86 | 87 | if udpAddr != "" { 88 | addr, err := net.ResolveUDPAddr("udp", udpAddr) 89 | if err != nil { 90 | fmt.Println("Can't resolve udp address: ", err) 91 | return nil, err 92 | } 93 | p2pAddr := "" 94 | 95 | for i := 0; i < 5; i++ { 96 | sock.WriteToUDP([]byte("makehole"), addr) 97 | buf := make([]byte, 100) 98 | sock.SetReadDeadline(time.Now().Add(time.Duration(1) * time.Second)) 99 | n, _, err := sock.ReadFromUDP(buf) 100 | if err != nil { 101 | fmt.Println("Can't ReadFromUDP: ", err, addr.String()) 102 | continue 103 | } else { 104 | p2pAddr = string(buf[0:n]) 105 | fmt.Println("read: ", p2pAddr) 106 | break 107 | } 108 | } 109 | 110 | addLen := len(p2pAddr) 111 | if addLen > 0 { 112 | tmparr := strings.Split(p2pAddr, ":") 113 | 114 | var strip string 115 | var strport string 116 | strip, strport = tmparr[0], tmparr[1] 117 | ip := net.ParseIP(strip) 118 | port, _ := strconv.Atoi(strport) 119 | ret = append(ret, candidate{&net.UDPAddr{IP: ip, Port: port}}) 120 | } 121 | } 122 | arr := strings.Split(outIpList, ";") 123 | 124 | for _, ip := range arr { 125 | addip(ip, 0) 126 | } 127 | 128 | /* for _, info := range ret { 129 | log.Println("init ip:", info.Addr.String()) 130 | }*/ 131 | return ret, nil 132 | } 133 | -------------------------------------------------------------------------------- /ikcp/ikcp_test_h.go: -------------------------------------------------------------------------------- 1 | package ikcp 2 | import "container/list" 3 | import "math/rand" 4 | import "time" 5 | 6 | func iclock() int32 { 7 | return int32((time.Now().UnixNano()/1000000) & 0xffffffff) 8 | } 9 | type DelayPacket struct { 10 | _ptr []byte 11 | _size int 12 | _ts int32 13 | } 14 | 15 | func (p *DelayPacket) Init(size int, src []byte) { 16 | p._ptr = make([]byte, size) 17 | p._size = size 18 | copy(p._ptr, src[:size]) 19 | } 20 | 21 | func (p *DelayPacket) ptr() []byte { return p._ptr } 22 | func (p *DelayPacket) size() int { return p._size } 23 | func (p *DelayPacket) ts() int32 { return p._ts } 24 | func (p *DelayPacket) setts(ts int32) { p._ts = ts} 25 | 26 | type DelayTunnel struct {*list.List} 27 | type Random *rand.Rand 28 | type LatencySimulator struct { 29 | current int32 30 | lostrate, rttmin, rttmax, nmax int 31 | p12 DelayTunnel 32 | p21 DelayTunnel 33 | r12 *rand.Rand 34 | r21 *rand.Rand 35 | } 36 | 37 | // lostrate: 往返一周丢包率的百分比,默认 10% 38 | // rttmin:rtt最小值,默认 60 39 | // rttmax:rtt最大值,默认 125 40 | //func (p *LatencySimulator)Init(int lostrate = 10, int rttmin = 60, int rttmax = 125, int nmax = 1000): 41 | func (p *LatencySimulator)Init(lostrate, rttmin ,rttmax, nmax int) { 42 | p.r12 = rand.New(rand.NewSource(9)) 43 | p.r21 = rand.New(rand.NewSource(99)) 44 | p.p12 = DelayTunnel{list.New()} 45 | p.p21 = DelayTunnel{list.New()} 46 | p.current = iclock() 47 | p.lostrate = lostrate / 2; // 上面数据是往返丢包率,单程除以2 48 | p.rttmin = rttmin / 2 49 | p.rttmax = rttmax / 2 50 | p.nmax = nmax 51 | } 52 | // 发送数据 53 | // peer - 端点0/1,从0发送,从1接收;从1发送从0接收 54 | func (p *LatencySimulator) send(peer int, data []byte, size int) int { 55 | rnd := 0 56 | if (peer == 0) { 57 | rnd = p.r12.Intn(100) 58 | } else { 59 | rnd = p.r21.Intn(100) 60 | } 61 | //println("!!!!!!!!!!!!!!!!!!!!", rnd, p.lostrate, peer) 62 | if (rnd < p.lostrate) { return 0} 63 | pkt := &DelayPacket{} 64 | pkt.Init(size, data) 65 | p.current = iclock() 66 | delay := p.rttmin 67 | if (p.rttmax > p.rttmin) { 68 | delay += rand.Int() % (p.rttmax - p.rttmin) 69 | } 70 | pkt.setts(p.current + int32(delay)) 71 | if (peer == 0) { 72 | p.p12.PushBack(pkt) 73 | } else { 74 | p.p21.PushBack(pkt) 75 | } 76 | return 1 77 | } 78 | 79 | // 接收数据 80 | func (p *LatencySimulator)recv(peer int, data []byte, maxsize int) int32 { 81 | var it *list.Element 82 | if (peer == 0) { 83 | it = p.p21.Front() 84 | if (p.p21.Len() == 0){ return -1} 85 | } else { 86 | it = p.p12.Front() 87 | if (p.p12.Len() == 0){ return -1} 88 | } 89 | pkt := it.Value.(*DelayPacket) 90 | p.current = iclock() 91 | if (p.current < pkt.ts()) { return -2 } 92 | if (maxsize < pkt.size()) { return -3 } 93 | if (peer == 0) { 94 | p.p21.Remove(it) 95 | } else { 96 | p.p12.Remove(it) 97 | } 98 | maxsize = pkt.size() 99 | copy(data, pkt.ptr()[:maxsize]) 100 | return int32(maxsize) 101 | } 102 | -------------------------------------------------------------------------------- /common/common.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "crypto/md5" 7 | "encoding/binary" 8 | "errors" 9 | "fmt" 10 | "io" 11 | "log" 12 | "net" 13 | "strconv" 14 | ) 15 | 16 | const Version = 0.80 17 | 18 | type ClientSetting struct { 19 | AccessKey string 20 | ClientKey string 21 | 22 | Name string 23 | ClientType string 24 | Version float32 25 | Delay int 26 | Mode int 27 | PipeNum int 28 | AesKey string 29 | } 30 | 31 | var encodingData []byte = []byte("bertdfvuifu4359c") 32 | var encodingLen int = 16 33 | var headerLen int = 4 34 | 35 | func init() { 36 | encodingLen = len(encodingData) 37 | headerLen = binary.Size(uint32(1)) 38 | } 39 | 40 | func Xor(s string) string { 41 | n := len(s) 42 | if n == 0 { 43 | return "" 44 | } 45 | r := make([]byte, n) 46 | for i := 0; i < n; i++ { 47 | r[i] = s[i] ^ encodingData[i%encodingLen] 48 | } 49 | return string(r) 50 | } 51 | 52 | func Write(conn net.Conn, id string, action string, content string) error { 53 | if conn == nil { 54 | return nil 55 | } 56 | l1 := len(id) 57 | action = Xor(action) 58 | l2 := len(action) 59 | l3 := len(content) 60 | var buf bytes.Buffer 61 | binary.Write(&buf, binary.LittleEndian, uint32(l1)) 62 | binary.Write(&buf, binary.LittleEndian, uint32(l2)) 63 | binary.Write(&buf, binary.LittleEndian, uint32(l3)) 64 | binary.Write(&buf, binary.LittleEndian, []byte(id)) 65 | binary.Write(&buf, binary.LittleEndian, []byte(action)) 66 | binary.Write(&buf, binary.LittleEndian, []byte(content)) 67 | _, err := conn.Write(buf.Bytes()) 68 | //println("write!!!", old, l1, l2, l3) 69 | if err != nil { 70 | println("write err", err.Error()) 71 | } 72 | return err 73 | } 74 | 75 | type ReadCallBack func(conn net.Conn, id string, action string, arg string) 76 | type ReadUDPCallBack func(conn *net.UDPConn, addr *net.UDPAddr, id string, action string, arg string) 77 | 78 | func Read(conn net.Conn, callback ReadCallBack) { 79 | scanner := bufio.NewScanner(conn) 80 | split := func(data []byte, atEOF bool) (adv int, token []byte, err error) { 81 | l := len(data) 82 | if l < headerLen*3 { 83 | return 0, nil, nil 84 | } 85 | if l > 1048576 { //1024*1024=1048576 86 | conn.Close() 87 | log.Println("invalid query!") 88 | return 0, nil, errors.New("too large data!") 89 | } 90 | var l1, l2, l3 uint32 91 | buf := bytes.NewReader(data) 92 | binary.Read(buf, binary.LittleEndian, &l1) 93 | binary.Read(buf, binary.LittleEndian, &l2) 94 | binary.Read(buf, binary.LittleEndian, &l3) 95 | tail := l - headerLen*3 96 | lhead := l1 + l2 + l3 97 | if lhead > 1048576 { 98 | conn.Close() 99 | log.Println("invalid query2!") 100 | return 0, nil, errors.New("too large data!") 101 | } 102 | if uint32(tail) < lhead { 103 | return 0, nil, nil 104 | } 105 | id := make([]byte, l1) 106 | action := make([]byte, l2) 107 | content := make([]byte, l3) 108 | binary.Read(buf, binary.LittleEndian, &id) 109 | binary.Read(buf, binary.LittleEndian, &action) 110 | binary.Read(buf, binary.LittleEndian, &content) 111 | callback(conn, string(id), Xor(string(action)), string(content)) 112 | //println("read11!!", l1,l2, l3,string(id), Xor(string(action)), string(content)) 113 | return headerLen*3 + int(l1+l2+l3), []byte{}, nil 114 | } 115 | scanner.Split(split) 116 | for scanner.Scan() { 117 | } 118 | if scanner.Err() != nil { 119 | println(scanner.Err().Error()) 120 | } 121 | } 122 | 123 | func Md5(msg string) string { 124 | h := md5.New() 125 | io.WriteString(h, msg) 126 | return fmt.Sprintf("%x", h.Sum(nil)) 127 | } 128 | 129 | func HashPasswd(pass string) string { 130 | return Md5(pass + "testzc222sf") 131 | } 132 | 133 | type _reuseTbl struct { 134 | tbl map[string]bool 135 | } 136 | 137 | var currIdMap map[string]int 138 | var reuseTbl map[string]*_reuseTbl 139 | 140 | func GetId(name string) string { 141 | if reuseTbl != nil { 142 | tbl, bHave := reuseTbl[name] 143 | if bHave { 144 | if len(tbl.tbl) > 0 { 145 | for key := range tbl.tbl { 146 | delete(tbl.tbl, key) 147 | // println("got old id", key) 148 | return key 149 | } 150 | } 151 | } 152 | } 153 | if currIdMap == nil { 154 | currIdMap = make(map[string]int) 155 | currIdMap[name] = 0 156 | } 157 | currIdMap[name]++ 158 | // println("gen new id", currIdMap[name]) 159 | return strconv.Itoa(currIdMap[name]) 160 | } 161 | 162 | func RmId(name, id string) { 163 | return 164 | if currIdMap == nil { 165 | currIdMap = make(map[string]int) 166 | currIdMap[name] = 0 167 | } 168 | n, err := strconv.Atoi(id) 169 | if err != nil { 170 | return 171 | } 172 | if n > currIdMap[name] { 173 | return 174 | } 175 | if reuseTbl == nil { 176 | reuseTbl = make(map[string]*_reuseTbl) 177 | } 178 | tbl, bHave := reuseTbl[name] 179 | if !bHave { 180 | reuseTbl[name] = &_reuseTbl{tbl: make(map[string]bool)} 181 | tbl = reuseTbl[name] 182 | } 183 | tbl.tbl[id] = true 184 | // println("can reuse ", name, id) 185 | } 186 | 187 | func Id_test(name string) { 188 | id1 := GetId(name) 189 | id2 := GetId(name) 190 | id3 := GetId(name) 191 | id4 := GetId(name) 192 | 193 | RmId(name, id2) 194 | RmId(name, id4) 195 | println(GetId(name)) 196 | println(GetId(name)) 197 | RmId(name, id1) 198 | println(GetId(name)) 199 | RmId(name, id3) 200 | println(GetId(name)) 201 | println(GetId(name)) 202 | } 203 | -------------------------------------------------------------------------------- /ikcp/ikcp_test.go: -------------------------------------------------------------------------------- 1 | package ikcp 2 | import "encoding/binary" 3 | import "bytes" 4 | import "time" 5 | import "fmt" 6 | import "testing" 7 | //===================================================================== 8 | //===================================================================== 9 | 10 | // 模拟网络 11 | var vnet *LatencySimulator 12 | 13 | // 模拟网络:模拟发送一个 udp包 14 | func udp_output(buf []byte, _len int32, kcp *Ikcpcb, user interface{}) int32 { 15 | arr := (user).([]byte) 16 | var id uint32 = uint32(arr[0]) 17 | //println("send!!!!", id, _len) 18 | if vnet.send(int(id), buf, int(_len)) != 1 { 19 | //println("wocao !!!", id, _len) 20 | } 21 | return 0 22 | } 23 | 24 | // 测试用例 25 | func test(mode int) { 26 | // 创建模拟网络:丢包率10%,Rtt 60ms~125ms 27 | vnet = &LatencySimulator{} 28 | vnet.Init(10, 60, 125, 1000) 29 | 30 | // 创建两个端点的 kcp对象,第一个参数 conv是会话编号,同一个会话需要相同 31 | // 最后一个是 user参数,用来传递标识 32 | a := []byte {0} 33 | b := []byte {1} 34 | kcp1 := Ikcp_create(0x11223344, a) 35 | kcp2 := Ikcp_create(0x11223344, b) 36 | 37 | // 设置kcp的下层输出,这里为 udp_output,模拟udp网络输出函数 38 | kcp1.Output = udp_output 39 | kcp2.Output = udp_output 40 | 41 | current := uint32(iclock()) 42 | slap := current + 20 43 | index := 0 44 | next := 0 45 | var sumrtt uint32 = 0 46 | count := 0 47 | maxrtt := 0 48 | 49 | // 配置窗口大小:平均延迟200ms,每20ms发送一个包, 50 | // 而考虑到丢包重发,设置最大收发窗口为128 51 | Ikcp_wndsize(kcp1, 128, 128) 52 | Ikcp_wndsize(kcp2, 128, 128) 53 | 54 | // 判断测试用例的模式 55 | if (mode == 0) { 56 | // 默认模式 57 | Ikcp_nodelay(kcp1, 0, 10, 0, 0) 58 | Ikcp_nodelay(kcp2, 0, 10, 0, 0) 59 | } else if (mode == 1) { 60 | // 普通模式,关闭流控等 61 | Ikcp_nodelay(kcp1, 0, 10, 0, 1) 62 | Ikcp_nodelay(kcp2, 0, 10, 0, 1) 63 | } else { 64 | // 启动快速模式 65 | // 第二个参数 nodelay-启用以后若干常规加速将启动 66 | // 第三个参数 interval为内部处理时钟,默认设置为 10ms 67 | // 第四个参数 resend为快速重传指标,设置为2 68 | // 第五个参数 为是否禁用常规流控,这里禁止 69 | Ikcp_nodelay(kcp1, 1, 10, 2, 1) 70 | Ikcp_nodelay(kcp2, 1, 10, 2, 1) 71 | } 72 | 73 | 74 | var buffer []byte = make([]byte, 2000) 75 | var hr int32 76 | 77 | ts1 := iclock() 78 | 79 | for { 80 | time.Sleep(100* time.Millisecond) 81 | current = uint32(iclock()) 82 | Ikcp_update(kcp1,uint32(iclock())) 83 | Ikcp_update(kcp2, uint32(iclock())) 84 | 85 | // 每隔 20ms,kcp1发送数据 86 | for ; current >= slap; slap += 20 { 87 | buf := new(bytes.Buffer) 88 | binary.Write(buf, binary.LittleEndian, uint32(index)) 89 | index++ 90 | binary.Write(buf, binary.LittleEndian, uint64(current)) 91 | // 发送上层协议包 92 | Ikcp_send(kcp1, buf.Bytes(), 8) 93 | //println("now", iclock()) 94 | } 95 | 96 | // 处理虚拟网络:检测是否有udp包从p1->p2 97 | for { 98 | hr = vnet.recv(1, buffer, 2000) 99 | if (hr < 0) { 100 | break 101 | } 102 | // 如果 p2收到udp,则作为下层协议输入到kcp2 103 | Ikcp_input(kcp2, buffer, int(hr)) 104 | } 105 | 106 | // 处理虚拟网络:检测是否有udp包从p2->p1 107 | for { 108 | hr = vnet.recv(0, buffer, 2000) 109 | if (hr < 0) { break } 110 | // 如果 p1收到udp,则作为下层协议输入到kcp1 111 | Ikcp_input(kcp1, buffer, int(hr)) 112 | //println("@@@@", hr, r) 113 | } 114 | 115 | // kcp2接收到任何包都返回回去 116 | for { 117 | hr = Ikcp_recv(kcp2, buffer, 10) 118 | // 没有收到包就退出 119 | if (hr < 0) { break } 120 | // 如果收到包就回射 121 | buf := bytes.NewReader(buffer) 122 | var sn uint32 123 | binary.Read(buf, binary.LittleEndian, &sn) 124 | Ikcp_send(kcp2, buffer, int(hr)) 125 | } 126 | 127 | // kcp1收到kcp2的回射数据 128 | for { 129 | hr = Ikcp_recv(kcp1, buffer, 10) 130 | buf := bytes.NewReader(buffer) 131 | // 没有收到包就退出 132 | if (hr < 0) { break } 133 | var sn uint32 134 | var ts, rtt uint32 135 | binary.Read(buf, binary.LittleEndian, &sn) 136 | binary.Read(buf, binary.LittleEndian, &ts) 137 | rtt = uint32(current) - ts 138 | 139 | if (sn != uint32(next)) { 140 | // 如果收到的包不连续 141 | //for i:=0;i<8 ;i++ { 142 | //println("---", i, buffer[i]) 143 | //} 144 | println("ERROR sn ", count, "<->", next, sn) 145 | return 146 | } 147 | 148 | next++ 149 | sumrtt += rtt 150 | count++ 151 | if (rtt > uint32(maxrtt)) { maxrtt = int(rtt) } 152 | 153 | println("[RECV] mode=", mode, " sn=",sn, " rtt=", rtt) 154 | } 155 | if (next > 100) { break } 156 | } 157 | 158 | ts1 = iclock() - ts1 159 | 160 | names := []string{ "default", "normal", "fast" } 161 | fmt.Printf("%s mode result (%dms):\n", names[mode], ts1) 162 | fmt.Printf("avgrtt=%d maxrtt=%d\n", int(sumrtt / uint32(count)), maxrtt) 163 | } 164 | 165 | func TestNetwork(t *testing.T) { 166 | test(0); // 默认模式,类似 TCP:正常模式,无快速重传,常规流控 167 | test(1); // 普通模式,关闭流控等 168 | test(2); // 快速模式,所有开关都打开,且关闭流控 169 | } 170 | 171 | /* 172 | default mode result (20917ms): 173 | avgrtt=740 maxrtt=1507 174 | 175 | normal mode result (20131ms): 176 | avgrtt=156 maxrtt=571 177 | 178 | fast mode result (20207ms): 179 | avgrtt=138 maxrtt=392 180 | */ 181 | 182 | -------------------------------------------------------------------------------- /nat/nat.go: -------------------------------------------------------------------------------- 1 | package nat 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | "strings" 7 | "time" 8 | 9 | "github.com/vzex/dog-tunnel/nat/stun" 10 | ) 11 | 12 | func Init(outIpList string, buster bool, id int, udpAddr string) (*AttemptEngine, error) { 13 | sock, err := net.ListenUDP("udp", &net.UDPAddr{}) 14 | if err != nil { 15 | return nil, err 16 | } 17 | 18 | engine := &AttemptEngine{sock: sock, buster: buster, id: id} 19 | if err := engine.init(outIpList, udpAddr); err != nil { 20 | return nil, err 21 | } 22 | return engine, nil 23 | } 24 | 25 | type attempt struct { 26 | candidate 27 | tid []byte 28 | timeout time.Time 29 | success bool // did we get a STUN response from this addr 30 | chosen bool // Has this channel been picked for the connection? 31 | localaddr net.Addr 32 | } 33 | 34 | type AttemptEngine struct { 35 | id int 36 | buster bool 37 | sock *net.UDPConn 38 | attempts []attempt 39 | local_attempts []attempt 40 | p2pconn net.Conn 41 | otherReady bool 42 | status string 43 | } 44 | 45 | const probeTimeout = 500 * time.Millisecond 46 | const probeInterval = 100 * time.Millisecond 47 | const decisionTime = 2 * time.Second 48 | 49 | func (e *AttemptEngine) SetOtherAddrList(addrList string) { 50 | arr := strings.Split(addrList, "\n") 51 | e.attempts = make([]attempt, 0) 52 | for _, addrStr := range arr { 53 | if addrStr != "" { 54 | addr, err := net.ResolveUDPAddr("udp", addrStr) 55 | if err != nil { 56 | debug("resolve udp addr err", err.Error()) 57 | } else { 58 | e.attempts = append(e.attempts, attempt{candidate: candidate{Addr: addr}}) 59 | } 60 | } 61 | } 62 | } 63 | 64 | func (e *AttemptEngine) GetAddrList() string { 65 | tmp := "" 66 | for _, attempt := range e.local_attempts { 67 | tmp += attempt.Addr.String() + "\n" 68 | } 69 | return tmp 70 | } 71 | 72 | func (e *AttemptEngine) Fail() { 73 | e.status = "quit" 74 | if e.sock != nil { 75 | //debug("close udp sock") 76 | e.sock.Close() 77 | } 78 | } 79 | 80 | func (e *AttemptEngine) GetConn(f func(), encode, decode func([]byte) []byte) (net.Conn, error) { 81 | var conn net.Conn 82 | var err error 83 | if conn, err = e.run(f, encode, decode); err != nil { 84 | return nil, err 85 | } 86 | return conn, nil 87 | } 88 | 89 | func (e *AttemptEngine) init(outIpList string, udpAddr string) error { 90 | candidates, err := GatherCandidates(e.sock, outIpList, udpAddr) 91 | if err != nil { 92 | return err 93 | } 94 | e.local_attempts = make([]attempt, len(candidates)) 95 | for i := range candidates { 96 | e.local_attempts[i].candidate = candidates[i] 97 | debug("init addr", candidates[i].Addr.String()) 98 | } 99 | 100 | e.sock.SetWriteDeadline(time.Time{}) 101 | 102 | return nil 103 | } 104 | 105 | func (e *AttemptEngine) xmit() (time.Time, error) { 106 | now := time.Now() 107 | var ret time.Time 108 | var err error 109 | 110 | if e.p2pconn != nil { 111 | return ret, nil 112 | } 113 | 114 | for i := range e.attempts { 115 | if e.attempts[i].timeout.Before(now) { 116 | e.attempts[i].timeout = time.Now().Add(probeTimeout) 117 | e.attempts[i].tid, err = stun.RandomTid() 118 | if err != nil { 119 | return time.Time{}, err 120 | } 121 | packet, err := stun.BindRequest(e.attempts[i].tid, e.attempts[i].Addr, nil, false, e.attempts[i].chosen) 122 | if err != nil { 123 | return time.Time{}, err 124 | } 125 | //debug("===send", i,e.attempts[i].Addr.String()) 126 | e.sock.WriteToUDP(packet, e.attempts[i].Addr) 127 | 128 | for j := range e.local_attempts { 129 | if e.local_attempts[j].success { 130 | packet, err := stun.BindRequest(e.attempts[i].tid, e.attempts[i].Addr, nil, false, e.attempts[i].chosen) 131 | if err != nil { 132 | return time.Time{}, err 133 | } 134 | //debug("===send local", i,e.local_attempts[j].localaddr.String()) 135 | e.sock.WriteToUDP(packet, e.local_attempts[j].localaddr.(*net.UDPAddr)) 136 | } 137 | } 138 | } 139 | if ret.IsZero() || e.attempts[i].timeout.Before(ret) { 140 | ret = e.attempts[i].timeout 141 | } 142 | } 143 | return ret, nil 144 | } 145 | 146 | func (e *AttemptEngine) read() error { 147 | if e.status == "over" { 148 | return nil 149 | } 150 | buf := make([]byte, 512) 151 | n, from, err := e.sock.ReadFromUDP(buf) 152 | //println("read", n, from, err) 153 | if err != nil { 154 | if neterr, ok := err.(net.Error); ok && neterr.Timeout() { 155 | return nil 156 | } 157 | return err 158 | } 159 | if string(buf[0:n]) == "makeholeover" { 160 | if e.status == "wait" { 161 | debug("wait client !!!!!!! close") 162 | e.status = "over" 163 | e.sock.WriteToUDP([]byte("makeholeover2"), from) 164 | } 165 | return nil 166 | } 167 | 168 | if string(buf[0:n]) == "makeholeover2" { 169 | if e.status == "wait" { 170 | debug("wait server !!!!!!! close") 171 | e.status = "over" 172 | } 173 | return nil 174 | } 175 | 176 | //debug("========", string(buf[0:n])) 177 | packet, err := stun.ParsePacket(buf[:n], nil) 178 | if err != nil { 179 | return nil 180 | } 181 | 182 | if packet.Method != stun.MethodBinding { 183 | return nil 184 | } 185 | 186 | validAddr := packet.Addr 187 | for i := range e.local_attempts { 188 | my_local_addr := e.local_attempts[i].Addr 189 | //debug("check local",i, validAddr.String(), packet.Class, from.String(), my_local_addr.String()) 190 | if validAddr.String() == my_local_addr.String() { 191 | e.local_attempts[i].localaddr = from 192 | e.local_attempts[i].success = true 193 | //debug("find the addr from request", packet.Class, from.String()) 194 | if packet.Class == stun.ClassRequest { 195 | for j := range e.attempts { 196 | my_remote_addr := e.attempts[j].Addr 197 | response, err := stun.BindResponse(packet.Tid[:], my_remote_addr, nil, false) 198 | if err != nil { 199 | return nil 200 | } 201 | debug("write to succ", from.String(), j, my_remote_addr.String()) 202 | e.sock.WriteToUDP(response, from) 203 | } 204 | } else if packet.Class == stun.ClassSuccess { 205 | if e.p2pconn == nil { 206 | debug("make conn success", from.String(), e.local_attempts[i].localaddr.String()) 207 | e.p2pconn = newConn(e.sock, e.local_attempts[i].Addr, e.local_attempts[i].localaddr, e.id) 208 | for j := range e.attempts { 209 | my_remote_addr := e.attempts[j].Addr 210 | response, err := stun.InformReady(packet.Tid[:], my_remote_addr, nil) 211 | if err != nil { 212 | return nil 213 | } 214 | debug("write to ready", from.String(), j, my_remote_addr.String()) 215 | e.sock.WriteToUDP(response, from) 216 | } 217 | } 218 | } else if packet.Class == stun.ClassIndication { 219 | debug("recv other ready") 220 | e.otherReady = true 221 | /* for j := range e.attempts { 222 | debug("write !!!!!!", from.String(),j) 223 | e.sock.WriteToUDP([]byte("wocao,okokokook1!!"), from) 224 | }*/ 225 | } else if packet.Class == stun.ClassError { 226 | // debug("!!!!!!!!!!!!!") 227 | } 228 | } 229 | } 230 | 231 | return nil 232 | } 233 | 234 | func (e *AttemptEngine) run(f func(), encode, decode func([]byte) []byte) (net.Conn, error) { 235 | bInform := false 236 | beginTime := time.Now().Unix() 237 | for { 238 | if time.Now().Unix()-beginTime > 10 { 239 | e.status = "fail" 240 | } 241 | if e.status == "fail" || e.status == "quit" { 242 | break 243 | } 244 | timeout, err := e.xmit() 245 | if err != nil { 246 | return nil, err 247 | } 248 | if !bInform { 249 | f() 250 | bInform = true 251 | beginTime = time.Now().Unix() 252 | } 253 | e.sock.SetReadDeadline(timeout) 254 | if err = e.read(); err != nil { 255 | //return nil, err 256 | } 257 | if e.p2pconn != nil && e.otherReady { 258 | if e.buster && e.status == "" { 259 | debug("write final!!!!!!") 260 | e.sock.WriteToUDP([]byte("makeholeover"), e.p2pconn.RemoteAddr().(*net.UDPAddr)) 261 | } 262 | if e.status != "over" { 263 | e.status = "wait" 264 | } 265 | } 266 | if e.status == "over" { 267 | e.p2pconn.(*Conn).SetCrypt(encode, decode) 268 | e.p2pconn.(*Conn).Run() 269 | return e.p2pconn, nil 270 | } 271 | } 272 | 273 | return nil, errors.New(e.status) 274 | } 275 | -------------------------------------------------------------------------------- /nat/connection.go: -------------------------------------------------------------------------------- 1 | package nat 2 | 3 | import "github.com/vzex/dog-tunnel/ikcp" 4 | 5 | import ( 6 | "errors" 7 | "flag" 8 | "log" 9 | "net" 10 | "time" 11 | ) 12 | 13 | const ( 14 | Ping byte = 1 15 | Data byte = 2 16 | ) 17 | 18 | var bDebug = flag.Bool("debug", false, "whether show nat pipe debug msg") 19 | 20 | var defaultQueueSize = 1 21 | 22 | const dataLimit = 4000 23 | 24 | func debug(args ...interface{}) { 25 | if *bDebug { 26 | log.Println(args...) 27 | } 28 | } 29 | func iclock() int32 { 30 | return int32((time.Now().UnixNano() / 1000000) & 0xffffffff) 31 | } 32 | 33 | func udp_output(buf []byte, _len int32, kcp *ikcp.Ikcpcb, user interface{}) int32 { 34 | debug("write!!!", _len) 35 | c := user.(*Conn) 36 | c.conn.WriteTo(buf[:_len], c.remote) 37 | return 0 38 | } 39 | 40 | type cache struct { 41 | b []byte 42 | l int 43 | c chan int 44 | } 45 | 46 | type Conn struct { 47 | conn *net.UDPConn 48 | local, remote net.Addr 49 | closed bool 50 | quit chan bool 51 | sendChan chan string 52 | checkCanWrite chan chan bool 53 | readChan chan cache 54 | kcp *ikcp.Ikcpcb 55 | 56 | tmp []byte 57 | tmp2 []byte 58 | encode, decode func([]byte) []byte 59 | overTime int64 60 | } 61 | 62 | func newConn(sock *net.UDPConn, local, remote net.Addr, id int) *Conn { 63 | sock.SetDeadline(time.Time{}) 64 | conn := &Conn{conn: sock, local: local, remote: remote, closed: false, quit: make(chan bool), tmp: make([]byte, 2000), tmp2: make([]byte, 2000), sendChan: make(chan string, 10), checkCanWrite: make(chan chan bool), readChan: make(chan cache), overTime: time.Now().Unix() + 30} 65 | debug("create", id) 66 | conn.kcp = ikcp.Ikcp_create(uint32(id), conn) 67 | conn.kcp.Output = udp_output 68 | ikcp.Ikcp_wndsize(conn.kcp, 128, 128) 69 | ikcp.Ikcp_nodelay(conn.kcp, 1, 10, 2, 1) 70 | return conn 71 | } 72 | 73 | func (c *Conn) Run() { 74 | go c.onUpdate() 75 | } 76 | 77 | func (c *Conn) onUpdate() { 78 | recvChan := make(chan []byte) 79 | go func() { 80 | for { 81 | n, addr, err := c.conn.ReadFrom(c.tmp) 82 | //debug("want read!", n, addr, err) 83 | // Generic non-address related errors. 84 | if addr == nil && err != nil { 85 | if err.(net.Error).Timeout() { 86 | continue 87 | } else { 88 | break 89 | } 90 | } 91 | b := make([]byte, n) 92 | copy(b, c.tmp[:n]) 93 | select { 94 | case recvChan <- b: 95 | case <-c.quit: 96 | return 97 | } 98 | } 99 | }() 100 | ping := make(chan struct{}) 101 | pingC := 0 102 | 103 | updateChan := time.NewTicker(20 * time.Millisecond) 104 | waitList := [](chan bool){} 105 | recoverChan := make(chan bool) 106 | var waitRecvCache *cache 107 | go func() { 108 | select { 109 | case ping <- struct{}{}: 110 | case <-c.quit: 111 | } 112 | 113 | }() 114 | out: 115 | for { 116 | select { 117 | case <-ping: 118 | pingC++ 119 | if pingC >= 4 { 120 | pingC = 0 121 | go c.Ping() 122 | } 123 | if time.Now().Unix() > c.overTime { 124 | log.Println("overtime close", c.LocalAddr().String(), c.RemoteAddr().String()) 125 | go c.Close() 126 | } else { 127 | time.AfterFunc(300*time.Millisecond, func() { 128 | select { 129 | case ping <- struct{}{}: 130 | case <-c.quit: 131 | } 132 | }) 133 | } 134 | case cache := <-c.readChan: 135 | for { 136 | hr := ikcp.Ikcp_recv(c.kcp, c.tmp2, 2000) 137 | if hr > 0 { 138 | action := c.tmp2[0] 139 | if action == Data { 140 | copy(cache.b, c.tmp2[1:hr]) 141 | hr-- 142 | if c.decode != nil { 143 | d := c.decode(cache.b[:hr]) 144 | copy(cache.b, d) 145 | hr = int32(len(d)) 146 | } 147 | select { 148 | case cache.c <- int(hr): 149 | case <-c.quit: 150 | } 151 | } else { 152 | continue 153 | } 154 | } else { 155 | waitRecvCache = &cache 156 | } 157 | break 158 | } 159 | case b := <-recvChan: 160 | c.overTime = time.Now().Unix() + 30 161 | ikcp.Ikcp_input(c.kcp, b, len(b)) 162 | if waitRecvCache != nil { 163 | ca := *waitRecvCache 164 | for { 165 | hr := ikcp.Ikcp_recv(c.kcp, c.tmp2, 2000) 166 | if hr > 0 { 167 | action := c.tmp2[0] 168 | if action == Data { 169 | waitRecvCache = nil 170 | copy(ca.b, c.tmp2[1:hr]) 171 | hr-- 172 | if c.decode != nil { 173 | d := c.decode(ca.b[:hr]) 174 | copy(ca.b, d) 175 | hr = int32(len(d)) 176 | } 177 | select { 178 | case ca.c <- int(hr): 179 | case <-c.quit: 180 | } 181 | } else { 182 | continue 183 | } 184 | } else { 185 | } 186 | break 187 | } 188 | } 189 | case <-recoverChan: 190 | for _, r := range waitList { 191 | log.Println("recover writing data") 192 | select { 193 | case r <- true: 194 | case <-c.quit: 195 | } 196 | } 197 | waitList = [](chan bool){} 198 | case s := <-c.checkCanWrite: 199 | if !c.closed { 200 | if ikcp.Ikcp_waitsnd(c.kcp) > dataLimit { 201 | log.Println("wait for data limit") 202 | waitList = append(waitList, s) 203 | var f func() 204 | f = func() { 205 | n := ikcp.Ikcp_waitsnd(c.kcp) 206 | if n <= dataLimit/2 { 207 | select { 208 | case <-c.quit: 209 | log.Println("recover writing data quit") 210 | case recoverChan <- true: 211 | } 212 | } else { 213 | time.AfterFunc(40*time.Millisecond, f) 214 | } 215 | } 216 | time.AfterFunc(20*time.Millisecond, f) 217 | log.Println("wait for data limitover") 218 | } else { 219 | select { 220 | case s <- true: 221 | case <-c.quit: 222 | } 223 | } 224 | } 225 | case s := <-c.sendChan: 226 | b := []byte(s) 227 | ikcp.Ikcp_send(c.kcp, b, len(b)) 228 | case <-updateChan.C: 229 | if c.closed { 230 | break out 231 | } 232 | ikcp.Ikcp_update(c.kcp, uint32(iclock())) 233 | case <-c.quit: 234 | break out 235 | } 236 | } 237 | updateChan.Stop() 238 | } 239 | func (c *Conn) Read(b []byte) (int, error) { 240 | if !c.closed { 241 | var n = 0 242 | wc := cache{b, 0, make(chan int)} 243 | select { 244 | case c.readChan <- wc: 245 | select { 246 | case n = <-wc.c: 247 | case <-c.quit: 248 | n = 0 249 | } 250 | case <-c.quit: 251 | n = 0 252 | } 253 | return n, nil 254 | } 255 | return 0, errors.New("force quit") 256 | } 257 | 258 | // type 0, check, 1 msg 259 | func (c *Conn) Write(b []byte) (int, error) { 260 | if c.closed { 261 | return 0, errors.New("eof") 262 | } 263 | 264 | if c.encode != nil { 265 | b = c.encode(b) 266 | } 267 | sendL := len(b) 268 | if sendL == 0 { 269 | return 0, nil 270 | } 271 | //log.Println("try write", sendL) 272 | wc := make(chan bool) 273 | select { 274 | case c.checkCanWrite <- wc: 275 | select { 276 | case <-wc: 277 | data := make([]byte, sendL+1) 278 | data[0] = Data 279 | copy(data[1:], b) 280 | c.sendChan <- string(data) 281 | case <-c.quit: 282 | } 283 | case <-c.quit: 284 | } 285 | return sendL, nil 286 | } 287 | 288 | func (c *Conn) Ping() (int, error) { 289 | if c.closed { 290 | return 0, errors.New("eof") 291 | } 292 | wc := make(chan bool) 293 | select { 294 | case c.checkCanWrite <- wc: 295 | select { 296 | case <-wc: 297 | data := []byte{Ping} 298 | c.sendChan <- string(data) 299 | case <-c.quit: 300 | } 301 | case <-c.quit: 302 | } 303 | return 1, nil 304 | } 305 | func (c *Conn) Close() error { 306 | if !c.closed { 307 | c.closed = true 308 | } 309 | if c.quit != nil { 310 | close(c.quit) 311 | c.quit = nil 312 | } 313 | return c.conn.Close() 314 | } 315 | 316 | func (c *Conn) LocalAddr() net.Addr { 317 | return c.local 318 | } 319 | 320 | func (c *Conn) RemoteAddr() net.Addr { 321 | return c.remote 322 | } 323 | 324 | func (c *Conn) SetDeadline(t time.Time) error { 325 | return c.conn.SetDeadline(t) 326 | } 327 | 328 | func (c *Conn) SetReadDeadline(t time.Time) error { 329 | return c.conn.SetReadDeadline(t) 330 | } 331 | 332 | func (c *Conn) SetWriteDeadline(t time.Time) error { 333 | return c.conn.SetWriteDeadline(t) 334 | } 335 | 336 | func (c *Conn) SetCrypt(encode, decode func([]byte) []byte) { 337 | c.encode = encode 338 | c.decode = decode 339 | } 340 | -------------------------------------------------------------------------------- /common/servercommon.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | "strconv" 8 | "time" 9 | ) 10 | 11 | type ClientInfo struct { 12 | Conn net.Conn 13 | ClientMap map[net.Conn]*Session 14 | Id2Session map[string]*Session 15 | 16 | UserName string 17 | ClientKey string 18 | 19 | ResponseTime int64 20 | 21 | Quit chan bool 22 | 23 | IsServer bool 24 | ServerName string // is serverName != "", this client is a server! 25 | Id2MakeSession map[string]*UDPMakeSession 26 | } 27 | 28 | type UDPMakeSession struct { 29 | Id string 30 | CreateTime int64 31 | ClientA net.Conn 32 | ClientB net.Conn 33 | SessionId string 34 | PipeType string 35 | Status string 36 | ServerName string 37 | Quit chan bool 38 | } 39 | 40 | type Session struct { 41 | Id string 42 | ClientA net.Conn 43 | ClientB net.Conn 44 | Status string 45 | OverTime int64 46 | Method string 47 | Setting ClientSetting 48 | MakeHoleResponseN int 49 | MakeHoleHasFail bool 50 | Quit chan bool 51 | } 52 | 53 | func (session *Session) String() string { 54 | return fmt.Sprintf("%s|delay:%d|status:%s|method:%s|ClientA:%s|ClientB:%s|Pipes:%d/%d", session.Id, session.Setting.Delay, session.Status, session.Method, session.ClientA.RemoteAddr().String(), session.ClientB.RemoteAddr().String(), session.MakeHoleResponseN, session.Setting.PipeNum) 55 | } 56 | 57 | type AdminInfo struct { 58 | Conn net.Conn 59 | } 60 | 61 | func (session *Session) RestartSession(ServerName string) { 62 | log.Println("restart session", session.Id) 63 | session.Method = "restart" 64 | session.Quit <- true 65 | tmp := session.ClientA 66 | session.ClientA = session.ClientB 67 | session.ClientB = tmp 68 | session.MakeHoleResponseN = 0 69 | session.MakeHoleHasFail = false 70 | n := session.Setting.PipeNum 71 | session.StartSession(n, ServerName, session.Id) 72 | } 73 | 74 | func (session *Session) Down() { 75 | if session.Quit != nil { 76 | close(session.Quit) 77 | session.Quit = nil 78 | } 79 | session.Status = "down" 80 | } 81 | 82 | func (session *Session) StartCSMode() { 83 | //make sure ClientA and ClientB not exchanged 84 | session.Method = "cs" 85 | clientConn := session.ClientA 86 | session.Status = "csmode_begin" 87 | Write(clientConn, session.Id, "csmode_c_begin", "") 88 | session.Loop() 89 | } 90 | 91 | func (session *Session) Loop() { 92 | go func() { 93 | checkChan := time.NewTicker(10 * time.Second) 94 | out: 95 | for { 96 | select { 97 | case <-checkChan.C: 98 | //println("check lop session status", session.status) 99 | if time.Now().Unix() > session.OverTime { 100 | if session.Status != "ok" { 101 | if session.Method == "udp" || session.Method == "cs" { 102 | session.ClientA.Close() 103 | } else { 104 | session.ClientB.Close() 105 | } 106 | } 107 | } 108 | case <-session.Quit: 109 | log.Println("session loop quit", session.Id) 110 | break out 111 | } 112 | } 113 | checkChan.Stop() 114 | }() 115 | } 116 | 117 | func (session *Session) StartSession(n int, ServerName, sessionId string) { 118 | if n > 10 { 119 | if session.Method == "udp" || session.Method == "cs" { 120 | Write(session.ClientA, "0", "showandquit", "pipen cannot larger than "+strconv.Itoa(10)) 121 | } else { 122 | Write(session.ClientB, "0", "showandquit", "pipen cannot larger than "+strconv.Itoa(10)) 123 | } 124 | } 125 | for i := 0; i < n; i++ { 126 | session.startUdpSession(ServerName, sessionId, "common") 127 | } 128 | //session.startUdpSession(ServerName, sessionId, "file") 129 | session.OverTime = time.Now().Add(60 * time.Second).Unix() 130 | session.Loop() 131 | } 132 | 133 | func (session *Session) startUdpSession(ServerName, sessionId, pipeType string) { 134 | udpSessionId := GetId("makehole") 135 | log.Println("start session", session.Id, session.Setting.Mode, ServerName, udpSessionId) 136 | udpSession := &UDPMakeSession{CreateTime: time.Now().Unix(), Id: udpSessionId, ClientA: session.ClientA, ClientB: session.ClientB, SessionId: sessionId, PipeType: pipeType, ServerName: ServerName, Status: "init", Quit: make(chan bool)} 137 | GetClientInfoByName(ServerName, func(server *ClientInfo) { 138 | server.Id2MakeSession[udpSession.Id] = udpSession 139 | }, func() {}) 140 | udpSession.BeginMakeHole(0, "") 141 | udpSession.Loop() 142 | } 143 | 144 | func (s *ClientInfo) GetSession(conn net.Conn) *Session { 145 | session, bHave := s.ClientMap[conn] 146 | if bHave { 147 | return session 148 | } else { 149 | return nil 150 | } 151 | } 152 | 153 | func (s *ClientInfo) AddClient(conn net.Conn, clientInfo ClientSetting) { 154 | id := GetId(s.ServerName) 155 | s.ClientMap[conn] = &Session{ClientA: conn, ClientB: s.Conn, Method: "udp", OverTime: 0, Status: "init", Id: id, Setting: clientInfo, Quit: make(chan bool), MakeHoleResponseN: 0, MakeHoleHasFail: false} 156 | s.Id2Session[id] = s.ClientMap[conn] 157 | if s.ClientMap[conn].Setting.Mode == 2 { 158 | s.ClientMap[conn].StartCSMode() 159 | } else { 160 | if clientInfo.AesKey != "" { 161 | Write(s.Conn, id, "aeskey", clientInfo.AesKey) 162 | } 163 | n := clientInfo.PipeNum 164 | s.ClientMap[conn].StartSession(n, s.ServerName, id) 165 | } 166 | } 167 | 168 | func (s *ClientInfo) Loop() { 169 | go func() { 170 | checkChan := time.NewTicker(10 * time.Second) 171 | out: 172 | for { 173 | select { 174 | case <-checkChan.C: 175 | if time.Now().Unix()-s.ResponseTime > 1800 { 176 | log.Println("timeout,client loop quit", s.Conn.RemoteAddr().String()) 177 | break out 178 | } 179 | case <-s.Quit: 180 | break out 181 | } 182 | } 183 | checkChan.Stop() 184 | s.Conn.Close() 185 | }() 186 | } 187 | 188 | func (s *ClientInfo) DelClient(conn net.Conn) string { 189 | session, bHave := s.ClientMap[conn] 190 | if bHave { 191 | Write(conn, "0", "showandquit", "server kick you out") 192 | id := session.Id 193 | session.Down() 194 | log.Println("remove client session", id) 195 | delete(s.Id2Session, id) 196 | delete(s.ClientMap, conn) 197 | RmId(s.ServerName, id) 198 | return id 199 | } 200 | return "" 201 | } 202 | 203 | func (udpsession *UDPMakeSession) Remove(bTimeout bool) { 204 | if bTimeout { 205 | log.Println("timeout,remove udpsession", udpsession.Id) 206 | } else { 207 | //log.Println("remove udpsession", udpsession.Id) 208 | } 209 | close(udpsession.Quit) 210 | GetClientInfoByName(udpsession.ServerName, func(server *ClientInfo) { 211 | delete(server.Id2MakeSession, udpsession.Id) 212 | session, bHave := server.Id2Session[udpsession.SessionId] 213 | if bHave && bTimeout { 214 | Write(session.ClientA, udpsession.Id, "remove_udpsession", "") 215 | Write(session.ClientB, udpsession.Id, "remove_udpsession", "") 216 | } 217 | }, func() {}) 218 | RmId("makehole", udpsession.Id) 219 | } 220 | 221 | func (udpsession *UDPMakeSession) Loop() { 222 | go func() { 223 | checkChan := time.NewTicker(10 * time.Second) 224 | out: 225 | for { 226 | select { 227 | case <-checkChan.C: 228 | if time.Now().Unix()-udpsession.CreateTime > 120 { 229 | udpsession.Remove(true) 230 | break out 231 | } 232 | case <-udpsession.Quit: 233 | break out 234 | } 235 | } 236 | checkChan.Stop() 237 | }() 238 | } 239 | 240 | func (udpsession *UDPMakeSession) BeginMakeHole(step int, content string) { 241 | var session *Session = nil 242 | GetClientInfoByName(udpsession.ServerName, func(server *ClientInfo) { 243 | session = server.Id2Session[udpsession.SessionId] 244 | }, func() {}) 245 | if session != nil && session.Method == "cs" { 246 | return 247 | } 248 | id := udpsession.Id 249 | ClientA := udpsession.ClientA 250 | ClientB := udpsession.ClientB 251 | if step == 0 { 252 | log.Println("===>>tell a to report addrlist", ClientA.RemoteAddr().String(), udpsession.ServerName, udpsession.Id) 253 | delay := 0 254 | if session != nil { 255 | delay = session.Setting.Delay 256 | } 257 | Write(ClientA, id+"-"+udpsession.SessionId+"-"+udpsession.PipeType, "query_addrlist_a", ClientA.RemoteAddr().(*net.TCPAddr).IP.String()+":"+strconv.Itoa(delay)) 258 | if session != nil { 259 | session.Status = "tella" 260 | } 261 | udpsession.Status = "tella" 262 | } else if step == 1 { 263 | if udpsession.Status == "tella" { 264 | udpsession.Status = "atellb" 265 | if session != nil { 266 | session.Status = "atellb" 267 | } 268 | log.Println("===>>tell b to report addlist,give b the a's addrlist", ClientB.RemoteAddr().String(), udpsession.ServerName, udpsession.Id) 269 | Write(ClientB, id+"-"+udpsession.SessionId+"-"+udpsession.PipeType, "query_addrlist_b", ClientB.RemoteAddr().(*net.TCPAddr).IP.String()+":"+content) 270 | } else if udpsession.Status == "atellb" { 271 | udpsession.Status = "bust_start_a" 272 | if session != nil { 273 | session.Status = "bust_start_a" 274 | } 275 | log.Println("=====>>tell a the b 's addrlist, and a start bust", ClientA.RemoteAddr().String(), udpsession.ServerName, udpsession.Id) 276 | Write(ClientA, id, "tell_bust_a", content) 277 | } 278 | } else if step == 2 { 279 | udpsession.Status = "bust_start_b" 280 | if session != nil { 281 | session.Status = "bust_start_b" 282 | } 283 | log.Println("=====>>tell b start bust", ClientB.RemoteAddr().String(), udpsession.ServerName, udpsession.Id) 284 | Write(ClientB, id, "tell_bust_b", content) 285 | } 286 | } 287 | 288 | func GetServerInfoByConn(conn net.Conn, cb_ok func(*ClientInfo), cb_fail func()) { 289 | info, bHave := Conn2ClientInfo[conn] 290 | if bHave { 291 | if info.IsServer { 292 | cb_ok(info) 293 | } else { 294 | ServerName := info.ServerName 295 | GetClientInfoByName(ServerName, cb_ok, cb_fail) 296 | } 297 | } else { 298 | cb_fail() 299 | } 300 | } 301 | func GetClientInfoByConn(conn net.Conn, cb_ok func(*ClientInfo), cb_fail func()) { 302 | info, bHave := Conn2ClientInfo[conn] 303 | if bHave { 304 | cb_ok(info) 305 | } else { 306 | cb_fail() 307 | } 308 | } 309 | func GetClientInfoByName(ServerName string, cb_ok func(*ClientInfo), cb_fail func()) { 310 | conn, bHave := ServerName2Conn[ServerName] 311 | if bHave { 312 | GetClientInfoByConn(conn, cb_ok, cb_fail) 313 | return 314 | } else { 315 | cb_fail() 316 | } 317 | } 318 | 319 | func GetOnlineServiceNumByNameAndIP(userName, ip string) int { 320 | size := 0 321 | for _, info := range Conn2ClientInfo { 322 | if info.IsServer && info.UserName == userName && (ip == info.Conn.RemoteAddr().(*net.TCPAddr).IP.String()) { 323 | size++ 324 | } 325 | } 326 | return size 327 | } 328 | 329 | func GetOnlineServiceNumByName(userName string) int { 330 | size := 0 331 | for _, info := range Conn2ClientInfo { 332 | if info.IsServer && info.UserName == userName { 333 | size++ 334 | } 335 | } 336 | return size 337 | } 338 | 339 | var ServerName2Conn map[string]net.Conn 340 | var Conn2ClientInfo map[net.Conn]*ClientInfo 341 | var Conn2Admin map[net.Conn]*AdminInfo 342 | -------------------------------------------------------------------------------- /auth/auth.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "database/sql" 5 | "errors" 6 | "fmt" 7 | "log" 8 | "reflect" 9 | "time" 10 | 11 | _ "github.com/go-sql-driver/mysql" 12 | "github.com/vzex/dog-tunnel/common" 13 | ) 14 | 15 | const ( 16 | UserType_Normal = iota 17 | UserType_BlackList 18 | UserType_Super 19 | UserType_Admin 20 | 21 | CacheTime = 30 22 | 23 | DefaultMaxOnlineServerNum = 2 24 | DefaultMaxSessionNum = 2 25 | DefaultMaxPipeNum = 2 26 | DefaultMaxSameIPServers = 2 27 | DefaultMaxCSModeData = 10000000 //bytes 28 | ) 29 | 30 | type User struct { 31 | //save to database 32 | UserName string 33 | Passwd string 34 | UserType int 35 | AuthKey string 36 | 37 | LastLoginTime int64 38 | LastLogoutTime int64 39 | MaxOnlineServerNum int 40 | MaxSessionNum int 41 | MaxPipeNum int 42 | MaxSameIPServers int 43 | TodayCSModeData int 44 | LimitDataSize int `stop:"true"` 45 | //donnot save 46 | lastProcessTime int64 47 | //for cache 48 | overTime int64 49 | cacheTime int64 50 | } 51 | 52 | func (u *User) CheckType() bool { 53 | if u.UserType == UserType_BlackList { 54 | return false 55 | } 56 | return true 57 | } 58 | 59 | func (u *User) OnLogin() { 60 | u.LastLoginTime = time.Now().Unix() 61 | u.lastProcessTime = u.LastLoginTime 62 | log.Println("OnLogin", u.lastProcessTime) 63 | } 64 | 65 | func (u *User) OnLogout() { 66 | u.LastLogoutTime = time.Now().Unix() 67 | updateUserDB(u) 68 | } 69 | 70 | func (u *User) CheckIpLimit(ip string) bool { 71 | if u.UserType == UserType_BlackList { 72 | return false 73 | } 74 | if u.UserType == UserType_Admin { 75 | return true 76 | } 77 | if common.GetOnlineServiceNumByNameAndIP(u.UserName, ip) >= u.MaxSameIPServers { 78 | return false 79 | } 80 | 81 | return true 82 | } 83 | 84 | func (u *User) CheckOnlineServiceNum() bool { 85 | if u.UserType == UserType_BlackList { 86 | return false 87 | } 88 | if u.UserType == UserType_Admin { 89 | return true 90 | } 91 | if common.GetOnlineServiceNumByName(u.UserName) >= u.MaxOnlineServerNum { 92 | return false 93 | } 94 | return true 95 | } 96 | 97 | func (u *User) CheckPipeNum(n int) bool { 98 | if u.UserType == UserType_BlackList { 99 | return false 100 | } 101 | if u.UserType == UserType_Admin { 102 | return true 103 | } 104 | if n > u.MaxPipeNum { 105 | return false 106 | } 107 | return true 108 | } 109 | 110 | func (u *User) CheckSessionNum(n int) bool { 111 | if u.UserType == UserType_BlackList { 112 | return false 113 | } 114 | if u.UserType == UserType_Admin { 115 | return true 116 | } 117 | if n >= u.MaxSessionNum { 118 | return false 119 | } 120 | return true 121 | } 122 | 123 | func (u *User) UpdateCSMode(size int) bool { 124 | if u.UserType == UserType_BlackList { 125 | return false 126 | } 127 | if u.UserType == UserType_Admin { 128 | return true 129 | } 130 | old := time.Unix(u.lastProcessTime, 0) 131 | now := time.Now() 132 | if now.Year() == old.Year() && now.YearDay() == old.YearDay() { 133 | u.TodayCSModeData += size 134 | } else { 135 | u.TodayCSModeData = size 136 | } 137 | u.lastProcessTime = now.Unix() 138 | n := DefaultMaxCSModeData 139 | if u.LimitDataSize > 0 { 140 | n = u.LimitDataSize 141 | } 142 | if u.TodayCSModeData > n { 143 | return false 144 | } 145 | return true 146 | } 147 | 148 | func (u *User) IsAlive() bool { 149 | return time.Now().Unix() < u.overTime 150 | } 151 | 152 | func (u *User) SetCacheTime(t int64) { 153 | if t >= 0 { 154 | u.cacheTime = t 155 | } else { 156 | t = u.cacheTime 157 | } 158 | u.overTime = t + time.Now().Unix() 159 | } 160 | 161 | func (u *User) DeInit() { 162 | updateUserDB(u) 163 | //log.Println("remove user from cache", u.UserName) 164 | } 165 | 166 | var g_Name2Users map[string]*User 167 | var g_Database *sql.DB 168 | var g_QueryUserStmt *sql.Stmt 169 | var g_QueryUserNameByKeyStmt *sql.Stmt 170 | var g_DelUserStmt *sql.Stmt 171 | var g_AddUserStmt *sql.Stmt 172 | var g_UpdateUserStmt *sql.Stmt 173 | 174 | func Init(user, passwd, host string) error { 175 | g_Name2Users = make(map[string]*User) 176 | var err error 177 | g_Database, err = sql.Open("mysql", user+":"+passwd+"@tcp("+host+")/dogtunnel") 178 | if err != nil { 179 | return err 180 | } 181 | g_QueryUserStmt, err = g_Database.Prepare("SELECT UserName, Passwd, UserType, AuthKey, LastLoginTime, LastLogoutTime, MaxOnlineServerNum, MaxSessionNum, MaxPipeNum, MaxSameIPServers, TodayCSModeData, LimitDataSize FROM users WHERE UserName = ?") 182 | if err != nil { 183 | return err 184 | } 185 | g_QueryUserNameByKeyStmt, err = g_Database.Prepare("SELECT UserName FROM users WHERE AuthKey = ?") 186 | if err != nil { 187 | return err 188 | } 189 | g_DelUserStmt, err = g_Database.Prepare("DELETE FROM users where UserName = ?") 190 | if err != nil { 191 | return err 192 | } 193 | g_AddUserStmt, err = g_Database.Prepare("INSERT INTO users (UserName, Passwd, UserType, AuthKey, LastLoginTime, LastLogoutTime, MaxOnlineServerNum, MaxSessionNum, MaxPipeNum, MaxSameIPServers, TodayCSModeData, LimitDataSize) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") 194 | if err != nil { 195 | return err 196 | } 197 | g_UpdateUserStmt, err = g_Database.Prepare("UPDATE users SET Passwd = ?, UserType = ?, AuthKey = ?, LastLoginTime = ? , LastLogoutTime = ?, MaxOnlineServerNum = ?, MaxSessionNum = ?, MaxPipeNum = ?, MaxSameIPServers = ?, TodayCSModeData = ?, LimitDataSize = ? WHERE UserName = ?") 198 | if err != nil { 199 | return err 200 | } 201 | go func() { 202 | c := time.Tick(time.Minute * 15) 203 | for _ = range c { 204 | g_Database.Ping() 205 | } 206 | }() 207 | return nil 208 | } 209 | 210 | func DeInit() { 211 | if g_Database != nil { 212 | g_Database.Close() 213 | g_Database = nil 214 | } 215 | } 216 | 217 | func preScan(struc interface{}) []interface{} { 218 | s := reflect.ValueOf(struc).Elem() 219 | s2 := reflect.TypeOf(struc).Elem() 220 | length := s.NumField() 221 | onerow := make([]interface{}, 0) 222 | for i := 0; i < length; i++ { 223 | onerow = append(onerow, s.Field(i).Addr().Interface()) 224 | if s2.Field(i).Tag.Get("stop") != "" { 225 | break 226 | } 227 | } 228 | return onerow 229 | } 230 | 231 | var g_UserKey2Name map[string]string 232 | 233 | func GetUserByKey(key string) (*User, error) { 234 | if g_UserKey2Name == nil { 235 | g_UserKey2Name = make(map[string]string) 236 | } 237 | var err error 238 | name, bHave := g_UserKey2Name[key] 239 | if !bHave { 240 | err = g_QueryUserNameByKeyStmt.QueryRow(key).Scan(&name) 241 | //fmt.Printf("load from db %+v\n", _user) 242 | if err == nil { 243 | g_UserKey2Name[key] = name 244 | } 245 | if err == sql.ErrNoRows { 246 | g_UserKey2Name[key] = "" 247 | err = nil 248 | } 249 | } 250 | if name != "" { 251 | return GetUser(name) 252 | } 253 | return nil, err 254 | } 255 | 256 | func GetUser(name string) (*User, error) { 257 | cache := common.GetCacheContainer("user") 258 | var user *User = nil 259 | var err error 260 | info := cache.GetCache(name) 261 | if info == nil { 262 | _user := &User{} 263 | row := preScan(_user) 264 | err = g_QueryUserStmt.QueryRow(name).Scan(row...) 265 | //fmt.Printf("load from db %+v,%d,%v\n", _user, _user.TodayCSModeData, err) 266 | if err == nil { 267 | user = _user 268 | cache.AddCache(name, _user, CacheTime) 269 | user.OnLogin() 270 | } 271 | if err == sql.ErrNoRows { 272 | err = nil 273 | } 274 | } else { 275 | user = info.(*User) 276 | user.SetCacheTime(-1) 277 | } 278 | return user, err 279 | } 280 | 281 | func DelUser(name string) (bool, error) { 282 | user, err := GetUser(name) 283 | if user != nil { 284 | if g_UserKey2Name != nil { 285 | delete(g_UserKey2Name, user.AuthKey) 286 | } 287 | } 288 | cache := common.GetCacheContainer("user") 289 | cache.DelCache(name) 290 | result, err := g_DelUserStmt.Exec(name) 291 | n, _ := result.RowsAffected() 292 | return n > 0, err 293 | } 294 | 295 | func updateUserDB(user *User) error { 296 | row := preScan(user) 297 | _row := append(row[1:], row[0]) 298 | _, _err := g_UpdateUserStmt.Exec(_row...) 299 | if _err != nil { 300 | return _err 301 | } 302 | return nil 303 | } 304 | 305 | func UpdateUser(name string, user *User) error { 306 | cache := common.GetCacheContainer("user") 307 | info := cache.GetCache(name) 308 | if info != nil { 309 | cache.UpdateCache(name, user) 310 | return nil 311 | } else { 312 | return updateUserDB(user) 313 | } 314 | } 315 | 316 | var authBaseId int = 1 317 | var staticKey string = "admin vzex" 318 | 319 | func genUserKey(name string) string { 320 | authBaseId++ 321 | return common.Md5(fmt.Sprintf("%d%.0f%s%s", authBaseId, time.Now().Unix(), name, staticKey)) 322 | } 323 | 324 | func UpdateUserKey(name, key string) error { 325 | if g_UserKey2Name == nil { 326 | g_UserKey2Name = make(map[string]string) 327 | } 328 | user, err := GetUser(name) 329 | if err != nil { 330 | return err 331 | } 332 | 333 | if user != nil { 334 | if user.AuthKey == key { 335 | return nil 336 | } 337 | g_UserKey2Name[user.AuthKey] = "" 338 | } else { 339 | return errors.New("no user") 340 | } 341 | g_UserKey2Name[key] = name 342 | user.AuthKey = key 343 | err = UpdateUser(name, user) 344 | return err 345 | } 346 | 347 | func GenUserKey(name string) string { 348 | if g_UserKey2Name == nil { 349 | g_UserKey2Name = make(map[string]string) 350 | } 351 | for i := 0; i < 10; i++ { 352 | key := genUserKey(name) 353 | _, bHave := g_UserKey2Name[key] 354 | if !bHave { 355 | return key 356 | } 357 | } 358 | return "" 359 | } 360 | 361 | func AddUser(name string, user *User) (string, error) { 362 | old, err := GetUser(name) 363 | if old != nil { 364 | return "", errors.New("already have user") 365 | } 366 | if err != nil { 367 | return "", err 368 | } 369 | key := GenUserKey(name) 370 | if key == "" { 371 | return "", errors.New("gen user key fail") 372 | } 373 | user.AuthKey = key 374 | row := preScan(user) 375 | _, _err := g_AddUserStmt.Exec(row...) 376 | if _err != nil { 377 | return "", _err 378 | } 379 | if g_UserKey2Name == nil { 380 | g_UserKey2Name = make(map[string]string) 381 | } 382 | g_UserKey2Name[user.AuthKey] = name 383 | return user.AuthKey, nil 384 | } 385 | 386 | func GetUserNameList(limita, limitb string) []string { 387 | names := []string{} 388 | rows, err := g_Database.Query("select UserName from users limit " + limita + "," + limitb) 389 | if err != nil { 390 | return names 391 | } 392 | for rows.Next() { 393 | var name string 394 | if err := rows.Scan(&name); err == nil { 395 | names = append(names, name) 396 | } 397 | } 398 | return names 399 | } 400 | 401 | /* 402 | func main() { 403 | err := Init("dog", "dog") 404 | if err != nil { 405 | panic(err) 406 | } 407 | defer DeInit() 408 | user, _err := GetUser("vzex") 409 | user, _err = GetUser("vzex") 410 | user, _err = GetUser("vzex") 411 | if _err == nil { 412 | fmt.Printf("%+v\n", *user) 413 | } else { 414 | panic(_err) 415 | } 416 | time.Sleep(time.Second * 31) 417 | user, _err = GetUser("vzex") 418 | time.Sleep(time.Second * 50) 419 | } 420 | */ 421 | -------------------------------------------------------------------------------- /admin/admin.go: -------------------------------------------------------------------------------- 1 | package admin 2 | 3 | import ( 4 | "crypto/tls" 5 | "encoding/json" 6 | "fmt" 7 | "net" 8 | "net/http" 9 | "strconv" 10 | 11 | "github.com/vzex/dog-tunnel/auth" 12 | "github.com/vzex/dog-tunnel/common" 13 | ) 14 | 15 | var g_AdminCommands map[string]cmdHandler 16 | 17 | type cmdHandler func(w http.ResponseWriter, r *http.Request) (result string, bSuccess bool) 18 | 19 | func addAdminCmd(cmd string, callback cmdHandler) { 20 | g_AdminCommands[cmd] = callback 21 | } 22 | 23 | func initAdminCmds() { 24 | g_AdminCommands = make(map[string]cmdHandler) 25 | addAdminCmd("servers", _adminGetServers) 26 | addAdminCmd("sessions", _adminGetSession) 27 | addAdminCmd("kicksession", _adminKickSession) 28 | addAdminCmd("kickserver", _adminKickServer) 29 | 30 | addAdminCmd("broadcast", _adminBroadcast) 31 | addAdminCmd("setglobal", _adminSetGlobal) 32 | addAdminCmd("getglobal", _adminGetGlobal) 33 | 34 | addAdminCmd("usersetting", _adminUserSetting) 35 | } 36 | 37 | func InitAdminPort(addr, certFile, keyFile string) error { 38 | initAdminCmds() 39 | mux := http.NewServeMux() 40 | mux.HandleFunc("/admin", adminHandler) 41 | server := &http.Server{Addr: addr, Handler: mux} 42 | listener, err := net.Listen("tcp", addr) 43 | if err != nil { 44 | return err 45 | } 46 | if certFile != "" && keyFile != "" { 47 | config := &tls.Config{} 48 | config.NextProtos = []string{"http/1.1"} 49 | var err error 50 | config.Certificates = make([]tls.Certificate, 1) 51 | config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) 52 | if err != nil { 53 | return err 54 | } 55 | tlsListener := tls.NewListener(listener, config) 56 | go server.Serve(tlsListener) 57 | } else { 58 | go server.Serve(listener) 59 | } 60 | return nil 61 | } 62 | 63 | type handlerResult struct { 64 | Code int 65 | Msg string 66 | } 67 | 68 | func adminHandler(w http.ResponseWriter, r *http.Request) { 69 | command := r.FormValue("cmd") 70 | if command != "" { 71 | handler, bHave := g_AdminCommands[command] 72 | if bHave { 73 | result, bOk := handler(w, r) 74 | if bOk { 75 | res, _ := json.Marshal(handlerResult{Code: 200, Msg: result}) 76 | w.Write([]byte(res)) 77 | } else { 78 | res, _ := json.Marshal(handlerResult{Code: 201, Msg: result}) 79 | w.Write([]byte(res)) 80 | } 81 | return 82 | } 83 | } 84 | res, _ := json.Marshal(handlerResult{Code: 202, Msg: "invalid command"}) 85 | w.Write([]byte(res)) 86 | } 87 | 88 | func _adminKickServer(w http.ResponseWriter, r *http.Request) (result string, bSuccess bool) { 89 | server := r.FormValue("server") 90 | if server == "" { 91 | result = "please spec server" 92 | bSuccess = false 93 | return 94 | } 95 | conn, bHave := common.ServerName2Conn[server] 96 | if bHave { 97 | common.Write(conn, "0", "showandquit", "admin kick you out") 98 | result = "kick server ok" 99 | } else { 100 | bSuccess = false 101 | result = "donnot have this serverName" 102 | return 103 | } 104 | bSuccess = true 105 | return 106 | } 107 | 108 | func _adminGetServers(w http.ResponseWriter, r *http.Request) (result string, bSuccess bool) { 109 | arr := make(map[string]([]string)) 110 | for _, server := range common.Conn2ClientInfo { 111 | if server.IsServer { 112 | _arr, bHave := arr[server.UserName] 113 | if bHave { 114 | arr[server.UserName] = append(_arr, server.ServerName) 115 | arr[server.UserName] = append(arr[server.UserName], server.Conn.RemoteAddr().String()) 116 | } else { 117 | arr[server.UserName] = []string{server.ServerName, server.Conn.RemoteAddr().String()} 118 | } 119 | } 120 | } 121 | _result, _ := json.Marshal(arr) 122 | result = string(_result) 123 | bSuccess = true 124 | return 125 | } 126 | 127 | func _adminKickSession(w http.ResponseWriter, r *http.Request) (result string, bSuccess bool) { 128 | server := r.FormValue("server") 129 | session := r.FormValue("session") 130 | if server == "" || session == "" { 131 | result = "please spec server and session" 132 | bSuccess = false 133 | return 134 | } 135 | conn, bHave := common.ServerName2Conn[server] 136 | if bHave { 137 | server, bHave2 := common.Conn2ClientInfo[conn] 138 | if bHave2 { 139 | session, bHave := server.Id2Session[session] 140 | if bHave { 141 | if session.ClientA != conn { 142 | common.Write(session.ClientA, "0", "showandquit", "admin kick you out") 143 | } else if session.ClientB != conn { 144 | common.Write(session.ClientB, "0", "showandquit", "admin kick you out") 145 | } 146 | result = "kick session ok" 147 | } else { 148 | result = "no need kick" 149 | } 150 | } else { 151 | bSuccess = false 152 | result = "donnot have this conn" 153 | } 154 | } else { 155 | bSuccess = false 156 | result = "donnot have this serverName" 157 | return 158 | } 159 | bSuccess = true 160 | return 161 | } 162 | 163 | func _adminGetSession(w http.ResponseWriter, r *http.Request) (result string, bSuccess bool) { 164 | server := r.FormValue("server") 165 | if server == "" { 166 | result = "please spec server" 167 | bSuccess = false 168 | return 169 | } 170 | arr := []string{} 171 | conn, bHave := common.ServerName2Conn[server] 172 | if bHave { 173 | server, bHave2 := common.Conn2ClientInfo[conn] 174 | if bHave2 { 175 | for _, session := range server.Id2Session { 176 | arr = append(arr, session.String()) 177 | } 178 | } else { 179 | bSuccess = false 180 | result = "donnot have this conn" 181 | } 182 | } else { 183 | bSuccess = false 184 | result = "donnot have this serverName" 185 | return 186 | } 187 | _result, _ := json.Marshal(arr) 188 | result = string(_result) 189 | bSuccess = true 190 | return 191 | } 192 | 193 | func _adminBroadcast(w http.ResponseWriter, r *http.Request) (result string, bSuccess bool) { 194 | msgtype := r.FormValue("type") 195 | if msgtype == "" { 196 | result = "please spec type" 197 | bSuccess = false 198 | return 199 | } 200 | msg := r.FormValue("msg") 201 | quit := r.FormValue("quit") 202 | cmd := "show" 203 | if quit != "" { 204 | cmd = "showandquit" 205 | } 206 | n := 0 207 | for conn, info := range common.Conn2ClientInfo { 208 | hit := false 209 | if msgtype == "s" && info.IsServer { 210 | hit = true 211 | } else if msgtype == "c" && !info.IsServer { 212 | hit = true 213 | } else if msgtype == "a" { 214 | hit = true 215 | } 216 | if hit { 217 | common.Write(conn, "0", cmd, msg) 218 | n++ 219 | } 220 | } 221 | result = fmt.Sprintf("%d", n) 222 | bSuccess = true 223 | return 224 | } 225 | 226 | func _adminSetGlobal(w http.ResponseWriter, r *http.Request) (result string, bSuccess bool) { 227 | key := r.FormValue("key") 228 | //value := r.FormValue("value") 229 | if key == "" { 230 | result = "please spec key" 231 | bSuccess = false 232 | return 233 | } 234 | result = "" 235 | bSuccess = true 236 | return 237 | } 238 | 239 | func _adminGetGlobal(w http.ResponseWriter, r *http.Request) (result string, bSuccess bool) { 240 | key := r.FormValue("key") 241 | if key == "" { 242 | result = "please spec key" 243 | bSuccess = false 244 | return 245 | } 246 | result = "" 247 | bSuccess = true 248 | return 249 | } 250 | 251 | func _adminUserSetting(w http.ResponseWriter, r *http.Request) (result string, bSuccess bool) { 252 | action := r.FormValue("action") 253 | key := r.FormValue("user") 254 | if key == "" && action != "list" { 255 | result = "please spec user" 256 | bSuccess = false 257 | return 258 | } 259 | switch action { 260 | case "limit": 261 | n := r.FormValue("size") 262 | size, _ := strconv.Atoi(n) 263 | 264 | user, err := auth.GetUser(key) 265 | if err != nil { 266 | result = err.Error() 267 | bSuccess = false 268 | return 269 | } else { 270 | user.LimitDataSize = size 271 | err := auth.UpdateUser(key, user) 272 | if err == nil { 273 | bSuccess = true 274 | } else { 275 | result = err.Error() 276 | bSuccess = false 277 | } 278 | return 279 | } 280 | case "add": 281 | passwd := r.FormValue("passwd") 282 | if passwd == "" { 283 | result = "please spec passwd" 284 | bSuccess = false 285 | return 286 | } 287 | _usertype := auth.UserType_Normal 288 | usertype := r.FormValue("type") 289 | maxOnlineServerNum := auth.DefaultMaxOnlineServerNum 290 | maxSessionNum := auth.DefaultMaxSessionNum 291 | maxPipeNum := auth.DefaultMaxPipeNum 292 | maxSameIPServers := auth.DefaultMaxSameIPServers 293 | switch usertype { 294 | case "black": 295 | _usertype = auth.UserType_BlackList 296 | case "super": 297 | _usertype = auth.UserType_Super 298 | maxOnlineServerNum = 10 299 | maxSessionNum = 10 300 | maxPipeNum = 10 301 | maxSameIPServers = 10 302 | case "admin": 303 | _usertype = auth.UserType_Admin 304 | } 305 | 306 | user := &auth.User{UserName: key, Passwd: common.HashPasswd(common.Md5(passwd)), UserType: _usertype, LastLoginTime: 0, LastLogoutTime: 0, MaxOnlineServerNum: maxOnlineServerNum, MaxSessionNum: maxSessionNum, MaxPipeNum: maxPipeNum, MaxSameIPServers: maxSameIPServers, TodayCSModeData: 0, LimitDataSize: 0} 307 | key, err := auth.AddUser(key, user) 308 | if err != nil { 309 | result = err.Error() 310 | bSuccess = false 311 | return 312 | } else { 313 | result = key 314 | bSuccess = true 315 | return 316 | } 317 | case "list": 318 | limita := r.FormValue("limita") 319 | limitb := r.FormValue("limitb") 320 | if limita == "" || limitb == "" { 321 | result = "please limita and limitb" 322 | bSuccess = false 323 | return 324 | } 325 | arr := auth.GetUserNameList(limita, limitb) 326 | res, _ := json.Marshal(arr) 327 | result = string(res) 328 | bSuccess = true 329 | return 330 | case "get": 331 | user, err := auth.GetUser(key) 332 | if err != nil { 333 | result = err.Error() 334 | bSuccess = false 335 | return 336 | } else { 337 | if user == nil { 338 | result = "donnot have this user" 339 | bSuccess = false 340 | return 341 | } 342 | 343 | res, _ := json.Marshal(user) 344 | result = string(res) 345 | bSuccess = true 346 | return 347 | } 348 | case "del": 349 | bHave, err := auth.DelUser(key) 350 | if err != nil { 351 | result = err.Error() 352 | bSuccess = false 353 | return 354 | } else { 355 | if !bHave { 356 | result = "donnot have this user" 357 | } 358 | bSuccess = true 359 | return 360 | } 361 | case "key": 362 | _key := auth.GenUserKey(key) 363 | if _key == "" { 364 | result = "gen user key fail" 365 | bSuccess = false 366 | return 367 | } 368 | err := auth.UpdateUserKey(key, _key) 369 | if err == nil { 370 | result = _key 371 | bSuccess = true 372 | } else { 373 | result = err.Error() 374 | bSuccess = false 375 | } 376 | return 377 | case "set": 378 | _usertype := -1 379 | maxOnlineServerNum := -1 380 | maxSessionNum := -1 381 | maxPipeNum := -1 382 | maxSameIPServers := -1 383 | pass := "" 384 | passwd := r.FormValue("passwd") 385 | if passwd != "" { 386 | pass = common.HashPasswd(common.Md5(passwd)) 387 | } 388 | usertype := r.FormValue("type") 389 | if usertype != "" { 390 | switch usertype { 391 | case "black": 392 | _usertype = auth.UserType_BlackList 393 | case "super": 394 | _usertype = auth.UserType_Super 395 | maxOnlineServerNum = 10 396 | maxSessionNum = 10 397 | maxPipeNum = 10 398 | case "normal": 399 | _usertype = auth.UserType_Normal 400 | maxOnlineServerNum = auth.DefaultMaxOnlineServerNum 401 | maxSessionNum = auth.DefaultMaxSessionNum 402 | maxPipeNum = auth.DefaultMaxPipeNum 403 | maxSameIPServers = auth.DefaultMaxSameIPServers 404 | case "admin": 405 | _usertype = auth.UserType_Admin 406 | } 407 | } 408 | servern := r.FormValue("serven") 409 | if servern != "" { 410 | maxOnlineServerNum, _ = strconv.Atoi(servern) 411 | } 412 | sessionn := r.FormValue("sessionn") 413 | if sessionn != "" { 414 | maxSessionNum, _ = strconv.Atoi(sessionn) 415 | } 416 | pipen := r.FormValue("pipen") 417 | if pipen != "" { 418 | maxPipeNum, _ = strconv.Atoi(pipen) 419 | } 420 | ipn := r.FormValue("sameip") 421 | if ipn != "" { 422 | maxSameIPServers, _ = strconv.Atoi(ipn) 423 | } 424 | user, err := auth.GetUser(key) 425 | if err != nil { 426 | result = err.Error() 427 | bSuccess = false 428 | return 429 | } else { 430 | if _usertype != -1 { 431 | user.UserType = _usertype 432 | } 433 | if maxOnlineServerNum != -1 { 434 | user.MaxOnlineServerNum = maxOnlineServerNum 435 | } 436 | if maxSessionNum != -1 { 437 | user.MaxSessionNum = maxSessionNum 438 | } 439 | if maxPipeNum != -1 { 440 | user.MaxPipeNum = maxPipeNum 441 | } 442 | if maxSameIPServers != -1 { 443 | user.MaxSameIPServers = maxSameIPServers 444 | } 445 | if pass != "" { 446 | user.Passwd = pass 447 | } 448 | err := auth.UpdateUser(key, user) 449 | if err == nil { 450 | bSuccess = true 451 | } else { 452 | result = err.Error() 453 | bSuccess = false 454 | } 455 | return 456 | } 457 | default: 458 | result = "invalid action" 459 | bSuccess = false 460 | return 461 | } 462 | result = "" 463 | bSuccess = true 464 | return 465 | } 466 | -------------------------------------------------------------------------------- /nat/stun/stun.go: -------------------------------------------------------------------------------- 1 | // Package stun implements a subset of the Session Traversal Utilities 2 | // for NAT (STUN) protocol, described in RFC 5389. Notably absent is 3 | // support for long-term credentials. 4 | package stun 5 | 6 | import ( 7 | "bytes" 8 | "crypto/hmac" 9 | "crypto/sha1" 10 | "crypto/rand" 11 | "encoding/binary" 12 | "errors" 13 | "fmt" 14 | "hash/crc32" 15 | "io" 16 | "net" 17 | ) 18 | 19 | type Class uint8 20 | type Method uint16 21 | 22 | // Possible classes and methods for a STUN packet. 23 | const ( 24 | ClassRequest = iota 25 | ClassIndication 26 | ClassSuccess 27 | ClassError 28 | MethodBinding = 1 29 | ) 30 | 31 | // A Packet presents select information about a STUN packet. 32 | type Packet struct { 33 | Class Class 34 | Method Method 35 | Tid [12]byte 36 | Addr *net.UDPAddr 37 | HasMac bool 38 | Software string 39 | UseCandidate bool 40 | 41 | Error *PacketError 42 | Alternate *net.UDPAddr 43 | } 44 | 45 | func RandomTid() ([]byte, error) { 46 | ret := make([]byte, 12) 47 | _, err := io.ReadFull(rand.Reader, ret) 48 | if err != nil { 49 | return nil, err 50 | } 51 | return ret, nil 52 | } 53 | 54 | func InformReady(tid []byte, addr *net.UDPAddr, macKey []byte) ([]byte, error) { 55 | if len(tid) != 12 { 56 | panic("Wrong length for tid") 57 | } 58 | var hdr header 59 | hdr.TypeCode = typeCode(ClassIndication, MethodBinding) 60 | hdr.Magic = magic 61 | copy(hdr.Tid[:], tid) 62 | 63 | var buf bytes.Buffer 64 | if addr != nil { 65 | ip := addr.IP.To4() 66 | family := 1 67 | if ip == nil { 68 | ip = addr.IP 69 | family++ 70 | } 71 | 72 | binary.Write(&buf, binary.BigEndian, []uint16{ 73 | attrAddress, 74 | uint16(4 + len(ip)), 75 | uint16(family), 76 | uint16(addr.Port)}) 77 | buf.Write(ip) 78 | } 79 | return buildPacket(hdr, buf.Bytes(), macKey, false) 80 | } 81 | // BindRequest constructs and returns a Binding Request STUN packet. 82 | // 83 | // tid must be 12 bytes long. If a macKey is provided, the returned 84 | // packet is signed. 85 | func BindRequest(tid []byte, addr *net.UDPAddr, macKey []byte, compat bool, useCandidate bool) ([]byte, error) { 86 | if len(tid) != 12 { 87 | panic("Wrong length for tid") 88 | } 89 | var hdr header 90 | hdr.TypeCode = typeCode(ClassRequest, MethodBinding) 91 | hdr.Magic = magic 92 | copy(hdr.Tid[:], tid) 93 | 94 | var buf bytes.Buffer 95 | if useCandidate { 96 | binary.Write(&buf, binary.BigEndian, []uint16{ 97 | attrUseCandidate, 98 | uint16(0)}) 99 | } 100 | 101 | if addr != nil { 102 | ip := addr.IP.To4() 103 | family := 1 104 | if ip == nil { 105 | ip = addr.IP 106 | family++ 107 | } 108 | 109 | binary.Write(&buf, binary.BigEndian, []uint16{ 110 | attrAddress, 111 | uint16(4 + len(ip)), 112 | uint16(family), 113 | uint16(addr.Port)}) 114 | buf.Write(ip) 115 | } 116 | return buildPacket(hdr, buf.Bytes(), macKey, compat) 117 | } 118 | 119 | // BindResponse constructs and returns a Binding Success STUN packet. 120 | // 121 | // tid must be 12 bytes long. If a macKey is provided, the returned 122 | // packet is signed. 123 | func BindResponse(tid []byte, addr *net.UDPAddr, macKey []byte, compat bool) ([]byte, error) { 124 | if len(tid) != 12 { 125 | panic("Wrong length for tid") 126 | } 127 | var hdr header 128 | hdr.TypeCode = typeCode(ClassSuccess, MethodBinding) 129 | hdr.Magic = magic 130 | copy(hdr.Tid[:], tid) 131 | 132 | ip := addr.IP.To4() 133 | family := 1 134 | if ip == nil { 135 | ip = addr.IP 136 | family++ 137 | } 138 | 139 | var buf bytes.Buffer 140 | binary.Write(&buf, binary.BigEndian, []uint16{ 141 | attrXorAddress, 142 | uint16(4 + len(ip)), 143 | uint16(family), 144 | uint16(addr.Port ^ magic>>16)}) 145 | buf.Write(ip) 146 | 147 | attrs := buf.Bytes() 148 | for i := range magicBytes { 149 | attrs[8+i] ^= magicBytes[i] 150 | } 151 | for i := range attrs[12:] { 152 | attrs[12+i] ^= tid[i] 153 | } 154 | return buildPacket(hdr, attrs, macKey, compat) 155 | } 156 | 157 | // ParsePacket parses a byte slice as a STUN packet. 158 | // 159 | // If a macKey is provided, only packets correctly signed with that 160 | // key will be accepted. If no macKey is provided, only unsigned 161 | // packets will be accepted. 162 | func ParsePacket(raw []byte, macKey []byte) (*Packet, error) { 163 | var hdr header 164 | if err := binary.Read(bytes.NewBuffer(raw[:headerLen]), binary.BigEndian, &hdr); err != nil { 165 | return nil, err 166 | } 167 | 168 | // Initial sanity checks: verify initial bits, magic, length and 169 | // optional fingerprint. 170 | if hdr.TypeCode&0xC000 != 0 || int(hdr.Length+20) != len(raw) || hdr.Magic != magic { 171 | return nil, MalformedPacket{} 172 | } 173 | if hdr.Length >= fpLen { 174 | if present, valid := checkFp(raw); present { 175 | if !valid { 176 | return nil, MalformedPacket{} 177 | } 178 | raw = raw[:len(raw)-fpLen] 179 | } 180 | } 181 | 182 | pkt := &Packet{ 183 | Class: typeCodeClass(hdr.TypeCode), 184 | Method: typeCodeMethod(hdr.TypeCode), 185 | Tid: hdr.Tid, 186 | } 187 | 188 | attrReader := bytes.NewBuffer(raw[headerLen:]) 189 | var haveXor bool 190 | for { 191 | if attrReader.Len() == 0 { 192 | break 193 | } 194 | 195 | var ahdr attrHeader 196 | if err := binary.Read(attrReader, binary.BigEndian, &ahdr); err != nil { 197 | return nil, err 198 | } 199 | if ahdr.Length > 500 || attrReader.Len() < int(ahdr.Length) { 200 | return nil, MalformedPacket{} 201 | } 202 | value := attrReader.Next(int(ahdr.Length)) 203 | if ahdr.Length%4 != 0 { 204 | attrReader.Next(int(4 - ahdr.Length%4)) 205 | } 206 | 207 | switch ahdr.Type { 208 | case attrAddress: 209 | if !haveXor { 210 | ip, port, err := parseAddress(value) 211 | if err != nil { 212 | return nil, err 213 | } 214 | pkt.Addr = &net.UDPAddr{IP:ip, Port:port} 215 | } 216 | case attrXorAddress: 217 | ip, port, err := parseAddress(value) 218 | if err != nil { 219 | return nil, err 220 | } 221 | for i := range ip { 222 | ip[i] ^= raw[4+i] 223 | } 224 | port ^= int(binary.BigEndian.Uint16(raw[4:])) 225 | pkt.Addr = &net.UDPAddr{IP:ip, Port:port} 226 | haveXor = true 227 | case attrUseCandidate: 228 | pkt.UseCandidate = true 229 | 230 | case attrFingerprint: 231 | return nil, MalformedPacket{} 232 | case attrIntegrity: 233 | if len(macKey) == 0 { 234 | return nil, UnverifiableMac{} 235 | } 236 | tocheck := raw[:len(raw)-attrReader.Len()-macLen] 237 | binary.BigEndian.PutUint16(tocheck[2:4], uint16(len(tocheck)+macLen-headerLen)) 238 | macer := hmac.New(sha1.New, macKey) 239 | if _, err := macer.Write(tocheck); err != nil { 240 | return nil, err 241 | } 242 | mac := make([]byte, 0, 20) 243 | mac = macer.Sum(mac) 244 | if !bytes.Equal(mac, value) { 245 | return nil, BadMac{} 246 | } 247 | pkt.HasMac = true 248 | return pkt, nil 249 | 250 | case attrErrCode: 251 | code := uint16(value[2])*100 + uint16(value[3]) 252 | reason := string(value[4:]) 253 | pkt.Error = &PacketError{code, reason} 254 | case attrUnknownAttrs: 255 | // Ignored 256 | case attrSoftware: 257 | pkt.Software = string(value) 258 | case attrAlternate: 259 | ip, port, err := parseAddress(value) 260 | if err != nil { 261 | return nil, err 262 | } 263 | pkt.Alternate = &net.UDPAddr{IP:ip, Port:port} 264 | 265 | case attrUsername: 266 | case attrRealm: 267 | case attrNonce: 268 | return nil, errors.New("Unsupported STUN attribute") 269 | } 270 | } 271 | 272 | if len(macKey) > 0 { 273 | return nil, MissingMac{} 274 | } 275 | return pkt, nil 276 | } 277 | 278 | // A MalformedPacket error is returned by ParsePacket when it 279 | // encounters structural malformations in the STUN packet. 280 | // 281 | // On a network endpoing where STUN coexists with another protocol, 282 | // this error can be used to differentiate STUN and non-STUN traffic. 283 | type MalformedPacket struct{} 284 | 285 | func (m MalformedPacket) Error() string { 286 | return "Malformed STUN packet" 287 | } 288 | 289 | // A BadMac error is returned by ParsePacket when a structurally sound 290 | // STUN packet is received with a signature not matching the provided 291 | // macKey. 292 | type BadMac struct{} 293 | 294 | func (b BadMac) Error() string { 295 | return "Incorrect MAC on packet" 296 | } 297 | 298 | // A MissingMac error is returned by ParsePacket when it receives a 299 | // valid but unsigned STUN packet where it expected a signed packet. 300 | type MissingMac struct{} 301 | 302 | func (m MissingMac) Error() string { 303 | return "MAC expected but missing" 304 | } 305 | 306 | // An UnverifiableMac error is returned by ParsePacket when it 307 | // encounters a valid and signed STUN packet, and no macKey was 308 | // provided. 309 | type UnverifiableMac struct{} 310 | 311 | func (u UnverifiableMac) Error() string { 312 | return "MAC found but no key given" 313 | } 314 | 315 | // A PacketError describes an error returned by a STUN server. 316 | type PacketError struct { 317 | Code uint16 318 | Reason string 319 | } 320 | 321 | func (p PacketError) Error() string { 322 | var genericErr string 323 | switch p.Code { 324 | case errTryAlternate: 325 | genericErr = "Try Alternate" 326 | case errBadRequest: 327 | genericErr = "Bad Request" 328 | case errUnauthorized: 329 | genericErr = "Unauthorized" 330 | case errUnknownAttribute: 331 | genericErr = "Unknown Attribute(s)" 332 | case errStaleNonce: 333 | genericErr = "Stale Nonce" 334 | case errServerInternal: 335 | genericErr = "Internal Server Error" 336 | default: 337 | genericErr = fmt.Sprintf("Error %d", p.Code) 338 | } 339 | if len(p.Reason) == 0 { 340 | return genericErr 341 | } 342 | return fmt.Sprintf("%s: %s", genericErr, p.Reason) 343 | } 344 | 345 | func buildPacket(hdr header, attributes, macKey []byte, compat bool) ([]byte, error) { 346 | var buf bytes.Buffer 347 | 348 | if len(macKey) > 0 { 349 | hdr.Length = uint16(len(attributes) + macLen) 350 | 351 | macer := hmac.New(sha1.New, macKey) 352 | if err := binary.Write(macer, binary.BigEndian, hdr); err != nil { 353 | return nil, err 354 | } 355 | if _, err := macer.Write(attributes); err != nil { 356 | return nil, err 357 | } 358 | 359 | if err := binary.Write(&buf, binary.BigEndian, attrHeader{attrIntegrity, 20}); err != nil { 360 | return nil, err 361 | } 362 | attributes = append(attributes, macer.Sum(buf.Bytes())...) 363 | buf.Reset() 364 | } 365 | hdr.Length = uint16(len(attributes)) 366 | if !compat { 367 | hdr.Length += fpLen 368 | } 369 | if err := binary.Write(&buf, binary.BigEndian, hdr); err != nil { 370 | return nil, err 371 | } 372 | buf.Write(attributes) 373 | if !compat { 374 | var fp fpAttr 375 | fp.Type = attrFingerprint 376 | fp.Length = 4 377 | fp.Crc = crc32.ChecksumIEEE(buf.Bytes()) ^ 0x5354554e 378 | if err := binary.Write(&buf, binary.BigEndian, fp); err != nil { 379 | return nil, err 380 | } 381 | } 382 | return buf.Bytes(), nil 383 | } 384 | 385 | func parseAddress(raw []byte) (net.IP, int, error) { 386 | if len(raw) != 8 && len(raw) != 20 { 387 | return nil, 0, MalformedPacket{} 388 | } 389 | var family int 390 | switch int(raw[1]) { 391 | case 1: 392 | family = 4 393 | case 2: 394 | family = 16 395 | default: 396 | return nil, 0, MalformedPacket{} 397 | } 398 | port := binary.BigEndian.Uint16(raw[2:]) 399 | ip := make([]byte, len(raw[4:])) 400 | copy(ip, raw[4:]) 401 | if len(ip) != family { 402 | return nil, 0, MalformedPacket{} 403 | } 404 | return net.IP(ip), int(port), nil 405 | } 406 | 407 | func checkFp(raw []byte) (present, valid bool) { 408 | split := len(raw) - fpLen 409 | var fp fpAttr 410 | if err := binary.Read(bytes.NewBuffer(raw[split:]), binary.BigEndian, &fp); err != nil { 411 | return false, false 412 | } 413 | if fp.Type != attrFingerprint || fp.Length != 4 { 414 | return false, false 415 | } 416 | if fp.Crc != (crc32.ChecksumIEEE(raw[:split]) ^ 0x5354554e) { 417 | return true, false 418 | } 419 | return true, true 420 | } 421 | 422 | func typeCode(class uint8, method uint16) uint16 { 423 | return method<<2&0xFE00 | uint16(class)&2<<7 | method<<1&0x00E0 | uint16(class)&1<<4 | method&0xF 424 | } 425 | 426 | func typeCodeClass(typeCode uint16) Class { 427 | return Class(typeCode>>4&1 | typeCode>>7&2) 428 | } 429 | 430 | func typeCodeMethod(typeCode uint16) Method { 431 | return Method(typeCode&0xF | typeCode&0xE0>>1 | typeCode&0xFE00>>2) 432 | } 433 | 434 | // Parsing structs 435 | type header struct { 436 | TypeCode uint16 437 | Length uint16 438 | Magic uint32 439 | Tid [12]byte 440 | } 441 | 442 | type attrHeader struct { 443 | Type uint16 444 | Length uint16 445 | } 446 | 447 | type fpAttr struct { 448 | attrHeader 449 | Crc uint32 450 | } 451 | 452 | // Constants 453 | 454 | const ( 455 | magic = 0x2112a442 456 | headerLen = 20 457 | fpLen = 8 458 | macLen = 24 459 | ) 460 | 461 | var magicBytes = []byte{0x21, 0x12, 0xa4, 0x42} 462 | 463 | const ( 464 | // Comprehension required 465 | attrAddress = 0x01 // 466 | attrUsername = 0x06 // 467 | attrIntegrity = 0x08 // 468 | attrErrCode = 0x09 // 469 | attrUnknownAttrs = 0x0A // 470 | attrRealm = 0x14 // 471 | attrNonce = 0x15 // 472 | attrXorAddress = 0x20 // 473 | attrUseCandidate = 0x25 // 474 | 475 | // Comprehension optional 476 | attrSoftware = 0x8022 // 477 | attrAlternate = 0x8023 // 478 | attrFingerprint = 0x8028 // 479 | ) 480 | 481 | const ( 482 | errTryAlternate = 300 483 | errBadRequest = 400 484 | errUnauthorized = 401 485 | errUnknownAttribute = 420 486 | errStaleNonce = 438 487 | errServerInternal = 500 488 | ) 489 | -------------------------------------------------------------------------------- /server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "encoding/json" 6 | "flag" 7 | "fmt" 8 | "log" 9 | "net" 10 | "os" 11 | "os/signal" 12 | "strconv" 13 | "strings" 14 | "syscall" 15 | "time" 16 | 17 | "github.com/vzex/dog-tunnel/admin" 18 | "github.com/vzex/dog-tunnel/auth" 19 | "github.com/vzex/dog-tunnel/common" 20 | ) 21 | 22 | var listenAddr = flag.String("addr", "0.0.0.0:8000", "server addr") 23 | var listenAddrUDP = flag.String("addrudp", "0.0.0.0:8018", "udp server addr") 24 | var bUseSSL = flag.Bool("ssl", false, "use ssl") 25 | var bUseHttps = flag.Bool("https", false, "use https") 26 | var certFile = flag.String("cert", "", "cert file") 27 | var keyFile = flag.String("key", "", "key file") 28 | 29 | var adminAddr = flag.String("admin", "", "admin addr") 30 | var bShowVersion = flag.Bool("version", false, "show version") 31 | 32 | var db_user = flag.String("dbuser", "", "db user") 33 | var db_pass = flag.String("dbpass", "", "db password") 34 | var db_host = flag.String("dbhost", "", "db host") 35 | 36 | var bUseDB = false 37 | 38 | func handleClient(conn net.Conn) { 39 | common.Conn2ClientInfo[conn] = &common.ClientInfo{Conn: conn, ClientMap: make(map[net.Conn]*common.Session), Id2Session: make(map[string]*common.Session), IsServer: false, Quit: make(chan bool), ResponseTime: time.Now().Unix()} 40 | log.Println("client linked success", conn.RemoteAddr().String()) 41 | common.Conn2ClientInfo[conn].Loop() 42 | common.Read(conn, handleResponse) 43 | client, bHave := common.Conn2ClientInfo[conn] 44 | if bHave { 45 | close(client.Quit) 46 | if client.IsServer { 47 | for conn, session := range client.ClientMap { 48 | conn.Close() 49 | common.RmId(client.ServerName, session.Id) 50 | } 51 | delete(common.ServerName2Conn, client.ServerName) 52 | log.Println("unregister service Name", client.ServerName) 53 | if bUseDB { 54 | user, _ := auth.GetUser(client.UserName) 55 | if user != nil { 56 | user.OnLogout() 57 | } 58 | } 59 | } else { 60 | common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { 61 | id := server.DelClient(conn) 62 | log.Println("send quit") 63 | common.Write(server.Conn, id, "clientquit", "") 64 | }, func() {}) 65 | } 66 | delete(common.Conn2ClientInfo, conn) 67 | } 68 | conn.Close() 69 | log.Println("client disconnected", conn.RemoteAddr().String()) 70 | } 71 | 72 | func udphandleClient(conn *net.UDPConn) { 73 | 74 | for { 75 | 76 | data := make([]byte, 1024) 77 | 78 | _, remoteAddr, err := conn.ReadFromUDP(data) 79 | if err != nil { 80 | log.Println("failed to read UDP msg because of ", err.Error()) 81 | break 82 | } 83 | 84 | conn.WriteToUDP([]byte(remoteAddr.String()), remoteAddr) 85 | } 86 | } 87 | 88 | func handleResponse(conn net.Conn, id string, action string, content string) { 89 | //log.Println("got", id, action, content) 90 | common.GetClientInfoByConn(conn, func(client *common.ClientInfo) { 91 | client.ResponseTime = time.Now().Unix() 92 | }, func() { 93 | }) 94 | switch action { 95 | case "init": 96 | clientInfoStr := content 97 | var clientInfo common.ClientSetting 98 | err := json.Unmarshal([]byte(clientInfoStr), &clientInfo) 99 | if err != nil { 100 | log.Println("error decode clientinfo, kick out", conn.RemoteAddr().String()) 101 | common.Write(conn, "0", "showandquit", "server decode clientInfo error") 102 | return 103 | } 104 | if common.Version != clientInfo.Version { 105 | s_version := fmt.Sprintf("%.2f", common.Version) 106 | c_version := fmt.Sprintf("%.2f", clientInfo.Version) 107 | log.Println("version not eq", conn.RemoteAddr().String(), s_version, c_version) 108 | common.Write(conn, "0", "showandquit", "client version:"+c_version+" not eq with server:"+s_version) 109 | return 110 | } 111 | ServerName := clientInfo.Name 112 | if clientInfo.ClientType == "reg" { 113 | var user *auth.User 114 | if bUseDB { 115 | if clientInfo.AccessKey == "" { 116 | user, _ = auth.GetUser("test") 117 | } else { 118 | user, _ = auth.GetUserByKey(clientInfo.AccessKey) 119 | } 120 | } else { 121 | user = &auth.User{UserType: auth.UserType_Admin} 122 | } 123 | //fmt.Printf("%+v\n", user) 124 | if user == nil { 125 | common.Write(conn, "0", "showandquit", "invalid user accessKey:"+clientInfo.AccessKey+"!!!") 126 | return 127 | } 128 | if !user.CheckOnlineServiceNum() { 129 | common.Write(conn, "0", "showandquit", "online service num cannot overstep "+strconv.Itoa(user.MaxOnlineServerNum)) 130 | return 131 | } 132 | if !user.CheckIpLimit(conn.RemoteAddr().(*net.TCPAddr).IP.String()) { 133 | common.Write(conn, "0", "showandquit", "ip limit service num cannot overstep "+strconv.Itoa(user.MaxSameIPServers)) 134 | return 135 | } 136 | common.GetClientInfoByName(ServerName, func(server *common.ClientInfo) { 137 | common.Write(conn, "0", "showandretry", "already have the ServerName!") 138 | }, func() { 139 | common.ServerName2Conn[ServerName] = conn 140 | common.GetClientInfoByConn(conn, func(info *common.ClientInfo) { 141 | info.ServerName = ServerName 142 | info.IsServer = true 143 | info.Id2MakeSession = make(map[string]*common.UDPMakeSession) 144 | info.UserName = user.UserName 145 | info.ClientKey = clientInfo.ClientKey 146 | }, func() {}) 147 | log.Println("client reg service success", conn.RemoteAddr().String(), user.UserName, ServerName) 148 | common.Write(conn, "0", "show", "register service ok, user:"+user.UserName) 149 | }) 150 | } else if clientInfo.ClientType == "link" { 151 | if clientInfo.Mode < 0 || clientInfo.Mode > 2 { 152 | clientInfo.Mode = 0 153 | } 154 | ServerName := clientInfo.Name 155 | bAuth := true 156 | common.GetClientInfoByName(ServerName, func(info *common.ClientInfo) { 157 | var user *auth.User 158 | if bUseDB { 159 | user, _ = auth.GetUser(info.UserName) 160 | } else { 161 | user = &auth.User{UserType: auth.UserType_Admin} 162 | } 163 | //fmt.Printf("%+v\n", user) 164 | if user == nil { 165 | common.Write(conn, "0", "showandquit", "invalid user:"+info.UserName+"!!!") 166 | bAuth = false 167 | return 168 | } 169 | if info.ClientKey != clientInfo.ClientKey { 170 | common.Write(conn, "0", "showandquit", "clientkey invalid!!!") 171 | bAuth = false 172 | return 173 | } 174 | if !user.CheckSessionNum(len(info.ClientMap)) { 175 | common.Write(conn, "0", "showandquit", "session numcannot overstep "+strconv.Itoa(len(info.ClientMap))) 176 | bAuth = false 177 | return 178 | } 179 | if !user.CheckPipeNum(clientInfo.PipeNum) { 180 | common.Write(conn, "0", "showandquit", "pipenum cannot overstep "+strconv.Itoa(user.MaxPipeNum)) 181 | bAuth = false 182 | return 183 | } 184 | }, func() { 185 | common.Write(conn, "0", "showandquit", "serverName invalid!!!") 186 | bAuth = false 187 | }) 188 | if !bAuth { 189 | return 190 | } 191 | common.GetClientInfoByConn(conn, func(client *common.ClientInfo) { 192 | client.ServerName = ServerName 193 | }, func() { 194 | }) 195 | common.GetClientInfoByName(ServerName, func(server *common.ClientInfo) { 196 | log.Println("client link service success", conn.RemoteAddr().String(), ServerName) 197 | server.AddClient(conn, clientInfo) 198 | }, func() { 199 | common.Write(conn, "0", "showandquit", "donnt have this service name") 200 | }) 201 | } 202 | case "tunnel_error": 203 | common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { 204 | log.Println("<<=====tunnel_error", server.ServerName, conn.RemoteAddr().String()) 205 | session, bHave := server.Id2Session[id] 206 | if bHave { 207 | session.Status = "fail" 208 | common.Write(session.ClientA, "0", "showandquit", content) 209 | server.DelClient(session.ClientA) 210 | } 211 | }, func() { 212 | }) 213 | case "makeholefail": 214 | common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { 215 | udpsession, bHave := server.Id2MakeSession[id] 216 | if bHave { 217 | log.Println("<<=====make hole fail", conn.RemoteAddr().String(), udpsession.ServerName, udpsession.SessionId, id) 218 | sessionId := udpsession.SessionId 219 | session, _bHave := server.Id2Session[sessionId] 220 | if _bHave { 221 | session.Status = "fail" 222 | session.MakeHoleResponseN++ 223 | session.MakeHoleHasFail = true 224 | if session.MakeHoleResponseN == session.Setting.PipeNum { 225 | if session.Method == "udp" { 226 | session.RestartSession(server.ServerName) 227 | } else if session.Method == "restart" { 228 | if session.Setting.Mode == 0 { 229 | tmp := session.ClientA 230 | session.ClientA = session.ClientB 231 | session.ClientB = tmp 232 | session.StartCSMode() 233 | } else { 234 | server.DelClient(session.ClientB) 235 | } 236 | } else { 237 | server.DelClient(session.ClientA) 238 | } 239 | } 240 | } 241 | udpsession.Remove(false) 242 | } 243 | }, func() { 244 | }) 245 | case "makeholeok": 246 | common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { 247 | if content == "csmode" { 248 | session, _bHave := server.Id2Session[id] 249 | if _bHave { 250 | log.Println("<<=====make hole ok", conn.RemoteAddr().String(), server.ServerName, session.Id) 251 | session.Status = "ok" 252 | session.MakeHoleResponseN++ 253 | } 254 | } 255 | udpsession, bHave := server.Id2MakeSession[id] 256 | if bHave { 257 | log.Println("<<=====make hole ok", conn.RemoteAddr().String(), udpsession.ServerName, udpsession.SessionId, id) 258 | sessionId := udpsession.SessionId 259 | session, _bHave := server.Id2Session[sessionId] 260 | if _bHave { 261 | session.MakeHoleResponseN++ 262 | if session.MakeHoleResponseN == session.Setting.PipeNum { 263 | if !session.MakeHoleHasFail { 264 | session.Status = "ok" 265 | } 266 | } 267 | } 268 | udpsession.Remove(false) 269 | } 270 | }, func() { 271 | }) 272 | case "report_addrlist": 273 | common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { 274 | udpsession, bHave := server.Id2MakeSession[id] 275 | //log.Println("test", udpsession, id, server.ServerName) 276 | if bHave { 277 | log.Println("<<===report addr list ok", conn.RemoteAddr().String(), udpsession.ServerName, udpsession.Id) 278 | udpsession.BeginMakeHole(1, content) 279 | } 280 | }, func() { 281 | }) 282 | case "success_bust_a": 283 | common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { 284 | udpsession, bHave := server.Id2MakeSession[id] 285 | if bHave { 286 | log.Println("<<=====success_bust_a", conn.RemoteAddr().String(), udpsession.ServerName, udpsession.SessionId, id) 287 | udpsession.BeginMakeHole(2, content) 288 | } 289 | }, func() { 290 | }) 291 | // for c/s mode 292 | case "tunnel_close": 293 | common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { 294 | session := server.GetSession(conn) 295 | if session != nil { 296 | common.Write(session.ClientB, session.Id+"-"+id, "csmode_s_tunnel_close", content) 297 | } else { 298 | println("no session") 299 | } 300 | }, func() { 301 | }) 302 | case "tunnel_open": 303 | common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { 304 | session := server.GetSession(conn) 305 | if session != nil { 306 | common.Write(session.ClientB, session.Id+"-"+id, "csmode_s_tunnel_open", content) 307 | } else { 308 | println("no session") 309 | } 310 | }, func() { 311 | }) 312 | case "tunnel_msg_c": 313 | common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { 314 | var user *auth.User 315 | if bUseDB { 316 | user, _ = auth.GetUser(server.UserName) 317 | } else { 318 | user = &auth.User{UserType: auth.UserType_Admin} 319 | } 320 | if user == nil { 321 | common.Write(conn, "0", "showandquit", "cannot get userinfo of this service "+server.UserName) 322 | return 323 | } 324 | if !user.UpdateCSMode(len(content)) { 325 | common.Write(conn, "0", "showandquit", "reach today's csmode data limit") 326 | return 327 | } 328 | session := server.GetSession(conn) 329 | if session != nil { 330 | common.Write(session.ClientB, session.Id+"-"+id, "csmode_msg_c", content) 331 | } else { 332 | println("no session") 333 | } 334 | }, func() { 335 | }) 336 | case "tunnel_msg_s": 337 | common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { 338 | var user *auth.User 339 | if bUseDB { 340 | user, _ = auth.GetUser(server.UserName) 341 | } else { 342 | user = &auth.User{UserType: auth.UserType_Admin} 343 | } 344 | if user == nil { 345 | common.Write(conn, "0", "showandquit", "cannot get userinfo of this service"+server.UserName) 346 | return 347 | } 348 | if !user.UpdateCSMode(len(content)) { 349 | common.Write(conn, "0", "show", "reach today's csmode data limit") 350 | return 351 | } 352 | arr := strings.Split(id, "-") 353 | clientId := arr[0] 354 | session, bHave := server.Id2Session[clientId] 355 | if bHave { 356 | common.Write(session.ClientA, id, "csmode_msg_s", content) 357 | } else { 358 | println("no session") 359 | } 360 | }, func() { 361 | }) 362 | case "tunnel_close_s": 363 | common.GetServerInfoByConn(conn, func(server *common.ClientInfo) { 364 | arr := strings.Split(id, "-") 365 | clientId := arr[0] 366 | session, bHave := server.Id2Session[clientId] 367 | if bHave { 368 | common.Write(session.ClientA, id, "csmode_c_tunnel_close", content) 369 | } else { 370 | println("no session") 371 | } 372 | }, func() { 373 | }) 374 | } 375 | } 376 | 377 | var err error 378 | var g_Master net.Listener 379 | 380 | func main() { 381 | flag.Parse() 382 | if *bShowVersion { 383 | fmt.Printf("%.2f\n", common.Version) 384 | return 385 | } 386 | common.Conn2ClientInfo = make(map[net.Conn]*common.ClientInfo) 387 | common.ServerName2Conn = make(map[string]net.Conn) 388 | common.Conn2Admin = make(map[net.Conn]*common.AdminInfo) 389 | listener, err := net.Listen("tcp", *listenAddr) 390 | if err != nil { 391 | log.Println("cannot listen addr:" + err.Error()) 392 | return 393 | } 394 | if *bUseSSL { 395 | config := &tls.Config{} 396 | config.Certificates = make([]tls.Certificate, 1) 397 | config.Certificates[0], err = tls.LoadX509KeyPair(*certFile, *keyFile) 398 | if err != nil { 399 | log.Println("load key file error", err.Error()) 400 | return 401 | } 402 | g_Master = tls.NewListener(listener, config) 403 | } else { 404 | g_Master = listener 405 | } 406 | go func() { 407 | for { 408 | conn, err := g_Master.Accept() 409 | if err != nil { 410 | continue 411 | } 412 | go handleClient(conn) 413 | } 414 | }() 415 | 416 | udpaddr, err := net.ResolveUDPAddr("udp", *listenAddrUDP) 417 | if err != nil { 418 | log.Println("Can't resolve address: ", err) 419 | return 420 | } 421 | 422 | udpconn, err := net.ListenUDP("udp", udpaddr) 423 | if err != nil { 424 | log.Println("Error UDP listening:", err) 425 | return 426 | } 427 | 428 | log.Println("listenAdd: ", *listenAddrUDP) 429 | 430 | defer udpconn.Close() 431 | 432 | go udphandleClient(udpconn) 433 | if *db_host != "" { 434 | err = auth.Init(*db_user, *db_pass, *db_host) 435 | if err != nil { 436 | log.Println("mysql client fail", err.Error()) 437 | return 438 | } 439 | defer auth.DeInit() 440 | bUseDB = true 441 | } 442 | log.Println("master start success") 443 | if *adminAddr != "" { 444 | cert, key := "", "" 445 | if *bUseHttps { 446 | cert, key = *certFile, *keyFile 447 | } 448 | err := admin.InitAdminPort(*adminAddr, cert, key) 449 | if err != nil { 450 | log.Println("admin service start fail", err.Error()) 451 | return 452 | } 453 | log.Println("admin service start success") 454 | } 455 | c := make(chan os.Signal, 1) 456 | signal.Notify(c, os.Interrupt, syscall.SIGTERM) 457 | <-c 458 | log.Println("received signal,shutdown") 459 | shutdown() 460 | } 461 | 462 | func shutdown() { 463 | for conn, client := range common.Conn2ClientInfo { 464 | if !client.IsServer { 465 | log.Println("shutdown client", client.ServerName) 466 | common.Write(conn, "0", "showandquit", "server shutdown") 467 | } else { 468 | log.Println("unregister service Name", client.ServerName) 469 | if bUseDB { 470 | user, _ := auth.GetUser(client.UserName) 471 | if user != nil { 472 | user.OnLogout() 473 | } 474 | } 475 | //donnot showandquit,because client_server need to reconnect 476 | } 477 | } 478 | } 479 | -------------------------------------------------------------------------------- /ikcp/ikcp.go: -------------------------------------------------------------------------------- 1 | package ikcp 2 | 3 | import "container/list" 4 | import "encoding/binary" 5 | import _ "fmt" 6 | 7 | //===================================================================== 8 | // 9 | // KCP - A Better ARQ Protocol Implementation 10 | // skywind3000 (at) gmail.com, 2010-2011 11 | // 12 | // Features: 13 | // + Average RTT reduce 30% - 40% vs traditional ARQ like tcp. 14 | // + Maximum RTT reduce three times vs tcp. 15 | // + Lightweight, distributed as a single source file. 16 | // 17 | //===================================================================== 18 | 19 | //===================================================================== 20 | // KCP BASIC 21 | //===================================================================== 22 | const IKCP_RTO_NDL uint32 = 30 // no delay min rto 23 | const IKCP_RTO_MIN uint32 = 100 // normal min rto 24 | const IKCP_RTO_DEF uint32 = 200 25 | const IKCP_RTO_MAX uint32 = 60000 26 | const IKCP_CMD_PUSH uint32 = 81 // cmd: push data 27 | const IKCP_CMD_ACK uint32 = 82 // cmd: ack 28 | const IKCP_CMD_WASK uint32 = 83 // cmd: window probe (ask) 29 | const IKCP_CMD_WINS uint32 = 84 // cmd: window size (tell) 30 | const IKCP_ASK_SEND uint32 = 1 // need to send IKCP_CMD_WASK 31 | const IKCP_ASK_TELL uint32 = 2 // need to send IKCP_CMD_WINS 32 | const IKCP_WND_SND uint32 = 32 33 | const IKCP_WND_RCV uint32 = 32 34 | const IKCP_MTU_DEF uint32 = 1400 35 | const IKCP_ACK_FAST uint32 = 3 36 | const IKCP_INTERVAL uint32 = 100 37 | const IKCP_OVERHEAD uint32 = 24 38 | const IKCP_DEADLINK uint32 = 10 39 | const IKCP_THRESH_INIT uint32 = 2 40 | const IKCP_THRESH_MIN uint32 = 2 41 | const IKCP_PROBE_INIT uint32 = 7000 // 7 secs to probe window size 42 | const IKCP_PROBE_LIMIT uint32 = 120000 // up to 120 secs to probe window 43 | 44 | //--------------------------------------------------------------------- 45 | // encode / decode 46 | //--------------------------------------------------------------------- 47 | 48 | /* encode 8 bits unsigned int */ 49 | func ikcp_encode8u(p []byte, c byte) []byte { 50 | p[0] = c 51 | return p[1:] 52 | } 53 | 54 | /* decode 8 bits unsigned int */ 55 | func ikcp_decode8u(p []byte, c *byte) []byte { 56 | *c = p[0] 57 | return p[1:] 58 | } 59 | 60 | /* encode 16 bits unsigned int (lsb) */ 61 | func ikcp_encode16u(p []byte, w uint16) []byte { 62 | binary.LittleEndian.PutUint16(p, w) 63 | return p[2:] 64 | } 65 | 66 | /* decode 16 bits unsigned int (lsb) */ 67 | func ikcp_decode16u(p []byte, w *uint16) []byte { 68 | *w = binary.LittleEndian.Uint16(p) 69 | return p[2:] 70 | } 71 | 72 | /* encode 32 bits unsigned int (lsb) */ 73 | func ikcp_encode32u(p []byte, l uint32) []byte { 74 | binary.LittleEndian.PutUint32(p, l) 75 | return p[4:] 76 | } 77 | 78 | /* decode 32 bits unsigned int (lsb) */ 79 | func ikcp_decode32u(p []byte, l *uint32) []byte { 80 | *l = binary.LittleEndian.Uint32(p) 81 | return p[4:] 82 | } 83 | 84 | func _imin_(a, b uint32) uint32 { 85 | if a <= b { 86 | return a 87 | } else { 88 | return b 89 | } 90 | } 91 | 92 | func _imax_(a, b uint32) uint32 { 93 | if a >= b { 94 | return a 95 | } else { 96 | return b 97 | } 98 | } 99 | 100 | func _ibound_(lower, middle, upper uint32) uint32 { 101 | return _imin_(_imax_(lower, middle), upper) 102 | } 103 | 104 | func _itimediff(later, earlier uint32) int32 { 105 | return ((int32)(later - earlier)) 106 | } 107 | 108 | //--------------------------------------------------------------------- 109 | // manage segment 110 | //--------------------------------------------------------------------- 111 | type IKCPSEG struct { 112 | conv uint32 113 | cmd uint32 114 | frg uint32 115 | wnd uint32 116 | ts uint32 117 | sn uint32 118 | una uint32 119 | _len uint32 120 | resendts uint32 121 | rto uint32 122 | fastack uint32 123 | xmit uint32 124 | data []byte //1 size 125 | } 126 | 127 | /* 128 | static void* (*ikcp_malloc_hook)(size_t) = nil 129 | static void (*ikcp_free_hook)(void *) = nil 130 | 131 | // internal malloc 132 | static void* ikcp_malloc(size_t size) { 133 | if (ikcp_malloc_hook) 134 | return ikcp_malloc_hook(size) 135 | return malloc(size) 136 | } 137 | 138 | // internal free 139 | static void ikcp_free(void *ptr) { 140 | if (ikcp_free_hook) { 141 | ikcp_free_hook(ptr) 142 | } else { 143 | free(ptr) 144 | } 145 | } 146 | // redefine allocator 147 | void ikcp_allocator(void* (*new_malloc)(size_t), void (*new_free)(void*)) 148 | { 149 | ikcp_malloc_hook = new_malloc 150 | ikcp_free_hook = new_free 151 | } 152 | 153 | // allocate a new kcp segment 154 | */ 155 | func ikcp_segment_new(kcp *Ikcpcb, size int32) *IKCPSEG { 156 | newInfo := &IKCPSEG{} 157 | newInfo.data = make([]byte, size) 158 | return newInfo 159 | } 160 | 161 | // delete a segment 162 | 163 | // write log 164 | func Ikcp_log(kcp *Ikcpcb, mask int32, head string, args ...interface{}) { 165 | //if ((mask & kcp.logmask) == 0 || kcp.writelog == 0) { return } 166 | //fmt.Printf(head, args...) 167 | } 168 | 169 | // check log mask 170 | func ikcp_canlog(kcp *Ikcpcb, mask int32) int32 { 171 | if (mask&kcp.logmask) == 0 || kcp.writelog == nil { 172 | return 0 173 | } 174 | return 1 175 | } 176 | 177 | // output segment 178 | func ikcp_output(kcp *Ikcpcb, data []byte, size int32) int32 { 179 | if ikcp_canlog(kcp, IKCP_LOG_OUTPUT) != 0 { 180 | Ikcp_log(kcp, IKCP_LOG_OUTPUT, "[RO] %ld bytes", int32(size)) 181 | } 182 | if size == 0 { 183 | return 0 184 | } 185 | return kcp.Output(data, size, kcp, kcp.user) 186 | } 187 | 188 | //--------------------------------------------------------------------- 189 | // create a new kcpcb 190 | //--------------------------------------------------------------------- 191 | func Ikcp_create(conv uint32, user interface{}) *Ikcpcb { 192 | kcp := &Ikcpcb{} 193 | kcp.conv = conv 194 | kcp.user = user 195 | kcp.snd_una = 0 196 | kcp.snd_nxt = 0 197 | kcp.rcv_nxt = 0 198 | kcp.ts_recent = 0 199 | kcp.ts_lastack = 0 200 | kcp.ts_probe = 0 201 | kcp.probe_wait = 0 202 | kcp.snd_wnd = IKCP_WND_SND 203 | kcp.rcv_wnd = IKCP_WND_RCV 204 | kcp.rmt_wnd = IKCP_WND_RCV 205 | kcp.cwnd = 0 206 | kcp.incr = 0 207 | kcp.probe = 0 208 | kcp.mtu = IKCP_MTU_DEF 209 | kcp.mss = kcp.mtu - IKCP_OVERHEAD 210 | 211 | kcp.buffer = make([]byte, (kcp.mtu+IKCP_OVERHEAD)*3) 212 | if kcp.buffer == nil { 213 | return nil 214 | } 215 | 216 | kcp.snd_queue = list.New() 217 | kcp.rcv_queue = list.New() 218 | kcp.snd_buf = list.New() 219 | kcp.rcv_buf = list.New() 220 | kcp.nrcv_buf = 0 221 | kcp.nsnd_buf = 0 222 | kcp.nrcv_que = 0 223 | kcp.nsnd_que = 0 224 | kcp.state = 0 225 | kcp.acklist = nil 226 | kcp.ackblock = 0 227 | kcp.ackcount = 0 228 | kcp.rx_srtt = 0 229 | kcp.rx_rttval = 0 230 | kcp.rx_rto = IKCP_RTO_DEF 231 | kcp.rx_minrto = IKCP_RTO_MIN 232 | kcp.current = 0 233 | kcp.interval = IKCP_INTERVAL 234 | kcp.ts_flush = IKCP_INTERVAL 235 | kcp.nodelay = 0 236 | kcp.updated = 0 237 | kcp.logmask = 0 238 | kcp.ssthresh = IKCP_THRESH_INIT 239 | kcp.fastresend = 0 240 | kcp.nocwnd = 0 241 | kcp.xmit = 0 242 | kcp.dead_link = IKCP_DEADLINK 243 | kcp.Output = nil 244 | kcp.writelog = nil 245 | 246 | return kcp 247 | } 248 | 249 | //--------------------------------------------------------------------- 250 | // release a new kcpcb 251 | //--------------------------------------------------------------------- 252 | func Ikcp_release(kcp *Ikcpcb) { 253 | if kcp != nil { 254 | kcp.nrcv_buf = 0 255 | kcp.nsnd_buf = 0 256 | kcp.nrcv_que = 0 257 | kcp.nsnd_que = 0 258 | kcp.ackcount = 0 259 | kcp.buffer = nil 260 | kcp.acklist = nil 261 | } 262 | } 263 | 264 | //--------------------------------------------------------------------- 265 | // recv data 266 | //--------------------------------------------------------------------- 267 | func Ikcp_recv(kcp *Ikcpcb, buffer []byte, _len int32) int32 { 268 | ispeek := 1 269 | if _len >= 0 { 270 | ispeek = 0 271 | } 272 | var peeksize int32 273 | _recover := 0 274 | var seg *IKCPSEG 275 | 276 | if kcp.rcv_queue.Len() == 0 { 277 | return -1 278 | } 279 | 280 | if _len < 0 { 281 | _len = -_len 282 | } 283 | 284 | peeksize = Ikcp_peeksize(kcp) 285 | 286 | if peeksize < 0 { 287 | return -2 288 | } 289 | 290 | if peeksize > _len { 291 | return -3 292 | } 293 | 294 | if kcp.nrcv_que >= kcp.rcv_wnd { 295 | _recover = 1 296 | } 297 | 298 | //if kcp.user[0] == 0 { 299 | //fmt.Println("have!!!!") 300 | //} 301 | // merge fragment 302 | _len = 0 303 | for p := kcp.rcv_queue.Front(); p != nil; { 304 | var fragment int32 305 | seg = p.Value.(*IKCPSEG) 306 | 307 | if len(buffer) > 0 { 308 | copy(buffer, seg.data[:seg._len]) 309 | buffer = buffer[seg._len:] 310 | } 311 | 312 | _len += int32(seg._len) 313 | fragment = int32(seg.frg) 314 | 315 | if ikcp_canlog(kcp, IKCP_LOG_RECV) != 0 { 316 | Ikcp_log(kcp, IKCP_LOG_RECV, "recv sn=", seg.sn, seg._len, kcp.user) 317 | } 318 | 319 | if ispeek == 0 { 320 | q := p.Next() 321 | kcp.rcv_queue.Remove(p) 322 | p = q 323 | kcp.nrcv_que-- 324 | //if kcp.user[0] == 0 { 325 | //fmt.Println("remove from recvqueue", kcp.rcv_queue.Len(), kcp.user, "rcv q:", kcp.nrcv_que) 326 | //} 327 | } else { 328 | p = p.Next() 329 | } 330 | 331 | if fragment == 0 { 332 | break 333 | } 334 | } 335 | // move available data from rcv_buf . rcv_queue 336 | for p := kcp.rcv_buf.Front(); p != nil; { 337 | seg := p.Value.(*IKCPSEG) 338 | if seg.sn == kcp.rcv_nxt && kcp.nrcv_que < kcp.rcv_wnd { 339 | q := p.Next() 340 | kcp.rcv_buf.Remove(p) 341 | p = q 342 | kcp.nrcv_buf-- 343 | kcp.rcv_queue.PushBack(seg) 344 | kcp.nrcv_que++ 345 | //if kcp.user[0] == 0 { 346 | //fmt.Println("insert from recvqueue", kcp.rcv_queue.Len(), kcp.user, "rcv q:", kcp.nrcv_que) 347 | //} 348 | kcp.rcv_nxt++ 349 | } else { 350 | break 351 | } 352 | } 353 | 354 | // fast _recover 355 | if kcp.nrcv_que < kcp.rcv_wnd && _recover != 0 { 356 | // ready to send back IKCP_CMD_WINS in Ikcp_flush 357 | // tell remote my window size 358 | kcp.probe |= IKCP_ASK_TELL 359 | } 360 | 361 | return _len 362 | } 363 | 364 | //--------------------------------------------------------------------- 365 | // send data 366 | //--------------------------------------------------------------------- 367 | func Ikcp_peeksize(kcp *Ikcpcb) int32 { 368 | length := 0 369 | 370 | if kcp.rcv_queue.Len() == 0 { 371 | return -1 372 | } 373 | 374 | seg := kcp.rcv_queue.Front().Value.(*IKCPSEG) 375 | if seg.frg == 0 { 376 | return int32(seg._len) 377 | } 378 | 379 | if kcp.nrcv_que < seg.frg+1 { 380 | return -1 381 | } 382 | 383 | for p := kcp.rcv_queue.Front(); p != nil; p = p.Next() { 384 | seg = p.Value.(*IKCPSEG) 385 | length += int(seg._len) 386 | if seg.frg == 0 { 387 | break 388 | } 389 | } 390 | 391 | return int32(length) 392 | } 393 | 394 | //--------------------------------------------------------------------- 395 | // send data 396 | //--------------------------------------------------------------------- 397 | func Ikcp_send(kcp *Ikcpcb, buffer []byte, _len int) int { 398 | var seg *IKCPSEG 399 | var count, i int32 400 | 401 | if _len < 0 { 402 | return -1 403 | } 404 | 405 | if _len <= int(kcp.mss) { 406 | count = 1 407 | } else { 408 | count = (int32(_len) + int32(kcp.mss) - 1) / int32(kcp.mss) 409 | } 410 | 411 | if count > 255 { 412 | return -2 413 | } 414 | 415 | if count == 0 { 416 | count = 1 417 | } 418 | 419 | // fragment 420 | for i = 0; i < count; i++ { 421 | size := int32(kcp.mss) 422 | if _len <= int(kcp.mss) { 423 | size = int32(_len) 424 | } 425 | seg = ikcp_segment_new(kcp, size) 426 | if seg == nil { 427 | return -2 428 | } 429 | if buffer != nil && _len > 0 { 430 | copy(seg.data, buffer[:size]) 431 | } 432 | seg._len = uint32(size) 433 | seg.frg = uint32(count - i - 1) 434 | kcp.snd_queue.PushBack(seg) 435 | //if kcp.user[0] == 0 { 436 | //fmt.Println(kcp.user, "send", kcp.snd_queue.Len()) 437 | //} 438 | kcp.nsnd_que++ 439 | if buffer != nil { 440 | buffer = buffer[size:] 441 | } 442 | _len -= int(size) 443 | } 444 | 445 | return 0 446 | } 447 | 448 | //--------------------------------------------------------------------- 449 | // parse ack 450 | //--------------------------------------------------------------------- 451 | func Ikcp_update_ack(kcp *Ikcpcb, rtt int32) { 452 | rto := 0 453 | if kcp.rx_srtt == 0 { 454 | kcp.rx_srtt = uint32(rtt) 455 | kcp.rx_rttval = uint32(rtt) / 2 456 | } else { 457 | delta := rtt - int32(kcp.rx_srtt) 458 | if delta < 0 { 459 | delta = -delta 460 | } 461 | kcp.rx_rttval = (3*kcp.rx_rttval + uint32(delta)) / 4 462 | kcp.rx_srtt = (7*kcp.rx_srtt + uint32(rtt)) / 8 463 | if kcp.rx_srtt < 1 { 464 | kcp.rx_srtt = 1 465 | } 466 | } 467 | rto = int(kcp.rx_srtt + _imax_(1, 4*kcp.rx_rttval)) 468 | kcp.rx_rto = _ibound_(kcp.rx_minrto, uint32(rto), IKCP_RTO_MAX) 469 | } 470 | 471 | func ikcp_shrink_buf(kcp *Ikcpcb) { 472 | if kcp.snd_buf.Len() > 0 { 473 | p := kcp.snd_buf.Front() 474 | seg := p.Value.(*IKCPSEG) 475 | kcp.snd_una = seg.sn 476 | //if kcp.user[0] == 0 { 477 | //println("set snd_una:", seg.sn) 478 | //} 479 | } else { 480 | kcp.snd_una = kcp.snd_nxt 481 | //if kcp.user[0] == 0 { 482 | //println("set2 snd_una:", kcp.snd_nxt) 483 | //} 484 | } 485 | } 486 | 487 | func ikcp_parse_ack(kcp *Ikcpcb, sn uint32) { 488 | if _itimediff(sn, kcp.snd_una) < 0 || _itimediff(sn, kcp.snd_nxt) >= 0 { 489 | // //fmt.Printf("wi %d,%d %d,%d\n", sn, kcp.snd_una, sn, kcp.snd_nxt) 490 | return 491 | } 492 | 493 | for p := kcp.snd_buf.Front(); p != nil; p = p.Next() { 494 | seg := p.Value.(*IKCPSEG) 495 | if sn == seg.sn { 496 | // //println("!!!!!!!") 497 | kcp.snd_buf.Remove(p) 498 | kcp.nsnd_buf-- 499 | break 500 | } else { 501 | seg.fastack++ 502 | } 503 | } 504 | } 505 | 506 | func ikcp_parse_una(kcp *Ikcpcb, una uint32) { 507 | for p := kcp.snd_buf.Front(); p != nil; { 508 | seg := p.Value.(*IKCPSEG) 509 | if _itimediff(una, seg.sn) > 0 { 510 | q := p.Next() 511 | kcp.snd_buf.Remove(p) 512 | p = q 513 | kcp.nsnd_buf-- 514 | } else { 515 | break 516 | } 517 | } 518 | } 519 | 520 | //--------------------------------------------------------------------- 521 | // ack append 522 | //--------------------------------------------------------------------- 523 | func ikcp_ack_push(kcp *Ikcpcb, sn, ts uint32) { 524 | newsize := kcp.ackcount + 1 525 | 526 | if newsize > kcp.ackblock { 527 | var acklist []uint32 528 | var newblock int32 529 | 530 | for newblock = 8; uint32(newblock) < newsize; newblock <<= 1 { 531 | } 532 | acklist = make([]uint32, newblock*2) 533 | if kcp.acklist != nil { 534 | for x := 0; uint32(x) < kcp.ackcount; x++ { 535 | acklist[x*2+0] = kcp.acklist[x*2+0] 536 | acklist[x*2+1] = kcp.acklist[x*2+1] 537 | } 538 | } 539 | kcp.acklist = acklist 540 | kcp.ackblock = uint32(newblock) 541 | } 542 | 543 | ptr := kcp.acklist[kcp.ackcount*2:] 544 | ptr[0] = sn 545 | ptr[1] = ts 546 | kcp.ackcount++ 547 | } 548 | 549 | func ikcp_ack_get(kcp *Ikcpcb, p int32, sn, ts *uint32) { 550 | if sn != nil { 551 | *sn = kcp.acklist[p*2+0] 552 | } 553 | if ts != nil { 554 | *ts = kcp.acklist[p*2+1] 555 | } 556 | } 557 | 558 | //--------------------------------------------------------------------- 559 | // parse data 560 | //--------------------------------------------------------------------- 561 | func ikcp_parse_data(kcp *Ikcpcb, newseg *IKCPSEG) { 562 | var p *list.Element 563 | sn := newseg.sn 564 | repeat := 0 565 | if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) >= 0 || 566 | _itimediff(sn, kcp.rcv_nxt) < 0 { 567 | return 568 | } 569 | 570 | for p = kcp.rcv_buf.Back(); p != nil; p = p.Prev() { 571 | seg := p.Value.(*IKCPSEG) 572 | if seg.sn == sn { 573 | repeat = 1 574 | break 575 | } 576 | if _itimediff(sn, seg.sn) > 0 { 577 | break 578 | } 579 | } 580 | 581 | if repeat == 0 { 582 | if p == nil { 583 | kcp.rcv_buf.PushFront(newseg) 584 | } else { 585 | kcp.rcv_buf.InsertAfter(newseg, p) 586 | } 587 | kcp.nrcv_buf++ 588 | } else { 589 | } 590 | for p = kcp.rcv_buf.Front(); p != nil; { 591 | seg := p.Value.(*IKCPSEG) 592 | if seg.sn == kcp.rcv_nxt && kcp.nrcv_que < kcp.rcv_wnd { 593 | q := p.Next() 594 | kcp.rcv_buf.Remove(p) 595 | p = q 596 | kcp.nrcv_buf-- 597 | kcp.rcv_queue.PushBack(seg) 598 | //if kcp.user[0] == 0 { 599 | //fmt.Println("insert from recvqueue2", kcp.rcv_queue.Len(), kcp.user) 600 | //} 601 | kcp.nrcv_que++ 602 | kcp.rcv_nxt++ 603 | } else { 604 | break 605 | } 606 | } 607 | ////println("inputok!!!", kcp.nrcv_buf, kcp.nrcv_que) 608 | } 609 | 610 | //--------------------------------------------------------------------- 611 | // input data 612 | //--------------------------------------------------------------------- 613 | func Ikcp_input(kcp *Ikcpcb, data []byte, size int) int { 614 | una := kcp.snd_una 615 | if ikcp_canlog(kcp, IKCP_LOG_INPUT) != 0 { 616 | Ikcp_log(kcp, IKCP_LOG_INPUT, "[RI] %d bytes", size) 617 | } 618 | 619 | if data == nil || size < 24 { 620 | return 0 621 | } 622 | 623 | for { 624 | var ts, sn, _len, una, conv uint32 625 | var wnd uint16 626 | var cmd, frg uint8 627 | var seg *IKCPSEG 628 | 629 | if size < int(IKCP_OVERHEAD) { 630 | break 631 | } 632 | 633 | data = ikcp_decode32u(data, &conv) 634 | if conv != kcp.conv { 635 | return -1 636 | } 637 | 638 | data = ikcp_decode8u(data, &cmd) 639 | data = ikcp_decode8u(data, &frg) 640 | data = ikcp_decode16u(data, &wnd) 641 | data = ikcp_decode32u(data, &ts) 642 | data = ikcp_decode32u(data, &sn) 643 | data = ikcp_decode32u(data, &una) 644 | data = ikcp_decode32u(data, &_len) 645 | 646 | size -= int(IKCP_OVERHEAD) 647 | 648 | if uint32(size) < uint32(_len) { 649 | return -2 650 | } 651 | 652 | if cmd != uint8(IKCP_CMD_PUSH) && cmd != uint8(IKCP_CMD_ACK) && 653 | cmd != uint8(IKCP_CMD_WASK) && cmd != uint8(IKCP_CMD_WINS) { 654 | return -3 655 | } 656 | 657 | kcp.rmt_wnd = uint32(wnd) 658 | ikcp_parse_una(kcp, una) 659 | ikcp_shrink_buf(kcp) 660 | 661 | if cmd == uint8(IKCP_CMD_ACK) { 662 | if _itimediff(kcp.current, ts) >= 0 { 663 | Ikcp_update_ack(kcp, _itimediff(kcp.current, ts)) 664 | } 665 | ikcp_parse_ack(kcp, sn) 666 | ikcp_shrink_buf(kcp) 667 | if ikcp_canlog(kcp, IKCP_LOG_IN_ACK) != 0 { 668 | Ikcp_log(kcp, IKCP_LOG_IN_DATA, 669 | "input ack: sn=%lu rtt=%ld rto=%ld", sn, 670 | uint32(_itimediff(kcp.current, ts)), 671 | uint32(kcp.rx_rto)) 672 | } 673 | } else if cmd == uint8(IKCP_CMD_PUSH) { 674 | if ikcp_canlog(kcp, IKCP_LOG_IN_DATA) != 0 { 675 | Ikcp_log(kcp, IKCP_LOG_IN_DATA, 676 | "input psh: sn=%lu ts=%lu", sn, ts) 677 | } 678 | if _itimediff(sn, kcp.rcv_nxt+kcp.rcv_wnd) < 0 { 679 | ikcp_ack_push(kcp, sn, ts) 680 | if _itimediff(sn, kcp.rcv_nxt) >= 0 { 681 | seg = ikcp_segment_new(kcp, int32(_len)) 682 | seg.conv = conv 683 | seg.cmd = uint32(cmd) 684 | seg.frg = uint32(frg) 685 | seg.wnd = uint32(wnd) 686 | seg.ts = ts 687 | seg.sn = sn 688 | seg.una = una 689 | seg._len = _len 690 | 691 | if _len > 0 { 692 | copy(seg.data, data[:_len]) 693 | } 694 | 695 | ikcp_parse_data(kcp, seg) 696 | } 697 | } 698 | } else if cmd == uint8(IKCP_CMD_WASK) { 699 | // ready to send back IKCP_CMD_WINS in Ikcp_flush 700 | // tell remote my window size 701 | kcp.probe |= IKCP_ASK_TELL 702 | if ikcp_canlog(kcp, IKCP_LOG_IN_PROBE) != 0 { 703 | Ikcp_log(kcp, IKCP_LOG_IN_PROBE, "input probe") 704 | } 705 | } else if cmd == uint8(IKCP_CMD_WINS) { 706 | // do nothing 707 | if ikcp_canlog(kcp, IKCP_LOG_IN_WIN) != 0 { 708 | Ikcp_log(kcp, IKCP_LOG_IN_WIN, 709 | "input wins: %lu", uint32(wnd)) 710 | } 711 | } else { 712 | return -3 713 | } 714 | 715 | data = data[_len:] 716 | size -= int(_len) 717 | } 718 | 719 | if _itimediff(kcp.snd_una, una) > 0 { 720 | if kcp.cwnd < kcp.rmt_wnd { 721 | mss := kcp.mss 722 | if kcp.cwnd < kcp.ssthresh { 723 | kcp.cwnd++ 724 | kcp.incr += mss 725 | } else { 726 | if kcp.incr < mss { 727 | kcp.incr = mss 728 | } 729 | kcp.incr += (mss*mss)/kcp.incr + (mss / 16) 730 | if (kcp.cwnd+1)*mss <= kcp.incr { 731 | kcp.cwnd++ 732 | } 733 | } 734 | if kcp.cwnd > kcp.rmt_wnd { 735 | kcp.cwnd = kcp.rmt_wnd 736 | kcp.incr = kcp.rmt_wnd * mss 737 | } 738 | } 739 | } 740 | 741 | return 0 742 | } 743 | 744 | //--------------------------------------------------------------------- 745 | // ikcp_encode_seg 746 | //--------------------------------------------------------------------- 747 | func ikcp_encode_seg(ptr []byte, seg *IKCPSEG) []byte { 748 | ptr = ikcp_encode32u(ptr, seg.conv) 749 | ptr = ikcp_encode8u(ptr, uint8(seg.cmd)) 750 | ptr = ikcp_encode8u(ptr, uint8(seg.frg)) 751 | ptr = ikcp_encode16u(ptr, uint16(seg.wnd)) 752 | ptr = ikcp_encode32u(ptr, seg.ts) 753 | ptr = ikcp_encode32u(ptr, seg.sn) 754 | ptr = ikcp_encode32u(ptr, seg.una) 755 | ptr = ikcp_encode32u(ptr, seg._len) 756 | return ptr 757 | } 758 | 759 | func ikcp_wnd_unused(kcp *Ikcpcb) int32 { 760 | if kcp.nrcv_que < kcp.rcv_wnd { 761 | return int32(kcp.rcv_wnd - kcp.nrcv_que) 762 | } 763 | return 0 764 | } 765 | 766 | //--------------------------------------------------------------------- 767 | // Ikcp_flush 768 | //--------------------------------------------------------------------- 769 | func Ikcp_flush(kcp *Ikcpcb) { 770 | current := kcp.current 771 | buffer := kcp.buffer 772 | ptr := buffer 773 | var count, size, i int32 774 | var resent, cwnd uint32 775 | var rtomin uint32 776 | change := 0 777 | lost := 0 778 | var seg IKCPSEG 779 | 780 | // 'Ikcp_update' haven't been called. 781 | if kcp.updated == 0 { 782 | return 783 | } 784 | 785 | seg.conv = kcp.conv 786 | seg.cmd = IKCP_CMD_ACK 787 | seg.frg = 0 788 | seg.wnd = uint32(ikcp_wnd_unused(kcp)) 789 | seg.una = kcp.rcv_nxt 790 | seg._len = 0 791 | seg.sn = 0 792 | seg.ts = 0 793 | 794 | // flush acknowledges 795 | size = 0 796 | count = int32(kcp.ackcount) 797 | for i = 0; i < count; i++ { 798 | //size = int32(ptr - buffer) 799 | if size > int32(kcp.mtu) { 800 | ikcp_output(kcp, buffer, size) 801 | ptr = buffer 802 | size = 0 803 | } 804 | ikcp_ack_get(kcp, i, &seg.sn, &seg.ts) 805 | ptr = ikcp_encode_seg(ptr, &seg) 806 | size += 24 807 | } 808 | 809 | kcp.ackcount = 0 810 | 811 | // probe window size (if remote window size equals zero) 812 | if kcp.rmt_wnd == 0 { 813 | if kcp.probe_wait == 0 { 814 | kcp.probe_wait = IKCP_PROBE_INIT 815 | kcp.ts_probe = kcp.current + kcp.probe_wait 816 | } else { 817 | if _itimediff(kcp.current, kcp.ts_probe) >= 0 { 818 | if kcp.probe_wait < IKCP_PROBE_INIT { 819 | kcp.probe_wait = IKCP_PROBE_INIT 820 | } 821 | kcp.probe_wait += kcp.probe_wait / 2 822 | if kcp.probe_wait > IKCP_PROBE_LIMIT { 823 | kcp.probe_wait = IKCP_PROBE_LIMIT 824 | } 825 | kcp.ts_probe = kcp.current + kcp.probe_wait 826 | kcp.probe |= IKCP_ASK_SEND 827 | } 828 | } 829 | } else { 830 | kcp.ts_probe = 0 831 | kcp.probe_wait = 0 832 | } 833 | 834 | // flush window probing commands 835 | if (kcp.probe & IKCP_ASK_SEND) != 0 { 836 | seg.cmd = IKCP_CMD_WASK 837 | if size > int32(kcp.mtu) { 838 | ikcp_output(kcp, buffer, size) 839 | ptr = buffer 840 | size = 0 841 | } 842 | ptr = ikcp_encode_seg(ptr, &seg) 843 | size += 24 844 | } 845 | 846 | // flush window probing commands 847 | if (kcp.probe & IKCP_ASK_TELL) != 0 { 848 | seg.cmd = IKCP_CMD_WINS 849 | if size > int32(kcp.mtu) { 850 | ikcp_output(kcp, buffer, size) 851 | ptr = buffer 852 | size = 0 853 | } 854 | ptr = ikcp_encode_seg(ptr, &seg) 855 | size += 24 856 | } 857 | 858 | kcp.probe = 0 859 | 860 | // calculate window size 861 | cwnd = _imin_(kcp.snd_wnd, kcp.rmt_wnd) 862 | if kcp.nocwnd == 0 { 863 | cwnd = _imin_(kcp.cwnd, cwnd) 864 | } 865 | 866 | // move data from snd_queue to snd_buf 867 | ////println("check",kcp.snd_queue.Len()) 868 | t := 0 869 | for p := kcp.snd_queue.Front(); p != nil; { 870 | ////println("debug check:", t, p.Next(), kcp.snd_nxt, kcp.snd_una, cwnd, _itimediff(kcp.snd_nxt, kcp.snd_una + cwnd)) 871 | ////fmt.Printf("timediff %d,%d,%d,%d\n", kcp.snd_nxt, kcp.snd_una, cwnd, _itimediff(kcp.snd_nxt, kcp.snd_una + cwnd)); 872 | t++ 873 | if _itimediff(kcp.snd_nxt, kcp.snd_una+cwnd) >= 0 { 874 | //if kcp.user[0] == 0 { 875 | ////fmt.Println("=======", kcp.snd_nxt, kcp.snd_una, cwnd) 876 | //} 877 | break 878 | } 879 | newseg := p.Value.(*IKCPSEG) 880 | q := p.Next() 881 | kcp.snd_queue.Remove(p) 882 | p = q 883 | kcp.snd_buf.PushBack(newseg) 884 | //if kcp.user[0] == 0 { 885 | //println("debug check2:", t, kcp.snd_queue.Len(), kcp.snd_buf.Len(), kcp.nsnd_que) 886 | //} 887 | kcp.nsnd_que-- 888 | kcp.nsnd_buf++ 889 | 890 | newseg.conv = kcp.conv 891 | newseg.cmd = IKCP_CMD_PUSH 892 | newseg.wnd = seg.wnd 893 | newseg.ts = current 894 | newseg.sn = kcp.snd_nxt 895 | kcp.snd_nxt++ 896 | newseg.una = kcp.rcv_nxt 897 | newseg.resendts = current 898 | newseg.rto = kcp.rx_rto 899 | newseg.fastack = 0 900 | newseg.xmit = 0 901 | } 902 | 903 | // calculate resent 904 | resent = uint32(kcp.fastresend) 905 | if kcp.fastresend <= 0 { 906 | resent = 0xffffffff 907 | } 908 | rtomin = (kcp.rx_rto >> 3) 909 | if kcp.nodelay != 0 { 910 | rtomin = 0 911 | } 912 | 913 | a := 0 914 | // flush data segments 915 | for p := kcp.snd_buf.Front(); p != nil; p = p.Next() { 916 | ////println("debug loop", a, kcp.snd_buf.Len()) 917 | a++ 918 | segment := p.Value.(*IKCPSEG) 919 | needsend := 0 920 | if segment.xmit == 0 { 921 | needsend = 1 922 | segment.xmit++ 923 | segment.rto = kcp.rx_rto 924 | segment.resendts = current + segment.rto + rtomin 925 | } else if _itimediff(current, segment.resendts) >= 0 { 926 | needsend = 1 927 | segment.xmit++ 928 | kcp.xmit++ 929 | if kcp.nodelay == 0 { 930 | segment.rto += kcp.rx_rto 931 | } else { 932 | segment.rto += kcp.rx_rto / 2 933 | } 934 | segment.resendts = current + segment.rto 935 | lost = 1 936 | } else if segment.fastack >= resent { 937 | needsend = 1 938 | segment.xmit++ 939 | segment.fastack = 0 940 | segment.resendts = current + segment.rto 941 | change++ 942 | } 943 | if needsend != 0 { 944 | var need int32 945 | segment.ts = current 946 | segment.wnd = seg.wnd 947 | segment.una = kcp.rcv_nxt 948 | 949 | need = int32(IKCP_OVERHEAD + segment._len) 950 | 951 | ////fmt.Printf("vzex:need send%d, %d,%d,%d\n", kcp.nsnd_buf, size, need, kcp.mtu) 952 | if size+need >= int32(kcp.mtu) { 953 | // //fmt.Printf("trigger!\n"); 954 | ikcp_output(kcp, buffer, size) 955 | ptr = buffer 956 | size = 0 957 | } 958 | 959 | ptr = ikcp_encode_seg(ptr, segment) 960 | size += 24 961 | 962 | if segment._len > 0 { 963 | copy(ptr, segment.data[:segment._len]) 964 | ptr = ptr[segment._len:] 965 | size += int32(segment._len) 966 | } 967 | 968 | if segment.xmit >= kcp.dead_link { 969 | kcp.state = 0 970 | } 971 | } 972 | } 973 | 974 | // flash remain segments 975 | if size > 0 { 976 | ikcp_output(kcp, buffer, size) 977 | } 978 | 979 | // update ssthresh 980 | if change != 0 { 981 | inflight := kcp.snd_nxt - kcp.snd_una 982 | kcp.ssthresh = inflight / 2 983 | if kcp.ssthresh < IKCP_THRESH_MIN { 984 | kcp.ssthresh = IKCP_THRESH_MIN 985 | } 986 | kcp.cwnd = kcp.ssthresh + resent 987 | kcp.incr = kcp.cwnd * kcp.mss 988 | } 989 | 990 | if lost != 0 { 991 | kcp.ssthresh = cwnd / 2 992 | if kcp.ssthresh < IKCP_THRESH_MIN { 993 | kcp.ssthresh = IKCP_THRESH_MIN 994 | } 995 | kcp.cwnd = 1 996 | kcp.incr = kcp.mss 997 | } 998 | 999 | if kcp.cwnd < 1 { 1000 | kcp.cwnd = 1 1001 | kcp.incr = kcp.mss 1002 | } 1003 | } 1004 | 1005 | //--------------------------------------------------------------------- 1006 | // input update 1007 | //--------------------------------------------------------------------- 1008 | func Ikcp_update(kcp *Ikcpcb, current uint32) { 1009 | var slap int32 1010 | 1011 | kcp.current = current 1012 | 1013 | if kcp.updated == 0 { 1014 | kcp.updated = 1 1015 | kcp.ts_flush = kcp.current 1016 | } 1017 | 1018 | slap = _itimediff(kcp.current, kcp.ts_flush) 1019 | 1020 | if slap >= 10000 || slap < -10000 { 1021 | kcp.ts_flush = kcp.current 1022 | slap = 0 1023 | } 1024 | 1025 | if slap >= 0 { 1026 | kcp.ts_flush += kcp.interval 1027 | if _itimediff(kcp.current, kcp.ts_flush) >= 0 { 1028 | kcp.ts_flush = kcp.current + kcp.interval 1029 | } 1030 | Ikcp_flush(kcp) 1031 | } 1032 | } 1033 | 1034 | func Ikcp_check(kcp *Ikcpcb, current uint32) uint32 { 1035 | ts_flush := kcp.ts_flush 1036 | tm_flush := 0x7fffffff 1037 | tm_packet := 0x7fffffff 1038 | minimal := 0 1039 | if kcp.updated == 0 { 1040 | return current 1041 | } 1042 | 1043 | if _itimediff(current, ts_flush) >= 10000 || 1044 | _itimediff(current, ts_flush) < -10000 { 1045 | ts_flush = current 1046 | } 1047 | 1048 | if _itimediff(current, ts_flush) >= 0 { 1049 | return current 1050 | } 1051 | 1052 | tm_flush = int(_itimediff(ts_flush, current)) 1053 | 1054 | for p := kcp.snd_buf.Front(); p != nil; p = p.Next() { 1055 | seg := p.Value.(*IKCPSEG) 1056 | diff := _itimediff(seg.resendts, current) 1057 | if diff <= 0 { 1058 | return current 1059 | } 1060 | if diff < int32(tm_packet) { 1061 | tm_packet = int(diff) 1062 | } 1063 | } 1064 | 1065 | minimal = int(tm_packet) 1066 | if tm_packet >= tm_flush { 1067 | minimal = int(tm_flush) 1068 | } 1069 | if uint32(minimal) >= kcp.interval { 1070 | minimal = int(kcp.interval) 1071 | } 1072 | 1073 | return current + uint32(minimal) 1074 | } 1075 | 1076 | func Ikcp_setmtu(kcp *Ikcpcb, mtu int32) int32 { 1077 | if mtu < 50 || mtu < int32(IKCP_OVERHEAD) { 1078 | return -1 1079 | } 1080 | buffer := make([]byte, (uint32(mtu)+IKCP_OVERHEAD)*3) 1081 | if buffer == nil { 1082 | return -2 1083 | } 1084 | kcp.mtu = uint32(mtu) 1085 | kcp.mss = kcp.mtu - IKCP_OVERHEAD 1086 | kcp.buffer = buffer 1087 | return 0 1088 | } 1089 | 1090 | func ikcp_interval(kcp *Ikcpcb, interval int32) int32 { 1091 | if interval > 5000 { 1092 | interval = 5000 1093 | } else if interval < 10 { 1094 | interval = 10 1095 | } 1096 | kcp.interval = uint32(interval) 1097 | return 0 1098 | } 1099 | 1100 | func Ikcp_nodelay(kcp *Ikcpcb, nodelay, interval, resend, nc int32) int32 { 1101 | if nodelay >= 0 { 1102 | kcp.nodelay = uint32(nodelay) 1103 | if nodelay != 0 { 1104 | kcp.rx_minrto = IKCP_RTO_NDL 1105 | } else { 1106 | kcp.rx_minrto = IKCP_RTO_MIN 1107 | } 1108 | } 1109 | if interval >= 0 { 1110 | if interval > 5000 { 1111 | interval = 5000 1112 | } else if interval < 10 { 1113 | interval = 10 1114 | } 1115 | kcp.interval = uint32(interval) 1116 | } 1117 | if resend >= 0 { 1118 | kcp.fastresend = resend 1119 | } 1120 | if nc >= 0 { 1121 | kcp.nocwnd = nc 1122 | } 1123 | return 0 1124 | } 1125 | 1126 | func Ikcp_wndsize(kcp *Ikcpcb, sndwnd, rcvwnd int32) int32 { 1127 | if kcp != nil { 1128 | if sndwnd > 0 { 1129 | kcp.snd_wnd = uint32(sndwnd) 1130 | } 1131 | if rcvwnd > 0 { 1132 | kcp.rcv_wnd = uint32(rcvwnd) 1133 | } 1134 | } 1135 | return 0 1136 | } 1137 | 1138 | func Ikcp_waitsnd(kcp *Ikcpcb) int32 { 1139 | return int32(kcp.nsnd_buf + kcp.nsnd_que) 1140 | } 1141 | -------------------------------------------------------------------------------- /client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | "crypto/tls" 8 | "encoding/json" 9 | "flag" 10 | "fmt" 11 | "io/ioutil" 12 | "log" 13 | "math/rand" 14 | "net" 15 | "os" 16 | "os/signal" 17 | "os/user" 18 | "path" 19 | "strconv" 20 | "strings" 21 | "sync" 22 | "syscall" 23 | "time" 24 | 25 | "github.com/vzex/dog-tunnel/common" 26 | "github.com/vzex/dog-tunnel/nat" 27 | ) 28 | 29 | var accessKey = flag.String("key", "", "please login into dog-tunnel.tk to get accesskey") 30 | var clientKey = flag.String("clientkey", "", "when other client linkt to the reg client, need clientkey, or empty") 31 | 32 | var serverAddr = flag.String("remote", "dog-tunnel.tk:8000", "connect remote server") 33 | var serverBustAddr = flag.String("buster", "dog-tunnel.tk:8018", "MakeHole server") 34 | 35 | var addInitAddr = flag.String("addip", "127.0.0.1", "addip for bust,xx.xx.xx.xx;xx.xx.xx.xx;") 36 | var pipeNum = flag.Int("pipen", 1, "pipe num for transmission") 37 | 38 | var serveName = flag.String("reg", "", "reg the name for client link, must assign reg or link") 39 | 40 | var linkName = flag.String("link", "", "name for link, must assign reg or link") 41 | var localAddr = flag.String("local", "", "addr for listen or connect(value \"socks5\" means tcp socks5 proxy for reg),depends on link or reg") 42 | var bVerbose = flag.Bool("v", false, "verbose mode") 43 | var delayTime = flag.Int("delay", 2, "if bust fail, try to make some delay seconds") 44 | var clientMode = flag.Int("mode", 0, "connect mode:0 if p2p fail, use c/s mode;1 just p2p mode;2 just c/s mode") 45 | var bUseSSL = flag.Bool("ssl", true, "use ssl") 46 | var bShowVersion = flag.Bool("version", false, "show version") 47 | var bLoadSettingFromFile = flag.Bool("f", false, "load setting from file(~/.dtunnel)") 48 | var bEncrypt = flag.Bool("encrypt", false, "p2p mode encrypt") 49 | var dnsCacheNum = flag.Int("dnscache", 0, "if > 0, dns will cache xx minutes") 50 | 51 | var aesKey *cipher.Block 52 | 53 | var remoteConn net.Conn 54 | var clientType = -1 55 | 56 | type dnsInfo struct { 57 | Ip string 58 | Status string 59 | Queue []*dnsQueryReq 60 | overTime, cacheTime int64 61 | } 62 | 63 | func (u *dnsInfo) IsAlive() bool { 64 | return time.Now().Unix() < u.overTime 65 | } 66 | 67 | func (u *dnsInfo) GetCacheTime() int64 { 68 | return u.overTime 69 | } 70 | 71 | func (u *dnsInfo) SetCacheTime(t int64) { 72 | if t >= 0 { 73 | u.cacheTime = t 74 | } else { 75 | t = u.cacheTime 76 | } 77 | u.overTime = t + time.Now().Unix() 78 | } 79 | func (u *dnsInfo) DeInit() {} 80 | 81 | var g_ClientMap map[string]*Client 82 | var g_ClientMapKey map[string]*cipher.Block 83 | var g_Id2UDPSession map[string]*UDPMakeSession 84 | var markName = "" 85 | var bForceQuit = false 86 | 87 | func isCommonSessionId(id string) bool { 88 | return id == "common" 89 | } 90 | 91 | func handleResponse(conn net.Conn, clientId string, action string, content string) { 92 | //log.Println("got", clientId, action) 93 | switch action { 94 | case "aeskey": 95 | fmt.Println("init aeskey for client", clientId, content) 96 | block, _ := aes.NewCipher([]byte(content)) 97 | g_ClientMapKey[clientId] = &block 98 | case "show": 99 | fmt.Println(time.Now().Format("2006-01-02 15:04:05"), content) 100 | case "showandretry": 101 | fmt.Println(time.Now().Format("2006-01-02 15:04:05"), content) 102 | remoteConn.Close() 103 | case "showandquit": 104 | fmt.Println(time.Now().Format("2006-01-02 15:04:05"), content) 105 | remoteConn.Close() 106 | bForceQuit = true 107 | case "clientquit": 108 | client := g_ClientMap[clientId] 109 | log.Println("clientquit!!!", clientId, client) 110 | if client != nil { 111 | client.Quit() 112 | } 113 | case "remove_udpsession": 114 | log.Println("server force remove udpsession", clientId) 115 | delete(g_Id2UDPSession, clientId) 116 | case "query_addrlist_a": 117 | outip := content 118 | arr := strings.Split(clientId, "-") 119 | id := arr[0] 120 | sessionId := arr[1] 121 | pipeType := arr[2] 122 | g_Id2UDPSession[id] = &UDPMakeSession{id: id, sessionId: sessionId, pipeType: pipeType} 123 | go g_Id2UDPSession[id].reportAddrList(true, outip) 124 | case "query_addrlist_b": 125 | arr := strings.Split(clientId, "-") 126 | id := arr[0] 127 | sessionId := arr[1] 128 | pipeType := arr[2] 129 | g_Id2UDPSession[id] = &UDPMakeSession{id: id, sessionId: sessionId, pipeType: pipeType} 130 | go g_Id2UDPSession[id].reportAddrList(false, content) 131 | case "tell_bust_a": 132 | session, bHave := g_Id2UDPSession[clientId] 133 | if bHave { 134 | go session.beginMakeHole(content) 135 | } 136 | case "tell_bust_b": 137 | session, bHave := g_Id2UDPSession[clientId] 138 | if bHave { 139 | go session.beginMakeHole("") 140 | } 141 | case "csmode_c_tunnel_close": 142 | log.Println("receive close msg from server") 143 | arr := strings.Split(clientId, "-") 144 | clientId = arr[0] 145 | sessionId := arr[1] 146 | client, bHave := g_ClientMap[clientId] 147 | if bHave { 148 | client.removeSession(sessionId) 149 | } 150 | case "csmode_s_tunnel_close": 151 | arr := strings.Split(clientId, "-") 152 | clientId = arr[0] 153 | sessionId := arr[1] 154 | client, bHave := g_ClientMap[clientId] 155 | if bHave { 156 | client.removeSession(sessionId) 157 | } 158 | case "csmode_s_tunnel_open": 159 | oriId := clientId 160 | arr := strings.Split(oriId, "-") 161 | clientId = arr[0] 162 | sessionId := arr[1] 163 | client, bHave := g_ClientMap[clientId] 164 | if !bHave { 165 | client = &Client{id: clientId, pipes: make(map[int]net.Conn), engine: nil, buster: true, sessions: make(map[string]*clientSession), ready: true, bUdp: false} 166 | client.pipes[0] = remoteConn 167 | g_ClientMap[clientId] = client 168 | } else { 169 | client.pipes[0] = remoteConn 170 | client.ready = true 171 | client.bUdp = false 172 | } 173 | //log.Println("client init csmode", clientId, sessionId) 174 | if *localAddr != "socks5" { 175 | s_conn, err := net.DialTimeout("tcp", *localAddr, 10*time.Second) 176 | if err != nil { 177 | log.Println("connect to local server fail:", err.Error()) 178 | msg := "cannot connect to bind addr" + *localAddr 179 | common.Write(remoteConn, clientId, "tunnel_error", msg) 180 | //remoteConn.Close() 181 | return 182 | } else { 183 | client.sessionLock.Lock() 184 | client.sessions[sessionId] = &clientSession{pipe: remoteConn, localConn: s_conn} 185 | client.sessionLock.Unlock() 186 | go handleLocalPortResponse(client, oriId) 187 | } 188 | } else { 189 | client.sessionLock.Lock() 190 | client.sessions[sessionId] = &clientSession{pipe: remoteConn, localConn: nil, status: "init", recvMsg: ""} 191 | client.sessionLock.Unlock() 192 | } 193 | case "csmode_c_begin": 194 | client, bHave := g_ClientMap[clientId] 195 | if !bHave { 196 | client = &Client{id: clientId, pipes: make(map[int]net.Conn), engine: nil, buster: false, sessions: make(map[string]*clientSession), ready: true, bUdp: false} 197 | client.pipes[0] = remoteConn 198 | g_ClientMap[clientId] = client 199 | } else { 200 | client.pipes[0] = remoteConn 201 | client.ready = true 202 | client.bUdp = false 203 | } 204 | if client.MultiListen() { 205 | common.Write(remoteConn, clientId, "makeholeok", "csmode") 206 | } 207 | case "csmode_msg_c": 208 | oriId := clientId 209 | arr := strings.Split(clientId, "-") 210 | clientId = arr[0] 211 | sessionId := arr[1] 212 | client, bHave := g_ClientMap[clientId] 213 | if bHave { 214 | session := client.getSession(sessionId) 215 | if session != nil && session.localConn != nil { 216 | session.localConn.Write([]byte(content)) 217 | } else if session != nil && *localAddr == "socks5" { 218 | session.processSockProxy(client, oriId, content, func() { 219 | if len(session.recvMsg) > 0 && session.localConn != nil { 220 | session.localConn.Write([]byte(session.recvMsg)) 221 | } 222 | }) 223 | } 224 | } 225 | case "csmode_msg_s": 226 | arr := strings.Split(clientId, "-") 227 | clientId = arr[0] 228 | sessionId := arr[1] 229 | client, bHave := g_ClientMap[clientId] 230 | if bHave { 231 | session := client.getSession(sessionId) 232 | if session != nil && session.localConn != nil { 233 | session.localConn.Write([]byte(content)) 234 | } else { 235 | //log.Println("cs:cannot tunnel msg", sessionId) 236 | } 237 | } 238 | } 239 | } 240 | 241 | type UDPMakeSession struct { 242 | id string 243 | sessionId string 244 | buster bool 245 | engine *nat.AttemptEngine 246 | delay int 247 | pipeType string 248 | } 249 | 250 | func (session *UDPMakeSession) beginMakeHole(content string) { 251 | engine := session.engine 252 | if engine == nil { 253 | return 254 | } 255 | addrList := content 256 | if session.buster { 257 | engine.SetOtherAddrList(addrList) 258 | } 259 | log.Println("begin bust", session.id, session.sessionId, session.buster) 260 | if clientType == 1 && !session.buster { 261 | log.Println("retry bust!") 262 | } 263 | report := func() { 264 | if session.buster { 265 | if session.delay > 0 { 266 | log.Println("try to delay", session.delay, "seconds") 267 | time.Sleep(time.Duration(session.delay) * time.Second) 268 | } 269 | go common.Write(remoteConn, session.id, "success_bust_a", "") 270 | } 271 | } 272 | oldSession := session 273 | var aesBlock *cipher.Block 274 | if clientType == 1 { 275 | aesBlock = aesKey 276 | } else { 277 | aesBlock, _ = g_ClientMapKey[session.sessionId] 278 | } 279 | var conn net.Conn 280 | var err error 281 | if aesBlock == nil { 282 | conn, err = engine.GetConn(report, nil, nil) 283 | } else { 284 | conn, err = engine.GetConn(report, func(s []byte) []byte { 285 | if aesBlock == nil { 286 | return s 287 | } else { 288 | padLen := aes.BlockSize - (len(s) % aes.BlockSize) 289 | for i := 0; i < padLen; i++ { 290 | s = append(s, byte(padLen)) 291 | } 292 | srcLen := len(s) 293 | encryptText := make([]byte, srcLen+aes.BlockSize) 294 | iv := encryptText[srcLen:] 295 | for i := 0; i < len(iv); i++ { 296 | iv[i] = byte(i) 297 | } 298 | mode := cipher.NewCBCEncrypter(*aesBlock, iv) 299 | mode.CryptBlocks(encryptText[:srcLen], s) 300 | return encryptText 301 | } 302 | }, func(s []byte) []byte { 303 | if aesBlock == nil { 304 | return s 305 | } else { 306 | if len(s) < aes.BlockSize*2 || len(s)%aes.BlockSize != 0 { 307 | return []byte{} 308 | } 309 | srcLen := len(s) - aes.BlockSize 310 | decryptText := make([]byte, srcLen) 311 | iv := s[srcLen:] 312 | mode := cipher.NewCBCDecrypter(*aesBlock, iv) 313 | mode.CryptBlocks(decryptText, s[:srcLen]) 314 | paddingLen := int(decryptText[srcLen-1]) 315 | if paddingLen > 16 { 316 | return []byte{} 317 | } 318 | return decryptText[:srcLen-paddingLen] 319 | } 320 | }) 321 | } 322 | session, _bHave := g_Id2UDPSession[session.id] 323 | if session != oldSession { 324 | return 325 | } 326 | if !_bHave { 327 | return 328 | } 329 | delete(g_Id2UDPSession, session.id) 330 | if err == nil { 331 | if !session.buster { 332 | common.Write(remoteConn, session.id, "makeholeok", "") 333 | } 334 | client, bHave := g_ClientMap[session.sessionId] 335 | if !bHave { 336 | client = &Client{id: session.sessionId, engine: session.engine, buster: session.buster, ready: true, bUdp: true, sessions: make(map[string]*clientSession), specPipes: make(map[string]net.Conn), pipes: make(map[int]net.Conn)} 337 | g_ClientMap[session.sessionId] = client 338 | } 339 | if isCommonSessionId(session.pipeType) { 340 | size := len(client.pipes) 341 | client.pipes[size] = conn 342 | go client.Run(size, "") 343 | log.Println("add common session", session.buster, session.sessionId, session.id) 344 | if clientType == 1 { 345 | if len(client.pipes) == *pipeNum { 346 | client.MultiListen() 347 | } 348 | } 349 | } else { 350 | client.specPipes[session.pipeType] = conn 351 | go client.Run(-1, session.pipeType) 352 | log.Println("add session for", session.pipeType) 353 | } 354 | } else { 355 | delete(g_ClientMap, session.sessionId) 356 | delete(g_ClientMapKey, session.sessionId) 357 | log.Println("cannot connect", err.Error()) 358 | if !session.buster && err.Error() != "quit" { 359 | common.Write(remoteConn, session.id, "makeholefail", "") 360 | } 361 | } 362 | } 363 | 364 | func (session *UDPMakeSession) reportAddrList(buster bool, outip string) { 365 | id := session.id 366 | var otherAddrList string 367 | if !buster { 368 | arr := strings.SplitN(outip, ":", 2) 369 | outip, otherAddrList = arr[0], arr[1] 370 | } else { 371 | arr := strings.SplitN(outip, ":", 2) 372 | var delayTime string 373 | outip, delayTime = arr[0], arr[1] 374 | session.delay, _ = strconv.Atoi(delayTime) 375 | if session.delay < 0 { 376 | session.delay = 0 377 | } 378 | } 379 | outip += ";" + *addInitAddr 380 | _id, _ := strconv.Atoi(id) 381 | engine, err := nat.Init(outip, buster, _id, *serverBustAddr) 382 | if err != nil { 383 | println("init error", err.Error()) 384 | disconnect() 385 | return 386 | } 387 | session.engine = engine 388 | session.buster = buster 389 | if !buster { 390 | engine.SetOtherAddrList(otherAddrList) 391 | } 392 | addrList := engine.GetAddrList() 393 | println("addrList", addrList) 394 | common.Write(remoteConn, id, "report_addrlist", addrList) 395 | } 396 | 397 | type fileSetting struct { 398 | Key string 399 | } 400 | 401 | func saveSettings(info fileSetting) error { 402 | clientInfoStr, err := json.Marshal(info) 403 | if err != nil { 404 | return err 405 | } 406 | user, err := user.Current() 407 | if err != nil { 408 | return err 409 | } 410 | filePath := path.Join(user.HomeDir, ".dtunnel") 411 | 412 | return ioutil.WriteFile(filePath, clientInfoStr, 0700) 413 | } 414 | 415 | func loadSettings(info *fileSetting) error { 416 | user, err := user.Current() 417 | if err != nil { 418 | return err 419 | } 420 | filePath := path.Join(user.HomeDir, ".dtunnel") 421 | content, err := ioutil.ReadFile(filePath) 422 | if err != nil { 423 | return err 424 | } 425 | err = json.Unmarshal([]byte(content), info) 426 | if err != nil { 427 | return err 428 | } 429 | return nil 430 | } 431 | 432 | func main() { 433 | flag.Parse() 434 | checkDns = make(chan *dnsQueryReq) 435 | checkDnsRes = make(chan *dnsQueryBack) 436 | go dnsLoop() 437 | if *bShowVersion { 438 | fmt.Printf("%.2f\n", common.Version) 439 | return 440 | } 441 | if !*bVerbose { 442 | log.SetOutput(ioutil.Discard) 443 | } 444 | if *serveName == "" && *linkName == "" { 445 | println("you must assign reg or link") 446 | return 447 | } 448 | if *serveName != "" && *linkName != "" { 449 | println("you must assign reg or link, not both of them") 450 | return 451 | } 452 | if *localAddr == "" { 453 | println("you must assign the local addr") 454 | return 455 | } 456 | if *serveName != "" { 457 | clientType = 0 458 | } else { 459 | clientType = 1 460 | } 461 | if *bEncrypt { 462 | if clientType != 1 { 463 | println("only link size need encrypt") 464 | return 465 | } 466 | } 467 | go func() { 468 | c := make(chan os.Signal, 1) 469 | signal.Notify(c, os.Interrupt, syscall.SIGTERM) 470 | n := 0 471 | for { 472 | <-c 473 | log.Println("received signal,shutdown") 474 | bForceQuit = true 475 | if remoteConn != nil { 476 | remoteConn.Close() 477 | } 478 | n++ 479 | if n > 5 { 480 | log.Println("force shutdown") 481 | os.Exit(-1) 482 | } 483 | } 484 | }() 485 | 486 | loop := func() bool { 487 | if bForceQuit { 488 | return true 489 | } 490 | g_ClientMap = make(map[string]*Client) 491 | g_ClientMapKey = make(map[string]*cipher.Block) 492 | g_Id2UDPSession = make(map[string]*UDPMakeSession) 493 | //var err error 494 | if *bUseSSL { 495 | _remoteConn, err := tls.Dial("tcp", *serverAddr, &tls.Config{InsecureSkipVerify: true}) 496 | if err != nil { 497 | println("connect remote err:" + err.Error()) 498 | return false 499 | } 500 | remoteConn = net.Conn(_remoteConn) 501 | } else { 502 | _remoteConn, err := net.DialTimeout("tcp", *serverAddr, 10*time.Second) 503 | if err != nil { 504 | println("connect remote err:" + err.Error()) 505 | return false 506 | } 507 | remoteConn = _remoteConn 508 | } 509 | println("connect to server succeed") 510 | go connect() 511 | q := make(chan bool) 512 | go func() { 513 | c := time.NewTicker(time.Second * 10) 514 | out: 515 | for { 516 | select { 517 | case <-c.C: 518 | if remoteConn != nil { 519 | common.Write(remoteConn, "-1", "ping", "") 520 | } 521 | case <-q: 522 | break out 523 | } 524 | } 525 | c.Stop() 526 | }() 527 | 528 | common.Read(remoteConn, handleResponse) 529 | q <- true 530 | for clientId, client := range g_ClientMap { 531 | log.Println("client shutdown", clientId) 532 | client.Quit() 533 | } 534 | 535 | for _, session := range g_Id2UDPSession { 536 | if session.engine != nil { 537 | session.engine.Fail() 538 | } 539 | } 540 | if remoteConn != nil { 541 | remoteConn.Close() 542 | } 543 | if bForceQuit { 544 | return true 545 | } 546 | return false 547 | } 548 | if clientType == 0 { 549 | for { 550 | if loop() { 551 | break 552 | } 553 | time.Sleep(10 * time.Second) 554 | } 555 | } else { 556 | loop() 557 | } 558 | log.Println("service shutdown") 559 | } 560 | 561 | func connect() { 562 | if *pipeNum <= 0 { 563 | *pipeNum = 1 564 | } 565 | clientInfo := common.ClientSetting{Version: common.Version, Delay: *delayTime, Mode: *clientMode, PipeNum: *pipeNum, AccessKey: *accessKey, ClientKey: *clientKey, AesKey: ""} 566 | if *bEncrypt { 567 | clientInfo.AesKey = string([]byte(fmt.Sprintf("asd4%d%d", int32(time.Now().Unix()), (rand.Intn(100000) + 100)))[:16]) 568 | log.Println("debug aeskey", clientInfo.AesKey) 569 | key, _ := aes.NewCipher([]byte(clientInfo.AesKey)) 570 | aesKey = &key 571 | } 572 | if *bLoadSettingFromFile { 573 | var setting fileSetting 574 | err := loadSettings(&setting) 575 | if err == nil { 576 | clientInfo.AccessKey = setting.Key 577 | } else { 578 | log.Println("load setting fail", err.Error()) 579 | } 580 | } else { 581 | if clientInfo.AccessKey != "" { 582 | var setting = fileSetting{Key: clientInfo.AccessKey} 583 | err := saveSettings(setting) 584 | if err != nil { 585 | log.Println("save setting error", err.Error()) 586 | } else { 587 | println("save setting ok, nexttime please use -f to replace -key") 588 | } 589 | } 590 | } 591 | if clientType == 0 { 592 | markName = *serveName 593 | clientInfo.ClientType = "reg" 594 | } else if clientType == 1 { 595 | markName = *linkName 596 | clientInfo.ClientType = "link" 597 | } else { 598 | println("no clienttype!") 599 | } 600 | clientInfo.Name = markName 601 | clientInfoStr, err := json.Marshal(clientInfo) 602 | if err != nil { 603 | println("encode args error") 604 | } 605 | log.Println("init client", string(clientInfoStr)) 606 | common.Write(remoteConn, "0", "init", string(clientInfoStr)) 607 | } 608 | 609 | func disconnect() { 610 | if remoteConn != nil { 611 | remoteConn.Close() 612 | remoteConn = nil 613 | } 614 | } 615 | 616 | type clientSession struct { 617 | pipe net.Conn 618 | localConn net.Conn 619 | status string 620 | recvMsg string 621 | extra uint8 622 | } 623 | 624 | func (session *clientSession) processSockProxy(sc *Client, sessionId, content string, callback func()) { 625 | pipe := session.pipe 626 | session.recvMsg += content 627 | bytes := []byte(session.recvMsg) 628 | size := len(bytes) 629 | //log.Println("recv msg-====", len(session.recvMsg), session.recvMsg, session.status, sessionId) 630 | switch session.status { 631 | case "init": 632 | if session.localConn != nil { 633 | session.localConn.Close() 634 | session.localConn = nil 635 | } 636 | if size < 2 { 637 | //println("wait init") 638 | return 639 | } 640 | var _, nmethod uint8 = bytes[0], bytes[1] 641 | //println("version", version, nmethod) 642 | session.status = "version" 643 | session.recvMsg = string(bytes[2:]) 644 | session.extra = nmethod 645 | case "version": 646 | if uint8(size) < session.extra { 647 | //println("wait version") 648 | return 649 | } 650 | var send = []uint8{5, 0} 651 | go common.Write(pipe, sessionId, "tunnel_msg_s", string(send)) 652 | session.status = "hello" 653 | session.recvMsg = string(bytes[session.extra:]) 654 | session.extra = 0 655 | //log.Println("now", len(session.recvMsg)) 656 | case "hello": 657 | var hello reqMsg 658 | bOk, tail := hello.read(bytes) 659 | if bOk { 660 | go func() { 661 | var ansmsg ansMsg 662 | url := hello.url 663 | var s_conn net.Conn 664 | var err error 665 | if *dnsCacheNum > 0 && hello.atyp == 3 { 666 | host := string(hello.dst_addr[1 : 1+hello.dst_addr[0]]) 667 | resChan := make(chan *dnsQueryRes) 668 | checkDns <- &dnsQueryReq{c: resChan, host: host, port: int(hello.dst_port2), reqtype: hello.reqtype, url: url} 669 | res := <-resChan 670 | s_conn = res.conn 671 | err = res.err 672 | if res.ip != "" { 673 | url = net.JoinHostPort(res.ip, fmt.Sprintf("%d", hello.dst_port2)) 674 | } 675 | } 676 | if s_conn == nil && err == nil { 677 | s_conn, err = net.DialTimeout(hello.reqtype, url, 30*time.Second) 678 | } 679 | if err != nil { 680 | log.Println("connect to local server fail:", err.Error()) 681 | ansmsg.gen(&hello, 4) 682 | go common.Write(pipe, sessionId, "tunnel_msg_s", string(ansmsg.buf[:ansmsg.mlen])) 683 | return 684 | } else { 685 | session.localConn = s_conn 686 | go handleLocalPortResponse(sc, sessionId) 687 | ansmsg.gen(&hello, 0) 688 | go common.Write(pipe, sessionId, "tunnel_msg_s", string(ansmsg.buf[:ansmsg.mlen])) 689 | session.status = "ok" 690 | session.recvMsg = string(tail) 691 | callback() 692 | return 693 | } 694 | }() 695 | } else { 696 | //log.Println("wait hello") 697 | } 698 | return 699 | case "ok": 700 | return 701 | } 702 | session.processSockProxy(sc, sessionId, "", callback) 703 | } 704 | 705 | var checkDns chan *dnsQueryReq 706 | var checkDnsRes chan *dnsQueryBack 707 | 708 | type dnsQueryReq struct { 709 | c chan *dnsQueryRes 710 | host string 711 | port int 712 | reqtype string 713 | url string 714 | } 715 | 716 | type dnsQueryBack struct { 717 | host string 718 | status string 719 | conn net.Conn 720 | err error 721 | } 722 | 723 | type dnsQueryRes struct { 724 | conn net.Conn 725 | err error 726 | ip string 727 | } 728 | 729 | func dnsLoop() { 730 | for { 731 | select { 732 | case info := <-checkDns: 733 | cache := common.GetCacheContainer("dns") 734 | cacheInfo := cache.GetCache(info.host) 735 | if cacheInfo == nil { 736 | cache.AddCache(info.host, &dnsInfo{Queue: []*dnsQueryReq{info}, Status: "querying"}, int64(*dnsCacheNum*60)) 737 | go func() { 738 | back := &dnsQueryBack{host: info.host} 739 | //log.Println("try dial", info.url) 740 | s_conn, err := net.DialTimeout(info.reqtype, info.url, 30*time.Second) 741 | //log.Println("try dial", info.url, "ok") 742 | if err != nil { 743 | back.status = "queryfail" 744 | back.err = err 745 | } else { 746 | back.status = "queryok" 747 | back.conn = s_conn 748 | } 749 | checkDnsRes <- back 750 | }() 751 | } else { 752 | _cacheInfo := cacheInfo.(*dnsInfo) 753 | //log.Println("on trigger", info.host, _cacheInfo.GetCacheTime(), len(_cacheInfo.Queue)) 754 | switch _cacheInfo.Status { 755 | case "querying": 756 | _cacheInfo.Queue = append(_cacheInfo.Queue, info) 757 | //cache.UpdateCache(info.host, _cacheInfo) 758 | cacheInfo.SetCacheTime(-1) 759 | case "queryok": 760 | cacheInfo.SetCacheTime(-1) 761 | go func() { 762 | info.c <- &dnsQueryRes{ip: _cacheInfo.Ip} 763 | }() 764 | } 765 | //url = cacheInfo.(*dnsInfo).Ip + fmt.Sprintf(":%d", info.port) 766 | } 767 | case info := <-checkDnsRes: 768 | cache := common.GetCacheContainer("dns") 769 | cacheInfo := cache.GetCache(info.host) 770 | if cacheInfo != nil { 771 | _cacheInfo := cacheInfo.(*dnsInfo) 772 | _cacheInfo.Status = info.status 773 | switch info.status { 774 | case "queryfail": 775 | for _, _info := range _cacheInfo.Queue { 776 | c := _info.c 777 | go func() { 778 | c <- &dnsQueryRes{err: info.err} 779 | }() 780 | } 781 | cache.DelCache(info.host) 782 | case "queryok": 783 | log.Println("add host", info.host, "to dns cache") 784 | _cacheInfo.Ip, _, _ = net.SplitHostPort(info.conn.RemoteAddr().String()) 785 | _cacheInfo.SetCacheTime(-1) 786 | //log.Println("process the queue of host", info.host, len(_cacheInfo.Queue)) 787 | conn := info.conn 788 | for _, _info := range _cacheInfo.Queue { 789 | c := _info.c 790 | go func() { 791 | c <- &dnsQueryRes{ip: _cacheInfo.Ip, conn: conn} 792 | }() 793 | conn = nil 794 | } 795 | _cacheInfo.Queue = []*dnsQueryReq{} 796 | } 797 | //cache.UpdateCache(info.host, _cacheInfo) 798 | } 799 | } 800 | } 801 | } 802 | 803 | type ansMsg struct { 804 | ver uint8 805 | rep uint8 806 | rsv uint8 807 | atyp uint8 808 | buf [300]uint8 809 | mlen uint16 810 | } 811 | 812 | func (msg *ansMsg) gen(req *reqMsg, rep uint8) { 813 | msg.ver = 5 814 | msg.rep = rep //rfc1928 815 | msg.rsv = 0 816 | msg.atyp = 1 817 | 818 | msg.buf[0], msg.buf[1], msg.buf[2], msg.buf[3] = msg.ver, msg.rep, msg.rsv, msg.atyp 819 | for i := 5; i < 11; i++ { 820 | msg.buf[i] = 0 821 | } 822 | msg.mlen = 10 823 | } 824 | 825 | type reqMsg struct { 826 | ver uint8 // socks v5: 0x05 827 | cmd uint8 // CONNECT: 0x01, BIND:0x02, UDP ASSOCIATE: 0x03 828 | rsv uint8 //RESERVED 829 | atyp uint8 //IP V4 addr: 0x01, DOMANNAME: 0x03, IP V6 addr: 0x04 830 | dst_addr [255]byte // 831 | dst_port [2]uint8 // 832 | dst_port2 uint16 // 833 | 834 | reqtype string 835 | url string 836 | } 837 | 838 | func (msg *reqMsg) read(bytes []byte) (bool, []byte) { 839 | size := len(bytes) 840 | if size < 4 { 841 | return false, bytes 842 | } 843 | buf := bytes[0:4] 844 | 845 | msg.ver, msg.cmd, msg.rsv, msg.atyp = buf[0], buf[1], buf[2], buf[3] 846 | //println("test", msg.ver, msg.cmd, msg.rsv, msg.atyp) 847 | 848 | if 5 != msg.ver || 0 != msg.rsv { 849 | log.Println("Request Message VER or RSV error!") 850 | return false, bytes[4:] 851 | } 852 | buf = bytes[4:] 853 | size = len(buf) 854 | switch msg.atyp { 855 | case 1: //ip v4 856 | if size < 4 { 857 | return false, buf 858 | } 859 | copy(msg.dst_addr[:4], buf[:4]) 860 | buf = buf[4:] 861 | size = len(buf) 862 | case 4: 863 | if size < 16 { 864 | return false, buf 865 | } 866 | copy(msg.dst_addr[:16], buf[:16]) 867 | buf = buf[16:] 868 | size = len(buf) 869 | case 3: 870 | if size < 1 { 871 | return false, buf 872 | } 873 | copy(msg.dst_addr[:1], buf[:1]) 874 | buf = buf[1:] 875 | size = len(buf) 876 | if size < int(msg.dst_addr[0]) { 877 | return false, buf 878 | } 879 | copy(msg.dst_addr[1:], buf[:int(msg.dst_addr[0])]) 880 | buf = buf[int(msg.dst_addr[0]):] 881 | size = len(buf) 882 | } 883 | if size < 2 { 884 | return false, buf 885 | } 886 | copy(msg.dst_port[:], buf[:2]) 887 | msg.dst_port2 = (uint16(msg.dst_port[0]) << 8) + uint16(msg.dst_port[1]) 888 | 889 | switch msg.cmd { 890 | case 1: 891 | msg.reqtype = "tcp" 892 | case 2: 893 | log.Println("BIND") 894 | case 3: 895 | msg.reqtype = "udp" 896 | } 897 | switch msg.atyp { 898 | case 1: // ipv4 899 | msg.url = fmt.Sprintf("%d.%d.%d.%d:%d", msg.dst_addr[0], msg.dst_addr[1], msg.dst_addr[2], msg.dst_addr[3], msg.dst_port2) 900 | case 3: //DOMANNAME 901 | msg.url = net.JoinHostPort(string(msg.dst_addr[1:1+msg.dst_addr[0]]), fmt.Sprintf("%d", msg.dst_port2)) 902 | case 4: //ipv6 903 | msg.url = fmt.Sprintf("[%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x]:%d", msg.dst_addr[0], msg.dst_addr[1], msg.dst_addr[2], msg.dst_addr[3], 904 | msg.dst_addr[4], msg.dst_addr[5], msg.dst_addr[6], msg.dst_addr[7], 905 | msg.dst_addr[8], msg.dst_addr[9], msg.dst_addr[10], msg.dst_addr[11], 906 | msg.dst_addr[12], msg.dst_addr[13], msg.dst_addr[14], msg.dst_addr[15], 907 | msg.dst_port2) 908 | } 909 | log.Println(msg.reqtype, msg.url, msg.atyp, msg.dst_port2) 910 | return true, buf[2:] 911 | } 912 | 913 | type Client struct { 914 | id string 915 | buster bool 916 | engine *nat.AttemptEngine 917 | pipes map[int]net.Conn // client for pipes 918 | specPipes map[string]net.Conn // client for pipes 919 | sessions map[string]*clientSession // session to pipeid 920 | sessionLock sync.RWMutex 921 | ready bool 922 | bUdp bool 923 | } 924 | 925 | // pipe : client to client 926 | // local : client to local apps 927 | func (sc *Client) getSession(sessionId string) *clientSession { 928 | sc.sessionLock.RLock() 929 | session, _ := sc.sessions[sessionId] 930 | sc.sessionLock.RUnlock() 931 | return session 932 | } 933 | 934 | func (sc *Client) removeSession(sessionId string) bool { 935 | if clientType == 1 { 936 | common.RmId("udp", sessionId) 937 | } 938 | sc.sessionLock.RLock() 939 | session, bHave := sc.sessions[sessionId] 940 | sc.sessionLock.RUnlock() 941 | if bHave { 942 | if session.localConn != nil { 943 | session.localConn.Close() 944 | } 945 | sc.sessionLock.Lock() 946 | delete(sc.sessions, sessionId) 947 | sc.sessionLock.Unlock() 948 | //log.Println("client", sc.id, "remove session", sessionId) 949 | return true 950 | } 951 | return false 952 | } 953 | 954 | func (sc *Client) OnTunnelRecv(pipe net.Conn, sessionId string, action string, content string) { 955 | //println("recv p2p tunnel", sessionId, action, content) 956 | session := sc.getSession(sessionId) 957 | var conn net.Conn 958 | if session != nil { 959 | conn = session.localConn 960 | } 961 | switch action { 962 | case "tunnel_error": 963 | if conn != nil { 964 | conn.Write([]byte(content)) 965 | log.Println("tunnel error", content, sessionId) 966 | } 967 | sc.removeSession(sessionId) 968 | //case "serve_begin": 969 | case "tunnel_msg_s": 970 | if conn != nil { 971 | //println("tunnel msg", sessionId, len(content)) 972 | conn.Write([]byte(content)) 973 | } else { 974 | //log.Println("cannot tunnel msg", sessionId) 975 | } 976 | case "tunnel_close_s": 977 | sc.removeSession(sessionId) 978 | case "ping", "pingback": 979 | //log.Println("recv", action) 980 | if action == "ping" { 981 | common.Write(pipe, sessionId, "pingback", "") 982 | } 983 | case "tunnel_msg_c": 984 | if conn != nil { 985 | //log.Println("tunnel", len(content), sessionId) 986 | conn.Write([]byte(content)) 987 | } else if *localAddr == "socks5" { 988 | if session == nil { 989 | return 990 | } 991 | session.processSockProxy(sc, sessionId, content, func() { 992 | sc.OnTunnelRecv(pipe, sessionId, action, session.recvMsg) 993 | }) 994 | } 995 | case "tunnel_close": 996 | sc.removeSession(sessionId) 997 | case "tunnel_open": 998 | if clientType == 0 { 999 | if *localAddr != "socks5" { 1000 | s_conn, err := net.DialTimeout("tcp", *localAddr, 10*time.Second) 1001 | if err != nil { 1002 | log.Println("connect to local server fail:", err.Error()) 1003 | msg := "cannot connect to bind addr" + *localAddr 1004 | common.Write(pipe, sessionId, "tunnel_error", msg) 1005 | //remoteConn.Close() 1006 | return 1007 | } else { 1008 | sc.sessionLock.Lock() 1009 | sc.sessions[sessionId] = &clientSession{pipe: pipe, localConn: s_conn} 1010 | sc.sessionLock.Unlock() 1011 | go handleLocalPortResponse(sc, sessionId) 1012 | } 1013 | } else { 1014 | sc.sessionLock.Lock() 1015 | sc.sessions[sessionId] = &clientSession{pipe: pipe, localConn: nil, status: "init", recvMsg: ""} 1016 | sc.sessionLock.Unlock() 1017 | } 1018 | } 1019 | } 1020 | } 1021 | 1022 | func (sc *Client) Quit() { 1023 | log.Println("client quit", sc.id) 1024 | delete(g_ClientMap, sc.id) 1025 | delete(g_ClientMapKey, sc.id) 1026 | for id, _ := range sc.sessions { 1027 | sc.removeSession(id) 1028 | } 1029 | for _, pipe := range sc.pipes { 1030 | if pipe != remoteConn { 1031 | pipe.Close() 1032 | } 1033 | } 1034 | if sc.engine != nil { 1035 | sc.engine.Fail() 1036 | } 1037 | } 1038 | 1039 | ///////////////////////multi pipe support 1040 | var g_LocalConn net.Conn 1041 | 1042 | func (sc *Client) MultiListen() bool { 1043 | if g_LocalConn == nil { 1044 | g_LocalConn, err := net.Listen("tcp", *localAddr) 1045 | if err != nil { 1046 | log.Println("cannot listen addr:" + err.Error()) 1047 | if remoteConn != nil { 1048 | remoteConn.Close() 1049 | } 1050 | return false 1051 | } 1052 | go func() { 1053 | quit := false 1054 | ping := time.NewTicker(time.Second * 5) 1055 | go func() { 1056 | out: 1057 | for { 1058 | select { 1059 | case <-ping.C: 1060 | if quit { 1061 | break out 1062 | } 1063 | for _, pipe := range sc.pipes { 1064 | common.Write(pipe, "-1", "ping", "") 1065 | } 1066 | } 1067 | } 1068 | }() 1069 | ping.Stop() 1070 | for { 1071 | conn, err := g_LocalConn.Accept() 1072 | if err != nil { 1073 | continue 1074 | } 1075 | sessionId := common.GetId("udp") 1076 | pipe := sc.getOnePipe() 1077 | if pipe == nil { 1078 | log.Println("cannot get pipe for client") 1079 | if remoteConn != nil { 1080 | remoteConn.Close() 1081 | } 1082 | return 1083 | } 1084 | sc.sessionLock.Lock() 1085 | sc.sessions[sessionId] = &clientSession{pipe: pipe, localConn: conn} 1086 | sc.sessionLock.Unlock() 1087 | log.Println("client", sc.id, "create session", sessionId) 1088 | go handleLocalServerResponse(sc, sessionId) 1089 | } 1090 | quit = true 1091 | }() 1092 | mode := "p2p mode" 1093 | if !sc.bUdp { 1094 | mode = "c/s mode" 1095 | delete(g_ClientMapKey, sc.id) 1096 | } 1097 | println("service start success,please connect", *localAddr, mode) 1098 | } 1099 | return true 1100 | } 1101 | 1102 | func (sc *Client) getOnePipe() net.Conn { 1103 | tmp := []int{} 1104 | for id, _ := range sc.pipes { 1105 | tmp = append(tmp, id) 1106 | } 1107 | size := len(tmp) 1108 | if size == 0 { 1109 | return nil 1110 | } 1111 | index := rand.Intn(size) 1112 | log.Println("choose pipe for ", sc.id, ",", index, "of", size) 1113 | hitId := tmp[index] 1114 | pipe, _ := sc.pipes[hitId] 1115 | return pipe 1116 | } 1117 | 1118 | ///////////////////////multi pipe support 1119 | 1120 | func (sc *Client) Run(index int, specPipe string) { 1121 | var pipe net.Conn 1122 | if index >= 0 { 1123 | pipe = sc.pipes[index] 1124 | } else { 1125 | pipe = sc.specPipes[specPipe] 1126 | } 1127 | if pipe == nil { 1128 | return 1129 | } 1130 | go func() { 1131 | callback := func(conn net.Conn, sessionId, action, content string) { 1132 | if sc != nil { 1133 | sc.OnTunnelRecv(conn, sessionId, action, content) 1134 | } 1135 | } 1136 | common.Read(pipe, callback) 1137 | log.Println("client end read", index) 1138 | if index >= 0 { 1139 | delete(sc.pipes, index) 1140 | if clientType == 1 { 1141 | if len(sc.pipes) == 0 { 1142 | if remoteConn != nil { 1143 | remoteConn.Close() 1144 | } 1145 | } 1146 | } 1147 | } else { 1148 | delete(sc.specPipes, specPipe) 1149 | } 1150 | }() 1151 | } 1152 | 1153 | func (sc *Client) LocalAddr() net.Addr { return nil } 1154 | func (sc *Client) Close() error { return nil } 1155 | func (sc *Client) RemoteAddr() net.Addr { return nil } 1156 | func (sc *Client) SetDeadline(t time.Time) error { return nil } 1157 | func (sc *Client) SetReadDeadline(t time.Time) error { return nil } 1158 | func (sc *Client) SetWriteDeadline(t time.Time) error { return nil } 1159 | 1160 | func handleLocalPortResponse(client *Client, id string) { 1161 | sessionId := id 1162 | if !client.bUdp { 1163 | arr := strings.Split(id, "-") 1164 | sessionId = arr[1] 1165 | } 1166 | session := client.getSession(sessionId) 1167 | if session == nil { 1168 | return 1169 | } 1170 | conn := session.localConn 1171 | if conn == nil { 1172 | return 1173 | } 1174 | arr := make([]byte, 1000) 1175 | reader := bufio.NewReader(conn) 1176 | for { 1177 | size, err := reader.Read(arr) 1178 | if err != nil { 1179 | break 1180 | } 1181 | if common.Write(session.pipe, id, "tunnel_msg_s", string(arr[0:size])) != nil { 1182 | break 1183 | } 1184 | } 1185 | // log.Println("handlerlocal down") 1186 | if client.removeSession(sessionId) { 1187 | common.Write(session.pipe, id, "tunnel_close_s", "") 1188 | } 1189 | } 1190 | 1191 | func handleLocalServerResponse(client *Client, sessionId string) { 1192 | session := client.getSession(sessionId) 1193 | if session == nil { 1194 | return 1195 | } 1196 | pipe := session.pipe 1197 | if pipe == nil { 1198 | return 1199 | } 1200 | conn := session.localConn 1201 | common.Write(pipe, sessionId, "tunnel_open", "") 1202 | arr := make([]byte, 1000) 1203 | reader := bufio.NewReader(conn) 1204 | for { 1205 | size, err := reader.Read(arr) 1206 | if err != nil { 1207 | break 1208 | } 1209 | if common.Write(pipe, sessionId, "tunnel_msg_c", string(arr[0:size])) != nil { 1210 | break 1211 | } 1212 | } 1213 | common.Write(pipe, sessionId, "tunnel_close", "") 1214 | client.removeSession(sessionId) 1215 | } 1216 | --------------------------------------------------------------------------------