-
-
Save ivan1993spb/5a92dd48f5842f95fc00ff3af11e9055 to your computer and use it in GitHub Desktop.
Revisions
-
jpillora revised this gist
Jun 22, 2016 . No changes.There are no files selected for viewing
-
jpillora revised this gist
Jun 22, 2016 . No changes.There are no files selected for viewing
-
jpillora revised this gist
Jan 29, 2015 . 1 changed file with 36 additions and 45 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -85,57 +85,51 @@ func main() { log.Printf("New SSH connection from %s (%s)", sshConn.RemoteAddr(), sshConn.ClientVersion()) // Discard all global out-of-band Requests go ssh.DiscardRequests(reqs) // Accept all channels go handleChannels(chans) } } func handleChannels(chans <-chan ssh.NewChannel) { // Service the incoming Channel channel in go routine for newChannel := range chans { go handleChannel(newChannel) } } func handleChannel(newChannel ssh.NewChannel) { // Since we're handling a shell, we expect a // channel type of "session". The also describes // "x11", "direct-tcpip" and "forwarded-tcpip" // channel types. if t := newChannel.ChannelType(); t != "session" { newChannel.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %s", t)) return } // At this point, we have the opportunity to reject the client's // request for another logical connection connection, requests, err := newChannel.Accept() if err != nil { log.Printf("Could not accept channel (%s)", err) return } // Fire up bash for this session bash := exec.Command("bash") // Prepare teardown function close := func() { connection.Close() _, err := bash.Process.Wait() if err != nil { log.Printf("Failed to exit bash (%s)", err) } log.Printf("Session closed") } // Allocate a terminal for this channel log.Print("Creating pty...") bashf, err := pty.Start(bash) if err != nil { @@ -144,6 +138,17 @@ func handleChannel(channel ssh.Channel, requests <-chan *ssh.Request) { return } //pipe session to bash and visa-versa var once sync.Once go func() { io.Copy(connection, bashf) once.Do(close) }() go func() { io.Copy(bashf, connection) once.Do(close) }() // Sessions have out-of-band requests such as "shell", "pty-req" and "env" go func() { for req := range requests { @@ -165,22 +170,8 @@ func handleChannel(channel ssh.Channel, requests <-chan *ssh.Request) { w, h := parseDims(req.Payload) SetWinsize(bashf.Fd(), w, h) } } }() } // ======================= @@ -208,4 +199,4 @@ func SetWinsize(fd uintptr, w, h uint32) { syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws))) } // Borrowed from https://github.com/creack/termios/blob/master/win/win.go -
jpillora revised this gist
Dec 26, 2014 . 1 changed file with 71 additions and 69 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ // A small SSH daemon providing bash sessions // // Server: // cd my/new/dir/ @@ -8,7 +8,7 @@ // go run sshd.go // // Client: // ssh foo@localhost -p 2200 #pass=bar package main @@ -44,7 +44,8 @@ func main() { } return nil, fmt.Errorf("password rejected for %q", c.User()) }, // You may also explicitly allow anonymous client authentication, though anon bash // sessions may not be a wise idea // NoClientAuth: true, } @@ -62,13 +63,13 @@ func main() { config.AddHostKey(private) // Once a ServerConfig has been configured, connections can be accepted. listener, err := net.Listen("tcp", "0.0.0.0:2200") if err != nil { log.Fatalf("Failed to listen on 2200 (%s)", err) } // Accept all connections log.Print("Listening on 2200...") for { tcpConn, err := listener.Accept() if err != nil { @@ -90,9 +91,9 @@ func main() { } } func handleRequests(requests <-chan *ssh.Request) { for req := range requests { log.Printf("Recieved out-of-band request: %+v", req) } } @@ -111,73 +112,75 @@ func handleChannels(chans <-chan ssh.NewChannel) { // request for another logical connection channel, requests, err := newChannel.Accept() if err != nil { log.Printf("Could not accept channel (%s)", err) continue } handleChannel(channel, requests) } } func handleChannel(channel ssh.Channel, requests <-chan *ssh.Request) { // fire up bash for this session bash := exec.Command("bash") // prepare teardown function close := func() { channel.Close() _, err := bash.Process.Wait() if err != nil { log.Printf("Failed to exit bash (%s)", err) } log.Printf("Session closed") } // allocate a terminal for this channel log.Print("Creating pty...") bashf, err := pty.Start(bash) if err != nil { log.Printf("Could not start pty (%s)", err) close() return } // Sessions have out-of-band requests such as "shell", "pty-req" and "env" go func() { for req := range requests { switch req.Type { case "shell": // We only accept the default shell // (i.e. no command in the Payload) if len(req.Payload) == 0 { req.Reply(true, nil) } case "pty-req": termLen := req.Payload[3] w, h := parseDims(req.Payload[termLen+4:]) SetWinsize(bashf.Fd(), w, h) // Responding true (OK) here will let the client // know we have a pty ready for input req.Reply(true, nil) case "window-change": w, h := parseDims(req.Payload) SetWinsize(bashf.Fd(), w, h) } } }() //pipe session to bash and visa-versa var once sync.Once go func() { io.Copy(channel, bashf) once.Do(close) }() go func() { io.Copy(bashf, channel) once.Do(close) }() //*important* - does not block } // ======================= @@ -201,7 +204,6 @@ type Winsize struct { // SetWinsize sets the size of the given pty. func SetWinsize(fd uintptr, w, h uint32) { ws := &Winsize{Width: uint16(w), Height: uint16(h)} syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws))) } -
jpillora revised this gist
Dec 23, 2014 . 1 changed file with 36 additions and 26 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,7 +2,8 @@ // // Server: // cd my/new/dir/ // #generate server keypair // ssh-keygen -t rsa // go get -v . // go run sshd.go // @@ -29,20 +30,25 @@ import ( func main() { // In the latest version of crypto/ssh (after Go 1.3), the SSH server type has been removed // in favour of an SSH connection type. A ssh.ServerConn is created by passing an existing // net.Conn and a ssh.ServerConfig to ssh.NewServerConn, in effect, upgrading the net.Conn // into an ssh.ServerConn config := &ssh.ServerConfig{ //Define a function to run when a client attempts a password login PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { // Should use constant-time compare (or better, salt+hash) in a production setting. if c.User() == "foo" && string(pass) == "bar" { return nil, nil } return nil, fmt.Errorf("password rejected for %q", c.User()) }, // You may also explicitly allow anonymous client authentication // NoClientAuth: true, } // You can generate a keypair with 'ssh-keygen -t rsa' privateBytes, err := ioutil.ReadFile("id_rsa") if err != nil { log.Fatal("Failed to load private key (./id_rsa)") @@ -58,26 +64,26 @@ func main() { // Once a ServerConfig has been configured, connections can be accepted. listener, err := net.Listen("tcp", "0.0.0.0:2022") if err != nil { log.Fatal("Failed to listen on 2022") } // Accept all connections log.Print("Listening on 2022...") for { tcpConn, err := listener.Accept() if err != nil { log.Printf("Failed to accept incoming connection (%s)", err) continue } // Before use, a handshake must be performed on the incoming net.Conn. sshConn, chans, reqs, err := ssh.NewServerConn(tcpConn, config) if err != nil { log.Printf("Failed to handshake (%s)", err) continue } log.Printf("New SSH connection from %s (%s)", sshConn.RemoteAddr(), sshConn.ClientVersion()) // Discard all global out-of-band Requests go handleRequests(reqs) // Accept all channels go handleChannels(chans) @@ -93,26 +99,26 @@ func handleRequests(reqs <-chan *ssh.Request) { func handleChannels(chans <-chan ssh.NewChannel) { // Service the incoming Channel channel. for newChannel := range chans { // Since we're handling the execution of a shell, we expect a // channel type of "session". However, there are also: "x11", "direct-tcpip" // and "forwarded-tcpip" channel types. if t := newChannel.ChannelType(); t != "session" { newChannel.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %s", t)) continue } // At this point, we have the opportunity to reject the client's // request for another logical connection channel, requests, err := newChannel.Accept() if err != nil { log.Printf("could not accept channel (%s)", err) continue } // fire up bash for this session bash := exec.Command("bash") // allocate a terminal for this channel log.Print("creating pty...") bashf, err := pty.Start(bash) if err != nil { log.Printf("could not start pty (%s)", err) continue @@ -122,7 +128,7 @@ func handleChannels(chans <-chan ssh.NewChannel) { var once sync.Once close := func() { channel.Close() _, err := bash.Process.Wait() if err != nil { log.Printf("failed to exit bash (%s)", err) } @@ -131,11 +137,11 @@ func handleChannels(chans <-chan ssh.NewChannel) { //pipe session to bash and visa-versa go func() { io.Copy(channel, bashf) once.Do(close) }() go func() { io.Copy(bashf, channel) once.Do(close) }() @@ -158,11 +164,11 @@ func handleChannels(chans <-chan ssh.NewChannel) { termLen := req.Payload[3] termEnv := string(req.Payload[4 : termLen+4]) w, h := parseDims(req.Payload[termLen+4:]) SetWinsize(bashf.Fd(), w, h) log.Printf("pty-req '%s'", termEnv) case "window-change": w, h := parseDims(req.Payload) SetWinsize(bashf.Fd(), w, h) continue //no response } if !ok { @@ -176,13 +182,15 @@ func handleChannels(chans <-chan ssh.NewChannel) { // ======================= // parseDims extracts terminal dimensions (width x height) from the provided buffer. func parseDims(b []byte) (uint32, uint32) { w := binary.BigEndian.Uint32(b) h := binary.BigEndian.Uint32(b[4:]) return w, h } // ====================== // Winsize stores the Height and Width of a terminal. type Winsize struct { Height uint16 @@ -197,3 +205,5 @@ func SetWinsize(fd uintptr, w, h uint32) { ws := &Winsize{Width: uint16(w), Height: uint16(h)} syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws))) } // Borrowed from https://github.com/creack/termios/blob/master/win/win.go -
jpillora revised this gist
Dec 3, 2014 . 1 changed file with 4 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -122,6 +122,10 @@ func handleChannels(chans <-chan ssh.NewChannel) { var once sync.Once close := func() { channel.Close() _, err := c.Process.Wait() if err != nil { log.Printf("failed to exit bash (%s)", err) } log.Printf("session closed") } -
jpillora revised this gist
Dec 2, 2014 . 1 changed file with 5 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -32,6 +32,7 @@ func main() { // An SSH server is represented by a ServerConfig, which holds // certificate details and handles authentication of ServerConns. config := &ssh.ServerConfig{ // NoClientAuth: true, PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { // Should use constant-time compare (or better, salt+hash) in a production setting. if c.User() == "foo" && string(pass) == "bar" { @@ -76,7 +77,7 @@ func main() { } log.Printf("new ssh connection from %s (%s)", sshConn.RemoteAddr(), sshConn.ClientVersion()) // Print incoming out-of-band Requests go handleRequests(reqs) // Accept all channels go handleChannels(chans) @@ -85,7 +86,7 @@ func main() { func handleRequests(reqs <-chan *ssh.Request) { for req := range reqs { log.Printf("recieved out-of-band request: %+v", req) } } @@ -124,7 +125,7 @@ func handleChannels(chans <-chan ssh.NewChannel) { log.Printf("session closed") } //pipe session to bash and visa-versa go func() { io.Copy(channel, f) once.Do(close) @@ -170,8 +171,8 @@ func handleChannels(chans <-chan ssh.NewChannel) { } // ======================= // parseDims extracts two uint32s from the provided buffer. func parseDims(b []byte) (uint32, uint32) { w := binary.BigEndian.Uint32(b) h := binary.BigEndian.Uint32(b[4:]) -
jpillora revised this gist
Dec 2, 2014 . 1 changed file with 3 additions and 8 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,11 +1,9 @@ // A simple SSH server providing bash sessions // // Server: // cd my/new/dir/ // ssh-keygen -t rsa #generate server keypair // go get -v . // go run sshd.go // // Client: @@ -136,12 +134,9 @@ func handleChannels(chans <-chan ssh.NewChannel) { once.Do(close) }() // Sessions have out-of-band requests such as "shell", "pty-req" and "env" go func(in <-chan *ssh.Request) { for req := range in { ok := false switch req.Type { case "shell": -
jpillora revised this gist
Dec 2, 2014 . 1 changed file with 58 additions and 16 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,17 +1,32 @@ // A simple SSH server providing bash sessions // // Requires: // go get github.com/kr/pty // go get golang.org/x/crypto/ssh // // Server: // ssh-keygen -t rsa #generate server keypair // go run sshd.go // // Client: // ssh foo@localhost -p 2022 #pass=bar package main import ( "encoding/binary" "fmt" "io" "io/ioutil" "log" "net" "os/exec" "sync" "syscall" "unsafe" "github.com/kr/pty" "golang.org/x/crypto/ssh" ) func main() { @@ -20,8 +35,7 @@ func main() { // certificate details and handles authentication of ServerConns. config := &ssh.ServerConfig{ PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { // Should use constant-time compare (or better, salt+hash) in a production setting. if c.User() == "foo" && string(pass) == "bar" { return nil, nil } @@ -95,7 +109,7 @@ func handleChannels(chans <-chan ssh.NewChannel) { } // allocate a terminal for this channel log.Print("creating pty...") //fire up bash for this session c := exec.Command("bash") @@ -105,19 +119,9 @@ func handleChannels(chans <-chan ssh.NewChannel) { continue } //teardown session var once sync.Once close := func() { channel.Close() log.Printf("session closed") } @@ -137,15 +141,29 @@ func handleChannels(chans <-chan ssh.NewChannel) { // "shell" request. go func(in <-chan *ssh.Request) { for req := range in { 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 // Parse body... termLen := req.Payload[3] termEnv := string(req.Payload[4 : termLen+4]) w, h := parseDims(req.Payload[termLen+4:]) SetWinsize(f.Fd(), w, h) log.Printf("pty-req '%s'", termEnv) case "window-change": w, h := parseDims(req.Payload) SetWinsize(f.Fd(), w, h) continue //no response } if !ok { log.Printf("declining %s request...", req.Type) @@ -155,3 +173,27 @@ func handleChannels(chans <-chan ssh.NewChannel) { }(requests) } } // ======================= // Window size helpers func parseDims(b []byte) (uint32, uint32) { w := binary.BigEndian.Uint32(b) h := binary.BigEndian.Uint32(b[4:]) return w, h } // Winsize stores the Height and Width of a terminal. type Winsize struct { Height uint16 Width uint16 x uint16 // unused y uint16 // unused } // SetWinsize sets the size of the given pty. func SetWinsize(fd uintptr, w, h uint32) { log.Printf("window resize %dx%d", w, h) ws := &Winsize{Width: uint16(w), Height: uint16(h)} syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws))) } -
jpillora revised this gist
Dec 2, 2014 . 1 changed file with 48 additions and 24 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -2,12 +2,16 @@ package main import ( "fmt" "io" "io/ioutil" "log" "net" "os/exec" "sync" "github.com/kr/pty" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/terminal" ) func main() { @@ -80,8 +84,8 @@ func handleChannels(chans <-chan ssh.NewChannel) { // protocol intended. In the case of a shell, the type is // "session" and ServerShell may be used to present a simple // terminal interface. if t := newChannel.ChannelType(); t != "session" { newChannel.Reject(ssh.UnknownChannelType, fmt.Sprintf("unknown channel type: %s", t)) continue } channel, requests, err := newChannel.Accept() @@ -90,6 +94,44 @@ func handleChannels(chans <-chan ssh.NewChannel) { continue } // allocate a terminal for this channel log.Print("allocating terminal...") //fire up bash for this session c := exec.Command("bash") f, err := pty.Start(c) if err != nil { log.Printf("could not start pty (%s)", err) continue } //this might be wrong? fd := int(f.Fd()) //set raw mode prev, err := terminal.MakeRaw(fd) if err != nil { log.Printf("could not set raw mode (%s)", err) continue } var once sync.Once close := func() { terminal.Restore(fd, prev) channel.Close() log.Printf("session closed") } //link session and bash streams go func() { io.Copy(channel, f) once.Do(close) }() go func() { io.Copy(f, channel) once.Do(close) }() // Sessions have out-of-band requests such as "shell", // "pty-req" and "env". Here we handle only the // "shell" request. @@ -98,36 +140,18 @@ func handleChannels(chans <-chan ssh.NewChannel) { 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 log.Printf("accepting shell request...") } } if !ok { log.Printf("declining %s request...", req.Type) } req.Reply(ok, nil) } }(requests) } } -
jpillora created this gist
Dec 1, 2014 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,133 @@ package main import ( "fmt" "io/ioutil" "log" "net" "code.google.com/p/go.crypto/ssh" "code.google.com/p/go.crypto/ssh/terminal" ) func main() { // An SSH server is represented by a ServerConfig, which holds // certificate details and handles authentication of ServerConns. config := &ssh.ServerConfig{ PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { // Should use constant-time compare (or better, salt+hash) in // a production setting. if c.User() == "foo" && string(pass) == "bar" { return nil, nil } return nil, fmt.Errorf("password rejected for %q", c.User()) }, } // You can generate a keypair with 'ssh-keygen -t rsa -C "[email protected]"' privateBytes, err := ioutil.ReadFile("id_rsa") if err != nil { log.Fatal("Failed to load private key (./id_rsa)") } private, err := ssh.ParsePrivateKey(privateBytes) if err != nil { log.Fatal("Failed to parse private key") } config.AddHostKey(private) // Once a ServerConfig has been configured, connections can be accepted. listener, err := net.Listen("tcp", "0.0.0.0:2022") if err != nil { log.Fatal("failed to listen on 2022") } // Accept all connections log.Print("listening on 2022...") for { tcpConn, err := listener.Accept() if err != nil { log.Printf("failed to accept incoming connection (%s)", err) continue } // Before use, a handshake must be performed on the incoming net.Conn. sshConn, chans, reqs, err := ssh.NewServerConn(tcpConn, config) if err != nil { log.Printf("failed to handshake (%s)", err) continue } log.Printf("new ssh connection from %s (%s)", sshConn.RemoteAddr(), sshConn.ClientVersion()) // Print incoming [out-of-band] Requests go handleRequests(reqs) // Accept all channels go handleChannels(chans) } } func handleRequests(reqs <-chan *ssh.Request) { for req := range reqs { log.Printf("recieved request: %+v", req) } } func handleChannels(chans <-chan ssh.NewChannel) { // Service the incoming Channel channel. for newChannel := range chans { // Channels have a type, depending on the application level // protocol intended. In the case of a shell, the type is // "session" and ServerShell may be used to present a simple // terminal interface. if newChannel.ChannelType() != "session" { newChannel.Reject(ssh.UnknownChannelType, "unknown channel type") continue } channel, requests, err := newChannel.Accept() if err != nil { log.Printf("could not accept channel (%s)", err) continue } // Sessions have out-of-band requests such as "shell", // "pty-req" and "env". Here we handle only the // "shell" request. go func(in <-chan *ssh.Request) { for req := range in { ok := false switch req.Type { case "shell": if len(req.Payload) == 0 { // We don't accept any // commands, only the // default shell. ok = true log.Printf("accepting shell request...") } } if !ok { log.Printf("declining %s request...", req.Type) } req.Reply(ok, nil) } }(requests) //allocate a terminal for this channel log.Print("allocating terminal...") term := terminal.NewTerminal(channel, "> ") go func() { defer channel.Close() for { line, err := term.ReadLine() if err != nil { log.Printf("could not read line (%s)", err) break } log.Printf("recieved: %s", line) } }() } }