github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadget-collection/gadgets/trace/sni/gadget.go (about)

     1  // Copyright 2019-2022 The Inspektor Gadget authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package snisnoop
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"sigs.k8s.io/controller-runtime/pkg/client"
    21  
    22  	gadgetv1alpha1 "github.com/inspektor-gadget/inspektor-gadget/pkg/apis/gadget/v1alpha1"
    23  	"github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection/networktracer"
    24  	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadget-collection/gadgets"
    25  	sniTracer "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/sni/tracer"
    26  	sniTypes "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/sni/types"
    27  	eventtypes "github.com/inspektor-gadget/inspektor-gadget/pkg/types"
    28  )
    29  
    30  type Trace struct {
    31  	helpers gadgets.GadgetHelpers
    32  	client  client.Client
    33  
    34  	started bool
    35  
    36  	tracer *sniTracer.Tracer
    37  	conn   *networktracer.ConnectionToContainerCollection
    38  }
    39  
    40  type TraceFactory struct {
    41  	gadgets.BaseFactory
    42  }
    43  
    44  func NewFactory() gadgets.TraceFactory {
    45  	return &TraceFactory{
    46  		BaseFactory: gadgets.BaseFactory{DeleteTrace: deleteTrace},
    47  	}
    48  }
    49  
    50  func (f *TraceFactory) Description() string {
    51  	return `The snisnoop gadget retrieves Server Name Indication (SNI) from TLS requests.`
    52  }
    53  
    54  func (f *TraceFactory) OutputModesSupported() map[gadgetv1alpha1.TraceOutputMode]struct{} {
    55  	return map[gadgetv1alpha1.TraceOutputMode]struct{}{
    56  		gadgetv1alpha1.TraceOutputModeStream: {},
    57  	}
    58  }
    59  
    60  func deleteTrace(name string, t interface{}) {
    61  	trace := t.(*Trace)
    62  	if trace.started {
    63  		if trace.conn != nil {
    64  			trace.conn.Close()
    65  		}
    66  		trace.tracer.Close()
    67  		trace.tracer = nil
    68  	}
    69  }
    70  
    71  func (f *TraceFactory) Operations() map[gadgetv1alpha1.Operation]gadgets.TraceOperation {
    72  	n := func() interface{} {
    73  		return &Trace{
    74  			client:  f.Client,
    75  			helpers: f.Helpers,
    76  		}
    77  	}
    78  
    79  	return map[gadgetv1alpha1.Operation]gadgets.TraceOperation{
    80  		gadgetv1alpha1.OperationStart: {
    81  			Doc: "Start snisnoop",
    82  			Operation: func(name string, trace *gadgetv1alpha1.Trace) {
    83  				f.LookupOrCreate(name, n).(*Trace).Start(trace)
    84  			},
    85  		},
    86  		gadgetv1alpha1.OperationStop: {
    87  			Doc: "Stop snisnoop",
    88  			Operation: func(name string, trace *gadgetv1alpha1.Trace) {
    89  				f.LookupOrCreate(name, n).(*Trace).Stop(trace)
    90  			},
    91  		},
    92  	}
    93  }
    94  
    95  func (t *Trace) publishEvent(trace *gadgetv1alpha1.Trace, event *sniTypes.Event) {
    96  	traceName := gadgets.TraceName(trace.ObjectMeta.Namespace, trace.ObjectMeta.Name)
    97  	t.helpers.PublishEvent(
    98  		traceName,
    99  		eventtypes.EventString(event),
   100  	)
   101  }
   102  
   103  func (t *Trace) Start(trace *gadgetv1alpha1.Trace) {
   104  	if t.started {
   105  		trace.Status.State = gadgetv1alpha1.TraceStateStarted
   106  		return
   107  	}
   108  
   109  	eventCallback := func(event *sniTypes.Event) {
   110  		t.publishEvent(trace, event)
   111  	}
   112  
   113  	var err error
   114  	t.tracer, err = sniTracer.NewTracer()
   115  	if err != nil {
   116  		trace.Status.OperationError = fmt.Sprintf("Failed to start sni tracer: %s", err)
   117  		return
   118  	}
   119  	t.tracer.SetEventHandler(eventCallback)
   120  
   121  	config := &networktracer.ConnectToContainerCollectionConfig[sniTypes.Event]{
   122  		Tracer:   t.tracer,
   123  		Resolver: t.helpers,
   124  		Selector: *gadgets.ContainerSelectorFromContainerFilter(trace.Spec.Filter),
   125  		Base:     sniTypes.Base,
   126  	}
   127  	t.conn, err = networktracer.ConnectToContainerCollection(config)
   128  	if err != nil {
   129  		trace.Status.OperationError = fmt.Sprintf("Failed to start sni tracer: %s", err)
   130  		return
   131  	}
   132  
   133  	if err := t.tracer.RunWorkaround(); err != nil {
   134  		trace.Status.OperationError = fmt.Sprintf("Failed to start sni tracer: %s", err)
   135  		return
   136  	}
   137  
   138  	t.started = true
   139  
   140  	trace.Status.State = gadgetv1alpha1.TraceStateStarted
   141  }
   142  
   143  func (t *Trace) Stop(trace *gadgetv1alpha1.Trace) {
   144  	if !t.started {
   145  		trace.Status.OperationError = "Not started"
   146  		return
   147  	}
   148  
   149  	if t.conn != nil {
   150  		t.conn.Close()
   151  	}
   152  	t.tracer.Close()
   153  	t.tracer = nil
   154  	t.started = false
   155  
   156  	trace.Status.State = gadgetv1alpha1.TraceStateStopped
   157  }