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  }