This commit is contained in:
esrrhs 2018-12-17 19:06:46 +08:00
parent edfbd3a3cf
commit a8910116d2
3 changed files with 218 additions and 120 deletions

View File

@ -1,17 +1,15 @@
package pingtunnel package pingtunnel
import ( import (
"encoding/json"
"fmt" "fmt"
"golang.org/x/net/icmp" "golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"net" "net"
"syscall" "time"
) )
func NewClient(addr string, target string) (*Client, error) { func NewClient(addr string, target string) (*Client, error) {
ipaddr, err := net.ResolveTCPAddr("tcp", addr) ipaddr, err := net.ResolveUDPAddr("udp", addr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -30,21 +28,24 @@ func NewClient(addr string, target string) (*Client, error) {
} }
type Client struct { type Client struct {
ipaddr *net.TCPAddr ipaddr *net.UDPAddr
addr string addr string
ipaddrTarget *net.IPAddr ipaddrTarget *net.IPAddr
addrTarget string addrTarget string
conn *icmp.PacketConn conn *icmp.PacketConn
listenConn *net.TCPListener listenConn *net.UDPConn
localConnToIdMap map[string]uint32
localIdToConnMap map[uint32]*net.UDPAddr
} }
func (p *Client) Addr() string { func (p *Client) Addr() string {
return p.addr return p.addr
} }
func (p *Client) IPAddr() *net.TCPAddr { func (p *Client) IPAddr() *net.UDPAddr {
return p.ipaddr return p.ipaddr
} }
@ -66,81 +67,78 @@ func (p *Client) Run() {
defer conn.Close() defer conn.Close()
p.conn = conn p.conn = conn
listener, err := net.ListenTCP("tcp", p.ipaddr) listener, err := net.ListenUDP("udp", p.ipaddr)
if err != nil { if err != nil {
fmt.Printf("Error listening for tcp packets: %s\n", err.Error()) fmt.Printf("Error listening for udp packets: %s\n", err.Error())
return return
} }
defer listener.Close()
p.listenConn = listener p.listenConn = listener
p.Accept() p.localConnToIdMap = make(map[string]uint32)
p.localIdToConnMap = make(map[uint32]*net.UDPAddr)
go p.Accept()
recv := make(chan *Packet, 1000)
go recvICMP(*p.conn, recv)
for {
select {
case r := <-recv:
p.processPacket(r)
}
}
} }
func (p *Client) Accept() error { func (p *Client) Accept() error {
fmt.Println("client waiting local accept") fmt.Println("client waiting local accept")
bytes := make([]byte, 10240)
for { for {
localConn, err := p.listenConn.AcceptTCP() p.conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
n, srcaddr, err := p.listenConn.ReadFromUDP(bytes)
if err != nil { 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, ok := err.(*net.OpError); ok {
if neterr.Err == syscall.ENOBUFS { if neterr.Timeout() {
// Read timeout
continue
} else {
fmt.Printf("Error read udp %s\n", err)
continue continue
} }
} }
fmt.Printf("sendICMP error %s %s\n", p.ipaddrTarget.String(), err)
} }
break
uuid := p.localConnToIdMap[srcaddr.String()]
if uuid == 0 {
uuid = UniqueId()
p.localConnToIdMap[srcaddr.String()] = uuid
p.localIdToConnMap[uuid] = srcaddr
fmt.Printf("client accept new local %d %s\n", uuid, srcaddr.String())
}
sendICMP(*p.conn, p.ipaddrTarget, uuid, (uint32)(DATA), bytes[:n])
}
}
func (p *Client) processPacket(packet *Packet) {
fmt.Printf("processPacket %d %s %d\n", packet.id, packet.src.String(), len(packet.data))
addr := p.localIdToConnMap[packet.id]
if addr == nil {
fmt.Printf("processPacket no conn %d \n", packet.id)
return
} }
return nil _, err := p.listenConn.WriteToUDP(packet.data, addr)
if err != nil {
fmt.Printf("WriteToUDP Error read udp %s\n", err)
p.localConnToIdMap[addr.String()] = 0
p.localIdToConnMap[packet.id] = nil
return
}
} }

View File

@ -1,60 +1,135 @@
package pingtunnel package pingtunnel
import ( import (
"crypto/md5"
"crypto/rand"
"encoding/base64"
"encoding/binary" "encoding/binary"
"encoding/hex" "fmt"
"io" "golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"net"
"sync/atomic"
"syscall"
"time"
) )
type MSGID int type MSGID int
const ( const (
REGISTER MSGID = 1 DATA MSGID = 0xDEADBEEF
) )
const ( const (
protocolICMP = 1 protocolICMP = 1
) )
type Msg struct { // An Echo represents an ICMP echo request or reply message body.
TYPE int type MyMsg struct {
ID string // identifier ID uint32
Data []byte // data TYPE uint32
Data []byte
} }
func (p *Msg) Len(proto int) int { // Len implements the Len method of MessageBody interface.
func (p *MyMsg) Len(proto int) int {
if p == nil { if p == nil {
return 0 return 0
} }
return 4 + 32 + len(p.Data) return 8 + len(p.Data)
} }
func (p *Msg) Marshal(proto int) ([]byte, error) { // Marshal implements the Marshal method of MessageBody interface.
func (p *MyMsg) Marshal(proto int) ([]byte, error) {
b := make([]byte, p.Len(proto)) b := make([]byte, p.Len(proto))
binary.BigEndian.PutUint32(b, uint32(p.TYPE)) binary.BigEndian.PutUint32(b[:4], uint32(p.ID))
copy(b[4:], p.ID) binary.BigEndian.PutUint32(b[4:8], uint32(p.TYPE))
copy(b[4+32:], p.Data) copy(b[8:], p.Data)
return b, nil return b, nil
} }
func UniqueId() string { // Marshal implements the Marshal method of MessageBody interface.
b := make([]byte, 48) func (p *MyMsg) Unmarshal(b []byte) error {
p.ID = binary.BigEndian.Uint32(b[:4])
p.TYPE = binary.BigEndian.Uint32(b[4:8])
p.Data = make([]byte, len(b[8:]))
copy(p.Data, b[8:])
return nil
}
if _, err := io.ReadFull(rand.Reader, b); err != nil { var uuid uint32
return ""
func UniqueId() uint32 {
newValue := atomic.AddUint32(&uuid, 1)
return (uint32)(newValue)
}
func sendICMP(conn icmp.PacketConn, target *net.IPAddr, connId uint32, msgType uint32, data []byte) {
m := &MyMsg{
ID: connId,
TYPE: msgType,
Data: data,
} }
return GetMd5String(base64.URLEncoding.EncodeToString(b))
msg := &icmp.Message{
Type: ipv4.ICMPTypeExtendedEchoRequest,
Code: 0,
Body: m,
}
bytes, err := msg.Marshal(nil)
if err != nil {
fmt.Printf("sendICMP Marshal error %s %s\n", target.String(), err)
return
}
for {
if _, err := conn.WriteTo(bytes, target); err != nil {
if neterr, ok := err.(*net.OpError); ok {
if neterr.Err == syscall.ENOBUFS {
continue
}
}
fmt.Printf("sendICMP WriteTo error %s %s\n", target.String(), err)
}
break
}
return
} }
func GetMd5String(s string) string { func recvICMP(conn icmp.PacketConn, recv chan<- *Packet) {
h := md5.New()
h.Write([]byte(s)) bytes := make([]byte, 10240)
return hex.EncodeToString(h.Sum(nil)) for {
conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
n, srcaddr, err := conn.ReadFrom(bytes)
if err != nil {
if neterr, ok := err.(*net.OpError); ok {
if neterr.Timeout() {
// Read timeout
continue
} else {
fmt.Printf("Error read icmp message %s\n", err)
continue
}
}
}
my := &MyMsg{
}
my.Unmarshal(bytes[4:n])
if my.TYPE != (uint32)(DATA) {
fmt.Printf("processPacket diff type %d \n", my.TYPE)
continue
}
recv <- &Packet{data: my.Data, id: my.ID, src: srcaddr.(*net.IPAddr)}
}
} }
type RegisterData struct { type Packet struct {
localaddr string data []byte
id uint32
src *net.IPAddr
} }

View File

@ -9,7 +9,7 @@ import (
func NewServer(target string) (*Server, error) { func NewServer(target string) (*Server, error) {
ipaddrTarget, err := net.ResolveTCPAddr("tcp", target) ipaddrTarget, err := net.ResolveUDPAddr("udp", target)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -21,17 +21,19 @@ func NewServer(target string) (*Server, error) {
} }
type Server struct { type Server struct {
ipaddrTarget *net.TCPAddr ipaddrTarget *net.UDPAddr
addrTarget string addrTarget string
conn net.PacketConn conn *icmp.PacketConn
localConnMap map[uint32]*net.UDPConn
} }
func (p *Server) TargetAddr() string { func (p *Server) TargetAddr() string {
return p.addrTarget return p.addrTarget
} }
func (p *Server) TargetIPAddr() *net.TCPAddr { func (p *Server) TargetIPAddr() *net.UDPAddr {
return p.ipaddrTarget return p.ipaddrTarget
} }
@ -44,43 +46,66 @@ func (p *Server) Run() {
} }
p.conn = conn p.conn = conn
p.Recv() p.localConnMap = make(map[uint32]*net.UDPConn)
}
func (p *Server) Recv() error { recv := make(chan *Packet, 1000)
go recvICMP(*p.conn, recv)
for { for {
bytes := make([]byte, 512) select {
p.conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100)) case r := <-recv:
n, srcaddr, err := p.conn.ReadFrom(bytes) p.processPacket(r)
}
}
}
func (p *Server) processPacket(packet *Packet) {
fmt.Printf("processPacket %d %s %d\n", packet.id, packet.src.String(), len(packet.data))
id := packet.id
udpConn := p.localConnMap[id]
if udpConn == nil {
targetConn, err := net.ListenUDP("udp", p.ipaddrTarget)
if err != nil {
fmt.Printf("Error listening for udp packets: %s\n", err.Error())
return
}
udpConn = targetConn
p.localConnMap[id] = udpConn
go p.Recv(udpConn, id, packet.src)
}
_, err := udpConn.WriteToUDP(packet.data, p.ipaddrTarget)
if err != nil {
fmt.Printf("WriteToUDP Error read udp %s\n", err)
p.localConnMap[id] = nil
return
}
}
func (p *Server) Recv(conn *net.UDPConn, id uint32, src *net.IPAddr) {
fmt.Println("server waiting target response")
bytes := make([]byte, 10240)
for {
p.conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
n, _, err := conn.ReadFromUDP(bytes)
if err != nil { if err != nil {
if neterr, ok := err.(*net.OpError); ok { if neterr, ok := err.(*net.OpError); ok {
if neterr.Timeout() { if neterr.Timeout() {
// Read timeout // Read timeout
continue continue
} else { } else {
return err fmt.Printf("ReadFromUDP Error read udp %s\n", err)
p.localConnMap[id] = nil
return
} }
} }
} }
var m *icmp.Message sendICMP(*p.conn, src, id, (uint32)(DATA), bytes[:n])
if m, err = icmp.ParseMessage(protocolICMP, bytes[: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
}