diff --git a/hkexnet/consts.go b/hkexnet/consts.go index 7ed1c3b..176b82f 100644 --- a/hkexnet/consts.go +++ b/hkexnet/consts.go @@ -7,6 +7,10 @@ // golang implementation by Russ Magee (rmagee_at_gmail.com) package hkexnet +// KEX algorithm values +// +// Specified (in string form) as the extensions parameter +// to hkexnet.Dial() const ( KEX_HERRADURA256 = iota // this MUST be first for default if omitted in ctor KEX_HERRADURA512 @@ -21,13 +25,13 @@ const ( KEX_KYBER1024 KEX_resvd11 KEX_NEWHOPE - KEX_NEWHOPE_SIMPLE // 'NewHopeLP-Simple' - https://eprint.iacr.org/2016/1157 + KEX_NEWHOPE_SIMPLE // 'NewHopeLP-Simple' - https://eprint.iacr.org/2016/1157 KEX_resvd14 KEX_resvd15 ) // Sent from client to server in order to specify which -// algo shall be used (eg., HerraduraKEx, [TODO: others...]) +// algo shall be used (see hkexnet.KEX_HERRADURA256, ...) type KEXAlg uint8 // Extended exit status codes - indicate comm/pty issues @@ -63,8 +67,8 @@ const ( CSOTunHangup // client -> server: tunnel lport hung up ) -// TunEndpoint.tunCtl control values - used to control workers for client or server tunnels -// depending on the code +// TunEndpoint.tunCtl control values - used to control workers for client +// or server tunnels depending on the code const ( TunCtl_Client_Listen = 'a' // [CSOTunAccept] @@ -77,12 +81,13 @@ const ( // action:server side should dial() rport on client's behalf ) -// Channel status Op byte type +// Channel status Op byte type (see CSONone, ... and CSENone, ...) type CSOType uint32 //TODO: this should be small (max unfragmented packet size?) const MAX_PAYLOAD_LEN = 4*1024*1024*1024 - 1 +// Session symmetric crypto algs const ( CAlgAES256 = iota CAlgTwofish128 // golang.org/x/crypto/twofish @@ -94,11 +99,12 @@ const ( // Available ciphers for hkex.Conn type CSCipherAlg uint32 +// Session packet auth HMAC algs const ( HmacSHA256 = iota HmacSHA512 HmacNoneDisallowed ) -// Available HMACs for hkex.Conn (TODO: not currently used) +// Available HMACs for hkex.Conn type CSHmacAlg uint32 diff --git a/hkexnet/hkexnet.go b/hkexnet/hkexnet.go index caa834b..494568e 100644 --- a/hkexnet/hkexnet.go +++ b/hkexnet/hkexnet.go @@ -9,13 +9,12 @@ package hkexnet -// TODO: -// If key exchange algs other than the experimental HerraduraKEx are to -// be supported, the Dial() and Accept() methods should take a kex param, -// specifying which to use; and the client/server negotiation must then -// prefix the channel setup with this param over the wire in order to decide -// which is in use. -// +// Implementation of HKEx-wrapped versions of the golang standard +// net package interfaces, allowing clients and servers to simply replace +// 'net.Dial' and 'net.Listen' with 'hkex.Dial' and 'hkex.Listen' +// (though some extra methods are implemented and must be used +// for things outside of the scope of plain sockets). + // DESIGN PRINCIPLE: There shall be no protocol features which enable // downgrade attacks. The server shall have final authority to accept or // reject any and all proposed KEx and connection parameters proposed by @@ -23,11 +22,6 @@ package hkexnet // with possibly a status code sent so client can determine why connection // was denied (compare to how failed auth is communicated to client). -// Implementation of HKEx-wrapped versions of the golang standard -// net package interfaces, allowing clients and servers to simply replace -// 'net.Dial' and 'net.Listen' with 'hkex.Dial' and 'hkex.Listen' -// (though some extra methods are implemented and must be used -// for things outside of the scope of plain sockets). import ( "bytes" "crypto/cipher" @@ -173,42 +167,6 @@ func (hc *Conn) SetOpts(opts uint32) { hc.opts = opts } -func getkexalgnum(extensions ...string) (k KEXAlg) { - k = KEX_HERRADURA256 // default - for _, s := range extensions { - switch s { - case "KEX_HERRADURA256": - k = KEX_HERRADURA256 - break //out of for - case "KEX_HERRADURA512": - k = KEX_HERRADURA512 - break //out of for - case "KEX_HERRADURA1024": - k = KEX_HERRADURA1024 - break //out of for - case "KEX_HERRADURA2048": - k = KEX_HERRADURA2048 - break //out of for - case "KEX_KYBER512": - k = KEX_KYBER512 - break //out of for - case "KEX_KYBER768": - k = KEX_KYBER768 - break //out of for - case "KEX_KYBER1024": - k = KEX_KYBER1024 - break //out of for - case "KEX_NEWHOPE": - k = KEX_NEWHOPE - break //out of for - case "KEX_NEWHOPE_SIMPLE": - k = KEX_NEWHOPE_SIMPLE - break //out of for - } - } - return -} - // Return a new hkexnet.Conn // // Note this is internal: use Dial() or Accept() @@ -253,6 +211,26 @@ func _new(kexAlg KEXAlg, conn *net.Conn) (hc *Conn, e error) { return } +// applyConnExtensions processes optional Dial() negotiation +// parameters. See also getkexalgnum(). +// +// Currently defined extension values +// +// KEx algs +// +// KEX_HERRADURA256 KEX_HERRADURA512 KEX_HERRADURA1024 KEX_HERRADURA2048 +// +// KEX_KYBER512 KEX_KYBER768 KEX_KYBER1024 +// +// KEX_NEWHOPE KEX_NEWHOPE_SIMPLE +// +// Session (symmetric) crypto +// +// C_AES_256 C_TWOFISH_128 C_BLOWFISH_128 C_CRYPTMT1 +// +// Session HMACs +// +// H_SHA256 H_SHA512 func (hc *Conn) applyConnExtensions(extensions ...string) { for _, s := range extensions { switch s { @@ -286,6 +264,42 @@ func (hc *Conn) applyConnExtensions(extensions ...string) { } } +func getkexalgnum(extensions ...string) (k KEXAlg) { + k = KEX_HERRADURA256 // default + for _, s := range extensions { + switch s { + case "KEX_HERRADURA256": + k = KEX_HERRADURA256 + break //out of for + case "KEX_HERRADURA512": + k = KEX_HERRADURA512 + break //out of for + case "KEX_HERRADURA1024": + k = KEX_HERRADURA1024 + break //out of for + case "KEX_HERRADURA2048": + k = KEX_HERRADURA2048 + break //out of for + case "KEX_KYBER512": + k = KEX_KYBER512 + break //out of for + case "KEX_KYBER768": + k = KEX_KYBER768 + break //out of for + case "KEX_KYBER1024": + k = KEX_KYBER1024 + break //out of for + case "KEX_NEWHOPE": + k = KEX_NEWHOPE + break //out of for + case "KEX_NEWHOPE_SIMPLE": + k = KEX_NEWHOPE_SIMPLE + break //out of for + } + } + return +} + // randReader wraps rand.Read() in a struct that implements io.Reader // for use by the Kyber and NEWHOPE/NEWHOPE_SIMPLE KEM methods. type randReader struct { @@ -302,7 +316,7 @@ func NewHopeDialSetup(c io.ReadWriter, hc *Conn) (err error) { // Alice, step 1: Generate a key pair. r := new(randReader) rand.Seed(time.Now().UnixNano()) - + privKeyAlice, pubKeyAlice, err := newhope.GenerateKeyPairAlice(r) if err != nil { panic(err) @@ -316,8 +330,8 @@ func NewHopeDialSetup(c io.ReadWriter, hc *Conn) (err error) { publicKeyBob := big.NewInt(0) fmt.Fscanf(c, "0x%x\n", publicKeyBob) var pubKeyBob newhope.PublicKeyBob - for i := range(pubKeyBob.Send) { - pubKeyBob.Send[i] = publicKeyBob.Bytes()[i] + for i := range pubKeyBob.Send { + pubKeyBob.Send[i] = publicKeyBob.Bytes()[i] } log.Printf("[Got server pubKey[]:%v]\n", pubKeyBob) @@ -360,8 +374,8 @@ func NewHopeSimpleDialSetup(c io.ReadWriter, hc *Conn) (err error) { publicKeyBob := big.NewInt(0) fmt.Fscanf(c, "0x%x\n", publicKeyBob) var pubKeyBob newhope.PublicKeySimpleBob - for i := range(pubKeyBob.Send) { - pubKeyBob.Send[i] = publicKeyBob.Bytes()[i] + for i := range pubKeyBob.Send { + pubKeyBob.Send[i] = publicKeyBob.Bytes()[i] } log.Printf("[Got server pubKey[]:%v]\n", pubKeyBob) @@ -491,10 +505,10 @@ func NewHopeAcceptSetup(c *net.Conn, hc *Conn) (err error) { } var pubKeyAlice newhope.PublicKeyAlice - for i := range(pubKeyAlice.Send) { - pubKeyAlice.Send[i] = alicePublicKey.Bytes()[i] + for i := range pubKeyAlice.Send { + pubKeyAlice.Send[i] = alicePublicKey.Bytes()[i] } - + _, err = fmt.Fscanf(*c, "0x%x:0x%x\n", &hc.cipheropts, &hc.opts) log.Printf("[Got cipheropts, opts:%v, %v]", hc.cipheropts, hc.opts) @@ -530,10 +544,10 @@ func NewHopeSimpleAcceptSetup(c *net.Conn, hc *Conn) (err error) { } var pubKeyAlice newhope.PublicKeySimpleAlice - for i := range(pubKeyAlice.Send) { - pubKeyAlice.Send[i] = alicePublicKey.Bytes()[i] + for i := range pubKeyAlice.Send { + pubKeyAlice.Send[i] = alicePublicKey.Bytes()[i] } - + _, err = fmt.Fscanf(*c, "0x%x:0x%x\n", &hc.cipheropts, &hc.opts) log.Printf("[Got cipheropts, opts:%v, %v]", hc.cipheropts, hc.opts) @@ -654,11 +668,13 @@ func HKExAcceptSetup(c *net.Conn, hc *Conn) (err error) { // channel on connect // // Can be called like net.Dial(), defaulting to C_AES_256/H_SHA256, -// or additional option arguments can be passed amongst the following: +// or additional extensions can be passed amongst the following: // -// "C_AES_256" | "C_TWOFISH_128" +// "C_AES_256" | "C_TWOFISH_128" | ... // -// "H_SHA256" +// "H_SHA256" | "H_SHA512" | ... +// +// See go doc -u hkexnet.applyConnExtensions func Dial(protocol string, ipport string, extensions ...string) (hc Conn, err error) { if Log == nil { Init(false, "client", logger.LOG_DAEMON|logger.LOG_DEBUG) diff --git a/hkexpasswd/hkexpasswd-vis.gv b/hkexpasswd/hkexpasswd-vis.gv index 95e67c8..380724f 100755 --- a/hkexpasswd/hkexpasswd-vis.gv +++ b/hkexpasswd/hkexpasswd-vis.gv @@ -14,43 +14,43 @@ digraph gocallvis { edge [minlen="2"] subgraph "cluster_focus" { - bgcolor="#e6ecfa"; -label="main"; + label="main"; labelloc="t"; labeljust="c"; fontsize="18"; +bgcolor="#e6ecfa"; "blitter.com/go/hkexsh/hkexpasswd.main" [ fillcolor="lightblue" label="main" penwidth="0.5" ] subgraph "cluster_blitter.com/go/hkexsh" { - style="filled"; -rank="sink"; + label="[hkexsh]"; penwidth="0.8"; +style="filled"; +rank="sink"; +URL="/?f=blitter.com/go/hkexsh"; +tooltip="package: blitter.com/go/hkexsh"; fontsize="16"; fillcolor="lightyellow"; fontname="bold"; -label="[hkexsh]"; -URL="/?f=blitter.com/go/hkexsh"; -tooltip="package: blitter.com/go/hkexsh"; - "blitter.com/go/hkexsh.ReadPassword" [ label="ReadPassword" penwidth="1.5" fillcolor="moccasin" ] + "blitter.com/go/hkexsh.ReadPassword" [ fillcolor="moccasin" label="ReadPassword" penwidth="1.5" ] } subgraph "cluster_github.com/jameskeane/bcrypt" { fontsize="16"; -fillcolor="lightyellow"; -fontname="bold"; rank="sink"; label="[bcrypt]"; URL="/?f=github.com/jameskeane/bcrypt"; tooltip="package: github.com/jameskeane/bcrypt"; penwidth="0.8"; style="filled"; +fillcolor="lightyellow"; +fontname="bold"; "github.com/jameskeane/bcrypt.Salt" [ fillcolor="moccasin" label="Salt" penwidth="1.5" ] "github.com/jameskeane/bcrypt.Hash" [ fillcolor="moccasin" label="Hash" penwidth="1.5" ] - "github.com/jameskeane/bcrypt.Match" [ penwidth="1.5" fillcolor="moccasin" label="Match" ] + "github.com/jameskeane/bcrypt.Match" [ fillcolor="moccasin" label="Match" penwidth="1.5" ] } diff --git a/hkexsh/hkexsh-vis-fixedup.png b/hkexsh/hkexsh-vis-fixedup.png index 07a29bc..312e863 100644 Binary files a/hkexsh/hkexsh-vis-fixedup.png and b/hkexsh/hkexsh-vis-fixedup.png differ diff --git a/hkexsh/hkexsh-vis.gv b/hkexsh/hkexsh-vis.gv index 191c65c..41242e3 100755 --- a/hkexsh/hkexsh-vis.gv +++ b/hkexsh/hkexsh-vis.gv @@ -14,52 +14,52 @@ digraph gocallvis { edge [minlen="2"] subgraph "cluster_focus" { - label="main"; + bgcolor="#e6ecfa"; +label="main"; labelloc="t"; labeljust="c"; fontsize="18"; -bgcolor="#e6ecfa"; - "blitter.com/go/hkexsh/hkexsh.doCopyMode" [ label="doCopyMode" penwidth="0.5" fillcolor="lightblue" ] - "blitter.com/go/hkexsh/hkexsh.main$2" [ fillcolor="lightblue" label="deferCloseChaff" style="dotted,filled" ] - "blitter.com/go/hkexsh/hkexsh.reqTunnel" [ fillcolor="lightblue" label="reqTunnel" penwidth="0.5" ] - "blitter.com/go/hkexsh/hkexsh.launchTuns" [ penwidth="0.5" fillcolor="lightblue" label="launchTuns" ] - "blitter.com/go/hkexsh/hkexsh.rejectUserMsg" [ penwidth="0.5" fillcolor="lightblue" label="rejectUserMsg" ] - "blitter.com/go/hkexsh/hkexsh.handleTermResizes$1" [ fillcolor="lightblue" label="handleTermResizes$1" style="dotted,filled" ] - "blitter.com/go/hkexsh/hkexsh.GetSize" [ fillcolor="lightblue" label="GetSize" penwidth="1.5" ] - "blitter.com/go/hkexsh/hkexsh.handleTermResizes" [ fillcolor="lightblue" label="handleTermResizes" penwidth="0.5" ] + "blitter.com/go/hkexsh/hkexsh.reqTunnel" [ penwidth="0.5" fillcolor="lightblue" label="reqTunnel" ] "blitter.com/go/hkexsh/hkexsh.doShellMode$1" [ fillcolor="lightblue" label="shellRemoteToStdin" style="dotted,filled" ] - "blitter.com/go/hkexsh/hkexsh.doShellMode$1$1" [ style="dotted,filled" fillcolor="lightblue" label="doShellMode$1$1" ] + "blitter.com/go/hkexsh/hkexsh.doShellMode$1$1" [ fillcolor="lightblue" label="doShellMode$1$1" style="dotted,filled" ] "blitter.com/go/hkexsh/hkexsh.doShellMode" [ fillcolor="lightblue" label="doShellMode" penwidth="0.5" ] + "blitter.com/go/hkexsh/hkexsh.handleTermResizes$1" [ fillcolor="lightblue" label="handleTermResizes$1" style="dotted,filled" ] + "blitter.com/go/hkexsh/hkexsh.GetSize" [ label="GetSize" penwidth="1.5" fillcolor="lightblue" ] + "blitter.com/go/hkexsh/hkexsh.handleTermResizes" [ penwidth="0.5" fillcolor="lightblue" label="handleTermResizes" ] "blitter.com/go/hkexsh/hkexsh.copyBuffer" [ fillcolor="lightblue" label="copyBuffer" penwidth="0.5" ] "blitter.com/go/hkexsh/hkexsh.copyBuffer$1" [ fillcolor="lightblue" label="copyBuffer$1" style="dotted,filled" ] "blitter.com/go/hkexsh/hkexsh.copyBuffer$2" [ fillcolor="lightblue" label="copyBuffer$2" style="dotted,filled" ] - "blitter.com/go/hkexsh/hkexsh.copyBuffer$3" [ fillcolor="lightblue" label="copyBuffer$3" style="dotted,filled" ] + "blitter.com/go/hkexsh/hkexsh.copyBuffer$3" [ style="dotted,filled" fillcolor="lightblue" label="copyBuffer$3" ] "blitter.com/go/hkexsh/hkexsh.Copy" [ fillcolor="lightblue" label="Copy" penwidth="1.5" ] "blitter.com/go/hkexsh/hkexsh.doShellMode$2$1" [ fillcolor="lightblue" label="doShellMode$2$1" style="dotted,filled" ] - "blitter.com/go/hkexsh/hkexsh.doShellMode$2" [ style="dotted,filled" fillcolor="lightblue" label="shellStdinToRemote" ] + "blitter.com/go/hkexsh/hkexsh.doShellMode$2" [ fillcolor="lightblue" label="shellStdinToRemote" style="dotted,filled" ] + "blitter.com/go/hkexsh/hkexsh.main$2" [ fillcolor="lightblue" label="deferCloseChaff" style="dotted,filled" ] "blitter.com/go/hkexsh/hkexsh.sendSessionParams" [ fillcolor="lightblue" label="sendSessionParams" penwidth="0.5" ] - "blitter.com/go/hkexsh/hkexsh.main$1" [ fillcolor="lightblue" label="deferRestore" style="dotted,filled" ] + "blitter.com/go/hkexsh/hkexsh.main$1" [ label="deferRestore" style="dotted,filled" fillcolor="lightblue" ] + "blitter.com/go/hkexsh/hkexsh.launchTuns" [ penwidth="0.5" fillcolor="lightblue" label="launchTuns" ] + "blitter.com/go/hkexsh/hkexsh.rejectUserMsg" [ label="rejectUserMsg" penwidth="0.5" fillcolor="lightblue" ] "blitter.com/go/hkexsh/hkexsh.main" [ fillcolor="lightblue" label="main" penwidth="0.5" ] "blitter.com/go/hkexsh/hkexsh.parseNonSwitchArgs" [ fillcolor="lightblue" label="parseNonSwitchArgs" penwidth="0.5" ] + "blitter.com/go/hkexsh/hkexsh.doCopyMode" [ fillcolor="lightblue" label="doCopyMode" penwidth="0.5" ] "blitter.com/go/hkexsh/hkexsh.usageShell" [ fillcolor="lightblue" label="usageShell" penwidth="0.5" ] "blitter.com/go/hkexsh/hkexsh.usageCp" [ fillcolor="lightblue" label="usageCp" penwidth="0.5" ] subgraph "cluster_blitter.com/go/hkexsh" { - fontsize="16"; -fontname="bold"; + style="filled"; +fillcolor="lightyellow"; rank="sink"; label="[hkexsh]"; -URL="/?f=blitter.com/go/hkexsh"; tooltip="package: blitter.com/go/hkexsh"; penwidth="0.8"; -fillcolor="lightyellow"; -style="filled"; +fontsize="16"; +fontname="bold"; +URL="/?f=blitter.com/go/hkexsh"; "blitter.com/go/hkexsh.Restore" [ fillcolor="moccasin" label="Restore" penwidth="1.5" ] "blitter.com/go/hkexsh.MakeRaw" [ fillcolor="moccasin" label="MakeRaw" penwidth="1.5" ] - "blitter.com/go/hkexsh.ReadPassword" [ fillcolor="moccasin" label="ReadPassword" penwidth="1.5" ] - "blitter.com/go/hkexsh.NewSession" [ fillcolor="moccasin" label="NewSession" penwidth="1.5" ] + "blitter.com/go/hkexsh.ReadPassword" [ penwidth="1.5" fillcolor="moccasin" label="ReadPassword" ] + "blitter.com/go/hkexsh.NewSession" [ label="NewSession" penwidth="1.5" fillcolor="moccasin" ] subgraph "cluster_*blitter.com/go/hkexsh.Session" { style="rounded,filled"; @@ -71,26 +71,26 @@ fontsize="15"; fontcolor="#222222"; labelloc="b"; - "(*blitter.com/go/hkexsh.Session).SetStatus" [ fillcolor="moccasin" label="SetStatus" penwidth="1.5" ] + "(*blitter.com/go/hkexsh.Session).SetStatus" [ label="SetStatus" penwidth="1.5" fillcolor="moccasin" ] } subgraph "cluster_blitter.com/go/hkexsh.Session" { - label="(Session)"; + fillcolor="wheat2"; +label="(Session)"; tooltip="type: blitter.com/go/hkexsh.Session"; penwidth="0.5"; fontsize="15"; fontcolor="#222222"; labelloc="b"; style="rounded,filled"; -fillcolor="wheat2"; - "(blitter.com/go/hkexsh.Session).Cmd" [ fillcolor="moccasin" label="Cmd" penwidth="1.5" ] - "(blitter.com/go/hkexsh.Session).Status" [ fillcolor="moccasin" label="Status" penwidth="1.5" ] + "(blitter.com/go/hkexsh.Session).Status" [ label="Status" penwidth="1.5" fillcolor="moccasin" ] "(blitter.com/go/hkexsh.Session).Op" [ fillcolor="moccasin" label="Op" penwidth="1.5" ] - "(blitter.com/go/hkexsh.Session).Who" [ label="Who" penwidth="1.5" fillcolor="moccasin" ] + "(blitter.com/go/hkexsh.Session).Who" [ fillcolor="moccasin" label="Who" penwidth="1.5" ] "(blitter.com/go/hkexsh.Session).ConnHost" [ fillcolor="moccasin" label="ConnHost" penwidth="1.5" ] - "(blitter.com/go/hkexsh.Session).TermType" [ fillcolor="moccasin" label="TermType" penwidth="1.5" ] + "(blitter.com/go/hkexsh.Session).TermType" [ penwidth="1.5" fillcolor="moccasin" label="TermType" ] + "(blitter.com/go/hkexsh.Session).Cmd" [ label="Cmd" penwidth="1.5" fillcolor="moccasin" ] "(blitter.com/go/hkexsh.Session).AuthCookie" [ fillcolor="moccasin" label="AuthCookie" penwidth="1.5" ] } @@ -98,67 +98,67 @@ fillcolor="wheat2"; } subgraph "cluster_blitter.com/go/hkexsh/hkexnet" { - rank="sink"; + fontname="bold"; label="[hkexnet]"; URL="/?f=blitter.com/go/hkexsh/hkexnet"; -penwidth="0.8"; -style="filled"; -fontname="bold"; tooltip="package: blitter.com/go/hkexsh/hkexnet"; fontsize="16"; fillcolor="lightyellow"; +rank="sink"; +penwidth="0.8"; +style="filled"; "blitter.com/go/hkexsh/hkexnet.Init" [ fillcolor="moccasin" label="Init" penwidth="1.5" ] - "blitter.com/go/hkexsh/hkexnet.Dial" [ fillcolor="moccasin" label="Dial" penwidth="1.5" ] + "blitter.com/go/hkexsh/hkexnet.Dial" [ penwidth="1.5" fillcolor="moccasin" label="Dial" ] subgraph "cluster_*blitter.com/go/hkexsh/hkexnet.Conn" { - labelloc="b"; + penwidth="0.5"; +fontsize="15"; +fontcolor="#222222"; +labelloc="b"; style="rounded,filled"; fillcolor="wheat2"; label="(*Conn)"; tooltip="type: *blitter.com/go/hkexsh/hkexnet.Conn"; -penwidth="0.5"; -fontsize="15"; -fontcolor="#222222"; - "(*blitter.com/go/hkexsh/hkexnet.Conn).WritePacket" [ penwidth="1.5" fillcolor="moccasin" label="WritePacket" ] - "(*blitter.com/go/hkexsh/hkexnet.Conn).SetStatus" [ fillcolor="moccasin" label="SetStatus" penwidth="1.5" ] - "(*blitter.com/go/hkexsh/hkexnet.Conn).Close" [ penwidth="1.5" fillcolor="moccasin" label="Close" ] + "(*blitter.com/go/hkexsh/hkexnet.Conn).WritePacket" [ fillcolor="moccasin" label="WritePacket" penwidth="1.5" ] + "(*blitter.com/go/hkexsh/hkexnet.Conn).Close" [ fillcolor="moccasin" label="Close" penwidth="1.5" ] "(*blitter.com/go/hkexsh/hkexnet.Conn).SetupChaff" [ fillcolor="moccasin" label="SetupChaff" penwidth="1.5" ] - "(*blitter.com/go/hkexsh/hkexnet.Conn).EnableChaff" [ label="EnableChaff" penwidth="1.5" fillcolor="moccasin" ] - "(*blitter.com/go/hkexsh/hkexnet.Conn).DisableChaff" [ penwidth="1.5" fillcolor="moccasin" label="DisableChaff" ] - "(*blitter.com/go/hkexsh/hkexnet.Conn).ShutdownChaff" [ penwidth="1.5" fillcolor="moccasin" label="ShutdownChaff" ] + "(*blitter.com/go/hkexsh/hkexnet.Conn).EnableChaff" [ fillcolor="moccasin" label="EnableChaff" penwidth="1.5" ] + "(*blitter.com/go/hkexsh/hkexnet.Conn).DisableChaff" [ fillcolor="moccasin" label="DisableChaff" penwidth="1.5" ] + "(*blitter.com/go/hkexsh/hkexnet.Conn).ShutdownChaff" [ label="ShutdownChaff" penwidth="1.5" fillcolor="moccasin" ] + "(*blitter.com/go/hkexsh/hkexnet.Conn).SetStatus" [ penwidth="1.5" fillcolor="moccasin" label="SetStatus" ] } subgraph "cluster_blitter.com/go/hkexsh/hkexnet.Conn" { - fontsize="15"; -fontcolor="#222222"; -labelloc="b"; + labelloc="b"; style="rounded,filled"; fillcolor="wheat2"; label="(Conn)"; tooltip="type: blitter.com/go/hkexsh/hkexnet.Conn"; penwidth="0.5"; +fontsize="15"; +fontcolor="#222222"; - "(blitter.com/go/hkexsh/hkexnet.Conn).Read" [ fillcolor="moccasin" label="Read" penwidth="1.5" ] "(blitter.com/go/hkexsh/hkexnet.Conn).GetStatus" [ fillcolor="moccasin" label="GetStatus" penwidth="1.5" ] "(blitter.com/go/hkexsh/hkexnet.Conn).Write" [ fillcolor="moccasin" label="Write" penwidth="1.5" ] + "(blitter.com/go/hkexsh/hkexnet.Conn).Read" [ fillcolor="moccasin" label="Read" penwidth="1.5" ] } } subgraph "cluster_blitter.com/go/hkexsh/logger" { - style="filled"; -fillcolor="lightyellow"; -URL="/?f=blitter.com/go/hkexsh/logger"; -penwidth="0.8"; -fontsize="16"; + fillcolor="lightyellow"; fontname="bold"; -rank="sink"; label="[logger]"; tooltip="package: blitter.com/go/hkexsh/logger"; +penwidth="0.8"; +style="filled"; +rank="sink"; +URL="/?f=blitter.com/go/hkexsh/logger"; +fontsize="16"; "blitter.com/go/hkexsh/logger.LogDebug" [ fillcolor="moccasin" label="LogDebug" penwidth="1.5" ] "blitter.com/go/hkexsh/logger.New" [ fillcolor="moccasin" label="New" penwidth="1.5" ] @@ -167,29 +167,29 @@ tooltip="package: blitter.com/go/hkexsh/logger"; subgraph "cluster_blitter.com/go/hkexsh/spinsult" { penwidth="0.8"; +style="filled"; +rank="sink"; +tooltip="package: blitter.com/go/hkexsh/spinsult"; fontsize="16"; fillcolor="lightyellow"; -rank="sink"; -label="[spinsult]"; -style="filled"; fontname="bold"; +label="[spinsult]"; URL="/?f=blitter.com/go/hkexsh/spinsult"; -tooltip="package: blitter.com/go/hkexsh/spinsult"; "blitter.com/go/hkexsh/spinsult.GetSentence" [ fillcolor="moccasin" label="GetSentence" penwidth="1.5" ] } subgraph "cluster_github.com/mattn/go-isatty" { - penwidth="0.8"; -URL="/?f=github.com/mattn/go-isatty"; -tooltip="package: github.com/mattn/go-isatty"; -fontsize="16"; -style="filled"; + tooltip="package: github.com/mattn/go-isatty"; +penwidth="0.8"; fillcolor="lightyellow"; -fontname="bold"; rank="sink"; label="[isatty]"; +URL="/?f=github.com/mattn/go-isatty"; +fontsize="16"; +style="filled"; +fontname="bold"; "github.com/mattn/go-isatty.IsTerminal" [ fillcolor="moccasin" label="IsTerminal" penwidth="1.5" ] @@ -197,25 +197,17 @@ label="[isatty]"; } - "blitter.com/go/hkexsh/hkexsh.doCopyMode" -> "(blitter.com/go/hkexsh.Session).Cmd" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexsh.doCopyMode" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).WritePacket" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexsh.doCopyMode" -> "(blitter.com/go/hkexsh/hkexnet.Conn).Read" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexsh.doCopyMode" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).SetStatus" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexsh.doCopyMode" -> "(blitter.com/go/hkexsh/hkexnet.Conn).GetStatus" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexsh.main$2" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).WritePacket" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.reqTunnel" -> "blitter.com/go/hkexsh/logger.LogDebug" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.reqTunnel" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).WritePacket" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexsh.launchTuns" -> "blitter.com/go/hkexsh/hkexsh.reqTunnel" [ ] - "blitter.com/go/hkexsh/hkexsh.rejectUserMsg" -> "blitter.com/go/hkexsh/spinsult.GetSentence" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexsh.handleTermResizes$1" -> "blitter.com/go/hkexsh/hkexsh.GetSize" [ ] - "blitter.com/go/hkexsh/hkexsh.handleTermResizes$1" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).WritePacket" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexsh.handleTermResizes" -> "blitter.com/go/hkexsh/hkexsh.handleTermResizes$1" [ arrowhead="normalnoneodot" ] "blitter.com/go/hkexsh/hkexsh.doShellMode$1" -> "blitter.com/go/hkexsh/hkexsh.doShellMode$1$1" [ arrowhead="normalnoneodiamond" ] "blitter.com/go/hkexsh/hkexsh.doShellMode$1" -> "blitter.com/go/hkexsh.Restore" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.doShellMode$1" -> "(blitter.com/go/hkexsh/hkexnet.Conn).GetStatus" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.doShellMode$1" -> "(*blitter.com/go/hkexsh.Session).SetStatus" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.doShellMode$1" -> "(blitter.com/go/hkexsh.Session).Status" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.doShellMode" -> "blitter.com/go/hkexsh/hkexsh.doShellMode$1" [ arrowhead="normalnoneodot" ] + "blitter.com/go/hkexsh/hkexsh.handleTermResizes$1" -> "blitter.com/go/hkexsh/hkexsh.GetSize" [ ] + "blitter.com/go/hkexsh/hkexsh.handleTermResizes$1" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).WritePacket" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexsh.handleTermResizes" -> "blitter.com/go/hkexsh/hkexsh.handleTermResizes$1" [ arrowhead="normalnoneodot" ] "blitter.com/go/hkexsh/hkexsh.doShellMode" -> "blitter.com/go/hkexsh/hkexsh.handleTermResizes" [ ] "blitter.com/go/hkexsh/hkexsh.copyBuffer" -> "(blitter.com/go/hkexsh/hkexnet.Conn).Write" [ style="dashed" color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.copyBuffer" -> "blitter.com/go/hkexsh/hkexsh.copyBuffer$1" [ style="dashed" ] @@ -226,6 +218,7 @@ label="[isatty]"; "blitter.com/go/hkexsh/hkexsh.doShellMode$2" -> "blitter.com/go/hkexsh/hkexsh.doShellMode$2$1" [ ] "blitter.com/go/hkexsh/hkexsh.doShellMode$2" -> "blitter.com/go/hkexsh.Restore" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.doShellMode" -> "blitter.com/go/hkexsh/hkexsh.doShellMode$2" [ arrowhead="normalnoneodot" ] + "blitter.com/go/hkexsh/hkexsh.main$2" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).WritePacket" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.sendSessionParams" -> "(blitter.com/go/hkexsh.Session).Op" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.sendSessionParams" -> "(blitter.com/go/hkexsh.Session).Who" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.sendSessionParams" -> "(blitter.com/go/hkexsh.Session).ConnHost" [ color="saddlebrown" ] @@ -234,11 +227,13 @@ label="[isatty]"; "blitter.com/go/hkexsh/hkexsh.sendSessionParams" -> "(blitter.com/go/hkexsh.Session).AuthCookie" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.sendSessionParams" -> "(blitter.com/go/hkexsh/hkexnet.Conn).Write" [ style="dashed" color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.main$1" -> "blitter.com/go/hkexsh.Restore" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexsh.launchTuns" -> "blitter.com/go/hkexsh/hkexsh.reqTunnel" [ ] + "blitter.com/go/hkexsh/hkexsh.rejectUserMsg" -> "blitter.com/go/hkexsh/spinsult.GetSentence" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh/hkexsh.parseNonSwitchArgs" [ ] "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh/logger.New" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh/hkexnet.Init" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh/hkexnet.Dial" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexsh.main" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).Close" [ arrowhead="normalnoneodiamond" color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexsh.main" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).Close" [ color="saddlebrown" arrowhead="normalnoneodiamond" ] "blitter.com/go/hkexsh/hkexsh.main" -> "github.com/mattn/go-isatty.IsTerminal" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh.MakeRaw" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh/hkexsh.main$1" [ arrowhead="normalnoneodiamond" ] @@ -250,12 +245,17 @@ label="[isatty]"; "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh/hkexsh.rejectUserMsg" [ ] "blitter.com/go/hkexsh/hkexsh.main" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).SetupChaff" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.main" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).EnableChaff" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexsh.main" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).DisableChaff" [ color="saddlebrown" arrowhead="normalnoneodiamond" ] + "blitter.com/go/hkexsh/hkexsh.main" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).DisableChaff" [ arrowhead="normalnoneodiamond" color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.main" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).ShutdownChaff" [ arrowhead="normalnoneodiamond" color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh/hkexsh.main$2" [ arrowhead="normalnoneodot" ] "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh/hkexsh.launchTuns" [ ] "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh/hkexsh.doShellMode" [ ] "blitter.com/go/hkexsh/hkexsh.main" -> "(blitter.com/go/hkexsh.Session).Status" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexsh.doCopyMode" -> "(blitter.com/go/hkexsh.Session).Cmd" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexsh.doCopyMode" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).WritePacket" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexsh.doCopyMode" -> "(blitter.com/go/hkexsh/hkexnet.Conn).Read" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexsh.doCopyMode" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).SetStatus" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexsh.doCopyMode" -> "(blitter.com/go/hkexsh/hkexnet.Conn).GetStatus" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh/hkexsh.doCopyMode" [ ] "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh.Restore" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexsh.main" -> "blitter.com/go/hkexsh/hkexsh.usageShell" [ style="dashed" ] diff --git a/hkexsh/hkexsh.go b/hkexsh/hkexsh.go index 104bca8..6891e63 100755 --- a/hkexsh/hkexsh.go +++ b/hkexsh/hkexsh.go @@ -1,6 +1,6 @@ // hkexsh client // -// Copyright (c) 2017-2018 Russell Magee +// Copyright (c) 2017-2019 Russell Magee // Licensed under the terms of the MIT license (see LICENSE.mit in this // distribution) // @@ -36,6 +36,7 @@ import ( ) var ( + // wg controls when the goroutines handling client I/O complete wg sync.WaitGroup // Log defaults to regular syslog output (no -d) Log *logger.Writer @@ -43,6 +44,7 @@ var ( //////////////////////////////////////////////////// +// Praise Bob. Do not remove, lest ye lose Slack. const bob = string("\r\n\r\n" + "@@@@@@@^^~~~~~~~~~~~~~~~~~~~~^@@@@@@@@@\r\n" + "@@@@@@^ ~^ @ @@ @ @ @ I ~^@@@@@@\r\n" + @@ -70,8 +72,10 @@ const bob = string("\r\n\r\n" + "\r\n") type ( + // Handler for special functions invoked by escSeqs escHandler func(io.Writer) - escSeqs map[byte]escHandler + // escSeqs is a map of special keystroke sequences to trigger escHandlers + escSeqs map[byte]escHandler ) // Copy copies from src to dst until either EOF is reached @@ -91,6 +95,8 @@ type ( // calls a client-custom version of copyBuffer(), which allows // some client escape sequences to trigger special actions during // interactive sessions. +// +// (See go doc hkexsh/hkexsh.{escSeqs,escHandler}) func Copy(dst io.Writer, src io.Reader) (written int64, err error) { written, err = copyBuffer(dst, src, nil) return @@ -102,9 +108,13 @@ func Copy(dst io.Writer, src io.Reader) (written int64, err error) { // This private version of copyBuffer is derived from the // go stdlib pkg/io, with escape sequence interpretation to trigger // some special client-side actions. +// +// (See go doc hkexsh/hkexsh.{escSeqs,escHandler}) func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) { // NOTE: using dst.Write() in these esc funcs will cause the output - // to function as a 'macro', outputting as if user typed the sequence. + // to function as a 'macro', outputting as if user typed the sequence + // (that is, the client 'sees' the user type it, and the server 'sees' + // it as well). // // Using os.Stdout outputs to the client's term w/o it or the server // 'seeing' the output. @@ -156,7 +166,7 @@ func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err er if buf[0] == 0x1d { seqPos++ } - } else /* seqPos > 0 */ { + } else { if v, ok := escs[buf[0]]; ok { v(dst) nr-- @@ -185,13 +195,14 @@ func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err er break } } - //_,_ = dst.Write([]byte{0x2f}) return written, err } //////////////////////////////////////////////////// // GetSize gets the terminal size using 'stty' command +// +// TODO: do in code someday instead of using external 'stty' func GetSize() (cols, rows int, err error) { cmd := exec.Command("stty", "size") // #nosec cmd.Stdin = os.Stdin @@ -216,6 +227,7 @@ func GetSize() (cols, rows int, err error) { } // doCopyMode begins a secure hkexsh local<->remote file copy operation. +// // TODO: reduce gocyclo func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *hkexsh.Session) (exitStatus uint32, err error) { if remoteDest { @@ -256,7 +268,6 @@ func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *hkexsh.S // NOTE the lack of quotes around --xform option's sed expression. // When args are passed in exec() format, no quoting is required // (as this isn't input from a shell) (right? -rlm 20180823) - //cmdArgs := []string{"-xvz", "-C", files, `--xform=s#.*/\(.*\)#\1#`} c = exec.Command(cmdName, cmdArgs...) // #nosec c.Dir, _ = os.Getwd() // #nosec log.Println("[wd:", c.Dir, "]") @@ -296,7 +307,6 @@ func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *hkexsh.S if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { exitStatus = uint32(status.ExitStatus()) fmt.Print(stdErrBuffer) - //fmt.Printf("Exit Status: %d\n", exitStatus) //# } } } @@ -331,10 +341,6 @@ func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *hkexsh.S log.Println("remote filepath:", string(rec.Cmd()), "local files:", files) var c *exec.Cmd - //os.Clearenv() - //os.Setenv("HOME", u.HomeDir) - //os.Setenv("TERM", "vt102") // TODO: server or client option? - cmdName := "/bin/tar" destPath := files @@ -353,7 +359,6 @@ func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *hkexsh.S err = c.Start() // returns immediately if err != nil { fmt.Println(err) - //log.Fatal(err) } else { if err = c.Wait(); err != nil { if exiterr, ok := err.(*exec.ExitError); ok { @@ -365,7 +370,6 @@ func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *hkexsh.S // an ExitStatus() method with the same signature. if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { exitStatus = uint32(status.ExitStatus()) - //log.Printf("Exit Status: %d", exitStatus) } } } @@ -380,7 +384,8 @@ func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *hkexsh.S return } -// doShellMode begins an hkexsh shell session (one-shot command or interactive). +// doShellMode begins an hkexsh shell session (one-shot command or +// interactive). func doShellMode(isInteractive bool, conn *hkexnet.Conn, oldState *hkexsh.State, rec *hkexsh.Session) { //client reader (from server) goroutine //Read remote end's stdout @@ -434,7 +439,6 @@ func doShellMode(isInteractive bool, conn *hkexnet.Conn, oldState *hkexsh.State, // TODO:.gv:doShellMode:2:shellStdinToRemote shellStdinToRemote := func() { defer wg.Done() - //!defer wg.Done() _, outerr := func(conn *hkexnet.Conn, r io.Reader) (w int64, e error) { // Copy() expects EOF so this will // exit with outerr == nil @@ -471,6 +475,10 @@ func usageCp() { flag.PrintDefaults() } +// rejectUserMsg snarkily rebukes users giving incorrect +// credentials. +// +// TODO: do this from the server side and have client just emit that func rejectUserMsg() string { return "Begone, " + spinsult.GetSentence() + "\r\n" } @@ -519,15 +527,9 @@ func parseNonSwitchArgs(a []string) (user, host, path string, isDest bool, other } fancyHost = fancyHostPath[0] - //if fancyPath == "" { - // fancyPath = "." - //} - if i == len(a)-1 { isDest = true - //fmt.Println("remote path isDest") } - //fmt.Println("fancyArgs: user:", fancyUser, "host:", fancyHost, "path:", fancyPath) } else { otherArgs = append(otherArgs, a[i]) } @@ -580,17 +582,6 @@ func sendSessionParams(conn io.Writer /* *hkexnet.Conn*/, rec *hkexsh.Session) ( return e } -// hkexsh - a client for secure shell and file copy operations. -// -// While conforming to the basic net.Conn interface HKex.Conn has extra -// capabilities designed to allow apps to define connection options, -// encryption/hmac settings and operations across the encrypted channel. -// -// Initial setup is the same as using plain net.Dial(), but one may -// specify extra extension tags (strings) to set the cipher and hmac -// setting desired; as well as the intended operation mode for the -// connection (app-specific, passed through to the server to use or -// ignore at its discretion). // TODO: reduce gocyclo func main() { version := hkexsh.Version diff --git a/hkexshd/hkexshd-vis-fixedup.png b/hkexshd/hkexshd-vis-fixedup.png index fe9196a..518a2fd 100644 Binary files a/hkexshd/hkexshd-vis-fixedup.png and b/hkexshd/hkexshd-vis-fixedup.png differ diff --git a/hkexshd/hkexshd-vis.gv b/hkexshd/hkexshd-vis.gv index 27ce976..dfecee9 100755 --- a/hkexshd/hkexshd-vis.gv +++ b/hkexshd/hkexshd-vis.gv @@ -14,171 +14,171 @@ digraph gocallvis { edge [minlen="2"] subgraph "cluster_focus" { - labelloc="t"; + bgcolor="#e6ecfa"; +label="main"; +labelloc="t"; labeljust="c"; fontsize="18"; -bgcolor="#e6ecfa"; -label="main"; - "blitter.com/go/hkexsh/hkexshd.runShellAs" [ fillcolor="lightblue" label="runShellAs" penwidth="0.5" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs$1" [ fillcolor="lightblue" label="deferPtmxClose" style="dotted,filled" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs$2" [ fillcolor="lightblue" label="termResizeWatcher" style="dotted,filled" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs$3" [ fillcolor="lightblue" label="stdinToPtyWorker" style="dotted,filled" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs$4" [ fillcolor="lightblue" label="deferChaffShutdown" style="dotted,filled" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs$5" [ fillcolor="lightblue" label="ptyToStdoutWorker" style="dotted,filled" ] - "blitter.com/go/hkexsh/hkexshd.main" [ fillcolor="lightblue" label="main" penwidth="0.5" ] "blitter.com/go/hkexsh/hkexshd.main$1" [ fillcolor="lightblue" label="main$1" style="dotted,filled" ] + "blitter.com/go/hkexsh/hkexshd.main$2$1" [ fillcolor="lightblue" label="main$2$1" style="dotted,filled" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs$4" [ fillcolor="lightblue" label="deferChaffShutdown" style="dotted,filled" ] + "blitter.com/go/hkexsh/hkexshd.main" [ fillcolor="lightblue" label="main" penwidth="0.5" ] "blitter.com/go/hkexsh/hkexshd.main$2" [ fillcolor="lightblue" label="main$2" style="dotted,filled" ] "blitter.com/go/hkexsh/hkexshd.GenAuthToken" [ fillcolor="lightblue" label="GenAuthToken" penwidth="1.5" ] - "blitter.com/go/hkexsh/hkexshd.main$2$1" [ fillcolor="lightblue" label="main$2$1" style="dotted,filled" ] - "blitter.com/go/hkexsh/hkexshd.runClientToServerCopyAs" [ penwidth="0.5" fillcolor="lightblue" label="runClientToServerCopyAs" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs" [ fillcolor="lightblue" label="runShellAs" penwidth="0.5" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs$1" [ label="deferPtmxClose" style="dotted,filled" fillcolor="lightblue" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs$2" [ style="dotted,filled" fillcolor="lightblue" label="termResizeWatcher" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs$3" [ fillcolor="lightblue" label="stdinToPtyWorker" style="dotted,filled" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs$5" [ fillcolor="lightblue" label="ptyToStdoutWorker" style="dotted,filled" ] + "blitter.com/go/hkexsh/hkexshd.runClientToServerCopyAs" [ fillcolor="lightblue" label="runClientToServerCopyAs" penwidth="0.5" ] "blitter.com/go/hkexsh/hkexshd.runServerToClientCopyAs" [ fillcolor="lightblue" label="runServerToClientCopyAs" penwidth="0.5" ] subgraph "cluster_blitter.com/go/goutmp" { - fontsize="16"; -style="filled"; -fillcolor="lightyellow"; + fontname="bold"; rank="sink"; -label="[goutmp]"; tooltip="package: blitter.com/go/goutmp"; penwidth="0.8"; -fontname="bold"; +fillcolor="lightyellow"; +label="[goutmp]"; URL="/?f=blitter.com/go/goutmp"; +fontsize="16"; +style="filled"; - "blitter.com/go/goutmp.GetHost" [ penwidth="1.5" fillcolor="moccasin" label="GetHost" ] - "blitter.com/go/goutmp.Put_utmp" [ fillcolor="moccasin" label="Put_utmp" penwidth="1.5" ] - "blitter.com/go/goutmp.Unput_utmp" [ fillcolor="moccasin" label="Unput_utmp" penwidth="1.5" ] - "blitter.com/go/goutmp.Put_lastlog_entry" [ label="Put_lastlog_entry" penwidth="1.5" fillcolor="moccasin" ] + "blitter.com/go/goutmp.Unput_utmp" [ label="Unput_utmp" penwidth="1.5" fillcolor="moccasin" ] + "blitter.com/go/goutmp.GetHost" [ fillcolor="moccasin" label="GetHost" penwidth="1.5" ] + "blitter.com/go/goutmp.Put_utmp" [ label="Put_utmp" penwidth="1.5" fillcolor="moccasin" ] + "blitter.com/go/goutmp.Put_lastlog_entry" [ fillcolor="moccasin" label="Put_lastlog_entry" penwidth="1.5" ] } subgraph "cluster_blitter.com/go/hkexsh" { - fontname="bold"; -rank="sink"; -URL="/?f=blitter.com/go/hkexsh"; -penwidth="0.8"; -style="filled"; -fillcolor="lightyellow"; -fontsize="16"; + fillcolor="lightyellow"; label="[hkexsh]"; tooltip="package: blitter.com/go/hkexsh"; +penwidth="0.8"; +style="filled"; +fontname="bold"; +rank="sink"; +URL="/?f=blitter.com/go/hkexsh"; +fontsize="16"; - "blitter.com/go/hkexsh.AuthUserByToken" [ penwidth="1.5" fillcolor="moccasin" label="AuthUserByToken" ] + "blitter.com/go/hkexsh.AuthUserByToken" [ label="AuthUserByToken" penwidth="1.5" fillcolor="moccasin" ] "blitter.com/go/hkexsh.AuthUserByPasswd" [ fillcolor="moccasin" label="AuthUserByPasswd" penwidth="1.5" ] subgraph "cluster_*blitter.com/go/hkexsh.Session" { - fontcolor="#222222"; + fontsize="15"; +fontcolor="#222222"; labelloc="b"; style="rounded,filled"; fillcolor="wheat2"; label="(*Session)"; tooltip="type: *blitter.com/go/hkexsh.Session"; penwidth="0.5"; -fontsize="15"; - "(*blitter.com/go/hkexsh.Session).SetOp" [ penwidth="1.5" fillcolor="moccasin" label="SetOp" ] + "(*blitter.com/go/hkexsh.Session).SetOp" [ fillcolor="moccasin" label="SetOp" penwidth="1.5" ] "(*blitter.com/go/hkexsh.Session).SetWho" [ fillcolor="moccasin" label="SetWho" penwidth="1.5" ] - "(*blitter.com/go/hkexsh.Session).SetConnHost" [ fillcolor="moccasin" label="SetConnHost" penwidth="1.5" ] - "(*blitter.com/go/hkexsh.Session).SetTermType" [ fillcolor="moccasin" label="SetTermType" penwidth="1.5" ] + "(*blitter.com/go/hkexsh.Session).SetConnHost" [ penwidth="1.5" fillcolor="moccasin" label="SetConnHost" ] + "(*blitter.com/go/hkexsh.Session).SetTermType" [ label="SetTermType" penwidth="1.5" fillcolor="moccasin" ] "(*blitter.com/go/hkexsh.Session).SetCmd" [ fillcolor="moccasin" label="SetCmd" penwidth="1.5" ] - "(*blitter.com/go/hkexsh.Session).SetAuthCookie" [ penwidth="1.5" fillcolor="moccasin" label="SetAuthCookie" ] - "(*blitter.com/go/hkexsh.Session).ClearAuthCookie" [ fillcolor="moccasin" label="ClearAuthCookie" penwidth="1.5" ] + "(*blitter.com/go/hkexsh.Session).SetAuthCookie" [ fillcolor="moccasin" label="SetAuthCookie" penwidth="1.5" ] + "(*blitter.com/go/hkexsh.Session).ClearAuthCookie" [ label="ClearAuthCookie" penwidth="1.5" fillcolor="moccasin" ] } subgraph "cluster_blitter.com/go/hkexsh.Session" { - labelloc="b"; -style="rounded,filled"; -fillcolor="wheat2"; + fillcolor="wheat2"; label="(Session)"; tooltip="type: blitter.com/go/hkexsh.Session"; penwidth="0.5"; fontsize="15"; fontcolor="#222222"; +labelloc="b"; +style="rounded,filled"; "(blitter.com/go/hkexsh.Session).Op" [ fillcolor="moccasin" label="Op" penwidth="1.5" ] "(blitter.com/go/hkexsh.Session).Who" [ fillcolor="moccasin" label="Who" penwidth="1.5" ] - "(blitter.com/go/hkexsh.Session).ConnHost" [ label="ConnHost" penwidth="1.5" fillcolor="moccasin" ] - "(blitter.com/go/hkexsh.Session).Cmd" [ fillcolor="moccasin" label="Cmd" penwidth="1.5" ] + "(blitter.com/go/hkexsh.Session).ConnHost" [ fillcolor="moccasin" label="ConnHost" penwidth="1.5" ] + "(blitter.com/go/hkexsh.Session).Cmd" [ penwidth="1.5" fillcolor="moccasin" label="Cmd" ] "(blitter.com/go/hkexsh.Session).AuthCookie" [ fillcolor="moccasin" label="AuthCookie" penwidth="1.5" ] - "(blitter.com/go/hkexsh.Session).TermType" [ label="TermType" penwidth="1.5" fillcolor="moccasin" ] + "(blitter.com/go/hkexsh.Session).TermType" [ fillcolor="moccasin" label="TermType" penwidth="1.5" ] } } subgraph "cluster_blitter.com/go/hkexsh/hkexnet" { - style="filled"; -fillcolor="lightyellow"; -fontname="bold"; -rank="sink"; + fontsize="16"; URL="/?f=blitter.com/go/hkexsh/hkexnet"; -fontsize="16"; +rank="sink"; label="[hkexnet]"; tooltip="package: blitter.com/go/hkexsh/hkexnet"; penwidth="0.8"; +style="filled"; +fillcolor="lightyellow"; +fontname="bold"; "blitter.com/go/hkexsh/hkexnet.Init" [ fillcolor="moccasin" label="Init" penwidth="1.5" ] "blitter.com/go/hkexsh/hkexnet.Listen" [ fillcolor="moccasin" label="Listen" penwidth="1.5" ] subgraph "cluster_*blitter.com/go/hkexsh/hkexnet.Conn" { - penwidth="0.5"; + tooltip="type: *blitter.com/go/hkexsh/hkexnet.Conn"; +penwidth="0.5"; fontsize="15"; fontcolor="#222222"; labelloc="b"; style="rounded,filled"; fillcolor="wheat2"; label="(*Conn)"; -tooltip="type: *blitter.com/go/hkexsh/hkexnet.Conn"; - "(*blitter.com/go/hkexsh/hkexnet.Conn).EnableChaff" [ fillcolor="moccasin" label="EnableChaff" penwidth="1.5" ] "(*blitter.com/go/hkexsh/hkexnet.Conn).DisableChaff" [ fillcolor="moccasin" label="DisableChaff" penwidth="1.5" ] "(*blitter.com/go/hkexsh/hkexnet.Conn).ShutdownChaff" [ fillcolor="moccasin" label="ShutdownChaff" penwidth="1.5" ] + "(*blitter.com/go/hkexsh/hkexnet.Conn).SetupChaff" [ fillcolor="moccasin" label="SetupChaff" penwidth="1.5" ] + "(*blitter.com/go/hkexsh/hkexnet.Conn).Close" [ fillcolor="moccasin" label="Close" penwidth="1.5" ] + "(*blitter.com/go/hkexsh/hkexnet.Conn).RemoteAddr" [ label="RemoteAddr" penwidth="1.5" fillcolor="moccasin" ] + "(*blitter.com/go/hkexsh/hkexnet.Conn).EnableChaff" [ fillcolor="moccasin" label="EnableChaff" penwidth="1.5" ] "(*blitter.com/go/hkexsh/hkexnet.Conn).SetStatus" [ fillcolor="moccasin" label="SetStatus" penwidth="1.5" ] - "(*blitter.com/go/hkexsh/hkexnet.Conn).SetupChaff" [ label="SetupChaff" penwidth="1.5" fillcolor="moccasin" ] - "(*blitter.com/go/hkexsh/hkexnet.Conn).Close" [ label="Close" penwidth="1.5" fillcolor="moccasin" ] - "(*blitter.com/go/hkexsh/hkexnet.Conn).RemoteAddr" [ fillcolor="moccasin" label="RemoteAddr" penwidth="1.5" ] - "(*blitter.com/go/hkexsh/hkexnet.Conn).WritePacket" [ fillcolor="moccasin" label="WritePacket" penwidth="1.5" ] + "(*blitter.com/go/hkexsh/hkexnet.Conn).WritePacket" [ label="WritePacket" penwidth="1.5" fillcolor="moccasin" ] } subgraph "cluster_*blitter.com/go/hkexsh/hkexnet.HKExListener" { - fontcolor="#222222"; + tooltip="type: *blitter.com/go/hkexsh/hkexnet.HKExListener"; +penwidth="0.5"; +fontsize="15"; +fontcolor="#222222"; labelloc="b"; style="rounded,filled"; fillcolor="wheat2"; label="(*HKExListener)"; -tooltip="type: *blitter.com/go/hkexsh/hkexnet.HKExListener"; -penwidth="0.5"; -fontsize="15"; "(*blitter.com/go/hkexsh/hkexnet.HKExListener).Accept" [ fillcolor="moccasin" label="Accept" penwidth="1.5" ] } subgraph "cluster_blitter.com/go/hkexsh/hkexnet.Conn" { - penwidth="0.5"; -fontsize="15"; -fontcolor="#222222"; + fontcolor="#222222"; labelloc="b"; style="rounded,filled"; fillcolor="wheat2"; label="(Conn)"; tooltip="type: blitter.com/go/hkexsh/hkexnet.Conn"; +penwidth="0.5"; +fontsize="15"; - "(blitter.com/go/hkexsh/hkexnet.Conn).Write" [ fillcolor="moccasin" label="Write" penwidth="1.5" ] + "(blitter.com/go/hkexsh/hkexnet.Conn).Write" [ label="Write" penwidth="1.5" fillcolor="moccasin" ] } subgraph "cluster_blitter.com/go/hkexsh/hkexnet.HKExListener" { - label="(HKExListener)"; + fillcolor="wheat2"; +label="(HKExListener)"; tooltip="type: blitter.com/go/hkexsh/hkexnet.HKExListener"; penwidth="0.5"; fontsize="15"; fontcolor="#222222"; labelloc="b"; style="rounded,filled"; -fillcolor="wheat2"; "(blitter.com/go/hkexsh/hkexnet.HKExListener).Close" [ fillcolor="moccasin" label="Close" penwidth="1.5" ] @@ -188,53 +188,45 @@ fillcolor="wheat2"; subgraph "cluster_blitter.com/go/hkexsh/logger" { penwidth="0.8"; -rank="sink"; fontsize="16"; style="filled"; +rank="sink"; fillcolor="lightyellow"; fontname="bold"; label="[logger]"; URL="/?f=blitter.com/go/hkexsh/logger"; tooltip="package: blitter.com/go/hkexsh/logger"; + "blitter.com/go/hkexsh/logger.LogNotice" [ fillcolor="moccasin" label="LogNotice" penwidth="1.5" ] "blitter.com/go/hkexsh/logger.New" [ fillcolor="moccasin" label="New" penwidth="1.5" ] - "blitter.com/go/hkexsh/logger.LogNotice" [ penwidth="1.5" fillcolor="moccasin" label="LogNotice" ] - "blitter.com/go/hkexsh/logger.LogErr" [ penwidth="1.5" fillcolor="moccasin" label="LogErr" ] + "blitter.com/go/hkexsh/logger.LogErr" [ fillcolor="moccasin" label="LogErr" penwidth="1.5" ] } subgraph "cluster_github.com/kr/pty" { - style="filled"; + penwidth="0.8"; +fillcolor="lightyellow"; +tooltip="package: github.com/kr/pty"; label="[pty]"; URL="/?f=github.com/kr/pty"; -penwidth="0.8"; fontsize="16"; -fillcolor="lightyellow"; +style="filled"; fontname="bold"; rank="sink"; -tooltip="package: github.com/kr/pty"; - "github.com/kr/pty.Start" [ fillcolor="moccasin" label="Start" penwidth="1.5" ] + "github.com/kr/pty.Start" [ label="Start" penwidth="1.5" fillcolor="moccasin" ] "github.com/kr/pty.Setsize" [ fillcolor="moccasin" label="Setsize" penwidth="1.5" ] } } - "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "github.com/kr/pty.Start" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "blitter.com/go/hkexsh/hkexshd.runShellAs$1" [ arrowhead="normalnoneodiamond" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs$2" -> "github.com/kr/pty.Setsize" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "blitter.com/go/hkexsh/hkexshd.runShellAs$2" [ arrowhead="normalnoneodot" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "blitter.com/go/hkexsh/hkexshd.runShellAs$3" [ arrowhead="normalnoneodot" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).EnableChaff" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexshd.main$1" -> "blitter.com/go/hkexsh/logger.LogNotice" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexshd.main$2$1" -> "blitter.com/go/goutmp.Unput_utmp" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.runShellAs$4" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).DisableChaff" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.runShellAs$4" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).ShutdownChaff" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "blitter.com/go/hkexsh/hkexshd.runShellAs$4" [ arrowhead="normalnoneodiamond" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "blitter.com/go/hkexsh/hkexshd.runShellAs$5" [ arrowhead="normalnoneodot" ] - "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).SetStatus" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.main" -> "blitter.com/go/hkexsh/logger.New" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.main" -> "blitter.com/go/hkexsh/hkexnet.Init" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexshd.main$1" -> "blitter.com/go/hkexsh/logger.LogNotice" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.main" -> "blitter.com/go/hkexsh/hkexshd.main$1" [ arrowhead="normalnoneodot" ] "blitter.com/go/hkexsh/hkexshd.main" -> "blitter.com/go/hkexsh/hkexnet.Listen" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.main" -> "(blitter.com/go/hkexsh/hkexnet.HKExListener).Close" [ arrowhead="normalnoneodiamond" color="saddlebrown" ] @@ -261,20 +253,28 @@ tooltip="package: github.com/kr/pty"; "blitter.com/go/hkexsh/hkexshd.main$2" -> "blitter.com/go/goutmp.GetHost" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.main$2" -> "blitter.com/go/hkexsh/hkexshd.GenAuthToken" [ ] "blitter.com/go/hkexsh/hkexshd.main$2" -> "(blitter.com/go/hkexsh.Session).TermType" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "github.com/kr/pty.Start" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "blitter.com/go/hkexsh/hkexshd.runShellAs$1" [ arrowhead="normalnoneodiamond" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs$2" -> "github.com/kr/pty.Setsize" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "blitter.com/go/hkexsh/hkexshd.runShellAs$2" [ arrowhead="normalnoneodot" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "blitter.com/go/hkexsh/hkexshd.runShellAs$3" [ arrowhead="normalnoneodot" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).EnableChaff" [ color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "blitter.com/go/hkexsh/hkexshd.runShellAs$4" [ arrowhead="normalnoneodiamond" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "blitter.com/go/hkexsh/hkexshd.runShellAs$5" [ arrowhead="normalnoneodot" ] + "blitter.com/go/hkexsh/hkexshd.runShellAs" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).SetStatus" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.main$2" -> "blitter.com/go/hkexsh/hkexshd.runShellAs" [ ] "blitter.com/go/hkexsh/hkexshd.main$2" -> "blitter.com/go/hkexsh/logger.LogErr" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.main$2" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).SetStatus" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.main$2" -> "blitter.com/go/goutmp.Put_utmp" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexshd.main$2$1" -> "blitter.com/go/goutmp.Unput_utmp" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.main$2" -> "blitter.com/go/hkexsh/hkexshd.main$2$1" [ arrowhead="normalnoneodiamond" ] "blitter.com/go/hkexsh/hkexshd.main$2" -> "blitter.com/go/goutmp.Put_lastlog_entry" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.runClientToServerCopyAs" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).EnableChaff" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.runClientToServerCopyAs" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).DisableChaff" [ arrowhead="normalnoneodiamond" color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexshd.runClientToServerCopyAs" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).ShutdownChaff" [ arrowhead="normalnoneodiamond" color="saddlebrown" ] + "blitter.com/go/hkexsh/hkexshd.runClientToServerCopyAs" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).ShutdownChaff" [ color="saddlebrown" arrowhead="normalnoneodiamond" ] "blitter.com/go/hkexsh/hkexshd.main$2" -> "blitter.com/go/hkexsh/hkexshd.runClientToServerCopyAs" [ ] "blitter.com/go/hkexsh/hkexshd.main$2" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).WritePacket" [ color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.runServerToClientCopyAs" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).EnableChaff" [ color="saddlebrown" ] - "blitter.com/go/hkexsh/hkexshd.runServerToClientCopyAs" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).DisableChaff" [ color="saddlebrown" arrowhead="normalnoneodiamond" ] + "blitter.com/go/hkexsh/hkexshd.runServerToClientCopyAs" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).DisableChaff" [ arrowhead="normalnoneodiamond" color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.runServerToClientCopyAs" -> "(*blitter.com/go/hkexsh/hkexnet.Conn).ShutdownChaff" [ arrowhead="normalnoneodiamond" color="saddlebrown" ] "blitter.com/go/hkexsh/hkexshd.main$2" -> "blitter.com/go/hkexsh/hkexshd.runServerToClientCopyAs" [ ] "blitter.com/go/hkexsh/hkexshd.main" -> "blitter.com/go/hkexsh/hkexshd.main$2" [ arrowhead="normalnoneodot" ] diff --git a/hkexshd/hkexshd-vis.png b/hkexshd/hkexshd-vis.png index 8f73787..51e1a4c 100644 Binary files a/hkexshd/hkexshd-vis.png and b/hkexshd/hkexshd-vis.png differ