From 081d88b9ade1551949cbb24f7b3692a66dbb4be4 Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Wed, 31 Oct 2018 20:11:00 -0700 Subject: [PATCH] tunnel setup stubs moved into Conn Read()/Write() handling --- hkexnet/hkexnet.go | 51 ++++--- hkexnet/hkextun.go | 350 +++++++++++++++++++++++---------------------- hkexsh/hkexsh.go | 29 ++-- 3 files changed, 222 insertions(+), 208 deletions(-) diff --git a/hkexnet/hkexnet.go b/hkexnet/hkexnet.go index e804481..073ba16 100644 --- a/hkexnet/hkexnet.go +++ b/hkexnet/hkexnet.go @@ -85,7 +85,7 @@ type ( Cols uint16 chaff ChaffConfig - tuns map[uint16]chan []byte + tuns map[uint16]*TunEndpoint closeStat *CSOType // close status (CSOExitStatus) r cipher.Stream //read cipherStream @@ -811,12 +811,16 @@ func (hc Conn) Read(b []byte) (n int, err error) { } hc.Close() } else if ctrlStatOp == CSOTunSetup { - // Client wants a tunnel set up - args [lport:rport] + // server side tunnel setup in response to client lport := binary.BigEndian.Uint16(payloadBytes) rport := binary.BigEndian.Uint16(payloadBytes[2:4]) - // spawn workers to listen for data and tunnel events - // via channel comms to hc.tuns[rport].tunCtl - startServerTunnel(&hc, lport, rport) + log.Printf("Tunnel setup [%d:%d]\r\n", lport, rport) + StartServerTunnel(&hc, lport, rport) + } else if ctrlStatOp == CSOTunSetupAck { + // client side has received ack from server + lport := binary.BigEndian.Uint16(payloadBytes) + rport := binary.BigEndian.Uint16(payloadBytes[2:4]) + log.Printf("Tunnel ack [%d:%d]\r\n", lport, rport) } else if ctrlStatOp == CSOTunData { lport := binary.BigEndian.Uint16(payloadBytes) rport := binary.BigEndian.Uint16(payloadBytes[2:4]) @@ -825,16 +829,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { if hc.tuns[rport] == nil { fmt.Printf("[Invalid rport:%d]\r\n", rport) } else { - hc.tuns[rport] <- payloadBytes[4:] - } - //fmt.Printf("[Done stuffing hc.tuns[rport]\n") - } else if ctrlStatOp == CSOTunClose { - lport := binary.BigEndian.Uint16(payloadBytes) - rport := binary.BigEndian.Uint16(payloadBytes[2:4]) - fmt.Printf("[Got CSOTunClose: [lport %d:rport %d]\r\n", lport, rport) - if hc.tuns[rport] != nil { - close(hc.tuns[rport]) - hc.tuns[rport] = nil + hc.tuns[rport].Data <- payloadBytes[4:] } } else { hc.dBuf.Write(payloadBytes) @@ -876,8 +871,8 @@ func (hc Conn) Write(b []byte) (n int, err error) { return n, err } -// Write a byte slice with specified ctrlStatusOp byte -func (hc *Conn) WritePacket(b []byte, op byte) (n int, err error) { +// Write a byte slice with specified ctrlStatOp byte +func (hc *Conn) WritePacket(b []byte, ctrlStatOp byte) (n int, err error) { //log.Printf("[Encrypting...]\r\n") var hmacOut []uint8 var payloadLen uint32 @@ -886,7 +881,26 @@ func (hc *Conn) WritePacket(b []byte, op byte) (n int, err error) { return 0, errors.New("Secure chan not ready for writing") } - //Padding + if ctrlStatOp == CSOTunSetup { + // Client-side tunnel setup + lport := binary.BigEndian.Uint16(b) + rport := binary.BigEndian.Uint16(b[2:4]) + // spawn workers to listen for data and tunnel events + // via channel comms to hc.tuns[rport].tunCtl + StartClientTunnel(hc, lport, rport) + // CSOTunSetup is written through to server side, + // see hc.Read() + } else if ctrlStatOp == CSOTunSetupAck { + lport := binary.BigEndian.Uint16(b) + rport := binary.BigEndian.Uint16(b[2:4]) + if lport == 0 || rport == 0 { + log.Printf("Responded with tunnel setup nak [%d:%d]\r\n", lport, rport) + } else { + log.Printf("Responded with tunnel setup ack [%d:%d]\r\n", lport, rport) + } + } + + //Padding prior to encryption padSz := (rand.Intn(PAD_SZ) / 2) + (PAD_SZ / 2) padLen := padSz - ((len(b) + padSz) % padSz) if padLen == padSz { @@ -938,7 +952,6 @@ func (hc *Conn) WritePacket(b []byte, op byte) (n int, err error) { } log.Printf(" ->ctext:\r\n%s\r\n", hex.Dump(wb.Bytes())) - ctrlStatOp := op err = binary.Write(*hc.c, binary.BigEndian, &ctrlStatOp) if err == nil { // Write hmac LSB, payloadLen followed by payload diff --git a/hkexnet/hkextun.go b/hkexnet/hkextun.go index 259324c..2ab15a4 100644 --- a/hkexnet/hkextun.go +++ b/hkexnet/hkextun.go @@ -11,12 +11,11 @@ package hkexnet import ( "bytes" "encoding/binary" - "fmt" - "io" - "log" + //"fmt" + //"io" + //"log" "net" - - "blitter.com/go/hkexsh/logger" + //"blitter.com/go/hkexsh/logger" ) type ( @@ -40,10 +39,11 @@ type ( // 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 - tunCtl chan<- rune //See TunCtl_* consts + Rport uint16 // Names are from client's perspective + Lport uint16 // ... ie., RPort is on server, LPort is on client + Peer string //net.Addr + Ctl chan<- rune //See TunCtl_* consts + Data chan []byte } TunPacket struct { @@ -52,178 +52,190 @@ type ( } ) -func startServerTunnel(hc *Conn, lport, rport uint16) { +func StartClientTunnel(hc *Conn, lport, rport uint16) { if hc.tuns == nil { - hc.tuns = make(map[uint16]chan []byte) + hc.tuns = make(map[uint16]*TunEndpoint) } if hc.tuns[rport] == nil { - hc.tuns[rport] = make(chan []byte, 32) + addrs, _ := net.InterfaceAddrs() + hc.tuns[rport] = &TunEndpoint{Peer: addrs[0].String(), + Lport: lport, Rport: rport, Ctl: make(chan<- rune)} } - addrs, _ := net.InterfaceAddrs() - t := TunEndpoint{Peer: addrs[0].String(), Lport: lport, Rport: rport} - var resp bytes.Buffer - binary.Write(&resp, binary.BigEndian, t.Lport) + /* + go func() { - //var dialHangup chan<- bool + 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() - 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) - } - } + defer func() { + //if hc.tuns[rport] != nil { + // close(hc.tuns[rport]) + // hc.tuns[rport] = nil + //} + c.Close() }() - // tunnel lport -> outside client (c) - go func() { - 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) + } + } }() - 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?]\n") - //break - } - } - }() + // 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?]\n") + //break + } + } + }() + + } } } - } - }() + }() + */ +} + +func StartServerTunnel(hc *Conn, lport, rport uint16) { + if hc.tuns == nil { + hc.tuns = make(map[uint16]*TunEndpoint) + } + if hc.tuns[rport] == nil { + addrs, _ := net.InterfaceAddrs() + hc.tuns[rport] = &TunEndpoint{Peer: addrs[0].String(), + Lport: lport, Rport: rport, Ctl: make(chan<- rune)} + } + + // Inform client of the tunPort + var resp bytes.Buffer + binary.Write(&resp, binary.BigEndian, hc.tuns[rport].Lport) + binary.Write(&resp, binary.BigEndian, hc.tuns[rport].Rport) + hc.WritePacket(resp.Bytes(), CSOTunSetupAck) + + /* + 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 + } + } + }() + + } + */ } diff --git a/hkexsh/hkexsh.go b/hkexsh/hkexsh.go index 43a4afd..727ef65 100755 --- a/hkexsh/hkexsh.go +++ b/hkexsh/hkexsh.go @@ -340,24 +340,18 @@ func rejectUserMsg() string { // Transmit request to server for it to set up the remote end of a tunnel // // Server responds with [CSOTunAck:rport] or [CSOTunRefused:rport] -func requestTunnel(hc *hkexnet.Conn, lp uint16, p string /*net.Addr*/, rp uint16) (t hkexnet.TunEndpoint) { +// (handled in hkexnet.Read()) +func reqTunnel(hc *hkexnet.Conn, lp uint16, p string /*net.Addr*/, rp uint16) { + // Write request to server so it can attempt to set up its end var bTmp bytes.Buffer binary.Write(&bTmp, binary.BigEndian, lp) binary.Write(&bTmp, binary.BigEndian, rp) - hc.WritePacket(bTmp.Bytes(), hkexnet.CSOTunReq) + hc.WritePacket(bTmp.Bytes(), hkexnet.CSOTunSetup) + // hkexnet.WritePacket() handles processing of client side tun setup, + // calling hkexnet.StartClientTunnel() - // Server should reply immediately with success (lport:rport) or - // refusal (lport:0) - var lportReply, rportReply uint16 - errL := binary.Read(hc, binary.BigEndian, &lportReply) - errR := binary.Read(hc, binary.BigEndian, &rportReply) - if errL == nil && errR == nil { - fmt.Printf("Server established tunnel [%d:%d]\r\n", lportReply, rportReply) - hkexnet.StartClientTunnel(hc, lp, rp) - } else { - fmt.Println("FAILED reading remPort") - } - t = hkexnet.TunEndpoint{Lport: lportReply, Peer: p, Rport: rportReply} + // Server should reply immediately with CSOTunSetupAck[lport:rport] + // hkexnet.Read() on server side handles server side tun setup. return } @@ -648,12 +642,7 @@ func main() { if shellMode { // TESTING - tunnel remAddrs, _ := net.LookupHost(remoteHost) - t := requestTunnel(&conn, 6001, remAddrs[0], 7001) - _ = t - //t := hkexnet.TunEndpoint{DataPort: 6001, Peer: nil, TunPort: 7001} - //var bTmp bytes.Buffer - //binary.Write(&bTmp, binary.BigEndian, t.DataPort) - //conn.WritePacket(bTmp.Bytes(), hkexnet.CSOTunReq) + reqTunnel(&conn, 6001, remAddrs[0], 7001) // END TESTING - tunnel doShellMode(isInteractive, &conn, oldState, rec)