fix
This commit is contained in:
parent
edfbd3a3cf
commit
a8910116d2
@ -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)
|
if neterr, ok := err.(*net.OpError); ok {
|
||||||
|
if neterr.Timeout() {
|
||||||
|
// Read timeout
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Error read udp %s\n", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
localConn.SetLinger(0)
|
|
||||||
go p.handleConn(*localConn)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Client) handleConn(conn net.TCPConn) {
|
uuid := p.localConnToIdMap[srcaddr.String()]
|
||||||
defer conn.Close()
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
uuid := UniqueId()
|
sendICMP(*p.conn, p.ipaddrTarget, uuid, (uint32)(DATA), bytes[:n])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Printf("client new conn %s %s", conn.RemoteAddr().String(), uuid)
|
func (p *Client) processPacket(packet *Packet) {
|
||||||
|
|
||||||
data, err := json.Marshal(RegisterData{localaddr: conn.RemoteAddr().String()})
|
fmt.Printf("processPacket %d %s %d\n", packet.id, packet.src.String(), len(packet.data))
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Unable to marshal data %s\n", err)
|
addr := p.localIdToConnMap[packet.id]
|
||||||
|
if addr == nil {
|
||||||
|
fmt.Printf("processPacket no conn %d \n", packet.id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
_, err := p.listenConn.WriteToUDP(packet.data, addr)
|
||||||
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 {
|
if err != nil {
|
||||||
return err
|
fmt.Printf("WriteToUDP Error read udp %s\n", err)
|
||||||
}
|
p.localConnToIdMap[addr.String()] = 0
|
||||||
|
p.localIdToConnMap[packet.id] = nil
|
||||||
for {
|
return
|
||||||
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
|
|
||||||
}
|
|
||||||
|
@ -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])
|
||||||
if _, err := io.ReadFull(rand.Reader, b); err != nil {
|
p.TYPE = binary.BigEndian.Uint32(b[4:8])
|
||||||
return ""
|
p.Data = make([]byte, len(b[8:]))
|
||||||
}
|
copy(p.Data, b[8:])
|
||||||
return GetMd5String(base64.URLEncoding.EncodeToString(b))
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMd5String(s string) string {
|
var uuid uint32
|
||||||
h := md5.New()
|
|
||||||
h.Write([]byte(s))
|
func UniqueId() uint32 {
|
||||||
return hex.EncodeToString(h.Sum(nil))
|
newValue := atomic.AddUint32(&uuid, 1)
|
||||||
|
return (uint32)(newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
type RegisterData struct {
|
func sendICMP(conn icmp.PacketConn, target *net.IPAddr, connId uint32, msgType uint32, data []byte) {
|
||||||
localaddr string
|
|
||||||
|
m := &MyMsg{
|
||||||
|
ID: connId,
|
||||||
|
TYPE: msgType,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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
|
||||||
|
}
|
||||||
|
|
||||||
|
recv <- &Packet{data: my.Data, id: my.ID, src: srcaddr.(*net.IPAddr)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Packet struct {
|
||||||
|
data []byte
|
||||||
|
id uint32
|
||||||
|
src *net.IPAddr
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user