croc/src/comm/comm.go

173 lines
4.2 KiB
Go
Raw Normal View History

2018-09-23 21:34:29 +02:00
package comm
import (
2018-09-23 21:50:03 +02:00
"bytes"
2019-04-27 18:20:03 +02:00
"encoding/binary"
2018-09-23 23:00:31 +02:00
"fmt"
"io"
2018-09-23 21:34:29 +02:00
"net"
"net/url"
"strings"
2018-09-23 22:32:46 +02:00
"time"
2018-10-13 15:09:55 +02:00
2021-04-17 19:33:38 +02:00
"github.com/schollz/croc/v9/src/utils"
2020-08-23 01:05:00 +02:00
log "github.com/schollz/logger"
2020-10-05 17:30:45 +02:00
"golang.org/x/net/proxy"
2018-09-23 21:34:29 +02:00
)
2020-10-05 17:30:45 +02:00
var Socks5Proxy = ""
var MAGIC_BYTES = []byte("croc")
2018-09-23 21:34:29 +02:00
// Comm is some basic TCP communication
type Comm struct {
2018-09-26 19:43:38 +02:00
connection net.Conn
2018-09-23 21:34:29 +02:00
}
2019-04-27 18:20:03 +02:00
// NewConnection gets a new comm to a tcp address
func NewConnection(address string, timelimit ...time.Duration) (c *Comm, err error) {
tlimit := 30 * time.Second
if len(timelimit) > 0 {
tlimit = timelimit[0]
}
2020-10-05 17:30:45 +02:00
var connection net.Conn
if Socks5Proxy != "" && !utils.IsLocalIP(address) {
var dialer proxy.Dialer
// prepend schema if no schema is given
if !strings.Contains(Socks5Proxy, `://`) {
Socks5Proxy = `socks5://` + Socks5Proxy
}
socks5ProxyURL, urlParseError := url.Parse(Socks5Proxy)
if urlParseError != nil {
err = fmt.Errorf("Unable to parse socks proxy url: %s", urlParseError)
return
}
dialer, err = proxy.FromURL(socks5ProxyURL, proxy.Direct)
2020-10-05 17:30:45 +02:00
if err != nil {
err = fmt.Errorf("proxy failed: %w", err)
return
}
connection, err = dialer.Dial("tcp", address)
} else {
connection, err = net.DialTimeout("tcp", address, tlimit)
}
2019-04-27 18:20:03 +02:00
if err != nil {
2020-08-27 17:10:44 +02:00
err = fmt.Errorf("comm.NewConnection failed: %w", err)
2019-04-27 18:20:03 +02:00
return
}
c = New(connection)
2020-08-27 17:10:44 +02:00
log.Debugf("connected to '%s'", address)
2019-04-27 18:20:03 +02:00
return
}
2018-09-23 21:34:29 +02:00
// New returns a new comm
2019-04-29 22:06:18 +02:00
func New(c net.Conn) *Comm {
2020-08-23 01:05:00 +02:00
if err := c.SetReadDeadline(time.Now().Add(3 * time.Hour)); err != nil {
log.Warnf("error setting read deadline: %v", err)
}
if err := c.SetDeadline(time.Now().Add(3 * time.Hour)); err != nil {
log.Warnf("error setting overall deadline: %v", err)
}
if err := c.SetWriteDeadline(time.Now().Add(3 * time.Hour)); err != nil {
log.Errorf("error setting write deadline: %v", err)
}
2019-04-29 22:06:18 +02:00
comm := new(Comm)
comm.connection = c
return comm
2018-09-23 21:34:29 +02:00
}
2018-09-26 23:31:45 +02:00
// Connection returns the net.Conn connection
2019-04-29 22:06:18 +02:00
func (c *Comm) Connection() net.Conn {
2018-09-23 21:34:29 +02:00
return c.connection
}
2018-09-25 01:10:04 +02:00
// Close closes the connection
2019-04-29 22:06:18 +02:00
func (c *Comm) Close() {
2020-08-23 01:05:00 +02:00
if err := c.connection.Close(); err != nil {
log.Warnf("error closing connection: %v", err)
}
2018-09-25 01:10:04 +02:00
}
func (c *Comm) Write(b []byte) (n int, err error) {
2019-04-27 18:20:03 +02:00
header := new(bytes.Buffer)
err = binary.Write(header, binary.LittleEndian, uint32(len(b)))
2019-04-27 18:20:03 +02:00
if err != nil {
fmt.Println("binary.Write failed:", err)
}
tmpCopy := append(header.Bytes(), b...)
tmpCopy = append(MAGIC_BYTES, tmpCopy...)
n, err = c.connection.Write(tmpCopy)
if err != nil {
err = fmt.Errorf("connection.Write failed: %w", err)
return
}
2018-10-10 04:36:59 +02:00
if n != len(tmpCopy) {
err = fmt.Errorf("wanted to write %d but wrote %d", len(b), n)
return
2018-09-23 23:00:31 +02:00
}
return
2018-09-23 21:34:29 +02:00
}
2019-04-29 22:06:18 +02:00
func (c *Comm) Read() (buf []byte, numBytes int, bs []byte, err error) {
// long read deadline in case waiting for file
2020-08-23 01:05:00 +02:00
if err := c.connection.SetReadDeadline(time.Now().Add(3 * time.Hour)); err != nil {
log.Warnf("error setting read deadline: %v", err)
}
// must clear the timeout setting
defer c.connection.SetDeadline(time.Time{})
// read until we get 4 bytes for the magic
header := make([]byte, 4)
_, err = io.ReadFull(c.connection, header)
if err != nil {
log.Debugf("initial read error: %v", err)
return
2018-09-23 23:15:23 +02:00
}
if !bytes.Equal(header, MAGIC_BYTES) {
err = fmt.Errorf("initial bytes are not magic: %x", header)
return
}
// read until we get 4 bytes for the header
header = make([]byte, 4)
_, err = io.ReadFull(c.connection, header)
if err != nil {
log.Debugf("initial read error: %v", err)
return
}
2018-09-24 16:51:24 +02:00
2019-04-27 18:20:03 +02:00
var numBytesUint32 uint32
rbuf := bytes.NewReader(header)
err = binary.Read(rbuf, binary.LittleEndian, &numBytesUint32)
2018-09-23 23:15:23 +02:00
if err != nil {
2020-08-23 01:05:00 +02:00
err = fmt.Errorf("binary.Read failed: %w", err)
log.Debug(err.Error())
return
2018-09-23 23:12:45 +02:00
}
2019-04-27 18:20:03 +02:00
numBytes = int(numBytesUint32)
// shorten the reading deadline in case getting weird data
2020-08-23 01:05:00 +02:00
if err := c.connection.SetReadDeadline(time.Now().Add(10 * time.Second)); err != nil {
log.Warnf("error setting read deadline: %v", err)
}
buf = make([]byte, numBytes)
_, err = io.ReadFull(c.connection, buf)
if err != nil {
log.Debugf("consecutive read error: %v", err)
return
2018-09-23 21:50:03 +02:00
}
2018-09-23 21:34:29 +02:00
return
}
// Send a message
2019-04-29 22:06:18 +02:00
func (c *Comm) Send(message []byte) (err error) {
2019-04-27 18:20:03 +02:00
_, err = c.Write(message)
2018-09-23 21:34:29 +02:00
return
}
// Receive a message
2019-04-29 22:06:18 +02:00
func (c *Comm) Receive() (b []byte, err error) {
2019-04-27 18:20:03 +02:00
b, _, _, err = c.Read()
2018-09-23 21:34:29 +02:00
return
}