utils.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * Copyright (c) 2016, 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 server
  20. import (
  21. "fmt"
  22. "io"
  23. "net"
  24. "strings"
  25. "sync/atomic"
  26. "github.com/wader/filtertransport"
  27. )
  28. // IntentionalPanicError is an error type that is used
  29. // when calling panic() in a situation where recovers
  30. // should propagate the panic.
  31. type IntentionalPanicError struct {
  32. message string
  33. }
  34. // NewIntentionalPanicError creates a new IntentionalPanicError.
  35. func NewIntentionalPanicError(errorMessage string) error {
  36. return IntentionalPanicError{
  37. message: fmt.Sprintf("intentional panic error: %s", errorMessage)}
  38. }
  39. // Error implements the error interface.
  40. func (err IntentionalPanicError) Error() string {
  41. return err.message
  42. }
  43. // PanickingLogWriter wraps an io.Writer and intentionally
  44. // panics when a Write() fails.
  45. type PanickingLogWriter struct {
  46. name string
  47. writer io.Writer
  48. }
  49. // NewPanickingLogWriter creates a new PanickingLogWriter.
  50. func NewPanickingLogWriter(
  51. name string, writer io.Writer) *PanickingLogWriter {
  52. return &PanickingLogWriter{
  53. name: name,
  54. writer: writer,
  55. }
  56. }
  57. // Write implements the io.Writer interface.
  58. func (w *PanickingLogWriter) Write(p []byte) (n int, err error) {
  59. n, err = w.writer.Write(p)
  60. if err != nil {
  61. panic(
  62. NewIntentionalPanicError(
  63. fmt.Sprintf("fatal write to %s failed: %s", w.name, err)))
  64. }
  65. return
  66. }
  67. func min(a, b int) int {
  68. if a < b {
  69. return a
  70. }
  71. return b
  72. }
  73. func greaterThanSwapInt64(addr *int64, new int64) bool {
  74. old := atomic.LoadInt64(addr)
  75. if new > old {
  76. return atomic.CompareAndSwapInt64(addr, old, new)
  77. }
  78. return false
  79. }
  80. var expectedTunnelIOErrorSubstrings = []string{
  81. "EOF",
  82. "use of closed network connection",
  83. "connection reset by peer",
  84. "connection has closed",
  85. "broken pipe",
  86. "i/o timeout",
  87. "deadline exceeded",
  88. "NetworkIdleTimeout",
  89. "PeerGoingAway",
  90. "Application error 0x0",
  91. "No recent network activity",
  92. }
  93. // isExpectedTunnelIOError checks if the error indicates failure due to tunnel
  94. // I/O timing out, use of a closed tunnel, etc. This is used to avoid logging
  95. // noise in cases where sending messages through the tunnel fail due regular,
  96. // expected tunnel failure conditions.
  97. //
  98. // Limitations introduced by error type wrapping and lack of common error
  99. // types across all network protcol layers means this function uses
  100. // heuristical error text substring matching and may fall out of sync with new
  101. // protocols/error messages. As such, this function should only be used for
  102. // the intended log noise purpose.
  103. func isExpectedTunnelIOError(err error) bool {
  104. errString := err.Error()
  105. for _, substring := range expectedTunnelIOErrorSubstrings {
  106. if strings.Contains(errString, substring) {
  107. return true
  108. }
  109. }
  110. return false
  111. }
  112. // IsBogon checks if the specified IP is a bogon (loopback, private addresses,
  113. // link-local addresses, etc.)
  114. func IsBogon(IP net.IP) bool {
  115. return filtertransport.FindIPNet(
  116. filtertransport.DefaultFilteredNetworks, IP)
  117. }