github.com/geph-official/geph2@v0.22.6-0.20210211030601-f527cb59b0df/libs/niaucchi4/obfssocket.go (about) 1 package niaucchi4 2 3 import ( 4 "fmt" 5 "log" 6 "net" 7 "os" 8 "sync" 9 "time" 10 11 "github.com/hashicorp/golang-lru/simplelru" 12 "github.com/patrickmn/go-cache" 13 ) 14 15 var doLogging = false 16 17 func init() { 18 doLogging = os.Getenv("N4LOG") != "" 19 } 20 21 type oAddr []byte 22 23 func (sa oAddr) Network() string { 24 return "o-sess" 25 } 26 27 func (sa oAddr) String() string { 28 return fmt.Sprintf("osid-%x", []byte(sa)[:10]) 29 } 30 31 // ObfsSocket represents an obfuscated PacketConn. 32 type ObfsSocket struct { 33 cookie []byte 34 cookieExceptions sync.Map 35 sscache *simplelru.LRU 36 tunnels *simplelru.LRU 37 pending *simplelru.LRU 38 wire net.PacketConn 39 wlock sync.Mutex 40 rdbuf [65536]byte 41 replayProtection bool 42 } 43 44 func newLRU() *simplelru.LRU { 45 l, e := simplelru.NewLRU(65536, nil) 46 if e != nil { 47 panic(e) 48 } 49 return l 50 } 51 52 // ObfsListen opens a new obfuscated PacketConn. 53 func ObfsListen(cookie []byte, wire net.PacketConn, replayProtection bool) *ObfsSocket { 54 return &ObfsSocket{ 55 cookie: cookie, 56 sscache: newLRU(), 57 tunnels: newLRU(), 58 pending: newLRU(), 59 wire: wire, 60 replayProtection: replayProtection, 61 } 62 } 63 64 // AddCookieException adds a cookie exception to a particular destination. 65 func (os *ObfsSocket) AddCookieException(addr net.Addr, cookie []byte) { 66 os.cookieExceptions.Store(addr, cookie) 67 } 68 69 func (os *ObfsSocket) WriteTo(b []byte, addr net.Addr) (int, error) { 70 os.wlock.Lock() 71 defer os.wlock.Unlock() 72 var isHidden bool 73 switch addr.(type) { 74 case oAddr: 75 v, ok := os.sscache.Get(string(addr.(oAddr))) 76 if !ok { 77 return 0, nil 78 } 79 addr = v.(net.Addr) 80 isHidden = true 81 } 82 if tuni, ok := os.tunnels.Get(addr.String()); ok { 83 tun := tuni.(*tunstate) 84 toWrite := tun.Encrypt(b) 85 _, err := os.wire.WriteTo(toWrite, addr) 86 if err != nil { 87 return 0, nil 88 } 89 return len(b), nil 90 } 91 if isHidden { 92 return 0, nil 93 } 94 // if we are pending, just ignore 95 if zz, ok := os.pending.Get(addr.String()); ok { 96 os.wire.WriteTo(zz.(*prototun).genHello(), addr) 97 if doLogging { 98 log.Println("N4: retransmitting existing pending to", addr.String()) 99 } 100 return len(b), nil 101 } 102 // establish a conn 103 cookie := os.cookie 104 if v, ok := os.cookieExceptions.Load(addr); ok { 105 cookie = v.([]byte) 106 } 107 pt := newproto(cookie) 108 if doLogging { 109 log.Printf("N4: newproto on %v [%x]", addr.String(), cookie) 110 } 111 os.pending.Add(addr.String(), pt) 112 var err error 113 _, err = os.wire.WriteTo(pt.genHello(), addr) 114 if err != nil { 115 return 0, nil 116 } 117 return len(b), nil 118 } 119 120 func (os *ObfsSocket) ReadFrom(b []byte) (n int, addr net.Addr, err error) { 121 for n == 0 && err == nil { 122 n, addr, err = os.hiddenReadFrom(b) 123 } 124 return 125 } 126 127 var badHelloBlacklist = cache.New(time.Minute*5, time.Minute) 128 129 func (os *ObfsSocket) hiddenReadFrom(p []byte) (n int, addr net.Addr, err error) { 130 readBytes, addr, err := os.wire.ReadFrom(os.rdbuf[:]) 131 if err != nil { 132 return 133 } 134 if _, ok := badHelloBlacklist.Get(addr.String()); ok { 135 return 136 } 137 os.wlock.Lock() 138 defer os.wlock.Unlock() 139 // check if the packet belongs to a known tunnel 140 if tuni, ok := os.tunnels.Get(addr.String()); ok { 141 tun := tuni.(*tunstate) 142 plain, e := tun.Decrypt(os.rdbuf[:readBytes]) 143 if e == nil { 144 os.tunnels.Add(addr.String(), tun) 145 n = copy(p, plain) 146 if _, ok := os.sscache.Get(string(tun.ss)); ok { 147 os.sscache.Add(string(tun.ss), addr) 148 addr = oAddr(tun.ss) 149 } 150 return 151 } 152 } 153 // check if the packet belongs to a pending thing 154 if proti, ok := os.pending.Get(addr.String()); ok { 155 prot := proti.(*prototun) 156 ts, e := prot.realize(os.rdbuf[:readBytes], false, os.replayProtection) 157 if e != nil { 158 return 159 } 160 os.tunnels.Add(addr.String(), ts) 161 if doLogging { 162 log.Println("N4: got realization of pending", addr) 163 } 164 return 165 } 166 // iterate through all the stuff to create an association 167 for _, k := range os.tunnels.Keys() { 168 v, ok := os.tunnels.Get(k) 169 if !ok { 170 continue 171 } 172 tun := v.(*tunstate) 173 plain, e := tun.Decrypt(os.rdbuf[:readBytes]) 174 if e == nil { 175 os.tunnels.Remove(k) 176 if doLogging { 177 log.Println("N4: found a decryptable session through scanning, ROAM to", addr) 178 } 179 os.tunnels.Add(addr.String(), tun) 180 n = copy(p, plain) 181 if _, ok := os.sscache.Get(string(tun.ss)); ok { 182 os.sscache.Add(string(tun.ss), addr) 183 addr = oAddr(tun.ss) 184 } 185 return 186 } 187 } 188 // otherwise it has to be some sort of tunnel opener 189 //log.Println("got suspected hello") 190 pt := newproto(os.cookie) 191 ts, e := pt.realize(os.rdbuf[:readBytes], true, os.replayProtection) 192 if e != nil { 193 if doLogging { 194 log.Println("N4: bad hello from", addr.String(), e.Error()) 195 } 196 badHelloBlacklist.SetDefault(addr.String(), true) 197 return 198 } 199 os.tunnels.Add(addr.String(), ts) 200 os.sscache.Add(string(ts.ss), addr) 201 go func() { 202 os.wlock.Lock() 203 defer os.wlock.Unlock() 204 os.wire.WriteTo(pt.genHello(), addr) 205 if doLogging { 206 log.Println("N4: responded to a hello from", addr) 207 } 208 }() 209 return 210 } 211 212 func (os *ObfsSocket) Close() error { 213 return os.wire.Close() 214 } 215 216 func (os *ObfsSocket) LocalAddr() net.Addr { 217 return os.wire.LocalAddr() 218 } 219 220 func (os *ObfsSocket) SetDeadline(t time.Time) error { 221 return os.wire.SetDeadline(t) 222 } 223 224 func (os *ObfsSocket) SetReadDeadline(t time.Time) error { 225 return os.wire.SetReadDeadline(t) 226 } 227 func (os *ObfsSocket) SetWriteDeadline(t time.Time) error { 228 return os.wire.SetWriteDeadline(t) 229 }