Secure Client for exposing TLS (aka SSL) secured services as plain-text connections locally, and for multiplexing a single port with multiple protocols using SNI
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sclient.go 2.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package main
  2. import (
  3. "crypto/tls"
  4. "fmt"
  5. "io"
  6. "net"
  7. "os"
  8. "strconv"
  9. "strings"
  10. )
  11. type SclientOpts struct {
  12. RemoteAddress string
  13. RemotePort int
  14. LocalAddress string
  15. LocalPort int
  16. InsecureSkipVerify bool
  17. }
  18. type Sclient struct{}
  19. func pipe(r net.Conn, w net.Conn, t string) {
  20. buffer := make([]byte, 2048)
  21. for {
  22. done := false
  23. // NOTE: count may be > 0 even if there's an err
  24. count, err := r.Read(buffer)
  25. //fmt.Fprintf(os.Stdout, "[debug] (%s) reading\n", t)
  26. if nil != err {
  27. //fmt.Fprintf(os.Stdout, "[debug] (%s:%d) error reading %s\n", t, count, err)
  28. if io.EOF != err {
  29. fmt.Fprintf(os.Stderr, "[read error] (%s:%s) %s\n", t, count, err)
  30. }
  31. r.Close()
  32. //w.Close()
  33. done = true
  34. }
  35. if 0 == count {
  36. break
  37. }
  38. _, err = w.Write(buffer[:count])
  39. if nil != err {
  40. //fmt.Fprintf(os.Stdout, "[debug] %s error writing\n", t)
  41. if io.EOF != err {
  42. fmt.Fprintf(os.Stderr, "[write error] (%s) %s\n", t, err)
  43. }
  44. // TODO handle error closing?
  45. r.Close()
  46. //w.Close()
  47. done = true
  48. }
  49. if done {
  50. break
  51. }
  52. }
  53. }
  54. func handleConnection(remote string, conn net.Conn, opts *SclientOpts) {
  55. sclient, err := tls.Dial("tcp", remote,
  56. &tls.Config{InsecureSkipVerify: opts.InsecureSkipVerify})
  57. if err != nil {
  58. fmt.Fprintf(os.Stderr, "[error] (remote) %s\n", err)
  59. conn.Close()
  60. return
  61. }
  62. fmt.Fprintf(os.Stdout, "[connect] %s => %s:%d\n",
  63. strings.Replace(conn.RemoteAddr().String(), "[::1]:", "localhost:", 1), opts.RemoteAddress, opts.RemotePort)
  64. go pipe(conn, sclient, "local")
  65. pipe(sclient, conn, "remote")
  66. }
  67. func (*Sclient) DialAndListen(opts *SclientOpts) error {
  68. remote := opts.RemoteAddress + ":" + strconv.Itoa(opts.RemotePort)
  69. conn, err := tls.Dial("tcp", remote,
  70. &tls.Config{InsecureSkipVerify: opts.InsecureSkipVerify})
  71. if err != nil {
  72. fmt.Fprintf(os.Stderr, "[warn] '%s' may not be accepting connections: %s\n", remote, err)
  73. } else {
  74. conn.Close()
  75. }
  76. local := opts.LocalAddress + ":" + strconv.Itoa(opts.LocalPort)
  77. ln, err := net.Listen("tcp", local)
  78. if err != nil {
  79. return err
  80. }
  81. fmt.Fprintf(os.Stdout, "[listening] %s:%d <= %s:%d\n",
  82. opts.RemoteAddress, opts.RemotePort, opts.LocalAddress, opts.LocalPort)
  83. for {
  84. conn, err := ln.Accept()
  85. if nil != err {
  86. fmt.Fprintf(os.Stderr, "[error] %s\n", err)
  87. continue
  88. }
  89. go handleConnection(remote, conn, opts)
  90. }
  91. }