github.com/devops-filetransfer/sshego@v7.0.4+incompatible/listen.go (about) 1 package sshego 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "net" 8 "sync" 9 "time" 10 11 "github.com/glycerine/sshego/xendor/github.com/glycerine/xcryptossh" 12 ) 13 14 // BasicServer configures a simple embedded sshd server 15 // that only expects RSA key (or other) based authentication, 16 // and doesn't expect TOTP or passphase. This makes 17 // it suitable for using with unattended systems / to 18 // replace a TLS server. 19 type BasicServer struct { 20 cfg *SshegoConfig 21 } 22 23 // NewBasicServer in 24 // listen.go provides net.Listen() compatibility 25 // for running an embedded sshd. It refactors 26 // server.go's Start() into Listen() and Accept(). 27 func NewBasicServer(cfg *SshegoConfig) *BasicServer { 28 cfg.NewEsshd() 29 return &BasicServer{cfg: cfg} 30 } 31 32 // Close releases all server port bindings. 33 func (b *BasicServer) Close() error { 34 // In case we haven't yet actually started, close Done too. 35 // Multiple Close() calls on Halter are fine. 36 b.cfg.Esshd.Halt.MarkDone() 37 return b.cfg.Esshd.Stop() 38 } 39 40 // Address satisfies the net.Addr interface, which 41 // BasicListener.Addr() returns. 42 type BasicAddress struct { 43 addr string 44 } 45 46 // Network returns the name of the network, "sshego" 47 func (a *BasicAddress) Network() string { 48 return "sshego" 49 } 50 51 // String returns the string form of the address. 52 func (a *BasicAddress) String() string { 53 return a.addr 54 } 55 56 // BasicListener satifies the net.Listener interface 57 type BasicListener struct { 58 bs *BasicServer 59 addr BasicAddress 60 esshd *Esshd 61 dom string 62 lsn net.Listener 63 attempt uint64 64 halt ssh.Halter 65 mut sync.Mutex 66 } 67 68 // Addr returns the listener's network address. 69 func (b *BasicListener) Addr() net.Addr { 70 return &BasicAddress{ 71 addr: b.bs.cfg.EmbeddedSSHd.Addr, 72 } 73 } 74 75 // Close closes the listener. 76 // Any blocked Accept operations will be unblocked and return errors. 77 func (b *BasicListener) Close() error { 78 // in case we haven't yet actually started, close the Done 79 // channel too. 80 81 // global shutdown: works but not what we want! 82 // b.bs.cfg.Esshd.Halt.MarkDone() 83 // return b.bs.cfg.Esshd.Stop() 84 85 b.halt.MarkDone() 86 b.halt.RequestStop() 87 return nil 88 } 89 90 // Listen announces on the local network address laddr. 91 // The syntax of laddr is "host:port", like "127.0.0.1:2222". 92 // We listen on a TCP port. 93 func (bs *BasicServer) Listen(laddr string) (*BasicListener, error) { 94 bs.cfg.EmbeddedSSHd.Addr = laddr 95 err := bs.cfg.EmbeddedSSHd.ParseAddr() 96 if err != nil { 97 return nil, err 98 } 99 return bs.cfg.Esshd.Listen(bs) 100 } 101 102 // Essh add-on methods 103 104 // Listen and Accept support BasicServer functionality. 105 // Together, Listen() then Accept() replace Start(). 106 func (e *Esshd) Listen(bs *BasicServer) (*BasicListener, error) { 107 108 log.Printf("Esshd.Listen() called. %s", SourceVersion()) 109 110 p("about to listen on %v", e.cfg.EmbeddedSSHd.Addr) 111 // Once a ServerConfig has been configured, connections can be 112 // accepted. 113 domain := "tcp" 114 if e.cfg.EmbeddedSSHd.UnixDomainPath != "" { 115 domain = "unix" 116 } 117 p("info: Essh.Listen() in listen.go: listening on "+ 118 "domain '%s', addr: '%s'", domain, e.cfg.EmbeddedSSHd.Addr) 119 120 listener, err := net.Listen(domain, e.cfg.EmbeddedSSHd.Addr) 121 if err != nil { 122 return nil, fmt.Errorf("failed to listen for connection on %v: %v", 123 e.cfg.EmbeddedSSHd.Addr, err) 124 } 125 126 return &BasicListener{ 127 bs: bs, 128 esshd: e, 129 dom: domain, 130 lsn: listener, 131 halt: *ssh.NewHalter(), 132 }, nil 133 } 134 135 // Accept and Listen support BasicServer functionality. 136 // Accept waits for and returns the next connection to the listener. 137 func (b *BasicListener) Accept(ctx context.Context) (net.Conn, error) { 138 p("Accept for BasicListener called.") 139 140 e := b.esshd 141 142 // most of the auth state is per user, so it has 143 // to wait until we have a login and a 144 // username at hand. 145 a := NewAuthState(nil) 146 147 // we copy the host key here to avoid a data race later. 148 e.cfg.HostDb.saveMut.Lock() 149 a.HostKey = e.cfg.HostDb.HostSshSigner 150 e.cfg.HostDb.saveMut.Unlock() 151 152 // don't Close()! We may want to re-use this listener 153 // for another Accept(). 154 // defer b.halt.MarkDone() 155 156 for { 157 // TODO: fail2ban: notice bad login IPs and if too many, block the IP. 158 159 timeoutMillisec := 1000 160 err := b.lsn.(*net.TCPListener). 161 SetDeadline(time.Now(). 162 Add(time.Duration(timeoutMillisec) * time.Millisecond)) 163 panicOn(err) 164 nConn, err := b.lsn.Accept() 165 p("back from Accept, err = %v", err) 166 if err != nil { 167 // simple timeout, check if stop requested 168 // 'accept tcp 127.0.0.1:54796: i/o timeout' 169 // p("simple timeout err: '%v'", err) 170 select { 171 case <-e.Halt.ReqStopChan(): 172 p("e.Halt.ReqStop detected") 173 return nil, fmt.Errorf("shutting down") 174 case <-b.halt.ReqStopChan(): 175 p("b.halt.ReqStop detected") 176 return nil, fmt.Errorf("shutting down") 177 default: 178 // no stop request, keep looping 179 //p("not stop request, keep looping") 180 } 181 continue 182 } 183 p("info: Essh.Accept() in listen.go: accepted new connection on "+ 184 "domain '%s', addr: '%s'", b.dom, e.cfg.EmbeddedSSHd.Addr) 185 186 attempt := NewPerAttempt(a, e.cfg) 187 attempt.SetupAuthRequirements() 188 189 // need to get the direct-tcp connection back directly. 190 ca := &ConnectionAlert{ 191 PortOne: make(chan ssh.Channel), 192 ShutDown: b.esshd.Halt.ReqStopChan(), 193 } 194 err = attempt.PerConnection(ctx, nConn, ca) 195 if err != nil { 196 return nil, err 197 } 198 199 select { 200 case <-b.halt.ReqStopChan(): 201 return nil, fmt.Errorf("shutting down") 202 case <-b.esshd.Halt.ReqStopChan(): 203 return nil, fmt.Errorf("shutting down") 204 case sshc := <-ca.PortOne: 205 return &withLocalAddr{sshc}, nil 206 } 207 } // end for 208 } 209 210 // withLocalAddr wraps an ssh.Channel to 211 // implements the net.Conn missing methods 212 type withLocalAddr struct { 213 ssh.Channel 214 } 215 216 func (w *withLocalAddr) LocalAddr() net.Addr { 217 panic("not implemented") 218 return &BasicAddress{} 219 } 220 func (w *withLocalAddr) RemoteAddr() net.Addr { 221 panic("not implemented") 222 return &BasicAddress{} 223 } 224 225 func (w *withLocalAddr) SetDeadline(t time.Time) error { 226 panic("not implemented") 227 return nil 228 } 229 func (w *withLocalAddr) SetReadDeadline(t time.Time) error { 230 panic("not implemented") 231 return nil 232 } 233 func (w *withLocalAddr) SetWriteDeadline(t time.Time) error { 234 panic("not implemented") 235 return nil 236 }