utils.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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. "errors"
  52. "fmt"
  53. "math/big"
  54. "net"
  55. "net/http"
  56. "net/url"
  57. "os"
  58. "runtime"
  59. "strings"
  60. "syscall"
  61. "time"
  62. )
  63. // Contains is a helper function that returns true
  64. // if the target string is in the list.
  65. func Contains(list []string, target string) bool {
  66. for _, listItem := range list {
  67. if listItem == target {
  68. return true
  69. }
  70. }
  71. return false
  72. }
  73. // FlipCoin is a helper function that randomly
  74. // returns true or false. If the underlying random
  75. // number generator fails, FlipCoin still returns
  76. // a result.
  77. func FlipCoin() bool {
  78. randomInt, _ := MakeSecureRandomInt(2)
  79. return randomInt == 1
  80. }
  81. // MakeSecureRandomInt is a helper function that wraps
  82. // MakeSecureRandomInt64.
  83. func MakeSecureRandomInt(max int) (int, error) {
  84. randomInt, err := MakeSecureRandomInt64(int64(max))
  85. return int(randomInt), err
  86. }
  87. // MakeSecureRandomInt64 is a helper function that wraps
  88. // crypto/rand.Int, which returns a uniform random value in [0, max).
  89. func MakeSecureRandomInt64(max int64) (int64, error) {
  90. randomInt, err := rand.Int(rand.Reader, big.NewInt(max))
  91. if err != nil {
  92. return 0, ContextError(err)
  93. }
  94. return randomInt.Int64(), nil
  95. }
  96. // MakeSecureRandomBytes is a helper function that wraps
  97. // crypto/rand.Read.
  98. func MakeSecureRandomBytes(length int) ([]byte, error) {
  99. randomBytes := make([]byte, length)
  100. n, err := rand.Read(randomBytes)
  101. if err != nil {
  102. return nil, ContextError(err)
  103. }
  104. if n != length {
  105. return nil, ContextError(errors.New("insufficient random bytes"))
  106. }
  107. return randomBytes, nil
  108. }
  109. // MakeSecureRandomPadding selects a random padding length in the indicated
  110. // range and returns a random byte array of the selected length.
  111. // In the unlikely case where an underlying MakeRandom functions fails,
  112. // the padding is length 0.
  113. func MakeSecureRandomPadding(minLength, maxLength int) []byte {
  114. var padding []byte
  115. paddingSize, err := MakeSecureRandomInt(maxLength - minLength)
  116. if err != nil {
  117. NoticeAlert("MakeSecureRandomPadding: MakeSecureRandomInt failed")
  118. return make([]byte, 0)
  119. }
  120. paddingSize += minLength
  121. padding, err = MakeSecureRandomBytes(paddingSize)
  122. if err != nil {
  123. NoticeAlert("MakeSecureRandomPadding: MakeSecureRandomBytes failed")
  124. return make([]byte, 0)
  125. }
  126. return padding
  127. }
  128. // MakeRandomPeriod returns a random duration, within a given range.
  129. // In the unlikely case where an underlying MakeRandom functions fails,
  130. // the period is the minimum.
  131. func MakeRandomPeriod(min, max time.Duration) (duration time.Duration) {
  132. period, err := MakeSecureRandomInt64(max.Nanoseconds() - min.Nanoseconds())
  133. if err != nil {
  134. NoticeAlert("NextRandomRangePeriod: MakeSecureRandomInt64 failed")
  135. }
  136. duration = min + time.Duration(period)
  137. return
  138. }
  139. // MakeRandomString returns a base64 encoded random string. byteLength
  140. // specifies the pre-encoded data length.
  141. func MakeRandomString(byteLength int) (string, error) {
  142. bytes, err := MakeSecureRandomBytes(byteLength)
  143. if err != nil {
  144. return "", ContextError(err)
  145. }
  146. return base64.RawStdEncoding.EncodeToString(bytes), nil
  147. }
  148. func DecodeCertificate(encodedCertificate string) (certificate *x509.Certificate, err error) {
  149. derEncodedCertificate, err := base64.StdEncoding.DecodeString(encodedCertificate)
  150. if err != nil {
  151. return nil, ContextError(err)
  152. }
  153. certificate, err = x509.ParseCertificate(derEncodedCertificate)
  154. if err != nil {
  155. return nil, ContextError(err)
  156. }
  157. return certificate, nil
  158. }
  159. // FilterUrlError transforms an error, when it is a url.Error, removing
  160. // the URL value. This is to avoid logging private user data in cases
  161. // where the URL may be a user input value.
  162. // This function is used with errors returned by net/http and net/url,
  163. // which are (currently) of type url.Error. In particular, the round trip
  164. // function used by our HttpProxy, http.Client.Do, returns errors of type
  165. // url.Error, with the URL being the url sent from the user's tunneled
  166. // applications:
  167. // https://github.com/golang/go/blob/release-branch.go1.4/src/net/http/client.go#L394
  168. func FilterUrlError(err error) error {
  169. if urlErr, ok := err.(*url.Error); ok {
  170. err = &url.Error{
  171. Op: urlErr.Op,
  172. URL: "",
  173. Err: urlErr.Err,
  174. }
  175. }
  176. return err
  177. }
  178. // TrimError removes the middle of over-long error message strings
  179. func TrimError(err error) error {
  180. const MAX_LEN = 100
  181. message := fmt.Sprintf("%s", err)
  182. if len(message) > MAX_LEN {
  183. return errors.New(message[:MAX_LEN/2] + "..." + message[len(message)-MAX_LEN/2:])
  184. }
  185. return err
  186. }
  187. // ContextError prefixes an error message with the current function name
  188. func ContextError(err error) error {
  189. if err == nil {
  190. return nil
  191. }
  192. pc, _, line, _ := runtime.Caller(1)
  193. funcName := runtime.FuncForPC(pc).Name()
  194. index := strings.LastIndex(funcName, "/")
  195. if index != -1 {
  196. funcName = funcName[index+1:]
  197. }
  198. return fmt.Errorf("%s#%d: %s", funcName, line, err)
  199. }
  200. // IsAddressInUseError returns true when the err is due to EADDRINUSE/WSAEADDRINUSE.
  201. func IsAddressInUseError(err error) bool {
  202. if err, ok := err.(*net.OpError); ok {
  203. if err, ok := err.Err.(*os.SyscallError); ok {
  204. if err.Err == syscall.EADDRINUSE {
  205. return true
  206. }
  207. // Special case for Windows (WSAEADDRINUSE = 10048)
  208. if errno, ok := err.Err.(syscall.Errno); ok {
  209. if 10048 == int(errno) {
  210. return true
  211. }
  212. }
  213. }
  214. }
  215. return false
  216. }
  217. // SyncFileWriter wraps a file and exposes an io.Writer. At predefined
  218. // steps, the file is synced (flushed to disk) while writing.
  219. type SyncFileWriter struct {
  220. file *os.File
  221. step int
  222. count int
  223. }
  224. // NewSyncFileWriter creates a SyncFileWriter.
  225. func NewSyncFileWriter(file *os.File) *SyncFileWriter {
  226. return &SyncFileWriter{
  227. file: file,
  228. step: 2 << 16,
  229. count: 0}
  230. }
  231. // Write implements io.Writer with periodic file syncing.
  232. func (writer *SyncFileWriter) Write(p []byte) (n int, err error) {
  233. n, err = writer.file.Write(p)
  234. if err != nil {
  235. return
  236. }
  237. writer.count += n
  238. if writer.count >= writer.step {
  239. err = writer.file.Sync()
  240. writer.count = 0
  241. }
  242. return
  243. }
  244. // GetCurrentTimestamp returns the current time in UTC as
  245. // an RFC 3339 formatted string.
  246. func GetCurrentTimestamp() string {
  247. return time.Now().UTC().Format(time.RFC3339)
  248. }
  249. // TruncateTimestampToHour truncates an RFC 3339 formatted string
  250. // to hour granularity. If the input is not a valid format, the
  251. // result is "".
  252. func TruncateTimestampToHour(timestamp string) string {
  253. t, err := time.Parse(time.RFC3339, timestamp)
  254. if err != nil {
  255. NoticeAlert("failed to truncate timestamp: %s", err)
  256. return ""
  257. }
  258. return t.Truncate(1 * time.Hour).Format(time.RFC3339)
  259. }
  260. // HTTPSServer is a wrapper around http.Server which adds the
  261. // ServeTLS function.
  262. type HTTPSServer struct {
  263. http.Server
  264. }
  265. // ServeTLS is a offers the equivalent interface as http.Serve.
  266. // The http package has both ListenAndServe and ListenAndServeTLS higher-
  267. // level interfaces, but only Serve (not TLS) offers a lower-level interface that
  268. // allows the caller to keep a refererence to the Listener, allowing for external
  269. // shutdown. ListenAndServeTLS also requires the TLS cert and key to be in files
  270. // and we avoid that here.
  271. // tcpKeepAliveListener is used in http.ListenAndServeTLS but not exported,
  272. // so we use a copy from https://golang.org/src/net/http/server.go.
  273. func (server *HTTPSServer) ServeTLS(listener net.Listener) error {
  274. tlsListener := tls.NewListener(tcpKeepAliveListener{listener.(*net.TCPListener)}, server.TLSConfig)
  275. return server.Serve(tlsListener)
  276. }
  277. type tcpKeepAliveListener struct {
  278. *net.TCPListener
  279. }
  280. func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
  281. tc, err := ln.AcceptTCP()
  282. if err != nil {
  283. return
  284. }
  285. tc.SetKeepAlive(true)
  286. tc.SetKeepAlivePeriod(3 * time.Minute)
  287. return tc, nil
  288. }