utils.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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. /*
  20. Copyright (c) 2012 The Go Authors. All rights reserved.
  21. Redistribution and use in source and binary forms, with or without
  22. modification, are permitted provided that the following conditions are
  23. met:
  24. * Redistributions of source code must retain the above copyright
  25. notice, this list of conditions and the following disclaimer.
  26. * Redistributions in binary form must reproduce the above
  27. copyright notice, this list of conditions and the following disclaimer
  28. in the documentation and/or other materials provided with the
  29. distribution.
  30. * Neither the name of Google Inc. nor the names of its
  31. contributors may be used to endorse or promote products derived from
  32. this software without specific prior written permission.
  33. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  34. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  35. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  36. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  37. OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  38. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  39. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  40. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  41. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  42. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  43. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. */
  45. package psiphon
  46. import (
  47. "crypto/rand"
  48. "crypto/tls"
  49. "crypto/x509"
  50. "encoding/base64"
  51. "encoding/hex"
  52. "errors"
  53. "fmt"
  54. "math/big"
  55. "net"
  56. "net/http"
  57. "net/url"
  58. "os"
  59. "runtime"
  60. "strings"
  61. "syscall"
  62. "time"
  63. )
  64. // Contains is a helper function that returns true
  65. // if the target string is in the list.
  66. func Contains(list []string, target string) bool {
  67. for _, listItem := range list {
  68. if listItem == target {
  69. return true
  70. }
  71. }
  72. return false
  73. }
  74. // FlipCoin is a helper function that randomly
  75. // returns true or false. If the underlying random
  76. // number generator fails, FlipCoin still returns
  77. // a result.
  78. func FlipCoin() bool {
  79. randomInt, _ := MakeSecureRandomInt(2)
  80. return randomInt == 1
  81. }
  82. // MakeSecureRandomInt is a helper function that wraps
  83. // MakeSecureRandomInt64.
  84. func MakeSecureRandomInt(max int) (int, error) {
  85. randomInt, err := MakeSecureRandomInt64(int64(max))
  86. return int(randomInt), err
  87. }
  88. // MakeSecureRandomInt64 is a helper function that wraps
  89. // crypto/rand.Int, which returns a uniform random value in [0, max).
  90. func MakeSecureRandomInt64(max int64) (int64, error) {
  91. randomInt, err := rand.Int(rand.Reader, big.NewInt(max))
  92. if err != nil {
  93. return 0, ContextError(err)
  94. }
  95. return randomInt.Int64(), nil
  96. }
  97. // MakeSecureRandomBytes is a helper function that wraps
  98. // crypto/rand.Read.
  99. func MakeSecureRandomBytes(length int) ([]byte, error) {
  100. randomBytes := make([]byte, length)
  101. n, err := rand.Read(randomBytes)
  102. if err != nil {
  103. return nil, ContextError(err)
  104. }
  105. if n != length {
  106. return nil, ContextError(errors.New("insufficient random bytes"))
  107. }
  108. return randomBytes, nil
  109. }
  110. // MakeSecureRandomPadding selects a random padding length in the indicated
  111. // range and returns a random byte array of the selected length.
  112. // In the unlikely case where an underlying MakeRandom functions fails,
  113. // the padding is length 0.
  114. func MakeSecureRandomPadding(minLength, maxLength int) []byte {
  115. var padding []byte
  116. paddingSize, err := MakeSecureRandomInt(maxLength - minLength)
  117. if err != nil {
  118. NoticeAlert("MakeSecureRandomPadding: MakeSecureRandomInt failed")
  119. return make([]byte, 0)
  120. }
  121. paddingSize += minLength
  122. padding, err = MakeSecureRandomBytes(paddingSize)
  123. if err != nil {
  124. NoticeAlert("MakeSecureRandomPadding: MakeSecureRandomBytes failed")
  125. return make([]byte, 0)
  126. }
  127. return padding
  128. }
  129. // MakeRandomPeriod returns a random duration, within a given range.
  130. // In the unlikely case where an underlying MakeRandom functions fails,
  131. // the period is the minimum.
  132. func MakeRandomPeriod(min, max time.Duration) (duration time.Duration) {
  133. period, err := MakeSecureRandomInt64(max.Nanoseconds() - min.Nanoseconds())
  134. if err != nil {
  135. NoticeAlert("NextRandomRangePeriod: MakeSecureRandomInt64 failed")
  136. }
  137. duration = min + time.Duration(period)
  138. return
  139. }
  140. // MakeRandomString returns a hex encoded random string. byteLength
  141. // specifies the pre-encoded data length.
  142. func MakeRandomString(byteLength int) (string, error) {
  143. bytes, err := MakeSecureRandomBytes(byteLength)
  144. if err != nil {
  145. return "", ContextError(err)
  146. }
  147. return hex.EncodeToString(bytes), nil
  148. }
  149. func DecodeCertificate(encodedCertificate string) (certificate *x509.Certificate, err error) {
  150. derEncodedCertificate, err := base64.StdEncoding.DecodeString(encodedCertificate)
  151. if err != nil {
  152. return nil, ContextError(err)
  153. }
  154. certificate, err = x509.ParseCertificate(derEncodedCertificate)
  155. if err != nil {
  156. return nil, ContextError(err)
  157. }
  158. return certificate, nil
  159. }
  160. // FilterUrlError transforms an error, when it is a url.Error, removing
  161. // the URL value. This is to avoid logging private user data in cases
  162. // where the URL may be a user input value.
  163. // This function is used with errors returned by net/http and net/url,
  164. // which are (currently) of type url.Error. In particular, the round trip
  165. // function used by our HttpProxy, http.Client.Do, returns errors of type
  166. // url.Error, with the URL being the url sent from the user's tunneled
  167. // applications:
  168. // https://github.com/golang/go/blob/release-branch.go1.4/src/net/http/client.go#L394
  169. func FilterUrlError(err error) error {
  170. if urlErr, ok := err.(*url.Error); ok {
  171. err = &url.Error{
  172. Op: urlErr.Op,
  173. URL: "",
  174. Err: urlErr.Err,
  175. }
  176. }
  177. return err
  178. }
  179. // TrimError removes the middle of over-long error message strings
  180. func TrimError(err error) error {
  181. const MAX_LEN = 100
  182. message := fmt.Sprintf("%s", err)
  183. if len(message) > MAX_LEN {
  184. return errors.New(message[:MAX_LEN/2] + "..." + message[len(message)-MAX_LEN/2:])
  185. }
  186. return err
  187. }
  188. // getFunctionName is a helper that extracts a simple function name from
  189. // full name returned byruntime.Func.Name(). This is used to declutter
  190. // log messages containing function names.
  191. func getFunctionName(pc uintptr) string {
  192. funcName := runtime.FuncForPC(pc).Name()
  193. index := strings.LastIndex(funcName, "/")
  194. if index != -1 {
  195. funcName = funcName[index+1:]
  196. }
  197. return funcName
  198. }
  199. // GetParentContext returns the parent function name and source file
  200. // line number.
  201. func GetParentContext() string {
  202. pc, _, line, _ := runtime.Caller(2)
  203. return fmt.Sprintf("%s#%d", getFunctionName(pc), line)
  204. }
  205. // ContextError prefixes an error message with the current function
  206. // name and source file line number.
  207. func ContextError(err error) error {
  208. if err == nil {
  209. return nil
  210. }
  211. pc, _, line, _ := runtime.Caller(1)
  212. return fmt.Errorf("%s#%d: %s", getFunctionName(pc), line, err)
  213. }
  214. // IsAddressInUseError returns true when the err is due to EADDRINUSE/WSAEADDRINUSE.
  215. func IsAddressInUseError(err error) bool {
  216. if err, ok := err.(*net.OpError); ok {
  217. if err, ok := err.Err.(*os.SyscallError); ok {
  218. if err.Err == syscall.EADDRINUSE {
  219. return true
  220. }
  221. // Special case for Windows (WSAEADDRINUSE = 10048)
  222. if errno, ok := err.Err.(syscall.Errno); ok {
  223. if 10048 == int(errno) {
  224. return true
  225. }
  226. }
  227. }
  228. }
  229. return false
  230. }
  231. // SyncFileWriter wraps a file and exposes an io.Writer. At predefined
  232. // steps, the file is synced (flushed to disk) while writing.
  233. type SyncFileWriter struct {
  234. file *os.File
  235. step int
  236. count int
  237. }
  238. // NewSyncFileWriter creates a SyncFileWriter.
  239. func NewSyncFileWriter(file *os.File) *SyncFileWriter {
  240. return &SyncFileWriter{
  241. file: file,
  242. step: 2 << 16,
  243. count: 0}
  244. }
  245. // Write implements io.Writer with periodic file syncing.
  246. func (writer *SyncFileWriter) Write(p []byte) (n int, err error) {
  247. n, err = writer.file.Write(p)
  248. if err != nil {
  249. return
  250. }
  251. writer.count += n
  252. if writer.count >= writer.step {
  253. err = writer.file.Sync()
  254. writer.count = 0
  255. }
  256. return
  257. }
  258. // GetCurrentTimestamp returns the current time in UTC as
  259. // an RFC 3339 formatted string.
  260. func GetCurrentTimestamp() string {
  261. return time.Now().UTC().Format(time.RFC3339)
  262. }
  263. // TruncateTimestampToHour truncates an RFC 3339 formatted string
  264. // to hour granularity. If the input is not a valid format, the
  265. // result is "".
  266. func TruncateTimestampToHour(timestamp string) string {
  267. t, err := time.Parse(time.RFC3339, timestamp)
  268. if err != nil {
  269. NoticeAlert("failed to truncate timestamp: %s", err)
  270. return ""
  271. }
  272. return t.Truncate(1 * time.Hour).Format(time.RFC3339)
  273. }
  274. // HTTPSServer is a wrapper around http.Server which adds the
  275. // ServeTLS function.
  276. type HTTPSServer struct {
  277. http.Server
  278. }
  279. // ServeTLS is a offers the equivalent interface as http.Serve.
  280. // The http package has both ListenAndServe and ListenAndServeTLS higher-
  281. // level interfaces, but only Serve (not TLS) offers a lower-level interface that
  282. // allows the caller to keep a refererence to the Listener, allowing for external
  283. // shutdown. ListenAndServeTLS also requires the TLS cert and key to be in files
  284. // and we avoid that here.
  285. // tcpKeepAliveListener is used in http.ListenAndServeTLS but not exported,
  286. // so we use a copy from https://golang.org/src/net/http/server.go.
  287. func (server *HTTPSServer) ServeTLS(listener net.Listener) error {
  288. tlsListener := tls.NewListener(tcpKeepAliveListener{listener.(*net.TCPListener)}, server.TLSConfig)
  289. return server.Serve(tlsListener)
  290. }
  291. type tcpKeepAliveListener struct {
  292. *net.TCPListener
  293. }
  294. func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
  295. tc, err := ln.AcceptTCP()
  296. if err != nil {
  297. return
  298. }
  299. tc.SetKeepAlive(true)
  300. tc.SetKeepAlivePeriod(3 * time.Minute)
  301. return tc, nil
  302. }