pt.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. // Package pt implements the Tor pluggable transports specification.
  2. //
  3. // Sample client usage:
  4. // var ptInfo pt.ClientInfo
  5. // ...
  6. // func handler(conn *pt.SocksConn) error {
  7. // defer conn.Close()
  8. // remote, err := net.Dial("tcp", conn.Req.Target)
  9. // if err != nil {
  10. // conn.Reject()
  11. // return err
  12. // }
  13. // defer remote.Close()
  14. // err = conn.Grant(remote.RemoteAddr().(*net.TCPAddr))
  15. // if err != nil {
  16. // return err
  17. // }
  18. // // do something with conn and remote.
  19. // return nil
  20. // }
  21. // func acceptLoop(ln *pt.SocksListener) error {
  22. // defer ln.Close()
  23. // for {
  24. // conn, err := ln.AcceptSocks()
  25. // if err != nil {
  26. // if e, ok := err.(net.Error); ok && !e.Temporary() {
  27. // return err
  28. // }
  29. // continue
  30. // }
  31. // go handler(conn)
  32. // }
  33. // return nil
  34. // }
  35. // ...
  36. // func main() {
  37. // var err error
  38. // ptInfo, err = pt.ClientSetup([]string{"foo"})
  39. // if err != nil {
  40. // os.Exit(1)
  41. // }
  42. // for _, methodName := range ptInfo.MethodNames {
  43. // switch methodName {
  44. // case "foo":
  45. // ln, err := pt.ListenSocks("tcp", "127.0.0.1:0")
  46. // if err != nil {
  47. // pt.CmethodError(methodName, err.Error())
  48. // break
  49. // }
  50. // go acceptLoop(ln)
  51. // pt.Cmethod(methodName, ln.Version(), ln.Addr())
  52. // default:
  53. // pt.CmethodError(methodName, "no such method")
  54. // }
  55. // }
  56. // pt.CmethodsDone()
  57. // }
  58. //
  59. // Sample server usage:
  60. // var ptInfo pt.ServerInfo
  61. // ...
  62. // func handler(conn net.Conn) error {
  63. // defer conn.Close()
  64. // or, err := pt.DialOr(&ptInfo, conn.RemoteAddr().String(), "foo")
  65. // if err != nil {
  66. // return
  67. // }
  68. // defer or.Close()
  69. // // do something with or and conn
  70. // return nil
  71. // }
  72. // func acceptLoop(ln net.Listener) error {
  73. // defer ln.Close()
  74. // for {
  75. // conn, err := ln.Accept()
  76. // if err != nil {
  77. // if e, ok := err.(net.Error); ok && !e.Temporary() {
  78. // return err
  79. // }
  80. // continue
  81. // }
  82. // go handler(conn)
  83. // }
  84. // return nil
  85. // }
  86. // ...
  87. // func main() {
  88. // var err error
  89. // ptInfo, err = pt.ServerSetup([]string{"foo"})
  90. // if err != nil {
  91. // os.Exit(1)
  92. // }
  93. // for _, bindaddr := range ptInfo.Bindaddrs {
  94. // switch bindaddr.MethodName {
  95. // case "foo":
  96. // ln, err := net.ListenTCP("tcp", bindaddr.Addr)
  97. // if err != nil {
  98. // pt.SmethodError(bindaddr.MethodName, err.Error())
  99. // break
  100. // }
  101. // go acceptLoop(ln)
  102. // pt.Smethod(bindaddr.MethodName, ln.Addr())
  103. // default:
  104. // pt.SmethodError(bindaddr.MethodName, "no such method")
  105. // }
  106. // }
  107. // pt.SmethodsDone()
  108. // }
  109. //
  110. // Some additional care is needed to handle SIGINT and shutdown properly. See
  111. // the example programs dummy-client and dummy-server.
  112. //
  113. // Tor pluggable transports specification:
  114. // https://gitweb.torproject.org/torspec.git/blob/HEAD:/pt-spec.txt.
  115. //
  116. // Extended ORPort:
  117. // https://gitweb.torproject.org/torspec.git/blob/HEAD:/proposals/196-transport-control-ports.txt.
  118. //
  119. // Extended ORPort Authentication:
  120. // https://gitweb.torproject.org/torspec.git/blob/HEAD:/proposals/217-ext-orport-auth.txt.
  121. //
  122. // The package implements a SOCKS5 server sufficient for a Tor client transport
  123. // plugin.
  124. //
  125. // https://www.ietf.org/rfc/rfc1928.txt
  126. // https://www.ietf.org/rfc/rfc1929.txt
  127. package pt
  128. import (
  129. "bytes"
  130. "crypto/hmac"
  131. "crypto/rand"
  132. "crypto/sha256"
  133. "crypto/subtle"
  134. "encoding/binary"
  135. "fmt"
  136. "io"
  137. "net"
  138. "os"
  139. "strconv"
  140. "strings"
  141. "time"
  142. )
  143. // This type wraps a Write method and calls Sync after each Write.
  144. type syncWriter struct {
  145. *os.File
  146. }
  147. // Call File.Write and then Sync. An error is returned if either operation
  148. // returns an error.
  149. func (w syncWriter) Write(p []byte) (n int, err error) {
  150. n, err = w.File.Write(p)
  151. if err != nil {
  152. return
  153. }
  154. err = w.Sync()
  155. return
  156. }
  157. // Writer to which pluggable transports negotiation messages are written. It
  158. // defaults to a Writer that writes to os.Stdout and calls Sync after each
  159. // write.
  160. //
  161. // You may, for example, log pluggable transports messages by defining a Writer
  162. // that logs what is written to it:
  163. // type logWriteWrapper struct {
  164. // io.Writer
  165. // }
  166. //
  167. // func (w logWriteWrapper) Write(p []byte) (int, error) {
  168. // log.Print(string(p))
  169. // return w.Writer.Write(p)
  170. // }
  171. // and then redefining Stdout:
  172. // pt.Stdout = logWriteWrapper{pt.Stdout}
  173. var Stdout io.Writer = syncWriter{os.Stdout}
  174. // Represents an error that can happen during negotiation, for example
  175. // ENV-ERROR. When an error occurs, we print it to stdout and also pass it up
  176. // the return chain.
  177. type ptErr struct {
  178. Keyword string
  179. Args []string
  180. }
  181. // Implements the error interface.
  182. func (err *ptErr) Error() string {
  183. return formatline(err.Keyword, err.Args...)
  184. }
  185. func getenv(key string) string {
  186. return os.Getenv(key)
  187. }
  188. // Returns an ENV-ERROR if the environment variable isn't set.
  189. func getenvRequired(key string) (string, error) {
  190. value := os.Getenv(key)
  191. if value == "" {
  192. return "", envError(fmt.Sprintf("no %s environment variable", key))
  193. }
  194. return value, nil
  195. }
  196. // Escape a string so it contains no byte values over 127 and doesn't contain
  197. // any of the characters '\x00' or '\n'.
  198. func escape(s string) string {
  199. var buf bytes.Buffer
  200. for _, b := range []byte(s) {
  201. if b == '\n' {
  202. buf.WriteString("\\n")
  203. } else if b == '\\' {
  204. buf.WriteString("\\\\")
  205. } else if 0 < b && b < 128 {
  206. buf.WriteByte(b)
  207. } else {
  208. fmt.Fprintf(&buf, "\\x%02x", b)
  209. }
  210. }
  211. return buf.String()
  212. }
  213. func formatline(keyword string, v ...string) string {
  214. var buf bytes.Buffer
  215. buf.WriteString(keyword)
  216. for _, x := range v {
  217. buf.WriteString(" " + escape(x))
  218. }
  219. return buf.String()
  220. }
  221. // Print a pluggable transports protocol line to Stdout. The line consists of an
  222. // unescaped keyword, followed by any number of escaped strings.
  223. func line(keyword string, v ...string) {
  224. fmt.Fprintln(Stdout, formatline(keyword, v...))
  225. }
  226. // Emit and return the given error as a ptErr.
  227. func doError(keyword string, v ...string) *ptErr {
  228. line(keyword, v...)
  229. return &ptErr{keyword, v}
  230. }
  231. // Emit an ENV-ERROR line with explanation text. Returns a representation of the
  232. // error.
  233. func envError(msg string) error {
  234. return doError("ENV-ERROR", msg)
  235. }
  236. // Emit a VERSION-ERROR line with explanation text. Returns a representation of
  237. // the error.
  238. func versionError(msg string) error {
  239. return doError("VERSION-ERROR", msg)
  240. }
  241. // Emit a CMETHOD-ERROR line with explanation text. Returns a representation of
  242. // the error.
  243. func CmethodError(methodName, msg string) error {
  244. return doError("CMETHOD-ERROR", methodName, msg)
  245. }
  246. // Emit an SMETHOD-ERROR line with explanation text. Returns a representation of
  247. // the error.
  248. func SmethodError(methodName, msg string) error {
  249. return doError("SMETHOD-ERROR", methodName, msg)
  250. }
  251. // Emit a CMETHOD line. socks must be "socks4" or "socks5". Call this once for
  252. // each listening client SOCKS port.
  253. func Cmethod(name string, socks string, addr net.Addr) {
  254. line("CMETHOD", name, socks, addr.String())
  255. }
  256. // Emit a CMETHODS DONE line. Call this after opening all client listeners.
  257. func CmethodsDone() {
  258. line("CMETHODS", "DONE")
  259. }
  260. // Emit an SMETHOD line. Call this once for each listening server port.
  261. func Smethod(name string, addr net.Addr) {
  262. line("SMETHOD", name, addr.String())
  263. }
  264. // Emit an SMETHOD line with an ARGS option. args is a name–value mapping that
  265. // will be added to the server's extrainfo document.
  266. //
  267. // This is an example of how to check for a required option:
  268. // secret, ok := bindaddr.Options.Get("shared-secret")
  269. // if ok {
  270. // args := pt.Args{}
  271. // args.Add("shared-secret", secret)
  272. // pt.SmethodArgs(bindaddr.MethodName, ln.Addr(), args)
  273. // } else {
  274. // pt.SmethodError(bindaddr.MethodName, "need a shared-secret option")
  275. // }
  276. // Or, if you just want to echo back the options provided by Tor from the
  277. // TransportServerOptions configuration,
  278. // pt.SmethodArgs(bindaddr.MethodName, ln.Addr(), bindaddr.Options)
  279. func SmethodArgs(name string, addr net.Addr, args Args) {
  280. line("SMETHOD", name, addr.String(), "ARGS:"+encodeSmethodArgs(args))
  281. }
  282. // Emit an SMETHODS DONE line. Call this after opening all server listeners.
  283. func SmethodsDone() {
  284. line("SMETHODS", "DONE")
  285. }
  286. // Get a pluggable transports version offered by Tor and understood by us, if
  287. // any. The only version we understand is "1". This function reads the
  288. // environment variable TOR_PT_MANAGED_TRANSPORT_VER.
  289. func getManagedTransportVer() (string, error) {
  290. const transportVersion = "1"
  291. managedTransportVer, err := getenvRequired("TOR_PT_MANAGED_TRANSPORT_VER")
  292. if err != nil {
  293. return "", err
  294. }
  295. for _, offered := range strings.Split(managedTransportVer, ",") {
  296. if offered == transportVersion {
  297. return offered, nil
  298. }
  299. }
  300. return "", versionError("no-version")
  301. }
  302. // Return the directory name in the TOR_PT_STATE_LOCATION environment variable,
  303. // creating it if it doesn't exist. Returns non-nil error if
  304. // TOR_PT_STATE_LOCATION is not set or if there is an error creating the
  305. // directory.
  306. func MakeStateDir() (string, error) {
  307. dir, err := getenvRequired("TOR_PT_STATE_LOCATION")
  308. if err != nil {
  309. return "", err
  310. }
  311. err = os.MkdirAll(dir, 0700)
  312. return dir, err
  313. }
  314. // Get the intersection of the method names offered by Tor and those in
  315. // methodNames. This function reads the environment variable
  316. // TOR_PT_CLIENT_TRANSPORTS.
  317. func getClientTransports(star []string) ([]string, error) {
  318. clientTransports, err := getenvRequired("TOR_PT_CLIENT_TRANSPORTS")
  319. if err != nil {
  320. return nil, err
  321. }
  322. if clientTransports == "*" {
  323. return star, nil
  324. }
  325. return strings.Split(clientTransports, ","), nil
  326. }
  327. // This structure is returned by ClientSetup. It consists of a list of method
  328. // names.
  329. type ClientInfo struct {
  330. MethodNames []string
  331. }
  332. // Check the client pluggable transports environment, emitting an error message
  333. // and returning a non-nil error if any error is encountered. star is the list
  334. // of method names to use in case "*" is requested by Tor. Returns a ClientInfo
  335. // struct.
  336. //
  337. // If your program needs to know whether to call ClientSetup or ServerSetup
  338. // (i.e., if the same program can be run as either a client or a server), check
  339. // whether the TOR_PT_CLIENT_TRANSPORTS environment variable is set:
  340. // if os.Getenv("TOR_PT_CLIENT_TRANSPORTS") != "" {
  341. // // Client mode; call pt.ClientSetup.
  342. // } else {
  343. // // Server mode; call pt.ServerSetup.
  344. // }
  345. func ClientSetup(star []string) (info ClientInfo, err error) {
  346. ver, err := getManagedTransportVer()
  347. if err != nil {
  348. return
  349. }
  350. line("VERSION", ver)
  351. info.MethodNames, err = getClientTransports(star)
  352. if err != nil {
  353. return
  354. }
  355. return info, nil
  356. }
  357. // A combination of a method name and an address, as extracted from
  358. // TOR_PT_SERVER_BINDADDR.
  359. type Bindaddr struct {
  360. MethodName string
  361. Addr *net.TCPAddr
  362. // Options from TOR_PT_SERVER_TRANSPORT_OPTIONS that pertain to this
  363. // transport.
  364. Options Args
  365. }
  366. func parsePort(portStr string) (int, error) {
  367. port, err := strconv.ParseUint(portStr, 10, 16)
  368. return int(port), err
  369. }
  370. // Resolve an address string into a net.TCPAddr. We are a bit more strict than
  371. // net.ResolveTCPAddr; we don't allow an empty host or port, and the host part
  372. // must be a literal IP address.
  373. func resolveAddr(addrStr string) (*net.TCPAddr, error) {
  374. ipStr, portStr, err := net.SplitHostPort(addrStr)
  375. if err != nil {
  376. // Before the fixing of bug #7011, tor doesn't put brackets around IPv6
  377. // addresses. Split after the last colon, assuming it is a port
  378. // separator, and try adding the brackets.
  379. parts := strings.Split(addrStr, ":")
  380. if len(parts) <= 2 {
  381. return nil, err
  382. }
  383. addrStr := "[" + strings.Join(parts[:len(parts)-1], ":") + "]:" + parts[len(parts)-1]
  384. ipStr, portStr, err = net.SplitHostPort(addrStr)
  385. }
  386. if err != nil {
  387. return nil, err
  388. }
  389. if ipStr == "" {
  390. return nil, net.InvalidAddrError(fmt.Sprintf("address string %q lacks a host part", addrStr))
  391. }
  392. if portStr == "" {
  393. return nil, net.InvalidAddrError(fmt.Sprintf("address string %q lacks a port part", addrStr))
  394. }
  395. ip := net.ParseIP(ipStr)
  396. if ip == nil {
  397. return nil, net.InvalidAddrError(fmt.Sprintf("not an IP string: %q", ipStr))
  398. }
  399. port, err := parsePort(portStr)
  400. if err != nil {
  401. return nil, err
  402. }
  403. return &net.TCPAddr{IP: ip, Port: port}, nil
  404. }
  405. // Return a new slice, the members of which are those members of addrs having a
  406. // MethodName in methodNames.
  407. func filterBindaddrs(addrs []Bindaddr, methodNames []string) []Bindaddr {
  408. var result []Bindaddr
  409. for _, ba := range addrs {
  410. for _, methodName := range methodNames {
  411. if ba.MethodName == methodName {
  412. result = append(result, ba)
  413. break
  414. }
  415. }
  416. }
  417. return result
  418. }
  419. // Return an array of Bindaddrs, being the contents of TOR_PT_SERVER_BINDADDR
  420. // with keys filtered by TOR_PT_SERVER_TRANSPORTS. If TOR_PT_SERVER_TRANSPORTS
  421. // is "*", then keys are filtered by the entries in star instead.
  422. // Transport-specific options from TOR_PT_SERVER_TRANSPORT_OPTIONS are assigned
  423. // to the Options member.
  424. func getServerBindaddrs(star []string) ([]Bindaddr, error) {
  425. var result []Bindaddr
  426. // Parse the list of server transport options.
  427. serverTransportOptions := getenv("TOR_PT_SERVER_TRANSPORT_OPTIONS")
  428. optionsMap, err := parseServerTransportOptions(serverTransportOptions)
  429. if err != nil {
  430. return nil, envError(fmt.Sprintf("TOR_PT_SERVER_TRANSPORT_OPTIONS: %q: %s", serverTransportOptions, err.Error()))
  431. }
  432. // Get the list of all requested bindaddrs.
  433. serverBindaddr, err := getenvRequired("TOR_PT_SERVER_BINDADDR")
  434. if err != nil {
  435. return nil, err
  436. }
  437. for _, spec := range strings.Split(serverBindaddr, ",") {
  438. var bindaddr Bindaddr
  439. parts := strings.SplitN(spec, "-", 2)
  440. if len(parts) != 2 {
  441. return nil, envError(fmt.Sprintf("TOR_PT_SERVER_BINDADDR: %q: doesn't contain \"-\"", spec))
  442. }
  443. bindaddr.MethodName = parts[0]
  444. addr, err := resolveAddr(parts[1])
  445. if err != nil {
  446. return nil, envError(fmt.Sprintf("TOR_PT_SERVER_BINDADDR: %q: %s", spec, err.Error()))
  447. }
  448. bindaddr.Addr = addr
  449. bindaddr.Options = optionsMap[bindaddr.MethodName]
  450. result = append(result, bindaddr)
  451. }
  452. // Filter by TOR_PT_SERVER_TRANSPORTS.
  453. serverTransports, err := getenvRequired("TOR_PT_SERVER_TRANSPORTS")
  454. if err != nil {
  455. return nil, err
  456. }
  457. if serverTransports == "*" {
  458. result = filterBindaddrs(result, star)
  459. } else {
  460. result = filterBindaddrs(result, strings.Split(serverTransports, ","))
  461. }
  462. return result, nil
  463. }
  464. func readAuthCookie(f io.Reader) ([]byte, error) {
  465. authCookieHeader := []byte("! Extended ORPort Auth Cookie !\x0a")
  466. buf := make([]byte, 64)
  467. n, err := io.ReadFull(f, buf)
  468. if err != nil {
  469. return nil, err
  470. }
  471. // Check that the file ends here.
  472. n, err = f.Read(make([]byte, 1))
  473. if n != 0 {
  474. return nil, fmt.Errorf("file is longer than 64 bytes")
  475. } else if err != io.EOF {
  476. return nil, fmt.Errorf("did not find EOF at end of file")
  477. }
  478. header := buf[0:32]
  479. cookie := buf[32:64]
  480. if subtle.ConstantTimeCompare(header, authCookieHeader) != 1 {
  481. return nil, fmt.Errorf("missing auth cookie header")
  482. }
  483. return cookie, nil
  484. }
  485. // Read and validate the contents of an auth cookie file. Returns the 32-byte
  486. // cookie. See section 4.2.1.2 of pt-spec.txt.
  487. func readAuthCookieFile(filename string) ([]byte, error) {
  488. f, err := os.Open(filename)
  489. if err != nil {
  490. return nil, err
  491. }
  492. defer f.Close()
  493. return readAuthCookie(f)
  494. }
  495. // This structure is returned by ServerSetup. It consists of a list of
  496. // Bindaddrs, an address for the ORPort, an address for the extended ORPort (if
  497. // any), and an authentication cookie (if any).
  498. type ServerInfo struct {
  499. Bindaddrs []Bindaddr
  500. OrAddr *net.TCPAddr
  501. ExtendedOrAddr *net.TCPAddr
  502. AuthCookie []byte
  503. }
  504. // Check the server pluggable transports environment, emitting an error message
  505. // and returning a non-nil error if any error is encountered. star is the list
  506. // of method names to use in case "*" is requested by Tor. Resolves the various
  507. // requested bind addresses, the server ORPort and extended ORPort, and reads
  508. // the auth cookie file. Returns a ServerInfo struct.
  509. //
  510. // If your program needs to know whether to call ClientSetup or ServerSetup
  511. // (i.e., if the same program can be run as either a client or a server), check
  512. // whether the TOR_PT_CLIENT_TRANSPORTS environment variable is set:
  513. // if os.Getenv("TOR_PT_CLIENT_TRANSPORTS") != "" {
  514. // // Client mode; call pt.ClientSetup.
  515. // } else {
  516. // // Server mode; call pt.ServerSetup.
  517. // }
  518. func ServerSetup(star []string) (info ServerInfo, err error) {
  519. ver, err := getManagedTransportVer()
  520. if err != nil {
  521. return
  522. }
  523. line("VERSION", ver)
  524. info.Bindaddrs, err = getServerBindaddrs(star)
  525. if err != nil {
  526. return
  527. }
  528. orPort := getenv("TOR_PT_ORPORT")
  529. if orPort != "" {
  530. info.OrAddr, err = resolveAddr(orPort)
  531. if err != nil {
  532. err = envError(fmt.Sprintf("cannot resolve TOR_PT_ORPORT %q: %s", orPort, err.Error()))
  533. return
  534. }
  535. }
  536. extendedOrPort := getenv("TOR_PT_EXTENDED_SERVER_PORT")
  537. if extendedOrPort != "" {
  538. info.ExtendedOrAddr, err = resolveAddr(extendedOrPort)
  539. if err != nil {
  540. err = envError(fmt.Sprintf("cannot resolve TOR_PT_EXTENDED_SERVER_PORT %q: %s", extendedOrPort, err.Error()))
  541. return
  542. }
  543. }
  544. authCookieFilename := getenv("TOR_PT_AUTH_COOKIE_FILE")
  545. if authCookieFilename != "" {
  546. info.AuthCookie, err = readAuthCookieFile(authCookieFilename)
  547. if err != nil {
  548. err = envError(fmt.Sprintf("error reading TOR_PT_AUTH_COOKIE_FILE %q: %s", authCookieFilename, err.Error()))
  549. return
  550. }
  551. }
  552. // Need either OrAddr or ExtendedOrAddr.
  553. if info.OrAddr == nil && (info.ExtendedOrAddr == nil || info.AuthCookie == nil) {
  554. err = envError("need TOR_PT_ORPORT or TOR_PT_EXTENDED_SERVER_PORT environment variable")
  555. return
  556. }
  557. return info, nil
  558. }
  559. // See 217-ext-orport-auth.txt section 4.2.1.3.
  560. func computeServerHash(authCookie, clientNonce, serverNonce []byte) []byte {
  561. h := hmac.New(sha256.New, authCookie)
  562. io.WriteString(h, "ExtORPort authentication server-to-client hash")
  563. h.Write(clientNonce)
  564. h.Write(serverNonce)
  565. return h.Sum([]byte{})
  566. }
  567. // See 217-ext-orport-auth.txt section 4.2.1.3.
  568. func computeClientHash(authCookie, clientNonce, serverNonce []byte) []byte {
  569. h := hmac.New(sha256.New, authCookie)
  570. io.WriteString(h, "ExtORPort authentication client-to-server hash")
  571. h.Write(clientNonce)
  572. h.Write(serverNonce)
  573. return h.Sum([]byte{})
  574. }
  575. func extOrPortAuthenticate(s io.ReadWriter, info *ServerInfo) error {
  576. // Read auth types. 217-ext-orport-auth.txt section 4.1.
  577. var authTypes [256]bool
  578. var count int
  579. for count = 0; count < 256; count++ {
  580. buf := make([]byte, 1)
  581. _, err := io.ReadFull(s, buf)
  582. if err != nil {
  583. return err
  584. }
  585. b := buf[0]
  586. if b == 0 {
  587. break
  588. }
  589. authTypes[b] = true
  590. }
  591. if count >= 256 {
  592. return fmt.Errorf("read 256 auth types without seeing \\x00")
  593. }
  594. // We support only type 1, SAFE_COOKIE.
  595. if !authTypes[1] {
  596. return fmt.Errorf("server didn't offer auth type 1")
  597. }
  598. _, err := s.Write([]byte{1})
  599. if err != nil {
  600. return err
  601. }
  602. clientNonce := make([]byte, 32)
  603. clientHash := make([]byte, 32)
  604. serverNonce := make([]byte, 32)
  605. serverHash := make([]byte, 32)
  606. _, err = io.ReadFull(rand.Reader, clientNonce)
  607. if err != nil {
  608. return err
  609. }
  610. _, err = s.Write(clientNonce)
  611. if err != nil {
  612. return err
  613. }
  614. _, err = io.ReadFull(s, serverHash)
  615. if err != nil {
  616. return err
  617. }
  618. _, err = io.ReadFull(s, serverNonce)
  619. if err != nil {
  620. return err
  621. }
  622. expectedServerHash := computeServerHash(info.AuthCookie, clientNonce, serverNonce)
  623. if subtle.ConstantTimeCompare(serverHash, expectedServerHash) != 1 {
  624. return fmt.Errorf("mismatch in server hash")
  625. }
  626. clientHash = computeClientHash(info.AuthCookie, clientNonce, serverNonce)
  627. _, err = s.Write(clientHash)
  628. if err != nil {
  629. return err
  630. }
  631. status := make([]byte, 1)
  632. _, err = io.ReadFull(s, status)
  633. if err != nil {
  634. return err
  635. }
  636. if status[0] != 1 {
  637. return fmt.Errorf("server rejected authentication")
  638. }
  639. return nil
  640. }
  641. // See section 3.1 of 196-transport-control-ports.txt.
  642. const (
  643. extOrCmdDone = 0x0000
  644. extOrCmdUserAddr = 0x0001
  645. extOrCmdTransport = 0x0002
  646. extOrCmdOkay = 0x1000
  647. extOrCmdDeny = 0x1001
  648. )
  649. func extOrPortSendCommand(s io.Writer, cmd uint16, body []byte) error {
  650. var buf bytes.Buffer
  651. if len(body) > 65535 {
  652. return fmt.Errorf("body length %d exceeds maximum of 65535", len(body))
  653. }
  654. err := binary.Write(&buf, binary.BigEndian, cmd)
  655. if err != nil {
  656. return err
  657. }
  658. err = binary.Write(&buf, binary.BigEndian, uint16(len(body)))
  659. if err != nil {
  660. return err
  661. }
  662. err = binary.Write(&buf, binary.BigEndian, body)
  663. if err != nil {
  664. return err
  665. }
  666. _, err = s.Write(buf.Bytes())
  667. if err != nil {
  668. return err
  669. }
  670. return nil
  671. }
  672. // Send a USERADDR command on s. See section 3.1.2.1 of
  673. // 196-transport-control-ports.txt.
  674. func extOrPortSendUserAddr(s io.Writer, addr string) error {
  675. return extOrPortSendCommand(s, extOrCmdUserAddr, []byte(addr))
  676. }
  677. // Send a TRANSPORT command on s. See section 3.1.2.2 of
  678. // 196-transport-control-ports.txt.
  679. func extOrPortSendTransport(s io.Writer, methodName string) error {
  680. return extOrPortSendCommand(s, extOrCmdTransport, []byte(methodName))
  681. }
  682. // Send a DONE command on s. See section 3.1 of 196-transport-control-ports.txt.
  683. func extOrPortSendDone(s io.Writer) error {
  684. return extOrPortSendCommand(s, extOrCmdDone, []byte{})
  685. }
  686. func extOrPortRecvCommand(s io.Reader) (cmd uint16, body []byte, err error) {
  687. var bodyLen uint16
  688. data := make([]byte, 4)
  689. _, err = io.ReadFull(s, data)
  690. if err != nil {
  691. return
  692. }
  693. buf := bytes.NewBuffer(data)
  694. err = binary.Read(buf, binary.BigEndian, &cmd)
  695. if err != nil {
  696. return
  697. }
  698. err = binary.Read(buf, binary.BigEndian, &bodyLen)
  699. if err != nil {
  700. return
  701. }
  702. body = make([]byte, bodyLen)
  703. _, err = io.ReadFull(s, body)
  704. if err != nil {
  705. return
  706. }
  707. return cmd, body, err
  708. }
  709. // Send USERADDR and TRANSPORT commands followed by a DONE command. Wait for an
  710. // OKAY or DENY response command from the server. If addr or methodName is "",
  711. // the corresponding command is not sent. Returns nil if and only if OKAY is
  712. // received.
  713. func extOrPortSetup(s io.ReadWriter, addr, methodName string) error {
  714. var err error
  715. if addr != "" {
  716. err = extOrPortSendUserAddr(s, addr)
  717. if err != nil {
  718. return err
  719. }
  720. }
  721. if methodName != "" {
  722. err = extOrPortSendTransport(s, methodName)
  723. if err != nil {
  724. return err
  725. }
  726. }
  727. err = extOrPortSendDone(s)
  728. if err != nil {
  729. return err
  730. }
  731. cmd, _, err := extOrPortRecvCommand(s)
  732. if err != nil {
  733. return err
  734. }
  735. if cmd == extOrCmdDeny {
  736. return fmt.Errorf("server returned DENY after our USERADDR and DONE")
  737. } else if cmd != extOrCmdOkay {
  738. return fmt.Errorf("server returned unknown command 0x%04x after our USERADDR and DONE", cmd)
  739. }
  740. return nil
  741. }
  742. // Dial info.ExtendedOrAddr if defined, or else info.OrAddr, and return an open
  743. // *net.TCPConn. If connecting to the extended OR port, extended OR port
  744. // authentication à la 217-ext-orport-auth.txt is done before returning; an
  745. // error is returned if authentication fails.
  746. //
  747. // The addr and methodName arguments are put in USERADDR and TRANSPORT ExtOrPort
  748. // commands, respectively. If either is "", the corresponding command is not
  749. // sent.
  750. func DialOr(info *ServerInfo, addr, methodName string) (*net.TCPConn, error) {
  751. if info.ExtendedOrAddr == nil || info.AuthCookie == nil {
  752. return net.DialTCP("tcp", nil, info.OrAddr)
  753. }
  754. s, err := net.DialTCP("tcp", nil, info.ExtendedOrAddr)
  755. if err != nil {
  756. return nil, err
  757. }
  758. s.SetDeadline(time.Now().Add(5 * time.Second))
  759. err = extOrPortAuthenticate(s, info)
  760. if err != nil {
  761. s.Close()
  762. return nil, err
  763. }
  764. err = extOrPortSetup(s, addr, methodName)
  765. if err != nil {
  766. s.Close()
  767. return nil, err
  768. }
  769. s.SetDeadline(time.Time{})
  770. return s, nil
  771. }