net.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. * Copyright (c) 2015, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. package psiphon
  20. import (
  21. "bufio"
  22. "errors"
  23. "fmt"
  24. "io"
  25. "net"
  26. "net/http"
  27. "strings"
  28. "sync"
  29. "time"
  30. "github.com/Psiphon-Inc/dns"
  31. )
  32. const DNS_PORT = 53
  33. // DialConfig contains parameters to determine the behavior
  34. // of a Psiphon dialer (TCPDial, MeekDial, etc.)
  35. type DialConfig struct {
  36. // UpstreamHttpProxyAddress specifies an HTTP proxy to connect through
  37. // (the proxy must support HTTP CONNECT). The address may be a hostname
  38. // or IP address and must include a port number.
  39. UpstreamHttpProxyAddress string
  40. ConnectTimeout time.Duration
  41. ReadTimeout time.Duration
  42. WriteTimeout time.Duration
  43. // PendingConns is used to interrupt dials in progress.
  44. // The dial may be interrupted using PendingConns.CloseAll(): on platforms
  45. // that support this, the new conn is added to pendingConns before the network
  46. // connect begins and removed from pendingConns once the connect succeeds or fails.
  47. PendingConns *Conns
  48. // BindToDevice parameters are used to exclude connections and
  49. // associated DNS requests from VPN routing.
  50. // When DeviceBinder is set, any underlying socket is
  51. // submitted to the device binding servicebefore connecting.
  52. // The service should bind the socket to a device so that it doesn't route
  53. // through a VPN interface. This service is also used to bind UDP sockets used
  54. // for DNS requests, in which case DnsServerGetter is used to get the
  55. // current active untunneled network DNS server.
  56. DeviceBinder DeviceBinder
  57. DnsServerGetter DnsServerGetter
  58. }
  59. // DeviceBinder defines the interface to the external BindToDevice provider
  60. type DeviceBinder interface {
  61. BindToDevice(fileDescriptor int) error
  62. }
  63. // NetworkConnectivityChecker defines the interface to the external
  64. // HasNetworkConnectivity provider
  65. type NetworkConnectivityChecker interface {
  66. // TODO: change to bool return value once gobind supports that type
  67. HasNetworkConnectivity() int
  68. }
  69. // DnsServerGetter defines the interface to the external GetDnsServer provider
  70. type DnsServerGetter interface {
  71. GetDnsServer() string
  72. }
  73. // Dialer is a custom dialer compatible with http.Transport.Dial.
  74. type Dialer func(string, string) (net.Conn, error)
  75. // Conn is a net.Conn which supports sending a signal to a channel when
  76. // it is closed. In Psiphon, this interface is implemented by tunnel
  77. // connection types (DirectConn and MeekConn) and the close signal is
  78. // used as one trigger for tearing down the tunnel.
  79. type Conn interface {
  80. net.Conn
  81. // SetClosedSignal sets the channel which will be signaled
  82. // when the connection is closed. This function returns false
  83. // if the connection is already closed (and would never send
  84. // the signal). SetClosedSignal and Close may be called by
  85. // concurrent goroutines.
  86. SetClosedSignal(closedSignal chan struct{}) bool
  87. }
  88. // Conns is a synchronized list of Conns that is used to coordinate
  89. // interrupting a set of goroutines establishing connections, or
  90. // close a set of open connections, etc.
  91. // Once the list is closed, no more items may be added to the
  92. // list (unless it is reset).
  93. type Conns struct {
  94. mutex sync.Mutex
  95. isClosed bool
  96. conns map[net.Conn]bool
  97. }
  98. func (conns *Conns) Reset() {
  99. conns.mutex.Lock()
  100. defer conns.mutex.Unlock()
  101. conns.isClosed = false
  102. conns.conns = make(map[net.Conn]bool)
  103. }
  104. func (conns *Conns) Add(conn net.Conn) bool {
  105. conns.mutex.Lock()
  106. defer conns.mutex.Unlock()
  107. if conns.isClosed {
  108. return false
  109. }
  110. if conns.conns == nil {
  111. conns.conns = make(map[net.Conn]bool)
  112. }
  113. conns.conns[conn] = true
  114. return true
  115. }
  116. func (conns *Conns) Remove(conn net.Conn) {
  117. conns.mutex.Lock()
  118. defer conns.mutex.Unlock()
  119. delete(conns.conns, conn)
  120. }
  121. func (conns *Conns) CloseAll() {
  122. conns.mutex.Lock()
  123. defer conns.mutex.Unlock()
  124. conns.isClosed = true
  125. for conn, _ := range conns.conns {
  126. conn.Close()
  127. }
  128. conns.conns = make(map[net.Conn]bool)
  129. }
  130. // Relay sends to remoteConn bytes received from localConn,
  131. // and sends to localConn bytes received from remoteConn.
  132. func Relay(localConn, remoteConn net.Conn) {
  133. copyWaitGroup := new(sync.WaitGroup)
  134. copyWaitGroup.Add(1)
  135. go func() {
  136. defer copyWaitGroup.Done()
  137. _, err := io.Copy(localConn, remoteConn)
  138. if err != nil {
  139. NoticeAlert("Relay failed: %s", ContextError(err))
  140. }
  141. }()
  142. _, err := io.Copy(remoteConn, localConn)
  143. if err != nil {
  144. NoticeAlert("Relay failed: %s", ContextError(err))
  145. }
  146. copyWaitGroup.Wait()
  147. }
  148. // HttpProxyConnect establishes a HTTP CONNECT tunnel to addr through
  149. // an established network connection to an HTTP proxy. It is assumed that
  150. // no payload bytes have been sent through the connection to the proxy.
  151. func HttpProxyConnect(rawConn net.Conn, addr string) (err error) {
  152. hostname, _, err := net.SplitHostPort(addr)
  153. if err != nil {
  154. return ContextError(err)
  155. }
  156. // TODO: use the proxy request/response code from net/http/transport.go?
  157. connectRequest := fmt.Sprintf(
  158. "CONNECT %s HTTP/1.1\r\nHost: %s\r\nConnection: Keep-Alive\r\n\r\n",
  159. addr, hostname)
  160. _, err = rawConn.Write([]byte(connectRequest))
  161. if err != nil {
  162. return ContextError(err)
  163. }
  164. // Adapted from dialConn in net/http/transport.go:
  165. // Read response.
  166. // Okay to use and discard buffered reader here, because
  167. // TLS server will not speak until spoken to.
  168. response, err := http.ReadResponse(bufio.NewReader(rawConn), nil)
  169. if err != nil {
  170. return ContextError(err)
  171. }
  172. if response.StatusCode != 200 {
  173. return ContextError(errors.New(strings.SplitN(response.Status, " ", 2)[1]))
  174. }
  175. return nil
  176. }
  177. // WaitForNetworkConnectivity uses a NetworkConnectivityChecker to
  178. // periodically check for network connectivity. It returns true if
  179. // no NetworkConnectivityChecker is provided (waiting is disabled)
  180. // or if NetworkConnectivityChecker.HasNetworkConnectivity() indicates
  181. // connectivity. It polls the checker once a second. If a stop is
  182. // broadcast, false is returned.
  183. func WaitForNetworkConnectivity(
  184. connectivityChecker NetworkConnectivityChecker, stopBroadcast <-chan struct{}) bool {
  185. if connectivityChecker == nil || 1 == connectivityChecker.HasNetworkConnectivity() {
  186. return true
  187. }
  188. NoticeInfo("waiting for network connectivity")
  189. ticker := time.NewTicker(1 * time.Second)
  190. for {
  191. if 1 == connectivityChecker.HasNetworkConnectivity() {
  192. return true
  193. }
  194. select {
  195. case <-ticker.C:
  196. // Check again
  197. case <-stopBroadcast:
  198. return false
  199. }
  200. }
  201. }
  202. // ResolveIP uses a custom dns stack to make a DNS query over the
  203. // given TCP or UDP conn. This is used, e.g., when we need to ensure
  204. // that a DNS connection bypasses a VPN interface (BindToDevice) or
  205. // when we need to ensure that a DNS connection is tunneled.
  206. // Caller must set timeouts or interruptibility as required for conn.
  207. func ResolveIP(host string, conn net.Conn) (addrs []net.IP, ttls []time.Duration, err error) {
  208. // Send the DNS query
  209. dnsConn := &dns.Conn{Conn: conn}
  210. defer dnsConn.Close()
  211. query := new(dns.Msg)
  212. query.SetQuestion(dns.Fqdn(host), dns.TypeA)
  213. query.RecursionDesired = true
  214. dnsConn.WriteMsg(query)
  215. // Process the response
  216. response, err := dnsConn.ReadMsg()
  217. if err != nil {
  218. return nil, nil, ContextError(err)
  219. }
  220. addrs = make([]net.IP, 0)
  221. ttls = make([]time.Duration, 0)
  222. for _, answer := range response.Answer {
  223. if a, ok := answer.(*dns.A); ok {
  224. addrs = append(addrs, a.A)
  225. ttl := time.Duration(a.Hdr.Ttl) * time.Second
  226. ttls = append(ttls, ttl)
  227. }
  228. }
  229. return addrs, ttls, nil
  230. }