From 9b0371a813c87f0c039f2d3eb248928e3e4b570e Mon Sep 17 00:00:00 2001 From: ZhangFeng Date: Tue, 30 Dec 2014 13:52:24 +0800 Subject: [PATCH 1/2] =?UTF-8?q?Support=20Android=20Client=EF=BC=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hop/buffer.go | 115 ++++--- hop/cipher.go | 72 ++-- hop/client.go | 635 +++++++++++++++++------------------ hop/common.go | 4 +- hop/config.go | 122 ++++--- hop/iface.go | 400 +++++++++++----------- hop/ippool.go | 69 ++-- hop/protocol.go | 344 ++++++++++--------- hop/server.go | 860 ++++++++++++++++++++++++++++-------------------- main.go | 120 ++++--- route.ini | 31 ++ server.ini | 17 +- vpn.sh | 72 ++++ 13 files changed, 1610 insertions(+), 1251 deletions(-) create mode 100644 route.ini create mode 100755 vpn.sh diff --git a/hop/buffer.go b/hop/buffer.go index 6fa1a62..9306d55 100644 --- a/hop/buffer.go +++ b/hop/buffer.go @@ -21,98 +21,97 @@ package hop import ( - "sort" - "errors" - "sync" - "time" + "errors" + "sort" + "sync" + "time" ) const ( - hpBufSize = 384 - bufferTimeout = 20 * time.Millisecond + hpBufSize = 384 + bufferTimeout = 20 * time.Millisecond ) type hopPacketBuffer struct { - buf [hpBufSize]*HopPacket - outQueue []*HopPacket - count int - timer *time.Timer - timeout time.Duration - flushChan chan *HopPacket - mutex sync.Mutex + buf [hpBufSize]*HopPacket + outQueue []*HopPacket + count int + timer *time.Timer + timeout time.Duration + flushChan chan *HopPacket + mutex sync.Mutex } var bufFull = errors.New("Buffer Full") func newHopPacketBuffer(flushChan chan *HopPacket, timeout time.Duration) *hopPacketBuffer { - hb := new(hopPacketBuffer) - hb.count = 0 - hb.timer = time.NewTimer(1000*time.Second) - hb.timer.Stop() - hb.flushChan = flushChan - hb.timeout = timeout - go func() { - for { - <-hb.timer.C - hb.FlushToChan(hb.flushChan) - hb.timer.Reset(hb.timeout) - } - }() - return hb + hb := new(hopPacketBuffer) + hb.count = 0 + hb.timer = time.NewTimer(1000 * time.Second) + hb.timer.Stop() + hb.flushChan = flushChan + hb.timeout = timeout + go func() { + for { + <-hb.timer.C + hb.FlushToChan(hb.flushChan) + hb.timer.Reset(hb.timeout) + } + }() + return hb } func (hb *hopPacketBuffer) Push(p *HopPacket) { - defer hb.mutex.Unlock() - hb.mutex.Lock() + defer hb.mutex.Unlock() + hb.mutex.Lock() - hb.timer.Reset(hb.timeout) + hb.timer.Reset(hb.timeout) - hb.buf[hb.count] = p - hb.count += 1 - if hb.count >= hpBufSize { - // logger.Warning("buffer full, flushing") - hb._flush() - } + hb.buf[hb.count] = p + hb.count += 1 + if hb.count >= hpBufSize { + // logger.Warning("buffer full, flushing") + hb._flush() + } } func (hb *hopPacketBuffer) Len() int { return len(hb.outQueue) } func (hb *hopPacketBuffer) Less(i, j int) bool { - a, b := hb.outQueue[i], hb.outQueue[j] - return a.Seq < b.Seq + a, b := hb.outQueue[i], hb.outQueue[j] + return a.Seq < b.Seq } func (hb *hopPacketBuffer) Swap(i, j int) { - hb.outQueue[i], hb.outQueue[j] = hb.outQueue[j], hb.outQueue[i] + hb.outQueue[i], hb.outQueue[j] = hb.outQueue[j], hb.outQueue[i] } - func (hb *hopPacketBuffer) Flush() { - defer hb.mutex.Unlock() - hb.mutex.Lock() - hb._flushToChan(hb.flushChan) + defer hb.mutex.Unlock() + hb.mutex.Lock() + hb._flushToChan(hb.flushChan) } func (hb *hopPacketBuffer) _flush() { - hb._flushToChan(hb.flushChan) + hb._flushToChan(hb.flushChan) } func (hb *hopPacketBuffer) _flushToChan(c chan *HopPacket) { - if hopFrager != nil { - hb.outQueue = hopFrager.reAssemble(hb.buf[:hb.count]) - } else { - hb.outQueue = hb.buf[:hb.count] - } - - sort.Sort(hb) - for _, p := range(hb.outQueue) { - c <- p - } - hb.count = 0 + if hopFrager != nil { + hb.outQueue = hopFrager.reAssemble(hb.buf[:hb.count]) + } else { + hb.outQueue = hb.buf[:hb.count] + } + + sort.Sort(hb) + for _, p := range hb.outQueue { + c <- p + } + hb.count = 0 } func (hb *hopPacketBuffer) FlushToChan(c chan *HopPacket) { - defer hb.mutex.Unlock() - hb.mutex.Lock() - hb._flushToChan(c) + defer hb.mutex.Unlock() + hb.mutex.Lock() + hb._flushToChan(c) } diff --git a/hop/cipher.go b/hop/cipher.go index dbeb137..abc2180 100644 --- a/hop/cipher.go +++ b/hop/cipher.go @@ -19,61 +19,63 @@ package hop import ( - "bytes" - "crypto/aes" - _cipher "crypto/cipher" - "crypto/rand" + "bytes" + "crypto/aes" + _cipher "crypto/cipher" + "crypto/md5" + "crypto/rand" ) type hopCipher struct { - block _cipher.Block + block _cipher.Block } const cipherBlockSize = 16 func newHopCipher(key []byte) (*hopCipher, error) { - s := new(hopCipher) - key = PKCS5Padding(key, cipherBlockSize) - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - s.block = block - return s, nil + s := new(hopCipher) + // key = PKCS5Padding(key, cipherBlockSize) + key1 := md5.Sum(key) + block, err := aes.NewCipher(key1[:]) + if err != nil { + return nil, err + } + s.block = block + return s, nil } func (s *hopCipher) encrypt(msg []byte) []byte { - pmsg := PKCS5Padding(msg, cipherBlockSize) - buf := make([]byte, len(pmsg)+cipherBlockSize) + pmsg := PKCS5Padding(msg, cipherBlockSize) + buf := make([]byte, len(pmsg)+cipherBlockSize) - iv := buf[:cipherBlockSize] - rand.Read(iv) - encrypter := _cipher.NewCBCEncrypter(s.block, iv) - encrypter.CryptBlocks(buf[cipherBlockSize:], pmsg) + iv := buf[:cipherBlockSize] + rand.Read(iv) + encrypter := _cipher.NewCBCEncrypter(s.block, iv) + encrypter.CryptBlocks(buf[cipherBlockSize:], pmsg) - return buf + return buf } func (s *hopCipher) decrypt(iv []byte, ctext []byte) []byte { - defer func(){ - if err := recover(); err != nil { - logger.Error("%v", err) - } - }() - decrypter := _cipher.NewCBCDecrypter(s.block, iv) - buf := make([]byte, len(ctext)) - decrypter.CryptBlocks(buf, ctext) - return PKCS5UnPadding(buf) + defer func() { + if err := recover(); err != nil { + logger.Error("%v", err) + } + }() + decrypter := _cipher.NewCBCDecrypter(s.block, iv) + buf := make([]byte, len(ctext)) + decrypter.CryptBlocks(buf, ctext) + return PKCS5UnPadding(buf) } func PKCS5Padding(ciphertext []byte, blockSize int) []byte { - padding := blockSize - len(ciphertext)%blockSize - padtext := bytes.Repeat([]byte{byte(padding)}, padding) - return append(ciphertext, padtext...) + padding := blockSize - len(ciphertext)%blockSize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(ciphertext, padtext...) } func PKCS5UnPadding(origData []byte) []byte { - length := len(origData) - unpadding := int(origData[length-1]) - return origData[:(length - unpadding)] + length := len(origData) + unpadding := int(origData[length-1]) + return origData[:(length - unpadding)] } diff --git a/hop/client.go b/hop/client.go index c4c1b89..83ebc56 100644 --- a/hop/client.go +++ b/hop/client.go @@ -19,382 +19,369 @@ package hop import ( - "net" - "os" - "os/signal" - "syscall" - "time" - "fmt" - "errors" - "crypto/rand" - mrand "math/rand" - "github.com/bigeagle/water" - "sync/atomic" + "crypto/rand" + "errors" + "fmt" + "github.com/bigeagle/water" + mrand "math/rand" + "net" + "os" + "os/signal" + "sync/atomic" + "syscall" + "time" ) var net_gateway, net_nic string type route struct { - dest, nextHop, iface string + dest, nextHop, iface string } type HopClient struct { - // config - cfg HopClientConfig - // interface - iface *water.Interface - // ip addr - ip net.IP - - // session id - sid [4]byte - // session state - state int32 - - // net to interface - toIface chan *HopPacket - // buffer for packets from net - recvBuf *hopPacketBuffer - // channel to send frames to net - toNet chan *HopPacket - - handshakeDone chan byte - finishAck chan byte - // state variable to ensure serverRoute added - srvRoute int32 - // routes need to be clean in the end - routes []string - // sequence number - seq uint32 + // config + cfg *HopClientConfig + // interface + iface *water.Interface + // ip addr + ip net.IP + + // session id + sid [4]byte + // session state + state int32 + + // net to interface + toIface chan *HopPacket + // buffer for packets from net + recvBuf *hopPacketBuffer + // channel to send frames to net + toNet chan *HopPacket + + handshakeDone chan byte + finishAck chan byte + // state variable to ensure serverRoute added + srvRoute int32 + // routes need to be clean in the end + routes []string + // sequence number + seq uint32 } - -func NewClient(cfg HopClientConfig) error { - var err error - - // logger.Debug("%v", cfg) - cipher, err = newHopCipher([]byte(cfg.Key)) - if err != nil { - return err - } - - if cfg.MTU != 0 { - MTU = cfg.MTU - } - - hopClient := new(HopClient) - rand.Read(hopClient.sid[:]) - hopClient.toIface = make(chan *HopPacket, 32) - hopClient.toNet = make(chan *HopPacket, 32) - hopClient.recvBuf = newHopPacketBuffer(hopClient.toIface, bufferTimeout) - hopClient.cfg = cfg - hopClient.state = HOP_STAT_INIT - hopClient.handshakeDone = make(chan byte) - hopClient.finishAck = make(chan byte) - hopClient.srvRoute = 0 - hopClient.routes = make([]string, 0, 1024) - - switch cfg.MorphMethod { - case "randsize": - m := newRandMorpher(MTU) - hopFrager = newHopFragmenter(m) - logger.Info("Using RandomSize Morpher") - default: - logger.Info("No Traffic Morphing") - } - - go hopClient.cleanUp() - - iface, err := newTun("") - if err != nil { - return err - } - hopClient.iface = iface - - net_gateway, net_nic, err = getNetGateway() - logger.Debug("Net Gateway: %s %s", net_gateway, net_nic) - if err != nil { - return err - } - - for port := cfg.HopStart; port <= cfg.HopEnd; port++ { - server := fmt.Sprintf("%s:%d", cfg.Server, port) - go hopClient.handleUDP(server) - } - - - // wait until handshake done - res := <-hopClient.handshakeDone - if res == 0 { - return errors.New("Handshake Fail") - } - - routeDone := make(chan bool) - go func() { - for _, dest := range cfg.Net_gateway { - addRoute(dest, net_gateway, net_nic) - hopClient.routes = append(hopClient.routes, dest) - } - if cfg.Redirect_gateway { - routeDone <- true - } - }() - - if cfg.Redirect_gateway { - go func() { - <-routeDone - err = redirectGateway(iface.Name(), tun_peer.String()) - if err != nil { - logger.Error(err.Error()) - return - } - }() - } - - hopClient.handleInterface() - - return errors.New("Not expected to exit") +func NewClient(cfg *HopClientConfig) error { + var err error + + // logger.Debug("%v", cfg) + cipher, err = newHopCipher([]byte(cfg.Key)) + if err != nil { + return err + } + + if cfg.MTU != 0 { + MTU = cfg.MTU + } + + hopClient := new(HopClient) + rand.Read(hopClient.sid[:]) + hopClient.toIface = make(chan *HopPacket, 32) + hopClient.toNet = make(chan *HopPacket, 32) + hopClient.recvBuf = newHopPacketBuffer(hopClient.toIface, bufferTimeout) + hopClient.cfg = cfg + hopClient.state = HOP_STAT_INIT + hopClient.handshakeDone = make(chan byte) + hopClient.finishAck = make(chan byte) + hopClient.srvRoute = 0 + hopClient.routes = make([]string, 0, 1024) + + switch cfg.MorphMethod { + case "randsize": + m := newRandMorpher(MTU) + hopFrager = newHopFragmenter(m) + logger.Info("Using RandomSize Morpher") + default: + logger.Info("No Traffic Morphing") + } + + go hopClient.cleanUp() + + iface, err := newTun("") + if err != nil { + return err + } + hopClient.iface = iface + + net_gateway, net_nic, err = getNetGateway() + logger.Debug("Net Gateway: %s %s", net_gateway, net_nic) + if err != nil { + return err + } + + for port := cfg.HopStart; port <= cfg.HopEnd; port++ { + server := fmt.Sprintf("%s:%d", cfg.Server, port) + go hopClient.handleUDP(server) + } + + // wait until handshake done + res := <-hopClient.handshakeDone + if res == 0 { + return errors.New("Handshake Fail") + } + + routeDone := make(chan bool) + go func() { + for _, dest := range cfg.Net_gateway { + addRoute(dest, net_gateway, net_nic) + hopClient.routes = append(hopClient.routes, dest) + } + if cfg.Redirect_gateway { + routeDone <- true + } + }() + + if cfg.Redirect_gateway { + go func() { + <-routeDone + err = redirectGateway(iface.Name(), tun_peer.String()) + if err != nil { + logger.Error(err.Error()) + return + } + }() + } + + hopClient.handleInterface() + + return errors.New("Not expected to exit") } func (clt *HopClient) handleInterface() { - // network packet to interface - go func() { - for { - hp := <-clt.toIface - // logger.Debug("New Net packet to device") - _, err := clt.iface.Write(hp.payload) - // logger.Debug("n: %d, len: %d", n, len(hp.payload)) - if err != nil { - logger.Error(err.Error()) - return - } - } - }() - - frame := make([]byte, IFACE_BUFSIZE) - for { - n, err := clt.iface.Read(frame) - if err != nil { - logger.Error(err.Error()) - return - } - - buf := make([]byte, n+HOP_HDR_LEN) - copy(buf[HOP_HDR_LEN:], frame[:n]) - if hopFrager == nil { - // if no traffic morphing - // Hack to reduce memcopy - hp := new(HopPacket) - hp.payload = buf[HOP_HDR_LEN:] - hp.buf = buf - hp.Seq = clt.Seq() - clt.toNet <- hp - - } else { - // with traffic morphing - packets := hopFrager.Fragmentate(clt, buf[HOP_HDR_LEN:]) - for _, hp := range(packets) { - clt.toNet <- hp - } - } - - } + // network packet to interface + go func() { + for { + hp := <-clt.toIface + // logger.Debug("New Net packet to device") + _, err := clt.iface.Write(hp.payload) + // logger.Debug("n: %d, len: %d", n, len(hp.payload)) + if err != nil { + logger.Error(err.Error()) + return + } + } + }() + + frame := make([]byte, IFACE_BUFSIZE) + for { + n, err := clt.iface.Read(frame) + if err != nil { + logger.Error(err.Error()) + return + } + + buf := make([]byte, n+HOP_HDR_LEN) + copy(buf[HOP_HDR_LEN:], frame[:n]) + if hopFrager == nil { + // if no traffic morphing + // Hack to reduce memcopy + hp := new(HopPacket) + hp.payload = buf[HOP_HDR_LEN:] + hp.buf = buf + hp.Seq = clt.Seq() + clt.toNet <- hp + + } else { + // with traffic morphing + packets := hopFrager.Fragmentate(clt, buf[HOP_HDR_LEN:]) + for _, hp := range packets { + clt.toNet <- hp + } + } + + } } func (clt *HopClient) handleUDP(server string) { - udpAddr, _ := net.ResolveUDPAddr("udp", server) - udpConn, _ := net.DialUDP("udp", nil, udpAddr) - - logger.Debug(udpConn.RemoteAddr().String()) - - // packet map - pktHandle := map[byte](func(*net.UDPConn, *HopPacket)){ - HOP_FLG_HSH | HOP_FLG_ACK: clt.handleHandshakeAck, - HOP_FLG_HSH | HOP_FLG_FIN: clt.handleHandshakeError, - HOP_FLG_DAT: clt.handleDataPacket, - HOP_FLG_DAT | HOP_FLG_MFR: clt.handleDataPacket, - HOP_FLG_FIN | HOP_FLG_ACK: clt.handleFinishAck, - } - - clt.knock(udpConn) - go func() { - n := mrand.Intn(1000) - time.Sleep(time.Duration(n) * time.Millisecond) - clt.handeshake(udpConn) - }() - - // add route through net gateway - if clt.cfg.Redirect_gateway && (!clt.cfg.Local) { - if atomic.CompareAndSwapInt32(&clt.srvRoute, 0, 1) { - if udpAddr, ok := udpConn.RemoteAddr().(*net.UDPAddr); ok { - srvIP := udpAddr.IP.To4() - if srvIP != nil { - srvDest := srvIP.String() + "/32" - addRoute(srvDest, net_gateway, net_nic) - clt.routes = append(clt.routes, srvDest) - } - } - } - } - - // forward iface frames to network - go func() { - for { - hp := <-clt.toNet - hp.setSid(clt.sid) - // logger.Debug("New iface frame") - // dest := waterutil.IPv4Destination(frame) - // logger.Debug("ip dest: %v", dest) - - udpConn.Write(hp.Pack()) - } - }() - - - buf := make([]byte, IFACE_BUFSIZE) - for { - logger.Debug("waiting for udp packet") - n, err := udpConn.Read(buf) - logger.Debug("New UDP Packet, len: %d", n) - if err != nil { - logger.Error(err.Error()) - return - } - - hp, err := unpackHopPacket(buf[:n]) - if err != nil { - logger.Debug("Error depacketing") - continue - } - if handle_func, ok := pktHandle[hp.Flag]; ok { - handle_func(udpConn, hp) - } else { - logger.Error("Unkown flag: %x", hp.Flag) - } - } + udpAddr, _ := net.ResolveUDPAddr("udp", server) + udpConn, _ := net.DialUDP("udp", nil, udpAddr) + + logger.Debug(udpConn.RemoteAddr().String()) + + // packet map + pktHandle := map[byte](func(*net.UDPConn, *HopPacket)){ + HOP_FLG_HSH | HOP_FLG_ACK: clt.handleHandshakeAck, + HOP_FLG_HSH | HOP_FLG_FIN: clt.handleHandshakeError, + HOP_FLG_DAT: clt.handleDataPacket, + HOP_FLG_DAT | HOP_FLG_MFR: clt.handleDataPacket, + HOP_FLG_FIN | HOP_FLG_ACK: clt.handleFinishAck, + } + + clt.knock(udpConn) + go func() { + n := mrand.Intn(1000) + time.Sleep(time.Duration(n) * time.Millisecond) + clt.handeshake(udpConn) + }() + + // add route through net gateway + if clt.cfg.Redirect_gateway && (!clt.cfg.Local) { + if atomic.CompareAndSwapInt32(&clt.srvRoute, 0, 1) { + if udpAddr, ok := udpConn.RemoteAddr().(*net.UDPAddr); ok { + srvIP := udpAddr.IP.To4() + if srvIP != nil { + srvDest := srvIP.String() + "/32" + addRoute(srvDest, net_gateway, net_nic) + clt.routes = append(clt.routes, srvDest) + } + } + } + } + + // forward iface frames to network + go func() { + for { + hp := <-clt.toNet + hp.setSid(clt.sid) + // logger.Debug("New iface frame") + // dest := waterutil.IPv4Destination(frame) + // logger.Debug("ip dest: %v", dest) + + udpConn.Write(hp.Pack()) + } + }() + + buf := make([]byte, IFACE_BUFSIZE) + for { + logger.Debug("waiting for udp packet") + n, err := udpConn.Read(buf) + logger.Debug("New UDP Packet, len: %d", n) + if err != nil { + logger.Error(err.Error()) + return + } + + hp, err := unpackHopPacket(buf[:n]) + if err != nil { + logger.Debug("Error depacketing") + continue + } + if handle_func, ok := pktHandle[hp.Flag]; ok { + handle_func(udpConn, hp) + } else { + logger.Error("Unkown flag: %x", hp.Flag) + } + } } func (clt *HopClient) Seq() uint32 { - return atomic.AddUint32(&clt.seq, 1) + return atomic.AddUint32(&clt.seq, 1) } func (clt *HopClient) toServer(u *net.UDPConn, flag byte, payload []byte, noise bool) { - hp := new(HopPacket) - hp.Flag = flag - hp.Seq = clt.Seq() - hp.setPayload(payload) - if noise { - hp.addNoise(mrand.Intn(MTU-64-len(payload))) - } - u.Write(hp.Pack()) + hp := new(HopPacket) + hp.Flag = flag + hp.Seq = clt.Seq() + hp.setPayload(payload) + if noise { + hp.addNoise(mrand.Intn(MTU - 64 - len(payload))) + } + u.Write(hp.Pack()) } // knock server port func (clt *HopClient) knock(u *net.UDPConn) { - clt.toServer(u, HOP_FLG_PSH, clt.sid[:], true) + clt.toServer(u, HOP_FLG_PSH, clt.sid[:], true) } // handshake with server func (clt *HopClient) handeshake(u *net.UDPConn) { - res := atomic.CompareAndSwapInt32(&clt.state, HOP_STAT_INIT, HOP_STAT_HANDSHAKE) - // logger.Debug("raced for handshake: %v", res) + res := atomic.CompareAndSwapInt32(&clt.state, HOP_STAT_INIT, HOP_STAT_HANDSHAKE) + // logger.Debug("raced for handshake: %v", res) - if res { - logger.Info("start handeshaking") - clt.toServer(u, HOP_FLG_HSH, clt.sid[:], true) - } + if res { + logger.Info("start handeshaking") + clt.toServer(u, HOP_FLG_HSH, clt.sid[:], true) + } } // finish session func (clt *HopClient) finishSession() { - logger.Info("Finishing Session") - atomic.StoreInt32(&clt.state, HOP_STAT_FIN) - hp := new(HopPacket) - hp.Flag = HOP_FLG_FIN - hp.setPayload(clt.sid[:]) - hp.Seq = clt.Seq() - clt.toNet <- hp - clt.toNet <- hp - clt.toNet <- hp + logger.Info("Finishing Session") + atomic.StoreInt32(&clt.state, HOP_STAT_FIN) + hp := new(HopPacket) + hp.Flag = HOP_FLG_FIN + hp.setPayload(clt.sid[:]) + hp.Seq = clt.Seq() + clt.toNet <- hp + clt.toNet <- hp + clt.toNet <- hp } - // handle handeshake ack func (clt *HopClient) handleHandshakeAck(u *net.UDPConn, hp *HopPacket) { - if atomic.LoadInt32(&clt.state) == HOP_STAT_HANDSHAKE { - _ip, _net, _mask := make([]byte, 4), make([]byte, 4), make([]byte, 4) - copy(_ip, hp.payload[:4]) - copy(_net, hp.payload[:4]) - copy(_mask, hp.payload[4:8]) - logger.Debug("%v", hp.payload) - _net[3] = 0 - - ip := net.IP(_ip) - subnet := &net.IPNet{_net, _mask} - setTunIP(clt.iface, ip, subnet) - if clt.cfg.FixMSS { - fixMSS(clt.iface.Name(), false) - } - res := atomic.CompareAndSwapInt32(&clt.state, HOP_STAT_HANDSHAKE, HOP_STAT_WORKING) - if !res { - logger.Error("Client state not expected: %d", clt.state) - } - logger.Info("Session Initialized") - clt.handshakeDone <- 1 - } - - logger.Debug("Handshake Ack to Server") - clt.toServer(u, HOP_FLG_HSH | HOP_FLG_ACK, clt.sid[:], true) + if atomic.LoadInt32(&clt.state) == HOP_STAT_HANDSHAKE { + by := hp.payload + addrStr := fmt.Sprintf("%d.%d.%d.%d/%d", by[0], by[1], by[2], by[3], by[4]) + ip, subnet, _ := net.ParseCIDR(addrStr) + setTunIP(clt.iface, ip, subnet) + if clt.cfg.FixMSS { + fixMSS(clt.iface.Name(), false) + } + res := atomic.CompareAndSwapInt32(&clt.state, HOP_STAT_HANDSHAKE, HOP_STAT_WORKING) + if !res { + logger.Error("Client state not expected: %d", clt.state) + } + logger.Info("Session Initialized") + clt.handshakeDone <- 1 + } + + logger.Debug("Handshake Ack to Server") + clt.toServer(u, HOP_FLG_HSH|HOP_FLG_ACK, clt.sid[:], true) } // handle handshake fail func (clt *HopClient) handleHandshakeError(u *net.UDPConn, hp *HopPacket) { - clt.handshakeDone <- 0 + clt.handshakeDone <- 0 } - // handle data packet func (clt *HopClient) handleDataPacket(u *net.UDPConn, hp *HopPacket) { - // logger.Debug("New HopPacket Seq: %d", packet.Seq) - clt.recvBuf.Push(hp) + // logger.Debug("New HopPacket Seq: %d", packet.Seq) + clt.recvBuf.Push(hp) } // handle finish ack func (clt *HopClient) handleFinishAck(u *net.UDPConn, hp *HopPacket) { - clt.finishAck <- byte(1) + clt.finishAck <- byte(1) } - func (clt *HopClient) cleanUp() { - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) - <-c - logger.Info("Cleaning Up") - - if clt.cfg.Redirect_gateway { - delRoute("0.0.0.0/1") - delRoute("128.0.0.0/1") - } - if clt.cfg.FixMSS { - clearMSS(clt.iface.Name(), false) - } - - - timeout := time.After(3 * time.Second) - if clt.state != HOP_STAT_INIT { - clt.finishSession() - } - - select { - case <-clt.finishAck: - logger.Info("Finish Acknowledged") - case <-timeout: - logger.Info("Timeout, give up") - } - - for _, dest := range clt.routes { - delRoute(dest) - } - - os.Exit(0) + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) + <-c + logger.Info("Cleaning Up") + + if clt.cfg.Redirect_gateway { + delRoute("0.0.0.0/1") + delRoute("128.0.0.0/1") + } + if clt.cfg.FixMSS { + clearMSS(clt.iface.Name(), false) + } + + timeout := time.After(3 * time.Second) + if clt.state != HOP_STAT_INIT { + clt.finishSession() + } + + select { + case <-clt.finishAck: + logger.Info("Finish Acknowledged") + case <-timeout: + logger.Info("Timeout, give up") + } + + for _, dest := range clt.routes { + delRoute(dest) + } + + os.Exit(0) } diff --git a/hop/common.go b/hop/common.go index e42f1a0..5fa10d4 100644 --- a/hop/common.go +++ b/hop/common.go @@ -19,7 +19,7 @@ package hop import ( - "github.com/bigeagle/gohop/logging" + "../logging" ) var logger = logging.GetLogger() @@ -27,5 +27,5 @@ var logger = logging.GetLogger() var MTU = 1400 const ( - IFACE_BUFSIZE = 2000 + IFACE_BUFSIZE = 2000 ) diff --git a/hop/config.go b/hop/config.go index fb31a05..77684b0 100644 --- a/hop/config.go +++ b/hop/config.go @@ -1,55 +1,101 @@ package hop import ( - "errors" - "code.google.com/p/gcfg" + "bufio" + "code.google.com/p/gcfg" + "errors" + "fmt" + "io" + "regexp" + "strconv" + "strings" ) + // Server Config type HopServerConfig struct { - HopStart int - HopEnd int - ListenAddr string - Addr string - MTU int - Key string - FixMSS bool - MorphMethod string + HopStart int + HopEnd int + ListenAddr string + Addr string + DNS []string + PeerTimeout int + MTU int + Key string + FixMSS bool + MorphMethod string + RouteFile string + RouteList map[uint32][][5]byte } // Client Config type HopClientConfig struct { - Server string - HopStart int - HopEnd int - Key string - MTU int - FixMSS bool - Local bool - MorphMethod string - Redirect_gateway bool - Net_gateway []string + Server string + HopStart int + HopEnd int + Key string + MTU int + FixMSS bool + Local bool + MorphMethod string + Redirect_gateway bool + Net_gateway []string } type HopConfig struct { - Default struct { - Mode string - } - Server HopServerConfig - Client HopClientConfig + Default struct { + Mode string + } + Server HopServerConfig + Client HopClientConfig } func ParseHopConfig(filename string) (interface{}, error) { - cfg := new(HopConfig) - err := gcfg.ReadFileInto(cfg, filename) - if err != nil { - return nil, err - } - switch cfg.Default.Mode { - case "server": - return cfg.Server, nil - case "client": - return cfg.Client, nil - default: - return nil, errors.New("Wrong mode") - } + cfg := new(HopConfig) + err := gcfg.ReadFileInto(cfg, filename) + if err != nil { + return nil, err + } + switch cfg.Default.Mode { + case "server": + return cfg.Server, nil + case "client": + return cfg.Client, nil + default: + return nil, errors.New("Wrong mode") + } +} + +func (cfg *HopServerConfig) RouteConfig(r io.Reader) { + + regCM := regexp.MustCompile(`#.*`) + regIP := regexp.MustCompile(`(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)`) + regGM := regexp.MustCompile(`\[\s*(\d+)\s*\]`) + key := uint32(0) + ip := [5]byte{} + cfg.RouteList = make(map[uint32][][5]byte) + + bf := bufio.NewReader(r) + for { + if line, err := bf.ReadString('\n'); err == nil { + if line = regCM.ReplaceAllString(line, ""); len(strings.TrimSpace(line)) < 3 { + continue + } + if ips := regIP.FindStringSubmatch(line); len(ips) == 6 { + for k, ipt := range ips[1:] { + v, _ := strconv.Atoi(ipt) + ip[k] = byte(v) + if k == 5 && uint8(ip[k]) > 32 { + ip[k] = 32 + } + } + cfg.RouteList[key] = append(cfg.RouteList[key], ip) + } else if gms := regGM.FindStringSubmatch(line); len(gms) == 2 { + v, _ := strconv.Atoi(gms[1]) + key = uint32(v) + } + } else { + break + } + } + logger.Debug(fmt.Sprintf("Route list : %v", cfg.RouteList)) } diff --git a/hop/iface.go b/hop/iface.go index 36110d4..5084c8e 100644 --- a/hop/iface.go +++ b/hop/iface.go @@ -21,16 +21,16 @@ package hop import ( - "bufio" - "bytes" - "errors" - "fmt" - "github.com/bigeagle/water" - "net" - "os" - "os/exec" - "strconv" - "strings" + "bufio" + "bytes" + "errors" + "fmt" + "github.com/bigeagle/water" + "net" + "os" + "os/exec" + "strconv" + "strings" ) var invalidAddr = errors.New("Invalid device ip address") @@ -39,235 +39,235 @@ var tun_peer net.IP func newTun(name string) (iface *water.Interface, err error) { - iface, err = water.NewTUN(name) - if err != nil { - return nil, err - } - logger.Info("interface %v created", iface.Name()) - - sargs := fmt.Sprintf("link set dev %s up mtu %d qlen 100", iface.Name(), MTU) - args := strings.Split(sargs, " ") - cmd := exec.Command("ip", args...) - logger.Info("ip %s", sargs) - err = cmd.Run() - if err != nil { - return nil, err - } - - return iface, nil + iface, err = water.NewTUN(name) + if err != nil { + return nil, err + } + logger.Info("interface %v created", iface.Name()) + + sargs := fmt.Sprintf("link set dev %s up mtu %d qlen 100", iface.Name(), MTU) + args := strings.Split(sargs, " ") + cmd := texec("ip", args...) + err = cmd.Run() + if err != nil { + return nil, err + } + + return iface, nil } func setTunIP(iface *water.Interface, ip net.IP, subnet *net.IPNet) (err error) { - ip = ip.To4() - logger.Debug("%v", ip) - if ip[3] % 2 == 0 { - return invalidAddr - } - - peer := net.IP(make([]byte, 4)) - copy([]byte(peer), []byte(ip)) - peer[3]++ - tun_peer = peer - - sargs := fmt.Sprintf("addr add dev %s local %s peer %s", iface.Name(), ip, peer) - args := strings.Split(sargs, " ") - cmd := exec.Command("ip", args...) - logger.Info("ip %s", sargs) - err = cmd.Run() - if err != nil { - return err - } - - sargs = fmt.Sprintf("route add %s via %s dev %s", subnet, peer, iface.Name()) - args = strings.Split(sargs, " ") - cmd = exec.Command("ip", args...) - logger.Info("ip %s", sargs) - err = cmd.Run() - return err + ip = ip.To4() + logger.Debug("%v", ip) + if ip[3]%2 == 0 { + return invalidAddr + } + + peer := net.IP(make([]byte, 4)) + copy([]byte(peer), []byte(ip)) + peer[3]++ + tun_peer = peer + + sargs := fmt.Sprintf("addr add dev %s local %s peer %s", iface.Name(), ip, peer) + args := strings.Split(sargs, " ") + cmd := texec("ip", args...) + err = cmd.Run() + if err != nil { + return err + } + + sargs = fmt.Sprintf("route add %s via %s dev %s", subnet, peer, iface.Name()) + args = strings.Split(sargs, " ") + cmd = texec("ip", args...) + err = cmd.Run() + return err } // return net gateway (default route) and nic func getNetGateway() (gw, dev string, err error) { - file, err := os.Open("/proc/net/route") - if err != nil { - return "", "", err - } - - defer file.Close() - rd := bufio.NewReader(file) - - s2byte := func(s string) byte { - b, _ := strconv.ParseUint(s, 16, 8) - return byte(b) - } - - for { - line, isPrefix, err := rd.ReadLine() - - if err != nil { - logger.Error(err.Error()) - return "", "", err - } - if isPrefix { - return "", "", errors.New("Line Too Long!") - } - buf := bytes.NewBuffer(line) - scanner := bufio.NewScanner(buf) - scanner.Split(bufio.ScanWords) - tokens := make([]string, 0, 8) - - for scanner.Scan() { - tokens = append(tokens, scanner.Text()) - } - - iface := tokens[0] - dest := tokens[1] - gw := tokens[2] - mask := tokens[7] - - if bytes.Equal([]byte(dest), []byte("00000000")) && - bytes.Equal([]byte(mask), []byte("00000000")) { - a := s2byte(gw[6:8]) - b := s2byte(gw[4:6]) - c := s2byte(gw[2:4]) - d := s2byte(gw[0:2]) - - ip := net.IPv4(a, b, c, d) - - return ip.String(), iface, nil - } - - } - return "", "", errors.New("No default gateway found") + file, err := os.Open("/proc/net/route") + if err != nil { + return "", "", err + } + + defer file.Close() + rd := bufio.NewReader(file) + + s2byte := func(s string) byte { + b, _ := strconv.ParseUint(s, 16, 8) + return byte(b) + } + + for { + line, isPrefix, err := rd.ReadLine() + + if err != nil { + logger.Error(err.Error()) + return "", "", err + } + if isPrefix { + return "", "", errors.New("Line Too Long!") + } + buf := bytes.NewBuffer(line) + scanner := bufio.NewScanner(buf) + scanner.Split(bufio.ScanWords) + tokens := make([]string, 0, 8) + + for scanner.Scan() { + tokens = append(tokens, scanner.Text()) + } + + iface := tokens[0] + dest := tokens[1] + gw := tokens[2] + mask := tokens[7] + + if bytes.Equal([]byte(dest), []byte("00000000")) && + bytes.Equal([]byte(mask), []byte("00000000")) { + a := s2byte(gw[6:8]) + b := s2byte(gw[4:6]) + c := s2byte(gw[2:4]) + d := s2byte(gw[0:2]) + + ip := net.IPv4(a, b, c, d) + + return ip.String(), iface, nil + } + + } + return "", "", errors.New("No default gateway found") } - // add route func addRoute(dest, nextHop, iface string) { - scmd := fmt.Sprintf("ip -4 r a %s via %s dev %s", dest, nextHop, iface) - cmd := exec.Command("bash", "-c", scmd) - logger.Info(scmd) - err := cmd.Run() + scmd := fmt.Sprintf("ip -4 r a %s via %s dev %s", dest, nextHop, iface) + cmd := texec("bash", "-c", scmd) + err := cmd.Run() - if err != nil { - logger.Warning(err.Error()) - } + if err != nil { + logger.Warning(err.Error()) + } } // delete route func delRoute(dest string) { - sargs := fmt.Sprintf("-4 route del %s", dest) - args := strings.Split(sargs, " ") - cmd := exec.Command("ip", args...) - logger.Info("ip %s", sargs) - err := cmd.Run() - - if err != nil { - logger.Warning(err.Error()) - } + sargs := fmt.Sprintf("-4 route del %s", dest) + args := strings.Split(sargs, " ") + cmd := texec("ip", args...) + err := cmd.Run() + + if err != nil { + logger.Warning(err.Error()) + } } // redirect default gateway func redirectGateway(iface, gw string) error { - subnets := []string{"0.0.0.0/1", "128.0.0.0/1"} - logger.Info("Redirecting Gateway") - for _, subnet := range subnets { - sargs := fmt.Sprintf("-4 route add %s via %s dev %s", subnet, gw, iface) - args := strings.Split(sargs, " ") - cmd := exec.Command("ip", args...) - logger.Info("ip %s", sargs) - err := cmd.Run() - - if err != nil { - return err - } - } - return nil + subnets := []string{"0.0.0.0/1", "128.0.0.0/1"} + logger.Debug("Redirecting Gateway") + for _, subnet := range subnets { + sargs := fmt.Sprintf("-4 route add %s via %s dev %s", subnet, gw, iface) + args := strings.Split(sargs, " ") + cmd := texec("ip", args...) + err := cmd.Run() + + if err != nil { + return err + } + } + return nil } - // redirect ports to one func redirectPort(from, to string) error { - //iptables -t nat -A PREROUTING -p udp -m udp --dport 40000:41000 -j REDIRECT --to-ports 1234 - logger.Info("Port Redirecting") - sargs := fmt.Sprintf("-t nat -A PREROUTING -p udp -m udp --dport %s -j REDIRECT --to-ports %s", from, to) - args := strings.Split(sargs, " ") - cmd := exec.Command("iptables", args...) - err := cmd.Run() - - if err != nil { - return err - } - cmd = exec.Command("ip6tables", args...) - err = cmd.Run() - - if err != nil { - return err - } - return nil + //iptables -t nat -A PREROUTING -p udp -m udp --dport 40000:41000 -j REDIRECT --to-ports 1234 + logger.Debug("Port Redirecting") + sargs := fmt.Sprintf("-t nat -A PREROUTING -p udp -m udp --dport %s -j REDIRECT --to-ports %s", from, to) + args := strings.Split(sargs, " ") + cmd := texec("iptables", args...) + err := cmd.Run() + + if err != nil { + return err + } + cmd = texec("ip6tables", args...) + err = cmd.Run() + + if err != nil { + return err + } + return nil } - // undo redirect ports func unredirectPort(from, to string) error { - //iptables -t nat -D PREROUTING -p udp -m udp --dport 40000:41000 -j REDIRECT --to-ports 1234 - logger.Info("Clear Port Redirecting") - sargs := fmt.Sprintf("-t nat -D PREROUTING -p udp -m udp --dport %s -j REDIRECT --to-ports %s", from, to) - args := strings.Split(sargs, " ") - cmd := exec.Command("iptables", args...) - err := cmd.Run() - - if err != nil { - return err - } - cmd = exec.Command("ip6tables", args...) - err = cmd.Run() - - if err != nil { - return err - } - return nil + //iptables -t nat -D PREROUTING -p udp -m udp --dport 40000:41000 -j REDIRECT --to-ports 1234 + logger.Debug("Clear Port Redirecting") + sargs := fmt.Sprintf("-t nat -D PREROUTING -p udp -m udp --dport %s -j REDIRECT --to-ports %s", from, to) + args := strings.Split(sargs, " ") + cmd := texec("iptables", args...) + err := cmd.Run() + + if err != nil { + return err + } + cmd = texec("ip6tables", args...) + err = cmd.Run() + + if err != nil { + return err + } + return nil } func fixMSS(iface string, is_server bool) error { - mss := MTU - 40 - logger.Info("Fix MSS with iptables to %d", mss) - io := "o" - if is_server { - io = "i" - } - - sargs := fmt.Sprintf("-I FORWARD -%s %s -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss %d", io, iface, mss) - args := strings.Split(sargs, " ") - cmd := exec.Command("iptables", args...) - err := cmd.Run() - - if err != nil { - return err - } - return nil + mss := MTU - 40 + logger.Debug("Fix MSS with iptables to %d", mss) + io := "o" + if is_server { + io = "i" + } + + sargs := fmt.Sprintf("-I FORWARD -%s %s -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss %d", io, iface, mss) + args := strings.Split(sargs, " ") + cmd := texec("iptables", args...) + err := cmd.Run() + + if err != nil { + return err + } + return nil } func clearMSS(iface string, is_server bool) error { - mss := MTU - 40 - logger.Info("Clean MSS fix") - io := "o" + mss := MTU - 40 + logger.Debug("Clean MSS fix") + io := "o" - if is_server { - io = "i" - } - sargs := fmt.Sprintf("-D FORWARD -%s %s -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss %d", io, iface, mss) + if is_server { + io = "i" + } + sargs := fmt.Sprintf("-D FORWARD -%s %s -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss %d", io, iface, mss) - args := strings.Split(sargs, " ") - cmd := exec.Command("iptables", args...) - err := cmd.Run() + args := strings.Split(sargs, " ") + cmd := texec("iptables", args...) + err := cmd.Run() - if err != nil { - return err - } + if err != nil { + return err + } + + return nil +} - return nil +func texec(name string, arg ...string) *exec.Cmd { + out := "EXEC:" + name + for _, s := range arg { + out += " " + s + } + logger.Debug(out) + return exec.Command(name, arg...) } diff --git a/hop/ippool.go b/hop/ippool.go index 971a892..b3bc24d 100644 --- a/hop/ippool.go +++ b/hop/ippool.go @@ -1,50 +1,49 @@ package hop import ( - "net" - "errors" - "sync/atomic" + "encoding/binary" + "errors" + "net" + "sync/atomic" ) type hopIPPool struct { - subnet *net.IPNet - pool [127]int32 + subnet *net.IPNet + pool []int32 } var poolFull = errors.New("IP Pool Full") func (p *hopIPPool) next() (*net.IPNet, error) { - found := false - var i int - for i = 3; i < 255; i +=2 { - if atomic.CompareAndSwapInt32(&p.pool[i], 0, 1) { - found = true - break - } - } - if !found { - return nil, poolFull - } - - - ipnet := &net.IPNet{ - make([]byte, 4), - make([]byte, 4), - } - copy([]byte(ipnet.IP), []byte(p.subnet.IP)) - copy([]byte(ipnet.Mask), []byte(p.subnet.Mask)) - ipnet.IP[3] = byte(i) - return ipnet, nil + if len(p.pool) == 0 { + maskint := binary.BigEndian.Uint32(p.subnet.Mask) + maskint = ^maskint & 0xffff //最长支持 65535 IP + p.pool = make([]int32, maskint) + } + for i := 3; i < len(p.pool); i++ { + lB := i & 0xff + if lB > 2 && lB < 255 && atomic.CompareAndSwapInt32(&p.pool[i], 0, 1) { + ipint := binary.BigEndian.Uint32(p.subnet.IP.To4()) + uint32(i) + ipnet := &net.IPNet{ + make([]byte, 4), + make([]byte, 4), + } + binary.BigEndian.PutUint32(ipnet.IP, ipint) + copy([]byte(ipnet.Mask), []byte(p.subnet.Mask)) + return ipnet, nil + } + } + return nil, poolFull } func (p *hopIPPool) relase(ip net.IP) { - defer func(){ - if err := recover(); err != nil { - logger.Error("%v", err) - } - }() - - logger.Debug("releasing ip: %v", ip) - i := ip[3] - p.pool[i] = 0 + defer func() { + if err := recover(); err != nil { + logger.Error("%v", err) + } + }() + logger.Debug("releasing ip: %v", ip) + + i := binary.BigEndian.Uint32(ip.To4()) & uint32(len(p.pool)) + p.pool[i] = 0 } diff --git a/hop/protocol.go b/hop/protocol.go index 93e4d77..eb86bb6 100644 --- a/hop/protocol.go +++ b/hop/protocol.go @@ -21,221 +21,253 @@ package hop import ( - "net" - "bytes" - "encoding/binary" - "crypto/rand" - "sync" - "sync/atomic" - "errors" - "fmt" - "strings" + "bytes" + "crypto/rand" + "encoding/binary" + "errors" + "fmt" + "net" + "strings" + "sync" + "sync/atomic" + "time" ) const ( - HOP_REQ uint8 = 0x20 - HOP_ACK uint8 = 0xAC - HOP_DAT uint8 = 0xDA - - HOP_FLG_PSH byte = 0x80 // port knocking and heartbeat - HOP_FLG_HSH byte = 0x40 // handshaking - HOP_FLG_FIN byte = 0x20 // finish session - HOP_FLG_MFR byte = 0x08 // more fragments - HOP_FLG_ACK byte = 0x04 // acknowledge - HOP_FLG_DAT byte = 0x00 // acknowledge - - HOP_STAT_INIT int32 = iota // initing - HOP_STAT_HANDSHAKE // handeshaking - HOP_STAT_WORKING // working - HOP_STAT_FIN // finishing - - HOP_HDR_LEN int = 16 + HOP_REQ uint8 = 0x20 + HOP_ACK uint8 = 0xAC + HOP_DAT uint8 = 0xDA + + HOP_FLG_PSH byte = 0x80 // port knocking and heartbeat + HOP_FLG_HSH byte = 0x40 // handshaking + HOP_FLG_FIN byte = 0x20 // finish session + HOP_FLG_MFR byte = 0x08 // more fragments + HOP_FLG_ACK byte = 0x04 // acknowledge + HOP_FLG_DAT byte = 0x00 // acknowledge + + HOP_STAT_INIT int32 = iota // initing + HOP_STAT_HANDSHAKE // handeshaking + HOP_STAT_WORKING // working + HOP_STAT_FIN // finishing + + HOP_HDR_LEN int = 16 + + DAT_CIPHER bool = true ) type hopPacketHeader struct { - Flag byte - Seq uint32 - Plen uint16 - FragPrefix uint16 - Frag uint8 - Sid uint32 - Dlen uint16 + Flag byte + Seq uint32 + Plen uint16 + FragPrefix uint16 + Frag uint8 + Sid uint32 + Dlen uint16 } func (p hopPacketHeader) String() string { - flag := make([]string, 0, 8) - if (p.Flag ^ HOP_FLG_MFR == 0) || (p.Flag == 0) { - flag = append(flag, "DAT") - } - if p.Flag & HOP_FLG_PSH != 0 { - flag = append(flag, "PSH") - } - if p.Flag & HOP_FLG_HSH != 0 { - flag = append(flag, "HSH") - } - if p.Flag & HOP_FLG_FIN != 0 { - flag = append(flag, "FIN") - } - if p.Flag & HOP_FLG_ACK != 0 { - flag = append(flag, "ACK") - } - if p.Flag & HOP_FLG_MFR != 0 { - flag = append(flag, "MFR") - } - - sflag := strings.Join(flag, " | ") - return fmt.Sprintf( - "{Flag: %s, Seq: %d, Plen: %d, Prefix: %d, Frag: %d, Dlen: %d}", - sflag, p.Seq, p.Plen, p.FragPrefix, p.Frag, p.Dlen, - ) + flag := make([]string, 0, 8) + if (p.Flag^HOP_FLG_MFR == 0) || (p.Flag == 0) { + flag = append(flag, "DAT") + } + if p.Flag&HOP_FLG_PSH != 0 { + flag = append(flag, "PSH") + } + if p.Flag&HOP_FLG_HSH != 0 { + flag = append(flag, "HSH") + } + if p.Flag&HOP_FLG_FIN != 0 { + flag = append(flag, "FIN") + } + if p.Flag&HOP_FLG_ACK != 0 { + flag = append(flag, "ACK") + } + if p.Flag&HOP_FLG_MFR != 0 { + flag = append(flag, "MFR") + } + + sflag := strings.Join(flag, " | ") + return fmt.Sprintf( + "{Flag: %s, Seq: %d, Plen: %d, Prefix: %d, Frag: %d, Dlen: %d}", + sflag, p.Seq, p.Plen, p.FragPrefix, p.Frag, p.Dlen, + ) } type HopPacket struct { - hopPacketHeader - payload []byte - noise []byte - buf []byte + hopPacketHeader + payload []byte + noise []byte + buf []byte } -var cipher *hopCipher +var cipher *hopCipher = nil func (p *HopPacket) Pack() []byte { - p.Dlen = uint16(len(p.payload)) - var buf *bytes.Buffer - if p.buf != nil { - // reduce memcopy - buf = bytes.NewBuffer(p.buf[:0]) - binary.Write(buf, binary.BigEndian, p.hopPacketHeader) - } else { - buf = bytes.NewBuffer(make([]byte, 0, p.Size())) - binary.Write(buf, binary.BigEndian, p.hopPacketHeader) - buf.Write(p.payload) - buf.Write(p.noise) - p.buf = buf.Bytes() - } - return cipher.encrypt(p.buf) + p.Dlen = uint16(len(p.payload)) + var buf *bytes.Buffer + if p.buf != nil { + // reduce memcopy + buf = bytes.NewBuffer(p.buf[:0]) + // write packet header to p.buf header + binary.Write(buf, binary.BigEndian, p.hopPacketHeader) + + } else { + buf = bytes.NewBuffer(make([]byte, 0, p.Size())) + binary.Write(buf, binary.BigEndian, p.hopPacketHeader) + buf.Write(p.payload) + buf.Write(p.noise) + p.buf = buf.Bytes() + } + + if cipher == nil { + return p.buf //暂时不用加密 + } + return cipher.encrypt(p.buf) // 数据加密 + } func (p *HopPacket) Size() int { - return HOP_HDR_LEN+len(p.payload)+len(p.noise) + return HOP_HDR_LEN + len(p.payload) + len(p.noise) } func (p *HopPacket) setPayload(d []byte) { - p.payload = d - p.Dlen = uint16(len(p.payload)) + p.payload = d + p.Dlen = uint16(len(p.payload)) } func (p *HopPacket) addNoise(n int) { - if p.buf != nil { - s := HOP_HDR_LEN+len(p.payload) - p.noise = p.buf[s:len(p.buf)] - } else { - p.noise = make([]byte, n) - } - rand.Read(p.noise) + if p.buf != nil { + s := HOP_HDR_LEN + len(p.payload) + p.noise = p.buf[s:len(p.buf)] + } else { + p.noise = make([]byte, n) + } + rand.Read(p.noise) } func (p *HopPacket) setSid(sid [4]byte) { - p.Sid = binary.BigEndian.Uint32(sid[:]) + p.Sid = binary.BigEndian.Uint32(sid[:]) } func (p *HopPacket) String() string { - return fmt.Sprintf( - "{%v, Payload: %v, Noise: %v}", - p.hopPacketHeader, p.payload, p.noise, - ) + return fmt.Sprintf( + "{%v, Payload: %v, Noise: %v}", + p.hopPacketHeader, p.payload, p.noise, + ) } func unpackHopPacket(b []byte) (*HopPacket, error) { - iv := b[:cipherBlockSize] - ctext := b[cipherBlockSize:] - if frame := cipher.decrypt(iv, ctext); frame != nil { - buf := bytes.NewBuffer(frame) - p := new(HopPacket) - binary.Read(buf, binary.BigEndian, &p.hopPacketHeader) - p.payload = make([]byte, p.Dlen) - buf.Read(p.payload) - return p, nil - } else { - return nil, errors.New("Decrypt Packet Error") - } + //不加密数据 + if cipher == nil { + logger.Debug("no ciph!") + buf := bytes.NewBuffer(b) + p := new(HopPacket) + err := binary.Read(buf, binary.BigEndian, &p.hopPacketHeader) + if err == nil { + p.payload = make([]byte, p.Dlen) + if _, err = buf.Read(p.payload); err == nil { + return p, nil + } + } + return nil, err + } + + // 加密数据 + iv := b[:cipherBlockSize] + ctext := b[cipherBlockSize:] + if frame := cipher.decrypt(iv, ctext); frame != nil { + buf := bytes.NewBuffer(frame) + + p := new(HopPacket) + binary.Read(buf, binary.BigEndian, &p.hopPacketHeader) + p.payload = make([]byte, p.Dlen) + buf.Read(p.payload) + return p, nil + } else { + return nil, errors.New("Decrypt Packet Error") + } } - -func udpAddrHash(a *net.UDPAddr) [6]byte{ - var b [6]byte - copy(b[:4], []byte(a.IP)[:4]) - p := uint16(a.Port) - b[4] = byte((p >> 8) & 0xFF) - b[5] = byte(p & 0xFF) - return b +func udpAddrHash(a *net.UDPAddr) [6]byte { + var b [6]byte + copy(b[:4], []byte(a.IP)[:4]) + p := uint16(a.Port) + b[4] = byte((p >> 8) & 0xFF) + b[5] = byte(p & 0xFF) + return b } type hUDPAddr struct { - u *net.UDPAddr - hash [6]byte + u *net.UDPAddr + hash [6]byte } func newhUDPAddr(a *net.UDPAddr) *hUDPAddr { - return &hUDPAddr{a, udpAddrHash(a)} + return &hUDPAddr{a, udpAddrHash(a)} } // gohop Peer is a record of a peer's available UDP addrs type HopPeer struct { - id uint64 - ip net.IP - addrs map[[6]byte]int - _addrs_lst []*hUDPAddr // i know it's ugly! - seq uint32 - state int32 - hsDone chan byte - recvBuffer *hopPacketBuffer - srv *HopServer - _lock sync.RWMutex + id uint64 + gmid uint32 //game id + uid uint32 //user id + lastConnTime time.Time + bytes_up uint32 //user update bytes + bytes_down uint32 //user download bytes + ip net.IP + addrs map[[6]byte]int + _addrs_lst []*hUDPAddr // i know it's ugly! + seq uint32 + state int32 + hsDone chan byte + recvBuffer *hopPacketBuffer + srv *HopServer + _lock sync.RWMutex } func newHopPeer(id uint64, srv *HopServer, addr *net.UDPAddr, idx int) *HopPeer { - hp := new(HopPeer) - hp.id = id - hp._addrs_lst = make([]*hUDPAddr, 0) - hp.addrs = make(map[[6]byte]int) - hp.state = HOP_STAT_INIT - hp.seq = 0 - hp.srv = srv - hp.recvBuffer = newHopPacketBuffer(srv.toIface, bufferTimeout/2) - // logger.Debug("%v, %v", hp.recvBuffer, hp.srv) - - - a := newhUDPAddr(addr) - hp._addrs_lst = append(hp._addrs_lst, a) - hp.addrs[a.hash] = idx - - return hp + hp := new(HopPeer) + hp.id = id + hp.bytes_up = 0 + hp.bytes_down = 0 + hp._addrs_lst = make([]*hUDPAddr, 0) + hp.addrs = make(map[[6]byte]int) + hp.state = HOP_STAT_INIT + hp.seq = 0 + hp.srv = srv + hp.recvBuffer = newHopPacketBuffer(srv.toIface, bufferTimeout/2) + // logger.Debug("%v, %v", hp.recvBuffer, hp.srv) + + a := newhUDPAddr(addr) + hp._addrs_lst = append(hp._addrs_lst, a) + hp.addrs[a.hash] = idx + + return hp } func (h *HopPeer) Seq() uint32 { - return atomic.AddUint32(&h.seq, 1) + return atomic.AddUint32(&h.seq, 1) } func (h *HopPeer) addr() (*net.UDPAddr, int, bool) { - defer h._lock.RUnlock() - h._lock.RLock() - addr := randAddr(h._addrs_lst) - // addr := h._addrs_lst[0] - idx, ok := h.addrs[addr.hash] + defer h._lock.RUnlock() + h._lock.RLock() + addr := randAddr(h._addrs_lst) + // addr := h._addrs_lst[0] + idx, ok := h.addrs[addr.hash] - return addr.u, idx, ok + return addr.u, idx, ok } func (h *HopPeer) insertAddr(addr *net.UDPAddr, idx int) { - defer h._lock.Unlock() - h._lock.Lock() - a := newhUDPAddr(addr) - if _, found := h.addrs[a.hash]; !found { - h.addrs[a.hash] = idx - h._addrs_lst = append(h._addrs_lst, a) - //logger.Info("%v %d", addr, len(h._addrs_lst)) - } + defer h._lock.Unlock() + h._lock.Lock() + a := newhUDPAddr(addr) + if _, found := h.addrs[a.hash]; !found { + h.addrs[a.hash] = idx + h._addrs_lst = append(h._addrs_lst, a) + //logger.Info("%v %d", addr, len(h._addrs_lst)) + } } diff --git a/hop/server.go b/hop/server.go index ea0c0fa..99bd101 100644 --- a/hop/server.go +++ b/hop/server.go @@ -19,408 +19,548 @@ package hop import ( - "github.com/bigeagle/water" - "github.com/bigeagle/water/waterutil" - "encoding/binary" - "bytes" - "fmt" - "net" - "os" - "os/signal" - "syscall" - "time" - "sync/atomic" - "sync" + "bytes" + "encoding/binary" + "fmt" + "github.com/bigeagle/water" + "github.com/bigeagle/water/waterutil" + "net" + "os" + "os/signal" + "sync" + "sync/atomic" + "syscall" + "time" ) // a udpPacket type udpPacket struct { - // client's addr - addr *net.UDPAddr - // data - data []byte - // channel - channel int + // client's addr + addr *net.UDPAddr + // data + data []byte + // channel + channel int } type HopServer struct { - // config - cfg HopServerConfig - // interface - iface *water.Interface - // subnet - ipnet *net.IPNet - // IP Pool - ippool *hopIPPool - // client peers, key is the mac address, value is a HopPeer record - peers map[uint64]*HopPeer - - // channel to put in packets read from udpsocket - fromNet chan *udpPacket - // channel to put packets to send through udpsocket - toNet []chan *udpPacket - // channel to put frames read from tun/tap device - fromIface chan []byte - toIface chan *HopPacket - _lock sync.RWMutex - _chanBufSize int + // config + cfg *HopServerConfig + // interface + iface *water.Interface + // subnet + ipnet *net.IPNet + // IP Pool + ippool *hopIPPool + // client peers, key is the mac address, value is a HopPeer record + peers map[uint64]*HopPeer + + // channel to put in packets read from udpsocket + fromNet chan *udpPacket + // channel to put packets to send through udpsocket + toNet []chan *udpPacket + // channel to put frames read from tun/tap device + fromIface chan []byte + toIface chan *HopPacket + _lock sync.RWMutex + _chanBufSize int } - -func NewServer(cfg HopServerConfig) error { - var err error - logger.Debug("%v", cfg) - - cipher, err = newHopCipher([]byte(cfg.Key)) - if err != nil { - return err - } - - if cfg.MTU != 0 { - MTU = cfg.MTU - } - - - hopServer := new(HopServer) - hopServer._chanBufSize = 256 - hopServer.fromNet = make(chan *udpPacket, hopServer._chanBufSize) - hopServer.fromIface = make(chan []byte, hopServer._chanBufSize) - hopServer.toIface = make(chan *HopPacket, hopServer._chanBufSize) - hopServer.peers = make(map[uint64]*HopPeer) - hopServer.cfg = cfg - hopServer.toNet = make([]chan *udpPacket, (cfg.HopEnd-cfg.HopStart+1)) - hopServer.ippool = new(hopIPPool) - - iface, err := newTun("") - if err != nil { - return err - } - hopServer.iface = iface - ip, subnet, err := net.ParseCIDR(cfg.Addr) - err = setTunIP(iface, ip, subnet) - if err != nil { - return err - } - hopServer.ipnet = &net.IPNet{ip, subnet.Mask} - hopServer.ippool.subnet = subnet - - if cfg.FixMSS { - fixMSS(iface.Name(), true) - } - - // traffic morpher - switch cfg.MorphMethod { - case "randsize": - m := newRandMorpher(MTU) - hopFrager = newHopFragmenter(m) - logger.Info("Using RandomSize Morpher") - default: - logger.Info("No Traffic Morphing") - } - - - // forward device frames to socket and socket packets to device - go hopServer.forwardFrames() - - // go func() { - // defer hopServer.cleanUp() - // redirectPort(cfg.HopRange, cfg.Port) - // }() - go hopServer.cleanUp() - - // serve for multiple ports - for idx, port := 0, cfg.HopStart; port <= cfg.HopEnd; port++ { - go hopServer.listenAndServe(cfg.ListenAddr, fmt.Sprintf("%d", port), idx) - idx++ - } - - logger.Debug("Recieving iface frames") - - - // handle interface - - go func() { - for { - hp := <-hopServer.toIface - // logger.Debug("New Net packet to device") - _, err := iface.Write(hp.payload) - // logger.Debug("n: %d, len: %d", n, len(hp.payload)) - if err != nil { - logger.Error(err.Error()) - return - } - } - }() - - buf := make([]byte, IFACE_BUFSIZE) - for { - n, err := iface.Read(buf) - if err != nil { - return err - } - - hpbuf := make([]byte, n+HOP_HDR_LEN) - copy(hpbuf[HOP_HDR_LEN:], buf[:n]) - hopServer.fromIface <- hpbuf - } +func NewServer(cfg *HopServerConfig) error { + var err error + logger.Debug("%v", cfg) + + if len(cfg.Key) > 0 { + cipher, err = newHopCipher([]byte(cfg.Key)) + if err != nil { + return err + } + } + + if cfg.MTU != 0 { + MTU = cfg.MTU + } + + hopServer := new(HopServer) + hopServer._chanBufSize = 256 + hopServer.fromNet = make(chan *udpPacket, hopServer._chanBufSize) + hopServer.fromIface = make(chan []byte, hopServer._chanBufSize) + hopServer.toIface = make(chan *HopPacket, hopServer._chanBufSize) + hopServer.peers = make(map[uint64]*HopPeer) + hopServer.cfg = cfg + hopServer.toNet = make([]chan *udpPacket, (cfg.HopEnd - cfg.HopStart + 1)) + hopServer.ippool = new(hopIPPool) + + iface, err := newTun("") + if err != nil { + return err + } + hopServer.iface = iface + ip, subnet, err := net.ParseCIDR(cfg.Addr) + err = setTunIP(iface, ip, subnet) + if err != nil { + return err + } + hopServer.ipnet = &net.IPNet{ip, subnet.Mask} + hopServer.ippool.subnet = subnet + + if cfg.FixMSS { + fixMSS(iface.Name(), true) + } + + // traffic morpher + switch cfg.MorphMethod { + case "randsize": + m := newRandMorpher(MTU) + hopFrager = newHopFragmenter(m) + logger.Info("Using RandomSize Morpher") + default: + logger.Info("No Traffic Morphing") + } + + // forward device frames to socket and socket packets to device + go hopServer.forwardFrames() + + // go func() { + // defer hopServer.cleanUp() + // redirectPort(cfg.HopRange, cfg.Port) + // }() + go hopServer.cleanUp() + + // serve for multiple ports + for idx, port := 0, cfg.HopStart; port <= cfg.HopEnd; port++ { + go hopServer.listenAndServe(cfg.ListenAddr, fmt.Sprintf("%d", port), idx) + idx++ + } + + // peer Timeout Watcher + go hopServer.peerTimeoutWatcher() + + logger.Info("Recieving iface frames") + + // handle interface + + go func() { + for { + hp := <-hopServer.toIface + // logger.Debug("New Net packet to device") + // logger.Debug("toIface : %v", hp.payload) + _, err := iface.Write(hp.payload) + // logger.Debug("n: %d, len: %d", n, len(hp.payload)) + if err != nil { + logger.Error(err.Error()) + return + } + } + }() + + buf := make([]byte, IFACE_BUFSIZE) + for { + n, err := iface.Read(buf) + if err != nil { + return err + } + + hpbuf := make([]byte, n+HOP_HDR_LEN) + copy(hpbuf[HOP_HDR_LEN:], buf[:n]) + hopServer.fromIface <- hpbuf + } } func (srv *HopServer) listenAndServe(addr string, port string, idx int) { - port = addr + ":" + port - udpAddr, err := net.ResolveUDPAddr("udp", port) - if err != nil { - logger.Error("Invalid port: %s", port) - return - } - udpConn, err := net.ListenUDP("udp", udpAddr) - if err != nil { - logger.Error("Failed to listen udp port %s: %s", port, err.Error()) - return - } - - toNet := make(chan *udpPacket, srv._chanBufSize) - - go func() { - defer srv._lock.Unlock() - srv._lock.Lock() - srv.toNet[idx] = toNet - // logger.Debug("Listening on port %s", port) - }() - - go func() { - for { - packet := <-toNet - // logger.Debug("index: %d, port: %s", idx, port) - // logger.Debug("client addr: %v", packet.addr) - udpConn.WriteTo(packet.data, packet.addr) - } - }() - - for { - var plen int - packet := new(udpPacket) - packet.channel = idx - buf := make([]byte, IFACE_BUFSIZE) - // logger.Debug("Recieving packet %s", port) - plen, packet.addr, err = udpConn.ReadFromUDP(buf) - // logger.Debug("New UDP Packet from: %v", packet.addr) - - packet.data = buf[:plen] - if err != nil { - logger.Error(err.Error()) - return - } - - srv.fromNet <- packet - } + port = addr + ":" + port + udpAddr, err := net.ResolveUDPAddr("udp", port) + if err != nil { + logger.Error("Invalid port: %s", port) + return + } + udpConn, err := net.ListenUDP("udp", udpAddr) + if err != nil { + logger.Error("Failed to listen udp port %s: %s", port, err.Error()) + return + } + + toNet := make(chan *udpPacket, srv._chanBufSize) + + go func() { + defer srv._lock.Unlock() + srv._lock.Lock() + srv.toNet[idx] = toNet + // logger.Debug("Listening on port %s", port) + }() + + go func() { + for { + packet := <-toNet + // logger.Debug("index: %d, port: %s", idx, port) + // logger.Debug("toClient: %v", packet.data) + _, err := udpConn.WriteTo(packet.data, packet.addr) + if err != nil { + logger.Error("ToNet Err: %v", err) + } + } + }() + + for { + func() { + defer func() { + if _err := recover(); _err != nil { + logger.Error("ReadFromUDP failed: %v", _err) + } + }() + var plen int + packet := new(udpPacket) + packet.channel = idx + buf := make([]byte, IFACE_BUFSIZE) + // logger.Debug("Recieving packet %s", port) + plen, packet.addr, err = udpConn.ReadFromUDP(buf) + // logger.Debug("New UDP Packet from: %v", packet.addr) + + packet.data = buf[:plen] + if err != nil { + logger.Error(err.Error()) + return + } + + srv.fromNet <- packet + }() + } } func (srv *HopServer) forwardFrames() { - // packet map - pktHandle := map[byte](func(*udpPacket, *HopPacket)){ - HOP_FLG_PSH: srv.handleKnock, - HOP_FLG_HSH: srv.handleHandshake, - HOP_FLG_HSH|HOP_FLG_ACK: srv.handleHandshakeAck, - HOP_FLG_DAT: srv.handleDataPacket, - HOP_FLG_DAT|HOP_FLG_MFR: srv.handleDataPacket, - HOP_FLG_FIN: srv.handleFinish, - } - - for { - select { - case pack := <-srv.fromIface: - // logger.Debug("New iface Frame") - // first byte is left for opcode - frame := pack[HOP_HDR_LEN:] - dest := waterutil.IPv4Destination(frame).To4() - mkey := ip4_uint64(dest) - - // logger.Debug("ip dest: %v", dest) - if hpeer, found := srv.peers[mkey]; found { - srv.bufferToClient(hpeer, pack) - } else { - logger.Warning("client peer with key %d not found", mkey) - } - - case packet := <-srv.fromNet: - - hPack, err := unpackHopPacket(packet.data) - if err == nil { - // logger.Debug("New UDP Packet from: %v", packet.addr) - - if handle_func, ok := pktHandle[hPack.Flag]; ok { - handle_func(packet, hPack) - } else { - logger.Error("Unkown flag: %x", hPack.Flag) - } - } else { - logger.Error(err.Error()) - } - } - - } + // packet map + pktHandle := map[byte](func(*udpPacket, *HopPacket)){ + HOP_FLG_PSH: srv.handleKnock, + HOP_FLG_HSH: srv.handleHandshake, + HOP_FLG_HSH | HOP_FLG_ACK: srv.handleHandshakeAck, + HOP_FLG_DAT: srv.handleDataPacket, + HOP_FLG_DAT | HOP_FLG_MFR: srv.handleDataPacket, + HOP_FLG_FIN: srv.handleFinish, + } + + for { + select { + case pack := <-srv.fromIface: + // logger.Debug("New iface Frame") + // first byte is left for opcode + frame := pack[HOP_HDR_LEN:] + dest := waterutil.IPv4Destination(frame).To4() + mkey := ip4_uint64(dest) + + // logger.Debug("fromIfc: ip dest: %v, data:%v", dest, frame) + if hpeer, found := srv.peers[mkey]; found { + srv.bufferToClient(hpeer, pack) + } else { + // logger.Debug("fromIface : client peer with key %d not found", mkey) + } + + case packet := <-srv.fromNet: + packet.handleFunction(pktHandle) + } + } +} + +func (packet *udpPacket) handleFunction(pktHandle map[byte](func(*udpPacket, *HopPacket))) { + + defer func() { + if err := recover(); err != nil { + logger.Error("handleFunction failed: %v, packet addr:%v", err, packet.addr) + } + }() + + // logger.Debug("Receive data[%d]:%v", len(packet.data), packet.data) + + hPack, err := unpackHopPacket(packet.data) //协议包拆包 + if err == nil { + // logger.Debug("fromClient: %v", hPack.String()) + if hPack.Flag != 0 { + logger.Debug("New UDP Packet [%v] from: %v", hPack.Flag, packet.addr) + } + + if handle_func, ok := pktHandle[hPack.Flag]; ok { + handle_func(packet, hPack) //事件处理 + } else { + logger.Error("Unkown flag: %x", hPack.Flag) + } + } else { + logger.Error(err.Error()) + } } func (srv *HopServer) toClient(peer *HopPeer, flag byte, payload []byte, noise bool) { - hp := new(HopPacket) - hp.Seq = peer.Seq() - hp.Flag = flag - hp.payload = payload - - if addr, idx, ok := peer.addr(); ok { - logger.Debug("peer: %v", addr) - upacket := &udpPacket{addr, hp.Pack(), idx} - srv.toNet[idx] <- upacket - } else { - logger.Debug("peer not found") - } + hp := new(HopPacket) + hp.Seq = peer.Seq() + hp.Flag = flag + hp.payload = payload + + if addr, idx, ok := peer.addr(); ok { + // logger.Debug("toClient : peer: %v", addr) + upacket := &udpPacket{addr, hp.Pack(), idx} + peer.bytes_down += uint32(len(upacket.data)) + srv.toNet[idx] <- upacket + } else { + logger.Debug("toClient : peer not found sid:%d, uid:%d, ip:%d", peer.id>>32, peer.uid, peer.ip) + } } func (srv *HopServer) bufferToClient(peer *HopPeer, buf []byte) { - if hopFrager == nil { - // if no traffic morphing - hp := new(HopPacket) - hp.Flag = HOP_FLG_DAT - hp.buf = buf - hp.payload = buf[HOP_HDR_LEN:] - hp.Seq = peer.Seq() - - if addr, idx, ok := peer.addr(); ok { - upacket := &udpPacket{addr, hp.Pack(), idx} - srv.toNet[idx] <- upacket - } - } else { - // with traffic morphing - frame := buf[HOP_HDR_LEN:] - packets := hopFrager.Fragmentate(peer, frame) - for _, hp := range(packets) { - if addr, idx, ok := peer.addr(); ok { - upacket := &udpPacket{addr, hp.Pack(), idx} - srv.toNet[idx] <- upacket - } - } - } + if hopFrager == nil { + // if no traffic morphing + hp := new(HopPacket) + hp.Flag = HOP_FLG_DAT + hp.buf = buf + hp.payload = buf[HOP_HDR_LEN:] + hp.Seq = peer.Seq() + + if addr, idx, ok := peer.addr(); ok { + // logger.Debug("bufferToClient : peer: %v", addr) + upacket := &udpPacket{addr, hp.Pack(), idx} + peer.bytes_down += uint32(len(upacket.data)) + srv.toNet[idx] <- upacket + } + } else { + // with traffic morphing + frame := buf[HOP_HDR_LEN:] + packets := hopFrager.Fragmentate(peer, frame) + for _, hp := range packets { + if addr, idx, ok := peer.addr(); ok { + upacket := &udpPacket{addr, hp.Pack(), idx} + peer.bytes_down += uint32(len(upacket.data)) + srv.toNet[idx] <- upacket + } + } + } } func (srv *HopServer) handleKnock(u *udpPacket, hp *HopPacket) { - sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) - logger.Debug("port knock from client %v, sid: %d", u.addr, sid) - sid = (sid << 32) & uint64(0xFFFFFFFF00000000) - - hpeer, ok := srv.peers[sid] - if ! ok { - hpeer = newHopPeer(sid, srv, u.addr, u.channel) - srv.peers[sid] = hpeer - } else { - hpeer.insertAddr(u.addr, u.channel) - } - + sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) + sid = (sid << 32) & uint64(0xFFFFFFFF00000000) + hpeer, ok := srv.peers[sid] + if !ok { + hpeer = newHopPeer(sid, srv, u.addr, u.channel) + srv.peers[sid] = hpeer + } else { + hpeer.insertAddr(u.addr, u.channel) + logger.Debug("[knock] from client %v, sid:%d, uid:%d, gid:%d", u.addr, sid>>32, hpeer.uid, hpeer.gmid) + if hpeer.state == HOP_STAT_WORKING { + srv.toClient(hpeer, HOP_FLG_PSH, []byte{0}, true) + } + } + hpeer.bytes_up += uint32(len(u.data)) + hpeer.lastConnTime = time.Now() } func (srv *HopServer) handleHandshake(u *udpPacket, hp *HopPacket) { - sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) - sid = (sid << 32) & uint64(0xFFFFFFFF00000000) - logger.Debug("handshake from client %v, sid: %d", u.addr, sid) - - hpeer, ok := srv.peers[sid] - if ! ok { - hpeer = newHopPeer(sid, srv, u.addr, u.channel) - srv.peers[sid] = hpeer - } else { - hpeer.insertAddr(u.addr, u.channel) - } - - cltIP, err := srv.ippool.next() - if err != nil { - msg := fmt.Sprintf("%s", err.Error()) - srv.toClient(hpeer, HOP_FLG_HSH | HOP_FLG_FIN, []byte(msg), true) - delete(srv.peers, sid) - } else { - hpeer.ip = cltIP.IP.To4() - buf := bytes.NewBuffer(make([]byte, 0, 8)) - buf.Write([]byte(hpeer.ip)) - buf.Write([]byte(cltIP.Mask)) - key := ip4_uint64(hpeer.ip) - - logger.Debug("assign address %s, route key %d", cltIP, key) - srv.peers[key] = hpeer - atomic.StoreInt32(&hpeer.state, HOP_STAT_HANDSHAKE) - srv.toClient(hpeer, HOP_FLG_HSH | HOP_FLG_ACK, buf.Bytes(), true) - hpeer.hsDone = make(chan byte) - go func(){ - for i := 0; i < 5; i++ { - select { - case <- hpeer.hsDone: - hpeer.state = HOP_STAT_WORKING - return - case <- time.After(2 * time.Second): - logger.Debug("Client Handshake Timeout") - srv.toClient(hpeer, HOP_FLG_HSH | HOP_FLG_ACK, buf.Bytes(), true) - } - } - // timeout, kick - srv.toClient(hpeer, HOP_FLG_HSH | HOP_FLG_FIN, []byte{}, true) - srv.toClient(hpeer, HOP_FLG_HSH | HOP_FLG_FIN, []byte{}, true) - srv.toClient(hpeer, HOP_FLG_HSH | HOP_FLG_FIN, []byte{}, true) - - srv.ippool.relase(hpeer.ip) - delete(srv.peers, sid) - delete(srv.peers, key) - - }() - } + tms := []uint32{0, 0, 0} + for i := 0; i*4+4 <= int(hp.Dlen); i++ { + tms[i] = binary.BigEndian.Uint32(hp.payload[i*4 : i*4+4]) + } + sid := uint64(tms[0]) + gmid := tms[1] + uid := tms[2] + + logger.Debug("[handshake] from client %v, sid:%d, uid:%d, gmid:%d", u.addr, sid, uid, gmid) + sid = (sid << 32) & uint64(0xFFFFFFFF00000000) + + hpeer, ok := srv.peers[sid] + if !ok { + hpeer = newHopPeer(sid, srv, u.addr, u.channel) + srv.peers[sid] = hpeer + } else { + hpeer.insertAddr(u.addr, u.channel) + } + + hpeer.gmid = gmid + hpeer.uid = uid + hpeer.bytes_up += uint32(len(u.data)) + hpeer.lastConnTime = time.Now() + + cltIP, err := srv.ippool.next() + if err != nil { + msg := fmt.Sprintf("%s", err.Error()) + srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_FIN, []byte(msg), true) + delete(srv.peers, sid) + logger.Error("Have no IP to allocation") + } else { + hpeer.ip = cltIP.IP.To4() + buf := bytes.NewBuffer(make([]byte, 0, 5)) + //set client ip + buf.Write([]byte(hpeer.ip)) + siz, _ := cltIP.Mask.Size() + // buf.Write([]byte(cltIP.Mask)) + buf.WriteByte(byte(siz)) + + //set client dns + for i := 0; i < 2; i++ { + if ip, _, err := net.ParseCIDR(srv.cfg.DNS[i]); err != nil { + buf.Write([]byte{0, 0, 0, 0, 0}) + } else { + ip = ip.To4() + buf.Write([]byte(ip)) + buf.WriteByte(0) + } + } + + //set client route + routes := srv.routeList(gmid) + for i := 0; i < len(routes) && i <= 256; i++ { + buf.Write(routes[i][:]) + } + + key := ip4_uint64(hpeer.ip) + + logger.Debug("assign address %s route; sid:%d, uid:%d, gid:%d", cltIP, hpeer.id>>32, hpeer.uid, hpeer.gmid) + srv.peers[key] = hpeer + atomic.StoreInt32(&hpeer.state, HOP_STAT_HANDSHAKE) + srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_ACK, buf.Bytes(), true) + hpeer.hsDone = make(chan byte) + go func() { + for i := 0; i < 5; i++ { + select { + case <-hpeer.hsDone: + logger.Debug("hperr.hsDone; sid:%d, uid:%d, gid:%d", hpeer.id>>32, hpeer.uid, hpeer.gmid) + // hpeer.state = HOP_STAT_WORKING + return + case <-time.After(2 * time.Second): + logger.Debug("Client Handshake Timeout; sid:%d, uid:%d, gid:%d", hpeer.id>>32, hpeer.uid, hpeer.gmid) + srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_ACK, buf.Bytes(), true) + } + } + // timeout, kick + srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_FIN, []byte{0}, true) + srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_FIN, []byte{0}, true) + srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_FIN, []byte{0}, true) + + srv.ippool.relase(hpeer.ip) + delete(srv.peers, sid) + delete(srv.peers, key) + + }() + } } func (srv *HopServer) handleHandshakeAck(u *udpPacket, hp *HopPacket) { - sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) - sid = (sid << 32) & uint64(0xFFFFFFFF00000000) - hpeer, ok := srv.peers[sid] - if ! ok { - return - } - logger.Debug("Client Handshake Done") - logger.Info("Client %d Connected", sid) - atomic.StoreInt32(&hpeer.state, HOP_STAT_WORKING) - hpeer.hsDone <- 1 + sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) + sid = (sid << 32) & uint64(0xFFFFFFFF00000000) + hpeer, ok := srv.peers[sid] + if !ok { + return + } + hpeer.bytes_up += uint32(len(u.data)) + hpeer.lastConnTime = time.Now() + logger.Info("Client sid:%d, uid:%d, gid:%d, ip %v Connected. DHCP:%v", sid>>32, hpeer.uid, hpeer.gmid, u.addr, hpeer.ip) + + if ok = atomic.CompareAndSwapInt32(&hpeer.state, HOP_STAT_HANDSHAKE, HOP_STAT_WORKING); ok { + hpeer.hsDone <- 1 + } } func (srv *HopServer) handleDataPacket(u *udpPacket, hp *HopPacket) { - sid := uint64(hp.Sid) - sid = (sid << 32) & uint64(0xFFFFFFFF00000000) - - if peer, ok := srv.peers[sid]; ok { - // logger.Debug("n peer addrs: %v", len(peer._addrs_lst)) - // peer.insertAddr(u.addr, u.channel) - peer.recvBuffer.Push(hp) - } + sid := uint64(hp.Sid) + sid = (sid << 32) & uint64(0xFFFFFFFF00000000) + + if hpeer, ok := srv.peers[sid]; ok && hpeer.state == HOP_STAT_WORKING { + // logger.Debug("n hpeer addrs: %v", len(hpeer._addrs_lst)) + // hpeer.insertAddr(u.addr, u.channel) + if ok, ip := srv.routeMatch(hpeer, hp); ok { + hpeer.lastConnTime = time.Now() + hpeer.recvBuffer.Push(hp) + } else { + logger.Info("DataPacket not routed to %v", ip) + } + hpeer.bytes_up += uint32(len(u.data)) + } else { + peer := newHopPeer(sid, srv, u.addr, u.channel) + srv.toClient(peer, HOP_FLG_FIN|HOP_FLG_ACK, []byte{0}, false) + } + } func (srv *HopServer) handleFinish(u *udpPacket, hp *HopPacket) { - sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) - sid = (sid << 32) & uint64(0xFFFFFFFF00000000) - logger.Info("releasing client %v, sid: %d", u.addr, sid) - - hpeer, ok := srv.peers[sid] - if ! ok { - return - } - - key := ip4_uint64(hpeer.ip) - srv.ippool.relase(hpeer.ip) - delete(srv.peers, sid) - delete(srv.peers, key) - srv.toClient(hpeer, HOP_FLG_FIN | HOP_FLG_ACK, []byte{}, false) + sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) + logger.Info("releasing client %v, sid:%d", u.addr, sid) + sid = (sid << 32) & uint64(0xFFFFFFFF00000000) + + srv.deletePeer(sid) +} + +func (srv *HopServer) deletePeer(sid uint64) { + hpeer, ok := srv.peers[sid] + if !ok { + return + } + srv.toClient(hpeer, HOP_FLG_FIN|HOP_FLG_ACK, []byte{0}, false) + key := ip4_uint64(hpeer.ip) + srv.ippool.relase(hpeer.ip) + + // log user info + if sid>>32 > 0 { + logger.Info("UserBytes sid:%d, uid:%d, gid:%d, up:%d, down:%d", hpeer.id>>32, hpeer.uid, hpeer.gmid, hpeer.bytes_up, hpeer.bytes_down) + } + delete(srv.peers, sid) + delete(srv.peers, key) } func (srv *HopServer) cleanUp() { - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) - <-c + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) + <-c + + clearMSS(srv.iface.Name(), true) + os.Exit(0) +} + +func (srv *HopServer) routeList(gmid uint32) [][5]byte { + var routes [][5]byte = make([][5]byte, 0, 5) + for _, k := range []uint32{1, gmid} { + if list, ok := srv.cfg.RouteList[k]; ok { + routes = append(routes, list...) + } + } + if len(routes) == 0 { + routes = [][5]byte{[5]byte{254, 254, 254, 254, 32}} + } + return routes +} + +func (srv *HopServer) routeMatch(peer *HopPeer, hp *HopPacket) (bool, net.IP) { + ip := waterutil.IPv4Destination(hp.payload).To4() + list := srv.routeList(peer.gmid) + intip := binary.BigEndian.Uint32([]byte(ip)) + for _, l := range list { + routeIp := binary.BigEndian.Uint32(l[:4]) + mask := 32 - l[4] + if intip >= routeIp && (intip>>mask) == (routeIp>>mask) { + return true, ip + } + } + + return false, ip +} - clearMSS(srv.iface.Name(), true) - os.Exit(0) +func (srv *HopServer) peerTimeoutWatcher() { + for { + if srv.cfg.PeerTimeout <= 0 { + return + } + time.Sleep(time.Minute) + count := 0 + timeout := time.Second * time.Duration(srv.cfg.PeerTimeout) + for sid, hpeer := range srv.peers { + // logger.Debug("watch:%v", hpeer.lastConnTime) + if sid>>32 > 0 { + count++ + } + conntime := time.Since(hpeer.lastConnTime) + // logger.Debug("watch:%v %v", conntime.Seconds(), timeout.Seconds()) + if conntime > timeout { + go srv.deletePeer(sid) + } + } + logger.Info("Ulinks:%d", count) + } } diff --git a/main.go b/main.go index dedfbbe..0fae379 100644 --- a/main.go +++ b/main.go @@ -19,11 +19,15 @@ package main import ( - "flag" - "fmt" - "github.com/bigeagle/gohop/hop" - "github.com/bigeagle/gohop/logging" - "os" + "./hop" + "./logging" + "flag" + "fmt" + "io" + "os" + "runtime" + "time" + "path/filepath" ) var srvMode, cltMode, debug, getVersion bool @@ -31,46 +35,84 @@ var cfgFile string var VERSION = "0.3.2-dev" +func init() { + flag.BoolVar(&getVersion, "version", false, "Get Version info") + flag.BoolVar(&debug, "debug", false, "Provide debug info") + flag.StringVar(&cfgFile, "config", "", "configfile") +} + func main() { - flag.BoolVar(&getVersion, "version", false, "Get Version info") - flag.BoolVar(&debug, "debug", false, "Provide debug info") - flag.StringVar(&cfgFile, "config", "", "configfile") - flag.Parse() + flag.Parse() + + if getVersion { + fmt.Println("GoHop: Yet Another VPN to Escape from Censorship") + fmt.Printf("Version: %s\n", VERSION) + os.Exit(0) + } - if getVersion { - fmt.Println("GoHop: Yet Another VPN to Escape from Censorship") - fmt.Printf("Version: %s\n", VERSION) - os.Exit(0) - } + logging.InitLogger(debug) + logger := logging.GetLogger() - logging.InitLogger(debug) - logger := logging.GetLogger() + checkerr := func(err error) { + if err != nil { + logger.Error(err.Error()) + os.Exit(1) + } + } - checkerr := func(err error) { - if err != nil { - logger.Error(err.Error()) - os.Exit(1) - } - } + if cfgFile == "" { + cfgFile = flag.Arg(0) + } - if cfgFile == "" { - cfgFile = flag.Arg(0) - } + logger.Info("using config file: %v", cfgFile) - logger.Info("using config file: %v", cfgFile) + icfg, err := hop.ParseHopConfig(cfgFile) + //logger.Debug("%v", icfg) + checkerr(err) - icfg, err := hop.ParseHopConfig(cfgFile) - logger.Debug("%v", icfg) - checkerr(err) + // 设置可使用的最大核心数 + runtime.GOMAXPROCS(runtime.NumCPU() - 1) + fmt.Printf("/** server start **/\nUse %d/%d CPU cores\n", runtime.GOMAXPROCS(-1), runtime.NumCPU()) - switch cfg := icfg.(type) { - case hop.HopServerConfig: - err := hop.NewServer(cfg) - checkerr(err) - case hop.HopClientConfig: - err := hop.NewClient(cfg) - checkerr(err) - default: - logger.Error("Invalid config file") - } + switch cfg := icfg.(type) { + case hop.HopServerConfig: + addWatchFile(cfg.RouteFile, cfg.RouteConfig, time.Second*60) + err := hop.NewServer(&cfg) + checkerr(err) + case hop.HopClientConfig: + err := hop.NewClient(&cfg) + checkerr(err) + default: + logger.Error("Invalid config file") + } +} + +/* +配置文件监控方法 +不能放到其他包中。避免非启动时调用。 +*/ +func addWatchFile(filename string, callback func(r io.Reader), st time.Duration) { + logger := logging.GetLogger() + modtime := int64(0) + filename, _ = filepath.Abs(filename) + logger.Info("addWatchFile : " + filename) + setF := func() { + if f, err := os.Open(filename); err != nil { + logger.Error("config file " + filename + " error : " + err.Error()) + } else if fi, err := f.Stat(); err != nil { + logger.Error("config file " + filename + " error : " + err.Error()) + } else if mt := fi.ModTime().Unix(); mt != modtime { + logger.Debug("load config file : " + filename + " begin !") + modtime = mt + callback(f) + logger.Debug("load config file : " + filename + " finish !") + } + } + setF() + go func() { + for { + time.Sleep(st) + setF() + } + }() } diff --git a/route.ini b/route.ini new file mode 100644 index 0000000..6ecf838 --- /dev/null +++ b/route.ini @@ -0,0 +1,31 @@ +# [游戏ID] : 游戏ID为 1 时,使用所有客户端通用规则 请慎用 +# 路由条目 : 如 202.58.246.0/24 +# 文件修改后1分钟生效 + + +[1] #通用规则 +# 220.254.254.254/32 + + + +[1000] #游戏ID为1000时,使用的路由规则 +12.0.0.0/6 +16.0.0.0/4 +32.0.0.0/3 +64.0.0.0/3 +96.0.0.0/4 +112.0.0.0/5 +120.0.0.0/6 +124.0.0.0/7 +132.0.0.0/6 +152.0.0.0/5 +160.0.0.0/5 +168.0.0.0/7 +175.0.0.0/8 +176.0.0.0/4 +202.0.0.0/7 +208.0.0.0/4 + + + + diff --git a/server.ini b/server.ini index bf0cc3f..0ac2404 100644 --- a/server.ini +++ b/server.ini @@ -4,14 +4,23 @@ mode = server [server] # port range to listen -hopstart = 40100 -hopend = 40200 +hopstart = 4000 +hopend = 4000 # server addr -addr = 10.1.1.1/24 +addr = 10.251.0.1/16 +dns = 0.0.0.0/0 +dns = 0.0.0.0/0 +# route file path +routefile = ./route.ini +# peer timeout (second) +peertimeout = 300 # master key mtu = 1400 -key = ilovethebigbrother +key = com_zhf5_tvpn # method of traffic morphing: none or randsize morphmethod = none # Fix MSS for tcp handshake fixmss = true + + + diff --git a/vpn.sh b/vpn.sh new file mode 100755 index 0000000..d0db180 --- /dev/null +++ b/vpn.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +CMD="./tvpn" +PID="./log/PID.txt" +LOG="./log/tvpn.log" +DEBUG="false" + +# --------------------------------------------------- + +function start { + $CMD -debug=$DEBUG server.ini >> $LOG 2>&1 & + tvpnpid=$! + echo $tvpnpid > $PID + echo "start [ok]" +} + +function stop { + kill `cat $PID` + rm $PID + echo "stop [ok]" +} + +# -------------------------------------------------- + + +echo "$CMD $1" + +case "$1" in +start) + sysctl net.ipv4.ip_forward=1 + iptables -t nat -A POSTROUTING -j MASQUERADE + start +;; +start_debug) + sysctl net.ipv4.ip_forward=1 + iptables -t nat -A POSTROUTING -j MASQUERADE + DEBUG="true" + start +;; +restart) + if [ -f $PID ] ; then + stop + sleep 4 + fi + start +;; +stop) + stop + exit 0 +;; +esac + + +for (( c=0 ; ; c++ )) +do + if [ -f $PID ] ; then + tvpnpid=`cat $PID` + cmdex="ps uh -p$tvpnpid" + psrtn=`$cmdex` + if [ -z "$psrtn" ]; then + echo "`date '+%Y/%m/%d %H:%M:%S'` FATALERROR RESTART SERVICE" >> $LOG + start + elif (( $c%20 == 0 )); then + echo "`date '+%Y/%m/%d %H:%M:%S'` PSINFO $psrtn" >> $LOG + c=0 + fi + sleep 3 + else + break + fi +done + From 8c5547401ec314db45194f97c1765b5f118268ff Mon Sep 17 00:00:00 2001 From: ZhangFeng Date: Tue, 30 Dec 2014 15:21:44 +0800 Subject: [PATCH 2/2] replace tab to space --- hop/buffer.go | 114 +++--- hop/cipher.go | 74 ++-- hop/client.go | 620 +++++++++++++++---------------- hop/common.go | 4 +- hop/config.go | 156 ++++---- hop/iface.go | 394 ++++++++++---------- hop/ippool.go | 66 ++-- hop/protocol.go | 362 +++++++++--------- hop/server.go | 962 ++++++++++++++++++++++++------------------------ main.go | 140 +++---- 10 files changed, 1446 insertions(+), 1446 deletions(-) diff --git a/hop/buffer.go b/hop/buffer.go index 9306d55..ace9b5f 100644 --- a/hop/buffer.go +++ b/hop/buffer.go @@ -21,97 +21,97 @@ package hop import ( - "errors" - "sort" - "sync" - "time" + "errors" + "sort" + "sync" + "time" ) const ( - hpBufSize = 384 - bufferTimeout = 20 * time.Millisecond + hpBufSize = 384 + bufferTimeout = 20 * time.Millisecond ) type hopPacketBuffer struct { - buf [hpBufSize]*HopPacket - outQueue []*HopPacket - count int - timer *time.Timer - timeout time.Duration - flushChan chan *HopPacket - mutex sync.Mutex + buf [hpBufSize]*HopPacket + outQueue []*HopPacket + count int + timer *time.Timer + timeout time.Duration + flushChan chan *HopPacket + mutex sync.Mutex } var bufFull = errors.New("Buffer Full") func newHopPacketBuffer(flushChan chan *HopPacket, timeout time.Duration) *hopPacketBuffer { - hb := new(hopPacketBuffer) - hb.count = 0 - hb.timer = time.NewTimer(1000 * time.Second) - hb.timer.Stop() - hb.flushChan = flushChan - hb.timeout = timeout - go func() { - for { - <-hb.timer.C - hb.FlushToChan(hb.flushChan) - hb.timer.Reset(hb.timeout) - } - }() - return hb + hb := new(hopPacketBuffer) + hb.count = 0 + hb.timer = time.NewTimer(1000 * time.Second) + hb.timer.Stop() + hb.flushChan = flushChan + hb.timeout = timeout + go func() { + for { + <-hb.timer.C + hb.FlushToChan(hb.flushChan) + hb.timer.Reset(hb.timeout) + } + }() + return hb } func (hb *hopPacketBuffer) Push(p *HopPacket) { - defer hb.mutex.Unlock() - hb.mutex.Lock() + defer hb.mutex.Unlock() + hb.mutex.Lock() - hb.timer.Reset(hb.timeout) + hb.timer.Reset(hb.timeout) - hb.buf[hb.count] = p - hb.count += 1 - if hb.count >= hpBufSize { - // logger.Warning("buffer full, flushing") - hb._flush() - } + hb.buf[hb.count] = p + hb.count += 1 + if hb.count >= hpBufSize { + // logger.Warning("buffer full, flushing") + hb._flush() + } } func (hb *hopPacketBuffer) Len() int { return len(hb.outQueue) } func (hb *hopPacketBuffer) Less(i, j int) bool { - a, b := hb.outQueue[i], hb.outQueue[j] - return a.Seq < b.Seq + a, b := hb.outQueue[i], hb.outQueue[j] + return a.Seq < b.Seq } func (hb *hopPacketBuffer) Swap(i, j int) { - hb.outQueue[i], hb.outQueue[j] = hb.outQueue[j], hb.outQueue[i] + hb.outQueue[i], hb.outQueue[j] = hb.outQueue[j], hb.outQueue[i] } func (hb *hopPacketBuffer) Flush() { - defer hb.mutex.Unlock() - hb.mutex.Lock() - hb._flushToChan(hb.flushChan) + defer hb.mutex.Unlock() + hb.mutex.Lock() + hb._flushToChan(hb.flushChan) } func (hb *hopPacketBuffer) _flush() { - hb._flushToChan(hb.flushChan) + hb._flushToChan(hb.flushChan) } func (hb *hopPacketBuffer) _flushToChan(c chan *HopPacket) { - if hopFrager != nil { - hb.outQueue = hopFrager.reAssemble(hb.buf[:hb.count]) - } else { - hb.outQueue = hb.buf[:hb.count] - } - - sort.Sort(hb) - for _, p := range hb.outQueue { - c <- p - } - hb.count = 0 + if hopFrager != nil { + hb.outQueue = hopFrager.reAssemble(hb.buf[:hb.count]) + } else { + hb.outQueue = hb.buf[:hb.count] + } + + sort.Sort(hb) + for _, p := range hb.outQueue { + c <- p + } + hb.count = 0 } func (hb *hopPacketBuffer) FlushToChan(c chan *HopPacket) { - defer hb.mutex.Unlock() - hb.mutex.Lock() - hb._flushToChan(c) + defer hb.mutex.Unlock() + hb.mutex.Lock() + hb._flushToChan(c) } diff --git a/hop/cipher.go b/hop/cipher.go index abc2180..ed1cbc5 100644 --- a/hop/cipher.go +++ b/hop/cipher.go @@ -19,63 +19,63 @@ package hop import ( - "bytes" - "crypto/aes" - _cipher "crypto/cipher" - "crypto/md5" - "crypto/rand" + "bytes" + "crypto/aes" + _cipher "crypto/cipher" + "crypto/md5" + "crypto/rand" ) type hopCipher struct { - block _cipher.Block + block _cipher.Block } const cipherBlockSize = 16 func newHopCipher(key []byte) (*hopCipher, error) { - s := new(hopCipher) - // key = PKCS5Padding(key, cipherBlockSize) - key1 := md5.Sum(key) - block, err := aes.NewCipher(key1[:]) - if err != nil { - return nil, err - } - s.block = block - return s, nil + s := new(hopCipher) + // key = PKCS5Padding(key, cipherBlockSize) + key1 := md5.Sum(key) + block, err := aes.NewCipher(key1[:]) + if err != nil { + return nil, err + } + s.block = block + return s, nil } func (s *hopCipher) encrypt(msg []byte) []byte { - pmsg := PKCS5Padding(msg, cipherBlockSize) - buf := make([]byte, len(pmsg)+cipherBlockSize) + pmsg := PKCS5Padding(msg, cipherBlockSize) + buf := make([]byte, len(pmsg)+cipherBlockSize) - iv := buf[:cipherBlockSize] - rand.Read(iv) - encrypter := _cipher.NewCBCEncrypter(s.block, iv) - encrypter.CryptBlocks(buf[cipherBlockSize:], pmsg) + iv := buf[:cipherBlockSize] + rand.Read(iv) + encrypter := _cipher.NewCBCEncrypter(s.block, iv) + encrypter.CryptBlocks(buf[cipherBlockSize:], pmsg) - return buf + return buf } func (s *hopCipher) decrypt(iv []byte, ctext []byte) []byte { - defer func() { - if err := recover(); err != nil { - logger.Error("%v", err) - } - }() - decrypter := _cipher.NewCBCDecrypter(s.block, iv) - buf := make([]byte, len(ctext)) - decrypter.CryptBlocks(buf, ctext) - return PKCS5UnPadding(buf) + defer func() { + if err := recover(); err != nil { + logger.Error("%v", err) + } + }() + decrypter := _cipher.NewCBCDecrypter(s.block, iv) + buf := make([]byte, len(ctext)) + decrypter.CryptBlocks(buf, ctext) + return PKCS5UnPadding(buf) } func PKCS5Padding(ciphertext []byte, blockSize int) []byte { - padding := blockSize - len(ciphertext)%blockSize - padtext := bytes.Repeat([]byte{byte(padding)}, padding) - return append(ciphertext, padtext...) + padding := blockSize - len(ciphertext)%blockSize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(ciphertext, padtext...) } func PKCS5UnPadding(origData []byte) []byte { - length := len(origData) - unpadding := int(origData[length-1]) - return origData[:(length - unpadding)] + length := len(origData) + unpadding := int(origData[length-1]) + return origData[:(length - unpadding)] } diff --git a/hop/client.go b/hop/client.go index 83ebc56..823e6f5 100644 --- a/hop/client.go +++ b/hop/client.go @@ -19,369 +19,369 @@ package hop import ( - "crypto/rand" - "errors" - "fmt" - "github.com/bigeagle/water" - mrand "math/rand" - "net" - "os" - "os/signal" - "sync/atomic" - "syscall" - "time" + "crypto/rand" + "errors" + "fmt" + "github.com/bigeagle/water" + mrand "math/rand" + "net" + "os" + "os/signal" + "sync/atomic" + "syscall" + "time" ) var net_gateway, net_nic string type route struct { - dest, nextHop, iface string + dest, nextHop, iface string } type HopClient struct { - // config - cfg *HopClientConfig - // interface - iface *water.Interface - // ip addr - ip net.IP - - // session id - sid [4]byte - // session state - state int32 - - // net to interface - toIface chan *HopPacket - // buffer for packets from net - recvBuf *hopPacketBuffer - // channel to send frames to net - toNet chan *HopPacket - - handshakeDone chan byte - finishAck chan byte - // state variable to ensure serverRoute added - srvRoute int32 - // routes need to be clean in the end - routes []string - // sequence number - seq uint32 + // config + cfg *HopClientConfig + // interface + iface *water.Interface + // ip addr + ip net.IP + + // session id + sid [4]byte + // session state + state int32 + + // net to interface + toIface chan *HopPacket + // buffer for packets from net + recvBuf *hopPacketBuffer + // channel to send frames to net + toNet chan *HopPacket + + handshakeDone chan byte + finishAck chan byte + // state variable to ensure serverRoute added + srvRoute int32 + // routes need to be clean in the end + routes []string + // sequence number + seq uint32 } func NewClient(cfg *HopClientConfig) error { - var err error - - // logger.Debug("%v", cfg) - cipher, err = newHopCipher([]byte(cfg.Key)) - if err != nil { - return err - } - - if cfg.MTU != 0 { - MTU = cfg.MTU - } - - hopClient := new(HopClient) - rand.Read(hopClient.sid[:]) - hopClient.toIface = make(chan *HopPacket, 32) - hopClient.toNet = make(chan *HopPacket, 32) - hopClient.recvBuf = newHopPacketBuffer(hopClient.toIface, bufferTimeout) - hopClient.cfg = cfg - hopClient.state = HOP_STAT_INIT - hopClient.handshakeDone = make(chan byte) - hopClient.finishAck = make(chan byte) - hopClient.srvRoute = 0 - hopClient.routes = make([]string, 0, 1024) - - switch cfg.MorphMethod { - case "randsize": - m := newRandMorpher(MTU) - hopFrager = newHopFragmenter(m) - logger.Info("Using RandomSize Morpher") - default: - logger.Info("No Traffic Morphing") - } - - go hopClient.cleanUp() - - iface, err := newTun("") - if err != nil { - return err - } - hopClient.iface = iface - - net_gateway, net_nic, err = getNetGateway() - logger.Debug("Net Gateway: %s %s", net_gateway, net_nic) - if err != nil { - return err - } - - for port := cfg.HopStart; port <= cfg.HopEnd; port++ { - server := fmt.Sprintf("%s:%d", cfg.Server, port) - go hopClient.handleUDP(server) - } - - // wait until handshake done - res := <-hopClient.handshakeDone - if res == 0 { - return errors.New("Handshake Fail") - } - - routeDone := make(chan bool) - go func() { - for _, dest := range cfg.Net_gateway { - addRoute(dest, net_gateway, net_nic) - hopClient.routes = append(hopClient.routes, dest) - } - if cfg.Redirect_gateway { - routeDone <- true - } - }() - - if cfg.Redirect_gateway { - go func() { - <-routeDone - err = redirectGateway(iface.Name(), tun_peer.String()) - if err != nil { - logger.Error(err.Error()) - return - } - }() - } - - hopClient.handleInterface() - - return errors.New("Not expected to exit") + var err error + + // logger.Debug("%v", cfg) + cipher, err = newHopCipher([]byte(cfg.Key)) + if err != nil { + return err + } + + if cfg.MTU != 0 { + MTU = cfg.MTU + } + + hopClient := new(HopClient) + rand.Read(hopClient.sid[:]) + hopClient.toIface = make(chan *HopPacket, 32) + hopClient.toNet = make(chan *HopPacket, 32) + hopClient.recvBuf = newHopPacketBuffer(hopClient.toIface, bufferTimeout) + hopClient.cfg = cfg + hopClient.state = HOP_STAT_INIT + hopClient.handshakeDone = make(chan byte) + hopClient.finishAck = make(chan byte) + hopClient.srvRoute = 0 + hopClient.routes = make([]string, 0, 1024) + + switch cfg.MorphMethod { + case "randsize": + m := newRandMorpher(MTU) + hopFrager = newHopFragmenter(m) + logger.Info("Using RandomSize Morpher") + default: + logger.Info("No Traffic Morphing") + } + + go hopClient.cleanUp() + + iface, err := newTun("") + if err != nil { + return err + } + hopClient.iface = iface + + net_gateway, net_nic, err = getNetGateway() + logger.Debug("Net Gateway: %s %s", net_gateway, net_nic) + if err != nil { + return err + } + + for port := cfg.HopStart; port <= cfg.HopEnd; port++ { + server := fmt.Sprintf("%s:%d", cfg.Server, port) + go hopClient.handleUDP(server) + } + + // wait until handshake done + res := <-hopClient.handshakeDone + if res == 0 { + return errors.New("Handshake Fail") + } + + routeDone := make(chan bool) + go func() { + for _, dest := range cfg.Net_gateway { + addRoute(dest, net_gateway, net_nic) + hopClient.routes = append(hopClient.routes, dest) + } + if cfg.Redirect_gateway { + routeDone <- true + } + }() + + if cfg.Redirect_gateway { + go func() { + <-routeDone + err = redirectGateway(iface.Name(), tun_peer.String()) + if err != nil { + logger.Error(err.Error()) + return + } + }() + } + + hopClient.handleInterface() + + return errors.New("Not expected to exit") } func (clt *HopClient) handleInterface() { - // network packet to interface - go func() { - for { - hp := <-clt.toIface - // logger.Debug("New Net packet to device") - _, err := clt.iface.Write(hp.payload) - // logger.Debug("n: %d, len: %d", n, len(hp.payload)) - if err != nil { - logger.Error(err.Error()) - return - } - } - }() - - frame := make([]byte, IFACE_BUFSIZE) - for { - n, err := clt.iface.Read(frame) - if err != nil { - logger.Error(err.Error()) - return - } - - buf := make([]byte, n+HOP_HDR_LEN) - copy(buf[HOP_HDR_LEN:], frame[:n]) - if hopFrager == nil { - // if no traffic morphing - // Hack to reduce memcopy - hp := new(HopPacket) - hp.payload = buf[HOP_HDR_LEN:] - hp.buf = buf - hp.Seq = clt.Seq() - clt.toNet <- hp - - } else { - // with traffic morphing - packets := hopFrager.Fragmentate(clt, buf[HOP_HDR_LEN:]) - for _, hp := range packets { - clt.toNet <- hp - } - } - - } + // network packet to interface + go func() { + for { + hp := <-clt.toIface + // logger.Debug("New Net packet to device") + _, err := clt.iface.Write(hp.payload) + // logger.Debug("n: %d, len: %d", n, len(hp.payload)) + if err != nil { + logger.Error(err.Error()) + return + } + } + }() + + frame := make([]byte, IFACE_BUFSIZE) + for { + n, err := clt.iface.Read(frame) + if err != nil { + logger.Error(err.Error()) + return + } + + buf := make([]byte, n+HOP_HDR_LEN) + copy(buf[HOP_HDR_LEN:], frame[:n]) + if hopFrager == nil { + // if no traffic morphing + // Hack to reduce memcopy + hp := new(HopPacket) + hp.payload = buf[HOP_HDR_LEN:] + hp.buf = buf + hp.Seq = clt.Seq() + clt.toNet <- hp + + } else { + // with traffic morphing + packets := hopFrager.Fragmentate(clt, buf[HOP_HDR_LEN:]) + for _, hp := range packets { + clt.toNet <- hp + } + } + + } } func (clt *HopClient) handleUDP(server string) { - udpAddr, _ := net.ResolveUDPAddr("udp", server) - udpConn, _ := net.DialUDP("udp", nil, udpAddr) - - logger.Debug(udpConn.RemoteAddr().String()) - - // packet map - pktHandle := map[byte](func(*net.UDPConn, *HopPacket)){ - HOP_FLG_HSH | HOP_FLG_ACK: clt.handleHandshakeAck, - HOP_FLG_HSH | HOP_FLG_FIN: clt.handleHandshakeError, - HOP_FLG_DAT: clt.handleDataPacket, - HOP_FLG_DAT | HOP_FLG_MFR: clt.handleDataPacket, - HOP_FLG_FIN | HOP_FLG_ACK: clt.handleFinishAck, - } - - clt.knock(udpConn) - go func() { - n := mrand.Intn(1000) - time.Sleep(time.Duration(n) * time.Millisecond) - clt.handeshake(udpConn) - }() - - // add route through net gateway - if clt.cfg.Redirect_gateway && (!clt.cfg.Local) { - if atomic.CompareAndSwapInt32(&clt.srvRoute, 0, 1) { - if udpAddr, ok := udpConn.RemoteAddr().(*net.UDPAddr); ok { - srvIP := udpAddr.IP.To4() - if srvIP != nil { - srvDest := srvIP.String() + "/32" - addRoute(srvDest, net_gateway, net_nic) - clt.routes = append(clt.routes, srvDest) - } - } - } - } - - // forward iface frames to network - go func() { - for { - hp := <-clt.toNet - hp.setSid(clt.sid) - // logger.Debug("New iface frame") - // dest := waterutil.IPv4Destination(frame) - // logger.Debug("ip dest: %v", dest) - - udpConn.Write(hp.Pack()) - } - }() - - buf := make([]byte, IFACE_BUFSIZE) - for { - logger.Debug("waiting for udp packet") - n, err := udpConn.Read(buf) - logger.Debug("New UDP Packet, len: %d", n) - if err != nil { - logger.Error(err.Error()) - return - } - - hp, err := unpackHopPacket(buf[:n]) - if err != nil { - logger.Debug("Error depacketing") - continue - } - if handle_func, ok := pktHandle[hp.Flag]; ok { - handle_func(udpConn, hp) - } else { - logger.Error("Unkown flag: %x", hp.Flag) - } - } + udpAddr, _ := net.ResolveUDPAddr("udp", server) + udpConn, _ := net.DialUDP("udp", nil, udpAddr) + + logger.Debug(udpConn.RemoteAddr().String()) + + // packet map + pktHandle := map[byte](func(*net.UDPConn, *HopPacket)){ + HOP_FLG_HSH | HOP_FLG_ACK: clt.handleHandshakeAck, + HOP_FLG_HSH | HOP_FLG_FIN: clt.handleHandshakeError, + HOP_FLG_DAT: clt.handleDataPacket, + HOP_FLG_DAT | HOP_FLG_MFR: clt.handleDataPacket, + HOP_FLG_FIN | HOP_FLG_ACK: clt.handleFinishAck, + } + + clt.knock(udpConn) + go func() { + n := mrand.Intn(1000) + time.Sleep(time.Duration(n) * time.Millisecond) + clt.handeshake(udpConn) + }() + + // add route through net gateway + if clt.cfg.Redirect_gateway && (!clt.cfg.Local) { + if atomic.CompareAndSwapInt32(&clt.srvRoute, 0, 1) { + if udpAddr, ok := udpConn.RemoteAddr().(*net.UDPAddr); ok { + srvIP := udpAddr.IP.To4() + if srvIP != nil { + srvDest := srvIP.String() + "/32" + addRoute(srvDest, net_gateway, net_nic) + clt.routes = append(clt.routes, srvDest) + } + } + } + } + + // forward iface frames to network + go func() { + for { + hp := <-clt.toNet + hp.setSid(clt.sid) + // logger.Debug("New iface frame") + // dest := waterutil.IPv4Destination(frame) + // logger.Debug("ip dest: %v", dest) + + udpConn.Write(hp.Pack()) + } + }() + + buf := make([]byte, IFACE_BUFSIZE) + for { + logger.Debug("waiting for udp packet") + n, err := udpConn.Read(buf) + logger.Debug("New UDP Packet, len: %d", n) + if err != nil { + logger.Error(err.Error()) + return + } + + hp, err := unpackHopPacket(buf[:n]) + if err != nil { + logger.Debug("Error depacketing") + continue + } + if handle_func, ok := pktHandle[hp.Flag]; ok { + handle_func(udpConn, hp) + } else { + logger.Error("Unkown flag: %x", hp.Flag) + } + } } func (clt *HopClient) Seq() uint32 { - return atomic.AddUint32(&clt.seq, 1) + return atomic.AddUint32(&clt.seq, 1) } func (clt *HopClient) toServer(u *net.UDPConn, flag byte, payload []byte, noise bool) { - hp := new(HopPacket) - hp.Flag = flag - hp.Seq = clt.Seq() - hp.setPayload(payload) - if noise { - hp.addNoise(mrand.Intn(MTU - 64 - len(payload))) - } - u.Write(hp.Pack()) + hp := new(HopPacket) + hp.Flag = flag + hp.Seq = clt.Seq() + hp.setPayload(payload) + if noise { + hp.addNoise(mrand.Intn(MTU - 64 - len(payload))) + } + u.Write(hp.Pack()) } // knock server port func (clt *HopClient) knock(u *net.UDPConn) { - clt.toServer(u, HOP_FLG_PSH, clt.sid[:], true) + clt.toServer(u, HOP_FLG_PSH, clt.sid[:], true) } // handshake with server func (clt *HopClient) handeshake(u *net.UDPConn) { - res := atomic.CompareAndSwapInt32(&clt.state, HOP_STAT_INIT, HOP_STAT_HANDSHAKE) - // logger.Debug("raced for handshake: %v", res) + res := atomic.CompareAndSwapInt32(&clt.state, HOP_STAT_INIT, HOP_STAT_HANDSHAKE) + // logger.Debug("raced for handshake: %v", res) - if res { - logger.Info("start handeshaking") - clt.toServer(u, HOP_FLG_HSH, clt.sid[:], true) - } + if res { + logger.Info("start handeshaking") + clt.toServer(u, HOP_FLG_HSH, clt.sid[:], true) + } } // finish session func (clt *HopClient) finishSession() { - logger.Info("Finishing Session") - atomic.StoreInt32(&clt.state, HOP_STAT_FIN) - hp := new(HopPacket) - hp.Flag = HOP_FLG_FIN - hp.setPayload(clt.sid[:]) - hp.Seq = clt.Seq() - clt.toNet <- hp - clt.toNet <- hp - clt.toNet <- hp + logger.Info("Finishing Session") + atomic.StoreInt32(&clt.state, HOP_STAT_FIN) + hp := new(HopPacket) + hp.Flag = HOP_FLG_FIN + hp.setPayload(clt.sid[:]) + hp.Seq = clt.Seq() + clt.toNet <- hp + clt.toNet <- hp + clt.toNet <- hp } // handle handeshake ack func (clt *HopClient) handleHandshakeAck(u *net.UDPConn, hp *HopPacket) { - if atomic.LoadInt32(&clt.state) == HOP_STAT_HANDSHAKE { - by := hp.payload - addrStr := fmt.Sprintf("%d.%d.%d.%d/%d", by[0], by[1], by[2], by[3], by[4]) - ip, subnet, _ := net.ParseCIDR(addrStr) - setTunIP(clt.iface, ip, subnet) - if clt.cfg.FixMSS { - fixMSS(clt.iface.Name(), false) - } - res := atomic.CompareAndSwapInt32(&clt.state, HOP_STAT_HANDSHAKE, HOP_STAT_WORKING) - if !res { - logger.Error("Client state not expected: %d", clt.state) - } - logger.Info("Session Initialized") - clt.handshakeDone <- 1 - } - - logger.Debug("Handshake Ack to Server") - clt.toServer(u, HOP_FLG_HSH|HOP_FLG_ACK, clt.sid[:], true) + if atomic.LoadInt32(&clt.state) == HOP_STAT_HANDSHAKE { + by := hp.payload + addrStr := fmt.Sprintf("%d.%d.%d.%d/%d", by[0], by[1], by[2], by[3], by[4]) + ip, subnet, _ := net.ParseCIDR(addrStr) + setTunIP(clt.iface, ip, subnet) + if clt.cfg.FixMSS { + fixMSS(clt.iface.Name(), false) + } + res := atomic.CompareAndSwapInt32(&clt.state, HOP_STAT_HANDSHAKE, HOP_STAT_WORKING) + if !res { + logger.Error("Client state not expected: %d", clt.state) + } + logger.Info("Session Initialized") + clt.handshakeDone <- 1 + } + + logger.Debug("Handshake Ack to Server") + clt.toServer(u, HOP_FLG_HSH|HOP_FLG_ACK, clt.sid[:], true) } // handle handshake fail func (clt *HopClient) handleHandshakeError(u *net.UDPConn, hp *HopPacket) { - clt.handshakeDone <- 0 + clt.handshakeDone <- 0 } // handle data packet func (clt *HopClient) handleDataPacket(u *net.UDPConn, hp *HopPacket) { - // logger.Debug("New HopPacket Seq: %d", packet.Seq) - clt.recvBuf.Push(hp) + // logger.Debug("New HopPacket Seq: %d", packet.Seq) + clt.recvBuf.Push(hp) } // handle finish ack func (clt *HopClient) handleFinishAck(u *net.UDPConn, hp *HopPacket) { - clt.finishAck <- byte(1) + clt.finishAck <- byte(1) } func (clt *HopClient) cleanUp() { - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) - <-c - logger.Info("Cleaning Up") - - if clt.cfg.Redirect_gateway { - delRoute("0.0.0.0/1") - delRoute("128.0.0.0/1") - } - if clt.cfg.FixMSS { - clearMSS(clt.iface.Name(), false) - } - - timeout := time.After(3 * time.Second) - if clt.state != HOP_STAT_INIT { - clt.finishSession() - } - - select { - case <-clt.finishAck: - logger.Info("Finish Acknowledged") - case <-timeout: - logger.Info("Timeout, give up") - } - - for _, dest := range clt.routes { - delRoute(dest) - } - - os.Exit(0) + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) + <-c + logger.Info("Cleaning Up") + + if clt.cfg.Redirect_gateway { + delRoute("0.0.0.0/1") + delRoute("128.0.0.0/1") + } + if clt.cfg.FixMSS { + clearMSS(clt.iface.Name(), false) + } + + timeout := time.After(3 * time.Second) + if clt.state != HOP_STAT_INIT { + clt.finishSession() + } + + select { + case <-clt.finishAck: + logger.Info("Finish Acknowledged") + case <-timeout: + logger.Info("Timeout, give up") + } + + for _, dest := range clt.routes { + delRoute(dest) + } + + os.Exit(0) } diff --git a/hop/common.go b/hop/common.go index 5fa10d4..1e61831 100644 --- a/hop/common.go +++ b/hop/common.go @@ -19,7 +19,7 @@ package hop import ( - "../logging" + "../logging" ) var logger = logging.GetLogger() @@ -27,5 +27,5 @@ var logger = logging.GetLogger() var MTU = 1400 const ( - IFACE_BUFSIZE = 2000 + IFACE_BUFSIZE = 2000 ) diff --git a/hop/config.go b/hop/config.go index 77684b0..eb5cddc 100644 --- a/hop/config.go +++ b/hop/config.go @@ -1,101 +1,101 @@ package hop import ( - "bufio" - "code.google.com/p/gcfg" - "errors" - "fmt" - "io" - "regexp" - "strconv" - "strings" + "bufio" + "code.google.com/p/gcfg" + "errors" + "fmt" + "io" + "regexp" + "strconv" + "strings" ) // Server Config type HopServerConfig struct { - HopStart int - HopEnd int - ListenAddr string - Addr string - DNS []string - PeerTimeout int - MTU int - Key string - FixMSS bool - MorphMethod string - RouteFile string - RouteList map[uint32][][5]byte + HopStart int + HopEnd int + ListenAddr string + Addr string + DNS []string + PeerTimeout int + MTU int + Key string + FixMSS bool + MorphMethod string + RouteFile string + RouteList map[uint32][][5]byte } // Client Config type HopClientConfig struct { - Server string - HopStart int - HopEnd int - Key string - MTU int - FixMSS bool - Local bool - MorphMethod string - Redirect_gateway bool - Net_gateway []string + Server string + HopStart int + HopEnd int + Key string + MTU int + FixMSS bool + Local bool + MorphMethod string + Redirect_gateway bool + Net_gateway []string } type HopConfig struct { - Default struct { - Mode string - } - Server HopServerConfig - Client HopClientConfig + Default struct { + Mode string + } + Server HopServerConfig + Client HopClientConfig } func ParseHopConfig(filename string) (interface{}, error) { - cfg := new(HopConfig) - err := gcfg.ReadFileInto(cfg, filename) - if err != nil { - return nil, err - } - switch cfg.Default.Mode { - case "server": - return cfg.Server, nil - case "client": - return cfg.Client, nil - default: - return nil, errors.New("Wrong mode") - } + cfg := new(HopConfig) + err := gcfg.ReadFileInto(cfg, filename) + if err != nil { + return nil, err + } + switch cfg.Default.Mode { + case "server": + return cfg.Server, nil + case "client": + return cfg.Client, nil + default: + return nil, errors.New("Wrong mode") + } } func (cfg *HopServerConfig) RouteConfig(r io.Reader) { - regCM := regexp.MustCompile(`#.*`) - regIP := regexp.MustCompile(`(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)`) - regGM := regexp.MustCompile(`\[\s*(\d+)\s*\]`) - key := uint32(0) - ip := [5]byte{} - cfg.RouteList = make(map[uint32][][5]byte) + regCM := regexp.MustCompile(`#.*`) + regIP := regexp.MustCompile(`(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)`) + regGM := regexp.MustCompile(`\[\s*(\d+)\s*\]`) + key := uint32(0) + ip := [5]byte{} + cfg.RouteList = make(map[uint32][][5]byte) - bf := bufio.NewReader(r) - for { - if line, err := bf.ReadString('\n'); err == nil { - if line = regCM.ReplaceAllString(line, ""); len(strings.TrimSpace(line)) < 3 { - continue - } - if ips := regIP.FindStringSubmatch(line); len(ips) == 6 { - for k, ipt := range ips[1:] { - v, _ := strconv.Atoi(ipt) - ip[k] = byte(v) - if k == 5 && uint8(ip[k]) > 32 { - ip[k] = 32 - } - } - cfg.RouteList[key] = append(cfg.RouteList[key], ip) - } else if gms := regGM.FindStringSubmatch(line); len(gms) == 2 { - v, _ := strconv.Atoi(gms[1]) - key = uint32(v) - } - } else { - break - } - } - logger.Debug(fmt.Sprintf("Route list : %v", cfg.RouteList)) + bf := bufio.NewReader(r) + for { + if line, err := bf.ReadString('\n'); err == nil { + if line = regCM.ReplaceAllString(line, ""); len(strings.TrimSpace(line)) < 3 { + continue + } + if ips := regIP.FindStringSubmatch(line); len(ips) == 6 { + for k, ipt := range ips[1:] { + v, _ := strconv.Atoi(ipt) + ip[k] = byte(v) + if k == 5 && uint8(ip[k]) > 32 { + ip[k] = 32 + } + } + cfg.RouteList[key] = append(cfg.RouteList[key], ip) + } else if gms := regGM.FindStringSubmatch(line); len(gms) == 2 { + v, _ := strconv.Atoi(gms[1]) + key = uint32(v) + } + } else { + break + } + } + logger.Debug(fmt.Sprintf("Route list : %v", cfg.RouteList)) } diff --git a/hop/iface.go b/hop/iface.go index 5084c8e..3f70a23 100644 --- a/hop/iface.go +++ b/hop/iface.go @@ -21,16 +21,16 @@ package hop import ( - "bufio" - "bytes" - "errors" - "fmt" - "github.com/bigeagle/water" - "net" - "os" - "os/exec" - "strconv" - "strings" + "bufio" + "bytes" + "errors" + "fmt" + "github.com/bigeagle/water" + "net" + "os" + "os/exec" + "strconv" + "strings" ) var invalidAddr = errors.New("Invalid device ip address") @@ -39,235 +39,235 @@ var tun_peer net.IP func newTun(name string) (iface *water.Interface, err error) { - iface, err = water.NewTUN(name) - if err != nil { - return nil, err - } - logger.Info("interface %v created", iface.Name()) - - sargs := fmt.Sprintf("link set dev %s up mtu %d qlen 100", iface.Name(), MTU) - args := strings.Split(sargs, " ") - cmd := texec("ip", args...) - err = cmd.Run() - if err != nil { - return nil, err - } - - return iface, nil + iface, err = water.NewTUN(name) + if err != nil { + return nil, err + } + logger.Info("interface %v created", iface.Name()) + + sargs := fmt.Sprintf("link set dev %s up mtu %d qlen 100", iface.Name(), MTU) + args := strings.Split(sargs, " ") + cmd := texec("ip", args...) + err = cmd.Run() + if err != nil { + return nil, err + } + + return iface, nil } func setTunIP(iface *water.Interface, ip net.IP, subnet *net.IPNet) (err error) { - ip = ip.To4() - logger.Debug("%v", ip) - if ip[3]%2 == 0 { - return invalidAddr - } - - peer := net.IP(make([]byte, 4)) - copy([]byte(peer), []byte(ip)) - peer[3]++ - tun_peer = peer - - sargs := fmt.Sprintf("addr add dev %s local %s peer %s", iface.Name(), ip, peer) - args := strings.Split(sargs, " ") - cmd := texec("ip", args...) - err = cmd.Run() - if err != nil { - return err - } - - sargs = fmt.Sprintf("route add %s via %s dev %s", subnet, peer, iface.Name()) - args = strings.Split(sargs, " ") - cmd = texec("ip", args...) - err = cmd.Run() - return err + ip = ip.To4() + logger.Debug("%v", ip) + if ip[3]%2 == 0 { + return invalidAddr + } + + peer := net.IP(make([]byte, 4)) + copy([]byte(peer), []byte(ip)) + peer[3]++ + tun_peer = peer + + sargs := fmt.Sprintf("addr add dev %s local %s peer %s", iface.Name(), ip, peer) + args := strings.Split(sargs, " ") + cmd := texec("ip", args...) + err = cmd.Run() + if err != nil { + return err + } + + sargs = fmt.Sprintf("route add %s via %s dev %s", subnet, peer, iface.Name()) + args = strings.Split(sargs, " ") + cmd = texec("ip", args...) + err = cmd.Run() + return err } // return net gateway (default route) and nic func getNetGateway() (gw, dev string, err error) { - file, err := os.Open("/proc/net/route") - if err != nil { - return "", "", err - } - - defer file.Close() - rd := bufio.NewReader(file) - - s2byte := func(s string) byte { - b, _ := strconv.ParseUint(s, 16, 8) - return byte(b) - } - - for { - line, isPrefix, err := rd.ReadLine() - - if err != nil { - logger.Error(err.Error()) - return "", "", err - } - if isPrefix { - return "", "", errors.New("Line Too Long!") - } - buf := bytes.NewBuffer(line) - scanner := bufio.NewScanner(buf) - scanner.Split(bufio.ScanWords) - tokens := make([]string, 0, 8) - - for scanner.Scan() { - tokens = append(tokens, scanner.Text()) - } - - iface := tokens[0] - dest := tokens[1] - gw := tokens[2] - mask := tokens[7] - - if bytes.Equal([]byte(dest), []byte("00000000")) && - bytes.Equal([]byte(mask), []byte("00000000")) { - a := s2byte(gw[6:8]) - b := s2byte(gw[4:6]) - c := s2byte(gw[2:4]) - d := s2byte(gw[0:2]) - - ip := net.IPv4(a, b, c, d) - - return ip.String(), iface, nil - } - - } - return "", "", errors.New("No default gateway found") + file, err := os.Open("/proc/net/route") + if err != nil { + return "", "", err + } + + defer file.Close() + rd := bufio.NewReader(file) + + s2byte := func(s string) byte { + b, _ := strconv.ParseUint(s, 16, 8) + return byte(b) + } + + for { + line, isPrefix, err := rd.ReadLine() + + if err != nil { + logger.Error(err.Error()) + return "", "", err + } + if isPrefix { + return "", "", errors.New("Line Too Long!") + } + buf := bytes.NewBuffer(line) + scanner := bufio.NewScanner(buf) + scanner.Split(bufio.ScanWords) + tokens := make([]string, 0, 8) + + for scanner.Scan() { + tokens = append(tokens, scanner.Text()) + } + + iface := tokens[0] + dest := tokens[1] + gw := tokens[2] + mask := tokens[7] + + if bytes.Equal([]byte(dest), []byte("00000000")) && + bytes.Equal([]byte(mask), []byte("00000000")) { + a := s2byte(gw[6:8]) + b := s2byte(gw[4:6]) + c := s2byte(gw[2:4]) + d := s2byte(gw[0:2]) + + ip := net.IPv4(a, b, c, d) + + return ip.String(), iface, nil + } + + } + return "", "", errors.New("No default gateway found") } // add route func addRoute(dest, nextHop, iface string) { - scmd := fmt.Sprintf("ip -4 r a %s via %s dev %s", dest, nextHop, iface) - cmd := texec("bash", "-c", scmd) - err := cmd.Run() + scmd := fmt.Sprintf("ip -4 r a %s via %s dev %s", dest, nextHop, iface) + cmd := texec("bash", "-c", scmd) + err := cmd.Run() - if err != nil { - logger.Warning(err.Error()) - } + if err != nil { + logger.Warning(err.Error()) + } } // delete route func delRoute(dest string) { - sargs := fmt.Sprintf("-4 route del %s", dest) - args := strings.Split(sargs, " ") - cmd := texec("ip", args...) - err := cmd.Run() - - if err != nil { - logger.Warning(err.Error()) - } + sargs := fmt.Sprintf("-4 route del %s", dest) + args := strings.Split(sargs, " ") + cmd := texec("ip", args...) + err := cmd.Run() + + if err != nil { + logger.Warning(err.Error()) + } } // redirect default gateway func redirectGateway(iface, gw string) error { - subnets := []string{"0.0.0.0/1", "128.0.0.0/1"} - logger.Debug("Redirecting Gateway") - for _, subnet := range subnets { - sargs := fmt.Sprintf("-4 route add %s via %s dev %s", subnet, gw, iface) - args := strings.Split(sargs, " ") - cmd := texec("ip", args...) - err := cmd.Run() - - if err != nil { - return err - } - } - return nil + subnets := []string{"0.0.0.0/1", "128.0.0.0/1"} + logger.Debug("Redirecting Gateway") + for _, subnet := range subnets { + sargs := fmt.Sprintf("-4 route add %s via %s dev %s", subnet, gw, iface) + args := strings.Split(sargs, " ") + cmd := texec("ip", args...) + err := cmd.Run() + + if err != nil { + return err + } + } + return nil } // redirect ports to one func redirectPort(from, to string) error { - //iptables -t nat -A PREROUTING -p udp -m udp --dport 40000:41000 -j REDIRECT --to-ports 1234 - logger.Debug("Port Redirecting") - sargs := fmt.Sprintf("-t nat -A PREROUTING -p udp -m udp --dport %s -j REDIRECT --to-ports %s", from, to) - args := strings.Split(sargs, " ") - cmd := texec("iptables", args...) - err := cmd.Run() - - if err != nil { - return err - } - cmd = texec("ip6tables", args...) - err = cmd.Run() - - if err != nil { - return err - } - return nil + //iptables -t nat -A PREROUTING -p udp -m udp --dport 40000:41000 -j REDIRECT --to-ports 1234 + logger.Debug("Port Redirecting") + sargs := fmt.Sprintf("-t nat -A PREROUTING -p udp -m udp --dport %s -j REDIRECT --to-ports %s", from, to) + args := strings.Split(sargs, " ") + cmd := texec("iptables", args...) + err := cmd.Run() + + if err != nil { + return err + } + cmd = texec("ip6tables", args...) + err = cmd.Run() + + if err != nil { + return err + } + return nil } // undo redirect ports func unredirectPort(from, to string) error { - //iptables -t nat -D PREROUTING -p udp -m udp --dport 40000:41000 -j REDIRECT --to-ports 1234 - logger.Debug("Clear Port Redirecting") - sargs := fmt.Sprintf("-t nat -D PREROUTING -p udp -m udp --dport %s -j REDIRECT --to-ports %s", from, to) - args := strings.Split(sargs, " ") - cmd := texec("iptables", args...) - err := cmd.Run() - - if err != nil { - return err - } - cmd = texec("ip6tables", args...) - err = cmd.Run() - - if err != nil { - return err - } - return nil + //iptables -t nat -D PREROUTING -p udp -m udp --dport 40000:41000 -j REDIRECT --to-ports 1234 + logger.Debug("Clear Port Redirecting") + sargs := fmt.Sprintf("-t nat -D PREROUTING -p udp -m udp --dport %s -j REDIRECT --to-ports %s", from, to) + args := strings.Split(sargs, " ") + cmd := texec("iptables", args...) + err := cmd.Run() + + if err != nil { + return err + } + cmd = texec("ip6tables", args...) + err = cmd.Run() + + if err != nil { + return err + } + return nil } func fixMSS(iface string, is_server bool) error { - mss := MTU - 40 - logger.Debug("Fix MSS with iptables to %d", mss) - io := "o" - if is_server { - io = "i" - } - - sargs := fmt.Sprintf("-I FORWARD -%s %s -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss %d", io, iface, mss) - args := strings.Split(sargs, " ") - cmd := texec("iptables", args...) - err := cmd.Run() - - if err != nil { - return err - } - return nil + mss := MTU - 40 + logger.Debug("Fix MSS with iptables to %d", mss) + io := "o" + if is_server { + io = "i" + } + + sargs := fmt.Sprintf("-I FORWARD -%s %s -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss %d", io, iface, mss) + args := strings.Split(sargs, " ") + cmd := texec("iptables", args...) + err := cmd.Run() + + if err != nil { + return err + } + return nil } func clearMSS(iface string, is_server bool) error { - mss := MTU - 40 - logger.Debug("Clean MSS fix") - io := "o" + mss := MTU - 40 + logger.Debug("Clean MSS fix") + io := "o" - if is_server { - io = "i" - } - sargs := fmt.Sprintf("-D FORWARD -%s %s -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss %d", io, iface, mss) + if is_server { + io = "i" + } + sargs := fmt.Sprintf("-D FORWARD -%s %s -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss %d", io, iface, mss) - args := strings.Split(sargs, " ") - cmd := texec("iptables", args...) - err := cmd.Run() + args := strings.Split(sargs, " ") + cmd := texec("iptables", args...) + err := cmd.Run() - if err != nil { - return err - } + if err != nil { + return err + } - return nil + return nil } func texec(name string, arg ...string) *exec.Cmd { - out := "EXEC:" + name - for _, s := range arg { - out += " " + s - } - logger.Debug(out) - return exec.Command(name, arg...) + out := "EXEC:" + name + for _, s := range arg { + out += " " + s + } + logger.Debug(out) + return exec.Command(name, arg...) } diff --git a/hop/ippool.go b/hop/ippool.go index b3bc24d..fd2651b 100644 --- a/hop/ippool.go +++ b/hop/ippool.go @@ -1,49 +1,49 @@ package hop import ( - "encoding/binary" - "errors" - "net" - "sync/atomic" + "encoding/binary" + "errors" + "net" + "sync/atomic" ) type hopIPPool struct { - subnet *net.IPNet - pool []int32 + subnet *net.IPNet + pool []int32 } var poolFull = errors.New("IP Pool Full") func (p *hopIPPool) next() (*net.IPNet, error) { - if len(p.pool) == 0 { - maskint := binary.BigEndian.Uint32(p.subnet.Mask) - maskint = ^maskint & 0xffff //最长支持 65535 IP - p.pool = make([]int32, maskint) - } - for i := 3; i < len(p.pool); i++ { - lB := i & 0xff - if lB > 2 && lB < 255 && atomic.CompareAndSwapInt32(&p.pool[i], 0, 1) { - ipint := binary.BigEndian.Uint32(p.subnet.IP.To4()) + uint32(i) - ipnet := &net.IPNet{ - make([]byte, 4), - make([]byte, 4), - } - binary.BigEndian.PutUint32(ipnet.IP, ipint) - copy([]byte(ipnet.Mask), []byte(p.subnet.Mask)) - return ipnet, nil - } - } - return nil, poolFull + if len(p.pool) == 0 { + maskint := binary.BigEndian.Uint32(p.subnet.Mask) + maskint = ^maskint & 0xffff //最长支持 65535 IP + p.pool = make([]int32, maskint) + } + for i := 3; i < len(p.pool); i++ { + lB := i & 0xff + if lB > 2 && lB < 255 && atomic.CompareAndSwapInt32(&p.pool[i], 0, 1) { + ipint := binary.BigEndian.Uint32(p.subnet.IP.To4()) + uint32(i) + ipnet := &net.IPNet{ + make([]byte, 4), + make([]byte, 4), + } + binary.BigEndian.PutUint32(ipnet.IP, ipint) + copy([]byte(ipnet.Mask), []byte(p.subnet.Mask)) + return ipnet, nil + } + } + return nil, poolFull } func (p *hopIPPool) relase(ip net.IP) { - defer func() { - if err := recover(); err != nil { - logger.Error("%v", err) - } - }() - logger.Debug("releasing ip: %v", ip) + defer func() { + if err := recover(); err != nil { + logger.Error("%v", err) + } + }() + logger.Debug("releasing ip: %v", ip) - i := binary.BigEndian.Uint32(ip.To4()) & uint32(len(p.pool)) - p.pool[i] = 0 + i := binary.BigEndian.Uint32(ip.To4()) & uint32(len(p.pool)) + p.pool[i] = 0 } diff --git a/hop/protocol.go b/hop/protocol.go index eb86bb6..a034c69 100644 --- a/hop/protocol.go +++ b/hop/protocol.go @@ -21,253 +21,253 @@ package hop import ( - "bytes" - "crypto/rand" - "encoding/binary" - "errors" - "fmt" - "net" - "strings" - "sync" - "sync/atomic" - "time" + "bytes" + "crypto/rand" + "encoding/binary" + "errors" + "fmt" + "net" + "strings" + "sync" + "sync/atomic" + "time" ) const ( - HOP_REQ uint8 = 0x20 - HOP_ACK uint8 = 0xAC - HOP_DAT uint8 = 0xDA + HOP_REQ uint8 = 0x20 + HOP_ACK uint8 = 0xAC + HOP_DAT uint8 = 0xDA - HOP_FLG_PSH byte = 0x80 // port knocking and heartbeat - HOP_FLG_HSH byte = 0x40 // handshaking - HOP_FLG_FIN byte = 0x20 // finish session - HOP_FLG_MFR byte = 0x08 // more fragments - HOP_FLG_ACK byte = 0x04 // acknowledge - HOP_FLG_DAT byte = 0x00 // acknowledge + HOP_FLG_PSH byte = 0x80 // port knocking and heartbeat + HOP_FLG_HSH byte = 0x40 // handshaking + HOP_FLG_FIN byte = 0x20 // finish session + HOP_FLG_MFR byte = 0x08 // more fragments + HOP_FLG_ACK byte = 0x04 // acknowledge + HOP_FLG_DAT byte = 0x00 // acknowledge - HOP_STAT_INIT int32 = iota // initing - HOP_STAT_HANDSHAKE // handeshaking - HOP_STAT_WORKING // working - HOP_STAT_FIN // finishing + HOP_STAT_INIT int32 = iota // initing + HOP_STAT_HANDSHAKE // handeshaking + HOP_STAT_WORKING // working + HOP_STAT_FIN // finishing - HOP_HDR_LEN int = 16 + HOP_HDR_LEN int = 16 - DAT_CIPHER bool = true + DAT_CIPHER bool = true ) type hopPacketHeader struct { - Flag byte - Seq uint32 - Plen uint16 - FragPrefix uint16 - Frag uint8 - Sid uint32 - Dlen uint16 + Flag byte + Seq uint32 + Plen uint16 + FragPrefix uint16 + Frag uint8 + Sid uint32 + Dlen uint16 } func (p hopPacketHeader) String() string { - flag := make([]string, 0, 8) - if (p.Flag^HOP_FLG_MFR == 0) || (p.Flag == 0) { - flag = append(flag, "DAT") - } - if p.Flag&HOP_FLG_PSH != 0 { - flag = append(flag, "PSH") - } - if p.Flag&HOP_FLG_HSH != 0 { - flag = append(flag, "HSH") - } - if p.Flag&HOP_FLG_FIN != 0 { - flag = append(flag, "FIN") - } - if p.Flag&HOP_FLG_ACK != 0 { - flag = append(flag, "ACK") - } - if p.Flag&HOP_FLG_MFR != 0 { - flag = append(flag, "MFR") - } - - sflag := strings.Join(flag, " | ") - return fmt.Sprintf( - "{Flag: %s, Seq: %d, Plen: %d, Prefix: %d, Frag: %d, Dlen: %d}", - sflag, p.Seq, p.Plen, p.FragPrefix, p.Frag, p.Dlen, - ) + flag := make([]string, 0, 8) + if (p.Flag^HOP_FLG_MFR == 0) || (p.Flag == 0) { + flag = append(flag, "DAT") + } + if p.Flag&HOP_FLG_PSH != 0 { + flag = append(flag, "PSH") + } + if p.Flag&HOP_FLG_HSH != 0 { + flag = append(flag, "HSH") + } + if p.Flag&HOP_FLG_FIN != 0 { + flag = append(flag, "FIN") + } + if p.Flag&HOP_FLG_ACK != 0 { + flag = append(flag, "ACK") + } + if p.Flag&HOP_FLG_MFR != 0 { + flag = append(flag, "MFR") + } + + sflag := strings.Join(flag, " | ") + return fmt.Sprintf( + "{Flag: %s, Seq: %d, Plen: %d, Prefix: %d, Frag: %d, Dlen: %d}", + sflag, p.Seq, p.Plen, p.FragPrefix, p.Frag, p.Dlen, + ) } type HopPacket struct { - hopPacketHeader - payload []byte - noise []byte - buf []byte + hopPacketHeader + payload []byte + noise []byte + buf []byte } var cipher *hopCipher = nil func (p *HopPacket) Pack() []byte { - p.Dlen = uint16(len(p.payload)) - var buf *bytes.Buffer - if p.buf != nil { - // reduce memcopy - buf = bytes.NewBuffer(p.buf[:0]) - // write packet header to p.buf header - binary.Write(buf, binary.BigEndian, p.hopPacketHeader) - - } else { - buf = bytes.NewBuffer(make([]byte, 0, p.Size())) - binary.Write(buf, binary.BigEndian, p.hopPacketHeader) - buf.Write(p.payload) - buf.Write(p.noise) - p.buf = buf.Bytes() - } - - if cipher == nil { - return p.buf //暂时不用加密 - } - return cipher.encrypt(p.buf) // 数据加密 + p.Dlen = uint16(len(p.payload)) + var buf *bytes.Buffer + if p.buf != nil { + // reduce memcopy + buf = bytes.NewBuffer(p.buf[:0]) + // write packet header to p.buf header + binary.Write(buf, binary.BigEndian, p.hopPacketHeader) + + } else { + buf = bytes.NewBuffer(make([]byte, 0, p.Size())) + binary.Write(buf, binary.BigEndian, p.hopPacketHeader) + buf.Write(p.payload) + buf.Write(p.noise) + p.buf = buf.Bytes() + } + + if cipher == nil { + return p.buf //暂时不用加密 + } + return cipher.encrypt(p.buf) // 数据加密 } func (p *HopPacket) Size() int { - return HOP_HDR_LEN + len(p.payload) + len(p.noise) + return HOP_HDR_LEN + len(p.payload) + len(p.noise) } func (p *HopPacket) setPayload(d []byte) { - p.payload = d - p.Dlen = uint16(len(p.payload)) + p.payload = d + p.Dlen = uint16(len(p.payload)) } func (p *HopPacket) addNoise(n int) { - if p.buf != nil { - s := HOP_HDR_LEN + len(p.payload) - p.noise = p.buf[s:len(p.buf)] - } else { - p.noise = make([]byte, n) - } - rand.Read(p.noise) + if p.buf != nil { + s := HOP_HDR_LEN + len(p.payload) + p.noise = p.buf[s:len(p.buf)] + } else { + p.noise = make([]byte, n) + } + rand.Read(p.noise) } func (p *HopPacket) setSid(sid [4]byte) { - p.Sid = binary.BigEndian.Uint32(sid[:]) + p.Sid = binary.BigEndian.Uint32(sid[:]) } func (p *HopPacket) String() string { - return fmt.Sprintf( - "{%v, Payload: %v, Noise: %v}", - p.hopPacketHeader, p.payload, p.noise, - ) + return fmt.Sprintf( + "{%v, Payload: %v, Noise: %v}", + p.hopPacketHeader, p.payload, p.noise, + ) } func unpackHopPacket(b []byte) (*HopPacket, error) { - //不加密数据 - if cipher == nil { - logger.Debug("no ciph!") - buf := bytes.NewBuffer(b) - p := new(HopPacket) - err := binary.Read(buf, binary.BigEndian, &p.hopPacketHeader) - if err == nil { - p.payload = make([]byte, p.Dlen) - if _, err = buf.Read(p.payload); err == nil { - return p, nil - } - } - return nil, err - } - - // 加密数据 - iv := b[:cipherBlockSize] - ctext := b[cipherBlockSize:] - if frame := cipher.decrypt(iv, ctext); frame != nil { - buf := bytes.NewBuffer(frame) - - p := new(HopPacket) - binary.Read(buf, binary.BigEndian, &p.hopPacketHeader) - p.payload = make([]byte, p.Dlen) - buf.Read(p.payload) - return p, nil - } else { - return nil, errors.New("Decrypt Packet Error") - } + //不加密数据 + if cipher == nil { + logger.Debug("no ciph!") + buf := bytes.NewBuffer(b) + p := new(HopPacket) + err := binary.Read(buf, binary.BigEndian, &p.hopPacketHeader) + if err == nil { + p.payload = make([]byte, p.Dlen) + if _, err = buf.Read(p.payload); err == nil { + return p, nil + } + } + return nil, err + } + + // 加密数据 + iv := b[:cipherBlockSize] + ctext := b[cipherBlockSize:] + if frame := cipher.decrypt(iv, ctext); frame != nil { + buf := bytes.NewBuffer(frame) + + p := new(HopPacket) + binary.Read(buf, binary.BigEndian, &p.hopPacketHeader) + p.payload = make([]byte, p.Dlen) + buf.Read(p.payload) + return p, nil + } else { + return nil, errors.New("Decrypt Packet Error") + } } func udpAddrHash(a *net.UDPAddr) [6]byte { - var b [6]byte - copy(b[:4], []byte(a.IP)[:4]) - p := uint16(a.Port) - b[4] = byte((p >> 8) & 0xFF) - b[5] = byte(p & 0xFF) - return b + var b [6]byte + copy(b[:4], []byte(a.IP)[:4]) + p := uint16(a.Port) + b[4] = byte((p >> 8) & 0xFF) + b[5] = byte(p & 0xFF) + return b } type hUDPAddr struct { - u *net.UDPAddr - hash [6]byte + u *net.UDPAddr + hash [6]byte } func newhUDPAddr(a *net.UDPAddr) *hUDPAddr { - return &hUDPAddr{a, udpAddrHash(a)} + return &hUDPAddr{a, udpAddrHash(a)} } // gohop Peer is a record of a peer's available UDP addrs type HopPeer struct { - id uint64 - gmid uint32 //game id - uid uint32 //user id - lastConnTime time.Time - bytes_up uint32 //user update bytes - bytes_down uint32 //user download bytes - ip net.IP - addrs map[[6]byte]int - _addrs_lst []*hUDPAddr // i know it's ugly! - seq uint32 - state int32 - hsDone chan byte - recvBuffer *hopPacketBuffer - srv *HopServer - _lock sync.RWMutex + id uint64 + gmid uint32 //game id + uid uint32 //user id + lastConnTime time.Time + bytes_up uint32 //user update bytes + bytes_down uint32 //user download bytes + ip net.IP + addrs map[[6]byte]int + _addrs_lst []*hUDPAddr // i know it's ugly! + seq uint32 + state int32 + hsDone chan byte + recvBuffer *hopPacketBuffer + srv *HopServer + _lock sync.RWMutex } func newHopPeer(id uint64, srv *HopServer, addr *net.UDPAddr, idx int) *HopPeer { - hp := new(HopPeer) - hp.id = id - hp.bytes_up = 0 - hp.bytes_down = 0 - hp._addrs_lst = make([]*hUDPAddr, 0) - hp.addrs = make(map[[6]byte]int) - hp.state = HOP_STAT_INIT - hp.seq = 0 - hp.srv = srv - hp.recvBuffer = newHopPacketBuffer(srv.toIface, bufferTimeout/2) - // logger.Debug("%v, %v", hp.recvBuffer, hp.srv) - - a := newhUDPAddr(addr) - hp._addrs_lst = append(hp._addrs_lst, a) - hp.addrs[a.hash] = idx - - return hp + hp := new(HopPeer) + hp.id = id + hp.bytes_up = 0 + hp.bytes_down = 0 + hp._addrs_lst = make([]*hUDPAddr, 0) + hp.addrs = make(map[[6]byte]int) + hp.state = HOP_STAT_INIT + hp.seq = 0 + hp.srv = srv + hp.recvBuffer = newHopPacketBuffer(srv.toIface, bufferTimeout/2) + // logger.Debug("%v, %v", hp.recvBuffer, hp.srv) + + a := newhUDPAddr(addr) + hp._addrs_lst = append(hp._addrs_lst, a) + hp.addrs[a.hash] = idx + + return hp } func (h *HopPeer) Seq() uint32 { - return atomic.AddUint32(&h.seq, 1) + return atomic.AddUint32(&h.seq, 1) } func (h *HopPeer) addr() (*net.UDPAddr, int, bool) { - defer h._lock.RUnlock() - h._lock.RLock() - addr := randAddr(h._addrs_lst) - // addr := h._addrs_lst[0] - idx, ok := h.addrs[addr.hash] + defer h._lock.RUnlock() + h._lock.RLock() + addr := randAddr(h._addrs_lst) + // addr := h._addrs_lst[0] + idx, ok := h.addrs[addr.hash] - return addr.u, idx, ok + return addr.u, idx, ok } func (h *HopPeer) insertAddr(addr *net.UDPAddr, idx int) { - defer h._lock.Unlock() - h._lock.Lock() - a := newhUDPAddr(addr) - if _, found := h.addrs[a.hash]; !found { - h.addrs[a.hash] = idx - h._addrs_lst = append(h._addrs_lst, a) - //logger.Info("%v %d", addr, len(h._addrs_lst)) - } + defer h._lock.Unlock() + h._lock.Lock() + a := newhUDPAddr(addr) + if _, found := h.addrs[a.hash]; !found { + h.addrs[a.hash] = idx + h._addrs_lst = append(h._addrs_lst, a) + //logger.Info("%v %d", addr, len(h._addrs_lst)) + } } diff --git a/hop/server.go b/hop/server.go index 99bd101..ba47674 100644 --- a/hop/server.go +++ b/hop/server.go @@ -19,548 +19,548 @@ package hop import ( - "bytes" - "encoding/binary" - "fmt" - "github.com/bigeagle/water" - "github.com/bigeagle/water/waterutil" - "net" - "os" - "os/signal" - "sync" - "sync/atomic" - "syscall" - "time" + "bytes" + "encoding/binary" + "fmt" + "github.com/bigeagle/water" + "github.com/bigeagle/water/waterutil" + "net" + "os" + "os/signal" + "sync" + "sync/atomic" + "syscall" + "time" ) // a udpPacket type udpPacket struct { - // client's addr - addr *net.UDPAddr - // data - data []byte - // channel - channel int + // client's addr + addr *net.UDPAddr + // data + data []byte + // channel + channel int } type HopServer struct { - // config - cfg *HopServerConfig - // interface - iface *water.Interface - // subnet - ipnet *net.IPNet - // IP Pool - ippool *hopIPPool - // client peers, key is the mac address, value is a HopPeer record - peers map[uint64]*HopPeer - - // channel to put in packets read from udpsocket - fromNet chan *udpPacket - // channel to put packets to send through udpsocket - toNet []chan *udpPacket - // channel to put frames read from tun/tap device - fromIface chan []byte - toIface chan *HopPacket - _lock sync.RWMutex - _chanBufSize int + // config + cfg *HopServerConfig + // interface + iface *water.Interface + // subnet + ipnet *net.IPNet + // IP Pool + ippool *hopIPPool + // client peers, key is the mac address, value is a HopPeer record + peers map[uint64]*HopPeer + + // channel to put in packets read from udpsocket + fromNet chan *udpPacket + // channel to put packets to send through udpsocket + toNet []chan *udpPacket + // channel to put frames read from tun/tap device + fromIface chan []byte + toIface chan *HopPacket + _lock sync.RWMutex + _chanBufSize int } func NewServer(cfg *HopServerConfig) error { - var err error - logger.Debug("%v", cfg) - - if len(cfg.Key) > 0 { - cipher, err = newHopCipher([]byte(cfg.Key)) - if err != nil { - return err - } - } - - if cfg.MTU != 0 { - MTU = cfg.MTU - } - - hopServer := new(HopServer) - hopServer._chanBufSize = 256 - hopServer.fromNet = make(chan *udpPacket, hopServer._chanBufSize) - hopServer.fromIface = make(chan []byte, hopServer._chanBufSize) - hopServer.toIface = make(chan *HopPacket, hopServer._chanBufSize) - hopServer.peers = make(map[uint64]*HopPeer) - hopServer.cfg = cfg - hopServer.toNet = make([]chan *udpPacket, (cfg.HopEnd - cfg.HopStart + 1)) - hopServer.ippool = new(hopIPPool) - - iface, err := newTun("") - if err != nil { - return err - } - hopServer.iface = iface - ip, subnet, err := net.ParseCIDR(cfg.Addr) - err = setTunIP(iface, ip, subnet) - if err != nil { - return err - } - hopServer.ipnet = &net.IPNet{ip, subnet.Mask} - hopServer.ippool.subnet = subnet - - if cfg.FixMSS { - fixMSS(iface.Name(), true) - } - - // traffic morpher - switch cfg.MorphMethod { - case "randsize": - m := newRandMorpher(MTU) - hopFrager = newHopFragmenter(m) - logger.Info("Using RandomSize Morpher") - default: - logger.Info("No Traffic Morphing") - } - - // forward device frames to socket and socket packets to device - go hopServer.forwardFrames() - - // go func() { - // defer hopServer.cleanUp() - // redirectPort(cfg.HopRange, cfg.Port) - // }() - go hopServer.cleanUp() - - // serve for multiple ports - for idx, port := 0, cfg.HopStart; port <= cfg.HopEnd; port++ { - go hopServer.listenAndServe(cfg.ListenAddr, fmt.Sprintf("%d", port), idx) - idx++ - } - - // peer Timeout Watcher - go hopServer.peerTimeoutWatcher() - - logger.Info("Recieving iface frames") - - // handle interface - - go func() { - for { - hp := <-hopServer.toIface - // logger.Debug("New Net packet to device") - // logger.Debug("toIface : %v", hp.payload) - _, err := iface.Write(hp.payload) - // logger.Debug("n: %d, len: %d", n, len(hp.payload)) - if err != nil { - logger.Error(err.Error()) - return - } - } - }() - - buf := make([]byte, IFACE_BUFSIZE) - for { - n, err := iface.Read(buf) - if err != nil { - return err - } - - hpbuf := make([]byte, n+HOP_HDR_LEN) - copy(hpbuf[HOP_HDR_LEN:], buf[:n]) - hopServer.fromIface <- hpbuf - } + var err error + logger.Debug("%v", cfg) + + if len(cfg.Key) > 0 { + cipher, err = newHopCipher([]byte(cfg.Key)) + if err != nil { + return err + } + } + + if cfg.MTU != 0 { + MTU = cfg.MTU + } + + hopServer := new(HopServer) + hopServer._chanBufSize = 256 + hopServer.fromNet = make(chan *udpPacket, hopServer._chanBufSize) + hopServer.fromIface = make(chan []byte, hopServer._chanBufSize) + hopServer.toIface = make(chan *HopPacket, hopServer._chanBufSize) + hopServer.peers = make(map[uint64]*HopPeer) + hopServer.cfg = cfg + hopServer.toNet = make([]chan *udpPacket, (cfg.HopEnd - cfg.HopStart + 1)) + hopServer.ippool = new(hopIPPool) + + iface, err := newTun("") + if err != nil { + return err + } + hopServer.iface = iface + ip, subnet, err := net.ParseCIDR(cfg.Addr) + err = setTunIP(iface, ip, subnet) + if err != nil { + return err + } + hopServer.ipnet = &net.IPNet{ip, subnet.Mask} + hopServer.ippool.subnet = subnet + + if cfg.FixMSS { + fixMSS(iface.Name(), true) + } + + // traffic morpher + switch cfg.MorphMethod { + case "randsize": + m := newRandMorpher(MTU) + hopFrager = newHopFragmenter(m) + logger.Info("Using RandomSize Morpher") + default: + logger.Info("No Traffic Morphing") + } + + // forward device frames to socket and socket packets to device + go hopServer.forwardFrames() + + // go func() { + // defer hopServer.cleanUp() + // redirectPort(cfg.HopRange, cfg.Port) + // }() + go hopServer.cleanUp() + + // serve for multiple ports + for idx, port := 0, cfg.HopStart; port <= cfg.HopEnd; port++ { + go hopServer.listenAndServe(cfg.ListenAddr, fmt.Sprintf("%d", port), idx) + idx++ + } + + // peer Timeout Watcher + go hopServer.peerTimeoutWatcher() + + logger.Info("Recieving iface frames") + + // handle interface + + go func() { + for { + hp := <-hopServer.toIface + // logger.Debug("New Net packet to device") + // logger.Debug("toIface : %v", hp.payload) + _, err := iface.Write(hp.payload) + // logger.Debug("n: %d, len: %d", n, len(hp.payload)) + if err != nil { + logger.Error(err.Error()) + return + } + } + }() + + buf := make([]byte, IFACE_BUFSIZE) + for { + n, err := iface.Read(buf) + if err != nil { + return err + } + + hpbuf := make([]byte, n+HOP_HDR_LEN) + copy(hpbuf[HOP_HDR_LEN:], buf[:n]) + hopServer.fromIface <- hpbuf + } } func (srv *HopServer) listenAndServe(addr string, port string, idx int) { - port = addr + ":" + port - udpAddr, err := net.ResolveUDPAddr("udp", port) - if err != nil { - logger.Error("Invalid port: %s", port) - return - } - udpConn, err := net.ListenUDP("udp", udpAddr) - if err != nil { - logger.Error("Failed to listen udp port %s: %s", port, err.Error()) - return - } - - toNet := make(chan *udpPacket, srv._chanBufSize) - - go func() { - defer srv._lock.Unlock() - srv._lock.Lock() - srv.toNet[idx] = toNet - // logger.Debug("Listening on port %s", port) - }() - - go func() { - for { - packet := <-toNet - // logger.Debug("index: %d, port: %s", idx, port) - // logger.Debug("toClient: %v", packet.data) - _, err := udpConn.WriteTo(packet.data, packet.addr) - if err != nil { - logger.Error("ToNet Err: %v", err) - } - } - }() - - for { - func() { - defer func() { - if _err := recover(); _err != nil { - logger.Error("ReadFromUDP failed: %v", _err) - } - }() - var plen int - packet := new(udpPacket) - packet.channel = idx - buf := make([]byte, IFACE_BUFSIZE) - // logger.Debug("Recieving packet %s", port) - plen, packet.addr, err = udpConn.ReadFromUDP(buf) - // logger.Debug("New UDP Packet from: %v", packet.addr) - - packet.data = buf[:plen] - if err != nil { - logger.Error(err.Error()) - return - } - - srv.fromNet <- packet - }() - } + port = addr + ":" + port + udpAddr, err := net.ResolveUDPAddr("udp", port) + if err != nil { + logger.Error("Invalid port: %s", port) + return + } + udpConn, err := net.ListenUDP("udp", udpAddr) + if err != nil { + logger.Error("Failed to listen udp port %s: %s", port, err.Error()) + return + } + + toNet := make(chan *udpPacket, srv._chanBufSize) + + go func() { + defer srv._lock.Unlock() + srv._lock.Lock() + srv.toNet[idx] = toNet + // logger.Debug("Listening on port %s", port) + }() + + go func() { + for { + packet := <-toNet + // logger.Debug("index: %d, port: %s", idx, port) + // logger.Debug("toClient: %v", packet.data) + _, err := udpConn.WriteTo(packet.data, packet.addr) + if err != nil { + logger.Error("ToNet Err: %v", err) + } + } + }() + + for { + func() { + defer func() { + if _err := recover(); _err != nil { + logger.Error("ReadFromUDP failed: %v", _err) + } + }() + var plen int + packet := new(udpPacket) + packet.channel = idx + buf := make([]byte, IFACE_BUFSIZE) + // logger.Debug("Recieving packet %s", port) + plen, packet.addr, err = udpConn.ReadFromUDP(buf) + // logger.Debug("New UDP Packet from: %v", packet.addr) + + packet.data = buf[:plen] + if err != nil { + logger.Error(err.Error()) + return + } + + srv.fromNet <- packet + }() + } } func (srv *HopServer) forwardFrames() { - // packet map - pktHandle := map[byte](func(*udpPacket, *HopPacket)){ - HOP_FLG_PSH: srv.handleKnock, - HOP_FLG_HSH: srv.handleHandshake, - HOP_FLG_HSH | HOP_FLG_ACK: srv.handleHandshakeAck, - HOP_FLG_DAT: srv.handleDataPacket, - HOP_FLG_DAT | HOP_FLG_MFR: srv.handleDataPacket, - HOP_FLG_FIN: srv.handleFinish, - } - - for { - select { - case pack := <-srv.fromIface: - // logger.Debug("New iface Frame") - // first byte is left for opcode - frame := pack[HOP_HDR_LEN:] - dest := waterutil.IPv4Destination(frame).To4() - mkey := ip4_uint64(dest) - - // logger.Debug("fromIfc: ip dest: %v, data:%v", dest, frame) - if hpeer, found := srv.peers[mkey]; found { - srv.bufferToClient(hpeer, pack) - } else { - // logger.Debug("fromIface : client peer with key %d not found", mkey) - } - - case packet := <-srv.fromNet: - packet.handleFunction(pktHandle) - } - } + // packet map + pktHandle := map[byte](func(*udpPacket, *HopPacket)){ + HOP_FLG_PSH: srv.handleKnock, + HOP_FLG_HSH: srv.handleHandshake, + HOP_FLG_HSH | HOP_FLG_ACK: srv.handleHandshakeAck, + HOP_FLG_DAT: srv.handleDataPacket, + HOP_FLG_DAT | HOP_FLG_MFR: srv.handleDataPacket, + HOP_FLG_FIN: srv.handleFinish, + } + + for { + select { + case pack := <-srv.fromIface: + // logger.Debug("New iface Frame") + // first byte is left for opcode + frame := pack[HOP_HDR_LEN:] + dest := waterutil.IPv4Destination(frame).To4() + mkey := ip4_uint64(dest) + + // logger.Debug("fromIfc: ip dest: %v, data:%v", dest, frame) + if hpeer, found := srv.peers[mkey]; found { + srv.bufferToClient(hpeer, pack) + } else { + // logger.Debug("fromIface : client peer with key %d not found", mkey) + } + + case packet := <-srv.fromNet: + packet.handleFunction(pktHandle) + } + } } func (packet *udpPacket) handleFunction(pktHandle map[byte](func(*udpPacket, *HopPacket))) { - defer func() { - if err := recover(); err != nil { - logger.Error("handleFunction failed: %v, packet addr:%v", err, packet.addr) - } - }() - - // logger.Debug("Receive data[%d]:%v", len(packet.data), packet.data) - - hPack, err := unpackHopPacket(packet.data) //协议包拆包 - if err == nil { - // logger.Debug("fromClient: %v", hPack.String()) - if hPack.Flag != 0 { - logger.Debug("New UDP Packet [%v] from: %v", hPack.Flag, packet.addr) - } - - if handle_func, ok := pktHandle[hPack.Flag]; ok { - handle_func(packet, hPack) //事件处理 - } else { - logger.Error("Unkown flag: %x", hPack.Flag) - } - } else { - logger.Error(err.Error()) - } + defer func() { + if err := recover(); err != nil { + logger.Error("handleFunction failed: %v, packet addr:%v", err, packet.addr) + } + }() + + // logger.Debug("Receive data[%d]:%v", len(packet.data), packet.data) + + hPack, err := unpackHopPacket(packet.data) //协议包拆包 + if err == nil { + // logger.Debug("fromClient: %v", hPack.String()) + if hPack.Flag != 0 { + logger.Debug("New UDP Packet [%v] from: %v", hPack.Flag, packet.addr) + } + + if handle_func, ok := pktHandle[hPack.Flag]; ok { + handle_func(packet, hPack) //事件处理 + } else { + logger.Error("Unkown flag: %x", hPack.Flag) + } + } else { + logger.Error(err.Error()) + } } func (srv *HopServer) toClient(peer *HopPeer, flag byte, payload []byte, noise bool) { - hp := new(HopPacket) - hp.Seq = peer.Seq() - hp.Flag = flag - hp.payload = payload - - if addr, idx, ok := peer.addr(); ok { - // logger.Debug("toClient : peer: %v", addr) - upacket := &udpPacket{addr, hp.Pack(), idx} - peer.bytes_down += uint32(len(upacket.data)) - srv.toNet[idx] <- upacket - } else { - logger.Debug("toClient : peer not found sid:%d, uid:%d, ip:%d", peer.id>>32, peer.uid, peer.ip) - } + hp := new(HopPacket) + hp.Seq = peer.Seq() + hp.Flag = flag + hp.payload = payload + + if addr, idx, ok := peer.addr(); ok { + // logger.Debug("toClient : peer: %v", addr) + upacket := &udpPacket{addr, hp.Pack(), idx} + peer.bytes_down += uint32(len(upacket.data)) + srv.toNet[idx] <- upacket + } else { + logger.Debug("toClient : peer not found sid:%d, uid:%d, ip:%d", peer.id>>32, peer.uid, peer.ip) + } } func (srv *HopServer) bufferToClient(peer *HopPeer, buf []byte) { - if hopFrager == nil { - // if no traffic morphing - hp := new(HopPacket) - hp.Flag = HOP_FLG_DAT - hp.buf = buf - hp.payload = buf[HOP_HDR_LEN:] - hp.Seq = peer.Seq() - - if addr, idx, ok := peer.addr(); ok { - // logger.Debug("bufferToClient : peer: %v", addr) - upacket := &udpPacket{addr, hp.Pack(), idx} - peer.bytes_down += uint32(len(upacket.data)) - srv.toNet[idx] <- upacket - } - } else { - // with traffic morphing - frame := buf[HOP_HDR_LEN:] - packets := hopFrager.Fragmentate(peer, frame) - for _, hp := range packets { - if addr, idx, ok := peer.addr(); ok { - upacket := &udpPacket{addr, hp.Pack(), idx} - peer.bytes_down += uint32(len(upacket.data)) - srv.toNet[idx] <- upacket - } - } - } + if hopFrager == nil { + // if no traffic morphing + hp := new(HopPacket) + hp.Flag = HOP_FLG_DAT + hp.buf = buf + hp.payload = buf[HOP_HDR_LEN:] + hp.Seq = peer.Seq() + + if addr, idx, ok := peer.addr(); ok { + // logger.Debug("bufferToClient : peer: %v", addr) + upacket := &udpPacket{addr, hp.Pack(), idx} + peer.bytes_down += uint32(len(upacket.data)) + srv.toNet[idx] <- upacket + } + } else { + // with traffic morphing + frame := buf[HOP_HDR_LEN:] + packets := hopFrager.Fragmentate(peer, frame) + for _, hp := range packets { + if addr, idx, ok := peer.addr(); ok { + upacket := &udpPacket{addr, hp.Pack(), idx} + peer.bytes_down += uint32(len(upacket.data)) + srv.toNet[idx] <- upacket + } + } + } } func (srv *HopServer) handleKnock(u *udpPacket, hp *HopPacket) { - sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) - sid = (sid << 32) & uint64(0xFFFFFFFF00000000) - hpeer, ok := srv.peers[sid] - if !ok { - hpeer = newHopPeer(sid, srv, u.addr, u.channel) - srv.peers[sid] = hpeer - } else { - hpeer.insertAddr(u.addr, u.channel) - logger.Debug("[knock] from client %v, sid:%d, uid:%d, gid:%d", u.addr, sid>>32, hpeer.uid, hpeer.gmid) - if hpeer.state == HOP_STAT_WORKING { - srv.toClient(hpeer, HOP_FLG_PSH, []byte{0}, true) - } - } - hpeer.bytes_up += uint32(len(u.data)) - hpeer.lastConnTime = time.Now() + sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) + sid = (sid << 32) & uint64(0xFFFFFFFF00000000) + hpeer, ok := srv.peers[sid] + if !ok { + hpeer = newHopPeer(sid, srv, u.addr, u.channel) + srv.peers[sid] = hpeer + } else { + hpeer.insertAddr(u.addr, u.channel) + logger.Debug("[knock] from client %v, sid:%d, uid:%d, gid:%d", u.addr, sid>>32, hpeer.uid, hpeer.gmid) + if hpeer.state == HOP_STAT_WORKING { + srv.toClient(hpeer, HOP_FLG_PSH, []byte{0}, true) + } + } + hpeer.bytes_up += uint32(len(u.data)) + hpeer.lastConnTime = time.Now() } func (srv *HopServer) handleHandshake(u *udpPacket, hp *HopPacket) { - tms := []uint32{0, 0, 0} - for i := 0; i*4+4 <= int(hp.Dlen); i++ { - tms[i] = binary.BigEndian.Uint32(hp.payload[i*4 : i*4+4]) - } - sid := uint64(tms[0]) - gmid := tms[1] - uid := tms[2] - - logger.Debug("[handshake] from client %v, sid:%d, uid:%d, gmid:%d", u.addr, sid, uid, gmid) - sid = (sid << 32) & uint64(0xFFFFFFFF00000000) - - hpeer, ok := srv.peers[sid] - if !ok { - hpeer = newHopPeer(sid, srv, u.addr, u.channel) - srv.peers[sid] = hpeer - } else { - hpeer.insertAddr(u.addr, u.channel) - } - - hpeer.gmid = gmid - hpeer.uid = uid - hpeer.bytes_up += uint32(len(u.data)) - hpeer.lastConnTime = time.Now() - - cltIP, err := srv.ippool.next() - if err != nil { - msg := fmt.Sprintf("%s", err.Error()) - srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_FIN, []byte(msg), true) - delete(srv.peers, sid) - logger.Error("Have no IP to allocation") - } else { - hpeer.ip = cltIP.IP.To4() - buf := bytes.NewBuffer(make([]byte, 0, 5)) - //set client ip - buf.Write([]byte(hpeer.ip)) - siz, _ := cltIP.Mask.Size() - // buf.Write([]byte(cltIP.Mask)) - buf.WriteByte(byte(siz)) - - //set client dns - for i := 0; i < 2; i++ { - if ip, _, err := net.ParseCIDR(srv.cfg.DNS[i]); err != nil { - buf.Write([]byte{0, 0, 0, 0, 0}) - } else { - ip = ip.To4() - buf.Write([]byte(ip)) - buf.WriteByte(0) - } - } - - //set client route - routes := srv.routeList(gmid) - for i := 0; i < len(routes) && i <= 256; i++ { - buf.Write(routes[i][:]) - } - - key := ip4_uint64(hpeer.ip) - - logger.Debug("assign address %s route; sid:%d, uid:%d, gid:%d", cltIP, hpeer.id>>32, hpeer.uid, hpeer.gmid) - srv.peers[key] = hpeer - atomic.StoreInt32(&hpeer.state, HOP_STAT_HANDSHAKE) - srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_ACK, buf.Bytes(), true) - hpeer.hsDone = make(chan byte) - go func() { - for i := 0; i < 5; i++ { - select { - case <-hpeer.hsDone: - logger.Debug("hperr.hsDone; sid:%d, uid:%d, gid:%d", hpeer.id>>32, hpeer.uid, hpeer.gmid) - // hpeer.state = HOP_STAT_WORKING - return - case <-time.After(2 * time.Second): - logger.Debug("Client Handshake Timeout; sid:%d, uid:%d, gid:%d", hpeer.id>>32, hpeer.uid, hpeer.gmid) - srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_ACK, buf.Bytes(), true) - } - } - // timeout, kick - srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_FIN, []byte{0}, true) - srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_FIN, []byte{0}, true) - srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_FIN, []byte{0}, true) - - srv.ippool.relase(hpeer.ip) - delete(srv.peers, sid) - delete(srv.peers, key) - - }() - } + tms := []uint32{0, 0, 0} + for i := 0; i*4+4 <= int(hp.Dlen); i++ { + tms[i] = binary.BigEndian.Uint32(hp.payload[i*4 : i*4+4]) + } + sid := uint64(tms[0]) + gmid := tms[1] + uid := tms[2] + + logger.Debug("[handshake] from client %v, sid:%d, uid:%d, gmid:%d", u.addr, sid, uid, gmid) + sid = (sid << 32) & uint64(0xFFFFFFFF00000000) + + hpeer, ok := srv.peers[sid] + if !ok { + hpeer = newHopPeer(sid, srv, u.addr, u.channel) + srv.peers[sid] = hpeer + } else { + hpeer.insertAddr(u.addr, u.channel) + } + + hpeer.gmid = gmid + hpeer.uid = uid + hpeer.bytes_up += uint32(len(u.data)) + hpeer.lastConnTime = time.Now() + + cltIP, err := srv.ippool.next() + if err != nil { + msg := fmt.Sprintf("%s", err.Error()) + srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_FIN, []byte(msg), true) + delete(srv.peers, sid) + logger.Error("Have no IP to allocation") + } else { + hpeer.ip = cltIP.IP.To4() + buf := bytes.NewBuffer(make([]byte, 0, 5)) + //set client ip + buf.Write([]byte(hpeer.ip)) + siz, _ := cltIP.Mask.Size() + // buf.Write([]byte(cltIP.Mask)) + buf.WriteByte(byte(siz)) + + //set client dns + for i := 0; i < 2; i++ { + if ip, _, err := net.ParseCIDR(srv.cfg.DNS[i]); err != nil { + buf.Write([]byte{0, 0, 0, 0, 0}) + } else { + ip = ip.To4() + buf.Write([]byte(ip)) + buf.WriteByte(0) + } + } + + //set client route + routes := srv.routeList(gmid) + for i := 0; i < len(routes) && i <= 256; i++ { + buf.Write(routes[i][:]) + } + + key := ip4_uint64(hpeer.ip) + + logger.Debug("assign address %s route; sid:%d, uid:%d, gid:%d", cltIP, hpeer.id>>32, hpeer.uid, hpeer.gmid) + srv.peers[key] = hpeer + atomic.StoreInt32(&hpeer.state, HOP_STAT_HANDSHAKE) + srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_ACK, buf.Bytes(), true) + hpeer.hsDone = make(chan byte) + go func() { + for i := 0; i < 5; i++ { + select { + case <-hpeer.hsDone: + logger.Debug("hperr.hsDone; sid:%d, uid:%d, gid:%d", hpeer.id>>32, hpeer.uid, hpeer.gmid) + // hpeer.state = HOP_STAT_WORKING + return + case <-time.After(2 * time.Second): + logger.Debug("Client Handshake Timeout; sid:%d, uid:%d, gid:%d", hpeer.id>>32, hpeer.uid, hpeer.gmid) + srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_ACK, buf.Bytes(), true) + } + } + // timeout, kick + srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_FIN, []byte{0}, true) + srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_FIN, []byte{0}, true) + srv.toClient(hpeer, HOP_FLG_HSH|HOP_FLG_FIN, []byte{0}, true) + + srv.ippool.relase(hpeer.ip) + delete(srv.peers, sid) + delete(srv.peers, key) + + }() + } } func (srv *HopServer) handleHandshakeAck(u *udpPacket, hp *HopPacket) { - sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) - sid = (sid << 32) & uint64(0xFFFFFFFF00000000) - hpeer, ok := srv.peers[sid] - if !ok { - return - } - hpeer.bytes_up += uint32(len(u.data)) - hpeer.lastConnTime = time.Now() - logger.Info("Client sid:%d, uid:%d, gid:%d, ip %v Connected. DHCP:%v", sid>>32, hpeer.uid, hpeer.gmid, u.addr, hpeer.ip) - - if ok = atomic.CompareAndSwapInt32(&hpeer.state, HOP_STAT_HANDSHAKE, HOP_STAT_WORKING); ok { - hpeer.hsDone <- 1 - } + sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) + sid = (sid << 32) & uint64(0xFFFFFFFF00000000) + hpeer, ok := srv.peers[sid] + if !ok { + return + } + hpeer.bytes_up += uint32(len(u.data)) + hpeer.lastConnTime = time.Now() + logger.Info("Client sid:%d, uid:%d, gid:%d, ip %v Connected. DHCP:%v", sid>>32, hpeer.uid, hpeer.gmid, u.addr, hpeer.ip) + + if ok = atomic.CompareAndSwapInt32(&hpeer.state, HOP_STAT_HANDSHAKE, HOP_STAT_WORKING); ok { + hpeer.hsDone <- 1 + } } func (srv *HopServer) handleDataPacket(u *udpPacket, hp *HopPacket) { - sid := uint64(hp.Sid) - sid = (sid << 32) & uint64(0xFFFFFFFF00000000) - - if hpeer, ok := srv.peers[sid]; ok && hpeer.state == HOP_STAT_WORKING { - // logger.Debug("n hpeer addrs: %v", len(hpeer._addrs_lst)) - // hpeer.insertAddr(u.addr, u.channel) - if ok, ip := srv.routeMatch(hpeer, hp); ok { - hpeer.lastConnTime = time.Now() - hpeer.recvBuffer.Push(hp) - } else { - logger.Info("DataPacket not routed to %v", ip) - } - hpeer.bytes_up += uint32(len(u.data)) - } else { - peer := newHopPeer(sid, srv, u.addr, u.channel) - srv.toClient(peer, HOP_FLG_FIN|HOP_FLG_ACK, []byte{0}, false) - } + sid := uint64(hp.Sid) + sid = (sid << 32) & uint64(0xFFFFFFFF00000000) + + if hpeer, ok := srv.peers[sid]; ok && hpeer.state == HOP_STAT_WORKING { + // logger.Debug("n hpeer addrs: %v", len(hpeer._addrs_lst)) + // hpeer.insertAddr(u.addr, u.channel) + if ok, ip := srv.routeMatch(hpeer, hp); ok { + hpeer.lastConnTime = time.Now() + hpeer.recvBuffer.Push(hp) + } else { + logger.Info("DataPacket not routed to %v", ip) + } + hpeer.bytes_up += uint32(len(u.data)) + } else { + peer := newHopPeer(sid, srv, u.addr, u.channel) + srv.toClient(peer, HOP_FLG_FIN|HOP_FLG_ACK, []byte{0}, false) + } } func (srv *HopServer) handleFinish(u *udpPacket, hp *HopPacket) { - sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) - logger.Info("releasing client %v, sid:%d", u.addr, sid) - sid = (sid << 32) & uint64(0xFFFFFFFF00000000) + sid := uint64(binary.BigEndian.Uint32(hp.payload[:4])) + logger.Info("releasing client %v, sid:%d", u.addr, sid) + sid = (sid << 32) & uint64(0xFFFFFFFF00000000) - srv.deletePeer(sid) + srv.deletePeer(sid) } func (srv *HopServer) deletePeer(sid uint64) { - hpeer, ok := srv.peers[sid] - if !ok { - return - } - srv.toClient(hpeer, HOP_FLG_FIN|HOP_FLG_ACK, []byte{0}, false) - key := ip4_uint64(hpeer.ip) - srv.ippool.relase(hpeer.ip) - - // log user info - if sid>>32 > 0 { - logger.Info("UserBytes sid:%d, uid:%d, gid:%d, up:%d, down:%d", hpeer.id>>32, hpeer.uid, hpeer.gmid, hpeer.bytes_up, hpeer.bytes_down) - } - delete(srv.peers, sid) - delete(srv.peers, key) + hpeer, ok := srv.peers[sid] + if !ok { + return + } + srv.toClient(hpeer, HOP_FLG_FIN|HOP_FLG_ACK, []byte{0}, false) + key := ip4_uint64(hpeer.ip) + srv.ippool.relase(hpeer.ip) + + // log user info + if sid>>32 > 0 { + logger.Info("UserBytes sid:%d, uid:%d, gid:%d, up:%d, down:%d", hpeer.id>>32, hpeer.uid, hpeer.gmid, hpeer.bytes_up, hpeer.bytes_down) + } + delete(srv.peers, sid) + delete(srv.peers, key) } func (srv *HopServer) cleanUp() { - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) - <-c + c := make(chan os.Signal, 1) + signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) + <-c - clearMSS(srv.iface.Name(), true) - os.Exit(0) + clearMSS(srv.iface.Name(), true) + os.Exit(0) } func (srv *HopServer) routeList(gmid uint32) [][5]byte { - var routes [][5]byte = make([][5]byte, 0, 5) - for _, k := range []uint32{1, gmid} { - if list, ok := srv.cfg.RouteList[k]; ok { - routes = append(routes, list...) - } - } - if len(routes) == 0 { - routes = [][5]byte{[5]byte{254, 254, 254, 254, 32}} - } - return routes + var routes [][5]byte = make([][5]byte, 0, 5) + for _, k := range []uint32{1, gmid} { + if list, ok := srv.cfg.RouteList[k]; ok { + routes = append(routes, list...) + } + } + if len(routes) == 0 { + routes = [][5]byte{[5]byte{254, 254, 254, 254, 32}} + } + return routes } func (srv *HopServer) routeMatch(peer *HopPeer, hp *HopPacket) (bool, net.IP) { - ip := waterutil.IPv4Destination(hp.payload).To4() - list := srv.routeList(peer.gmid) - intip := binary.BigEndian.Uint32([]byte(ip)) - for _, l := range list { - routeIp := binary.BigEndian.Uint32(l[:4]) - mask := 32 - l[4] - if intip >= routeIp && (intip>>mask) == (routeIp>>mask) { - return true, ip - } - } - - return false, ip + ip := waterutil.IPv4Destination(hp.payload).To4() + list := srv.routeList(peer.gmid) + intip := binary.BigEndian.Uint32([]byte(ip)) + for _, l := range list { + routeIp := binary.BigEndian.Uint32(l[:4]) + mask := 32 - l[4] + if intip >= routeIp && (intip>>mask) == (routeIp>>mask) { + return true, ip + } + } + + return false, ip } func (srv *HopServer) peerTimeoutWatcher() { - for { - if srv.cfg.PeerTimeout <= 0 { - return - } - time.Sleep(time.Minute) - count := 0 - timeout := time.Second * time.Duration(srv.cfg.PeerTimeout) - for sid, hpeer := range srv.peers { - // logger.Debug("watch:%v", hpeer.lastConnTime) - if sid>>32 > 0 { - count++ - } - conntime := time.Since(hpeer.lastConnTime) - // logger.Debug("watch:%v %v", conntime.Seconds(), timeout.Seconds()) - if conntime > timeout { - go srv.deletePeer(sid) - } - } - logger.Info("Ulinks:%d", count) - } + for { + if srv.cfg.PeerTimeout <= 0 { + return + } + time.Sleep(time.Minute) + count := 0 + timeout := time.Second * time.Duration(srv.cfg.PeerTimeout) + for sid, hpeer := range srv.peers { + // logger.Debug("watch:%v", hpeer.lastConnTime) + if sid>>32 > 0 { + count++ + } + conntime := time.Since(hpeer.lastConnTime) + // logger.Debug("watch:%v %v", conntime.Seconds(), timeout.Seconds()) + if conntime > timeout { + go srv.deletePeer(sid) + } + } + logger.Info("Ulinks:%d", count) + } } diff --git a/main.go b/main.go index 0fae379..2040fe0 100644 --- a/main.go +++ b/main.go @@ -19,15 +19,15 @@ package main import ( - "./hop" - "./logging" - "flag" - "fmt" - "io" - "os" - "runtime" - "time" - "path/filepath" + "./hop" + "./logging" + "flag" + "fmt" + "io" + "os" + "runtime" + "time" + "path/filepath" ) var srvMode, cltMode, debug, getVersion bool @@ -36,55 +36,55 @@ var cfgFile string var VERSION = "0.3.2-dev" func init() { - flag.BoolVar(&getVersion, "version", false, "Get Version info") - flag.BoolVar(&debug, "debug", false, "Provide debug info") - flag.StringVar(&cfgFile, "config", "", "configfile") + flag.BoolVar(&getVersion, "version", false, "Get Version info") + flag.BoolVar(&debug, "debug", false, "Provide debug info") + flag.StringVar(&cfgFile, "config", "", "configfile") } func main() { - flag.Parse() + flag.Parse() - if getVersion { - fmt.Println("GoHop: Yet Another VPN to Escape from Censorship") - fmt.Printf("Version: %s\n", VERSION) - os.Exit(0) - } + if getVersion { + fmt.Println("GoHop: Yet Another VPN to Escape from Censorship") + fmt.Printf("Version: %s\n", VERSION) + os.Exit(0) + } - logging.InitLogger(debug) - logger := logging.GetLogger() + logging.InitLogger(debug) + logger := logging.GetLogger() - checkerr := func(err error) { - if err != nil { - logger.Error(err.Error()) - os.Exit(1) - } - } + checkerr := func(err error) { + if err != nil { + logger.Error(err.Error()) + os.Exit(1) + } + } - if cfgFile == "" { - cfgFile = flag.Arg(0) - } + if cfgFile == "" { + cfgFile = flag.Arg(0) + } - logger.Info("using config file: %v", cfgFile) + logger.Info("using config file: %v", cfgFile) - icfg, err := hop.ParseHopConfig(cfgFile) - //logger.Debug("%v", icfg) - checkerr(err) + icfg, err := hop.ParseHopConfig(cfgFile) + //logger.Debug("%v", icfg) + checkerr(err) - // 设置可使用的最大核心数 - runtime.GOMAXPROCS(runtime.NumCPU() - 1) - fmt.Printf("/** server start **/\nUse %d/%d CPU cores\n", runtime.GOMAXPROCS(-1), runtime.NumCPU()) + // 设置可使用的最大核心数 + runtime.GOMAXPROCS(runtime.NumCPU() - 1) + fmt.Printf("/** server start **/\nUse %d/%d CPU cores\n", runtime.GOMAXPROCS(-1), runtime.NumCPU()) - switch cfg := icfg.(type) { - case hop.HopServerConfig: - addWatchFile(cfg.RouteFile, cfg.RouteConfig, time.Second*60) - err := hop.NewServer(&cfg) - checkerr(err) - case hop.HopClientConfig: - err := hop.NewClient(&cfg) - checkerr(err) - default: - logger.Error("Invalid config file") - } + switch cfg := icfg.(type) { + case hop.HopServerConfig: + addWatchFile(cfg.RouteFile, cfg.RouteConfig, time.Second*60) + err := hop.NewServer(&cfg) + checkerr(err) + case hop.HopClientConfig: + err := hop.NewClient(&cfg) + checkerr(err) + default: + logger.Error("Invalid config file") + } } /* @@ -92,27 +92,27 @@ func main() { 不能放到其他包中。避免非启动时调用。 */ func addWatchFile(filename string, callback func(r io.Reader), st time.Duration) { - logger := logging.GetLogger() - modtime := int64(0) - filename, _ = filepath.Abs(filename) - logger.Info("addWatchFile : " + filename) - setF := func() { - if f, err := os.Open(filename); err != nil { - logger.Error("config file " + filename + " error : " + err.Error()) - } else if fi, err := f.Stat(); err != nil { - logger.Error("config file " + filename + " error : " + err.Error()) - } else if mt := fi.ModTime().Unix(); mt != modtime { - logger.Debug("load config file : " + filename + " begin !") - modtime = mt - callback(f) - logger.Debug("load config file : " + filename + " finish !") - } - } - setF() - go func() { - for { - time.Sleep(st) - setF() - } - }() + logger := logging.GetLogger() + modtime := int64(0) + filename, _ = filepath.Abs(filename) + logger.Info("addWatchFile : " + filename) + setF := func() { + if f, err := os.Open(filename); err != nil { + logger.Error("config file " + filename + " error : " + err.Error()) + } else if fi, err := f.Stat(); err != nil { + logger.Error("config file " + filename + " error : " + err.Error()) + } else if mt := fi.ModTime().Unix(); mt != modtime { + logger.Debug("load config file : " + filename + " begin !") + modtime = mt + callback(f) + logger.Debug("load config file : " + filename + " finish !") + } + } + setF() + go func() { + for { + time.Sleep(st) + setF() + } + }() }