example_test.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package ssh_test
  5. import (
  6. "bufio"
  7. "bytes"
  8. "fmt"
  9. "io/ioutil"
  10. "log"
  11. "net"
  12. "net/http"
  13. "os"
  14. "path/filepath"
  15. "strings"
  16. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/ssh"
  17. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/ssh/terminal"
  18. )
  19. func ExampleNewServerConn() {
  20. // Public key authentication is done by comparing
  21. // the public key of a received connection
  22. // with the entries in the authorized_keys file.
  23. authorizedKeysBytes, err := ioutil.ReadFile("authorized_keys")
  24. if err != nil {
  25. log.Fatalf("Failed to load authorized_keys, err: %v", err)
  26. }
  27. authorizedKeysMap := map[string]bool{}
  28. for len(authorizedKeysBytes) > 0 {
  29. pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)
  30. if err != nil {
  31. log.Fatal(err)
  32. }
  33. authorizedKeysMap[string(pubKey.Marshal())] = true
  34. authorizedKeysBytes = rest
  35. }
  36. // An SSH server is represented by a ServerConfig, which holds
  37. // certificate details and handles authentication of ServerConns.
  38. config := &ssh.ServerConfig{
  39. // Remove to disable password auth.
  40. PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
  41. // Should use constant-time compare (or better, salt+hash) in
  42. // a production setting.
  43. if c.User() == "testuser" && string(pass) == "tiger" {
  44. return nil, nil
  45. }
  46. return nil, fmt.Errorf("password rejected for %q", c.User())
  47. },
  48. // Remove to disable public key auth.
  49. PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
  50. if authorizedKeysMap[string(pubKey.Marshal())] {
  51. return &ssh.Permissions{
  52. // Record the public key used for authentication.
  53. Extensions: map[string]string{
  54. "pubkey-fp": ssh.FingerprintSHA256(pubKey),
  55. },
  56. }, nil
  57. }
  58. return nil, fmt.Errorf("unknown public key for %q", c.User())
  59. },
  60. }
  61. privateBytes, err := ioutil.ReadFile("id_rsa")
  62. if err != nil {
  63. log.Fatal("Failed to load private key: ", err)
  64. }
  65. private, err := ssh.ParsePrivateKey(privateBytes)
  66. if err != nil {
  67. log.Fatal("Failed to parse private key: ", err)
  68. }
  69. config.AddHostKey(private)
  70. // Once a ServerConfig has been configured, connections can be
  71. // accepted.
  72. listener, err := net.Listen("tcp", "0.0.0.0:2022")
  73. if err != nil {
  74. log.Fatal("failed to listen for connection: ", err)
  75. }
  76. nConn, err := listener.Accept()
  77. if err != nil {
  78. log.Fatal("failed to accept incoming connection: ", err)
  79. }
  80. // Before use, a handshake must be performed on the incoming
  81. // net.Conn.
  82. conn, chans, reqs, err := ssh.NewServerConn(nConn, config)
  83. if err != nil {
  84. log.Fatal("failed to handshake: ", err)
  85. }
  86. log.Printf("logged in with key %s", conn.Permissions.Extensions["pubkey-fp"])
  87. // The incoming Request channel must be serviced.
  88. go ssh.DiscardRequests(reqs)
  89. // Service the incoming Channel channel.
  90. for newChannel := range chans {
  91. // Channels have a type, depending on the application level
  92. // protocol intended. In the case of a shell, the type is
  93. // "session" and ServerShell may be used to present a simple
  94. // terminal interface.
  95. if newChannel.ChannelType() != "session" {
  96. newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
  97. continue
  98. }
  99. channel, requests, err := newChannel.Accept()
  100. if err != nil {
  101. log.Fatalf("Could not accept channel: %v", err)
  102. }
  103. // Sessions have out-of-band requests such as "shell",
  104. // "pty-req" and "env". Here we handle only the
  105. // "shell" request.
  106. go func(in <-chan *ssh.Request) {
  107. for req := range in {
  108. req.Reply(req.Type == "shell", nil)
  109. }
  110. }(requests)
  111. term := terminal.NewTerminal(channel, "> ")
  112. go func() {
  113. defer channel.Close()
  114. for {
  115. line, err := term.ReadLine()
  116. if err != nil {
  117. break
  118. }
  119. fmt.Println(line)
  120. }
  121. }()
  122. }
  123. }
  124. func ExampleClientConfig_HostKeyCallback() {
  125. // Every client must provide a host key check. Here is a
  126. // simple-minded parse of OpenSSH's known_hosts file
  127. host := "hostname"
  128. file, err := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "known_hosts"))
  129. if err != nil {
  130. log.Fatal(err)
  131. }
  132. defer file.Close()
  133. scanner := bufio.NewScanner(file)
  134. var hostKey ssh.PublicKey
  135. for scanner.Scan() {
  136. fields := strings.Split(scanner.Text(), " ")
  137. if len(fields) != 3 {
  138. continue
  139. }
  140. if strings.Contains(fields[0], host) {
  141. var err error
  142. hostKey, _, _, _, err = ssh.ParseAuthorizedKey(scanner.Bytes())
  143. if err != nil {
  144. log.Fatalf("error parsing %q: %v", fields[2], err)
  145. }
  146. break
  147. }
  148. }
  149. if hostKey == nil {
  150. log.Fatalf("no hostkey for %s", host)
  151. }
  152. config := ssh.ClientConfig{
  153. User: os.Getenv("USER"),
  154. HostKeyCallback: ssh.FixedHostKey(hostKey),
  155. }
  156. _, err = ssh.Dial("tcp", host+":22", &config)
  157. log.Println(err)
  158. }
  159. func ExampleDial() {
  160. var hostKey ssh.PublicKey
  161. // An SSH client is represented with a ClientConn.
  162. //
  163. // To authenticate with the remote server you must pass at least one
  164. // implementation of AuthMethod via the Auth field in ClientConfig,
  165. // and provide a HostKeyCallback.
  166. config := &ssh.ClientConfig{
  167. User: "username",
  168. Auth: []ssh.AuthMethod{
  169. ssh.Password("yourpassword"),
  170. },
  171. HostKeyCallback: ssh.FixedHostKey(hostKey),
  172. }
  173. client, err := ssh.Dial("tcp", "yourserver.com:22", config)
  174. if err != nil {
  175. log.Fatal("Failed to dial: ", err)
  176. }
  177. defer client.Close()
  178. // Each ClientConn can support multiple interactive sessions,
  179. // represented by a Session.
  180. session, err := client.NewSession()
  181. if err != nil {
  182. log.Fatal("Failed to create session: ", err)
  183. }
  184. defer session.Close()
  185. // Once a Session is created, you can execute a single command on
  186. // the remote side using the Run method.
  187. var b bytes.Buffer
  188. session.Stdout = &b
  189. if err := session.Run("/usr/bin/whoami"); err != nil {
  190. log.Fatal("Failed to run: " + err.Error())
  191. }
  192. fmt.Println(b.String())
  193. }
  194. func ExamplePublicKeys() {
  195. var hostKey ssh.PublicKey
  196. // A public key may be used to authenticate against the remote
  197. // server by using an unencrypted PEM-encoded private key file.
  198. //
  199. // If you have an encrypted private key, the crypto/x509 package
  200. // can be used to decrypt it.
  201. key, err := ioutil.ReadFile("/home/user/.ssh/id_rsa")
  202. if err != nil {
  203. log.Fatalf("unable to read private key: %v", err)
  204. }
  205. // Create the Signer for this private key.
  206. signer, err := ssh.ParsePrivateKey(key)
  207. if err != nil {
  208. log.Fatalf("unable to parse private key: %v", err)
  209. }
  210. config := &ssh.ClientConfig{
  211. User: "user",
  212. Auth: []ssh.AuthMethod{
  213. // Use the PublicKeys method for remote authentication.
  214. ssh.PublicKeys(signer),
  215. },
  216. HostKeyCallback: ssh.FixedHostKey(hostKey),
  217. }
  218. // Connect to the remote server and perform the SSH handshake.
  219. client, err := ssh.Dial("tcp", "host.com:22", config)
  220. if err != nil {
  221. log.Fatalf("unable to connect: %v", err)
  222. }
  223. defer client.Close()
  224. }
  225. func ExampleClient_Listen() {
  226. var hostKey ssh.PublicKey
  227. config := &ssh.ClientConfig{
  228. User: "username",
  229. Auth: []ssh.AuthMethod{
  230. ssh.Password("password"),
  231. },
  232. HostKeyCallback: ssh.FixedHostKey(hostKey),
  233. }
  234. // Dial your ssh server.
  235. conn, err := ssh.Dial("tcp", "localhost:22", config)
  236. if err != nil {
  237. log.Fatal("unable to connect: ", err)
  238. }
  239. defer conn.Close()
  240. // Request the remote side to open port 8080 on all interfaces.
  241. l, err := conn.Listen("tcp", "0.0.0.0:8080")
  242. if err != nil {
  243. log.Fatal("unable to register tcp forward: ", err)
  244. }
  245. defer l.Close()
  246. // Serve HTTP with your SSH server acting as a reverse proxy.
  247. http.Serve(l, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
  248. fmt.Fprintf(resp, "Hello world!\n")
  249. }))
  250. }
  251. func ExampleSession_RequestPty() {
  252. var hostKey ssh.PublicKey
  253. // Create client config
  254. config := &ssh.ClientConfig{
  255. User: "username",
  256. Auth: []ssh.AuthMethod{
  257. ssh.Password("password"),
  258. },
  259. HostKeyCallback: ssh.FixedHostKey(hostKey),
  260. }
  261. // Connect to ssh server
  262. conn, err := ssh.Dial("tcp", "localhost:22", config)
  263. if err != nil {
  264. log.Fatal("unable to connect: ", err)
  265. }
  266. defer conn.Close()
  267. // Create a session
  268. session, err := conn.NewSession()
  269. if err != nil {
  270. log.Fatal("unable to create session: ", err)
  271. }
  272. defer session.Close()
  273. // Set up terminal modes
  274. modes := ssh.TerminalModes{
  275. ssh.ECHO: 0, // disable echoing
  276. ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
  277. ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
  278. }
  279. // Request pseudo terminal
  280. if err := session.RequestPty("xterm", 40, 80, modes); err != nil {
  281. log.Fatal("request for pseudo terminal failed: ", err)
  282. }
  283. // Start remote shell
  284. if err := session.Shell(); err != nil {
  285. log.Fatal("failed to start shell: ", err)
  286. }
  287. }