mirror of https://gogs.blitter.com/RLabs/xs
Cleaned up error handling in hkexnet.Conn.Read() a bit
This commit is contained in:
parent
e75ed159f6
commit
fcbdb77c79
|
@ -685,10 +685,8 @@ func (hl *HKExListener) Accept() (hc Conn, err error) {
|
||||||
//
|
//
|
||||||
// See go doc io.Reader
|
// See go doc io.Reader
|
||||||
func (hc Conn) Read(b []byte) (n int, err error) {
|
func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
//log.Printf("[Decrypting...]\r\n")
|
|
||||||
for {
|
for {
|
||||||
//log.Printf("hc.dBuf.Len(): %d\n", hc.dBuf.Len())
|
if hc.dBuf.Len() > 0 {
|
||||||
if hc.dBuf.Len() > 0 /* len(b) */ {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -698,31 +696,52 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
|
|
||||||
// Read ctrl/status opcode (CSOHmacInvalid on hmac mismatch)
|
// Read ctrl/status opcode (CSOHmacInvalid on hmac mismatch)
|
||||||
err = binary.Read(*hc.c, binary.BigEndian, &ctrlStatOp)
|
err = binary.Read(*hc.c, binary.BigEndian, &ctrlStatOp)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() == "EOF" {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
||||||
|
logger.LogNotice(fmt.Sprintln("[Client hung up]"))
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
etxt := fmt.Sprintf("** Failed read:%s (%s) **", "ctrlStatOp", err)
|
||||||
|
logger.LogErr(etxt)
|
||||||
|
return 0, errors.New(etxt)
|
||||||
|
}
|
||||||
log.Printf("[ctrlStatOp: %v]\n", ctrlStatOp)
|
log.Printf("[ctrlStatOp: %v]\n", ctrlStatOp)
|
||||||
if ctrlStatOp == CSOHmacInvalid {
|
if ctrlStatOp == CSOHmacInvalid {
|
||||||
// Other side indicated channel tampering, close channel
|
// Other side indicated channel tampering, close channel
|
||||||
hc.Close()
|
hc.Close()
|
||||||
return 1, errors.New("** ALERT - remote end detected HMAC mismatch - possible channel tampering **")
|
return 0, errors.New("** ALERT - remote end detected HMAC mismatch - possible channel tampering **")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the hmac and payload len first
|
// Read the hmac and payload len first
|
||||||
err = binary.Read(*hc.c, binary.BigEndian, &hmacIn)
|
err = binary.Read(*hc.c, binary.BigEndian, &hmacIn)
|
||||||
// Normal client 'exit' from interactive session will cause
|
|
||||||
// (on server side) err.Error() == "<iface/addr info ...>: use of closed network connection"
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF || strings.HasSuffix(err.Error(), "use of closed network connection") {
|
if err.Error() == "EOF" {
|
||||||
logger.LogNotice(fmt.Sprintln("[Client hung up]"))
|
return 0, io.EOF
|
||||||
} else {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
}
|
||||||
return 0, err
|
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
||||||
|
logger.LogNotice(fmt.Sprintln("[Client hung up]"))
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
etxt := fmt.Sprintf("** Failed read:%s (%s) **", "HMAC", err)
|
||||||
|
logger.LogErr(etxt)
|
||||||
|
return 0, errors.New(etxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = binary.Read(*hc.c, binary.BigEndian, &payloadLen)
|
err = binary.Read(*hc.c, binary.BigEndian, &payloadLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() != "EOF" {
|
if err.Error() == "EOF" {
|
||||||
logger.LogErr(fmt.Sprintln("[2]unexpected Read() err:", err))
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
|
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
||||||
|
logger.LogNotice(fmt.Sprintln("[Client hung up]"))
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
etxt := fmt.Sprintf("** Failed read:%s (%s) **", "payloadLen", err)
|
||||||
|
logger.LogErr(etxt)
|
||||||
|
return 0, errors.New(etxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
if payloadLen > MAX_PAYLOAD_LEN {
|
if payloadLen > MAX_PAYLOAD_LEN {
|
||||||
|
@ -733,15 +752,17 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
|
|
||||||
var payloadBytes = make([]byte, payloadLen)
|
var payloadBytes = make([]byte, payloadLen)
|
||||||
n, err = io.ReadFull(*hc.c, payloadBytes)
|
n, err = io.ReadFull(*hc.c, payloadBytes)
|
||||||
|
if err != nil {
|
||||||
// Normal client 'exit' from interactive session will cause
|
if err.Error() == "EOF" {
|
||||||
// (on server side) err.Error() == "<iface/addr info ...>: use of closed network connection"
|
return 0, io.EOF
|
||||||
if err != nil && err.Error() != "EOF" {
|
|
||||||
if !strings.HasSuffix(err.Error(), "use of closed network connection") {
|
|
||||||
logger.LogErr(fmt.Sprintln("[3]unexpected Read() err:", err))
|
|
||||||
} else {
|
|
||||||
logger.LogNotice(fmt.Sprintln("[Client hung up]"))
|
|
||||||
}
|
}
|
||||||
|
if strings.HasSuffix(err.Error(), "use of closed network connection") {
|
||||||
|
logger.LogNotice(fmt.Sprintln("[Client hung up]"))
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
etxt := fmt.Sprintf("** Failed read:%s (%s) **", "payloadBytes", err)
|
||||||
|
logger.LogErr(etxt)
|
||||||
|
return 0, errors.New(etxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf(" <:ctext:\r\n%s\r\n", hex.Dump(payloadBytes[:n]))
|
log.Printf(" <:ctext:\r\n%s\r\n", hex.Dump(payloadBytes[:n]))
|
||||||
|
@ -797,19 +818,21 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
} else if ctrlStatOp == CSOTunData {
|
} else if ctrlStatOp == CSOTunData {
|
||||||
lport := binary.BigEndian.Uint16(payloadBytes)
|
lport := binary.BigEndian.Uint16(payloadBytes)
|
||||||
rport := binary.BigEndian.Uint16(payloadBytes[2:4])
|
rport := binary.BigEndian.Uint16(payloadBytes[2:4])
|
||||||
fmt.Printf("[Got CSOTunData: [lport %d:rport %d] data:%v\n", lport, rport, payloadBytes[4:])
|
_ = lport
|
||||||
|
//fmt.Printf("[Got CSOTunData: [lport %d:rport %d] data:%v\n", lport, rport, payloadBytes[4:])
|
||||||
if hc.tuns[rport] == nil {
|
if hc.tuns[rport] == nil {
|
||||||
fmt.Printf("[Invalid rport:%d]\n", rport)
|
fmt.Printf("[Invalid rport:%d]\r\n", rport)
|
||||||
} else {
|
} else {
|
||||||
hc.tuns[rport] <- payloadBytes[4:]
|
hc.tuns[rport] <- payloadBytes[4:]
|
||||||
}
|
}
|
||||||
fmt.Printf("[Done stuffing hc.tuns[rport]\n")
|
//fmt.Printf("[Done stuffing hc.tuns[rport]\n")
|
||||||
} else if ctrlStatOp == CSOTunClose {
|
} else if ctrlStatOp == CSOTunClose {
|
||||||
lport := binary.BigEndian.Uint16(payloadBytes)
|
lport := binary.BigEndian.Uint16(payloadBytes)
|
||||||
rport := binary.BigEndian.Uint16(payloadBytes[2:4])
|
rport := binary.BigEndian.Uint16(payloadBytes[2:4])
|
||||||
fmt.Printf("[Got CSOTunClose: [lport %d:rport %d]\n", lport, rport)
|
fmt.Printf("[Got CSOTunClose: [lport %d:rport %d]\r\n", lport, rport)
|
||||||
if hc.tuns[rport] != nil {
|
if hc.tuns[rport] != nil {
|
||||||
close(hc.tuns[rport])
|
close(hc.tuns[rport])
|
||||||
|
hc.tuns[rport] = nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hc.dBuf.Write(payloadBytes)
|
hc.dBuf.Write(payloadBytes)
|
||||||
|
|
|
@ -0,0 +1,228 @@
|
||||||
|
// hkextun.go - Tunnel setup using an established hkexnet.Conn
|
||||||
|
|
||||||
|
// Copyright (c) 2017-2018 Russell Magee
|
||||||
|
// Licensed under the terms of the MIT license (see LICENSE.mit in this
|
||||||
|
// distribution)
|
||||||
|
//
|
||||||
|
// golang implementation by Russ Magee (rmagee_at_gmail.com)
|
||||||
|
|
||||||
|
package hkexnet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"blitter.com/go/hkexsh/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Tunnels
|
||||||
|
// --
|
||||||
|
// 1. client is given (lport, remhost, rport) by local user
|
||||||
|
// 2. client sends [CSOTunReq:rport] to server
|
||||||
|
// client=> [CSOTunReq:rport] =>remhost
|
||||||
|
//
|
||||||
|
// remhost starts worker to receive/send data using rport
|
||||||
|
// remhost replies to client with rport to acknowledge tun is ready
|
||||||
|
// client<= [CSOTunAck:rport] <=remhost
|
||||||
|
// ... or if rhost rport refuses connection, sends
|
||||||
|
// [CSOTunRefused:rport]
|
||||||
|
//
|
||||||
|
// client starts worker to receive/send data using lport
|
||||||
|
// ... client disconnects: sends remhost [CSOTunClose:rport]
|
||||||
|
// ... or server disconnects: sends client [CSOTunClose:lport]
|
||||||
|
// server at any time sends [CSOTunRefused:rport] if daemon died
|
||||||
|
// --
|
||||||
|
|
||||||
|
// TunEndpoint [securePort:peer:dataPort]
|
||||||
|
TunEndpoint struct {
|
||||||
|
Rport uint16 // Names are from client's perspective
|
||||||
|
Lport uint16 // ... ie., RPort is on server, LPort is on client
|
||||||
|
Peer string //net.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
TunPacket struct {
|
||||||
|
n uint32
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func startServerTunnel(hc *Conn, lport, rport uint16) {
|
||||||
|
if hc.tuns == nil {
|
||||||
|
hc.tuns = make(map[uint16]chan []byte)
|
||||||
|
}
|
||||||
|
if hc.tuns[rport] == nil {
|
||||||
|
hc.tuns[rport] = make(chan []byte, 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
addrs, _ := net.InterfaceAddrs()
|
||||||
|
t := TunEndpoint{Peer: addrs[0].String(), Lport: lport, Rport: rport}
|
||||||
|
var resp bytes.Buffer
|
||||||
|
binary.Write(&resp, binary.BigEndian, t.Lport)
|
||||||
|
|
||||||
|
//var dialHangup chan<- bool
|
||||||
|
|
||||||
|
c, err := net.Dial("tcp", fmt.Sprintf(":%d", rport))
|
||||||
|
if err != nil {
|
||||||
|
logger.LogErr(fmt.Sprintf("Nothing is serving at rport :%d!", rport))
|
||||||
|
binary.Write(&resp, binary.BigEndian, uint16(0))
|
||||||
|
// Inform client of the tunPort
|
||||||
|
hc.WritePacket(resp.Bytes(), CSOTunRefused)
|
||||||
|
} else {
|
||||||
|
binary.Write(&resp, binary.BigEndian, t.Rport)
|
||||||
|
logger.LogNotice(fmt.Sprintf("[Tunnel Opened - %d:%s:%d]", t.Lport, t.Peer, t.Rport))
|
||||||
|
|
||||||
|
//
|
||||||
|
// worker to read data from the rport (to encrypt & send to client)
|
||||||
|
//
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
//if hc.tuns[rport] != nil {
|
||||||
|
// close(hc.tuns[rport])
|
||||||
|
// hc.tuns[rport] = nil
|
||||||
|
//}
|
||||||
|
c.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
var tunDst bytes.Buffer
|
||||||
|
binary.Write(&tunDst, binary.BigEndian, t.Lport)
|
||||||
|
binary.Write(&tunDst, binary.BigEndian, t.Rport)
|
||||||
|
for {
|
||||||
|
rBuf := make([]byte, 1024)
|
||||||
|
// Read data from c, encrypt/write via hc to client(lport)
|
||||||
|
n, e := c.Read(rBuf)
|
||||||
|
if e != nil {
|
||||||
|
if e == io.EOF {
|
||||||
|
logger.LogNotice(fmt.Sprintf("rport Disconnected: shutting down tunnel %v\n", t))
|
||||||
|
} else {
|
||||||
|
logger.LogErr(fmt.Sprintf("Read error from rport of tun %v\n%s", t, e))
|
||||||
|
}
|
||||||
|
hc.WritePacket(resp.Bytes(), CSOTunClose)
|
||||||
|
fmt.Printf("Closing server rport net.Dial()\n")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
rBuf = append(tunDst.Bytes(), rBuf[:n]...)
|
||||||
|
logger.LogNotice(fmt.Sprintf("Got rport data:%v", tunDst.Bytes()))
|
||||||
|
hc.WritePacket(rBuf[:n+4], CSOTunData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// worker to read data from client (already decrypted) & fwd to rport
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
//if hc.tuns[rport] != nil {
|
||||||
|
//close(hc.tuns[rport])
|
||||||
|
//hc.tuns[rport] = nil
|
||||||
|
//}
|
||||||
|
c.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
rData, ok := <-hc.tuns[rport]
|
||||||
|
if ok {
|
||||||
|
logger.LogNotice(fmt.Sprintf("Got client data:%v", rData))
|
||||||
|
c.Write(rData)
|
||||||
|
} else {
|
||||||
|
logger.LogErr("!!! ERROR reading from hc.tuns[] channel !!!")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Inform client of the tunPort
|
||||||
|
hc.WritePacket(resp.Bytes(), CSOTunAck)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func StartClientTunnel(hc *Conn, lport, rport uint16) {
|
||||||
|
go func() {
|
||||||
|
if hc.tuns == nil {
|
||||||
|
hc.tuns = make(map[uint16]chan []byte)
|
||||||
|
}
|
||||||
|
if hc.tuns[rport] == nil {
|
||||||
|
hc.tuns[rport] = make(chan []byte, 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
l, e := net.Listen("tcp", fmt.Sprintf(":%d", lport))
|
||||||
|
if e != nil {
|
||||||
|
fmt.Printf("[Could not get lport %d! (%s)\n", lport, e)
|
||||||
|
} else {
|
||||||
|
defer l.Close()
|
||||||
|
for {
|
||||||
|
c, e := l.Accept()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
//if hc.tuns[rport] != nil {
|
||||||
|
// close(hc.tuns[rport])
|
||||||
|
// hc.tuns[rport] = nil
|
||||||
|
//}
|
||||||
|
c.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if e != nil {
|
||||||
|
log.Printf("Accept() got error(%v), hanging up.\n", e)
|
||||||
|
break
|
||||||
|
//log.Fatal(err)
|
||||||
|
} else {
|
||||||
|
log.Println("Accepted client")
|
||||||
|
|
||||||
|
// outside client -> tunnel lport
|
||||||
|
go func() {
|
||||||
|
var tunDst bytes.Buffer
|
||||||
|
binary.Write(&tunDst, binary.BigEndian, lport)
|
||||||
|
binary.Write(&tunDst, binary.BigEndian, rport)
|
||||||
|
for {
|
||||||
|
rBuf := make([]byte, 1024)
|
||||||
|
//Read data from c, encrypt/write via hc to client(lport)
|
||||||
|
n, e := c.Read(rBuf)
|
||||||
|
if e != nil {
|
||||||
|
if e == io.EOF {
|
||||||
|
logger.LogNotice(fmt.Sprintf("lport Disconnected: shutting down tunnel [%d:%d]\n", lport, rport))
|
||||||
|
} else {
|
||||||
|
logger.LogErr(fmt.Sprintf("Read error from lport of tun [%d:%d]\n%s", lport, rport, e))
|
||||||
|
}
|
||||||
|
hc.WritePacket(tunDst.Bytes(), CSOTunClose)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
rBuf = append(tunDst.Bytes(), rBuf[:n]...)
|
||||||
|
logger.LogNotice(fmt.Sprintf("Got lport data:%v\n", tunDst.Bytes()))
|
||||||
|
hc.WritePacket(rBuf[:n+4], CSOTunData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// tunnel lport -> outside client (c)
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
//if hc.tuns[rport] != nil {
|
||||||
|
// close(hc.tuns[rport])
|
||||||
|
// hc.tuns[rport] = nil
|
||||||
|
//}
|
||||||
|
c.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
//fmt.Printf("Reading from client hc.tuns[%d]\n", lport)
|
||||||
|
bytes, ok := <-hc.tuns[rport]
|
||||||
|
if ok {
|
||||||
|
//fmt.Printf("[Got this through tunnel:%v]\n", bytes)
|
||||||
|
c.Write(bytes)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("[Channel closed? exiting client worker!]\n")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
|
@ -352,7 +352,7 @@ func requestTunnel(hc *hkexnet.Conn, lp uint16, p string /*net.Addr*/, rp uint16
|
||||||
errL := binary.Read(hc, binary.BigEndian, &lportReply)
|
errL := binary.Read(hc, binary.BigEndian, &lportReply)
|
||||||
errR := binary.Read(hc, binary.BigEndian, &rportReply)
|
errR := binary.Read(hc, binary.BigEndian, &rportReply)
|
||||||
if errL == nil && errR == nil {
|
if errL == nil && errR == nil {
|
||||||
fmt.Printf("Server established tunnel [%d:%d]\n", lportReply, rportReply)
|
fmt.Printf("Server established tunnel [%d:%d]\r\n", lportReply, rportReply)
|
||||||
hkexnet.StartClientTunnel(hc, lp, rp)
|
hkexnet.StartClientTunnel(hc, lp, rp)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("FAILED reading remPort")
|
fmt.Println("FAILED reading remPort")
|
||||||
|
|
Loading…
Reference in New Issue