gosnmp

Форк
0
/
marshal.go 
1390 строк · 39.7 Кб
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
package gosnmp
6

7
import (
8
	"bytes"
9
	"context"
10
	"encoding/asn1"
11
	"encoding/binary"
12
	"errors"
13
	"fmt"
14
	"io"
15
	"net"
16
	"runtime"
17
	"strings"
18
	"sync/atomic"
19
	"time"
20
)
21

22
//
23
// Remaining globals and definitions located here.
24
// See http://www.rane.com/note161.html for a succint description of the SNMP
25
// protocol.
26
//
27

28
// SnmpVersion 1, 2c and 3 implemented
29
type SnmpVersion uint8
30

31
// SnmpVersion 1, 2c and 3 implemented
32
const (
33
	Version1  SnmpVersion = 0x0
34
	Version2c SnmpVersion = 0x1
35
	Version3  SnmpVersion = 0x3
36
)
37

38
// SnmpPacket struct represents the entire SNMP Message or Sequence at the
39
// application layer.
40
type SnmpPacket struct {
41
	Version            SnmpVersion
42
	MsgFlags           SnmpV3MsgFlags
43
	SecurityModel      SnmpV3SecurityModel
44
	SecurityParameters SnmpV3SecurityParameters // interface
45
	ContextEngineID    string
46
	ContextName        string
47
	Community          string
48
	PDUType            PDUType
49
	MsgID              uint32
50
	RequestID          uint32
51
	MsgMaxSize         uint32
52
	Error              SNMPError
53
	ErrorIndex         uint8
54
	NonRepeaters       uint8
55
	MaxRepetitions     uint32
56
	Variables          []SnmpPDU
57
	Logger             Logger
58

59
	// v1 traps have a very different format from v2c and v3 traps.
60
	//
61
	// These fields are set via the SnmpTrap parameter to SendTrap().
62
	SnmpTrap
63
}
64

65
// SnmpTrap is used to define a SNMP trap, and is passed into SendTrap
66
type SnmpTrap struct {
67
	Variables []SnmpPDU
68

69
	// If true, the trap is an InformRequest, not a trap. This has no effect on
70
	// v1 traps, as Inform is not part of the v1 protocol.
71
	IsInform bool
72

73
	// These fields are required for SNMPV1 Trap Headers
74
	Enterprise   string
75
	AgentAddress string
76
	GenericTrap  int
77
	SpecificTrap int
78
	Timestamp    uint
79
}
80

81
// VarBind struct represents an SNMP Varbind.
82
type VarBind struct {
83
	Name  asn1.ObjectIdentifier
84
	Value asn1.RawValue
85
}
86

87
// PDUType describes which SNMP Protocol Data Unit is being sent.
88
type PDUType byte
89

90
// The currently supported PDUType's
91
const (
92
	Sequence       PDUType = 0x30
93
	GetRequest     PDUType = 0xa0
94
	GetNextRequest PDUType = 0xa1
95
	GetResponse    PDUType = 0xa2
96
	SetRequest     PDUType = 0xa3
97
	Trap           PDUType = 0xa4 // v1
98
	GetBulkRequest PDUType = 0xa5
99
	InformRequest  PDUType = 0xa6
100
	SNMPv2Trap     PDUType = 0xa7 // v2c, v3
101
	Report         PDUType = 0xa8 // v3
102
)
103

104
//go:generate stringer -type=PDUType
105

106
// SNMPv3: User-based Security Model Report PDUs and
107
// error types as per https://tools.ietf.org/html/rfc3414
108
const (
109
	usmStatsUnsupportedSecLevels = ".1.3.6.1.6.3.15.1.1.1.0"
110
	usmStatsNotInTimeWindows     = ".1.3.6.1.6.3.15.1.1.2.0"
111
	usmStatsUnknownUserNames     = ".1.3.6.1.6.3.15.1.1.3.0"
112
	usmStatsUnknownEngineIDs     = ".1.3.6.1.6.3.15.1.1.4.0"
113
	usmStatsWrongDigests         = ".1.3.6.1.6.3.15.1.1.5.0"
114
	usmStatsDecryptionErrors     = ".1.3.6.1.6.3.15.1.1.6.0"
115
	snmpUnknownSecurityModels    = ".1.3.6.1.6.3.11.2.1.1.0"
116
	snmpInvalidMsgs              = ".1.3.6.1.6.3.11.2.1.2.0"
117
	snmpUnknownPDUHandlers       = ".1.3.6.1.6.3.11.2.1.3.0"
118
)
119

120
var (
121
	ErrDecryption            = errors.New("decryption error")
122
	ErrInvalidMsgs           = errors.New("invalid messages")
123
	ErrNotInTimeWindow       = errors.New("not in time window")
124
	ErrUnknownEngineID       = errors.New("unknown engine id")
125
	ErrUnknownPDUHandlers    = errors.New("unknown pdu handlers")
126
	ErrUnknownReportPDU      = errors.New("unknown report pdu")
127
	ErrUnknownSecurityLevel  = errors.New("unknown security level")
128
	ErrUnknownSecurityModels = errors.New("unknown security models")
129
	ErrUnknownUsername       = errors.New("unknown username")
130
	ErrWrongDigest           = errors.New("wrong digest")
131
)
132

133
const rxBufSize = 65535 // max size of IPv4 & IPv6 packet
134

135
// Logger is an interface used for debugging. Both Print and
136
// Printf have the same interfaces as Package Log in the std library. The
137
// Logger interface is small to give you flexibility in how you do
138
// your debugging.
139
//
140

141
// Logger
142
// For verbose logging to stdout:
143
// gosnmp_logger = NewLogger(log.New(os.Stdout, "", 0))
144
type LoggerInterface interface {
145
	Print(v ...interface{})
146
	Printf(format string, v ...interface{})
147
}
148

149
type Logger struct {
150
	logger LoggerInterface
151
}
152

153
func NewLogger(logger LoggerInterface) Logger {
154
	return Logger{
155
		logger: logger,
156
	}
157
}
158

159
func (packet *SnmpPacket) SafeString() string {
160
	sp := ""
161
	if packet.SecurityParameters != nil {
162
		sp = packet.SecurityParameters.SafeString()
163
	}
164
	return fmt.Sprintf("Version:%s, MsgFlags:%s, SecurityModel:%s, SecurityParameters:%s, ContextEngineID:%s, ContextName:%s, Community:%s, PDUType:%s, MsgID:%d, RequestID:%d, MsgMaxSize:%d, Error:%s, ErrorIndex:%d, NonRepeaters:%d, MaxRepetitions:%d, Variables:%v",
165
		packet.Version,
166
		packet.MsgFlags,
167
		packet.SecurityModel,
168
		sp,
169
		packet.ContextEngineID,
170
		packet.ContextName,
171
		packet.Community,
172
		packet.PDUType,
173
		packet.MsgID,
174
		packet.RequestID,
175
		packet.MsgMaxSize,
176
		packet.Error,
177
		packet.ErrorIndex,
178
		packet.NonRepeaters,
179
		packet.MaxRepetitions,
180
		packet.Variables,
181
	)
182
}
183

184
// GoSNMP
185
// send/receive one snmp request
186
func (x *GoSNMP) sendOneRequest(packetOut *SnmpPacket,
187
	wait bool) (result *SnmpPacket, err error) {
188
	allReqIDs := make([]uint32, 0, x.Retries+1)
189
	// allMsgIDs := make([]uint32, 0, x.Retries+1) // unused
190

191
	timeout := x.Timeout
192
	withContextDeadline := false
193
	for retries := 0; ; retries++ {
194
		if retries > 0 {
195
			if x.OnRetry != nil {
196
				x.OnRetry(x)
197
			}
198

199
			x.Logger.Printf("Retry number %d. Last error was: %v", retries, err)
200
			if withContextDeadline && strings.Contains(err.Error(), "timeout") {
201
				err = context.DeadlineExceeded
202
				break
203
			}
204
			if retries > x.Retries {
205
				if strings.Contains(err.Error(), "timeout") {
206
					err = fmt.Errorf("request timeout (after %d retries)", retries-1)
207
				}
208
				break
209
			}
210
			if x.ExponentialTimeout {
211
				// https://www.webnms.com/snmp/help/snmpapi/snmpv3/v1/timeout.html
212
				timeout *= 2
213
			}
214
			withContextDeadline = false
215
		}
216
		err = nil
217

218
		if x.Context.Err() != nil {
219
			return nil, x.Context.Err()
220
		}
221

222
		reqDeadline := time.Now().Add(timeout)
223
		if contextDeadline, ok := x.Context.Deadline(); ok {
224
			if contextDeadline.Before(reqDeadline) {
225
				reqDeadline = contextDeadline
226
				withContextDeadline = true
227
			}
228
		}
229

230
		err = x.Conn.SetDeadline(reqDeadline)
231
		if err != nil {
232
			return nil, err
233
		}
234

235
		// Request ID is an atomic counter that wraps to 0 at max int32.
236
		reqID := (atomic.AddUint32(&(x.requestID), 1) & 0x7FFFFFFF)
237
		allReqIDs = append(allReqIDs, reqID)
238

239
		packetOut.RequestID = reqID
240

241
		if x.Version == Version3 {
242
			msgID := (atomic.AddUint32(&(x.msgID), 1) & 0x7FFFFFFF)
243

244
			// allMsgIDs = append(allMsgIDs, msgID) // unused
245

246
			packetOut.MsgID = msgID
247

248
			err = x.initPacket(packetOut)
249
			if err != nil {
250
				break
251
			}
252
		}
253
		if x.Version == Version3 {
254
			packetOut.SecurityParameters.Log()
255
		}
256

257
		var outBuf []byte
258
		outBuf, err = packetOut.marshalMsg()
259
		if err != nil {
260
			// Don't retry - not going to get any better!
261
			err = fmt.Errorf("marshal: %w", err)
262
			break
263
		}
264

265
		if x.PreSend != nil {
266
			x.PreSend(x)
267
		}
268
		x.Logger.Printf("SENDING PACKET: %s", packetOut.SafeString())
269
		// If using UDP and unconnected socket, send packet directly to stored address.
270
		if uconn, ok := x.Conn.(net.PacketConn); ok && x.uaddr != nil {
271
			_, err = uconn.WriteTo(outBuf, x.uaddr)
272
		} else {
273
			_, err = x.Conn.Write(outBuf)
274
		}
275
		if err != nil {
276
			continue
277
		}
278
		if x.OnSent != nil {
279
			x.OnSent(x)
280
		}
281

282
		// all sends wait for the return packet, except for SNMPv2Trap
283
		if !wait {
284
			return &SnmpPacket{}, nil
285
		}
286

287
	waitingResponse:
288
		for {
289
			x.Logger.Print("WAITING RESPONSE...")
290
			// Receive response and try receiving again on any decoding error.
291
			// Let the deadline abort us if we don't receive a valid response.
292

293
			var resp []byte
294
			resp, err = x.receive()
295
			if err == io.EOF && strings.HasPrefix(x.Transport, tcp) {
296
				// EOF on TCP: reconnect and retry. Do not count
297
				// as retry as socket was broken
298
				x.Logger.Printf("ERROR: EOF. Performing reconnect")
299
				err = x.netConnect()
300
				if err != nil {
301
					return nil, err
302
				}
303
				retries--
304
				break
305
			} else if err != nil {
306
				// receive error. retrying won't help. abort
307
				break
308
			}
309
			if x.OnRecv != nil {
310
				x.OnRecv(x)
311
			}
312
			x.Logger.Printf("GET RESPONSE OK: %+v", resp)
313
			result = new(SnmpPacket)
314
			result.Logger = x.Logger
315

316
			result.MsgFlags = packetOut.MsgFlags
317
			if packetOut.SecurityParameters != nil {
318
				result.SecurityParameters = packetOut.SecurityParameters.Copy()
319
			}
320

321
			var cursor int
322
			cursor, err = x.unmarshalHeader(resp, result)
323
			if err != nil {
324
				x.Logger.Printf("ERROR on unmarshall header: %s", err)
325
				break
326
			}
327

328
			if x.Version == Version3 {
329
				useResponseSecurityParameters := false
330
				if usp, ok := x.SecurityParameters.(*UsmSecurityParameters); ok {
331
					if usp.AuthoritativeEngineID == "" {
332
						useResponseSecurityParameters = true
333
					}
334
				}
335
				err = x.testAuthentication(resp, result, useResponseSecurityParameters)
336
				if err != nil {
337
					x.Logger.Printf("ERROR on Test Authentication on v3: %s", err)
338
					break
339
				}
340
				resp, cursor, err = x.decryptPacket(resp, cursor, result)
341
				if err != nil {
342
					x.Logger.Printf("ERROR on decryptPacket on v3: %s", err)
343
					break
344
				}
345
			}
346

347
			err = x.unmarshalPayload(resp, cursor, result)
348
			if err != nil {
349
				x.Logger.Printf("ERROR on UnmarshalPayload on v3: %s", err)
350
				break
351
			}
352
			if result.Error == NoError && len(result.Variables) < 1 {
353
				x.Logger.Printf("ERROR on UnmarshalPayload on v3: Empty result")
354
				break
355
			}
356

357
			// While Report PDU was defined by RFC 1905 as part of SNMPv2, it was never
358
			// used until SNMPv3. Report PDU's allow a SNMP engine to tell another SNMP
359
			// engine that an error was detected while processing an SNMP message.
360
			//
361
			// The format for a Report PDU is
362
			// -----------------------------------
363
			// | 0xA8 | reqid | 0 | 0 | varbinds |
364
			// -----------------------------------
365
			// where:
366
			// - PDU type 0xA8 indicates a Report PDU.
367
			// - reqid is either:
368
			//    The request identifier of the message that triggered the report
369
			//    or zero if the request identifier cannot be extracted.
370
			// - The variable bindings will contain a single object identifier and its value
371
			//
372
			// usmStatsNotInTimeWindows and usmStatsUnknownEngineIDs are recoverable errors
373
			// and will be retransmitted, for others we return the result with an error.
374
			if result.Version == Version3 && result.PDUType == Report && len(result.Variables) == 1 {
375
				switch result.Variables[0].Name {
376
				case usmStatsUnsupportedSecLevels:
377
					return result, ErrUnknownSecurityLevel
378
				case usmStatsNotInTimeWindows:
379
					break waitingResponse
380
				case usmStatsUnknownUserNames:
381
					return result, ErrUnknownUsername
382
				case usmStatsUnknownEngineIDs:
383
					break waitingResponse
384
				case usmStatsWrongDigests:
385
					return result, ErrWrongDigest
386
				case usmStatsDecryptionErrors:
387
					return result, ErrDecryption
388
				case snmpUnknownSecurityModels:
389
					return result, ErrUnknownSecurityModels
390
				case snmpInvalidMsgs:
391
					return result, ErrInvalidMsgs
392
				case snmpUnknownPDUHandlers:
393
					return result, ErrUnknownPDUHandlers
394
				default:
395
					return result, ErrUnknownReportPDU
396
				}
397
			}
398

399
			validID := false
400
			for _, id := range allReqIDs {
401
				if id == result.RequestID {
402
					validID = true
403
				}
404
			}
405
			if result.RequestID == 0 {
406
				validID = true
407
			}
408
			if !validID {
409
				x.Logger.Print("ERROR out of order")
410
				continue
411
			}
412

413
			break
414
		}
415
		if err != nil {
416
			continue
417
		}
418

419
		if x.OnFinish != nil {
420
			x.OnFinish(x)
421
		}
422
		// Success!
423
		return result, nil
424
	}
425

426
	// Return last error
427
	return nil, err
428
}
429

430
// generic "sender" that negotiate any version of snmp request
431
//
432
// all sends wait for the return packet, except for SNMPv2Trap
433
func (x *GoSNMP) send(packetOut *SnmpPacket, wait bool) (result *SnmpPacket, err error) {
434
	defer func() {
435
		if e := recover(); e != nil {
436
			var buf = make([]byte, 8192)
437
			runtime.Stack(buf, true)
438

439
			err = fmt.Errorf("recover: %v Stack:%v", e, string(buf))
440
		}
441
	}()
442

443
	if x.Conn == nil {
444
		return nil, fmt.Errorf("&GoSNMP.Conn is missing. Provide a connection or use Connect()")
445
	}
446

447
	if x.Retries < 0 {
448
		x.Retries = 0
449
	}
450
	x.Logger.Print("SEND INIT")
451
	if packetOut.Version == Version3 {
452
		x.Logger.Print("SEND INIT NEGOTIATE SECURITY PARAMS")
453
		if err = x.negotiateInitialSecurityParameters(packetOut); err != nil {
454
			return &SnmpPacket{}, err
455
		}
456
		x.Logger.Print("SEND END NEGOTIATE SECURITY PARAMS")
457
	}
458

459
	// perform request
460
	result, err = x.sendOneRequest(packetOut, wait)
461
	if err != nil {
462
		x.Logger.Printf("SEND Error on the first Request Error: %s", err)
463
		return result, err
464
	}
465

466
	if result.Version == Version3 {
467
		x.Logger.Printf("SEND STORE SECURITY PARAMS from result: %s", result.SecurityParameters.SafeString())
468
		err = x.storeSecurityParameters(result)
469

470
		if result.PDUType == Report && len(result.Variables) == 1 {
471
			switch result.Variables[0].Name {
472
			case usmStatsNotInTimeWindows:
473
				x.Logger.Print("WARNING detected out-of-time-window ERROR")
474
				if err = x.updatePktSecurityParameters(packetOut); err != nil {
475
					x.Logger.Printf("ERROR updatePktSecurityParameters error: %s", err)
476
					return nil, err
477
				}
478
				// retransmit with updated auth engine params
479
				result, err = x.sendOneRequest(packetOut, wait)
480
				if err != nil {
481
					x.Logger.Printf("ERROR out-of-time-window retransmit error: %s", err)
482
					return result, ErrNotInTimeWindow
483
				}
484

485
			case usmStatsUnknownEngineIDs:
486
				x.Logger.Print("WARNING detected unknown engine id ERROR")
487
				if err = x.updatePktSecurityParameters(packetOut); err != nil {
488
					x.Logger.Printf("ERROR updatePktSecurityParameters error: %s", err)
489
					return nil, err
490
				}
491
				// retransmit with updated engine id
492
				result, err = x.sendOneRequest(packetOut, wait)
493
				if err != nil {
494
					x.Logger.Printf("ERROR unknown engine id retransmit error: %s", err)
495
					return result, ErrUnknownEngineID
496
				}
497
			}
498
		}
499
	}
500
	return result, err
501
}
502

503
// -- Marshalling Logic --------------------------------------------------------
504

505
// MarshalMsg marshalls a snmp packet, ready for sending across the wire
506
func (packet *SnmpPacket) MarshalMsg() ([]byte, error) {
507
	return packet.marshalMsg()
508
}
509

510
// marshal an SNMP message
511
func (packet *SnmpPacket) marshalMsg() ([]byte, error) {
512
	var err error
513
	buf := new(bytes.Buffer)
514

515
	// version
516
	buf.Write([]byte{2, 1, byte(packet.Version)})
517

518
	if packet.Version == Version3 {
519
		buf, err = packet.marshalV3(buf)
520
		if err != nil {
521
			return nil, err
522
		}
523
	} else {
524
		// community
525
		buf.Write([]byte{4, uint8(len(packet.Community))})
526
		buf.WriteString(packet.Community)
527
		// pdu
528
		pdu, err2 := packet.marshalPDU()
529
		if err2 != nil {
530
			return nil, err2
531
		}
532
		buf.Write(pdu)
533
	}
534

535
	// build up resulting msg - sequence, length then the tail (buf)
536
	msg := new(bytes.Buffer)
537
	msg.WriteByte(byte(Sequence))
538

539
	bufLengthBytes, err2 := marshalLength(buf.Len())
540
	if err2 != nil {
541
		return nil, err2
542
	}
543
	msg.Write(bufLengthBytes)
544
	_, err = buf.WriteTo(msg)
545
	if err != nil {
546
		return nil, err
547
	}
548

549
	authenticatedMessage, err := packet.authenticate(msg.Bytes())
550
	if err != nil {
551
		return nil, err
552
	}
553

554
	return authenticatedMessage, nil
555
}
556

557
func (packet *SnmpPacket) marshalSNMPV1TrapHeader() ([]byte, error) {
558
	buf := new(bytes.Buffer)
559

560
	// marshal OID
561
	oidBytes, err := marshalObjectIdentifier(packet.Enterprise)
562
	if err != nil {
563
		return nil, fmt.Errorf("unable to marshal OID: %w", err)
564
	}
565
	buf.Write([]byte{byte(ObjectIdentifier), byte(len(oidBytes))})
566
	buf.Write(oidBytes)
567

568
	// marshal AgentAddress (ip address)
569
	ip := net.ParseIP(packet.AgentAddress)
570
	ipAddressBytes := ipv4toBytes(ip)
571
	buf.Write([]byte{byte(IPAddress), byte(len(ipAddressBytes))})
572
	buf.Write(ipAddressBytes)
573

574
	// marshal GenericTrap. Could just cast GenericTrap to a single byte as IDs greater than 6 are unknown,
575
	// but do it properly. See issue 182.
576
	var genericTrapBytes []byte
577
	genericTrapBytes, err = marshalInt32(packet.GenericTrap)
578
	if err != nil {
579
		return nil, fmt.Errorf("unable to marshal SNMPv1 GenericTrap: %w", err)
580
	}
581
	buf.Write([]byte{byte(Integer), byte(len(genericTrapBytes))})
582
	buf.Write(genericTrapBytes)
583

584
	// marshal SpecificTrap
585
	var specificTrapBytes []byte
586
	specificTrapBytes, err = marshalInt32(packet.SpecificTrap)
587
	if err != nil {
588
		return nil, fmt.Errorf("unable to marshal SNMPv1 SpecificTrap: %w", err)
589
	}
590
	buf.Write([]byte{byte(Integer), byte(len(specificTrapBytes))})
591
	buf.Write(specificTrapBytes)
592

593
	// marshal timeTicks
594
	timeTickBytes, err := marshalUint32(packet.Timestamp)
595
	if err != nil {
596
		return nil, fmt.Errorf("unable to Timestamp: %w", err)
597
	}
598
	buf.Write([]byte{byte(TimeTicks), byte(len(timeTickBytes))})
599
	buf.Write(timeTickBytes)
600

601
	return buf.Bytes(), nil
602
}
603

604
// marshal a PDU
605
func (packet *SnmpPacket) marshalPDU() ([]byte, error) {
606
	buf := new(bytes.Buffer)
607

608
	switch packet.PDUType {
609
	case GetBulkRequest:
610
		// requestid
611
		err := shrinkAndWriteUint(buf, int(packet.RequestID))
612
		if err != nil {
613
			return nil, err
614
		}
615

616
		// non repeaters
617
		nonRepeaters, err := marshalUint32(packet.NonRepeaters)
618
		if err != nil {
619
			return nil, fmt.Errorf("marshalPDU: unable to marshal NonRepeaters to uint32: %w", err)
620
		}
621

622
		buf.Write([]byte{2, byte(len(nonRepeaters))})
623
		if err = binary.Write(buf, binary.BigEndian, nonRepeaters); err != nil {
624
			return nil, fmt.Errorf("marshalPDU: unable to marshal NonRepeaters: %w", err)
625
		}
626

627
		// max repetitions
628
		maxRepetitions, err := marshalUint32(packet.MaxRepetitions)
629
		if err != nil {
630
			return nil, fmt.Errorf("marshalPDU: unable to marshal maxRepetitions to uint32: %w", err)
631
		}
632

633
		buf.Write([]byte{2, byte(len(maxRepetitions))})
634
		if err = binary.Write(buf, binary.BigEndian, maxRepetitions); err != nil {
635
			return nil, fmt.Errorf("marshalPDU: unable to marshal maxRepetitions: %w", err)
636
		}
637

638
	case Trap:
639
		// write SNMP V1 Trap Header fields
640
		snmpV1TrapHeader, err := packet.marshalSNMPV1TrapHeader()
641
		if err != nil {
642
			return nil, err
643
		}
644

645
		buf.Write(snmpV1TrapHeader)
646

647
	default:
648
		// requestid
649
		err := shrinkAndWriteUint(buf, int(packet.RequestID))
650
		if err != nil {
651
			return nil, err
652
		}
653

654
		// error status
655
		errorStatus, err := marshalUint32(packet.Error)
656
		if err != nil {
657
			return nil, fmt.Errorf("marshalPDU: unable to marshal errorStatus to uint32: %w", err)
658
		}
659

660
		buf.Write([]byte{2, byte(len(errorStatus))})
661
		if err = binary.Write(buf, binary.BigEndian, errorStatus); err != nil {
662
			return nil, fmt.Errorf("marshalPDU: unable to marshal errorStatus: %w", err)
663
		}
664

665
		// error index
666
		errorIndex, err := marshalUint32(packet.ErrorIndex)
667
		if err != nil {
668
			return nil, fmt.Errorf("marshalPDU: unable to marshal errorIndex to uint32: %w", err)
669
		}
670

671
		buf.Write([]byte{2, byte(len(errorIndex))})
672
		if err = binary.Write(buf, binary.BigEndian, errorIndex); err != nil {
673
			return nil, fmt.Errorf("marshalPDU: unable to marshal errorIndex: %w", err)
674
		}
675
	}
676

677
	// build varbind list
678
	vbl, err := packet.marshalVBL()
679
	if err != nil {
680
		return nil, fmt.Errorf("marshalPDU: unable to marshal varbind list: %w", err)
681
	}
682
	buf.Write(vbl)
683

684
	// build up resulting pdu
685
	pdu := new(bytes.Buffer)
686
	// calculate pdu length
687
	bufLengthBytes, err := marshalLength(buf.Len())
688
	if err != nil {
689
		return nil, fmt.Errorf("marshalPDU: unable to marshal pdu length: %w", err)
690
	}
691
	// write request type
692
	pdu.WriteByte(byte(packet.PDUType))
693
	// write pdu length
694
	pdu.Write(bufLengthBytes)
695
	// write the tail (buf)
696
	if _, err = buf.WriteTo(pdu); err != nil {
697
		return nil, fmt.Errorf("marshalPDU: unable to marshal pdu: %w", err)
698
	}
699

700
	return pdu.Bytes(), nil
701
}
702

703
// marshal a varbind list
704
func (packet *SnmpPacket) marshalVBL() ([]byte, error) {
705
	vblBuf := new(bytes.Buffer)
706
	for _, pdu := range packet.Variables {
707
		pdu := pdu
708
		vb, err := marshalVarbind(&pdu)
709
		if err != nil {
710
			return nil, err
711
		}
712
		vblBuf.Write(vb)
713
	}
714

715
	vblBytes := vblBuf.Bytes()
716
	vblLengthBytes, err := marshalLength(len(vblBytes))
717
	if err != nil {
718
		return nil, err
719
	}
720

721
	// FIX does bytes.Buffer give better performance than byte slices?
722
	result := []byte{byte(Sequence)}
723
	result = append(result, vblLengthBytes...)
724
	result = append(result, vblBytes...)
725
	return result, nil
726
}
727

728
// marshal a varbind
729
func marshalVarbind(pdu *SnmpPDU) ([]byte, error) {
730
	oid, err := marshalObjectIdentifier(pdu.Name)
731
	if err != nil {
732
		return nil, err
733
	}
734
	pduBuf := new(bytes.Buffer)
735
	tmpBuf := new(bytes.Buffer)
736

737
	// Marshal the PDU type into the appropriate BER
738
	switch pdu.Type {
739
	case Null:
740
		ltmp, err2 := marshalLength(len(oid))
741
		if err2 != nil {
742
			return nil, err2
743
		}
744
		tmpBuf.Write([]byte{byte(ObjectIdentifier)})
745
		tmpBuf.Write(ltmp)
746
		tmpBuf.Write(oid)
747
		tmpBuf.Write([]byte{byte(Null), byte(EndOfContents)})
748

749
		ltmp, err2 = marshalLength(tmpBuf.Len())
750
		if err2 != nil {
751
			return nil, err2
752
		}
753
		pduBuf.Write([]byte{byte(Sequence)})
754
		pduBuf.Write(ltmp)
755
		_, err2 = tmpBuf.WriteTo(pduBuf)
756
		if err2 != nil {
757
			return nil, err2
758
		}
759

760
	case Integer:
761
		// Oid
762
		tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))})
763
		tmpBuf.Write(oid)
764

765
		// Number
766
		var intBytes []byte
767
		switch value := pdu.Value.(type) {
768
		case byte:
769
			intBytes = []byte{byte(pdu.Value.(int))}
770
		case int:
771
			if intBytes, err = marshalInt32(value); err != nil {
772
				return nil, fmt.Errorf("error mashalling PDU Integer: %w", err)
773
			}
774
		default:
775
			return nil, fmt.Errorf("unable to marshal PDU Integer; not byte or int")
776
		}
777
		tmpBuf.Write([]byte{byte(Integer), byte(len(intBytes))})
778
		tmpBuf.Write(intBytes)
779

780
		// Sequence, length of oid + integer, then oid/integer data
781
		pduBuf.WriteByte(byte(Sequence))
782
		pduBuf.WriteByte(byte(len(oid) + len(intBytes) + 4))
783
		pduBuf.Write(tmpBuf.Bytes())
784

785
	case Counter32, Gauge32, TimeTicks, Uinteger32:
786
		// Oid
787
		tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))})
788
		tmpBuf.Write(oid)
789

790
		// Number
791
		var intBytes []byte
792
		switch value := pdu.Value.(type) {
793
		case uint32:
794
			if intBytes, err = marshalUint32(value); err != nil {
795
				return nil, fmt.Errorf("error marshalling PDU Uinteger32 type from uint32: %w", err)
796
			}
797
		case uint:
798
			if intBytes, err = marshalUint32(value); err != nil {
799
				return nil, fmt.Errorf("error marshalling PDU Uinteger32 type from uint: %w", err)
800
			}
801
		default:
802
			return nil, fmt.Errorf("unable to marshal pdu.Type %v; unknown pdu.Value %v[type=%T]", pdu.Type, pdu.Value, pdu.Value)
803
		}
804
		tmpBuf.Write([]byte{byte(pdu.Type), byte(len(intBytes))})
805
		tmpBuf.Write(intBytes)
806

807
		// Sequence, length of oid + integer, then oid/integer data
808
		pduBuf.WriteByte(byte(Sequence))
809
		pduBuf.WriteByte(byte(len(oid) + len(intBytes) + 4))
810
		pduBuf.Write(tmpBuf.Bytes())
811

812
	case OctetString, BitString, Opaque:
813
		// Oid
814
		tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))})
815
		tmpBuf.Write(oid)
816

817
		// OctetString
818
		var octetStringBytes []byte
819
		switch value := pdu.Value.(type) {
820
		case []byte:
821
			octetStringBytes = value
822
		case string:
823
			octetStringBytes = []byte(value)
824
		default:
825
			return nil, fmt.Errorf("unable to marshal PDU OctetString; not []byte or string")
826
		}
827

828
		var length []byte
829
		length, err = marshalLength(len(octetStringBytes))
830
		if err != nil {
831
			return nil, fmt.Errorf("unable to marshal PDU length: %w", err)
832
		}
833
		tmpBuf.WriteByte(byte(pdu.Type))
834
		tmpBuf.Write(length)
835
		tmpBuf.Write(octetStringBytes)
836

837
		tmpBytes := tmpBuf.Bytes()
838

839
		length, err = marshalLength(len(tmpBytes))
840
		if err != nil {
841
			return nil, fmt.Errorf("unable to marshal PDU data length: %w", err)
842
		}
843
		// Sequence, length of oid + octetstring, then oid/octetstring data
844
		pduBuf.WriteByte(byte(Sequence))
845

846
		pduBuf.Write(length)
847
		pduBuf.Write(tmpBytes)
848

849
	case ObjectIdentifier:
850
		// Oid
851
		tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))})
852
		tmpBuf.Write(oid)
853
		value := pdu.Value.(string)
854
		oidBytes, err := marshalObjectIdentifier(value)
855
		if err != nil {
856
			return nil, fmt.Errorf("error marshalling ObjectIdentifier: %w", err)
857
		}
858

859
		// Oid data
860
		var length []byte
861
		length, err = marshalLength(len(oidBytes))
862
		if err != nil {
863
			return nil, fmt.Errorf("error marshalling ObjectIdentifier length: %w", err)
864
		}
865
		tmpBuf.WriteByte(byte(pdu.Type))
866
		tmpBuf.Write(length)
867
		tmpBuf.Write(oidBytes)
868

869
		tmpBytes := tmpBuf.Bytes()
870
		length, err = marshalLength(len(tmpBytes))
871
		if err != nil {
872
			return nil, fmt.Errorf("error marshalling ObjectIdentifier data length: %w", err)
873
		}
874
		// Sequence, length of oid + oid, then oid/oid data
875
		pduBuf.WriteByte(byte(Sequence))
876
		pduBuf.Write(length)
877
		pduBuf.Write(tmpBytes)
878

879
	case IPAddress:
880
		// Oid
881
		tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))})
882
		tmpBuf.Write(oid)
883
		// OctetString
884
		var ipAddressBytes []byte
885
		switch value := pdu.Value.(type) {
886
		case []byte:
887
			ipAddressBytes = value
888
		case string:
889
			ip := net.ParseIP(value)
890
			ipAddressBytes = ipv4toBytes(ip)
891
		default:
892
			return nil, fmt.Errorf("unable to marshal PDU IPAddress; not []byte or string")
893
		}
894
		tmpBuf.Write([]byte{byte(IPAddress), byte(len(ipAddressBytes))})
895
		tmpBuf.Write(ipAddressBytes)
896
		// Sequence, length of oid + octetstring, then oid/octetstring data
897
		pduBuf.WriteByte(byte(Sequence))
898
		pduBuf.WriteByte(byte(len(oid) + len(ipAddressBytes) + 4))
899
		pduBuf.Write(tmpBuf.Bytes())
900

901
	case OpaqueFloat, OpaqueDouble:
902
		converters := map[Asn1BER]func(interface{}) ([]byte, error){
903
			OpaqueFloat:  marshalFloat32,
904
			OpaqueDouble: marshalFloat64,
905
		}
906

907
		intBuf := new(bytes.Buffer)
908
		intBuf.WriteByte(byte(AsnExtensionTag))
909
		intBuf.WriteByte(byte(pdu.Type))
910
		intBytes, err := converters[pdu.Type](pdu.Value)
911
		if err != nil {
912
			return nil, fmt.Errorf("error converting PDU value type %v to %v: %w", pdu.Value, pdu.Type, err)
913
		}
914
		intLength, err := marshalLength(len(intBytes))
915
		if err != nil {
916
			return nil, fmt.Errorf("error marshalling Float type length: %w", err)
917
		}
918
		intBuf.Write(intLength)
919
		intBuf.Write(intBytes)
920

921
		opaqueLength, err := marshalLength(len(intBuf.Bytes()))
922
		if err != nil {
923
			return nil, fmt.Errorf("error marshalling Float type length: %w", err)
924
		}
925
		tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))})
926
		tmpBuf.Write(oid)
927
		tmpBuf.WriteByte(byte(Opaque))
928
		tmpBuf.Write(opaqueLength)
929
		tmpBuf.Write(intBuf.Bytes())
930

931
		length, err := marshalLength(len(tmpBuf.Bytes()))
932
		if err != nil {
933
			return nil, fmt.Errorf("error marshalling Float type length: %w", err)
934
		}
935

936
		// Sequence, length of oid + oid, then oid/oid data
937
		pduBuf.WriteByte(byte(Sequence))
938
		pduBuf.Write(length)
939
		pduBuf.Write(tmpBuf.Bytes())
940

941
	case Counter64:
942
		tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))})
943
		tmpBuf.Write(oid)
944
		tmpBuf.WriteByte(byte(pdu.Type))
945
		intBytes := marshalUint64(pdu.Value)
946
		tmpBuf.WriteByte(byte(len(intBytes)))
947
		tmpBuf.Write(intBytes)
948
		tmpBytes := tmpBuf.Bytes()
949
		length, err := marshalLength(len(tmpBytes))
950
		if err != nil {
951
			return nil, fmt.Errorf("error marshalling Float type length: %w", err)
952
		}
953
		// Sequence, length of oid + oid, then oid/oid data
954
		pduBuf.WriteByte(byte(Sequence))
955
		pduBuf.Write(length)
956
		pduBuf.Write(tmpBytes)
957

958
	case NoSuchInstance, NoSuchObject, EndOfMibView:
959
		tmpBuf.Write([]byte{byte(ObjectIdentifier), byte(len(oid))})
960
		tmpBuf.Write(oid)
961
		tmpBuf.WriteByte(byte(pdu.Type))
962
		tmpBuf.WriteByte(byte(EndOfContents))
963
		tmpBytes := tmpBuf.Bytes()
964
		length, err := marshalLength(len(tmpBytes))
965
		if err != nil {
966
			return nil, fmt.Errorf("error marshalling Null type data length: %w", err)
967
		}
968
		// Sequence, length of oid + oid, then oid/oid data
969
		pduBuf.WriteByte(byte(Sequence))
970
		pduBuf.Write(length)
971
		pduBuf.Write(tmpBytes)
972

973
	default:
974
		return nil, fmt.Errorf("unable to marshal PDU: unknown BER type %q", pdu.Type)
975
	}
976

977
	return pduBuf.Bytes(), nil
978
}
979

980
// -- Unmarshalling Logic ------------------------------------------------------
981

982
func (x *GoSNMP) unmarshalVersionFromHeader(packet []byte, response *SnmpPacket) (SnmpVersion, int, error) {
983
	if len(packet) < 2 {
984
		return 0, 0, fmt.Errorf("cannot unmarshal empty packet")
985
	}
986
	if response == nil {
987
		return 0, 0, fmt.Errorf("cannot unmarshal response into nil packet reference")
988
	}
989

990
	response.Variables = make([]SnmpPDU, 0, 5)
991

992
	// Start parsing the packet
993
	cursor := 0
994

995
	// First bytes should be 0x30
996
	if PDUType(packet[0]) != Sequence {
997
		return 0, 0, fmt.Errorf("invalid packet header")
998
	}
999

1000
	length, cursor, err := parseLength(packet)
1001
	if err != nil {
1002
		return 0, 0, err
1003
	}
1004
	if len(packet) != length {
1005
		return 0, 0, fmt.Errorf("error verifying packet sanity: Got %d Expected: %d", len(packet), length)
1006
	}
1007
	x.Logger.Printf("Packet sanity verified, we got all the bytes (%d)", length)
1008

1009
	// Parse SNMP Version
1010
	rawVersion, count, err := parseRawField(x.Logger, packet[cursor:], "version")
1011
	if err != nil {
1012
		return 0, 0, fmt.Errorf("error parsing SNMP packet version: %w", err)
1013
	}
1014

1015
	cursor += count
1016
	if cursor >= len(packet) {
1017
		return 0, 0, fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
1018
	}
1019

1020
	if version, ok := rawVersion.(int); ok {
1021
		x.Logger.Printf("Parsed version %d", version)
1022
		return SnmpVersion(version), cursor, nil
1023
	}
1024
	return 0, cursor, err
1025
}
1026

1027
func (x *GoSNMP) unmarshalHeader(packet []byte, response *SnmpPacket) (int, error) {
1028
	version, cursor, err := x.unmarshalVersionFromHeader(packet, response)
1029
	if err != nil {
1030
		return 0, err
1031
	}
1032
	response.Version = version
1033

1034
	if response.Version == Version3 {
1035
		oldcursor := cursor
1036
		cursor, err = x.unmarshalV3Header(packet, cursor, response)
1037
		if err != nil {
1038
			return 0, err
1039
		}
1040
		x.Logger.Printf("UnmarshalV3Header done. [with SecurityParameters]. Header Size %d. Last 4 Bytes=[%v]", cursor-oldcursor, packet[cursor-4:cursor])
1041
	} else {
1042
		// Parse community
1043
		rawCommunity, count, err := parseRawField(x.Logger, packet[cursor:], "community")
1044
		if err != nil {
1045
			return 0, fmt.Errorf("error parsing community string: %w", err)
1046
		}
1047
		cursor += count
1048
		if cursor > len(packet) {
1049
			return 0, fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
1050
		}
1051

1052
		if community, ok := rawCommunity.(string); ok {
1053
			response.Community = community
1054
			x.Logger.Printf("Parsed community %s", community)
1055
		}
1056
	}
1057
	return cursor, nil
1058
}
1059

1060
func (x *GoSNMP) unmarshalPayload(packet []byte, cursor int, response *SnmpPacket) error {
1061
	if len(packet) == 0 {
1062
		return errors.New("cannot unmarshal nil or empty payload packet")
1063
	}
1064
	if cursor >= len(packet) {
1065
		return fmt.Errorf("cannot unmarshal payload, packet length %d cursor %d", len(packet), cursor)
1066
	}
1067
	if response == nil {
1068
		return errors.New("cannot unmarshal payload response into nil packet reference")
1069
	}
1070

1071
	// Parse SNMP packet type
1072
	requestType := PDUType(packet[cursor])
1073
	x.Logger.Printf("UnmarshalPayload Meet PDUType %#x. Offset %v", requestType, cursor)
1074
	switch requestType {
1075
	// known, supported types
1076
	case GetResponse, GetNextRequest, GetBulkRequest, Report, SNMPv2Trap, GetRequest, SetRequest, InformRequest:
1077
		response.PDUType = requestType
1078
		if err := x.unmarshalResponse(packet[cursor:], response); err != nil {
1079
			return fmt.Errorf("error in unmarshalResponse: %w", err)
1080
		}
1081
		// If it's an InformRequest, mark the trap.
1082
		response.IsInform = (requestType == InformRequest)
1083
	case Trap:
1084
		response.PDUType = requestType
1085
		if err := x.unmarshalTrapV1(packet[cursor:], response); err != nil {
1086
			return fmt.Errorf("error in unmarshalTrapV1: %w", err)
1087
		}
1088
	default:
1089
		x.Logger.Printf("UnmarshalPayload Meet Unknown PDUType %#x. Offset %v", requestType, cursor)
1090
		return fmt.Errorf("unknown PDUType %#x", requestType)
1091
	}
1092
	return nil
1093
}
1094

1095
func (x *GoSNMP) unmarshalResponse(packet []byte, response *SnmpPacket) error {
1096
	cursor := 0
1097

1098
	getResponseLength, cursor, err := parseLength(packet)
1099
	if err != nil {
1100
		return err
1101
	}
1102
	if len(packet) != getResponseLength {
1103
		return fmt.Errorf("error verifying Response sanity: Got %d Expected: %d", len(packet), getResponseLength)
1104
	}
1105
	x.Logger.Printf("getResponseLength: %d", getResponseLength)
1106

1107
	// Parse Request-ID
1108
	rawRequestID, count, err := parseRawField(x.Logger, packet[cursor:], "request id")
1109
	if err != nil {
1110
		return fmt.Errorf("error parsing SNMP packet request ID: %w", err)
1111
	}
1112
	cursor += count
1113
	if cursor > len(packet) {
1114
		return fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
1115
	}
1116

1117
	if requestid, ok := rawRequestID.(int); ok {
1118
		response.RequestID = uint32(requestid)
1119
		x.Logger.Printf("requestID: %d", response.RequestID)
1120
	}
1121

1122
	if response.PDUType == GetBulkRequest {
1123
		// Parse Non Repeaters
1124
		rawNonRepeaters, count, err := parseRawField(x.Logger, packet[cursor:], "non repeaters")
1125
		if err != nil {
1126
			return fmt.Errorf("error parsing SNMP packet non repeaters: %w", err)
1127
		}
1128
		cursor += count
1129
		if cursor > len(packet) {
1130
			return fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
1131
		}
1132

1133
		if nonRepeaters, ok := rawNonRepeaters.(int); ok {
1134
			response.NonRepeaters = uint8(nonRepeaters)
1135
		}
1136

1137
		// Parse Max Repetitions
1138
		rawMaxRepetitions, count, err := parseRawField(x.Logger, packet[cursor:], "max repetitions")
1139
		if err != nil {
1140
			return fmt.Errorf("error parsing SNMP packet max repetitions: %w", err)
1141
		}
1142
		cursor += count
1143
		if cursor > len(packet) {
1144
			return fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
1145
		}
1146

1147
		if maxRepetitions, ok := rawMaxRepetitions.(int); ok {
1148
			response.MaxRepetitions = uint32(maxRepetitions & 0x7FFFFFFF)
1149
		}
1150
	} else {
1151
		// Parse Error-Status
1152
		rawError, count, err := parseRawField(x.Logger, packet[cursor:], "error-status")
1153
		if err != nil {
1154
			return fmt.Errorf("error parsing SNMP packet error: %w", err)
1155
		}
1156
		cursor += count
1157
		if cursor > len(packet) {
1158
			return fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
1159
		}
1160

1161
		if errorStatus, ok := rawError.(int); ok {
1162
			response.Error = SNMPError(errorStatus)
1163
			x.Logger.Printf("errorStatus: %d", uint8(errorStatus))
1164
		}
1165

1166
		// Parse Error-Index
1167
		rawErrorIndex, count, err := parseRawField(x.Logger, packet[cursor:], "error index")
1168
		if err != nil {
1169
			return fmt.Errorf("error parsing SNMP packet error index: %w", err)
1170
		}
1171
		cursor += count
1172
		if cursor > len(packet) {
1173
			return fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
1174
		}
1175

1176
		if errorindex, ok := rawErrorIndex.(int); ok {
1177
			response.ErrorIndex = uint8(errorindex)
1178
			x.Logger.Printf("error-index: %d", uint8(errorindex))
1179
		}
1180
	}
1181

1182
	return x.unmarshalVBL(packet[cursor:], response)
1183
}
1184

1185
func (x *GoSNMP) unmarshalTrapV1(packet []byte, response *SnmpPacket) error {
1186
	cursor := 0
1187

1188
	getResponseLength, cursor, err := parseLength(packet)
1189
	if err != nil {
1190
		return err
1191
	}
1192
	if len(packet) != getResponseLength {
1193
		return fmt.Errorf("error verifying Response sanity: Got %d Expected: %d", len(packet), getResponseLength)
1194
	}
1195
	x.Logger.Printf("getResponseLength: %d", getResponseLength)
1196

1197
	// Parse Enterprise
1198
	rawEnterprise, count, err := parseRawField(x.Logger, packet[cursor:], "enterprise")
1199
	if err != nil {
1200
		return fmt.Errorf("error parsing SNMP packet error: %w", err)
1201
	}
1202

1203
	cursor += count
1204
	if cursor > len(packet) {
1205
		return fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
1206
	}
1207

1208
	if Enterprise, ok := rawEnterprise.(string); ok {
1209
		response.Enterprise = Enterprise
1210
		x.Logger.Printf("Enterprise: %+v", Enterprise)
1211
	}
1212

1213
	// Parse AgentAddress
1214
	rawAgentAddress, count, err := parseRawField(x.Logger, packet[cursor:], "agent-address")
1215
	if err != nil {
1216
		return fmt.Errorf("error parsing SNMP packet error: %w", err)
1217
	}
1218
	cursor += count
1219
	if cursor > len(packet) {
1220
		return fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
1221
	}
1222

1223
	if AgentAddress, ok := rawAgentAddress.(string); ok {
1224
		response.AgentAddress = AgentAddress
1225
		x.Logger.Printf("AgentAddress: %s", AgentAddress)
1226
	}
1227

1228
	// Parse GenericTrap
1229
	rawGenericTrap, count, err := parseRawField(x.Logger, packet[cursor:], "generic-trap")
1230
	if err != nil {
1231
		return fmt.Errorf("error parsing SNMP packet error: %w", err)
1232
	}
1233
	cursor += count
1234
	if cursor > len(packet) {
1235
		return fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
1236
	}
1237

1238
	if GenericTrap, ok := rawGenericTrap.(int); ok {
1239
		response.GenericTrap = GenericTrap
1240
		x.Logger.Printf("GenericTrap: %d", GenericTrap)
1241
	}
1242

1243
	// Parse SpecificTrap
1244
	rawSpecificTrap, count, err := parseRawField(x.Logger, packet[cursor:], "specific-trap")
1245
	if err != nil {
1246
		return fmt.Errorf("error parsing SNMP packet error: %w", err)
1247
	}
1248
	cursor += count
1249
	if cursor > len(packet) {
1250
		return fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
1251
	}
1252

1253
	if SpecificTrap, ok := rawSpecificTrap.(int); ok {
1254
		response.SpecificTrap = SpecificTrap
1255
		x.Logger.Printf("SpecificTrap: %d", SpecificTrap)
1256
	}
1257

1258
	// Parse TimeStamp
1259
	rawTimestamp, count, err := parseRawField(x.Logger, packet[cursor:], "time-stamp")
1260
	if err != nil {
1261
		return fmt.Errorf("error parsing SNMP packet error: %w", err)
1262
	}
1263
	cursor += count
1264
	if cursor > len(packet) {
1265
		return fmt.Errorf("error parsing SNMP packet, packet length %d cursor %d", len(packet), cursor)
1266
	}
1267

1268
	if Timestamp, ok := rawTimestamp.(uint); ok {
1269
		response.Timestamp = Timestamp
1270
		x.Logger.Printf("Timestamp: %d", Timestamp)
1271
	}
1272

1273
	return x.unmarshalVBL(packet[cursor:], response)
1274
}
1275

1276
// unmarshal a Varbind list
1277
func (x *GoSNMP) unmarshalVBL(packet []byte, response *SnmpPacket) error {
1278
	var cursor, cursorInc int
1279
	var vblLength int
1280

1281
	if len(packet) == 0 || cursor > len(packet) {
1282
		return fmt.Errorf("truncated packet when unmarshalling a VBL, got length %d cursor %d", len(packet), cursor)
1283
	}
1284

1285
	if packet[cursor] != 0x30 {
1286
		return fmt.Errorf("expected a sequence when unmarshalling a VBL, got %x", packet[cursor])
1287
	}
1288

1289
	vblLength, cursor, err := parseLength(packet)
1290
	if err != nil {
1291
		return err
1292
	}
1293
	if vblLength == 0 || vblLength > len(packet) {
1294
		return fmt.Errorf("truncated packet when unmarshalling a VBL, packet length %d cursor %d", len(packet), cursor)
1295
	}
1296

1297
	if len(packet) != vblLength {
1298
		return fmt.Errorf("error verifying: packet length %d vbl length %d", len(packet), vblLength)
1299
	}
1300
	x.Logger.Printf("vblLength: %d", vblLength)
1301

1302
	// check for an empty response
1303
	if vblLength == 2 && packet[1] == 0x00 {
1304
		return nil
1305
	}
1306

1307
	// Loop & parse Varbinds
1308
	for cursor < vblLength {
1309
		if packet[cursor] != 0x30 {
1310
			return fmt.Errorf("expected a sequence when unmarshalling a VB, got %x", packet[cursor])
1311
		}
1312

1313
		_, cursorInc, err = parseLength(packet[cursor:])
1314
		if err != nil {
1315
			return err
1316
		}
1317
		cursor += cursorInc
1318
		if cursor > len(packet) {
1319
			return fmt.Errorf("error parsing OID Value: packet %d cursor %d", len(packet), cursor)
1320
		}
1321

1322
		// Parse OID
1323
		rawOid, oidLength, err := parseRawField(x.Logger, packet[cursor:], "OID")
1324
		if err != nil {
1325
			return fmt.Errorf("error parsing OID Value: %w", err)
1326
		}
1327
		cursor += oidLength
1328
		if cursor > len(packet) {
1329
			return fmt.Errorf("error parsing OID Value: truncated, packet length %d cursor %d", len(packet), cursor)
1330
		}
1331
		oid, ok := rawOid.(string)
1332
		if !ok {
1333
			return fmt.Errorf("unable to type assert rawOid |%v| to string", rawOid)
1334
		}
1335
		x.Logger.Printf("OID: %s", oid)
1336
		// Parse Value
1337
		var decodedVal variable
1338
		if err = x.decodeValue(packet[cursor:], &decodedVal); err != nil {
1339
			return fmt.Errorf("error decoding value: %w", err)
1340
		}
1341

1342
		valueLength, _, err := parseLength(packet[cursor:])
1343
		if err != nil {
1344
			return err
1345
		}
1346
		cursor += valueLength
1347
		if cursor > len(packet) {
1348
			return fmt.Errorf("error decoding OID Value: truncated, packet length %d cursor %d", len(packet), cursor)
1349
		}
1350

1351
		response.Variables = append(response.Variables, SnmpPDU{Name: oid, Type: decodedVal.Type, Value: decodedVal.Value})
1352
	}
1353
	return nil
1354
}
1355

1356
// receive response from network and read into a byte array
1357
func (x *GoSNMP) receive() ([]byte, error) {
1358
	var n int
1359
	var err error
1360
	// If we are using UDP and unconnected socket, read the packet and
1361
	// disregard the source address.
1362
	if uconn, ok := x.Conn.(net.PacketConn); ok {
1363
		n, _, err = uconn.ReadFrom(x.rxBuf[:])
1364
	} else {
1365
		n, err = x.Conn.Read(x.rxBuf[:])
1366
	}
1367
	if err == io.EOF {
1368
		return nil, err
1369
	} else if err != nil {
1370
		return nil, fmt.Errorf("error reading from socket: %w", err)
1371
	}
1372

1373
	if n == rxBufSize {
1374
		// This should never happen unless we're using something like a unix domain socket.
1375
		return nil, fmt.Errorf("response buffer too small")
1376
	}
1377

1378
	resp := make([]byte, n)
1379
	copy(resp, x.rxBuf[:n])
1380
	return resp, nil
1381
}
1382

1383
func shrinkAndWriteUint(buf io.Writer, in int) error {
1384
	out, err := asn1.Marshal(in)
1385
	if err != nil {
1386
		return err
1387
	}
1388
	_, err = buf.Write(out)
1389
	return err
1390
}
1391

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

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

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

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