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

     1  // Copyright 2019-2021 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 dns
    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  	dnsTracer "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/tracer"
    26  	dnsTypes "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/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 *dnsTracer.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 dns gadget traces DNS 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 dns",
    82  			Operation: func(name string, trace *gadgetv1alpha1.Trace) {
    83  				f.LookupOrCreate(name, n).(*Trace).Start(trace)
    84  			},
    85  		},
    86  		gadgetv1alpha1.OperationStop: {
    87  			Doc: "Stop dns and store results",
    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 *dnsTypes.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 *dnsTypes.Event) {
   110  		t.publishEvent(trace, event)
   111  	}
   112  
   113  	var err error
   114  	t.tracer, err = dnsTracer.NewTracer()
   115  	if err != nil {
   116  		trace.Status.OperationError = fmt.Sprintf("Failed to start dns tracer: %s", err)
   117  		return
   118  	}
   119  
   120  	t.tracer.SetEventHandler(eventCallback)
   121  
   122  	config := &networktracer.ConnectToContainerCollectionConfig[dnsTypes.Event]{
   123  		Tracer:   t.tracer,
   124  		Resolver: t.helpers,
   125  		Selector: *gadgets.ContainerSelectorFromContainerFilter(trace.Spec.Filter),
   126  		Base:     dnsTypes.Base,
   127  	}
   128  	t.conn, err = networktracer.ConnectToContainerCollection(config)
   129  	if err != nil {
   130  		trace.Status.OperationError = fmt.Sprintf("Failed to start dns tracer: %s", err)
   131  		return
   132  	}
   133  
   134  	if err := t.tracer.RunWorkaround(); err != nil {
   135  		trace.Status.OperationError = fmt.Sprintf("Failed to start dns tracer: %s", err)
   136  		return
   137  	}
   138  
   139  	t.started = true
   140  
   141  	trace.Status.State = gadgetv1alpha1.TraceStateStarted
   142  }
   143  
   144  func (t *Trace) Stop(trace *gadgetv1alpha1.Trace) {
   145  	if !t.started {
   146  		trace.Status.OperationError = "Not started"
   147  		return
   148  	}
   149  
   150  	if t.conn != nil {
   151  		t.conn.Close()
   152  	}
   153  	t.tracer.Close()
   154  	t.tracer = nil
   155  	t.started = false
   156  
   157  	trace.Status.State = gadgetv1alpha1.TraceStateStopped
   158  }