github.com/castai/kvisor@v1.7.1-0.20240516114728-b3572a2607b5/pkg/ebpftracer/signature/socks5_detected.go (about)

     1  package signature
     2  
     3  import (
     4  	"fmt"
     5  
     6  	v1 "github.com/castai/kvisor/api/v1/runtime"
     7  	"github.com/castai/kvisor/pkg/ebpftracer/events"
     8  	"github.com/castai/kvisor/pkg/ebpftracer/types"
     9  	"github.com/castai/kvisor/pkg/net/packet"
    10  	"github.com/castai/kvisor/pkg/proc"
    11  	"github.com/elastic/go-freelru"
    12  )
    13  
    14  var _ Signature = (*SOCKS5Detected)(nil)
    15  
    16  type SOCKS5DetectionState uint8
    17  
    18  const (
    19  	SOCKS5Unknown SOCKS5DetectionState = iota
    20  	SOCKS5InitialClientRequestReceived
    21  	SOCKS5InitialClientRequestSend
    22  	SOCKS5InitialServerResponseSend
    23  	SOCKS5InitialServerResponseReceived
    24  )
    25  
    26  const DefaultSOCKS5SignatureCacheSize = 1024
    27  
    28  type SOCKS5DetectionSignatureConfig struct {
    29  	CacheSize uint32
    30  }
    31  
    32  type SOCKS5Detected struct {
    33  	detectionStateCache freelru.Cache[proc.PID, SOCKS5DetectionState]
    34  }
    35  
    36  func NewSOCKS5DetectedSignature(cfg SOCKS5DetectionSignatureConfig) (Signature, error) {
    37  	var cacheSize uint32 = DefaultSOCKS5SignatureCacheSize
    38  	if cfg.CacheSize > 0 {
    39  		cacheSize = cfg.CacheSize
    40  	}
    41  
    42  	cache, err := freelru.NewSynced[proc.PID, SOCKS5DetectionState](cacheSize, func(u uint32) uint32 {
    43  		return u
    44  	})
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	return &SOCKS5Detected{
    50  		detectionStateCache: cache,
    51  	}, nil
    52  }
    53  
    54  func (*SOCKS5Detected) GetMetadata() SignatureMetadata {
    55  	return SignatureMetadata{
    56  		ID:      v1.SignatureEventID_SIGNATURE_SOCKS5_DETECTED,
    57  		Name:    "socks5_detected",
    58  		Version: "0.0.1",
    59  		TargetEvents: []events.ID{
    60  			events.NetPacketSOCKS5Base,
    61  		},
    62  	}
    63  }
    64  
    65  func toProtocolAddressType(t packet.SOCKS5AddressType) v1.SOCKS5AddressType {
    66  	switch t {
    67  	case packet.SOCKS5AddressTypeIPv4:
    68  		return v1.SOCKS5AddressType_SOCKS5_ADDRESS_TYPE_IPv4
    69  	case packet.SOCKS5AddressTypeDomainName:
    70  		return v1.SOCKS5AddressType_SOCKS5_ADDRESS_TYPE_DOMAIN_NAME
    71  	case packet.SOCKS5AddressTypeIPv6:
    72  		return v1.SOCKS5AddressType_SOCKS5_ADDRESS_TYPE_IPv6
    73  	}
    74  
    75  	return v1.SOCKS5AddressType_SOCKS5_ADDRESS_TYPE_UNKNOWN
    76  }
    77  
    78  func toProtocolFlowDirection(f types.FlowDirection) v1.FlowDirection {
    79  	switch f {
    80  	case types.FlowDirectionIngress:
    81  		return v1.FlowDirection_FLOW_INGRESS
    82  	case types.FlowDirectionEgress:
    83  		return v1.FlowDirection_FLOW_EGRESS
    84  	default:
    85  		return v1.FlowDirection_FLOW_UNKNOWN
    86  	}
    87  }
    88  
    89  func toSOCKS5Finding(state SOCKS5DetectionState, flowDirection types.FlowDirection, msg packet.SOCKS5RequestOrReply) *v1.SOCKS5DetectedFinding {
    90  	var role v1.SOCKS5Role
    91  
    92  	switch state {
    93  	case SOCKS5InitialClientRequestSend, SOCKS5InitialServerResponseReceived:
    94  		role = v1.SOCKS5Role_SOCKS5_ROLE_CLIENT
    95  	case SOCKS5InitialClientRequestReceived, SOCKS5InitialServerResponseSend:
    96  		role = v1.SOCKS5Role_SOCKS5_ROLE_SERVER
    97  	default:
    98  		role = v1.SOCKS5Role_SOCKS5_ROLE_UNKNOWN
    99  	}
   100  
   101  	return &v1.SOCKS5DetectedFinding{
   102  		Role:          role,
   103  		FlowDirection: toProtocolFlowDirection(flowDirection),
   104  		CmdOrReply:    uint32(msg.CmdOrReply),
   105  		AddressType:   toProtocolAddressType(msg.AddressType),
   106  		Address:       msg.Address,
   107  		Port:          uint32(msg.Port),
   108  	}
   109  }
   110  
   111  func (s *SOCKS5Detected) OnEvent(event *types.Event) *v1.SignatureFinding {
   112  	var networkData []byte
   113  
   114  	switch args := event.Args.(type) {
   115  	case types.NetPacketSOCKS5BaseArgs:
   116  		networkData = args.Payload
   117  	default:
   118  		return nil
   119  	}
   120  
   121  	payload, _, err := packet.ExtractPayload(networkData)
   122  	if err != nil {
   123  		fmt.Println(err)
   124  		return nil
   125  	}
   126  
   127  	message, err := packet.ParseSOCKS5(payload)
   128  	if err != nil {
   129  		return nil
   130  	}
   131  
   132  	flowDirection := event.Context.GetFlowDirection()
   133  
   134  	switch msg := message.(type) {
   135  	case packet.SOCKS5InitialClientRequest:
   136  		switch flowDirection {
   137  		case types.FlowDirectionEgress:
   138  			s.detectionStateCache.Add(event.Context.Pid, SOCKS5InitialClientRequestSend)
   139  		case types.FlowDirectionIngress:
   140  			s.detectionStateCache.Add(event.Context.Pid, SOCKS5InitialClientRequestReceived)
   141  		}
   142  
   143  		return nil
   144  
   145  	case packet.SOCKS5InitialServerResponse:
   146  		switch flowDirection {
   147  		case types.FlowDirectionEgress:
   148  			s.detectionStateCache.Add(event.Context.Pid, SOCKS5InitialServerResponseSend)
   149  		case types.FlowDirectionIngress:
   150  			s.detectionStateCache.Add(event.Context.Pid, SOCKS5InitialServerResponseReceived)
   151  		}
   152  
   153  		return nil
   154  
   155  	case packet.SOCKS5RequestOrReply:
   156  		state, found := s.detectionStateCache.Get(event.Context.Pid)
   157  		if !found {
   158  			state = SOCKS5Unknown
   159  		}
   160  
   161  		return &v1.SignatureFinding{
   162  			Data: &v1.SignatureFinding_Socks5Detected{
   163  				Socks5Detected: toSOCKS5Finding(state, flowDirection, msg),
   164  			},
   165  		}
   166  	}
   167  
   168  	return &v1.SignatureFinding{}
   169  }