From 70e47f37574334a4931b51996ab7a4975fda5840 Mon Sep 17 00:00:00 2001 From: esrrhs Date: Mon, 17 Dec 2018 15:21:15 +0800 Subject: [PATCH] add --- cmd/main.go | 12 +- src/pingtunnel/client.go | 146 ++++++++++++++++++++ src/pingtunnel/pingtunnel.go | 261 +++++------------------------------ src/pingtunnel/server.go | 88 ++++++++++++ 4 files changed, 272 insertions(+), 235 deletions(-) create mode 100644 src/pingtunnel/client.go create mode 100644 src/pingtunnel/server.go diff --git a/cmd/main.go b/cmd/main.go index 7b74856..fdaca9d 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -9,9 +9,9 @@ import ( var usage = ` Usage: - pingtunnel -t server -l SERVER_IP:4455 -t TARGET_IP:443 + pingtunnel -type server -t TARGET_IP:4455 - pingtunnel -t client -l LOCAL_IP:4455 -t SERVER_IP:4455 + pingtunnel -type client -l LOCAL_IP:4455 -t SERVER_IP ` @@ -37,21 +37,21 @@ func main() { fmt.Printf("target %s\n", *target) if *t == "server" { - s, err := pingtunnel.NewPingTunnelServer(*listen, *target) + s, err := pingtunnel.NewServer(*target) if err != nil { fmt.Printf("ERROR: %s\n", err.Error()) return } - fmt.Printf("Server Listen %s (%s) Target %s (%s):\n", s.Addr(), s.IPAddr(), s.TargetAddr(), s.TargetIPAddr()) + fmt.Printf("Server Target %s (%s):\n", s.TargetAddr(), s.TargetIPAddr()) s.Run() } if *t == "client" { - c, err := pingtunnel.NewPingTunnelClient(*listen, *target) + c, err := pingtunnel.NewClient(*listen, *target) if err != nil { fmt.Printf("ERROR: %s\n", err.Error()) return } - c.Run() fmt.Printf("Client Listen %s (%s) Target %s (%s):\n", c.Addr(), c.IPAddr(), c.TargetAddr(), c.TargetIPAddr()) + c.Run() } } diff --git a/src/pingtunnel/client.go b/src/pingtunnel/client.go new file mode 100644 index 0000000..11bdf56 --- /dev/null +++ b/src/pingtunnel/client.go @@ -0,0 +1,146 @@ +package pingtunnel + +import ( + "encoding/json" + "fmt" + "golang.org/x/net/icmp" + "golang.org/x/net/ipv4" + "net" + "syscall" +) + +func NewClient(addr string, target string) (*Client, error) { + + ipaddr, err := net.ResolveTCPAddr("tcp", addr) + if err != nil { + return nil, err + } + + ipaddrTarget, err := net.ResolveIPAddr("ip", target) + if err != nil { + return nil, err + } + + return &Client{ + ipaddr: ipaddr, + addr: addr, + ipaddrTarget: ipaddrTarget, + addrTarget: target, + }, nil +} + +type Client struct { + ipaddr *net.TCPAddr + addr string + + ipaddrTarget *net.IPAddr + addrTarget string + + conn *icmp.PacketConn + listenConn *net.TCPListener +} + +func (p *Client) Addr() string { + return p.addr +} + +func (p *Client) IPAddr() *net.TCPAddr { + return p.ipaddr +} + +func (p *Client) TargetAddr() string { + return p.addrTarget +} + +func (p *Client) TargetIPAddr() *net.IPAddr { + return p.ipaddrTarget +} + +func (p *Client) Run() { + + conn, err := icmp.ListenPacket("ip4:icmp", "") + if err != nil { + fmt.Printf("Error listening for ICMP packets: %s\n", err.Error()) + return + } + defer conn.Close() + p.conn = conn + + listener, err := net.ListenTCP("tcp", p.ipaddr) + if err != nil { + fmt.Printf("Error listening for tcp packets: %s\n", err.Error()) + return + } + + p.listenConn = listener + + p.Accept() +} + +func (p *Client) Accept() error { + + fmt.Println("client waiting local accept") + + for { + localConn, err := p.listenConn.AcceptTCP() + if err != nil { + fmt.Println(err) + continue + } + + localConn.SetLinger(0) + go p.handleConn(*localConn) + } +} + +func (p *Client) handleConn(conn net.TCPConn) { + defer conn.Close() + + uuid := UniqueId() + + fmt.Printf("client new conn %s %s", conn.RemoteAddr().String(), uuid) + + data, err := json.Marshal(RegisterData{localaddr: conn.RemoteAddr().String()}) + if err != nil { + fmt.Printf("Unable to marshal data %s\n", err) + return + } + + for { + p.sendICMP(uuid, REGISTER, data) + } +} + +func (p *Client) sendICMP(connId string, msgType MSGID, data []byte) error { + + body := &Msg{ + ID: connId, + TYPE: (int)(msgType), + Data: data, + } + + msg := &icmp.Message{ + Type: ipv4.ICMPTypeExtendedEchoRequest, + Code: 0, + Body: body, + } + + bytes, err := msg.Marshal(nil) + if err != nil { + return err + } + + for { + if _, err := (*p.conn).WriteTo(bytes, p.ipaddrTarget); err != nil { + if neterr, ok := err.(*net.OpError); ok { + if neterr.Err == syscall.ENOBUFS { + continue + } + } + fmt.Printf("sendICMP error %s %s\n", p.ipaddrTarget.String(), err) + } + break + } + + return nil +} diff --git a/src/pingtunnel/pingtunnel.go b/src/pingtunnel/pingtunnel.go index 1b86e93..bd46eea 100644 --- a/src/pingtunnel/pingtunnel.go +++ b/src/pingtunnel/pingtunnel.go @@ -1,230 +1,24 @@ package pingtunnel import ( + "crypto/md5" + "crypto/rand" + "encoding/base64" "encoding/binary" - "fmt" - "golang.org/x/net/icmp" + "encoding/hex" "golang.org/x/net/ipv4" - "net" - "syscall" - "time" + "io" ) -func NewPingTunnelServer(addr string, target string) (*PingTunnelServer, error) { +type MSGID int - ipaddr, err := net.ResolveTCPAddr("tcp", addr) - if err != nil { - return nil, err - } +const ( + REGISTER MSGID = 1 +) - ipaddrTarget, err := net.ResolveTCPAddr("tcp", target) - if err != nil { - return nil, err - } - - return &PingTunnelServer{ - ipaddr: ipaddr, - addr: addr, - ipaddrTarget: ipaddrTarget, - addrTarget: target, - }, nil -} - -func NewPingTunnelClient(addr string, target string) (*PingTunnelClient, error) { - - ipaddr, err := net.ResolveTCPAddr("tcp", addr) - if err != nil { - return nil, err - } - - ipaddrTarget, err := net.ResolveTCPAddr("tcp", target) - if err != nil { - return nil, err - } - - return &PingTunnelClient{ - ipaddr: ipaddr, - addr: addr, - ipaddrTarget: ipaddrTarget, - addrTarget: target, - }, nil -} - -type PingTunnelClient struct { - ipaddr *net.TCPAddr - addr string - - ipaddrTarget *net.IPAddr - addrTarget string - - conn *icmp.PacketConn - listenConn *net.TCPListener -} - -type PingTunnelServer struct { - ipaddr *net.TCPAddr - addr string - - ipaddrTarget *net.TCPAddr - addrTarget string - - conn net.PacketConn -} - -func (p *PingTunnelServer) Addr() string { - return p.addr -} - -func (p *PingTunnelServer) IPAddr() *net.TCPAddr { - return p.ipaddr -} - -func (p *PingTunnelServer) TargetAddr() string { - return p.addrTarget -} - -func (p *PingTunnelServer) TargetIPAddr() *net.TCPAddr { - return p.ipaddrTarget -} - -func (p *PingTunnelClient) Addr() string { - return p.addr -} - -func (p *PingTunnelClient) IPAddr() *net.TCPAddr { - return p.ipaddr -} - -func (p *PingTunnelClient) TargetAddr() string { - return p.addrTarget -} - -func (p *PingTunnelClient) TargetIPAddr() *net.IPAddr { - return p.ipaddrTarget -} - -func (p *PingTunnelServer) Run() { - conn, err := icmp.ListenPacket("ip4:icmp", "") - if err != nil { - fmt.Printf("Error listening for ICMP packets: %s\n", err.Error()) - return - } - - p.conn = conn - - p.Recv() -} - -func (p *PingTunnelClient) Run() { - - conn, err := icmp.ListenPacket("ip4:icmp", "") - if err != nil { - fmt.Printf("Error listening for ICMP packets: %s\n", err.Error()) - return - } - p.conn = conn - - ipaddrTarget, err := net.ResolveIPAddr("ip", p.addrTarget) - if err != nil { - return - } - p.ipaddrTarget = ipaddrTarget - - ipAddr, err := net.ResolveTCPAddr("tcp", p.addr) - if err != nil { - fmt.Printf("Error listening for Local packets: %s\n", err.Error()) - return - } - p.ipaddr = ipAddr - - listener, err := net.ListenTCP("tcp", p.ipaddr) - - p.listenConn = listener - - go p.Accept() -} - -func (p *PingTunnelClient) Accept() error { - - for { - localConn, err := p.listenConn.AcceptTCP() - if err != nil { - fmt.Println(err) - continue - } - - localConn.SetLinger(0) - go p.handleConn(*localConn) - } -} - -func (p *PingTunnelClient) handleConn(conn net.TCPConn) { - -} - -func (p *PingTunnelClient) sendICMP(connId int, msgType int, data []byte) error { - - body := &Msg{ - ID: connId, - TYPE: msgType, - Data: data, - } - - msg := &icmp.Message{ - Type: ipv4.ICMPTypeExtendedEchoRequest, - Code: 0, - Body: body, - } - - bytes, err := msg.Marshal(nil) - if err != nil { - return err - } - - for { - if _, err := p.conn.Write(bytes); err != nil { - if neterr, ok := err.(*net.OpError); ok { - if neterr.Err == syscall.ENOBUFS { - continue - } - } - } - break - } - - fmt.Printf("send %d\n", id) - - return nil -} - -func (p *PingTunnelServer) Recv() error { - - for { - bytes := make([]byte, 512) - p.conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100)) - n, srcaddr, err := p.conn.ReadFrom(bytes) - if err != nil { - if neterr, ok := err.(*net.OpError); ok { - if neterr.Timeout() { - // Read timeout - continue - } else { - return err - } - } - } - - var sbytes []byte - sbytes = ipv4Payload(bytes) - - var m *icmp.Message - if m, err = icmp.ParseMessage(1, sbytes[:n]); err != nil { - return fmt.Errorf("Error parsing icmp message") - } - - fmt.Printf("%d %d %d %s \n", m.Type, m.Code, n, srcaddr) - } -} +const ( + protocolICMP = 1 +) func ipv4Payload(b []byte) []byte { if len(b) < ipv4.HeaderLen { @@ -235,8 +29,8 @@ func ipv4Payload(b []byte) []byte { } type Msg struct { - ID int // identifier TYPE int + ID string // identifier Data []byte // data } @@ -244,23 +38,32 @@ func (p *Msg) Len(proto int) int { if p == nil { return 0 } - return 8 + len(p.Data) + return 4 + 32 + len(p.Data) } func (p *Msg) Marshal(proto int) ([]byte, error) { - b := make([]byte, 8+len(p.Data)) - binary.BigEndian.PutUint32(b, uint32(p.ID)) + b := make([]byte, p.Len(proto)) binary.BigEndian.PutUint32(b, uint32(p.TYPE)) - copy(b[8:], p.Data) + copy(b[4:], p.ID) + copy(b[4+32:], p.Data) return b, nil } -func (p *PingTunnelServer) listen(netProto string, source string) *icmp.PacketConn { +func UniqueId() string { + b := make([]byte, 48) - conn, err := icmp.ListenPacket(netProto, source) - if err != nil { - fmt.Printf("Error listening for ICMP packets: %s\n", err.Error()) - return nil + if _, err := io.ReadFull(rand.Reader, b); err != nil { + return "" } - return conn + return GetMd5String(base64.URLEncoding.EncodeToString(b)) +} + +func GetMd5String(s string) string { + h := md5.New() + h.Write([]byte(s)) + return hex.EncodeToString(h.Sum(nil)) +} + +type RegisterData struct { + localaddr string } diff --git a/src/pingtunnel/server.go b/src/pingtunnel/server.go new file mode 100644 index 0000000..5b816be --- /dev/null +++ b/src/pingtunnel/server.go @@ -0,0 +1,88 @@ +package pingtunnel + +import ( + "fmt" + "golang.org/x/net/icmp" + "net" + "time" +) + +func NewServer(target string) (*Server, error) { + + ipaddrTarget, err := net.ResolveTCPAddr("tcp", target) + if err != nil { + return nil, err + } + + return &Server{ + ipaddrTarget: ipaddrTarget, + addrTarget: target, + }, nil +} + +type Server struct { + ipaddrTarget *net.TCPAddr + addrTarget string + + conn net.PacketConn +} + +func (p *Server) TargetAddr() string { + return p.addrTarget +} + +func (p *Server) TargetIPAddr() *net.TCPAddr { + return p.ipaddrTarget +} + +func (p *Server) Run() { + + conn, err := icmp.ListenPacket("ip4:icmp", "") + if err != nil { + fmt.Printf("Error listening for ICMP packets: %s\n", err.Error()) + return + } + p.conn = conn + + p.Recv() +} + +func (p *Server) Recv() error { + + for { + bytes := make([]byte, 512) + p.conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100)) + n, srcaddr, err := p.conn.ReadFrom(bytes) + + if err != nil { + if neterr, ok := err.(*net.OpError); ok { + if neterr.Timeout() { + // Read timeout + continue + } else { + return err + } + } + } + + bytes1 := ipv4Payload(bytes) + + var m *icmp.Message + if m, err = icmp.ParseMessage(protocolICMP, bytes1[:n]); err != nil { + fmt.Println("Error parsing icmp message") + return err + } + + fmt.Printf("%d %d %d %s \n", m.Type, m.Code, n, srcaddr) + } +} + +func (p *Server) listen(netProto string, source string) *icmp.PacketConn { + + conn, err := icmp.ListenPacket(netProto, source) + if err != nil { + fmt.Printf("Error listening for ICMP packets: %s\n", err.Error()) + return nil + } + return conn +}