mirror of
https://github.com/shazow/ssh-chat.git
synced 2025-04-13 07:37:17 +03:00
Progress: Echo working.
This commit is contained in:
commit
d2aec8cc44
75
cmd.go
Normal file
75
cmd.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
|
||||||
|
"github.com/alexcesaro/log"
|
||||||
|
"github.com/alexcesaro/log/golog"
|
||||||
|
"github.com/jessevdk/go-flags"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
Verbose []bool `short:"v" long:"verbose" description:"Show verbose logging."`
|
||||||
|
Bind string `short:"b" long:"bind" description:"Host and port to listen on." default:"0.0.0.0:22"`
|
||||||
|
Identity string `short:"i" long:"identity" description:"Private key to identify server with." default:"~/.ssh/id_rsa"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var logLevels = []log.Level{
|
||||||
|
log.Warning,
|
||||||
|
log.Info,
|
||||||
|
log.Debug,
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
options := Options{}
|
||||||
|
parser := flags.NewParser(&options, flags.Default)
|
||||||
|
|
||||||
|
p, err := parser.Parse()
|
||||||
|
if err != nil {
|
||||||
|
if p == nil {
|
||||||
|
fmt.Print(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out the log level
|
||||||
|
numVerbose := len(options.Verbose)
|
||||||
|
if numVerbose > len(logLevels) {
|
||||||
|
numVerbose = len(logLevels)
|
||||||
|
}
|
||||||
|
|
||||||
|
logLevel := logLevels[numVerbose]
|
||||||
|
logger = golog.New(os.Stderr, logLevel)
|
||||||
|
|
||||||
|
privateKey, err := ioutil.ReadFile(options.Identity)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to load identity: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
server, err := NewServer(privateKey)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to create server: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct interrupt handler
|
||||||
|
sig := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sig, os.Interrupt)
|
||||||
|
go func() {
|
||||||
|
<-sig // Wait for ^C signal
|
||||||
|
logger.Warningf("Interrupt signal detected, shutting down.")
|
||||||
|
server.Stop()
|
||||||
|
}()
|
||||||
|
|
||||||
|
done, err := server.Start(options.Bind)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to start server: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
<-done
|
||||||
|
}
|
7
logger.go
Normal file
7
logger.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/alexcesaro/log/golog"
|
||||||
|
)
|
||||||
|
|
||||||
|
var logger *golog.Logger
|
142
server.go
Normal file
142
server.go
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
// TODO: NoClientAuth
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
sshConfig *ssh.ServerConfig
|
||||||
|
sshSigner *ssh.Signer
|
||||||
|
socket *net.Listener
|
||||||
|
done chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(privateKey []byte) (*Server, error) {
|
||||||
|
signer, err := ssh.ParsePrivateKey(privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config := ssh.ServerConfig{
|
||||||
|
NoClientAuth: true,
|
||||||
|
}
|
||||||
|
config.AddHostKey(signer)
|
||||||
|
|
||||||
|
server := Server{
|
||||||
|
sshConfig: &config,
|
||||||
|
sshSigner: &signer,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &server, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleShell(channel ssh.Channel) {
|
||||||
|
defer channel.Close()
|
||||||
|
|
||||||
|
term := terminal.NewTerminal(channel, "")
|
||||||
|
|
||||||
|
for {
|
||||||
|
line, err := term.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch line {
|
||||||
|
case "exit":
|
||||||
|
channel.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
term.Write([]byte("you wrote: " + string(line) + "\r\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleChannels(channels <-chan ssh.NewChannel) {
|
||||||
|
for ch := range channels {
|
||||||
|
if t := ch.ChannelType(); t != "session" {
|
||||||
|
ch.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %s", t))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, requests, err := ch.Accept()
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Could not accept channel: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
go func(in <-chan *ssh.Request) {
|
||||||
|
defer channel.Close()
|
||||||
|
for req := range in {
|
||||||
|
logger.Infof("Request: ", req.Type, string(req.Payload))
|
||||||
|
|
||||||
|
ok := false
|
||||||
|
switch req.Type {
|
||||||
|
case "shell":
|
||||||
|
// We don't accept any commands (Payload),
|
||||||
|
// only the default shell.
|
||||||
|
if len(req.Payload) == 0 {
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
case "pty-req":
|
||||||
|
// Responding 'ok' here will let the client
|
||||||
|
// know we have a pty ready for input
|
||||||
|
ok = true
|
||||||
|
case "window-change":
|
||||||
|
continue //no response
|
||||||
|
}
|
||||||
|
req.Reply(ok, nil)
|
||||||
|
}
|
||||||
|
}(requests)
|
||||||
|
|
||||||
|
go s.handleShell(channel)
|
||||||
|
|
||||||
|
channel.Write([]byte("Hello"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Start(laddr string) (<-chan struct{}, error) {
|
||||||
|
// Once a ServerConfig has been configured, connections can be
|
||||||
|
// accepted.
|
||||||
|
socket, err := net.Listen("tcp", laddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.socket = &socket
|
||||||
|
logger.Infof("Listening on %s", laddr)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
conn, err := socket.Accept()
|
||||||
|
if err != nil {
|
||||||
|
// TODO: Handle shutdown more gracefully.
|
||||||
|
logger.Errorf("Failed to accept connection, aborting loop: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// From a standard TCP connection to an encrypted SSH connection
|
||||||
|
sshConn, channels, requests, err := ssh.NewServerConn(conn, s.sshConfig)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to handshake: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Infof("Connection from: %s, %s, %s", sshConn.RemoteAddr(), sshConn.User(), sshConn.ClientVersion())
|
||||||
|
|
||||||
|
go ssh.DiscardRequests(requests)
|
||||||
|
go s.handleChannels(channels)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return s.done, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Stop() error {
|
||||||
|
err := (*s.socket).Close()
|
||||||
|
s.done <- struct{}{}
|
||||||
|
return err
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user