inspektor-gadget

Форк
0
247 строк · 6.5 Кб
1
// Copyright 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 socketenricher
16

17
import (
18
	"fmt"
19
	"sync"
20
	"time"
21

22
	"github.com/cilium/ebpf"
23
	"github.com/cilium/ebpf/link"
24
	log "github.com/sirupsen/logrus"
25

26
	"github.com/inspektor-gadget/inspektor-gadget/pkg/btfgen"
27
	"github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets"
28
	"github.com/inspektor-gadget/inspektor-gadget/pkg/kallsyms"
29
	bpfiterns "github.com/inspektor-gadget/inspektor-gadget/pkg/utils/bpf-iter-ns"
30
)
31

32
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target $TARGET -cc clang -cflags ${CFLAGS} socketenricher ./bpf/socket-enricher.bpf.c -- -I./bpf/
33

34
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -target $TARGET -cc clang -cflags ${CFLAGS} socketsiter ./bpf/sockets-iter.bpf.c -- -I./bpf/
35

36
const (
37
	SocketsMapName = "gadget_sockets"
38
)
39

40
// SocketEnricher creates a map exposing processes owning each socket.
41
//
42
// This makes it possible for network gadgets to access that information and
43
// display it directly from the BPF code. Example of such code in the dns and
44
// sni gadgets.
45
type SocketEnricher struct {
46
	objs     socketenricherObjects
47
	objsIter socketsiterObjects
48
	links    []link.Link
49

50
	closeOnce sync.Once
51
	done      chan bool
52
}
53

54
func (se *SocketEnricher) SocketsMap() *ebpf.Map {
55
	return se.objs.GadgetSockets
56
}
57

58
func NewSocketEnricher() (*SocketEnricher, error) {
59
	se := &SocketEnricher{}
60

61
	if err := se.start(); err != nil {
62
		se.Close()
63
		return nil, err
64
	}
65

66
	return se, nil
67
}
68

69
func (se *SocketEnricher) start() error {
70
	specIter, err := loadSocketsiter()
71
	if err != nil {
72
		return fmt.Errorf("loading socketsiter asset: %w", err)
73
	}
74

75
	err = kallsyms.SpecUpdateAddresses(specIter, []string{"socket_file_ops"})
76
	if err != nil {
77
		// Being unable to access to /proc/kallsyms can be caused by not having
78
		// CAP_SYSLOG.
79
		log.Warnf("updating socket_file_ops address with ksyms: %v\nEither you cannot access /proc/kallsyms or this file does not contain socket_file_ops", err)
80
	}
81

82
	opts := ebpf.CollectionOptions{
83
		Programs: ebpf.ProgramOptions{
84
			KernelTypes: btfgen.GetBTFSpec(),
85
		},
86
	}
87

88
	disableBPFIterators := false
89
	if err := specIter.LoadAndAssign(&se.objsIter, nil); err != nil {
90
		disableBPFIterators = true
91
		log.Warnf("Socket enricher: skip loading iterators: %v", err)
92
	}
93

94
	spec, err := loadSocketenricher()
95
	if err != nil {
96
		return fmt.Errorf("loading socket enricher asset: %w", err)
97
	}
98

99
	if disableBPFIterators {
100
		spec.RewriteConstants(map[string]interface{}{
101
			"disable_bpf_iterators": true,
102
		})
103
	} else {
104
		opts.MapReplacements = map[string]*ebpf.Map{
105
			SocketsMapName: se.objsIter.GadgetSockets,
106
		}
107
	}
108

109
	if err := spec.LoadAndAssign(&se.objs, &opts); err != nil {
110
		return fmt.Errorf("loading ebpf program: %w", err)
111
	}
112

113
	var l link.Link
114

115
	// bind
116
	l, err = link.Kprobe("inet_bind", se.objs.IgBindIpv4E, nil)
117
	if err != nil {
118
		return fmt.Errorf("attaching ipv4 kprobe: %w", err)
119
	}
120
	se.links = append(se.links, l)
121

122
	l, err = link.Kretprobe("inet_bind", se.objs.IgBindIpv4X, nil)
123
	if err != nil {
124
		return fmt.Errorf("attaching ipv4 kretprobe: %w", err)
125
	}
126
	se.links = append(se.links, l)
127

128
	l, err = link.Kprobe("inet6_bind", se.objs.IgBindIpv6E, nil)
129
	if err != nil {
130
		return fmt.Errorf("attaching ipv6 kprobe: %w", err)
131
	}
132
	se.links = append(se.links, l)
133

134
	l, err = link.Kretprobe("inet6_bind", se.objs.IgBindIpv6X, nil)
135
	if err != nil {
136
		return fmt.Errorf("attaching ipv6 kretprobe: %w", err)
137
	}
138
	se.links = append(se.links, l)
139

140
	// connect
141
	l, err = link.Kprobe("tcp_connect", se.objs.IgTcpCoE, nil)
142
	if err != nil {
143
		return fmt.Errorf("attaching connect kprobe: %w", err)
144
	}
145
	se.links = append(se.links, l)
146

147
	l, err = link.Kretprobe("tcp_connect", se.objs.IgTcpCoX, nil)
148
	if err != nil {
149
		return fmt.Errorf("attaching connect kretprobe: %w", err)
150
	}
151
	se.links = append(se.links, l)
152

153
	// udp_sendmsg
154
	l, err = link.Kprobe("udp_sendmsg", se.objs.IgUdpSendmsg, nil)
155
	if err != nil {
156
		return fmt.Errorf("attaching udp_sendmsg ipv4 kprobe: %w", err)
157
	}
158
	se.links = append(se.links, l)
159

160
	l, err = link.Kprobe("udpv6_sendmsg", se.objs.IgUdp6Sendmsg, nil)
161
	if err != nil {
162
		return fmt.Errorf("attaching udpv6_sendmsg ipv6 kprobe: %w", err)
163
	}
164
	se.links = append(se.links, l)
165

166
	// release
167
	l, err = link.Kprobe("inet_release", se.objs.IgFreeIpv4E, nil)
168
	if err != nil {
169
		return fmt.Errorf("attaching ipv4 release kprobe: %w", err)
170
	}
171
	se.links = append(se.links, l)
172

173
	l, err = link.Kprobe("inet6_release", se.objs.IgFreeIpv6E, nil)
174
	if err != nil {
175
		return fmt.Errorf("attaching ipv6 release kprobe: %w", err)
176
	}
177
	se.links = append(se.links, l)
178

179
	if !disableBPFIterators {
180
		// get initial sockets
181
		socketsIter, err := link.AttachIter(link.IterOptions{
182
			Program: se.objsIter.IgSocketsIt,
183
		})
184
		if err != nil {
185
			return fmt.Errorf("attach BPF iterator: %w", err)
186
		}
187
		defer socketsIter.Close()
188

189
		_, err = bpfiterns.Read(socketsIter)
190
		if err != nil {
191
			return fmt.Errorf("read BPF iterator: %w", err)
192
		}
193

194
		// Schedule socket cleanup
195
		cleanupIter, err := link.AttachIter(link.IterOptions{
196
			Program: se.objsIter.IgSkCleanup,
197
			Map:     se.objsIter.GadgetSockets,
198
		})
199
		if err != nil {
200
			return fmt.Errorf("attach BPF iterator for cleanups: %w", err)
201
		}
202
		se.links = append(se.links, cleanupIter)
203

204
		se.done = make(chan bool)
205
		go se.cleanupDeletedSockets(cleanupIter)
206
	}
207

208
	return nil
209
}
210

211
func (se *SocketEnricher) cleanupDeletedSockets(cleanupIter *link.Iter) {
212
	ticker := time.NewTicker(2 * time.Second)
213
	defer ticker.Stop()
214
	for {
215
		select {
216
		case <-se.done:
217
			return
218
		case <-ticker.C:
219
			err := se.cleanupDeletedSocketsNow(cleanupIter)
220
			if err != nil {
221
				fmt.Printf("socket enricher: %v\n", err)
222
			}
223
		}
224
	}
225
}
226

227
func (se *SocketEnricher) cleanupDeletedSocketsNow(cleanupIter *link.Iter) error {
228
	// No need to change pidns for this iterator because cleanupIter is an
229
	// iterator on a map, not on tasks.
230
	_, err := bpfiterns.ReadOnCurrentPidNs(cleanupIter)
231
	return err
232
}
233

234
func (se *SocketEnricher) Close() {
235
	se.closeOnce.Do(func() {
236
		if se.done != nil {
237
			close(se.done)
238
		}
239
	})
240

241
	for _, l := range se.links {
242
		gadgets.CloseLink(l)
243
	}
244
	se.links = nil
245
	se.objs.Close()
246
	se.objsIter.Close()
247
}
248

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.