2018-12-16 08:56:40 +03:00
|
|
|
package pingtunnel
|
|
|
|
|
|
|
|
import (
|
2018-12-18 10:36:59 +03:00
|
|
|
"crypto/md5"
|
|
|
|
"crypto/rand"
|
|
|
|
"encoding/base64"
|
2018-12-16 08:56:40 +03:00
|
|
|
"encoding/binary"
|
2018-12-18 10:36:59 +03:00
|
|
|
"encoding/hex"
|
2018-12-17 14:06:46 +03:00
|
|
|
"fmt"
|
|
|
|
"golang.org/x/net/icmp"
|
|
|
|
"golang.org/x/net/ipv4"
|
2018-12-18 10:36:59 +03:00
|
|
|
"io"
|
2018-12-17 14:06:46 +03:00
|
|
|
"net"
|
|
|
|
"syscall"
|
|
|
|
"time"
|
2018-12-16 08:56:40 +03:00
|
|
|
)
|
|
|
|
|
2018-12-17 10:21:15 +03:00
|
|
|
const (
|
2018-12-18 14:07:35 +03:00
|
|
|
DATA uint32 = 0x01010101
|
2018-12-17 10:21:15 +03:00
|
|
|
)
|
2018-12-16 08:56:40 +03:00
|
|
|
|
2018-12-17 14:06:46 +03:00
|
|
|
// An Echo represents an ICMP echo request or reply message body.
|
|
|
|
type MyMsg struct {
|
2018-12-18 06:39:16 +03:00
|
|
|
TYPE uint32
|
2018-12-18 10:36:59 +03:00
|
|
|
ID string
|
|
|
|
TARGET string
|
2018-12-18 06:39:16 +03:00
|
|
|
Data []byte
|
2018-12-16 08:56:40 +03:00
|
|
|
}
|
|
|
|
|
2018-12-17 14:06:46 +03:00
|
|
|
// Len implements the Len method of MessageBody interface.
|
|
|
|
func (p *MyMsg) Len(proto int) int {
|
2018-12-16 08:56:40 +03:00
|
|
|
if p == nil {
|
|
|
|
return 0
|
|
|
|
}
|
2018-12-18 10:36:59 +03:00
|
|
|
return 4 + p.LenString(p.ID) + p.LenString(p.TARGET) + len(p.Data)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *MyMsg) LenString(s string) int {
|
|
|
|
return 2 + len(s)
|
2018-12-16 08:56:40 +03:00
|
|
|
}
|
|
|
|
|
2018-12-17 14:06:46 +03:00
|
|
|
// Marshal implements the Marshal method of MessageBody interface.
|
|
|
|
func (p *MyMsg) Marshal(proto int) ([]byte, error) {
|
2018-12-18 10:36:59 +03:00
|
|
|
|
2018-12-17 10:21:15 +03:00
|
|
|
b := make([]byte, p.Len(proto))
|
2018-12-18 10:36:59 +03:00
|
|
|
|
|
|
|
binary.BigEndian.PutUint32(b[:4], uint32(p.TYPE))
|
|
|
|
|
|
|
|
id := p.MarshalString(p.ID)
|
|
|
|
copy(b[4:], id)
|
|
|
|
|
|
|
|
target := p.MarshalString(p.TARGET)
|
|
|
|
copy(b[4+p.LenString(p.ID):], target)
|
|
|
|
|
|
|
|
copy(b[4+p.LenString(p.ID)+p.LenString(p.TARGET):], p.Data)
|
|
|
|
|
2018-12-16 08:56:40 +03:00
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
|
2018-12-18 10:36:59 +03:00
|
|
|
func (p *MyMsg) MarshalString(s string) []byte {
|
|
|
|
b := make([]byte, p.LenString(s))
|
|
|
|
binary.BigEndian.PutUint16(b[:2], uint16(len(s)))
|
|
|
|
copy(b[2:], []byte(s))
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2018-12-17 14:06:46 +03:00
|
|
|
// Marshal implements the Marshal method of MessageBody interface.
|
|
|
|
func (p *MyMsg) Unmarshal(b []byte) error {
|
2018-12-18 11:08:28 +03:00
|
|
|
defer func() {
|
2018-12-18 11:17:57 +03:00
|
|
|
recover()
|
2018-12-18 11:08:28 +03:00
|
|
|
}()
|
2018-12-18 10:36:59 +03:00
|
|
|
|
|
|
|
p.TYPE = binary.BigEndian.Uint32(b[:4])
|
|
|
|
|
|
|
|
p.ID = p.UnmarshalString(b[4:])
|
|
|
|
|
|
|
|
p.TARGET = p.UnmarshalString(b[4+p.LenString(p.ID):])
|
|
|
|
|
|
|
|
p.Data = make([]byte, len(b[4+p.LenString(p.ID)+p.LenString(p.TARGET):]))
|
|
|
|
copy(p.Data, b[4+p.LenString(p.ID)+p.LenString(p.TARGET):])
|
|
|
|
|
2018-12-17 14:06:46 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-12-18 10:36:59 +03:00
|
|
|
func (p *MyMsg) UnmarshalString(b []byte) string {
|
|
|
|
len := binary.BigEndian.Uint16(b[:2])
|
|
|
|
data := make([]byte, len)
|
|
|
|
copy(data, b[2:])
|
|
|
|
return string(data)
|
2018-12-17 14:06:46 +03:00
|
|
|
}
|
|
|
|
|
2018-12-18 10:36:59 +03:00
|
|
|
func sendICMP(conn icmp.PacketConn, server *net.IPAddr, target string, connId string, msgType uint32, data []byte) {
|
2018-12-17 14:06:46 +03:00
|
|
|
|
|
|
|
m := &MyMsg{
|
2018-12-18 06:39:16 +03:00
|
|
|
ID: connId,
|
|
|
|
TYPE: msgType,
|
|
|
|
TARGET: target,
|
|
|
|
Data: data,
|
2018-12-17 14:06:46 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
msg := &icmp.Message{
|
2018-12-18 14:07:35 +03:00
|
|
|
Type: ipv4.ICMPTypeExtendedEchoRequest,
|
2018-12-17 14:06:46 +03:00
|
|
|
Code: 0,
|
|
|
|
Body: m,
|
|
|
|
}
|
2018-12-16 08:56:40 +03:00
|
|
|
|
2018-12-17 14:06:46 +03:00
|
|
|
bytes, err := msg.Marshal(nil)
|
|
|
|
if err != nil {
|
2018-12-18 06:39:16 +03:00
|
|
|
fmt.Printf("sendICMP Marshal error %s %s\n", server.String(), err)
|
2018-12-17 14:06:46 +03:00
|
|
|
return
|
2018-12-16 08:56:40 +03:00
|
|
|
}
|
2018-12-17 14:06:46 +03:00
|
|
|
|
|
|
|
for {
|
2018-12-18 06:39:16 +03:00
|
|
|
if _, err := conn.WriteTo(bytes, server); err != nil {
|
2018-12-17 14:06:46 +03:00
|
|
|
if neterr, ok := err.(*net.OpError); ok {
|
|
|
|
if neterr.Err == syscall.ENOBUFS {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
2018-12-18 06:39:16 +03:00
|
|
|
fmt.Printf("sendICMP WriteTo error %s %s\n", server.String(), err)
|
2018-12-17 14:06:46 +03:00
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
2018-12-17 10:21:15 +03:00
|
|
|
}
|
|
|
|
|
2018-12-17 14:06:46 +03:00
|
|
|
func recvICMP(conn icmp.PacketConn, recv chan<- *Packet) {
|
|
|
|
|
|
|
|
bytes := make([]byte, 10240)
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2018-12-18 06:39:16 +03:00
|
|
|
recv <- &Packet{data: my.Data, id: my.ID, target: my.TARGET, src: srcaddr.(*net.IPAddr)}
|
2018-12-17 14:06:46 +03:00
|
|
|
}
|
2018-12-17 10:21:15 +03:00
|
|
|
}
|
|
|
|
|
2018-12-17 14:06:46 +03:00
|
|
|
type Packet struct {
|
2018-12-18 06:39:16 +03:00
|
|
|
data []byte
|
2018-12-18 10:36:59 +03:00
|
|
|
id string
|
|
|
|
target string
|
2018-12-18 06:39:16 +03:00
|
|
|
src *net.IPAddr
|
2018-12-16 08:56:40 +03:00
|
|
|
}
|
2018-12-18 10:36:59 +03:00
|
|
|
|
|
|
|
func UniqueId() string {
|
|
|
|
b := make([]byte, 48)
|
|
|
|
|
|
|
|
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return GetMd5String(base64.URLEncoding.EncodeToString(b))
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetMd5String(s string) string {
|
|
|
|
h := md5.New()
|
|
|
|
h.Write([]byte(s))
|
|
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
|
|
}
|