├── .gitignore ├── LICENSE ├── README.md ├── cmd ├── waVingOceanConfigureFileElaboration │ └── main.go └── waVingOceanIgnite │ └── main.go ├── configure ├── Base.proto └── Makefile ├── definition └── interfaces.go ├── lowerup.go ├── master.go ├── v2dialer.go ├── vendor └── github.com │ └── yinghuocho │ └── gotun2socks │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── gotun2socks.go │ ├── internal │ └── packet │ │ ├── common.go │ │ ├── ip4.go │ │ ├── tcp.go │ │ └── udp.go │ ├── ip.go │ ├── mtubuf.go │ ├── tcp.go │ ├── tun │ ├── stop.go │ ├── tun_darwin.go │ ├── tun_linux.go │ └── tun_windows.go │ └── udp.go └── wavingocean.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | 16 | *.pb.go 17 | 18 | conf/ 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Xiaokang Wang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # waVingOcean -------------------------------------------------------------------------------- /cmd/waVingOceanConfigureFileElaboration/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "os" 7 | 8 | "github.com/golang/protobuf/proto" 9 | "github.com/ld9999999999/go-interfacetools" 10 | "github.com/nahanni/go-ucl" 11 | "github.com/xiaokangwang/waVingOcean/configure" 12 | ) 13 | 14 | func main() { 15 | switch os.Args[1] { 16 | case "T": 17 | par := ucl.NewParser(os.Stdin) 18 | out, err := par.Ucl() 19 | if err != nil { 20 | panic(err) 21 | } 22 | conffile := new(configure.WaVingOceanConfigure) 23 | err = interfacetools.CopyOut(out, conffile) 24 | if err != nil { 25 | panic(err) 26 | } 27 | pbout, err := proto.Marshal(conffile) 28 | if err != nil { 29 | panic(err) 30 | } 31 | io.Copy(os.Stdout, bytes.NewBuffer(pbout)) 32 | case "V": 33 | var inv2buf bytes.Buffer 34 | io.Copy(&inv2buf, os.Stdin) 35 | cfgfd, err := os.Open(os.Args[2]) 36 | if err != nil { 37 | panic(err) 38 | } 39 | var incfbuf bytes.Buffer 40 | io.Copy(&incfbuf, cfgfd) 41 | cfgfd.Close() 42 | conffile := new(configure.WaVingOceanConfigure) 43 | err = proto.Unmarshal(incfbuf.Bytes(), conffile) 44 | if err != nil { 45 | panic(err) 46 | } 47 | conffile.V2RayConfigure = inv2buf.Bytes() 48 | pbout, err := proto.Marshal(conffile) 49 | if err != nil { 50 | panic(err) 51 | } 52 | io.Copy(os.Stdout, bytes.NewBuffer(pbout)) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /cmd/waVingOceanIgnite/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "os" 7 | ) 8 | import ( 9 | "github.com/golang/protobuf/proto" 10 | "github.com/xiaokangwang/waVingOcean" 11 | "github.com/xiaokangwang/waVingOcean/configure" 12 | ) 13 | 14 | func main() { 15 | var inbuf bytes.Buffer 16 | io.Copy(&inbuf, os.Stdin) 17 | conffile := new(configure.WaVingOceanConfigure) 18 | err := proto.Unmarshal(inbuf.Bytes(), conffile) 19 | if err != nil { 20 | panic(err) 21 | } 22 | wavingocean.Ignite(*conffile) 23 | } 24 | -------------------------------------------------------------------------------- /configure/Base.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option go_package = "configure"; 4 | 5 | message waVingOceanConfigureTunCfg { 6 | string Name = 1; 7 | string Address = 2; 8 | string Gateway = 3; 9 | string Mask = 4; 10 | } 11 | message waVingOceanConfigure { 12 | bytes V2RayConfigure = 1; 13 | waVingOceanConfigureTunCfg tun = 2; 14 | repeated string DNSServers = 3; 15 | bool PublicOnly = 4; 16 | bool EnableDnsCache = 5; 17 | } 18 | -------------------------------------------------------------------------------- /configure/Makefile: -------------------------------------------------------------------------------- 1 | pb: 2 | protoc --go_out=. *.proto 3 | -------------------------------------------------------------------------------- /definition/interfaces.go: -------------------------------------------------------------------------------- 1 | package definition 2 | 3 | import ( 4 | "context" 5 | "net" 6 | ) 7 | 8 | /* 9 | SurrogateDialer represent a Dial interface 10 | for connections that needs to be transmited 11 | with an alternative tunnel 12 | */ 13 | type SurrogateDialer interface { 14 | Dial(network, address string, port uint16, ctx context.Context) (net.Conn, error) 15 | NotifyMeltdown(reason error) 16 | } 17 | -------------------------------------------------------------------------------- /lowerup.go: -------------------------------------------------------------------------------- 1 | package wavingocean 2 | 3 | import ( 4 | "context" 5 | "io" 6 | 7 | "github.com/xiaokangwang/waVingOcean/configure" 8 | "github.com/xiaokangwang/waVingOcean/definition" 9 | "github.com/yinghuocho/gotun2socks" 10 | ) 11 | 12 | type LowerUp struct { 13 | tuns *gotun2socks.Tun2Socks 14 | } 15 | 16 | func NewLowerUp(cfg configure.WaVingOceanConfigure, f io.ReadWriteCloser, dialer definition.SurrogateDialer, ctx context.Context) *LowerUp { 17 | tunc := gotun2socks.New(f, dialer, cfg.DNSServers, cfg.PublicOnly, cfg.EnableDnsCache, ctx) 18 | return &LowerUp{tuns: tunc} 19 | } 20 | 21 | func (l *LowerUp) Up() { 22 | l.tuns.Run() 23 | } 24 | 25 | func (l *LowerUp) Down() { 26 | l.tuns.Stop() 27 | } 28 | -------------------------------------------------------------------------------- /master.go: -------------------------------------------------------------------------------- 1 | package wavingocean 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | 7 | "github.com/xiaokangwang/waVingOcean/configure" 8 | "github.com/yinghuocho/gotun2socks" 9 | "github.com/yinghuocho/gotun2socks/tun" 10 | "v2ray.com/core" 11 | 12 | //load v2ray init codes 13 | _ "v2ray.com/core/main/distro/all" 14 | ) 15 | 16 | /*Ignite Start Tap server from configure 17 | */ 18 | func Ignite(cfg configure.WaVingOceanConfigure) { 19 | //Start V2Ray 20 | configure, err := core.LoadConfig("protobuf","", bytes.NewBuffer(cfg.V2RayConfigure)) 21 | if err != nil { 22 | panic(err) 23 | } 24 | ns, err := core.New(configure) 25 | if err != nil { 26 | panic(err) 27 | } 28 | err = ns.Start() 29 | if err != nil { 30 | panic(err) 31 | } 32 | 33 | //Start Tap 34 | f, e := tun.OpenTunDevice(cfg.Tun.Name, cfg.Tun.Address, cfg.Tun.Gateway, cfg.Tun.Mask, cfg.DNSServers) 35 | if e != nil { 36 | panic(e) 37 | } 38 | //Start Tun2Socks 39 | ctx := context.Background() 40 | tunc := gotun2socks.New(f, &V2Dialer{ser: ns}, cfg.DNSServers, cfg.PublicOnly, cfg.EnableDnsCache, ctx) 41 | tunc.Run() 42 | } 43 | -------------------------------------------------------------------------------- /v2dialer.go: -------------------------------------------------------------------------------- 1 | package wavingocean 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "net" 7 | "strconv" 8 | 9 | "v2ray.com/core" 10 | v2net "v2ray.com/core/common/net" 11 | ) 12 | 13 | type V2Dialer struct { 14 | ser *core.Instance 15 | } 16 | 17 | func (vd *V2Dialer) Dial(network, address string, port uint16, ctx context.Context) (net.Conn, error) { 18 | var dest net.Addr 19 | var err error 20 | switch network { 21 | case "tcp4": 22 | dest, err = net.ResolveTCPAddr(network, address+":"+strconv.Itoa(int(port))) 23 | log.Println(err) 24 | case "udp4": 25 | dest, err = net.ResolveUDPAddr(network, address+":"+strconv.Itoa(int(port))) 26 | log.Println(err) 27 | } 28 | v2dest := v2net.DestinationFromAddr(dest) 29 | return core.Dial(ctx, vd.ser, v2dest) 30 | } 31 | 32 | func (vd *V2Dialer) NotifyMeltdown(reason error) {} 33 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/.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 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, yinghuocho 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/README.md: -------------------------------------------------------------------------------- 1 | # gotun2socks 2 | 3 | A Golang implementation of tun2socks, including a library and a binary program. 4 | 5 | The binary program works on Linux, OS X and Windows. 6 | 7 | ## Usage 8 | 9 | Windows users need to install TAP-windows driver first. 10 | 11 | The binary program will create tun/tap device, config its IP address. On Windows, it also configs DNS resolvers of the opened tun/tap device. 12 | 13 | Users need to change routing table so that packets are sent through the tun/tap device. Generaly the process includes changing default route to the tun/tap device, and exclude IP addresses of remote servers to go through the original network device so that traffic forwarded from local SOCKS5 proxy to remote servers would not loop back. See Tun2Socks Introduction for how to change routing table. Linux and OS X users may also need to change system DNS resolvers in case the resolvers are not accessible by remote servers. 14 | 15 | ## UDP forwarding 16 | 17 | This implementation forwards UDP using standard SOCKS5 UDP request/reply. Thus to make UDP-based protocols (such as DNS) work, it needs to be chained with a UDP-enabled SOCKS5 proxy. 18 | 19 | 20 | ## Credits 21 | 22 | - https://github.com/google/gopacket 23 | - https://github.com/ambrop72/badvpn/ 24 | - https://github.com/songgao/water 25 | - https://github.com/FlexibleBroadband/tun-go 26 | 27 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/gotun2socks.go: -------------------------------------------------------------------------------- 1 | package gotun2socks 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "log" 7 | "net" 8 | "sync" 9 | 10 | "github.com/yinghuocho/gotun2socks/internal/packet" 11 | 12 | "github.com/xiaokangwang/waVingOcean/definition" 13 | ) 14 | 15 | const ( 16 | MTU = 1500 17 | ) 18 | 19 | var ( 20 | _, ip1, _ = net.ParseCIDR("10.0.0.0/8") 21 | _, ip2, _ = net.ParseCIDR("172.16.0.0/12") 22 | _, ip3, _ = net.ParseCIDR("192.168.0.0/24") 23 | ) 24 | 25 | type Tun2Socks struct { 26 | dev io.ReadWriteCloser 27 | localSocksAddr string 28 | publicOnly bool 29 | 30 | writerStopCh chan bool 31 | writeCh chan interface{} 32 | 33 | tcpConnTrackLock sync.Mutex 34 | tcpConnTrackMap map[string]*tcpConnTrack 35 | 36 | udpConnTrackLock sync.Mutex 37 | udpConnTrackMap map[string]*udpConnTrack 38 | 39 | dnsServers []string 40 | cache *dnsCache 41 | 42 | wg sync.WaitGroup 43 | 44 | ctx context.Context 45 | dialer definition.SurrogateDialer 46 | } 47 | 48 | func isPrivate(ip net.IP) bool { 49 | return ip1.Contains(ip) || ip2.Contains(ip) || ip3.Contains(ip) 50 | } 51 | 52 | func New(dev io.ReadWriteCloser, dialer definition.SurrogateDialer, dnsServers []string, publicOnly bool, enableDnsCache bool, ctx context.Context) *Tun2Socks { 53 | t2s := &Tun2Socks{ 54 | dev: dev, 55 | dialer: dialer, 56 | ctx: ctx, 57 | publicOnly: publicOnly, 58 | writerStopCh: make(chan bool, 10), 59 | writeCh: make(chan interface{}, 10000), 60 | tcpConnTrackMap: make(map[string]*tcpConnTrack), 61 | udpConnTrackMap: make(map[string]*udpConnTrack), 62 | dnsServers: dnsServers, 63 | } 64 | if enableDnsCache { 65 | t2s.cache = &dnsCache{ 66 | storage: make(map[string]*dnsCacheEntry), 67 | } 68 | } 69 | return t2s 70 | } 71 | 72 | func (t2s *Tun2Socks) Stop() { 73 | t2s.writerStopCh <- true 74 | t2s.dev.Close() 75 | 76 | t2s.tcpConnTrackLock.Lock() 77 | defer t2s.tcpConnTrackLock.Unlock() 78 | for _, tcpTrack := range t2s.tcpConnTrackMap { 79 | close(tcpTrack.quitByOther) 80 | } 81 | 82 | t2s.udpConnTrackLock.Lock() 83 | defer t2s.udpConnTrackLock.Unlock() 84 | for _, udpTrack := range t2s.udpConnTrackMap { 85 | close(udpTrack.quitByOther) 86 | } 87 | t2s.wg.Wait() 88 | } 89 | 90 | func (t2s *Tun2Socks) Run() { 91 | // writer 92 | go func() { 93 | t2s.wg.Add(1) 94 | defer t2s.wg.Done() 95 | for { 96 | select { 97 | case pkt := <-t2s.writeCh: 98 | switch pkt.(type) { 99 | case *tcpPacket: 100 | tcp := pkt.(*tcpPacket) 101 | t2s.dev.Write(tcp.wire) 102 | releaseTCPPacket(tcp) 103 | case *udpPacket: 104 | udp := pkt.(*udpPacket) 105 | t2s.dev.Write(udp.wire) 106 | releaseUDPPacket(udp) 107 | case *ipPacket: 108 | ip := pkt.(*ipPacket) 109 | t2s.dev.Write(ip.wire) 110 | releaseIPPacket(ip) 111 | } 112 | case <-t2s.writerStopCh: 113 | log.Printf("quit tun2socks writer") 114 | return 115 | case <-t2s.ctx.Done(): 116 | log.Printf("quit tun2socks writer: Context is done") 117 | return 118 | } 119 | } 120 | }() 121 | 122 | // reader 123 | var buf [MTU]byte 124 | var ip packet.IPv4 125 | var tcp packet.TCP 126 | var udp packet.UDP 127 | 128 | t2s.wg.Add(1) 129 | defer t2s.wg.Done() 130 | for { 131 | if t2s.ctx.Err() != nil { 132 | log.Printf("quit tun2socks reader: Context is done") 133 | return 134 | } 135 | n, e := t2s.dev.Read(buf[:]) 136 | if e != nil { 137 | // TODO: stop at critical error 138 | log.Printf("read packet error: %s", e) 139 | return 140 | } 141 | data := buf[:n] 142 | e = packet.ParseIPv4(data, &ip) 143 | if e != nil { 144 | log.Printf("error to parse IPv4: %s", e) 145 | continue 146 | } 147 | if t2s.publicOnly { 148 | if !ip.DstIP.IsGlobalUnicast() { 149 | continue 150 | } 151 | if isPrivate(ip.DstIP) { 152 | continue 153 | } 154 | } 155 | 156 | if ip.Flags&0x1 != 0 || ip.FragOffset != 0 { 157 | last, pkt, raw := procFragment(&ip, data) 158 | if last { 159 | ip = *pkt 160 | data = raw 161 | } else { 162 | continue 163 | } 164 | } 165 | 166 | switch ip.Protocol { 167 | case packet.IPProtocolTCP: 168 | e = packet.ParseTCP(ip.Payload, &tcp) 169 | if e != nil { 170 | log.Printf("error to parse TCP: %s", e) 171 | continue 172 | } 173 | t2s.tcp(data, &ip, &tcp) 174 | 175 | case packet.IPProtocolUDP: 176 | e = packet.ParseUDP(ip.Payload, &udp) 177 | if e != nil { 178 | log.Printf("error to parse UDP: %s", e) 179 | continue 180 | } 181 | t2s.udp(data, &ip, &udp) 182 | 183 | default: 184 | // Unsupported packets 185 | log.Printf("Unsupported packet: protocol %d", ip.Protocol) 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/internal/packet/common.go: -------------------------------------------------------------------------------- 1 | package packet 2 | 3 | var lotsOfZeros [1024]byte 4 | 5 | //func Checksum(data []byte) uint16 { 6 | // var csum uint32 7 | // length := len(data) - 1 8 | // for i := 0; i < length; i += 2 { 9 | // csum += uint32(data[i]) << 8 10 | // csum += uint32(data[i+1]) 11 | // } 12 | // if len(data)%2 == 1 { 13 | // csum += uint32(data[length]) << 8 14 | // } 15 | // for csum > 0xffff { 16 | // csum = (csum >> 16) + (csum & 0xffff) 17 | // } 18 | // return ^uint16(csum + (csum >> 16)) 19 | //} 20 | 21 | func Checksum(fields ...[]byte) uint16 { 22 | var csum uint32 23 | for _, field := range fields { 24 | length := len(field) - 1 25 | for i := 0; i < length; i += 2 { 26 | csum += uint32(field[i]) << 8 27 | csum += uint32(field[i+1]) 28 | } 29 | if len(field)%2 == 1 { 30 | // only last field may have odd number of bytes 31 | csum += uint32(field[length]) << 8 32 | } 33 | } 34 | 35 | for csum > 0xffff { 36 | csum = (csum >> 16) + (csum & 0xffff) 37 | } 38 | return ^uint16(csum + (csum >> 16)) 39 | } 40 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/internal/packet/ip4.go: -------------------------------------------------------------------------------- 1 | package packet 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "net" 7 | "sync" 8 | "sync/atomic" 9 | ) 10 | 11 | type IPv4Option struct { 12 | OptionType uint8 13 | OptionLength uint8 14 | OptionData []byte 15 | } 16 | 17 | // IPProtocol is an enumeration of IP protocol values, and acts as a decoder 18 | // for any type it supports. 19 | type IPProtocol uint8 20 | 21 | const ( 22 | IPProtocolIPv6HopByHop IPProtocol = 0 23 | IPProtocolICMPv4 IPProtocol = 1 24 | IPProtocolIGMP IPProtocol = 2 25 | IPProtocolIPv4 IPProtocol = 4 26 | IPProtocolTCP IPProtocol = 6 27 | IPProtocolUDP IPProtocol = 17 28 | IPProtocolRUDP IPProtocol = 27 29 | IPProtocolIPv6 IPProtocol = 41 30 | IPProtocolIPv6Routing IPProtocol = 43 31 | IPProtocolIPv6Fragment IPProtocol = 44 32 | IPProtocolGRE IPProtocol = 47 33 | IPProtocolESP IPProtocol = 50 34 | IPProtocolAH IPProtocol = 51 35 | IPProtocolICMPv6 IPProtocol = 58 36 | IPProtocolNoNextHeader IPProtocol = 59 37 | IPProtocolIPv6Destination IPProtocol = 60 38 | IPProtocolIPIP IPProtocol = 94 39 | IPProtocolEtherIP IPProtocol = 97 40 | IPProtocolSCTP IPProtocol = 132 41 | IPProtocolUDPLite IPProtocol = 136 42 | IPProtocolMPLSInIP IPProtocol = 137 43 | 44 | IPv4_PSEUDO_LENGTH int = 12 45 | ) 46 | 47 | type IPv4 struct { 48 | Version uint8 49 | IHL uint8 50 | TOS uint8 51 | Length uint16 52 | Id uint16 53 | Flags uint8 54 | FragOffset uint16 55 | TTL uint8 56 | Protocol IPProtocol 57 | Checksum uint16 58 | SrcIP net.IP 59 | DstIP net.IP 60 | Options []IPv4Option 61 | Padding []byte 62 | Payload []byte 63 | 64 | headerLength int 65 | } 66 | 67 | var ( 68 | ipv4Pool *sync.Pool = &sync.Pool{ 69 | New: func() interface{} { 70 | return &IPv4{} 71 | }, 72 | } 73 | 74 | globalIPID uint32 75 | ) 76 | 77 | func ReleaseIPv4(ip4 *IPv4) { 78 | // clear internal slice references 79 | ip4.SrcIP = nil 80 | ip4.DstIP = nil 81 | ip4.Options = nil 82 | ip4.Padding = nil 83 | ip4.Payload = nil 84 | 85 | ipv4Pool.Put(ip4) 86 | } 87 | 88 | func NewIPv4() *IPv4 { 89 | var zero IPv4 90 | ip4 := ipv4Pool.Get().(*IPv4) 91 | *ip4 = zero 92 | return ip4 93 | } 94 | 95 | func IPID() uint16 { 96 | return uint16(atomic.AddUint32(&globalIPID, 1) & 0x0000ffff) 97 | } 98 | 99 | func ParseIPv4(pkt []byte, ip4 *IPv4) error { 100 | flagsfrags := binary.BigEndian.Uint16(pkt[6:8]) 101 | 102 | ip4.Version = uint8(pkt[0]) >> 4 103 | ip4.IHL = uint8(pkt[0]) & 0x0F 104 | ip4.TOS = pkt[1] 105 | ip4.Length = binary.BigEndian.Uint16(pkt[2:4]) 106 | ip4.Id = binary.BigEndian.Uint16(pkt[4:6]) 107 | ip4.Flags = uint8(flagsfrags >> 13) 108 | ip4.FragOffset = flagsfrags & 0x1FFF 109 | ip4.TTL = pkt[8] 110 | ip4.Protocol = IPProtocol(pkt[9]) 111 | ip4.Checksum = binary.BigEndian.Uint16(pkt[10:12]) 112 | ip4.SrcIP = pkt[12:16] 113 | ip4.DstIP = pkt[16:20] 114 | 115 | if ip4.Length < 20 { 116 | return fmt.Errorf("Invalid (too small) IP length (%d < 20)", ip4.Length) 117 | } 118 | if ip4.IHL < 5 { 119 | return fmt.Errorf("Invalid (too small) IP header length (%d < 5)", ip4.IHL) 120 | } 121 | if int(ip4.IHL*4) > int(ip4.Length) { 122 | return fmt.Errorf("Invalid IP header length > IP length (%d > %d)", ip4.IHL, ip4.Length) 123 | } 124 | if int(ip4.IHL)*4 > len(pkt) { 125 | return fmt.Errorf("Not all IP header bytes available") 126 | } 127 | ip4.Payload = pkt[ip4.IHL*4:] 128 | rest := pkt[20 : ip4.IHL*4] 129 | // Pull out IP options 130 | for len(rest) > 0 { 131 | if ip4.Options == nil { 132 | // Pre-allocate to avoid growing the slice too much. 133 | ip4.Options = make([]IPv4Option, 0, 4) 134 | } 135 | opt := IPv4Option{OptionType: rest[0]} 136 | switch opt.OptionType { 137 | case 0: // End of options 138 | opt.OptionLength = 1 139 | ip4.Options = append(ip4.Options, opt) 140 | ip4.Padding = rest[1:] 141 | break 142 | case 1: // 1 byte padding 143 | opt.OptionLength = 1 144 | default: 145 | opt.OptionLength = rest[1] 146 | opt.OptionData = rest[2:opt.OptionLength] 147 | } 148 | if len(rest) >= int(opt.OptionLength) { 149 | rest = rest[opt.OptionLength:] 150 | } else { 151 | return fmt.Errorf("IP option length exceeds remaining IP header size, option type %v length %v", opt.OptionType, opt.OptionLength) 152 | } 153 | ip4.Options = append(ip4.Options, opt) 154 | } 155 | return nil 156 | } 157 | 158 | func (ip *IPv4) PseudoHeader(buf []byte, proto IPProtocol, dataLen int) error { 159 | if len(buf) != IPv4_PSEUDO_LENGTH { 160 | return fmt.Errorf("incorrect buffer size: %d buffer given, %d needed", len(buf), IPv4_PSEUDO_LENGTH) 161 | } 162 | copy(buf[0:4], ip.SrcIP) 163 | copy(buf[4:8], ip.DstIP) 164 | buf[8] = 0 165 | buf[9] = byte(proto) 166 | binary.BigEndian.PutUint16(buf[10:], uint16(dataLen)) 167 | return nil 168 | } 169 | 170 | func (ip *IPv4) HeaderLength() int { 171 | if ip.headerLength == 0 { 172 | optionLength := uint8(0) 173 | for _, opt := range ip.Options { 174 | switch opt.OptionType { 175 | case 0: 176 | // this is the end of option lists 177 | optionLength++ 178 | case 1: 179 | // this is the padding 180 | optionLength++ 181 | default: 182 | optionLength += opt.OptionLength 183 | 184 | } 185 | } 186 | // make sure the options are aligned to 32 bit boundary 187 | if (optionLength % 4) != 0 { 188 | optionLength += 4 - (optionLength % 4) 189 | } 190 | ip.IHL = 5 + (optionLength / 4) 191 | ip.headerLength = int(optionLength) + 20 192 | } 193 | return ip.headerLength 194 | } 195 | 196 | func (ip *IPv4) flagsfrags() (ff uint16) { 197 | ff |= uint16(ip.Flags) << 13 198 | ff |= ip.FragOffset 199 | return 200 | } 201 | 202 | func (ip *IPv4) Serialize(hdr []byte, dataLen int) error { 203 | if len(hdr) != ip.HeaderLength() { 204 | return fmt.Errorf("incorrect buffer size: %d buffer given, %d needed", len(hdr), ip.HeaderLength()) 205 | } 206 | hdr[0] = (ip.Version << 4) | ip.IHL 207 | hdr[1] = ip.TOS 208 | ip.Length = uint16(ip.headerLength + dataLen) 209 | binary.BigEndian.PutUint16(hdr[2:], ip.Length) 210 | binary.BigEndian.PutUint16(hdr[4:], ip.Id) 211 | binary.BigEndian.PutUint16(hdr[6:], ip.flagsfrags()) 212 | hdr[8] = ip.TTL 213 | hdr[9] = byte(ip.Protocol) 214 | copy(hdr[12:16], ip.SrcIP) 215 | copy(hdr[16:20], ip.DstIP) 216 | 217 | curLocation := 20 218 | // Now, we will encode the options 219 | for _, opt := range ip.Options { 220 | switch opt.OptionType { 221 | case 0: 222 | // this is the end of option lists 223 | hdr[curLocation] = 0 224 | curLocation++ 225 | case 1: 226 | // this is the padding 227 | hdr[curLocation] = 1 228 | curLocation++ 229 | default: 230 | hdr[curLocation] = opt.OptionType 231 | hdr[curLocation+1] = opt.OptionLength 232 | 233 | // sanity checking to protect us from buffer overrun 234 | if len(opt.OptionData) > int(opt.OptionLength-2) { 235 | return fmt.Errorf("option length is smaller than length of option data") 236 | } 237 | copy(hdr[curLocation+2:curLocation+int(opt.OptionLength)], opt.OptionData) 238 | curLocation += int(opt.OptionLength) 239 | } 240 | } 241 | hdr[10] = 0 242 | hdr[11] = 0 243 | ip.Checksum = Checksum(hdr) 244 | binary.BigEndian.PutUint16(hdr[10:], ip.Checksum) 245 | return nil 246 | } 247 | 248 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/internal/packet/tcp.go: -------------------------------------------------------------------------------- 1 | package packet 2 | 3 | import ( 4 | "encoding/binary" 5 | "errors" 6 | "fmt" 7 | "sync" 8 | ) 9 | 10 | type TCPOption struct { 11 | OptionType uint8 12 | OptionLength uint8 13 | OptionData []byte 14 | } 15 | 16 | type TCP struct { 17 | SrcPort uint16 18 | DstPort uint16 19 | Seq uint32 20 | Ack uint32 21 | DataOffset uint8 22 | FIN, SYN, RST, PSH, ACK, URG, ECE, CWR, NS bool 23 | Window uint16 24 | Checksum uint16 25 | Urgent uint16 26 | Options []TCPOption 27 | opts [4]TCPOption 28 | Padding []byte 29 | Payload []byte 30 | 31 | headerLength int 32 | } 33 | 34 | var ( 35 | tcpPool *sync.Pool = &sync.Pool{ 36 | New: func() interface{} { 37 | return &TCP{} 38 | }, 39 | } 40 | ) 41 | 42 | func NewTCP() *TCP { 43 | var zero TCP 44 | tcp := tcpPool.Get().(*TCP) 45 | *tcp = zero 46 | return tcp 47 | } 48 | 49 | func ReleaseTCP(tcp *TCP) { 50 | // clear internal slice references 51 | for _, opt := range tcp.Options { 52 | opt.OptionData = nil 53 | } 54 | tcp.Options = nil 55 | tcp.Padding = nil 56 | tcp.Payload = nil 57 | 58 | tcpPool.Put(tcp) 59 | } 60 | 61 | func ParseTCP(pkt []byte, tcp *TCP) error { 62 | if len(pkt) < 20 { 63 | return fmt.Errorf("payload too small for TCP: %d bytes", len(pkt)) 64 | } 65 | 66 | tcp.SrcPort = binary.BigEndian.Uint16(pkt[0:2]) 67 | tcp.DstPort = binary.BigEndian.Uint16(pkt[2:4]) 68 | tcp.Seq = binary.BigEndian.Uint32(pkt[4:8]) 69 | tcp.Ack = binary.BigEndian.Uint32(pkt[8:12]) 70 | tcp.DataOffset = pkt[12] >> 4 71 | tcp.FIN = pkt[13]&0x01 != 0 72 | tcp.SYN = pkt[13]&0x02 != 0 73 | tcp.RST = pkt[13]&0x04 != 0 74 | tcp.PSH = pkt[13]&0x08 != 0 75 | tcp.ACK = pkt[13]&0x10 != 0 76 | tcp.URG = pkt[13]&0x20 != 0 77 | tcp.ECE = pkt[13]&0x40 != 0 78 | tcp.CWR = pkt[13]&0x80 != 0 79 | tcp.NS = pkt[12]&0x01 != 0 80 | tcp.Window = binary.BigEndian.Uint16(pkt[14:16]) 81 | tcp.Checksum = binary.BigEndian.Uint16(pkt[16:18]) 82 | tcp.Urgent = binary.BigEndian.Uint16(pkt[18:20]) 83 | tcp.Options = tcp.opts[:0] 84 | if tcp.DataOffset < 5 { 85 | return fmt.Errorf("Invalid TCP data offset %d < 5", tcp.DataOffset) 86 | } 87 | dataStart := int(tcp.DataOffset) * 4 88 | if dataStart < 20 { 89 | return fmt.Errorf("TCP data offset too small: %d", dataStart) 90 | } 91 | if dataStart > len(pkt) { 92 | return errors.New("TCP data offset greater than packet length") 93 | } 94 | tcp.Payload = pkt[dataStart:] 95 | // From here on, data points just to the header options. 96 | rest := pkt[20:dataStart] 97 | for len(rest) > 0 { 98 | if tcp.Options == nil { 99 | // Pre-allocate to avoid allocating a slice. 100 | tcp.Options = tcp.opts[:0] 101 | } 102 | tcp.Options = append(tcp.Options, TCPOption{OptionType: rest[0]}) 103 | opt := &tcp.Options[len(tcp.Options)-1] 104 | switch opt.OptionType { 105 | case 0: // End of options 106 | opt.OptionLength = 1 107 | tcp.Padding = rest[1:] 108 | break 109 | case 1: // 1 byte padding 110 | opt.OptionLength = 1 111 | default: 112 | opt.OptionLength = rest[1] 113 | if opt.OptionLength < 2 { 114 | return fmt.Errorf("Invalid TCP option length %d < 2", opt.OptionLength) 115 | } else if int(opt.OptionLength) > len(rest) { 116 | return fmt.Errorf("Invalid TCP option length %d exceeds remaining %d bytes", opt.OptionLength, len(pkt)) 117 | } 118 | opt.OptionData = rest[2:opt.OptionLength] 119 | } 120 | rest = rest[opt.OptionLength:] 121 | } 122 | 123 | tcp.headerLength = int(tcp.DataOffset * 4) 124 | return nil 125 | } 126 | 127 | func (tcp *TCP) HeaderLength() int { 128 | if tcp.headerLength == 0 { 129 | optionLength := 0 130 | for _, o := range tcp.Options { 131 | switch o.OptionType { 132 | case 0, 1: 133 | optionLength += 1 134 | default: 135 | optionLength += 2 + len(o.OptionData) 136 | } 137 | } 138 | tcp.Padding = lotsOfZeros[:optionLength%4] 139 | tcp.headerLength = len(tcp.Padding) + optionLength + 20 140 | tcp.DataOffset = uint8(tcp.headerLength / 4) 141 | } 142 | 143 | return tcp.headerLength 144 | } 145 | 146 | func (tcp *TCP) flagsAndOffset() uint16 { 147 | f := uint16(tcp.DataOffset) << 12 148 | if tcp.FIN { 149 | f |= 0x0001 150 | } 151 | if tcp.SYN { 152 | f |= 0x0002 153 | } 154 | if tcp.RST { 155 | f |= 0x0004 156 | } 157 | if tcp.PSH { 158 | f |= 0x0008 159 | } 160 | if tcp.ACK { 161 | f |= 0x0010 162 | } 163 | if tcp.URG { 164 | f |= 0x0020 165 | } 166 | if tcp.ECE { 167 | f |= 0x0040 168 | } 169 | if tcp.CWR { 170 | f |= 0x0080 171 | } 172 | if tcp.NS { 173 | f |= 0x0100 174 | } 175 | return f 176 | } 177 | 178 | func (tcp *TCP) Serialize(hdr []byte, ckFields ...[]byte) error { 179 | if tcp.HeaderLength() != len(hdr) { 180 | return fmt.Errorf("incorrect buffer size: %d buffer given, %d needed", len(hdr), tcp.HeaderLength()) 181 | } 182 | binary.BigEndian.PutUint16(hdr, uint16(tcp.SrcPort)) 183 | binary.BigEndian.PutUint16(hdr[2:], uint16(tcp.DstPort)) 184 | binary.BigEndian.PutUint32(hdr[4:], tcp.Seq) 185 | binary.BigEndian.PutUint32(hdr[8:], tcp.Ack) 186 | binary.BigEndian.PutUint16(hdr[12:], tcp.flagsAndOffset()) 187 | binary.BigEndian.PutUint16(hdr[14:], tcp.Window) 188 | binary.BigEndian.PutUint16(hdr[18:], tcp.Urgent) 189 | start := 20 190 | for _, o := range tcp.Options { 191 | hdr[start] = o.OptionType 192 | switch o.OptionType { 193 | case 0, 1: 194 | start++ 195 | default: 196 | o.OptionLength = uint8(len(o.OptionData) + 2) 197 | hdr[start+1] = o.OptionLength 198 | copy(hdr[start+2:start+len(o.OptionData)+2], o.OptionData) 199 | start += int(o.OptionLength) 200 | } 201 | } 202 | copy(hdr[start:], tcp.Padding) 203 | 204 | hdr[16] = 0 205 | hdr[17] = 0 206 | tcp.Checksum = Checksum(ckFields...) 207 | binary.BigEndian.PutUint16(hdr[16:], tcp.Checksum) 208 | return nil 209 | } 210 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/internal/packet/udp.go: -------------------------------------------------------------------------------- 1 | package packet 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "sync" 7 | ) 8 | 9 | type UDP struct { 10 | SrcPort uint16 11 | DstPort uint16 12 | Length uint16 13 | Checksum uint16 14 | Payload []byte 15 | } 16 | 17 | var ( 18 | udpPool *sync.Pool = &sync.Pool{ 19 | New: func() interface{} { 20 | return &UDP{} 21 | }, 22 | } 23 | ) 24 | 25 | func NewUDP() *UDP { 26 | var zero UDP 27 | udp := udpPool.Get().(*UDP) 28 | *udp = zero 29 | return udp 30 | } 31 | 32 | func ReleaseUDP(udp *UDP) { 33 | // clear internal slice references 34 | udp.Payload = nil 35 | udpPool.Put(udp) 36 | } 37 | 38 | func ParseUDP(pkt []byte, udp *UDP) error { 39 | if len(pkt) < 8 { 40 | return fmt.Errorf("payload too small for UDP: %d bytes", len(pkt)) 41 | } 42 | 43 | udp.SrcPort = binary.BigEndian.Uint16(pkt[0:2]) 44 | udp.DstPort = binary.BigEndian.Uint16(pkt[2:4]) 45 | udp.Length = binary.BigEndian.Uint16(pkt[4:6]) 46 | udp.Checksum = binary.BigEndian.Uint16(pkt[6:8]) 47 | if len(pkt) > 8 { 48 | udp.Payload = pkt[8:] 49 | } else { 50 | udp.Payload = nil 51 | } 52 | 53 | return nil 54 | } 55 | 56 | func (udp *UDP) Serialize(hdr []byte, ckFields ...[]byte) error { 57 | if len(hdr) != 8 { 58 | return fmt.Errorf("incorrect buffer size: %d buffer given, 8 needed", len(hdr)) 59 | } 60 | binary.BigEndian.PutUint16(hdr, uint16(udp.SrcPort)) 61 | binary.BigEndian.PutUint16(hdr[2:], uint16(udp.DstPort)) 62 | udp.Length = uint16(len(udp.Payload)) + 8 63 | binary.BigEndian.PutUint16(hdr[4:], udp.Length) 64 | hdr[6] = 0 65 | hdr[7] = 0 66 | udp.Checksum = Checksum(ckFields...) 67 | binary.BigEndian.PutUint16(hdr[6:], udp.Checksum) 68 | return nil 69 | } 70 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/ip.go: -------------------------------------------------------------------------------- 1 | package gotun2socks 2 | 3 | import ( 4 | "log" 5 | "net" 6 | 7 | "github.com/yinghuocho/gotun2socks/internal/packet" 8 | ) 9 | 10 | type ipPacket struct { 11 | ip *packet.IPv4 12 | mtuBuf []byte 13 | wire []byte 14 | } 15 | 16 | var ( 17 | frags = make(map[uint16]*ipPacket) 18 | ) 19 | 20 | func procFragment(ip *packet.IPv4, raw []byte) (bool, *packet.IPv4, []byte) { 21 | exist, ok := frags[ip.Id] 22 | if !ok { 23 | if ip.Flags&0x1 == 0 { 24 | return false, nil, nil 25 | } 26 | // first 27 | log.Printf("first fragment of IPID %d", ip.Id) 28 | dup := make([]byte, len(raw)) 29 | copy(dup, raw) 30 | clone := &packet.IPv4{} 31 | packet.ParseIPv4(dup, clone) 32 | frags[ip.Id] = &ipPacket{ 33 | ip: clone, 34 | wire: dup, 35 | } 36 | return false, clone, dup 37 | } else { 38 | exist.wire = append(exist.wire, ip.Payload...) 39 | packet.ParseIPv4(exist.wire, exist.ip) 40 | 41 | last := false 42 | if ip.Flags&0x1 == 0 { 43 | log.Printf("last fragment of IPID %d", ip.Id) 44 | last = true 45 | } else { 46 | log.Printf("continue fragment of IPID %d", ip.Id) 47 | } 48 | 49 | return last, exist.ip, exist.wire 50 | } 51 | } 52 | 53 | func genFragments(first *packet.IPv4, offset uint16, data []byte) []*ipPacket { 54 | var ret []*ipPacket 55 | for { 56 | frag := packet.NewIPv4() 57 | 58 | frag.Version = 4 59 | frag.Id = first.Id 60 | frag.SrcIP = make(net.IP, len(first.SrcIP)) 61 | copy(frag.SrcIP, first.SrcIP) 62 | frag.DstIP = make(net.IP, len(first.DstIP)) 63 | copy(frag.DstIP, first.DstIP) 64 | frag.TTL = first.TTL 65 | frag.Protocol = first.Protocol 66 | frag.FragOffset = offset 67 | if len(data) <= MTU-20 { 68 | frag.Payload = data 69 | } else { 70 | frag.Flags = 1 71 | offset += (MTU - 20) / 8 72 | frag.Payload = data[:MTU-20] 73 | data = data[MTU-20:] 74 | } 75 | 76 | pkt := &ipPacket{ip: frag} 77 | pkt.mtuBuf = newBuffer() 78 | 79 | payloadL := len(frag.Payload) 80 | payloadStart := MTU - payloadL 81 | if payloadL != 0 { 82 | copy(pkt.mtuBuf[payloadStart:], frag.Payload) 83 | } 84 | ipHL := frag.HeaderLength() 85 | ipStart := payloadStart - ipHL 86 | frag.Serialize(pkt.mtuBuf[ipStart:payloadStart], payloadL) 87 | pkt.wire = pkt.mtuBuf[ipStart:] 88 | ret = append(ret, pkt) 89 | 90 | if frag.Flags == 0 { 91 | return ret 92 | } 93 | } 94 | } 95 | 96 | func releaseIPPacket(pkt *ipPacket) { 97 | packet.ReleaseIPv4(pkt.ip) 98 | if pkt.mtuBuf != nil { 99 | releaseBuffer(pkt.mtuBuf) 100 | } 101 | pkt.mtuBuf = nil 102 | pkt.wire = nil 103 | } 104 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/mtubuf.go: -------------------------------------------------------------------------------- 1 | package gotun2socks 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | var ( 8 | bufPool *sync.Pool = &sync.Pool{ 9 | New: func() interface{} { 10 | return make([]byte, MTU) 11 | }, 12 | } 13 | ) 14 | 15 | func newBuffer() []byte { 16 | return bufPool.Get().([]byte) 17 | } 18 | 19 | func releaseBuffer(buf []byte) { 20 | bufPool.Put(buf) 21 | } 22 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/tcp.go: -------------------------------------------------------------------------------- 1 | package gotun2socks 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | "strings" 8 | "sync" 9 | "sync/atomic" 10 | "time" 11 | 12 | "github.com/yinghuocho/gotun2socks/internal/packet" 13 | ) 14 | 15 | type tcpPacket struct { 16 | ip *packet.IPv4 17 | tcp *packet.TCP 18 | mtuBuf []byte 19 | wire []byte 20 | } 21 | 22 | type tcpState byte 23 | 24 | const ( 25 | // simplified server-side tcp states 26 | CLOSED tcpState = 0x0 27 | SYN_RCVD tcpState = 0x1 28 | ESTABLISHED tcpState = 0x2 29 | FIN_WAIT_1 tcpState = 0x3 30 | FIN_WAIT_2 tcpState = 0x4 31 | CLOSING tcpState = 0x5 32 | LAST_ACK tcpState = 0x6 33 | TIME_WAIT tcpState = 0x7 34 | 35 | MAX_RECV_WINDOW int = 65535 36 | MAX_SEND_WINDOW int = 65535 37 | ) 38 | 39 | type tcpConnTrack struct { 40 | t2s *Tun2Socks 41 | id string 42 | 43 | input chan *tcpPacket 44 | toTunCh chan<- interface{} 45 | fromSocksCh chan []byte 46 | toSocksCh chan *tcpPacket 47 | socksCloseCh chan bool 48 | quitBySelf chan bool 49 | quitByOther chan bool 50 | 51 | localSocksAddr string 52 | socksConn net.Conn 53 | 54 | // tcp context 55 | state tcpState 56 | // sequence I should use to send next segment 57 | // also as ack I expect in next received segment 58 | nxtSeq uint32 59 | // sequence I want in next received segment 60 | rcvNxtSeq uint32 61 | // what I have acked 62 | lastAck uint32 63 | 64 | // flow control 65 | recvWindow int32 66 | sendWindow int32 67 | sendWndCond *sync.Cond 68 | // recvWndCond *sync.Cond 69 | 70 | localIP net.IP 71 | remoteIP net.IP 72 | localPort uint16 73 | remotePort uint16 74 | } 75 | 76 | var ( 77 | tcpPacketPool *sync.Pool = &sync.Pool{ 78 | New: func() interface{} { 79 | return &tcpPacket{} 80 | }, 81 | } 82 | ) 83 | 84 | func tcpflagsString(tcp *packet.TCP) string { 85 | s := []string{} 86 | if tcp.SYN { 87 | s = append(s, "SYN") 88 | } 89 | if tcp.RST { 90 | s = append(s, "RST") 91 | } 92 | if tcp.FIN { 93 | s = append(s, "FIN") 94 | } 95 | if tcp.ACK { 96 | s = append(s, "ACK") 97 | } 98 | if tcp.PSH { 99 | s = append(s, "PSH") 100 | } 101 | if tcp.URG { 102 | s = append(s, "URG") 103 | } 104 | if tcp.ECE { 105 | s = append(s, "ECE") 106 | } 107 | if tcp.CWR { 108 | s = append(s, "CWR") 109 | } 110 | return strings.Join(s, ",") 111 | } 112 | 113 | func tcpstateString(state tcpState) string { 114 | switch state { 115 | case CLOSED: 116 | return "CLOSED" 117 | case SYN_RCVD: 118 | return "SYN_RCVD" 119 | case ESTABLISHED: 120 | return "ESTABLISHED" 121 | case FIN_WAIT_1: 122 | return "FIN_WAIT_1" 123 | case FIN_WAIT_2: 124 | return "FIN_WAIT_2" 125 | case CLOSING: 126 | return "CLOSING" 127 | case LAST_ACK: 128 | return "LAST_ACK" 129 | case TIME_WAIT: 130 | return "TIME_WAIT" 131 | } 132 | return "" 133 | } 134 | 135 | func newTCPPacket() *tcpPacket { 136 | return tcpPacketPool.Get().(*tcpPacket) 137 | } 138 | 139 | func releaseTCPPacket(pkt *tcpPacket) { 140 | packet.ReleaseIPv4(pkt.ip) 141 | packet.ReleaseTCP(pkt.tcp) 142 | if pkt.mtuBuf != nil { 143 | releaseBuffer(pkt.mtuBuf) 144 | } 145 | pkt.mtuBuf = nil 146 | pkt.wire = nil 147 | tcpPacketPool.Put(pkt) 148 | } 149 | 150 | func copyTCPPacket(raw []byte, ip *packet.IPv4, tcp *packet.TCP) *tcpPacket { 151 | iphdr := packet.NewIPv4() 152 | tcphdr := packet.NewTCP() 153 | pkt := newTCPPacket() 154 | 155 | // make a deep copy 156 | var buf []byte 157 | if len(raw) <= MTU { 158 | buf = newBuffer() 159 | pkt.mtuBuf = buf 160 | } else { 161 | buf = make([]byte, len(raw)) 162 | } 163 | n := copy(buf, raw) 164 | pkt.wire = buf[:n] 165 | packet.ParseIPv4(pkt.wire, iphdr) 166 | packet.ParseTCP(iphdr.Payload, tcphdr) 167 | pkt.ip = iphdr 168 | pkt.tcp = tcphdr 169 | 170 | return pkt 171 | } 172 | 173 | func tcpConnID(ip *packet.IPv4, tcp *packet.TCP) string { 174 | return strings.Join([]string{ 175 | ip.SrcIP.String(), 176 | fmt.Sprintf("%d", tcp.SrcPort), 177 | ip.DstIP.String(), 178 | fmt.Sprintf("%d", tcp.DstPort), 179 | }, "|") 180 | } 181 | 182 | func packTCP(ip *packet.IPv4, tcp *packet.TCP) *tcpPacket { 183 | pkt := newTCPPacket() 184 | pkt.ip = ip 185 | pkt.tcp = tcp 186 | 187 | buf := newBuffer() 188 | pkt.mtuBuf = buf 189 | 190 | payloadL := len(tcp.Payload) 191 | payloadStart := MTU - payloadL 192 | if payloadL != 0 { 193 | copy(pkt.mtuBuf[payloadStart:], tcp.Payload) 194 | } 195 | tcpHL := tcp.HeaderLength() 196 | tcpStart := payloadStart - tcpHL 197 | pseduoStart := tcpStart - packet.IPv4_PSEUDO_LENGTH 198 | ip.PseudoHeader(pkt.mtuBuf[pseduoStart:tcpStart], packet.IPProtocolTCP, tcpHL+payloadL) 199 | tcp.Serialize(pkt.mtuBuf[tcpStart:payloadStart], pkt.mtuBuf[pseduoStart:]) 200 | ipHL := ip.HeaderLength() 201 | ipStart := tcpStart - ipHL 202 | ip.Serialize(pkt.mtuBuf[ipStart:tcpStart], tcpHL+payloadL) 203 | pkt.wire = pkt.mtuBuf[ipStart:] 204 | return pkt 205 | } 206 | 207 | func rst(srcIP net.IP, dstIP net.IP, srcPort uint16, dstPort uint16, seq uint32, ack uint32, payloadLen uint32) *tcpPacket { 208 | iphdr := packet.NewIPv4() 209 | tcphdr := packet.NewTCP() 210 | 211 | iphdr.Version = 4 212 | iphdr.Id = packet.IPID() 213 | iphdr.DstIP = srcIP 214 | iphdr.SrcIP = dstIP 215 | iphdr.TTL = 64 216 | iphdr.Protocol = packet.IPProtocolTCP 217 | 218 | tcphdr.DstPort = srcPort 219 | tcphdr.SrcPort = dstPort 220 | tcphdr.Window = uint16(MAX_RECV_WINDOW) 221 | tcphdr.RST = true 222 | tcphdr.ACK = true 223 | tcphdr.Seq = 0 224 | 225 | // RFC 793: 226 | // "If the incoming segment has an ACK field, the reset takes its sequence 227 | // number from the ACK field of the segment, otherwise the reset has 228 | // sequence number zero and the ACK field is set to the sum of the sequence 229 | // number and segment length of the incoming segment. The connection remains 230 | // in the CLOSED state." 231 | tcphdr.Ack = seq + payloadLen 232 | if tcphdr.Ack == seq { 233 | tcphdr.Ack += 1 234 | } 235 | if ack != 0 { 236 | tcphdr.Seq = ack 237 | } 238 | return packTCP(iphdr, tcphdr) 239 | } 240 | 241 | func rstByPacket(pkt *tcpPacket) *tcpPacket { 242 | return rst(pkt.ip.SrcIP, pkt.ip.DstIP, pkt.tcp.SrcPort, pkt.tcp.DstPort, pkt.tcp.Seq, pkt.tcp.Ack, uint32(len(pkt.tcp.Payload))) 243 | } 244 | 245 | func (tt *tcpConnTrack) changeState(nxt tcpState) { 246 | log.Printf("### [%s -> %s]", tcpstateString(tt.state), tcpstateString(nxt)) 247 | tt.state = nxt 248 | } 249 | 250 | func (tt *tcpConnTrack) validAck(pkt *tcpPacket) bool { 251 | ret := (pkt.tcp.Ack == tt.nxtSeq) 252 | if !ret { 253 | log.Printf("WARNING: invalid ack: recvd: %d, expecting: %d", pkt.tcp.Ack, tt.nxtSeq) 254 | } 255 | return ret 256 | } 257 | 258 | func (tt *tcpConnTrack) validSeq(pkt *tcpPacket) bool { 259 | ret := (pkt.tcp.Seq == tt.rcvNxtSeq) 260 | if !ret { 261 | // log.Printf("WARNING: invalid seq: recvd: %d, expecting: %d", pkt.tcp.Seq, tt.rcvNxtSeq) 262 | // if (tt.rcvNxtSeq - pkt.tcp.Seq) == 1 && tt.state == ESTABLISHED { 263 | // log.Printf("(probably a keep-alive message)") 264 | // } 265 | } 266 | return ret 267 | } 268 | 269 | func (tt *tcpConnTrack) relayPayload(pkt *tcpPacket) bool { 270 | payloadLen := uint32(len(pkt.tcp.Payload)) 271 | select { 272 | case tt.toSocksCh <- pkt: 273 | tt.rcvNxtSeq += payloadLen 274 | 275 | // reduce window when recved 276 | wnd := atomic.LoadInt32(&tt.recvWindow) 277 | wnd -= int32(payloadLen) 278 | if wnd < 0 { 279 | wnd = 0 280 | } 281 | atomic.StoreInt32(&tt.recvWindow, wnd) 282 | 283 | return true 284 | case <-tt.socksCloseCh: 285 | return false 286 | } 287 | } 288 | 289 | func (tt *tcpConnTrack) send(pkt *tcpPacket) { 290 | //log.Printf("<-- [TCP][%s][%s][seq:%d][ack:%d][payload:%d]", tt.id, tcpflagsString(pkt.tcp), pkt.tcp.Seq, pkt.tcp.Ack, len(pkt.tcp.Payload)) 291 | if pkt.tcp.ACK { 292 | tt.lastAck = pkt.tcp.Ack 293 | } 294 | tt.toTunCh <- pkt 295 | } 296 | 297 | func (tt *tcpConnTrack) synAck(syn *tcpPacket) { 298 | iphdr := packet.NewIPv4() 299 | tcphdr := packet.NewTCP() 300 | 301 | iphdr.Version = 4 302 | iphdr.Id = packet.IPID() 303 | iphdr.SrcIP = tt.remoteIP 304 | iphdr.DstIP = tt.localIP 305 | iphdr.TTL = 64 306 | iphdr.Protocol = packet.IPProtocolTCP 307 | 308 | tcphdr.SrcPort = tt.remotePort 309 | tcphdr.DstPort = tt.localPort 310 | tcphdr.Window = uint16(atomic.LoadInt32(&tt.recvWindow)) 311 | tcphdr.SYN = true 312 | tcphdr.ACK = true 313 | tcphdr.Seq = tt.nxtSeq 314 | tcphdr.Ack = tt.rcvNxtSeq 315 | 316 | tcphdr.Options = []packet.TCPOption{{2, 4, []byte{0x5, 0xb4}}} 317 | 318 | synAck := packTCP(iphdr, tcphdr) 319 | tt.send(synAck) 320 | // SYN counts 1 seq 321 | tt.nxtSeq += 1 322 | } 323 | 324 | func (tt *tcpConnTrack) finAck() { 325 | iphdr := packet.NewIPv4() 326 | tcphdr := packet.NewTCP() 327 | 328 | iphdr.Version = 4 329 | iphdr.Id = packet.IPID() 330 | iphdr.SrcIP = tt.remoteIP 331 | iphdr.DstIP = tt.localIP 332 | iphdr.TTL = 64 333 | iphdr.Protocol = packet.IPProtocolTCP 334 | 335 | tcphdr.SrcPort = tt.remotePort 336 | tcphdr.DstPort = tt.localPort 337 | tcphdr.Window = uint16(atomic.LoadInt32(&tt.recvWindow)) 338 | tcphdr.FIN = true 339 | tcphdr.ACK = true 340 | tcphdr.Seq = tt.nxtSeq 341 | tcphdr.Ack = tt.rcvNxtSeq 342 | 343 | finAck := packTCP(iphdr, tcphdr) 344 | tt.send(finAck) 345 | // FIN counts 1 seq 346 | tt.nxtSeq += 1 347 | } 348 | 349 | func (tt *tcpConnTrack) ack() { 350 | iphdr := packet.NewIPv4() 351 | tcphdr := packet.NewTCP() 352 | 353 | iphdr.Version = 4 354 | iphdr.Id = packet.IPID() 355 | iphdr.SrcIP = tt.remoteIP 356 | iphdr.DstIP = tt.localIP 357 | iphdr.TTL = 64 358 | iphdr.Protocol = packet.IPProtocolTCP 359 | 360 | tcphdr.SrcPort = tt.remotePort 361 | tcphdr.DstPort = tt.localPort 362 | tcphdr.Window = uint16(atomic.LoadInt32(&tt.recvWindow)) 363 | tcphdr.ACK = true 364 | tcphdr.Seq = tt.nxtSeq 365 | tcphdr.Ack = tt.rcvNxtSeq 366 | 367 | ack := packTCP(iphdr, tcphdr) 368 | tt.send(ack) 369 | } 370 | 371 | func (tt *tcpConnTrack) payload(data []byte) { 372 | iphdr := packet.NewIPv4() 373 | tcphdr := packet.NewTCP() 374 | 375 | iphdr.Version = 4 376 | iphdr.Id = packet.IPID() 377 | iphdr.SrcIP = tt.remoteIP 378 | iphdr.DstIP = tt.localIP 379 | iphdr.TTL = 64 380 | iphdr.Protocol = packet.IPProtocolTCP 381 | 382 | tcphdr.SrcPort = tt.remotePort 383 | tcphdr.DstPort = tt.localPort 384 | tcphdr.Window = uint16(atomic.LoadInt32(&tt.recvWindow)) 385 | tcphdr.ACK = true 386 | tcphdr.PSH = true 387 | tcphdr.Seq = tt.nxtSeq 388 | tcphdr.Ack = tt.rcvNxtSeq 389 | tcphdr.Payload = data 390 | 391 | pkt := packTCP(iphdr, tcphdr) 392 | tt.send(pkt) 393 | // adjust seq 394 | tt.nxtSeq = tt.nxtSeq + uint32(len(data)) 395 | } 396 | 397 | // stateClosed receives a SYN packet, tries to connect the socks proxy, gives a 398 | // SYN/ACK if success, otherwise RST 399 | func (tt *tcpConnTrack) stateClosed(syn *tcpPacket) (continu bool, release bool) { 400 | var e error 401 | for i := 0; i < 2; i++ { 402 | tt.socksConn, e = tt.t2s.dialer.Dial("tcp4", syn.ip.DstIP.String(), syn.tcp.DstPort, tt.t2s.ctx) 403 | if e != nil { 404 | log.Printf("fail to connect SOCKS proxy: %s", e) 405 | } else { 406 | // no timeout 407 | tt.socksConn.SetDeadline(time.Time{}) 408 | break 409 | } 410 | } 411 | if tt.socksConn == nil { 412 | resp := rstByPacket(syn) 413 | tt.toTunCh <- resp.wire 414 | log.Printf("<-- [TCP][%s][RST]", tt.id) 415 | return false, true 416 | } 417 | // context variables 418 | tt.rcvNxtSeq = syn.tcp.Seq + 1 419 | tt.nxtSeq = 1 420 | 421 | tt.synAck(syn) 422 | tt.changeState(SYN_RCVD) 423 | return true, true 424 | } 425 | 426 | func (tt *tcpConnTrack) tcpSocks2Tun(dstIP net.IP, dstPort uint16, conn net.Conn, readCh chan<- []byte, writeCh <-chan *tcpPacket, closeCh chan bool) { 427 | /* 428 | _, e := gosocks.WriteSocksRequest(conn, &gosocks.SocksRequest{ 429 | Cmd: gosocks.SocksCmdConnect, 430 | HostType: gosocks.SocksIPv4Host, 431 | DstHost: dstIP.String(), 432 | DstPort: dstPort, 433 | }) 434 | if e != nil { 435 | log.Printf("error to send socks request: %s", e) 436 | conn.Close() 437 | close(closeCh) 438 | return 439 | } 440 | reply, e := gosocks.ReadSocksReply(conn) 441 | if e != nil { 442 | log.Printf("error to read socks reply: %s", e) 443 | conn.Close() 444 | close(closeCh) 445 | return 446 | } 447 | if reply.Rep != gosocks.SocksSucceeded { 448 | log.Printf("socks connect request fail, retcode: %d", reply.Rep) 449 | conn.Close() 450 | close(closeCh) 451 | return 452 | }*/ 453 | // writer 454 | go func() { 455 | loop: 456 | for { 457 | select { 458 | case <-closeCh: 459 | break loop 460 | case pkt := <-writeCh: 461 | conn.Write(pkt.tcp.Payload) 462 | 463 | // increase window when processed 464 | wnd := atomic.LoadInt32(&tt.recvWindow) 465 | wnd += int32(len(pkt.tcp.Payload)) 466 | if wnd > int32(MAX_RECV_WINDOW) { 467 | wnd = int32(MAX_RECV_WINDOW) 468 | } 469 | atomic.StoreInt32(&tt.recvWindow, wnd) 470 | 471 | releaseTCPPacket(pkt) 472 | } 473 | } 474 | }() 475 | 476 | // reader 477 | for { 478 | var buf [MTU - 40]byte 479 | 480 | // tt.sendWndCond.L.Lock() 481 | var wnd int32 482 | var cur int32 483 | wnd = atomic.LoadInt32(&tt.sendWindow) 484 | 485 | if wnd <= 0 { 486 | for wnd <= 0 { 487 | tt.sendWndCond.L.Lock() 488 | tt.sendWndCond.Wait() 489 | wnd = atomic.LoadInt32(&tt.sendWindow) 490 | } 491 | tt.sendWndCond.L.Unlock() 492 | } 493 | 494 | cur = wnd 495 | if cur > MTU-40 { 496 | cur = MTU - 40 497 | } 498 | // tt.sendWndCond.L.Unlock() 499 | 500 | n, e := conn.Read(buf[:cur]) 501 | if e != nil { 502 | log.Printf("error to read from socks: %s", e) 503 | conn.Close() 504 | break 505 | } else { 506 | b := make([]byte, n) 507 | copy(b, buf[:n]) 508 | readCh <- b 509 | 510 | // tt.sendWndCond.L.Lock() 511 | nxt := wnd - int32(n) 512 | if nxt < 0 { 513 | nxt = 0 514 | } 515 | // if sendWindow does not equal to wnd, it is already updated by a 516 | // received pkt from TUN 517 | atomic.CompareAndSwapInt32(&tt.sendWindow, wnd, nxt) 518 | // tt.sendWndCond.L.Unlock() 519 | } 520 | } 521 | close(closeCh) 522 | } 523 | 524 | // stateSynRcvd expects a ACK with matching ack number, 525 | func (tt *tcpConnTrack) stateSynRcvd(pkt *tcpPacket) (continu bool, release bool) { 526 | // rst to packet with invalid sequence/ack, state unchanged 527 | if !(tt.validSeq(pkt) && tt.validAck(pkt)) { 528 | if !pkt.tcp.RST { 529 | resp := rstByPacket(pkt) 530 | tt.toTunCh <- resp 531 | log.Printf("<-- [TCP][%s][RST] continue", tt.id) 532 | } 533 | return true, true 534 | } 535 | // connection ends by valid RST 536 | if pkt.tcp.RST { 537 | return false, true 538 | } 539 | // ignore non-ACK packets 540 | if !pkt.tcp.ACK { 541 | return true, true 542 | } 543 | 544 | continu = true 545 | release = true 546 | tt.changeState(ESTABLISHED) 547 | go tt.tcpSocks2Tun(tt.remoteIP, uint16(tt.remotePort), tt.socksConn, tt.fromSocksCh, tt.toSocksCh, tt.socksCloseCh) 548 | if len(pkt.tcp.Payload) != 0 { 549 | if tt.relayPayload(pkt) { 550 | // pkt hands to socks writer 551 | release = false 552 | } 553 | } 554 | return 555 | } 556 | 557 | func (tt *tcpConnTrack) stateEstablished(pkt *tcpPacket) (continu bool, release bool) { 558 | // ack if sequence is not expected 559 | if !tt.validSeq(pkt) { 560 | tt.ack() 561 | return true, true 562 | } 563 | // connection ends by valid RST 564 | if pkt.tcp.RST { 565 | return false, true 566 | } 567 | // ignore non-ACK packets 568 | if !pkt.tcp.ACK { 569 | return true, true 570 | } 571 | 572 | continu = true 573 | release = true 574 | if len(pkt.tcp.Payload) != 0 { 575 | if tt.relayPayload(pkt) { 576 | // pkt hands to socks writer 577 | release = false 578 | } 579 | } 580 | if pkt.tcp.FIN { 581 | tt.rcvNxtSeq += 1 582 | tt.finAck() 583 | tt.changeState(LAST_ACK) 584 | tt.socksConn.Close() 585 | } 586 | return 587 | } 588 | 589 | func (tt *tcpConnTrack) stateFinWait1(pkt *tcpPacket) (continu bool, release bool) { 590 | // ignore packet with invalid sequence, state unchanged 591 | if !tt.validSeq(pkt) { 592 | return true, true 593 | } 594 | // connection ends by valid RST 595 | if pkt.tcp.RST { 596 | return false, true 597 | } 598 | // ignore non-ACK packets 599 | if !pkt.tcp.ACK { 600 | return true, true 601 | } 602 | 603 | if pkt.tcp.FIN { 604 | tt.rcvNxtSeq += 1 605 | tt.ack() 606 | if pkt.tcp.ACK && tt.validAck(pkt) { 607 | tt.changeState(TIME_WAIT) 608 | return false, true 609 | } else { 610 | tt.changeState(CLOSING) 611 | return true, true 612 | } 613 | } else { 614 | tt.changeState(FIN_WAIT_2) 615 | return true, true 616 | } 617 | } 618 | 619 | func (tt *tcpConnTrack) stateFinWait2(pkt *tcpPacket) (continu bool, release bool) { 620 | // ignore packet with invalid sequence/ack, state unchanged 621 | if !(tt.validSeq(pkt) && tt.validAck(pkt)) { 622 | return true, true 623 | } 624 | // connection ends by valid RST 625 | if pkt.tcp.RST { 626 | return false, true 627 | } 628 | // ignore non-FIN non-ACK packets 629 | if !pkt.tcp.ACK || !pkt.tcp.FIN { 630 | return true, true 631 | } 632 | tt.rcvNxtSeq += 1 633 | tt.ack() 634 | tt.changeState(TIME_WAIT) 635 | return false, true 636 | } 637 | 638 | func (tt *tcpConnTrack) stateClosing(pkt *tcpPacket) (continu bool, release bool) { 639 | // ignore packet with invalid sequence/ack, state unchanged 640 | if !(tt.validSeq(pkt) && tt.validAck(pkt)) { 641 | return true, true 642 | } 643 | // connection ends by valid RST 644 | if pkt.tcp.RST { 645 | return false, true 646 | } 647 | // ignore non-ACK packets 648 | if !pkt.tcp.ACK { 649 | return true, true 650 | } 651 | tt.changeState(TIME_WAIT) 652 | return false, true 653 | } 654 | 655 | func (tt *tcpConnTrack) stateLastAck(pkt *tcpPacket) (continu bool, release bool) { 656 | // ignore packet with invalid sequence/ack, state unchanged 657 | if !(tt.validSeq(pkt) && tt.validAck(pkt)) { 658 | return true, true 659 | } 660 | // ignore non-ACK packets 661 | if !pkt.tcp.ACK { 662 | return true, true 663 | } 664 | // connection ends 665 | tt.changeState(CLOSED) 666 | return false, true 667 | } 668 | 669 | func (tt *tcpConnTrack) newPacket(pkt *tcpPacket) { 670 | select { 671 | case <-tt.quitByOther: 672 | case <-tt.quitBySelf: 673 | case tt.input <- pkt: 674 | } 675 | } 676 | 677 | func (tt *tcpConnTrack) updateSendWindow(pkt *tcpPacket) { 678 | // tt.sendWndCond.L.Lock() 679 | atomic.StoreInt32(&tt.sendWindow, int32(pkt.tcp.Window)) 680 | tt.sendWndCond.Signal() 681 | // tt.sendWndCond.L.Unlock() 682 | } 683 | 684 | func (tt *tcpConnTrack) run() { 685 | for { 686 | var ackTimer *time.Timer 687 | var timeout *time.Timer = time.NewTimer(5 * time.Minute) 688 | 689 | var ackTimeout <-chan time.Time 690 | var socksCloseCh chan bool 691 | var fromSocksCh chan []byte 692 | // enable some channels only when the state is ESTABLISHED 693 | if tt.state == ESTABLISHED { 694 | socksCloseCh = tt.socksCloseCh 695 | fromSocksCh = tt.fromSocksCh 696 | ackTimer = time.NewTimer(10 * time.Millisecond) 697 | ackTimeout = ackTimer.C 698 | } 699 | 700 | select { 701 | case pkt := <-tt.input: 702 | //log.Printf("--> [TCP][%s][%s][%s][seq:%d][ack:%d][payload:%d]", tt.id, tcpstateString(tt.state), tcpflagsString(pkt.tcp), pkt.tcp.Seq, pkt.tcp.Ack, len(pkt.tcp.Payload)) 703 | var continu, release bool 704 | 705 | tt.updateSendWindow(pkt) 706 | switch tt.state { 707 | case CLOSED: 708 | continu, release = tt.stateClosed(pkt) 709 | case SYN_RCVD: 710 | continu, release = tt.stateSynRcvd(pkt) 711 | case ESTABLISHED: 712 | continu, release = tt.stateEstablished(pkt) 713 | case FIN_WAIT_1: 714 | continu, release = tt.stateFinWait1(pkt) 715 | case FIN_WAIT_2: 716 | continu, release = tt.stateFinWait2(pkt) 717 | case CLOSING: 718 | continu, release = tt.stateClosing(pkt) 719 | case LAST_ACK: 720 | continu, release = tt.stateLastAck(pkt) 721 | } 722 | if release { 723 | releaseTCPPacket(pkt) 724 | } 725 | if !continu { 726 | if tt.socksConn != nil { 727 | tt.socksConn.Close() 728 | } 729 | close(tt.quitBySelf) 730 | tt.t2s.clearTCPConnTrack(tt.id) 731 | return 732 | } 733 | 734 | case <-ackTimeout: 735 | if tt.lastAck < tt.rcvNxtSeq { 736 | // have something to ack 737 | tt.ack() 738 | } 739 | 740 | case data := <-fromSocksCh: 741 | tt.payload(data) 742 | 743 | case <-socksCloseCh: 744 | tt.finAck() 745 | tt.changeState(FIN_WAIT_1) 746 | 747 | case <-timeout.C: 748 | if tt.socksConn != nil { 749 | tt.socksConn.Close() 750 | } 751 | close(tt.quitBySelf) 752 | tt.t2s.clearTCPConnTrack(tt.id) 753 | return 754 | 755 | case <-tt.quitByOther: 756 | // who closes this channel should be responsible to clear track map 757 | log.Printf("tcpConnTrack quitByOther") 758 | if tt.socksConn != nil { 759 | tt.socksConn.Close() 760 | } 761 | return 762 | } 763 | timeout.Stop() 764 | if ackTimer != nil { 765 | ackTimer.Stop() 766 | } 767 | } 768 | } 769 | 770 | func (t2s *Tun2Socks) createTCPConnTrack(id string, ip *packet.IPv4, tcp *packet.TCP) *tcpConnTrack { 771 | t2s.tcpConnTrackLock.Lock() 772 | defer t2s.tcpConnTrackLock.Unlock() 773 | 774 | track := &tcpConnTrack{ 775 | t2s: t2s, 776 | id: id, 777 | toTunCh: t2s.writeCh, 778 | input: make(chan *tcpPacket, 10000), 779 | fromSocksCh: make(chan []byte, 100), 780 | toSocksCh: make(chan *tcpPacket, 100), 781 | socksCloseCh: make(chan bool), 782 | quitBySelf: make(chan bool), 783 | quitByOther: make(chan bool), 784 | 785 | sendWindow: int32(MAX_SEND_WINDOW), 786 | recvWindow: int32(MAX_RECV_WINDOW), 787 | sendWndCond: &sync.Cond{L: &sync.Mutex{}}, 788 | 789 | localPort: tcp.SrcPort, 790 | remotePort: tcp.DstPort, 791 | localSocksAddr: t2s.localSocksAddr, 792 | state: CLOSED, 793 | } 794 | track.localIP = make(net.IP, len(ip.SrcIP)) 795 | copy(track.localIP, ip.SrcIP) 796 | track.remoteIP = make(net.IP, len(ip.DstIP)) 797 | copy(track.remoteIP, ip.DstIP) 798 | 799 | t2s.tcpConnTrackMap[id] = track 800 | go track.run() 801 | log.Printf("tracking %d TCP connections", len(t2s.tcpConnTrackMap)) 802 | return track 803 | } 804 | 805 | func (t2s *Tun2Socks) getTCPConnTrack(id string) *tcpConnTrack { 806 | t2s.tcpConnTrackLock.Lock() 807 | defer t2s.tcpConnTrackLock.Unlock() 808 | 809 | return t2s.tcpConnTrackMap[id] 810 | } 811 | 812 | func (t2s *Tun2Socks) clearTCPConnTrack(id string) { 813 | t2s.tcpConnTrackLock.Lock() 814 | defer t2s.tcpConnTrackLock.Unlock() 815 | 816 | delete(t2s.tcpConnTrackMap, id) 817 | log.Printf("tracking %d TCP connections", len(t2s.tcpConnTrackMap)) 818 | } 819 | 820 | func (t2s *Tun2Socks) tcp(raw []byte, ip *packet.IPv4, tcp *packet.TCP) { 821 | connID := tcpConnID(ip, tcp) 822 | track := t2s.getTCPConnTrack(connID) 823 | if track != nil { 824 | pkt := copyTCPPacket(raw, ip, tcp) 825 | track.newPacket(pkt) 826 | } else { 827 | // ignore RST, if there is no track of this connection 828 | if tcp.RST { 829 | log.Printf("--> [TCP][%s][%s]", connID, tcpflagsString(tcp)) 830 | return 831 | } 832 | // return a RST to non-SYN packet 833 | if !tcp.SYN { 834 | log.Printf("--> [TCP][%s][%s]", connID, tcpflagsString(tcp)) 835 | resp := rst(ip.SrcIP, ip.DstIP, tcp.SrcPort, tcp.DstPort, tcp.Seq, tcp.Ack, uint32(len(tcp.Payload))) 836 | t2s.writeCh <- resp 837 | log.Printf("<-- [TCP][%s][RST]", connID) 838 | return 839 | } 840 | pkt := copyTCPPacket(raw, ip, tcp) 841 | track := t2s.createTCPConnTrack(connID, ip, tcp) 842 | track.newPacket(pkt) 843 | } 844 | } 845 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/tun/stop.go: -------------------------------------------------------------------------------- 1 | package tun 2 | 3 | import ( 4 | "bytes" 5 | "log" 6 | "net" 7 | ) 8 | 9 | var stopMarker = []byte{2, 2, 2, 2, 2, 2, 2, 2} 10 | 11 | // Close of Windows and Linux tun/tap device do not interrupt blocking Read. 12 | // sendStopMarker is used to issue a specific packet to notify threads blocking 13 | // on Read. 14 | func sendStopMarker(src, dst string) { 15 | l, _ := net.ResolveUDPAddr("udp", src+":2222") 16 | r, _ := net.ResolveUDPAddr("udp", dst+":2222") 17 | conn, err := net.DialUDP("udp", l, r) 18 | if err != nil { 19 | log.Printf("fail to send stopmarker: %s", err) 20 | return 21 | } 22 | defer conn.Close() 23 | conn.Write(stopMarker) 24 | } 25 | 26 | func isStopMarker(pkt []byte, src, dst net.IP) bool { 27 | n := len(pkt) 28 | // at least should be 20(ip) + 8(udp) + 8(stopmarker) 29 | if n < 20+8+8 { 30 | return false 31 | } 32 | return pkt[0]&0xf0 == 0x40 && pkt[9] == 0x11 && src.Equal(pkt[12:16]) && 33 | dst.Equal(pkt[16:20]) && bytes.Compare(pkt[n-8:n], stopMarker) == 0 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/tun/tun_darwin.go: -------------------------------------------------------------------------------- 1 | package tun 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "os/exec" 8 | "syscall" 9 | "unsafe" 10 | ) 11 | 12 | const ( 13 | appleUTUNCtl = "com.apple.net.utun_control" 14 | appleCTLIOCGINFO = (0x40000000 | 0x80000000) | ((100 & 0x1fff) << 16) | uint32(byte('N'))<<8 | 3 15 | ) 16 | 17 | type sockaddrCtl struct { 18 | scLen uint8 19 | scFamily uint8 20 | ssSysaddr uint16 21 | scID uint32 22 | scUnit uint32 23 | scReserved [5]uint32 24 | } 25 | 26 | type utunDev struct { 27 | f *os.File 28 | 29 | rBuf [2048]byte 30 | wBuf [2048]byte 31 | } 32 | 33 | func (dev *utunDev) Read(data []byte) (int, error) { 34 | n, e := dev.f.Read(dev.rBuf[:]) 35 | if n > 0 { 36 | copy(data, dev.rBuf[4:n]) 37 | n -= 4 38 | } 39 | return n, e 40 | } 41 | 42 | // one packet, no more than MTU 43 | func (dev *utunDev) Write(data []byte) (int, error) { 44 | n := copy(dev.wBuf[4:], data) 45 | return dev.f.Write(dev.wBuf[:n+4]) 46 | } 47 | 48 | func (dev *utunDev) Close() error { 49 | return dev.f.Close() 50 | } 51 | 52 | var sockaddrCtlSize uintptr = 32 53 | 54 | func OpenTunDevice(name, addr, gw, mask string, dns []string) (io.ReadWriteCloser, error) { 55 | fd, err := syscall.Socket(syscall.AF_SYSTEM, syscall.SOCK_DGRAM, 2) 56 | if err != nil { 57 | return nil, err 58 | } 59 | 60 | var ctlInfo = &struct { 61 | ctlID uint32 62 | ctlName [96]byte 63 | }{} 64 | copy(ctlInfo.ctlName[:], []byte(appleUTUNCtl)) 65 | _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(appleCTLIOCGINFO), uintptr(unsafe.Pointer(ctlInfo))) 66 | if errno != 0 { 67 | return nil, fmt.Errorf("error in syscall.Syscall(syscall.SYS_IOTL, ...): %v", errno) 68 | } 69 | addrP := unsafe.Pointer(&sockaddrCtl{ 70 | scLen: uint8(sockaddrCtlSize), 71 | scFamily: syscall.AF_SYSTEM, 72 | /* #define AF_SYS_CONTROL 2 */ 73 | ssSysaddr: 2, 74 | scID: ctlInfo.ctlID, 75 | scUnit: 0, 76 | }) 77 | _, _, errno = syscall.RawSyscall(syscall.SYS_CONNECT, uintptr(fd), uintptr(addrP), uintptr(sockaddrCtlSize)) 78 | if errno != 0 { 79 | return nil, fmt.Errorf("error in syscall.RawSyscall(syscall.SYS_CONNECT, ...): %v", errno) 80 | } 81 | 82 | var ifName struct { 83 | name [16]byte 84 | } 85 | ifNameSize := uintptr(16) 86 | _, _, errno = syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(fd), 87 | 2, /* #define SYSPROTO_CONTROL 2 */ 88 | 2, /* #define UTUN_OPT_IFNAME 2 */ 89 | uintptr(unsafe.Pointer(&ifName)), 90 | uintptr(unsafe.Pointer(&ifNameSize)), 0) 91 | if errno != 0 { 92 | return nil, fmt.Errorf("error in syscall.Syscall6(syscall.SYS_GETSOCKOPT, ...): %v", errno) 93 | } 94 | cmd := exec.Command("ifconfig", string(ifName.name[:ifNameSize-1]), "inet", addr, gw, "netmask", mask, "mtu", "1500", "up") 95 | err = cmd.Run() 96 | if err != nil { 97 | syscall.Close(fd) 98 | return nil, err 99 | } 100 | 101 | dev := &utunDev{ 102 | f: os.NewFile(uintptr(fd), string(ifName.name[:ifNameSize-1])), 103 | } 104 | copy(dev.wBuf[:], []byte{0, 0, 0, 2}) 105 | return dev, nil 106 | } 107 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/tun/tun_linux.go: -------------------------------------------------------------------------------- 1 | package tun 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "log" 7 | "net" 8 | "os" 9 | "os/exec" 10 | "syscall" 11 | "unsafe" 12 | ) 13 | 14 | const ( 15 | IFF_TUN = 0x0001 16 | IFF_TAP = 0x0002 17 | IFF_NO_PI = 0x1000 18 | ) 19 | 20 | type ifReq struct { 21 | Name [0x10]byte 22 | Flags uint16 23 | pad [0x28 - 0x10 - 2]byte 24 | } 25 | 26 | func OpenTunDevice(name, addr, gw, mask string, dns []string) (io.ReadWriteCloser, error) { 27 | file, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0) 28 | if err != nil { 29 | return nil, err 30 | } 31 | var req ifReq 32 | copy(req.Name[:], name) 33 | req.Flags = IFF_TUN | IFF_NO_PI 34 | log.Printf("openning tun device") 35 | _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, file.Fd(), uintptr(syscall.TUNSETIFF), uintptr(unsafe.Pointer(&req))) 36 | if errno != 0 { 37 | err = errno 38 | return nil, err 39 | } 40 | 41 | // config address 42 | log.Printf("configuring tun device address") 43 | cmd := exec.Command("ifconfig", name, addr, "netmask", mask, "mtu", "1500") 44 | err = cmd.Run() 45 | if err != nil { 46 | file.Close() 47 | log.Printf("failed to configure tun device address") 48 | return nil, err 49 | } 50 | syscall.SetNonblock(int(file.Fd()), false) 51 | return &tunDev{ 52 | f: file, 53 | addr: addr, 54 | addrIP: net.ParseIP(addr).To4(), 55 | gw: gw, 56 | gwIP: net.ParseIP(gw).To4(), 57 | }, nil 58 | } 59 | 60 | func NewTunDev(fd uintptr, name string, addr string, gw string) io.ReadWriteCloser { 61 | syscall.SetNonblock(int(fd), false) 62 | return &tunDev{ 63 | f: os.NewFile(fd, name), 64 | addr: addr, 65 | addrIP: net.ParseIP(addr).To4(), 66 | gw: gw, 67 | gwIP: net.ParseIP(gw).To4(), 68 | } 69 | } 70 | 71 | type tunDev struct { 72 | name string 73 | addr string 74 | addrIP net.IP 75 | gw string 76 | gwIP net.IP 77 | marker []byte 78 | f *os.File 79 | } 80 | 81 | func (dev *tunDev) Read(data []byte) (int, error) { 82 | n, e := dev.f.Read(data) 83 | if e == nil && isStopMarker(data[:n], dev.addrIP, dev.gwIP) { 84 | return 0, errors.New("received stop marker") 85 | } 86 | return n, e 87 | } 88 | 89 | func (dev *tunDev) Write(data []byte) (int, error) { 90 | return dev.f.Write(data) 91 | } 92 | 93 | func (dev *tunDev) Close() error { 94 | log.Printf("send stop marker") 95 | sendStopMarker(dev.addr, dev.gw) 96 | return dev.f.Close() 97 | } 98 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/tun/tun_windows.go: -------------------------------------------------------------------------------- 1 | package tun 2 | 3 | import ( 4 | "encoding/binary" 5 | // "encoding/hex" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "log" 10 | "net" 11 | "os/exec" 12 | "strings" 13 | "syscall" 14 | "unsafe" 15 | 16 | "golang.org/x/sys/windows" 17 | "golang.org/x/sys/windows/registry" 18 | ) 19 | 20 | const ( 21 | TAPWIN32_MAX_REG_SIZE = 256 22 | TUNTAP_COMPONENT_ID_0901 = "tap0901" 23 | TUNTAP_COMPONENT_ID_0801 = "tap0801" 24 | NETWORK_KEY = `SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}` 25 | ADAPTER_KEY = `SYSTEM\CurrentControlSet\Control\Class\{4D36E972-E325-11CE-BFC1-08002BE10318}` 26 | ) 27 | 28 | func ctl_code(device_type, function, method, access uint32) uint32 { 29 | return (device_type << 16) | (access << 14) | (function << 2) | method 30 | } 31 | 32 | func tap_control_code(request, method uint32) uint32 { 33 | return ctl_code(34, request, method, 0) 34 | } 35 | 36 | var ( 37 | k32 = windows.NewLazySystemDLL("kernel32.dll") 38 | procGetOverlappedResult = k32.NewProc("GetOverlappedResult") 39 | TAP_IOCTL_GET_MTU = tap_control_code(3, 0) 40 | TAP_IOCTL_SET_MEDIA_STATUS = tap_control_code(6, 0) 41 | TAP_IOCTL_CONFIG_TUN = tap_control_code(10, 0) 42 | TAP_WIN_IOCTL_CONFIG_DHCP_MASQ = tap_control_code(7, 0) 43 | TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT = tap_control_code(9, 0) 44 | ) 45 | 46 | func decodeUTF16(b []byte) string { 47 | if len(b)%2 != 0 { 48 | return "" 49 | } 50 | 51 | l := len(b) / 2 52 | u16 := make([]uint16, l) 53 | for i := 0; i < l; i += 1 { 54 | u16[i] = uint16(b[2*i]) + (uint16(b[2*i+1]) << 8) 55 | } 56 | return windows.UTF16ToString(u16) 57 | } 58 | 59 | func getTuntapName(componentId string) (string, error) { 60 | keyName := fmt.Sprintf(NETWORK_KEY+"\\%s\\Connection", componentId) 61 | key, err := registry.OpenKey(registry.LOCAL_MACHINE, keyName, registry.READ) 62 | if err != nil { 63 | key.Close() 64 | return "", err 65 | } 66 | var bufLength uint32 = TAPWIN32_MAX_REG_SIZE 67 | buf := make([]byte, bufLength) 68 | name, _ := windows.UTF16FromString("Name") 69 | var valtype uint32 70 | err = windows.RegQueryValueEx( 71 | windows.Handle(key), 72 | &name[0], 73 | nil, 74 | &valtype, 75 | &buf[0], 76 | &bufLength, 77 | ) 78 | if err != nil { 79 | key.Close() 80 | return "", err 81 | } 82 | s := decodeUTF16(buf) 83 | return s, nil 84 | } 85 | 86 | func getTuntapComponentId() (string, error) { 87 | adapters, err := registry.OpenKey(registry.LOCAL_MACHINE, ADAPTER_KEY, registry.READ) 88 | if err != nil { 89 | return "", err 90 | } 91 | var i uint32 92 | for i = 0; i < 1000; i++ { 93 | var name_length uint32 = TAPWIN32_MAX_REG_SIZE 94 | buf := make([]uint16, name_length) 95 | if err = windows.RegEnumKeyEx( 96 | windows.Handle(adapters), 97 | i, 98 | &buf[0], 99 | &name_length, 100 | nil, 101 | nil, 102 | nil, 103 | nil); err != nil { 104 | return "", err 105 | } 106 | key_name := windows.UTF16ToString(buf[:]) 107 | adapter, err := registry.OpenKey(adapters, key_name, registry.READ) 108 | if err != nil { 109 | continue 110 | } 111 | name, _ := windows.UTF16FromString("ComponentId") 112 | name2, _ := windows.UTF16FromString("NetCfgInstanceId") 113 | var valtype uint32 114 | var component_id = make([]byte, TAPWIN32_MAX_REG_SIZE) 115 | var componentLen = uint32(len(component_id)) 116 | if err = windows.RegQueryValueEx( 117 | windows.Handle(adapter), 118 | &name[0], 119 | nil, 120 | &valtype, 121 | &component_id[0], 122 | &componentLen); err != nil { 123 | continue 124 | } 125 | 126 | id := decodeUTF16(component_id) 127 | if id == TUNTAP_COMPONENT_ID_0901 || id == TUNTAP_COMPONENT_ID_0801 { 128 | var valtype uint32 129 | var netCfgInstanceId = make([]byte, TAPWIN32_MAX_REG_SIZE) 130 | var netCfgInstanceIdLen = uint32(len(netCfgInstanceId)) 131 | if err = windows.RegQueryValueEx( 132 | windows.Handle(adapter), 133 | &name2[0], 134 | nil, 135 | &valtype, 136 | &netCfgInstanceId[0], 137 | &netCfgInstanceIdLen); err != nil { 138 | return "", err 139 | } 140 | s := decodeUTF16(netCfgInstanceId) 141 | log.Printf("device component id: %s", s) 142 | adapter.Close() 143 | adapters.Close() 144 | return s, nil 145 | } 146 | adapter.Close() 147 | } 148 | adapters.Close() 149 | return "", errors.New("not found component id") 150 | } 151 | 152 | func OpenTunDevice(name, addr, gw, mask string, dns []string) (io.ReadWriteCloser, error) { 153 | componentId, err := getTuntapComponentId() 154 | if err != nil { 155 | return nil, err 156 | } 157 | 158 | devId, _ := windows.UTF16FromString(fmt.Sprintf(`\\.\Global\%s.tap`, componentId)) 159 | devName, err := getTuntapName(componentId) 160 | log.Printf("device name: %s", devName) 161 | // set dhcp with netsh 162 | cmd := exec.Command("netsh", "interface", "ip", "set", "address", devName, "dhcp") 163 | cmd.Run() 164 | cmd = exec.Command("netsh", "interface", "ip", "set", "dns", devName, "dhcp") 165 | cmd.Run() 166 | // open 167 | fd, err := windows.CreateFile( 168 | &devId[0], 169 | windows.GENERIC_READ|windows.GENERIC_WRITE, 170 | windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, 171 | nil, 172 | windows.OPEN_EXISTING, 173 | windows.FILE_ATTRIBUTE_SYSTEM|windows.FILE_FLAG_OVERLAPPED, 174 | //windows.FILE_ATTRIBUTE_SYSTEM, 175 | 0, 176 | ) 177 | if err != nil { 178 | return nil, err 179 | } 180 | // set addresses with dhcp 181 | var returnLen uint32 182 | tunAddr := net.ParseIP(addr).To4() 183 | tunMask := net.ParseIP(mask).To4() 184 | gwAddr := net.ParseIP(gw).To4() 185 | addrParam := append(tunAddr, tunMask...) 186 | addrParam = append(addrParam, gwAddr...) 187 | lease := make([]byte, 4) 188 | binary.BigEndian.PutUint32(lease[:], 86400) 189 | addrParam = append(addrParam, lease...) 190 | err = windows.DeviceIoControl( 191 | fd, 192 | TAP_WIN_IOCTL_CONFIG_DHCP_MASQ, 193 | &addrParam[0], 194 | uint32(len(addrParam)), 195 | &addrParam[0], 196 | uint32(len(addrParam)), 197 | &returnLen, 198 | nil, 199 | ) 200 | if err != nil { 201 | windows.Close(fd) 202 | return nil, err 203 | } else { 204 | log.Printf("set %s with net/mask: %s/%s through DHCP", devName, addr, mask) 205 | } 206 | 207 | // set dns with dncp 208 | dnsParam := []byte{6, 4} 209 | primaryDNS := net.ParseIP(dns[0]).To4() 210 | dnsParam = append(dnsParam, primaryDNS...) 211 | if len(dns) >= 2 { 212 | secondaryDNS := net.ParseIP(dns[1]).To4() 213 | dnsParam = append(dnsParam, secondaryDNS...) 214 | dnsParam[1] += 4 215 | } 216 | err = windows.DeviceIoControl( 217 | fd, 218 | TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT, 219 | &dnsParam[0], 220 | uint32(len(dnsParam)), 221 | &addrParam[0], 222 | uint32(len(dnsParam)), 223 | &returnLen, 224 | nil, 225 | ) 226 | if err != nil { 227 | windows.Close(fd) 228 | return nil, err 229 | } else { 230 | log.Printf("set %s with dns: %s through DHCP", devName, strings.Join(dns, ",")) 231 | } 232 | 233 | // set connect. 234 | inBuffer := []byte("\x01\x00\x00\x00") 235 | err = windows.DeviceIoControl( 236 | fd, 237 | TAP_IOCTL_SET_MEDIA_STATUS, 238 | &inBuffer[0], 239 | uint32(len(inBuffer)), 240 | &inBuffer[0], 241 | uint32(len(inBuffer)), 242 | &returnLen, 243 | nil, 244 | ) 245 | if err != nil { 246 | windows.Close(fd) 247 | return nil, err 248 | } 249 | return newWinTapDev(fd, addr, gw), nil 250 | } 251 | 252 | type winTapDev struct { 253 | fd windows.Handle 254 | addr string 255 | addrIP net.IP 256 | gw string 257 | gwIP net.IP 258 | rBuf [2048]byte 259 | wBuf [2048]byte 260 | wInitiated bool 261 | rOverlapped windows.Overlapped 262 | wOverlapped windows.Overlapped 263 | } 264 | 265 | func newWinTapDev(fd windows.Handle, addr string, gw string) *winTapDev { 266 | rOverlapped := windows.Overlapped{} 267 | rEvent, _ := windows.CreateEvent(nil, 0, 0, nil) 268 | rOverlapped.HEvent = windows.Handle(rEvent) 269 | 270 | wOverlapped := windows.Overlapped{} 271 | wEvent, _ := windows.CreateEvent(nil, 0, 0, nil) 272 | wOverlapped.HEvent = windows.Handle(wEvent) 273 | 274 | dev := &winTapDev{ 275 | fd: fd, 276 | rOverlapped: rOverlapped, 277 | wOverlapped: wOverlapped, 278 | wInitiated: false, 279 | 280 | addr: addr, 281 | addrIP: net.ParseIP(addr).To4(), 282 | gw: gw, 283 | gwIP: net.ParseIP(gw).To4(), 284 | } 285 | return dev 286 | } 287 | 288 | func (dev *winTapDev) Read(data []byte) (int, error) { 289 | for { 290 | var done uint32 291 | var nr int 292 | 293 | err := windows.ReadFile(dev.fd, dev.rBuf[:], &done, &dev.rOverlapped) 294 | if err != nil { 295 | if err != windows.ERROR_IO_PENDING { 296 | return 0, err 297 | } else { 298 | windows.WaitForSingleObject(dev.rOverlapped.HEvent, windows.INFINITE) 299 | nr, err = getOverlappedResult(dev.fd, &dev.rOverlapped) 300 | if err != nil { 301 | return 0, err 302 | } 303 | } 304 | } else { 305 | nr = int(done) 306 | } 307 | if nr > 14 { 308 | if isStopMarker(dev.rBuf[14:nr], dev.addrIP, dev.gwIP) { 309 | return 0, errors.New("received stop marker") 310 | } 311 | 312 | // discard IPv6 packets 313 | if dev.rBuf[14]&0xf0 == 0x60 { 314 | log.Printf("ipv6 packet") 315 | continue 316 | } else if dev.rBuf[14]&0xf0 == 0x40 { 317 | if !dev.wInitiated { 318 | // copy ether header for writing 319 | copy(dev.wBuf[:], dev.rBuf[6:12]) 320 | copy(dev.wBuf[6:], dev.rBuf[0:6]) 321 | copy(dev.wBuf[12:], dev.rBuf[12:14]) 322 | dev.wInitiated = true 323 | } 324 | copy(data, dev.rBuf[14:nr]) 325 | return nr - 14, nil 326 | } 327 | } 328 | } 329 | } 330 | 331 | func (dev *winTapDev) Write(data []byte) (int, error) { 332 | var done uint32 333 | var nw int 334 | 335 | payloadL := copy(dev.wBuf[14:], data) 336 | packetL := payloadL + 14 337 | err := windows.WriteFile(dev.fd, dev.wBuf[:packetL], &done, &dev.wOverlapped) 338 | if err != nil { 339 | if err != windows.ERROR_IO_PENDING { 340 | return 0, err 341 | } else { 342 | windows.WaitForSingleObject(dev.wOverlapped.HEvent, windows.INFINITE) 343 | nw, err = getOverlappedResult(dev.fd, &dev.wOverlapped) 344 | if err != nil { 345 | return 0, err 346 | } 347 | } 348 | } else { 349 | nw = int(done) 350 | } 351 | if nw != packetL { 352 | return 0, fmt.Errorf("write %d packet (%d bytes payload), return %d", packetL, payloadL, nw) 353 | } else { 354 | return payloadL, nil 355 | } 356 | } 357 | 358 | func getOverlappedResult(h windows.Handle, overlapped *windows.Overlapped) (int, error) { 359 | var n int 360 | r, _, err := syscall.Syscall6(procGetOverlappedResult.Addr(), 4, 361 | uintptr(h), 362 | uintptr(unsafe.Pointer(overlapped)), 363 | uintptr(unsafe.Pointer(&n)), 1, 0, 0) 364 | if r == 0 { 365 | return n, err 366 | } 367 | return n, nil 368 | } 369 | 370 | func (dev *winTapDev) Close() error { 371 | log.Printf("close winTap device") 372 | sendStopMarker(dev.addr, dev.gw) 373 | return windows.Close(dev.fd) 374 | } 375 | -------------------------------------------------------------------------------- /vendor/github.com/yinghuocho/gotun2socks/udp.go: -------------------------------------------------------------------------------- 1 | package gotun2socks 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "net" 8 | "strings" 9 | "sync" 10 | "time" 11 | 12 | "github.com/miekg/dns" 13 | 14 | "github.com/yinghuocho/gotun2socks/internal/packet" 15 | ) 16 | 17 | type udpPacket struct { 18 | ip *packet.IPv4 19 | udp *packet.UDP 20 | mtuBuf []byte 21 | wire []byte 22 | } 23 | 24 | type udpConnTrack struct { 25 | t2s *Tun2Socks 26 | id string 27 | 28 | toTunCh chan<- interface{} 29 | quitBySelf chan bool 30 | quitByOther chan bool 31 | 32 | fromTunCh chan *udpPacket 33 | socksClosed chan bool 34 | 35 | localSocksAddr string 36 | socksConn net.Conn 37 | 38 | localIP net.IP 39 | remoteIP net.IP 40 | localPort uint16 41 | remotePort uint16 42 | } 43 | 44 | var ( 45 | udpPacketPool = &sync.Pool{ 46 | New: func() interface{} { 47 | return &udpPacket{} 48 | }, 49 | } 50 | ) 51 | 52 | func newUDPPacket() *udpPacket { 53 | return udpPacketPool.Get().(*udpPacket) 54 | } 55 | 56 | func releaseUDPPacket(pkt *udpPacket) { 57 | packet.ReleaseIPv4(pkt.ip) 58 | packet.ReleaseUDP(pkt.udp) 59 | if pkt.mtuBuf != nil { 60 | releaseBuffer(pkt.mtuBuf) 61 | } 62 | pkt.mtuBuf = nil 63 | pkt.wire = nil 64 | udpPacketPool.Put(pkt) 65 | } 66 | 67 | func udpConnID(ip *packet.IPv4, udp *packet.UDP) string { 68 | return strings.Join([]string{ 69 | ip.SrcIP.String(), 70 | fmt.Sprintf("%d", udp.SrcPort), 71 | ip.DstIP.String(), 72 | fmt.Sprintf("%d", udp.DstPort), 73 | }, "|") 74 | } 75 | 76 | func copyUDPPacket(raw []byte, ip *packet.IPv4, udp *packet.UDP) *udpPacket { 77 | iphdr := packet.NewIPv4() 78 | udphdr := packet.NewUDP() 79 | pkt := newUDPPacket() 80 | 81 | // make a deep copy 82 | var buf []byte 83 | if len(raw) <= MTU { 84 | buf = newBuffer() 85 | pkt.mtuBuf = buf 86 | } else { 87 | buf = make([]byte, len(raw)) 88 | } 89 | n := copy(buf, raw) 90 | pkt.wire = buf[:n] 91 | packet.ParseIPv4(pkt.wire, iphdr) 92 | packet.ParseUDP(iphdr.Payload, udphdr) 93 | pkt.ip = iphdr 94 | pkt.udp = udphdr 95 | 96 | return pkt 97 | } 98 | 99 | func responsePacket(local net.IP, remote net.IP, lPort uint16, rPort uint16, respPayload []byte) (*udpPacket, []*ipPacket) { 100 | ipid := packet.IPID() 101 | 102 | ip := packet.NewIPv4() 103 | udp := packet.NewUDP() 104 | 105 | ip.Version = 4 106 | ip.Id = ipid 107 | ip.SrcIP = make(net.IP, len(remote)) 108 | copy(ip.SrcIP, remote) 109 | ip.DstIP = make(net.IP, len(local)) 110 | copy(ip.DstIP, local) 111 | ip.TTL = 64 112 | ip.Protocol = packet.IPProtocolUDP 113 | 114 | udp.SrcPort = rPort 115 | udp.DstPort = lPort 116 | udp.Payload = respPayload 117 | 118 | pkt := newUDPPacket() 119 | pkt.ip = ip 120 | pkt.udp = udp 121 | 122 | pkt.mtuBuf = newBuffer() 123 | payloadL := len(udp.Payload) 124 | payloadStart := MTU - payloadL 125 | // if payload too long, need fragment, only part of payload put to mtubuf[28:] 126 | if payloadL > MTU-28 { 127 | ip.Flags = 1 128 | payloadStart = 28 129 | } 130 | udpHL := 8 131 | udpStart := payloadStart - udpHL 132 | pseduoStart := udpStart - packet.IPv4_PSEUDO_LENGTH 133 | ip.PseudoHeader(pkt.mtuBuf[pseduoStart:udpStart], packet.IPProtocolUDP, udpHL+payloadL) 134 | // udp length and checksum count on full payload 135 | udp.Serialize(pkt.mtuBuf[udpStart:payloadStart], pkt.mtuBuf[pseduoStart:payloadStart], udp.Payload) 136 | if payloadL != 0 { 137 | copy(pkt.mtuBuf[payloadStart:], udp.Payload) 138 | } 139 | ipHL := ip.HeaderLength() 140 | ipStart := udpStart - ipHL 141 | // ip length and checksum count on actual transmitting payload 142 | ip.Serialize(pkt.mtuBuf[ipStart:udpStart], udpHL+(MTU-payloadStart)) 143 | pkt.wire = pkt.mtuBuf[ipStart:] 144 | 145 | if ip.Flags == 0 { 146 | return pkt, nil 147 | } 148 | // generate fragments 149 | frags := genFragments(ip, (MTU-20)/8, respPayload[MTU-28:]) 150 | return pkt, frags 151 | } 152 | 153 | func (ut *udpConnTrack) send(data []byte) { 154 | pkt, fragments := responsePacket(ut.localIP, ut.remoteIP, ut.localPort, ut.remotePort, data) 155 | ut.toTunCh <- pkt 156 | if fragments != nil { 157 | for _, frag := range fragments { 158 | ut.toTunCh <- frag 159 | } 160 | } 161 | } 162 | 163 | func (ut *udpConnTrack) run() { 164 | childctx, cancel := context.WithCancel(ut.t2s.ctx) 165 | // connect to socks 166 | var e error 167 | for i := 0; i < 2; i++ { 168 | ut.socksConn, e = ut.t2s.dialer.Dial("udp4", ut.remoteIP.String(), ut.remotePort, childctx) 169 | if e != nil { 170 | log.Printf("fail to connect SOCKS proxy: %s", e) 171 | } else { 172 | // need to finish handshake in 1 mins 173 | ut.socksConn.SetDeadline(time.Now().Add(time.Minute * 1)) 174 | break 175 | } 176 | } 177 | if ut.socksConn == nil { 178 | close(ut.socksClosed) 179 | close(ut.quitBySelf) 180 | ut.t2s.clearUDPConnTrack(ut.id) 181 | cancel() 182 | return 183 | } 184 | /* 185 | // create one UDP to recv/send packets 186 | socksAddr := ut.socksConn.LocalAddr().(*net.TCPAddr) 187 | udpBind, err := net.ListenUDP("udp", &net.UDPAddr{ 188 | IP: socksAddr.IP, 189 | Port: 0, 190 | Zone: socksAddr.Zone, 191 | }) 192 | if err != nil { 193 | log.Printf("error in binding local UDP: %s", err) 194 | ut.socksConn.Close() 195 | close(ut.socksClosed) 196 | close(ut.quitBySelf) 197 | ut.t2s.clearUDPConnTrack(ut.id) 198 | return 199 | } 200 | 201 | // socks request/reply 202 | _, e = gosocks.WriteSocksRequest(ut.socksConn, &gosocks.SocksRequest{ 203 | Cmd: gosocks.SocksCmdUDPAssociate, 204 | HostType: gosocks.SocksIPv4Host, 205 | DstHost: "0.0.0.0", 206 | DstPort: 0, 207 | }) 208 | if e != nil { 209 | log.Printf("error to send socks request: %s", e) 210 | ut.socksConn.Close() 211 | close(ut.socksClosed) 212 | close(ut.quitBySelf) 213 | ut.t2s.clearUDPConnTrack(ut.id) 214 | return 215 | } 216 | reply, e := gosocks.ReadSocksReply(ut.socksConn) 217 | if e != nil { 218 | log.Printf("error to read socks reply: %s", e) 219 | ut.socksConn.Close() 220 | close(ut.socksClosed) 221 | close(ut.quitBySelf) 222 | ut.t2s.clearUDPConnTrack(ut.id) 223 | return 224 | } 225 | if reply.Rep != gosocks.SocksSucceeded { 226 | log.Printf("socks connect request fail, retcode: %d", reply.Rep) 227 | ut.socksConn.Close() 228 | close(ut.socksClosed) 229 | close(ut.quitBySelf) 230 | ut.t2s.clearUDPConnTrack(ut.id) 231 | return 232 | } 233 | relayAddr := gosocks.SocksAddrToNetAddr("udp", reply.BndHost, reply.BndPort).(*net.UDPAddr) 234 | 235 | ut.socksConn.SetDeadline(time.Time{}) 236 | // monitor socks TCP connection 237 | go gosocks.ConnMonitor(ut.socksConn, ut.socksClosed) 238 | // read UDP packets from relay 239 | 240 | chRelayUDP := make(chan *gosocks.UDPPacket) 241 | go gosocks.UDPReader(udpBind, chRelayUDP, quitUDP) 242 | */ 243 | 244 | quitUDP := make(chan bool) 245 | start := time.Now() 246 | go func() { 247 | var buffer [1500]byte 248 | for { 249 | if childctx.Err() != nil { 250 | return 251 | } 252 | n, err := ut.socksConn.Read(buffer[:]) 253 | if err != nil { 254 | cancel() 255 | return 256 | } 257 | ut.send(buffer[:n]) 258 | if ut.t2s.isDNS(ut.remoteIP.String(), ut.remotePort) { 259 | // DNS-without-fragment only has one request-response 260 | end := time.Now() 261 | ms := end.Sub(start).Nanoseconds() / 1000000 262 | log.Printf("DNS session response received: %d ms", ms) 263 | if ut.t2s.cache != nil { 264 | ut.t2s.cache.store(buffer[:n]) 265 | } 266 | ut.socksConn.Close() 267 | //close(ut.quitBySelf) 268 | ut.t2s.clearUDPConnTrack(ut.id) 269 | //close(quitUDP) 270 | return 271 | } 272 | } 273 | }() 274 | for { 275 | var t *time.Timer 276 | if ut.t2s.isDNS(ut.remoteIP.String(), ut.remotePort) { 277 | t = time.NewTimer(10 * time.Second) 278 | } else { 279 | t = time.NewTimer(2 * time.Minute) 280 | } 281 | select { 282 | // pkt from tun 283 | case pkt := <-ut.fromTunCh: 284 | 285 | _, err := ut.socksConn.Write(pkt.udp.Payload) 286 | releaseUDPPacket(pkt) 287 | if err != nil { 288 | log.Printf("error to send UDP packet to relay: %s", err) 289 | ut.socksConn.Close() 290 | close(ut.quitBySelf) 291 | ut.t2s.clearUDPConnTrack(ut.id) 292 | close(quitUDP) 293 | cancel() 294 | return 295 | } 296 | 297 | case <-ut.socksClosed: 298 | ut.socksConn.Close() 299 | close(ut.quitBySelf) 300 | ut.t2s.clearUDPConnTrack(ut.id) 301 | close(quitUDP) 302 | cancel() 303 | return 304 | 305 | case <-t.C: 306 | ut.socksConn.Close() 307 | cancel() 308 | close(ut.quitBySelf) 309 | ut.t2s.clearUDPConnTrack(ut.id) 310 | close(quitUDP) 311 | return 312 | 313 | case <-ut.quitByOther: 314 | log.Printf("udpConnTrack quitByOther") 315 | ut.socksConn.Close() 316 | cancel() 317 | close(quitUDP) 318 | return 319 | 320 | case <-childctx.Done(): 321 | //ut.socksConn.Close() 322 | //close(quitUDP) 323 | } 324 | t.Stop() 325 | } 326 | } 327 | 328 | func (ut *udpConnTrack) newPacket(pkt *udpPacket) { 329 | select { 330 | case <-ut.quitByOther: 331 | case <-ut.quitBySelf: 332 | case ut.fromTunCh <- pkt: 333 | // log.Printf("--> [UDP][%s]", ut.id) 334 | } 335 | } 336 | 337 | func (t2s *Tun2Socks) clearUDPConnTrack(id string) { 338 | t2s.udpConnTrackLock.Lock() 339 | defer t2s.udpConnTrackLock.Unlock() 340 | 341 | delete(t2s.udpConnTrackMap, id) 342 | log.Printf("tracking %d UDP connections", len(t2s.udpConnTrackMap)) 343 | } 344 | 345 | func (t2s *Tun2Socks) getUDPConnTrack(id string, ip *packet.IPv4, udp *packet.UDP) *udpConnTrack { 346 | t2s.udpConnTrackLock.Lock() 347 | defer t2s.udpConnTrackLock.Unlock() 348 | 349 | track := t2s.udpConnTrackMap[id] 350 | if track != nil { 351 | return track 352 | } else { 353 | track := &udpConnTrack{ 354 | t2s: t2s, 355 | id: id, 356 | toTunCh: t2s.writeCh, 357 | fromTunCh: make(chan *udpPacket, 100), 358 | socksClosed: make(chan bool), 359 | quitBySelf: make(chan bool), 360 | quitByOther: make(chan bool), 361 | 362 | localPort: udp.SrcPort, 363 | remotePort: udp.DstPort, 364 | 365 | localSocksAddr: t2s.localSocksAddr, 366 | } 367 | track.localIP = make(net.IP, len(ip.SrcIP)) 368 | copy(track.localIP, ip.SrcIP) 369 | track.remoteIP = make(net.IP, len(ip.DstIP)) 370 | copy(track.remoteIP, ip.DstIP) 371 | 372 | t2s.udpConnTrackMap[id] = track 373 | go track.run() 374 | log.Printf("tracking %d UDP connections", len(t2s.udpConnTrackMap)) 375 | return track 376 | } 377 | } 378 | 379 | func (t2s *Tun2Socks) udp(raw []byte, ip *packet.IPv4, udp *packet.UDP) { 380 | var buf [1024]byte 381 | var done bool 382 | 383 | // first look at dns cache 384 | if t2s.cache != nil && t2s.isDNS(ip.DstIP.String(), udp.DstPort) { 385 | answer := t2s.cache.query(udp.Payload) 386 | if answer != nil { 387 | data, e := answer.PackBuffer(buf[:]) 388 | if e == nil { 389 | resp, fragments := responsePacket(ip.SrcIP, ip.DstIP, udp.SrcPort, udp.DstPort, data) 390 | go func(first *udpPacket, frags []*ipPacket) { 391 | t2s.writeCh <- first 392 | if frags != nil { 393 | for _, frag := range frags { 394 | t2s.writeCh <- frag 395 | } 396 | } 397 | }(resp, fragments) 398 | done = true 399 | } 400 | } 401 | } 402 | 403 | // then open a udpConnTrack to forward 404 | if !done { 405 | connID := udpConnID(ip, udp) 406 | pkt := copyUDPPacket(raw, ip, udp) 407 | track := t2s.getUDPConnTrack(connID, ip, udp) 408 | track.newPacket(pkt) 409 | } 410 | } 411 | 412 | type dnsCacheEntry struct { 413 | msg *dns.Msg 414 | exp time.Time 415 | } 416 | 417 | type dnsCache struct { 418 | servers []string 419 | mutex sync.Mutex 420 | storage map[string]*dnsCacheEntry 421 | } 422 | 423 | func packUint16(i uint16) []byte { return []byte{byte(i >> 8), byte(i)} } 424 | 425 | func cacheKey(q dns.Question) string { 426 | return string(append([]byte(q.Name), packUint16(q.Qtype)...)) 427 | } 428 | 429 | func (t2s *Tun2Socks) isDNS(remoteIP string, remotePort uint16) bool { 430 | if remotePort != 53 { 431 | return false 432 | } 433 | for _, s := range t2s.dnsServers { 434 | if s == remoteIP { 435 | return true 436 | } 437 | } 438 | return false 439 | } 440 | 441 | func (c *dnsCache) query(payload []byte) *dns.Msg { 442 | request := new(dns.Msg) 443 | e := request.Unpack(payload) 444 | if e != nil { 445 | return nil 446 | } 447 | if len(request.Question) == 0 { 448 | return nil 449 | } 450 | 451 | c.mutex.Lock() 452 | defer c.mutex.Unlock() 453 | key := cacheKey(request.Question[0]) 454 | entry := c.storage[key] 455 | if entry == nil { 456 | return nil 457 | } 458 | if time.Now().After(entry.exp) { 459 | delete(c.storage, key) 460 | return nil 461 | } 462 | entry.msg.Id = request.Id 463 | return entry.msg 464 | } 465 | 466 | func (c *dnsCache) store(payload []byte) { 467 | resp := new(dns.Msg) 468 | e := resp.Unpack(payload) 469 | if e != nil { 470 | return 471 | } 472 | if resp.Rcode != dns.RcodeSuccess { 473 | return 474 | } 475 | if len(resp.Question) == 0 || len(resp.Answer) == 0 { 476 | return 477 | } 478 | 479 | c.mutex.Lock() 480 | defer c.mutex.Unlock() 481 | key := cacheKey(resp.Question[0]) 482 | log.Printf("cache DNS response for %s", key) 483 | c.storage[key] = &dnsCacheEntry{ 484 | msg: resp, 485 | exp: time.Now().Add(time.Duration(resp.Answer[0].Header().Ttl) * time.Second), 486 | } 487 | } 488 | -------------------------------------------------------------------------------- /wavingocean.go: -------------------------------------------------------------------------------- 1 | package wavingocean 2 | --------------------------------------------------------------------------------