forked from Psiphon-Labs/psiphon-tunnel-core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.go
132 lines (117 loc) · 3.52 KB
/
utils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
* Copyright (c) 2016, Psiphon Inc.
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package server
import (
"fmt"
"io"
"net"
"strings"
"sync/atomic"
"github.com/wader/filtertransport"
)
// IntentionalPanicError is an error type that is used
// when calling panic() in a situation where recovers
// should propagate the panic.
type IntentionalPanicError struct {
message string
}
// NewIntentionalPanicError creates a new IntentionalPanicError.
func NewIntentionalPanicError(errorMessage string) error {
return IntentionalPanicError{
message: fmt.Sprintf("intentional panic error: %s", errorMessage)}
}
// Error implements the error interface.
func (err IntentionalPanicError) Error() string {
return err.message
}
// PanickingLogWriter wraps an io.Writer and intentionally
// panics when a Write() fails.
type PanickingLogWriter struct {
name string
writer io.Writer
}
// NewPanickingLogWriter creates a new PanickingLogWriter.
func NewPanickingLogWriter(
name string, writer io.Writer) *PanickingLogWriter {
return &PanickingLogWriter{
name: name,
writer: writer,
}
}
// Write implements the io.Writer interface.
func (w *PanickingLogWriter) Write(p []byte) (n int, err error) {
n, err = w.writer.Write(p)
if err != nil {
panic(
NewIntentionalPanicError(
fmt.Sprintf("fatal write to %s failed: %s", w.name, err)))
}
return
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func greaterThanSwapInt64(addr *int64, new int64) bool {
old := atomic.LoadInt64(addr)
if new > old {
return atomic.CompareAndSwapInt64(addr, old, new)
}
return false
}
var expectedTunnelIOErrorSubstrings = []string{
"EOF",
"use of closed network connection",
"connection reset by peer",
"connection has closed",
"broken pipe",
"i/o timeout",
"deadline exceeded",
"NetworkIdleTimeout",
"PeerGoingAway",
"Application error 0x0",
"No recent network activity",
}
// isExpectedTunnelIOError checks if the error indicates failure due to tunnel
// I/O timing out, use of a closed tunnel, etc. This is used to avoid logging
// noise in cases where sending messages through the tunnel fail due regular,
// expected tunnel failure conditions.
//
// Limitations introduced by error type wrapping and lack of common error
// types across all network protcol layers means this function uses
// heuristical error text substring matching and may fall out of sync with new
// protocols/error messages. As such, this function should only be used for
// the intended log noise purpose.
func isExpectedTunnelIOError(err error) bool {
errString := err.Error()
for _, substring := range expectedTunnelIOErrorSubstrings {
if strings.Contains(errString, substring) {
return true
}
}
return false
}
// IsBogon checks if the specified IP is a bogon (loopback, private addresses,
// link-local addresses, etc.)
func IsBogon(IP net.IP) bool {
return filtertransport.FindIPNet(
filtertransport.DefaultFilteredNetworks, IP)
}