gosnmp

Форк
0
/
v3.go 
507 строк · 14.6 Кб
1
// Copyright 2012 The GoSNMP Authors. All rights reserved.  Use of this
2
// source code is governed by a BSD-style license that can be found in the
3
// LICENSE file.
4

5
// Copyright 2009 The Go Authors. All rights reserved.
6
// Use of this source code is governed by a BSD-style
7
// license that can be found in the LICENSE file.
8

9
package gosnmp
10

11
import (
12
	"bytes"
13
	"encoding/binary"
14
	"errors"
15
	"fmt"
16
	"runtime"
17
)
18

19
// SnmpV3MsgFlags contains various message flags to describe Authentication, Privacy, and whether a report PDU must be sent.
20
type SnmpV3MsgFlags uint8
21

22
// Possible values of SnmpV3MsgFlags
23
const (
24
	NoAuthNoPriv SnmpV3MsgFlags = 0x0 // No authentication, and no privacy
25
	AuthNoPriv   SnmpV3MsgFlags = 0x1 // Authentication and no privacy
26
	AuthPriv     SnmpV3MsgFlags = 0x3 // Authentication and privacy
27
	Reportable   SnmpV3MsgFlags = 0x4 // Report PDU must be sent.
28
)
29

30
//go:generate stringer -type=SnmpV3MsgFlags
31

32
// SnmpV3SecurityModel describes the security model used by a SnmpV3 connection
33
type SnmpV3SecurityModel uint8
34

35
// UserSecurityModel is the only SnmpV3SecurityModel currently implemented.
36
const (
37
	UserSecurityModel SnmpV3SecurityModel = 3
38
)
39

40
//go:generate stringer -type=SnmpV3SecurityModel
41

42
// SnmpV3SecurityParameters is a generic interface type to contain various implementations of SnmpV3SecurityParameters
43
type SnmpV3SecurityParameters interface {
44
	Log()
45
	Copy() SnmpV3SecurityParameters
46
	Description() string
47
	SafeString() string
48
	InitPacket(packet *SnmpPacket) error
49
	InitSecurityKeys() error
50
	validate(flags SnmpV3MsgFlags) error
51
	init(log Logger) error
52
	discoveryRequired() *SnmpPacket
53
	getDefaultContextEngineID() string
54
	setSecurityParameters(in SnmpV3SecurityParameters) error
55
	marshal(flags SnmpV3MsgFlags) ([]byte, error)
56
	unmarshal(flags SnmpV3MsgFlags, packet []byte, cursor int) (int, error)
57
	authenticate(packet []byte) error
58
	isAuthentic(packetBytes []byte, packet *SnmpPacket) (bool, error)
59
	encryptPacket(scopedPdu []byte) ([]byte, error)
60
	decryptPacket(packet []byte, cursor int) ([]byte, error)
61
	getIdentifier() string
62
	getLogger() Logger
63
	setLogger(log Logger)
64
}
65

66
func (x *GoSNMP) validateParametersV3() error {
67
	// update following code if you implement a new security model
68
	if x.SecurityModel != UserSecurityModel {
69
		return errors.New("the SNMPV3 User Security Model is the only SNMPV3 security model currently implemented")
70
	}
71
	if x.SecurityParameters == nil {
72
		return errors.New("SNMPV3 SecurityParameters must be set")
73
	}
74

75
	return x.SecurityParameters.validate(x.MsgFlags)
76
}
77

78
// authenticate the marshalled result of a snmp version 3 packet
79
func (packet *SnmpPacket) authenticate(msg []byte) ([]byte, error) {
80
	defer func() {
81
		if e := recover(); e != nil {
82
			var buf = make([]byte, 8192)
83
			runtime.Stack(buf, true)
84
			fmt.Printf("[v3::authenticate]recover: %v. Stack=%v\n", e, string(buf))
85
		}
86
	}()
87
	if packet.Version != Version3 {
88
		return msg, nil
89
	}
90
	if packet.MsgFlags&AuthNoPriv > 0 {
91
		err := packet.SecurityParameters.authenticate(msg)
92
		if err != nil {
93
			return nil, err
94
		}
95
	}
96

97
	return msg, nil
98
}
99

100
func (x *GoSNMP) testAuthentication(packet []byte, result *SnmpPacket, useResponseSecurityParameters bool) error {
101
	if x.Version != Version3 {
102
		return fmt.Errorf("testAuthentication called with non Version3 connection")
103
	}
104
	msgFlags := x.MsgFlags
105
	if useResponseSecurityParameters {
106
		msgFlags = result.MsgFlags
107
	}
108

109
	if msgFlags&AuthNoPriv > 0 {
110
		var authentic bool
111
		var err error
112
		if useResponseSecurityParameters {
113
			authentic, err = result.SecurityParameters.isAuthentic(packet, result)
114
		} else {
115
			authentic, err = x.SecurityParameters.isAuthentic(packet, result)
116
		}
117
		if err != nil {
118
			return err
119
		}
120
		if !authentic {
121
			return fmt.Errorf("incoming packet is not authentic, discarding")
122
		}
123
	}
124

125
	return nil
126
}
127

128
func (x *GoSNMP) initPacket(packetOut *SnmpPacket) error {
129
	if x.MsgFlags&AuthPriv > AuthNoPriv {
130
		return x.SecurityParameters.InitPacket(packetOut)
131
	}
132

133
	return nil
134
}
135

136
// http://tools.ietf.org/html/rfc2574#section-2.2.3 This code does not
137
// check if the last message received was more than 150 seconds ago The
138
// snmpds that this code was tested on emit an 'out of time window'
139
// error with the new time and this code will retransmit when that is
140
// received.
141
func (x *GoSNMP) negotiateInitialSecurityParameters(packetOut *SnmpPacket) error {
142
	if x.Version != Version3 || packetOut.Version != Version3 {
143
		return fmt.Errorf("negotiateInitialSecurityParameters called with non Version3 connection or packet")
144
	}
145

146
	if x.SecurityModel != packetOut.SecurityModel {
147
		return fmt.Errorf("connection security model does not match security model defined in packet")
148
	}
149

150
	if discoveryPacket := packetOut.SecurityParameters.discoveryRequired(); discoveryPacket != nil {
151
		discoveryPacket.ContextName = x.ContextName
152
		result, err := x.sendOneRequest(discoveryPacket, true)
153

154
		if err != nil {
155
			return err
156
		}
157

158
		err = x.storeSecurityParameters(result)
159
		if err != nil {
160
			return err
161
		}
162

163
		err = x.updatePktSecurityParameters(packetOut)
164
		if err != nil {
165
			return err
166
		}
167
	} else {
168
		err := packetOut.SecurityParameters.InitSecurityKeys()
169
		if err == nil {
170
			return err
171
		}
172
	}
173

174
	return nil
175
}
176

177
// save the connection security parameters after a request/response
178
func (x *GoSNMP) storeSecurityParameters(result *SnmpPacket) error {
179
	if x.Version != Version3 || result.Version != Version3 {
180
		return fmt.Errorf("storeParameters called with non Version3 connection or packet")
181
	}
182

183
	if x.SecurityModel != result.SecurityModel {
184
		return fmt.Errorf("connection security model does not match security model extracted from packet")
185
	}
186

187
	if x.ContextEngineID == "" {
188
		x.ContextEngineID = result.SecurityParameters.getDefaultContextEngineID()
189
	}
190

191
	return x.SecurityParameters.setSecurityParameters(result.SecurityParameters)
192
}
193

194
// update packet security parameters to match connection security parameters
195
func (x *GoSNMP) updatePktSecurityParameters(packetOut *SnmpPacket) error {
196
	if x.Version != Version3 || packetOut.Version != Version3 {
197
		return fmt.Errorf("updatePktSecurityParameters called with non Version3 connection or packet")
198
	}
199

200
	if x.SecurityModel != packetOut.SecurityModel {
201
		return fmt.Errorf("connection security model does not match security model extracted from packet")
202
	}
203

204
	err := packetOut.SecurityParameters.setSecurityParameters(x.SecurityParameters)
205
	if err != nil {
206
		return err
207
	}
208

209
	if packetOut.ContextEngineID == "" {
210
		packetOut.ContextEngineID = x.ContextEngineID
211
	}
212

213
	return nil
214
}
215

216
func (packet *SnmpPacket) marshalV3(buf *bytes.Buffer) (*bytes.Buffer, error) { //nolint:interfacer
217
	emptyBuffer := new(bytes.Buffer) // used when returning errors
218

219
	header, err := packet.marshalV3Header()
220
	if err != nil {
221
		return emptyBuffer, err
222
	}
223
	buf.Write([]byte{byte(Sequence), byte(len(header))})
224
	packet.Logger.Printf("Marshal V3 Header len=%d. Eaten Last 4 Bytes=%v", len(header), header[len(header)-4:])
225
	buf.Write(header)
226

227
	var securityParameters []byte
228
	securityParameters, err = packet.SecurityParameters.marshal(packet.MsgFlags)
229
	if err != nil {
230
		return emptyBuffer, err
231
	}
232
	packet.Logger.Printf("Marshal V3 SecurityParameters len=%d. Eaten Last 4 Bytes=%v",
233
		len(securityParameters), securityParameters[len(securityParameters)-4:])
234

235
	buf.Write([]byte{byte(OctetString)})
236
	secParamLen, err := marshalLength(len(securityParameters))
237
	if err != nil {
238
		return emptyBuffer, err
239
	}
240
	buf.Write(secParamLen)
241
	buf.Write(securityParameters)
242

243
	scopedPdu, err := packet.marshalV3ScopedPDU()
244
	if err != nil {
245
		return emptyBuffer, err
246
	}
247
	buf.Write(scopedPdu)
248
	return buf, nil
249
}
250

251
// marshal a snmp version 3 packet header
252
func (packet *SnmpPacket) marshalV3Header() ([]byte, error) {
253
	buf := new(bytes.Buffer)
254

255
	// msg id
256
	buf.Write([]byte{byte(Integer), 4})
257
	err := binary.Write(buf, binary.BigEndian, packet.MsgID)
258
	if err != nil {
259
		return nil, err
260
	}
261
	oldLen := 0
262
	packet.Logger.Printf("MarshalV3Header msgID len=%v", buf.Len()-oldLen)
263
	oldLen = buf.Len()
264
	// maximum response msg size
265
	var maxBufSize uint32 = rxBufSize
266
	if packet.MsgMaxSize != 0 {
267
		maxBufSize = packet.MsgMaxSize
268
	}
269
	maxmsgsize, err := marshalUint32(maxBufSize)
270
	if err != nil {
271
		return nil, err
272
	}
273
	buf.Write([]byte{byte(Integer), byte(len(maxmsgsize))})
274
	buf.Write(maxmsgsize)
275
	packet.Logger.Printf("MarshalV3Header maxmsgsize len=%v", buf.Len()-oldLen)
276
	oldLen = buf.Len()
277

278
	// msg flags
279
	buf.Write([]byte{byte(OctetString), 1, byte(packet.MsgFlags)})
280

281
	packet.Logger.Printf("MarshalV3Header msg flags len=%v", buf.Len()-oldLen)
282
	oldLen = buf.Len()
283

284
	// msg security model
285
	buf.Write([]byte{byte(Integer), 1, byte(packet.SecurityModel)})
286

287
	packet.Logger.Printf("MarshalV3Header msg security model len=%v", buf.Len()-oldLen)
288

289
	return buf.Bytes(), nil
290
}
291

292
// marshal and encrypt (if necessary) a snmp version 3 Scoped PDU
293
func (packet *SnmpPacket) marshalV3ScopedPDU() ([]byte, error) {
294
	var b []byte
295

296
	scopedPdu, err := packet.prepareV3ScopedPDU()
297
	if err != nil {
298
		return nil, err
299
	}
300
	pduLen, err := marshalLength(len(scopedPdu))
301
	if err != nil {
302
		return nil, err
303
	}
304
	b = append([]byte{byte(Sequence)}, pduLen...)
305
	scopedPdu = append(b, scopedPdu...)
306
	if packet.MsgFlags&AuthPriv > AuthNoPriv {
307
		scopedPdu, err = packet.SecurityParameters.encryptPacket(scopedPdu)
308
		if err != nil {
309
			return nil, err
310
		}
311
	}
312

313
	return scopedPdu, nil
314
}
315

316
// prepare the plain text of a snmp version 3 Scoped PDU
317
func (packet *SnmpPacket) prepareV3ScopedPDU() ([]byte, error) {
318
	var buf bytes.Buffer
319

320
	// ContextEngineID
321
	idlen, err := marshalLength(len(packet.ContextEngineID))
322
	if err != nil {
323
		return nil, err
324
	}
325
	buf.Write(append([]byte{byte(OctetString)}, idlen...))
326
	buf.WriteString(packet.ContextEngineID)
327

328
	// ContextName
329
	namelen, err := marshalLength(len(packet.ContextName))
330
	if err != nil {
331
		return nil, err
332
	}
333
	buf.Write(append([]byte{byte(OctetString)}, namelen...))
334
	buf.WriteString(packet.ContextName)
335

336
	data, err := packet.marshalPDU()
337
	if err != nil {
338
		return nil, err
339
	}
340
	buf.Write(data)
341
	return buf.Bytes(), nil
342
}
343

344
func (x *GoSNMP) unmarshalV3Header(packet []byte,
345
	cursor int,
346
	response *SnmpPacket) (int, error) {
347
	if PDUType(packet[cursor]) != Sequence {
348
		return 0, fmt.Errorf("invalid SNMPV3 Header")
349
	}
350

351
	_, cursorTmp, err := parseLength(packet[cursor:])
352
	if err != nil {
353
		return 0, err
354
	}
355
	cursor += cursorTmp
356
	if cursor > len(packet) {
357
		return 0, errors.New("error parsing SNMPV3 message ID: truncted packet")
358
	}
359

360
	rawMsgID, count, err := parseRawField(x.Logger, packet[cursor:], "msgID")
361
	if err != nil {
362
		return 0, fmt.Errorf("error parsing SNMPV3 message ID: %w", err)
363
	}
364
	cursor += count
365
	if cursor > len(packet) {
366
		return 0, errors.New("error parsing SNMPV3 message ID: truncted packet")
367
	}
368

369
	if MsgID, ok := rawMsgID.(int); ok {
370
		response.MsgID = uint32(MsgID)
371
		x.Logger.Printf("Parsed message ID %d", MsgID)
372
	}
373

374
	rawMsgMaxSize, count, err := parseRawField(x.Logger, packet[cursor:], "msgMaxSize")
375
	if err != nil {
376
		return 0, fmt.Errorf("error parsing SNMPV3 msgMaxSize: %w", err)
377
	}
378
	cursor += count
379
	if cursor > len(packet) {
380
		return 0, errors.New("error parsing SNMPV3 message ID: truncted packet")
381
	}
382

383
	if MsgMaxSize, ok := rawMsgMaxSize.(int); ok {
384
		response.MsgMaxSize = uint32(MsgMaxSize)
385
		x.Logger.Printf("Parsed message max size %d", MsgMaxSize)
386
	}
387

388
	rawMsgFlags, count, err := parseRawField(x.Logger, packet[cursor:], "msgFlags")
389
	if err != nil {
390
		return 0, fmt.Errorf("error parsing SNMPV3 msgFlags: %w", err)
391
	}
392
	cursor += count
393
	if cursor > len(packet) {
394
		return 0, errors.New("error parsing SNMPV3 message ID: truncted packet")
395
	}
396

397
	if MsgFlags, ok := rawMsgFlags.(string); ok && len(MsgFlags) > 0 {
398
		response.MsgFlags = SnmpV3MsgFlags(MsgFlags[0])
399
		x.Logger.Printf("parsed msg flags %s", MsgFlags)
400
	}
401

402
	rawSecModel, count, err := parseRawField(x.Logger, packet[cursor:], "msgSecurityModel")
403
	if err != nil {
404
		return 0, fmt.Errorf("error parsing SNMPV3 msgSecModel: %w", err)
405
	}
406
	cursor += count
407
	if cursor >= len(packet) {
408
		return 0, errors.New("error parsing SNMPV3 message ID: truncted packet")
409
	}
410

411
	if SecModel, ok := rawSecModel.(int); ok {
412
		response.SecurityModel = SnmpV3SecurityModel(SecModel)
413
		x.Logger.Printf("Parsed security model %d", SecModel)
414
	}
415

416
	if PDUType(packet[cursor]) != PDUType(OctetString) {
417
		return 0, errors.New("invalid SNMPV3 Security Parameters")
418
	}
419
	_, cursorTmp, err = parseLength(packet[cursor:])
420
	if err != nil {
421
		return 0, err
422
	}
423
	cursor += cursorTmp
424
	if cursor > len(packet) {
425
		return 0, errors.New("error parsing SNMPV3 message ID: truncted packet")
426
	}
427
	if response.SecurityParameters == nil {
428
		response.SecurityParameters = &UsmSecurityParameters{Logger: x.Logger}
429
	}
430

431
	cursor, err = response.SecurityParameters.unmarshal(response.MsgFlags, packet, cursor)
432
	if err != nil {
433
		return 0, err
434
	}
435
	x.Logger.Printf("Parsed Security Parameters. now offset=%v,", cursor)
436

437
	return cursor, nil
438
}
439

440
func (x *GoSNMP) decryptPacket(packet []byte, cursor int, response *SnmpPacket) ([]byte, int, error) {
441
	var err error
442
	var decrypted = false
443

444
	if cursor >= len(packet) {
445
		return nil, 0, errors.New("error parsing SNMPV3: truncated packet")
446
	}
447

448
	switch PDUType(packet[cursor]) {
449
	case PDUType(OctetString):
450
		// pdu is encrypted
451
		packet, err = response.SecurityParameters.decryptPacket(packet, cursor)
452
		if err != nil {
453
			return nil, 0, err
454
		}
455
		decrypted = true
456
		fallthrough
457
	case Sequence:
458
		// pdu is plaintext or has been decrypted
459
		tlength, cursorTmp, err := parseLength(packet[cursor:])
460
		if err != nil {
461
			return nil, 0, err
462
		}
463
		if decrypted {
464
			// truncate padding that might have been included with
465
			// the encrypted PDU
466
			if cursor+tlength > len(packet) {
467
				return nil, 0, errors.New("error parsing SNMPV3: truncated packet")
468
			}
469
			packet = packet[:cursor+tlength]
470
		}
471
		cursor += cursorTmp
472
		if cursor > len(packet) {
473
			return nil, 0, errors.New("error parsing SNMPV3: truncated packet")
474
		}
475

476
		rawContextEngineID, count, err := parseRawField(x.Logger, packet[cursor:], "contextEngineID")
477
		if err != nil {
478
			return nil, 0, fmt.Errorf("error parsing SNMPV3 contextEngineID: %w", err)
479
		}
480
		cursor += count
481
		if cursor > len(packet) {
482
			return nil, 0, errors.New("error parsing SNMPV3: truncated packet")
483
		}
484

485
		if contextEngineID, ok := rawContextEngineID.(string); ok {
486
			response.ContextEngineID = contextEngineID
487
			x.Logger.Printf("Parsed contextEngineID %s", contextEngineID)
488
		}
489
		rawContextName, count, err := parseRawField(x.Logger, packet[cursor:], "contextName")
490
		if err != nil {
491
			return nil, 0, fmt.Errorf("error parsing SNMPV3 contextName: %w", err)
492
		}
493
		cursor += count
494
		if cursor > len(packet) {
495
			return nil, 0, errors.New("error parsing SNMPV3: truncated packet")
496
		}
497

498
		if contextName, ok := rawContextName.(string); ok {
499
			response.ContextName = contextName
500
			x.Logger.Printf("Parsed contextName %s", contextName)
501
		}
502

503
	default:
504
		return nil, 0, errors.New("error parsing SNMPV3 scoped PDU")
505
	}
506
	return packet, cursor, nil
507
}
508

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

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

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

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