net.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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. "io"
  22. "net"
  23. "sync"
  24. "time"
  25. "github.com/Psiphon-Inc/dns"
  26. )
  27. const DNS_PORT = 53
  28. // DialConfig contains parameters to determine the behavior
  29. // of a Psiphon dialer (TCPDial, MeekDial, etc.)
  30. type DialConfig struct {
  31. // ClosedSignal is triggered when an underlying TCPConn network
  32. // connection is closed. This is used in operateTunnel to detect
  33. // an unexpected disconnect. Channel should be have buffer to
  34. // receive at least on signal. Sender in TCPConn.Close() does not
  35. // block.
  36. ClosedSignal chan struct{}
  37. // UpstreamProxyUrl specifies a proxy to connect through.
  38. // E.g., "http://proxyhost:8080"
  39. // "socks5://user:password@proxyhost:1080"
  40. // "socks4a://proxyhost:1080"
  41. // "http://NTDOMAIN\NTUser:password@proxyhost:3375"
  42. //
  43. // Certain tunnel protocols require HTTP CONNECT support
  44. // when a HTTP proxy is specified. If CONNECT is not
  45. // supported, those protocols will not connect.
  46. UpstreamProxyUrl string
  47. ConnectTimeout time.Duration
  48. ReadTimeout time.Duration
  49. WriteTimeout time.Duration
  50. // PendingConns is used to interrupt dials in progress.
  51. // The dial may be interrupted using PendingConns.CloseAll(): on platforms
  52. // that support this, the new conn is added to pendingConns before the network
  53. // connect begins and removed from pendingConns once the connect succeeds or fails.
  54. PendingConns *Conns
  55. // BindToDevice parameters are used to exclude connections and
  56. // associated DNS requests from VPN routing.
  57. // When DeviceBinder is set, any underlying socket is
  58. // submitted to the device binding servicebefore connecting.
  59. // The service should bind the socket to a device so that it doesn't route
  60. // through a VPN interface. This service is also used to bind UDP sockets used
  61. // for DNS requests, in which case DnsServerGetter is used to get the
  62. // current active untunneled network DNS server.
  63. DeviceBinder DeviceBinder
  64. DnsServerGetter DnsServerGetter
  65. }
  66. // DeviceBinder defines the interface to the external BindToDevice provider
  67. type DeviceBinder interface {
  68. BindToDevice(fileDescriptor int) error
  69. }
  70. // NetworkConnectivityChecker defines the interface to the external
  71. // HasNetworkConnectivity provider
  72. type NetworkConnectivityChecker interface {
  73. // TODO: change to bool return value once gobind supports that type
  74. HasNetworkConnectivity() int
  75. }
  76. // DnsServerGetter defines the interface to the external GetDnsServer provider
  77. type DnsServerGetter interface {
  78. GetDnsServer() string
  79. }
  80. // TimeoutError implements the error interface
  81. type TimeoutError struct{}
  82. func (TimeoutError) Error() string { return "timed out" }
  83. func (TimeoutError) Timeout() bool { return true }
  84. func (TimeoutError) Temporary() bool { return true }
  85. // Dialer is a custom dialer compatible with http.Transport.Dial.
  86. type Dialer func(string, string) (net.Conn, error)
  87. // Conn is a net.Conn which supports sending a signal to a channel when
  88. // it is closed. In Psiphon, this interface is implemented by tunnel
  89. // connection types (DirectConn and MeekConn) and the close signal is
  90. // used as one trigger for tearing down the tunnel.
  91. type Conn interface {
  92. net.Conn
  93. // SetClosedSignal sets the channel which will be signaled
  94. // when the connection is closed. This function returns false
  95. // if the connection is already closed (and would never send
  96. // the signal). SetClosedSignal and Close may be called by
  97. // concurrent goroutines.
  98. SetClosedSignal(closedSignal chan struct{}) bool
  99. }
  100. // Conns is a synchronized list of Conns that is used to coordinate
  101. // interrupting a set of goroutines establishing connections, or
  102. // close a set of open connections, etc.
  103. // Once the list is closed, no more items may be added to the
  104. // list (unless it is reset).
  105. type Conns struct {
  106. mutex sync.Mutex
  107. isClosed bool
  108. conns map[net.Conn]bool
  109. }
  110. func (conns *Conns) Reset() {
  111. conns.mutex.Lock()
  112. defer conns.mutex.Unlock()
  113. conns.isClosed = false
  114. conns.conns = make(map[net.Conn]bool)
  115. }
  116. func (conns *Conns) Add(conn net.Conn) bool {
  117. conns.mutex.Lock()
  118. defer conns.mutex.Unlock()
  119. if conns.isClosed {
  120. return false
  121. }
  122. if conns.conns == nil {
  123. conns.conns = make(map[net.Conn]bool)
  124. }
  125. conns.conns[conn] = true
  126. return true
  127. }
  128. func (conns *Conns) Remove(conn net.Conn) {
  129. conns.mutex.Lock()
  130. defer conns.mutex.Unlock()
  131. delete(conns.conns, conn)
  132. }
  133. func (conns *Conns) CloseAll() {
  134. conns.mutex.Lock()
  135. defer conns.mutex.Unlock()
  136. conns.isClosed = true
  137. for conn, _ := range conns.conns {
  138. conn.Close()
  139. }
  140. conns.conns = make(map[net.Conn]bool)
  141. }
  142. // Relay sends to remoteConn bytes received from localConn,
  143. // and sends to localConn bytes received from remoteConn.
  144. func Relay(localConn, remoteConn net.Conn) {
  145. copyWaitGroup := new(sync.WaitGroup)
  146. copyWaitGroup.Add(1)
  147. go func() {
  148. defer copyWaitGroup.Done()
  149. _, err := io.Copy(localConn, remoteConn)
  150. if err != nil {
  151. NoticeAlert("Relay failed: %s", ContextError(err))
  152. }
  153. }()
  154. _, err := io.Copy(remoteConn, localConn)
  155. if err != nil {
  156. NoticeAlert("Relay failed: %s", ContextError(err))
  157. }
  158. copyWaitGroup.Wait()
  159. }
  160. // WaitForNetworkConnectivity uses a NetworkConnectivityChecker to
  161. // periodically check for network connectivity. It returns true if
  162. // no NetworkConnectivityChecker is provided (waiting is disabled)
  163. // or if NetworkConnectivityChecker.HasNetworkConnectivity() indicates
  164. // connectivity. It polls the checker once a second. If a stop is
  165. // broadcast, false is returned.
  166. func WaitForNetworkConnectivity(
  167. connectivityChecker NetworkConnectivityChecker, stopBroadcast <-chan struct{}) bool {
  168. if connectivityChecker == nil || 1 == connectivityChecker.HasNetworkConnectivity() {
  169. return true
  170. }
  171. NoticeInfo("waiting for network connectivity")
  172. ticker := time.NewTicker(1 * time.Second)
  173. for {
  174. if 1 == connectivityChecker.HasNetworkConnectivity() {
  175. return true
  176. }
  177. select {
  178. case <-ticker.C:
  179. // Check again
  180. case <-stopBroadcast:
  181. return false
  182. }
  183. }
  184. }
  185. // ResolveIP uses a custom dns stack to make a DNS query over the
  186. // given TCP or UDP conn. This is used, e.g., when we need to ensure
  187. // that a DNS connection bypasses a VPN interface (BindToDevice) or
  188. // when we need to ensure that a DNS connection is tunneled.
  189. // Caller must set timeouts or interruptibility as required for conn.
  190. func ResolveIP(host string, conn net.Conn) (addrs []net.IP, ttls []time.Duration, err error) {
  191. // Send the DNS query
  192. dnsConn := &dns.Conn{Conn: conn}
  193. defer dnsConn.Close()
  194. query := new(dns.Msg)
  195. query.SetQuestion(dns.Fqdn(host), dns.TypeA)
  196. query.RecursionDesired = true
  197. dnsConn.WriteMsg(query)
  198. // Process the response
  199. response, err := dnsConn.ReadMsg()
  200. if err != nil {
  201. return nil, nil, ContextError(err)
  202. }
  203. addrs = make([]net.IP, 0)
  204. ttls = make([]time.Duration, 0)
  205. for _, answer := range response.Answer {
  206. if a, ok := answer.(*dns.A); ok {
  207. addrs = append(addrs, a.A)
  208. ttl := time.Duration(a.Hdr.Ttl) * time.Second
  209. ttls = append(ttls, ttl)
  210. }
  211. }
  212. return addrs, ttls, nil
  213. }