This commit is contained in:
esrrhs 2018-12-17 15:21:15 +08:00
parent eb1fe01a48
commit 70e47f3757
4 changed files with 272 additions and 235 deletions

View File

@ -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()
}
}

146
src/pingtunnel/client.go Normal file
View File

@ -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
}

View File

@ -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
}

88
src/pingtunnel/server.go Normal file
View File

@ -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
}