├── .envrc ├── .gitignore ├── README.md ├── client └── main.go └── server └── main.go /.envrc: -------------------------------------------------------------------------------- 1 | export GO_CURRENT_PROJECT=finaltun 2 | export GO_CURRENT_PACKAGE=github.com/tcz001 3 | export GLOBAL_GOPATH=$HOME/.gopath 4 | export LOCAL_GOPATH=$HOME/.gopkgs/$GO_CURRENT_PROJECT 5 | export GOPATH=$LOCAL_GOPATH:$GLOBAL_GOPATH 6 | 7 | PATH_add $LOCAL_GOPATH/bin 8 | mkdir -p $LOCAL_GOPATH 9 | mkdir -p $LOCAL_GOPATH/src 10 | mkdir -p $LOCAL_GOPATH/pkg 11 | mkdir -p $LOCAL_GOPATH/bin 12 | mkdir -p $LOCAL_GOPATH/src/$GO_CURRENT_PACKAGE 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | client/client 27 | server/server 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > Still in active development, don't use it for now 2 | 3 | # FinalTun 4 | Inspired by KCPTun and FinalSpeed 5 | 6 | ``` 7 | 8 | +---------------------------------------+ 9 | | | 10 | | FinalTun | 11 | | | 12 | +--------+ | +------------+ +------------+ | +--------+ 13 | | | | | | | | | | | 14 | | Client | +--> | |Final Client| +---> |Final Client| | +--> | Server | 15 | | | | | | | | | | | 16 | +--------+ | +------------+ +------------+ | +--------+ 17 | | | 18 | | | 19 | +---------------------------------------+ 20 | 21 | ``` 22 | 23 | # Quick Start 24 | 25 | 1. 假定服务器IP为: `xxx.xxx.xxx.xxx` 26 | 27 | 2. 在服务器端开启ssh -D (监听127.0.0.1:8080端口, 其他proxy工具也可以) 28 | `ssh -D 127.0.0.1:8080 user@localhost` 29 | 30 | 3. 在服务器启动finaltun server: 31 | `server -t "127.0.0.1:8080" -m tcp/kcp` // 所有数据包转发到sshd进程的socks 8080端口 32 | 33 | ---------------------------- 分割线,上面是服务器,下面是客户端 ---------------------------- 34 | 4. 在本地启动finaltun client 35 | `client -r "xxx.xxx.xxx.xxx:29900" -m tcp/kcp` // 连接到finaltun server,默认finaltun server端口是29900 36 | 37 | 5. 浏览器就可以连接12948端口进行socks5代理访问了。 // 默认finaltun client的端口是12948 38 | -------------------------------------------------------------------------------- /client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "log" 7 | "math/rand" 8 | "net" 9 | "os" 10 | "time" 11 | 12 | "github.com/google/gopacket" 13 | "github.com/google/gopacket/layers" 14 | "github.com/xtaci/kcp-go" 15 | 16 | "github.com/codegangsta/cli" 17 | ) 18 | 19 | const ( 20 | BUFSIZ = 65536 21 | ) 22 | 23 | var ( 24 | ch_buf chan []byte 25 | ch_tun chan gopacket.Packet 26 | iv []byte = []byte{147, 243, 201, 109, 83, 207, 190, 153, 204, 106, 86, 122, 71, 135, 200, 20} 27 | ) 28 | 29 | func init() { 30 | ch_buf = make(chan []byte, 1024) 31 | ch_tun = make(chan gopacket.Packet, 1024) 32 | go func() { 33 | for { 34 | ch_buf <- make([]byte, BUFSIZ) 35 | } 36 | }() 37 | 38 | rand.Seed(time.Now().UnixNano()) 39 | } 40 | 41 | func main() { 42 | cliApp := cli.NewApp() 43 | cliApp.Name = "finaltun" 44 | cliApp.Usage = "finaltun client" 45 | cliApp.Version = "1.0" 46 | cliApp.Flags = []cli.Flag{ 47 | cli.StringFlag{ 48 | Name: "mode,m", 49 | Value: "tcp", 50 | Usage: "transportation mode can be tcp/kcp/fs", 51 | }, 52 | cli.StringFlag{ 53 | Name: "device,d", 54 | Value: "lo0", 55 | Usage: "device ethernet:", 56 | }, 57 | cli.StringFlag{ 58 | Name: "port,p", 59 | Value: "12948", 60 | Usage: "local listen port:", 61 | }, 62 | cli.StringFlag{ 63 | Name: "remoteaddr, r", 64 | Value: "127.0.0.1:29900", 65 | Usage: "finaltun server addr", 66 | }, 67 | cli.StringFlag{ 68 | Name: "key", 69 | Value: "it's a secrect", 70 | Usage: "key for communcation, must be the same as finaltun server", 71 | }, 72 | } 73 | cliApp.Action = func(c *cli.Context) { 74 | addr, err := net.ResolveTCPAddr("tcp", ":"+c.String("port")) 75 | checkError(err) 76 | listener, err := net.ListenTCP("tcp", addr) 77 | checkError(err) 78 | log.Println("listening on:", listener.Addr()) 79 | for { 80 | conn, err := listener.AcceptTCP() 81 | if err != nil { 82 | log.Println("accept failed:", err) 83 | continue 84 | } 85 | go handleClient(conn, c) 86 | } 87 | } 88 | cliApp.Run(os.Args) 89 | } 90 | 91 | func peer(sess_die chan struct{}, c *cli.Context) (net.Conn, <-chan []byte) { 92 | switch c.String("mode") { 93 | case "tcp": 94 | return tcpPeer(sess_die, c.String("remoteaddr"), c.String("key")) 95 | case "kcp": 96 | return kcpPeer(sess_die, c.String("remoteaddr"), c.String("key")) 97 | case "fs": 98 | return fsPeer(sess_die, c.String("remoteaddr"), c.String("key"), c.String("device"), c.String("port")) 99 | default: 100 | panic("mode not support") 101 | } 102 | } 103 | 104 | func tcpPeer(sess_die chan struct{}, remote string, key string) (net.Conn, <-chan []byte) { 105 | conn, err := net.Dial("tcp", remote) 106 | if err != nil { 107 | log.Println(err) 108 | return nil, nil 109 | } 110 | ch := make(chan []byte, 1024) 111 | 112 | go func() { 113 | defer func() { 114 | close(ch) 115 | }() 116 | 117 | //decoder 118 | commkey := make([]byte, 32) 119 | copy(commkey, []byte(key)) 120 | block, err := aes.NewCipher(commkey) 121 | if err != nil { 122 | log.Println(err) 123 | return 124 | } 125 | decoder := cipher.NewCTR(block, iv) 126 | 127 | for { 128 | conn.SetReadDeadline(time.Now().Add(2 * time.Minute)) 129 | bts := <-ch_buf 130 | if n, err := conn.Read(bts); err == nil { 131 | bts = bts[:n] 132 | decoder.XORKeyStream(bts, bts) 133 | } else if err, ok := err.(*net.OpError); ok && err.Timeout() { 134 | continue 135 | } else { 136 | log.Println(err) 137 | return 138 | } 139 | 140 | select { 141 | case ch <- bts: 142 | case <-sess_die: 143 | return 144 | } 145 | } 146 | }() 147 | return conn, ch 148 | } 149 | 150 | func kcpPeer(sess_die chan struct{}, remote string, key string) (net.Conn, <-chan []byte) { 151 | conn, err := kcp.DialEncrypted(kcp.MODE_FAST, remote, []byte(key)) 152 | if err != nil { 153 | log.Fatal(err) 154 | return nil, nil 155 | } 156 | ch := make(chan []byte, 1024) 157 | 158 | conn.SetWindowSize(128, 1024) 159 | go func() { 160 | defer func() { 161 | close(ch) 162 | }() 163 | 164 | //decoder 165 | commkey := make([]byte, 32) 166 | copy(commkey, []byte(key)) 167 | block, err := aes.NewCipher(commkey) 168 | if err != nil { 169 | log.Println(err) 170 | return 171 | } 172 | decoder := cipher.NewCTR(block, iv) 173 | 174 | for { 175 | conn.SetReadDeadline(time.Now().Add(2 * time.Minute)) 176 | bts := <-ch_buf 177 | if n, err := conn.Read(bts); err == nil { 178 | bts = bts[:n] 179 | decoder.XORKeyStream(bts, bts) 180 | } else if err, ok := err.(*net.OpError); ok && err.Timeout() { 181 | continue 182 | } else { 183 | log.Println(err) 184 | return 185 | } 186 | 187 | select { 188 | case ch <- bts: 189 | case <-sess_die: 190 | return 191 | } 192 | } 193 | }() 194 | return conn, ch 195 | } 196 | 197 | func fsPeer(sess_die chan struct{}, remote string, key string, device string, port string) (net.Conn, <-chan []byte) { 198 | // TODO: conn := FSConn{} 199 | conn, err := net.Dial("tcp", remote) 200 | if err != nil { 201 | log.Fatal(err) 202 | return nil, nil 203 | } 204 | ch := make(chan []byte, 1024) 205 | go func() { 206 | defer func() { 207 | close(ch) 208 | }() 209 | //decoder 210 | commkey := make([]byte, 32) 211 | copy(commkey, []byte(key)) 212 | block, err := aes.NewCipher(commkey) 213 | if err != nil { 214 | log.Println(err) 215 | return 216 | } 217 | decoder := cipher.NewCTR(block, iv) 218 | 219 | for { 220 | conn.SetReadDeadline(time.Now().Add(2 * time.Minute)) 221 | bts := <-ch_buf 222 | if n, err := conn.Read(bts); err == nil { 223 | bts = bts[:n] 224 | decoder.XORKeyStream(bts, bts) 225 | } else if err, ok := err.(*net.OpError); ok && err.Timeout() { 226 | continue 227 | } else { 228 | log.Println(err) 229 | return 230 | } 231 | 232 | packet := gopacket.NewPacket(bts, layers.LayerTypeTCP, gopacket.Default) 233 | resend := handlePacket(packet) 234 | 235 | select { 236 | case ch <- bts: 237 | if resend { 238 | // TODO: btc.serialNumber++ 239 | // ch <- bts 240 | } 241 | case <-sess_die: 242 | return 243 | } 244 | } 245 | }() 246 | return conn, ch 247 | } 248 | 249 | type FSConn struct{} 250 | 251 | func (FSConn) Read(b []byte) (n int, err error) { 252 | return 0, nil 253 | } 254 | func (FSConn) Write(b []byte) (n int, err error) { 255 | return 0, nil 256 | } 257 | func (FSConn) Close() error { 258 | return nil 259 | } 260 | func (FSConn) LocalAddr() net.Addr { 261 | return nil 262 | } 263 | func (FSConn) RemoteAddr() net.Addr { 264 | return nil 265 | } 266 | func (FSConn) SetDeadline(t time.Time) error { 267 | return nil 268 | } 269 | func (FSConn) SetReadDeadline(t time.Time) error { 270 | return nil 271 | } 272 | func (FSConn) SetWriteDeadline(t time.Time) error { 273 | return nil 274 | } 275 | 276 | func client(conn net.Conn, sess_die chan struct{}, c *cli.Context) <-chan []byte { 277 | ch := make(chan []byte, 1024) 278 | go func() { 279 | defer func() { 280 | close(ch) 281 | }() 282 | 283 | // encoder 284 | commkey := make([]byte, 32) 285 | copy(commkey, []byte(c.String("key"))) 286 | block, err := aes.NewCipher(commkey) 287 | if err != nil { 288 | log.Println(err) 289 | return 290 | } 291 | encoder := cipher.NewCTR(block, iv) 292 | 293 | for { 294 | bts := <-ch_buf 295 | n, err := conn.Read(bts) 296 | if err != nil { 297 | log.Println(err) 298 | return 299 | } 300 | bts = bts[:n] 301 | 302 | packet := gopacket.NewPacket(bts, layers.LayerTypeTCP, gopacket.Default) 303 | resend := handlePacket(packet) && (c.String("mode") == "fs") 304 | 305 | encoder.XORKeyStream(bts, bts) 306 | select { 307 | case ch <- bts: 308 | if resend { 309 | // TODO: btc.serialNumber++ 310 | // ch <- bts 311 | } 312 | case <-sess_die: 313 | return 314 | } 315 | } 316 | }() 317 | return ch 318 | } 319 | 320 | func handleClient(conn *net.TCPConn, c *cli.Context) { 321 | log.Println("stream opened") 322 | defer log.Println("stream closed") 323 | sess_die := make(chan struct{}) 324 | defer func() { 325 | close(sess_die) 326 | conn.Close() 327 | }() 328 | 329 | conn_peer, ch_peer := peer(sess_die, c) 330 | ch_client := client(conn, sess_die, c) 331 | if conn_peer == nil { 332 | return 333 | } 334 | defer conn_peer.Close() 335 | 336 | for { 337 | select { 338 | case bts, ok := <-ch_peer: 339 | if !ok { 340 | return 341 | } 342 | if _, err := conn.Write(bts); err != nil { 343 | log.Println(err) 344 | return 345 | } 346 | case bts, ok := <-ch_client: 347 | if !ok { 348 | return 349 | } 350 | if _, err := conn_peer.Write(bts); err != nil { 351 | log.Println(err) 352 | return 353 | } 354 | } 355 | } 356 | } 357 | 358 | func checkError(err error) { 359 | if err != nil { 360 | log.Println(err) 361 | os.Exit(-1) 362 | } 363 | } 364 | 365 | func handlePacket(packet gopacket.Packet) bool { 366 | mac, ok := packet.LinkLayer().(*layers.Ethernet) 367 | if ok { 368 | log.Println("Ethernet", mac.LinkFlow()) 369 | } 370 | ip, ok := packet.NetworkLayer().(*layers.IPv4) 371 | if ok { 372 | log.Println("IPv4", ip.NetworkFlow()) 373 | } 374 | tcp, ok := packet.TransportLayer().(*layers.TCP) 375 | if ok { 376 | if tcp.SYN && !tcp.ACK { 377 | log.Println("Sent NO1 handshake: ") 378 | return true 379 | } 380 | if tcp.SYN && tcp.ACK { 381 | log.Println("Receive NO2 handshake: ") 382 | } 383 | if !tcp.SYN && tcp.ACK && len(tcp.LayerPayload()) != 0 { 384 | return true 385 | log.Println("Sent NO3 handshake: ") 386 | log.Println("data", len(tcp.LayerPayload())) 387 | } 388 | log.Println("TCP", tcp.TransportFlow()) 389 | } 390 | return false 391 | } 392 | -------------------------------------------------------------------------------- /server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "log" 7 | "math/rand" 8 | "net" 9 | "os" 10 | "time" 11 | 12 | "github.com/codegangsta/cli" 13 | "github.com/xtaci/kcp-go" 14 | ) 15 | 16 | const ( 17 | BUFSIZ = 65536 18 | ) 19 | 20 | var ( 21 | ch_buf chan []byte 22 | iv []byte = []byte{147, 243, 201, 109, 83, 207, 190, 153, 204, 106, 86, 122, 71, 135, 200, 20} 23 | ) 24 | 25 | func init() { 26 | ch_buf = make(chan []byte, 1024) 27 | go func() { 28 | for { 29 | ch_buf <- make([]byte, BUFSIZ) 30 | } 31 | }() 32 | rand.Seed(time.Now().UnixNano()) 33 | } 34 | 35 | func main() { 36 | serverApp := cli.NewApp() 37 | serverApp.Name = "finaltun" 38 | serverApp.Usage = "finaltun server" 39 | serverApp.Version = "1.0" 40 | serverApp.Flags = []cli.Flag{ 41 | cli.StringFlag{ 42 | Name: "mode,m", 43 | Value: "kcp", 44 | Usage: "transportation mode", 45 | }, 46 | cli.StringFlag{ 47 | Name: "listen,l", 48 | Value: ":29900", 49 | Usage: "finaltun server listen addr:", 50 | }, 51 | cli.StringFlag{ 52 | Name: "target, t", 53 | Value: "127.0.0.1:12948", 54 | Usage: "target server addr", 55 | }, 56 | cli.StringFlag{ 57 | Name: "key", 58 | Value: "it's a secrect", 59 | Usage: "key for communcation, must be the same as finaltun client", 60 | }, 61 | } 62 | serverApp.Action = func(c *cli.Context) { 63 | switch c.String("mode") { 64 | case "kcp": 65 | lis, err := kcp.ListenEncrypted(kcp.MODE_FAST, c.String("listen"), []byte(c.String("key"))) 66 | if err != nil { 67 | log.Fatal(err) 68 | } 69 | log.Println("listening on ", lis.Addr()) 70 | for { 71 | if conn, err := lis.Accept(); err == nil { 72 | conn.SetWindowSize(1024, 128) 73 | go handleClient(conn, c.String("target"), c.String("key")) 74 | } else { 75 | log.Println(err) 76 | } 77 | } 78 | break 79 | case "tcp": 80 | lis, err := net.Listen("tcp", c.String("listen")) 81 | if err != nil { 82 | log.Fatal(err) 83 | } 84 | log.Println("listening on ", lis.Addr()) 85 | for { 86 | if conn, err := lis.Accept(); err == nil { 87 | go handleClient(conn, c.String("target"), c.String("key")) 88 | } else { 89 | log.Println(err) 90 | } 91 | } 92 | break 93 | default: 94 | panic("mode not support") 95 | } 96 | 97 | } 98 | serverApp.Run(os.Args) 99 | } 100 | 101 | func peer(conn net.Conn, sess_die chan struct{}, key string) chan []byte { 102 | ch := make(chan []byte, 1024) 103 | go func() { 104 | defer func() { 105 | close(ch) 106 | }() 107 | 108 | //decoder 109 | commkey := make([]byte, 32) 110 | copy(commkey, []byte(key)) 111 | block, err := aes.NewCipher(commkey) 112 | if err != nil { 113 | log.Println(err) 114 | return 115 | } 116 | decoder := cipher.NewCTR(block, iv) 117 | 118 | for { 119 | conn.SetReadDeadline(time.Now().Add(2 * time.Minute)) 120 | bts := <-ch_buf 121 | if n, err := conn.Read(bts); err == nil { 122 | bts = bts[:n] 123 | decoder.XORKeyStream(bts, bts) 124 | } else if err, ok := err.(*net.OpError); ok && err.Timeout() { 125 | continue 126 | } else { 127 | log.Println(err) 128 | return 129 | } 130 | 131 | select { 132 | case ch <- bts: 133 | case <-sess_die: 134 | return 135 | } 136 | } 137 | }() 138 | return ch 139 | } 140 | 141 | func endpoint(sess_die chan struct{}, target string, key string) (net.Conn, <-chan []byte) { 142 | conn, err := net.Dial("tcp", target) 143 | if err != nil { 144 | log.Println(err) 145 | return nil, nil 146 | } 147 | 148 | ch := make(chan []byte, 1024) 149 | go func() { 150 | defer func() { 151 | close(ch) 152 | }() 153 | 154 | // encoder 155 | commkey := make([]byte, 32) 156 | copy(commkey, []byte(key)) 157 | block, err := aes.NewCipher(commkey) 158 | if err != nil { 159 | log.Println(err) 160 | return 161 | } 162 | encoder := cipher.NewCTR(block, iv) 163 | 164 | for { 165 | bts := <-ch_buf 166 | n, err := conn.Read(bts) 167 | if err != nil { 168 | log.Println(err) 169 | return 170 | } 171 | 172 | bts = bts[:n] 173 | encoder.XORKeyStream(bts, bts) 174 | select { 175 | case ch <- bts: 176 | case <-sess_die: 177 | return 178 | } 179 | } 180 | }() 181 | return conn, ch 182 | } 183 | 184 | func handleClient(conn net.Conn, target string, key string) { 185 | log.Println("stream open") 186 | defer log.Println("stream close") 187 | sess_die := make(chan struct{}) 188 | defer func() { 189 | close(sess_die) 190 | conn.Close() 191 | }() 192 | 193 | ch_peer := peer(conn, sess_die, key) 194 | conn_ep, ch_ep := endpoint(sess_die, target, key) 195 | if conn_ep == nil { 196 | return 197 | } 198 | defer conn_ep.Close() 199 | 200 | for { 201 | select { 202 | case bts, ok := <-ch_peer: 203 | if !ok { 204 | return 205 | } 206 | if _, err := conn_ep.Write(bts); err != nil { 207 | log.Println(err) 208 | return 209 | } 210 | case bts, ok := <-ch_ep: 211 | if !ok { 212 | return 213 | } 214 | if _, err := conn.Write(bts); err != nil { 215 | log.Println(err) 216 | return 217 | } 218 | } 219 | } 220 | } 221 | --------------------------------------------------------------------------------