croc/src/tcp/tcp.go

501 lines
10 KiB
Go
Raw Normal View History

2018-09-23 21:34:29 +02:00
package tcp
import (
2019-04-30 00:24:22 +02:00
"bytes"
"fmt"
2018-09-23 21:34:29 +02:00
"net"
2019-05-02 01:10:02 +02:00
"strings"
2018-09-23 21:34:29 +02:00
"sync"
"time"
2020-08-23 01:05:00 +02:00
log "github.com/schollz/logger"
2021-04-17 18:42:11 +02:00
"github.com/schollz/pake/v3"
2020-08-23 01:05:00 +02:00
2021-04-17 19:33:38 +02:00
"github.com/schollz/croc/v9/src/comm"
"github.com/schollz/croc/v9/src/crypt"
"github.com/schollz/croc/v9/src/models"
2018-09-23 21:34:29 +02:00
)
2019-04-30 01:29:36 +02:00
type server struct {
2019-04-30 01:38:49 +02:00
port string
debugLevel string
2019-05-01 01:05:19 +02:00
banner string
2019-11-18 17:16:19 +01:00
password string
2019-04-30 01:38:49 +02:00
rooms roomMap
2019-04-30 01:29:36 +02:00
}
2018-09-23 21:34:29 +02:00
type roomInfo struct {
2019-04-29 22:06:18 +02:00
first *comm.Comm
second *comm.Comm
2019-04-27 18:20:03 +02:00
opened time.Time
full bool
2018-09-23 21:34:29 +02:00
}
type roomMap struct {
rooms map[string]roomInfo
sync.Mutex
}
2019-09-08 15:12:16 +02:00
var timeToRoomDeletion = 10 * time.Minute
2020-10-22 19:09:04 +02:00
var pingRoom = "pinglkasjdlfjsaldjf"
2019-09-08 15:12:16 +02:00
2018-09-23 21:34:29 +02:00
// Run starts a tcp listener, run async
2019-11-18 17:16:19 +01:00
func Run(debugLevel, port, password string, banner ...string) (err error) {
2019-04-30 01:38:49 +02:00
s := new(server)
2019-04-30 01:29:36 +02:00
s.port = port
2019-11-18 17:16:19 +01:00
s.password = password
2019-04-30 01:29:36 +02:00
s.debugLevel = debugLevel
2019-05-01 01:05:19 +02:00
if len(banner) > 0 {
s.banner = banner[0]
}
2019-04-30 06:25:30 +02:00
return s.start()
2019-04-30 01:29:36 +02:00
}
2019-04-30 06:25:30 +02:00
func (s *server) start() (err error) {
2019-05-08 23:03:54 +02:00
log.SetLevel(s.debugLevel)
2019-11-18 17:16:19 +01:00
log.Debugf("starting with password '%s'", s.password)
2019-04-30 01:29:36 +02:00
s.rooms.Lock()
s.rooms.rooms = make(map[string]roomInfo)
s.rooms.Unlock()
2018-10-13 15:13:50 +02:00
// delete old rooms
go func() {
for {
2019-09-08 15:12:16 +02:00
time.Sleep(timeToRoomDeletion)
2020-08-23 01:05:00 +02:00
var roomsToDelete []string
2019-04-30 01:29:36 +02:00
s.rooms.Lock()
for room := range s.rooms.rooms {
if time.Since(s.rooms.rooms[room].opened) > 3*time.Hour {
roomsToDelete = append(roomsToDelete, room)
2018-10-13 15:13:50 +02:00
}
}
2019-04-30 01:29:36 +02:00
s.rooms.Unlock()
2019-05-03 05:57:55 +02:00
for _, room := range roomsToDelete {
s.deleteRoom(room)
}
2018-10-13 15:13:50 +02:00
}
}()
2019-04-30 06:25:30 +02:00
err = s.run()
2018-09-23 21:34:29 +02:00
if err != nil {
log.Error(err)
2019-05-01 01:05:19 +02:00
}
return
2018-09-23 21:34:29 +02:00
}
2019-04-30 01:29:36 +02:00
func (s *server) run() (err error) {
2019-05-02 21:08:23 +02:00
log.Infof("starting TCP server on " + s.port)
2019-04-30 06:33:13 +02:00
server, err := net.Listen("tcp", ":"+s.port)
2018-09-23 21:34:29 +02:00
if err != nil {
2020-08-23 01:05:00 +02:00
return fmt.Errorf("error listening on %s: %w", s.port, err)
2018-09-23 21:34:29 +02:00
}
defer server.Close()
// spawn a new goroutine whenever a client connects
for {
2018-09-26 19:43:38 +02:00
connection, err := server.Accept()
2018-09-23 21:34:29 +02:00
if err != nil {
2020-08-27 17:10:44 +02:00
return fmt.Errorf("problem accepting connection: %w", err)
2018-09-23 21:34:29 +02:00
}
log.Debugf("client %s connected", connection.RemoteAddr().String())
2018-09-26 19:43:38 +02:00
go func(port string, connection net.Conn) {
2019-11-18 22:09:17 +01:00
c := comm.New(connection)
2020-08-23 01:05:00 +02:00
room, errCommunication := s.clientCommunication(port, c)
2020-10-22 19:09:04 +02:00
log.Debugf("room: %+v", room)
log.Debugf("err: %+v", errCommunication)
2018-09-23 21:34:29 +02:00
if errCommunication != nil {
log.Debugf("relay-%s: %s", connection.RemoteAddr().String(), errCommunication.Error())
2020-10-22 19:09:04 +02:00
connection.Close()
return
}
if room == pingRoom {
log.Debugf("got ping")
connection.Close()
2020-10-22 18:59:55 +02:00
return
2018-09-23 21:34:29 +02:00
}
2019-11-18 22:09:17 +01:00
for {
// check connection
log.Debugf("checking connection of room %s for %+v", room, c)
deleteIt := false
s.rooms.Lock()
if _, ok := s.rooms.rooms[room]; !ok {
log.Debug("room is gone")
s.rooms.Unlock()
return
}
log.Debugf("room: %+v", s.rooms.rooms[room])
if s.rooms.rooms[room].first != nil && s.rooms.rooms[room].second != nil {
log.Debug("rooms ready")
s.rooms.Unlock()
break
} else {
if s.rooms.rooms[room].first != nil {
errSend := s.rooms.rooms[room].first.Send([]byte{1})
if errSend != nil {
log.Debug(errSend)
deleteIt = true
}
}
}
s.rooms.Unlock()
if deleteIt {
s.deleteRoom(room)
break
}
time.Sleep(1 * time.Second)
}
2019-04-30 01:38:49 +02:00
}(s.port, connection)
2018-09-23 21:34:29 +02:00
}
}
2020-02-28 20:59:56 +01:00
var weakKey = []byte{1, 2, 3}
2020-08-23 01:05:00 +02:00
func (s *server) clientCommunication(port string, c *comm.Comm) (room string, err error) {
2020-02-28 20:59:56 +01:00
// establish secure password with PAKE for communication with relay
2021-04-16 23:01:48 +02:00
B, err := pake.InitCurve(weakKey, 1, "siec")
2020-02-28 20:59:56 +01:00
if err != nil {
return
}
Abytes, err := c.Receive()
if err != nil {
return
}
2020-10-22 19:09:04 +02:00
if bytes.Equal(Abytes, []byte("ping")) {
room = pingRoom
c.Send([]byte("pong"))
return
}
2020-02-28 20:59:56 +01:00
err = B.Update(Abytes)
if err != nil {
return
}
err = c.Send(B.Bytes())
2021-03-10 01:48:38 +01:00
if err != nil {
return
}
2020-02-28 20:59:56 +01:00
strongKey, err := B.SessionKey()
if err != nil {
return
}
log.Debugf("strongkey: %x", strongKey)
// receive salt
salt, err := c.Receive()
2021-03-10 01:48:38 +01:00
if err != nil {
return
}
2020-02-28 20:59:56 +01:00
strongKeyForEncryption, _, err := crypt.New(strongKey, salt)
if err != nil {
return
}
2019-11-18 17:16:19 +01:00
log.Debugf("waiting for password")
2020-02-28 20:59:56 +01:00
passwordBytesEnc, err := c.Receive()
if err != nil {
return
}
passwordBytes, err := crypt.Decrypt(passwordBytesEnc, strongKeyForEncryption)
2019-11-18 17:16:19 +01:00
if err != nil {
return
}
if strings.TrimSpace(string(passwordBytes)) != s.password {
err = fmt.Errorf("bad password")
2020-02-28 20:59:56 +01:00
enc, _ := crypt.Decrypt([]byte(err.Error()), strongKeyForEncryption)
2020-08-23 01:05:00 +02:00
if err := c.Send(enc); err != nil {
return "", fmt.Errorf("send error: %w", err)
}
2019-11-18 17:16:19 +01:00
return
}
2018-09-23 21:34:29 +02:00
// send ok to tell client they are connected
2019-05-02 01:10:02 +02:00
banner := s.banner
if len(banner) == 0 {
banner = "ok"
2019-05-01 20:20:02 +02:00
}
2019-05-02 01:10:02 +02:00
log.Debugf("sending '%s'", banner)
2020-02-28 20:59:56 +01:00
bSend, err := crypt.Encrypt([]byte(banner+"|||"+c.Connection().RemoteAddr().String()), strongKeyForEncryption)
if err != nil {
return
}
err = c.Send(bSend)
2018-09-23 21:34:29 +02:00
if err != nil {
return
}
// wait for client to tell me which room they want
2018-10-13 15:09:55 +02:00
log.Debug("waiting for answer")
2020-02-28 20:59:56 +01:00
enc, err := c.Receive()
if err != nil {
return
}
roomBytes, err := crypt.Decrypt(enc, strongKeyForEncryption)
2018-09-23 21:34:29 +02:00
if err != nil {
return
}
2019-11-18 22:09:17 +01:00
room = string(roomBytes)
2018-09-23 21:34:29 +02:00
2019-04-30 01:29:36 +02:00
s.rooms.Lock()
2019-04-27 18:20:03 +02:00
// create the room if it is new
2019-04-30 01:29:36 +02:00
if _, ok := s.rooms.rooms[room]; !ok {
s.rooms.rooms[room] = roomInfo{
2019-04-27 18:20:03 +02:00
first: c,
opened: time.Now(),
2018-09-23 21:34:29 +02:00
}
2019-04-30 01:29:36 +02:00
s.rooms.Unlock()
2018-09-23 21:34:29 +02:00
// tell the client that they got the room
2020-02-28 20:59:56 +01:00
bSend, err = crypt.Encrypt([]byte("ok"), strongKeyForEncryption)
if err != nil {
return
}
err = c.Send(bSend)
2018-09-23 21:34:29 +02:00
if err != nil {
2018-10-13 15:09:55 +02:00
log.Error(err)
2019-05-01 20:11:20 +02:00
s.deleteRoom(room)
2018-09-23 21:34:29 +02:00
return
}
2019-04-27 18:20:03 +02:00
log.Debugf("room %s has 1", room)
2019-11-18 22:09:17 +01:00
return
2018-09-23 21:34:29 +02:00
}
2019-04-30 01:29:36 +02:00
if s.rooms.rooms[room].full {
defer s.deleteRoom(room)
2019-04-30 01:29:36 +02:00
s.rooms.Unlock()
2020-02-28 20:59:56 +01:00
bSend, err = crypt.Encrypt([]byte("room full"), strongKeyForEncryption)
if err != nil {
return
}
err = c.Send(bSend)
2019-04-27 18:20:03 +02:00
if err != nil {
log.Error(err)
return
}
2019-11-18 22:09:17 +01:00
return
2019-04-27 18:20:03 +02:00
}
log.Debugf("room %s has 2", room)
2019-04-30 01:29:36 +02:00
s.rooms.rooms[room] = roomInfo{
first: s.rooms.rooms[room].first,
2019-04-27 18:20:03 +02:00
second: c,
2019-04-30 01:29:36 +02:00
opened: s.rooms.rooms[room].opened,
2019-04-27 18:20:03 +02:00
full: true,
}
2019-04-30 01:29:36 +02:00
otherConnection := s.rooms.rooms[room].first
s.rooms.Unlock()
2018-09-23 21:34:29 +02:00
// second connection is the sender, time to staple connections
var wg sync.WaitGroup
wg.Add(1)
// start piping
2019-04-29 22:06:18 +02:00
go func(com1, com2 *comm.Comm, wg *sync.WaitGroup) {
2018-09-23 21:34:29 +02:00
log.Debug("starting pipes")
pipe(com1.Connection(), com2.Connection())
wg.Done()
log.Debug("done piping")
2019-04-27 18:20:03 +02:00
}(otherConnection, c, &wg)
2018-09-23 21:34:29 +02:00
// tell the sender everything is ready
2020-02-28 20:59:56 +01:00
bSend, err = crypt.Encrypt([]byte("ok"), strongKeyForEncryption)
if err != nil {
return
}
err = c.Send(bSend)
2018-09-23 21:34:29 +02:00
if err != nil {
2019-05-01 20:11:20 +02:00
s.deleteRoom(room)
2018-09-23 21:34:29 +02:00
return
}
wg.Wait()
// delete room
2019-05-01 20:11:20 +02:00
s.deleteRoom(room)
2019-11-18 22:09:17 +01:00
return
2019-05-01 20:11:20 +02:00
}
func (s *server) deleteRoom(room string) {
2019-04-30 01:29:36 +02:00
s.rooms.Lock()
2019-05-01 20:11:20 +02:00
defer s.rooms.Unlock()
if _, ok := s.rooms.rooms[room]; !ok {
return
}
2018-09-23 21:34:29 +02:00
log.Debugf("deleting room: %s", room)
2019-05-06 23:56:17 +02:00
if s.rooms.rooms[room].first != nil {
s.rooms.rooms[room].first.Close()
}
if s.rooms.rooms[room].second != nil {
s.rooms.rooms[room].second.Close()
}
2019-04-30 01:29:36 +02:00
s.rooms.rooms[room] = roomInfo{first: nil, second: nil}
delete(s.rooms.rooms, room)
2019-05-01 20:11:20 +02:00
2018-09-23 21:34:29 +02:00
}
// chanFromConn creates a channel from a Conn object, and sends everything it
// Read()s from the socket to the channel.
2018-09-26 19:43:38 +02:00
func chanFromConn(conn net.Conn) chan []byte {
2019-04-29 23:46:40 +02:00
c := make(chan []byte, 1)
2020-08-23 01:05:00 +02:00
if err := conn.SetReadDeadline(time.Now().Add(3 * time.Hour)); err != nil {
log.Warnf("can't set read deadline: %v", err)
}
2018-09-23 21:34:29 +02:00
go func() {
2019-04-30 15:57:45 +02:00
b := make([]byte, models.TCP_BUFFER_SIZE)
2018-09-23 21:34:29 +02:00
for {
2018-09-26 18:55:14 +02:00
n, err := conn.Read(b)
2018-09-26 15:36:47 +02:00
if n > 0 {
2018-09-26 18:14:24 +02:00
res := make([]byte, n)
// Copy the buffer so it doesn't get changed while read by the recipient.
copy(res, b[:n])
c <- res
2018-09-26 15:36:47 +02:00
}
2018-09-23 21:34:29 +02:00
if err != nil {
2018-10-13 15:09:55 +02:00
log.Debug(err)
2018-09-23 21:34:29 +02:00
c <- nil
break
}
}
2019-04-29 23:46:40 +02:00
log.Debug("exiting")
2018-09-23 21:34:29 +02:00
}()
return c
}
// pipe creates a full-duplex pipe between the two sockets and
// transfers data from one to the other.
2018-09-26 19:43:38 +02:00
func pipe(conn1 net.Conn, conn2 net.Conn) {
2018-09-23 21:34:29 +02:00
chan1 := chanFromConn(conn1)
2018-09-26 23:31:45 +02:00
chan2 := chanFromConn(conn2)
2018-09-23 21:34:29 +02:00
for {
2018-09-26 23:31:45 +02:00
select {
case b1 := <-chan1:
if b1 == nil {
return
}
2020-08-23 01:05:00 +02:00
if _, err := conn2.Write(b1); err != nil {
log.Errorf("write error on channel 1: %v", err)
}
2018-09-26 18:41:12 +02:00
2018-09-26 23:31:45 +02:00
case b2 := <-chan2:
if b2 == nil {
return
}
2020-08-23 01:05:00 +02:00
if _, err := conn1.Write(b2); err != nil {
log.Errorf("write error on channel 2: %v", err)
}
2018-09-26 23:31:45 +02:00
}
2018-09-23 21:34:29 +02:00
}
}
2019-04-30 04:20:03 +02:00
2020-10-22 19:09:04 +02:00
func PingServer(address string) (err error) {
c, err := comm.NewConnection(address, 200*time.Millisecond)
if err != nil {
return
}
err = c.Send([]byte("ping"))
if err != nil {
return
}
b, err := c.Receive()
if err != nil {
return
}
if bytes.Equal(b, []byte("pong")) {
return nil
}
return fmt.Errorf("no pong")
}
2019-09-07 18:46:04 +02:00
// ConnectToTCPServer will initiate a new connection
// to the specified address, room with optional time limit
2019-11-18 17:16:19 +01:00
func ConnectToTCPServer(address, password, room string, timelimit ...time.Duration) (c *comm.Comm, banner string, ipaddr string, err error) {
if len(timelimit) > 0 {
c, err = comm.NewConnection(address, timelimit[0])
} else {
c, err = comm.NewConnection(address)
}
2019-04-30 00:24:22 +02:00
if err != nil {
return
}
2020-02-28 20:59:56 +01:00
// get PAKE connection with server to establish strong key to transfer info
2021-04-16 23:01:48 +02:00
A, err := pake.InitCurve(weakKey, 0, "siec")
2020-02-28 20:59:56 +01:00
if err != nil {
return
}
err = c.Send(A.Bytes())
if err != nil {
return
}
Bbytes, err := c.Receive()
if err != nil {
return
}
err = A.Update(Bbytes)
if err != nil {
return
}
strongKey, err := A.SessionKey()
if err != nil {
return
}
log.Debugf("strong key: %x", strongKey)
strongKeyForEncryption, salt, err := crypt.New(strongKey, nil)
2021-03-10 01:48:38 +01:00
if err != nil {
return
}
2020-02-28 20:59:56 +01:00
// send salt
err = c.Send(salt)
if err != nil {
return
}
2019-11-18 17:16:19 +01:00
log.Debug("sending password")
2020-02-28 20:59:56 +01:00
bSend, err := crypt.Encrypt([]byte(password), strongKeyForEncryption)
if err != nil {
return
}
err = c.Send(bSend)
2019-11-18 17:16:19 +01:00
if err != nil {
return
}
2019-05-01 19:45:13 +02:00
log.Debug("waiting for first ok")
2020-02-28 20:59:56 +01:00
enc, err := c.Receive()
if err != nil {
return
}
data, err := crypt.Decrypt(enc, strongKeyForEncryption)
2019-04-30 00:24:22 +02:00
if err != nil {
return
}
2019-11-18 17:16:19 +01:00
if !strings.Contains(string(data), "|||") {
err = fmt.Errorf("bad response: %s", string(data))
return
}
2019-05-02 01:10:02 +02:00
banner = strings.Split(string(data), "|||")[0]
ipaddr = strings.Split(string(data), "|||")[1]
2019-05-01 19:45:13 +02:00
log.Debug("sending room")
2020-02-28 20:59:56 +01:00
bSend, err = crypt.Encrypt([]byte(room), strongKeyForEncryption)
if err != nil {
return
}
err = c.Send(bSend)
2019-04-30 00:24:22 +02:00
if err != nil {
return
}
2019-05-01 19:45:13 +02:00
log.Debug("waiting for room confirmation")
2020-02-28 20:59:56 +01:00
enc, err = c.Receive()
if err != nil {
return
}
data, err = crypt.Decrypt(enc, strongKeyForEncryption)
2019-04-30 00:24:22 +02:00
if err != nil {
return
}
if !bytes.Equal(data, []byte("ok")) {
err = fmt.Errorf("got bad response: %s", data)
return
}
2019-05-01 19:45:13 +02:00
log.Debug("all set")
2019-04-30 00:24:22 +02:00
return
}