gosnmp

Форк
0
/
helper.go 
876 строк · 24.0 Кб
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
	"io"
17
	"log"
18
	"math"
19
	"net"
20
	"os"
21
	"strconv"
22
)
23

24
// variable struct is used by decodeValue()
25
type variable struct {
26
	Value interface{}
27
	Type  Asn1BER
28
}
29

30
// helper error modes
31
var (
32
	ErrBase128IntegerTooLarge  = errors.New("base 128 integer too large")
33
	ErrBase128IntegerTruncated = errors.New("base 128 integer truncated")
34
	ErrFloatBufferTooShort     = errors.New("float buffer too short")
35
	ErrFloatTooLarge           = errors.New("float too large")
36
	ErrIntegerTooLarge         = errors.New("integer too large")
37
	ErrInvalidOidLength        = errors.New("invalid OID length")
38
	ErrInvalidPacketLength     = errors.New("invalid packet length")
39
	ErrZeroByteBuffer          = errors.New("zero byte buffer")
40
	ErrZeroLenInteger          = errors.New("zero length integer")
41
)
42

43
// -- helper functions (mostly) in alphabetical order --------------------------
44

45
// Check makes checking errors easy, so they actually get a minimal check
46
func (x *GoSNMP) Check(err error) {
47
	if err != nil {
48
		x.Logger.Printf("Check: %v\n", err)
49
		os.Exit(1)
50
	}
51
}
52

53
// Check makes checking errors easy, so they actually get a minimal check
54
func (packet *SnmpPacket) Check(err error) {
55
	if err != nil {
56
		packet.Logger.Printf("Check: %v\n", err)
57
		os.Exit(1)
58
	}
59
}
60

61
// Check makes checking errors easy, so they actually get a minimal check
62
func Check(err error) {
63
	if err != nil {
64
		log.Fatalf("Check: %v\n", err)
65
	}
66
}
67

68
func (x *GoSNMP) decodeValue(data []byte, retVal *variable) error {
69
	if len(data) == 0 {
70
		return ErrZeroByteBuffer
71
	}
72

73
	switch Asn1BER(data[0]) {
74
	case Integer, Uinteger32:
75
		// 0x02. signed
76
		x.Logger.Printf("decodeValue: type is %s", Asn1BER(data[0]).String())
77
		length, cursor, err := parseLength(data)
78
		if err != nil {
79
			return err
80
		}
81
		// check for truncated packets
82
		if length > len(data) {
83
			return fmt.Errorf("bytes: % x err: truncated (data %d length %d)", data, len(data), length)
84
		}
85

86
		var ret int
87
		if ret, err = parseInt(data[cursor:length]); err != nil {
88
			x.Logger.Printf("%v:", err)
89
			return fmt.Errorf("bytes: % x err: %w", data, err)
90
		}
91
		retVal.Type = Asn1BER(data[0])
92
		switch Asn1BER(data[0]) {
93
		case Uinteger32:
94
			retVal.Value = uint32(ret)
95
		default:
96
			retVal.Value = ret
97
		}
98

99
	case OctetString:
100
		// 0x04
101
		x.Logger.Print("decodeValue: type is OctetString")
102
		length, cursor, err := parseLength(data)
103
		if err != nil {
104
			return err
105
		}
106
		// check for truncated packet and throw an error
107
		if length > len(data) {
108
			return fmt.Errorf("bytes: % x err: truncated (data %d length %d)", data, len(data), length)
109
		}
110

111
		retVal.Type = OctetString
112
		retVal.Value = data[cursor:length]
113
	case Null:
114
		// 0x05
115
		x.Logger.Print("decodeValue: type is Null")
116
		retVal.Type = Null
117
		retVal.Value = nil
118
	case ObjectIdentifier:
119
		// 0x06
120
		x.Logger.Print("decodeValue: type is ObjectIdentifier")
121
		rawOid, _, err := parseRawField(x.Logger, data, "OID")
122
		if err != nil {
123
			return fmt.Errorf("error parsing OID Value: %w", err)
124
		}
125
		oid, ok := rawOid.(string)
126
		if !ok {
127
			return fmt.Errorf("unable to type assert rawOid |%v| to string", rawOid)
128
		}
129
		retVal.Type = ObjectIdentifier
130
		retVal.Value = oid
131
	case IPAddress:
132
		// 0x40
133
		x.Logger.Print("decodeValue: type is IPAddress")
134
		retVal.Type = IPAddress
135
		if len(data) < 2 {
136
			return fmt.Errorf("not enough data for ipv4 address: %x", data)
137
		}
138

139
		switch data[1] {
140
		case 0: // real life, buggy devices returning bad data
141
			retVal.Value = nil
142
			return nil
143
		case 4: // IPv4
144
			if len(data) < 6 {
145
				return fmt.Errorf("not enough data for ipv4 address: %x", data)
146
			}
147
			retVal.Value = net.IPv4(data[2], data[3], data[4], data[5]).String()
148
		case 16: // IPv6
149
			if len(data) < 18 {
150
				return fmt.Errorf("not enough data for ipv6 address: %x", data)
151
			}
152
			d := make(net.IP, 16)
153
			copy(d, data[2:17])
154
			retVal.Value = d.String()
155
		default:
156
			return fmt.Errorf("got ipaddress len %d, expected 4 or 16", data[1])
157
		}
158
	case Counter32:
159
		// 0x41. unsigned
160
		x.Logger.Print("decodeValue: type is Counter32")
161
		length, cursor, err := parseLength(data)
162
		if err != nil {
163
			return err
164
		}
165
		if length > len(data) {
166
			return fmt.Errorf("not enough data for Counter32 %x (data %d length %d)", data, len(data), length)
167
		}
168

169
		ret, err := parseUint(data[cursor:length])
170
		if err != nil {
171
			x.Logger.Printf("decodeValue: err is %v", err)
172
			break
173
		}
174
		retVal.Type = Counter32
175
		retVal.Value = ret
176
	case Gauge32:
177
		// 0x42. unsigned
178
		x.Logger.Print("decodeValue: type is Gauge32")
179
		length, cursor, err := parseLength(data)
180
		if err != nil {
181
			return err
182
		}
183
		if length > len(data) {
184
			return fmt.Errorf("not enough data for Gauge32 %x (data %d length %d)", data, len(data), length)
185
		}
186

187
		ret, err := parseUint(data[cursor:length])
188
		if err != nil {
189
			x.Logger.Printf("decodeValue: err is %v", err)
190
			break
191
		}
192
		retVal.Type = Gauge32
193
		retVal.Value = ret
194
	case TimeTicks:
195
		// 0x43
196
		x.Logger.Print("decodeValue: type is TimeTicks")
197
		length, cursor, err := parseLength(data)
198
		if err != nil {
199
			return err
200
		}
201
		if length > len(data) {
202
			return fmt.Errorf("not enough data for TimeTicks %x (data %d length %d)", data, len(data), length)
203
		}
204

205
		ret, err := parseUint32(data[cursor:length])
206
		if err != nil {
207
			x.Logger.Printf("decodeValue: err is %v", err)
208
			break
209
		}
210
		retVal.Type = TimeTicks
211
		retVal.Value = ret
212
	case Opaque:
213
		// 0x44
214
		x.Logger.Print("decodeValue: type is Opaque")
215
		length, cursor, err := parseLength(data)
216
		if err != nil {
217
			return err
218
		}
219
		if length > len(data) {
220
			return fmt.Errorf("not enough data for Opaque %x (data %d length %d)", data, len(data), length)
221
		}
222
		return parseOpaque(x.Logger, data[cursor:length], retVal)
223
	case Counter64:
224
		// 0x46
225
		x.Logger.Print("decodeValue: type is Counter64")
226
		length, cursor, err := parseLength(data)
227
		if err != nil {
228
			return err
229
		}
230
		if length > len(data) {
231
			return fmt.Errorf("not enough data for Counter64 %x (data %d length %d)", data, len(data), length)
232
		}
233
		ret, err := parseUint64(data[cursor:length])
234
		if err != nil {
235
			x.Logger.Printf("decodeValue: err is %v", err)
236
			break
237
		}
238
		retVal.Type = Counter64
239
		retVal.Value = ret
240
	case NoSuchObject:
241
		// 0x80
242
		x.Logger.Print("decodeValue: type is NoSuchObject")
243
		retVal.Type = NoSuchObject
244
		retVal.Value = nil
245
	case NoSuchInstance:
246
		// 0x81
247
		x.Logger.Print("decodeValue: type is NoSuchInstance")
248
		retVal.Type = NoSuchInstance
249
		retVal.Value = nil
250
	case EndOfMibView:
251
		// 0x82
252
		x.Logger.Print("decodeValue: type is EndOfMibView")
253
		retVal.Type = EndOfMibView
254
		retVal.Value = nil
255
	default:
256
		x.Logger.Printf("decodeValue: type %x isn't implemented", data[0])
257
		retVal.Type = UnknownType
258
		retVal.Value = nil
259
	}
260
	x.Logger.Printf("decodeValue: value is %#v", retVal.Value)
261
	return nil
262
}
263

264
func marshalBase128Int(out io.ByteWriter, n int64) (err error) {
265
	if n == 0 {
266
		err = out.WriteByte(0)
267
		return
268
	}
269

270
	l := 0
271
	for i := n; i > 0; i >>= 7 {
272
		l++
273
	}
274

275
	for i := l - 1; i >= 0; i-- {
276
		o := byte(n >> uint(i*7))
277
		o &= 0x7f
278
		if i != 0 {
279
			o |= 0x80
280
		}
281
		err = out.WriteByte(o)
282
		if err != nil {
283
			return
284
		}
285
	}
286

287
	return nil
288
}
289

290
/*
291
	snmp Integer32 and INTEGER:
292
	-2^31 and 2^31-1 inclusive (-2147483648 to 2147483647 decimal)
293
	(FYI https://groups.google.com/forum/#!topic/comp.protocols.snmp/1xaAMzCe_hE)
294

295
	versus:
296

297
	snmp Counter32, Gauge32, TimeTicks, Unsigned32: (below)
298
	non-negative integer, maximum value of 2^32-1 (4294967295 decimal)
299
*/
300

301
// marshalInt32 builds a byte representation of a signed 32 bit int in BigEndian form
302
// ie -2^31 and 2^31-1 inclusive (-2147483648 to 2147483647 decimal)
303
func marshalInt32(value int) ([]byte, error) {
304
	if value < math.MinInt32 || value > math.MaxInt32 {
305
		return nil, fmt.Errorf("unable to marshal: %d overflows int32", value)
306
	}
307
	const mask1 uint32 = 0xFFFFFF80
308
	const mask2 uint32 = 0xFFFF8000
309
	const mask3 uint32 = 0xFF800000
310
	const mask4 uint32 = 0x80000000
311
	// ITU-T Rec. X.690 (2002) 8.3.2
312
	// If the contents octets of an integer value encoding consist of more than
313
	// one octet, then the bits of the first octet and bit 8 of the second octet:
314
	//  a) shall not all be ones; and
315
	//  b) shall not all be zero
316
	// These rules ensure that an integer value is always encoded in the smallest
317
	// possible number of octets.
318
	val := uint32(value)
319
	switch {
320
	case val&mask1 == 0 || val&mask1 == mask1:
321
		return []byte{byte(val)}, nil
322
	case val&mask2 == 0 || val&mask2 == mask2:
323
		return []byte{byte(val >> 8), byte(val)}, nil
324
	case val&mask3 == 0 || val&mask3 == mask3:
325
		return []byte{byte(val >> 16), byte(val >> 8), byte(val)}, nil
326
	default:
327
		return []byte{byte(val >> 24), byte(val >> 16), byte(val >> 8), byte(val)}, nil
328
	}
329
}
330

331
func marshalUint64(v interface{}) []byte {
332
	bs := make([]byte, 8)
333
	source := v.(uint64)
334
	binary.BigEndian.PutUint64(bs, source) // will panic on failure
335
	// truncate leading zeros. Cleaner technique?
336
	return bytes.TrimLeft(bs, "\x00")
337
}
338

339
// Counter32, Gauge32, TimeTicks, Unsigned32, SNMPError
340
func marshalUint32(v interface{}) ([]byte, error) {
341
	var source uint32
342
	switch val := v.(type) {
343
	case uint32:
344
		source = val
345
	case uint:
346
		source = uint32(val)
347
	case uint8:
348
		source = uint32(val)
349
	case SNMPError:
350
		source = uint32(val)
351
	// We could do others here, but coercing from anything else is dangerous.
352
	// Even uint could be 64 bits, though in practice nothing we work with is.
353
	default:
354
		return nil, fmt.Errorf("unable to marshal %T to uint32", v)
355
	}
356
	buf := make([]byte, 4)
357
	binary.BigEndian.PutUint32(buf, source)
358
	var i int
359
	for i = 0; i < 3; i++ {
360
		if buf[i] != 0 {
361
			break
362
		}
363
	}
364
	buf = buf[i:]
365
	// if the highest bit in buf is set and x is not negative - prepend a byte to make it positive
366
	if len(buf) > 0 && buf[0]&0x80 > 0 {
367
		buf = append([]byte{0}, buf...)
368
	}
369
	return buf, nil
370
}
371

372
func marshalFloat32(v interface{}) ([]byte, error) {
373
	source := v.(float32)
374
	out := bytes.NewBuffer(nil)
375
	err := binary.Write(out, binary.BigEndian, source)
376
	return out.Bytes(), err
377
}
378

379
func marshalFloat64(v interface{}) ([]byte, error) {
380
	source := v.(float64)
381
	out := bytes.NewBuffer(nil)
382
	err := binary.Write(out, binary.BigEndian, source)
383
	return out.Bytes(), err
384
}
385

386
// marshalLength builds a byte representation of length
387
//
388
// http://luca.ntop.org/Teaching/Appunti/asn1.html
389
//
390
// Length octets. There are two forms: short (for lengths between 0 and 127),
391
// and long definite (for lengths between 0 and 2^1008 -1).
392
//
393
//   - Short form. One octet. Bit 8 has value "0" and bits 7-1 give the length.
394
//   - Long form. Two to 127 octets. Bit 8 of first octet has value "1" and bits
395
//     7-1 give the number of additional length octets. Second and following
396
//     octets give the length, base 256, most significant digit first.
397
func marshalLength(length int) ([]byte, error) {
398
	// more convenient to pass length as int than uint64. Therefore check < 0
399
	if length < 0 {
400
		return nil, fmt.Errorf("length must be greater than zero")
401
	} else if length < 127 {
402
		return []byte{byte(length)}, nil
403
	}
404

405
	buf := new(bytes.Buffer)
406
	err := binary.Write(buf, binary.BigEndian, uint64(length))
407
	if err != nil {
408
		return nil, err
409
	}
410
	bufBytes := buf.Bytes()
411

412
	// strip leading zeros
413
	for idx, octect := range bufBytes {
414
		if octect != 00 {
415
			bufBytes = bufBytes[idx:]
416
			break
417
		}
418
	}
419

420
	header := []byte{byte(128 | len(bufBytes))}
421
	return append(header, bufBytes...), nil
422
}
423

424
func marshalObjectIdentifier(oid string) ([]byte, error) {
425
	out := new(bytes.Buffer)
426
	oidLength := len(oid)
427
	oidBase := 0
428
	var err error
429
	i := 0
430
	for j := 0; j < oidLength; {
431
		if oid[j] == '.' {
432
			j++
433
			continue
434
		}
435
		var val int64
436
		for j < oidLength && oid[j] != '.' {
437
			ch := int64(oid[j] - '0')
438
			if ch > 9 {
439
				return []byte{}, fmt.Errorf("unable to marshal OID: Invalid object identifier")
440
			}
441
			val *= 10
442
			val += ch
443
			j++
444
		}
445
		switch i {
446
		case 0:
447
			if val > 6 {
448
				return []byte{}, fmt.Errorf("unable to marshal OID: Invalid object identifier")
449
			}
450
			oidBase = int(val * 40)
451
		case 1:
452
			if val >= 40 {
453
				return []byte{}, fmt.Errorf("unable to marshal OID: Invalid object identifier")
454
			}
455
			oidBase += int(val)
456
			err = out.WriteByte(byte(oidBase))
457
			if err != nil {
458
				return []byte{}, fmt.Errorf("unable to marshal OID: Invalid object identifier")
459
			}
460

461
		default:
462
			if val > MaxObjectSubIdentifierValue {
463
				return []byte{}, fmt.Errorf("unable to marshal OID: Value out of range")
464
			}
465
			err = marshalBase128Int(out, val)
466
			if err != nil {
467
				return []byte{}, fmt.Errorf("unable to marshal OID: Invalid object identifier")
468
			}
469
		}
470
		i++
471
	}
472
	if i < 2 || i > 128 {
473
		return []byte{}, fmt.Errorf("unable to marshal OID: Invalid object identifier")
474
	}
475

476
	return out.Bytes(), nil
477
}
478

479
// TODO no tests
480
func ipv4toBytes(ip net.IP) []byte {
481
	return []byte(ip)[12:]
482
}
483

484
// parseOpaque  parses a Opaque encoded data
485
// Known data-types is OpaqueDouble and OpaqueFloat
486
// Other data decoded as binary Opaque data
487
// TODO: add OpaqueCounter64 (0x76), OpaqueInteger64 (0x80), OpaqueUinteger64 (0x81)
488
func parseOpaque(logger Logger, data []byte, retVal *variable) error {
489
	if len(data) == 0 {
490
		return ErrZeroByteBuffer
491
	}
492
	if len(data) > 2 && data[0] == AsnExtensionTag {
493
		switch Asn1BER(data[1]) {
494
		case OpaqueDouble:
495
			// 0x79
496
			data = data[1:]
497
			logger.Print("decodeValue: type is OpaqueDouble")
498
			length, cursor, err := parseLength(data)
499
			if err != nil {
500
				return err
501
			}
502
			if length > len(data) {
503
				return fmt.Errorf("not enough data for OpaqueDouble %x (data %d length %d)", data, len(data), length)
504
			}
505
			retVal.Type = OpaqueDouble
506
			retVal.Value, err = parseFloat64(data[cursor:length])
507
			if err != nil {
508
				return err
509
			}
510
		case OpaqueFloat:
511
			// 0x78
512
			data = data[1:]
513
			logger.Print("decodeValue: type is OpaqueFloat")
514
			length, cursor, err := parseLength(data)
515
			if err != nil {
516
				return err
517
			}
518
			if length > len(data) {
519
				return fmt.Errorf("not enough data for OpaqueFloat %x (data %d length %d)", data, len(data), length)
520
			}
521
			if cursor > length {
522
				return fmt.Errorf("invalid cursor position for OpaqueFloat %x (data %d length %d cursor %d)", data, len(data), length, cursor)
523
			}
524
			retVal.Type = OpaqueFloat
525
			retVal.Value, err = parseFloat32(data[cursor:length])
526
			if err != nil {
527
				return err
528
			}
529
		default:
530
			logger.Print("decodeValue: type is Opaque")
531
			retVal.Type = Opaque
532
			retVal.Value = data[0:]
533
		}
534
	} else {
535
		logger.Print("decodeValue: type is Opaque")
536
		retVal.Type = Opaque
537
		retVal.Value = data[0:]
538
	}
539
	return nil
540
}
541

542
// parseBase128Int parses a base-128 encoded int from the given offset in the
543
// given byte slice. It returns the value and the new offset.
544
func parseBase128Int(bytes []byte, initOffset int) (int64, int, error) {
545
	var ret int64
546
	var offset = initOffset
547
	for shifted := 0; offset < len(bytes); shifted++ {
548
		if shifted > 4 {
549
			return 0, 0, ErrBase128IntegerTooLarge
550
		}
551
		ret <<= 7
552
		b := bytes[offset]
553
		ret |= int64(b & 0x7f)
554
		offset++
555
		if b&0x80 == 0 {
556
			return ret, offset, nil
557
		}
558
	}
559
	return 0, 0, ErrBase128IntegerTruncated
560
}
561

562
// parseInt64 treats the given bytes as a big-endian, signed integer and
563
// returns the result.
564
func parseInt64(bytes []byte) (int64, error) {
565
	switch {
566
	case len(bytes) == 0:
567
		// X.690 8.3.1: Encoding of an integer value:
568
		// The encoding of an integer value shall be primitive.
569
		// The contents octets shall consist of one or more octets.
570
		return 0, ErrZeroLenInteger
571
	case len(bytes) > 8:
572
		// We'll overflow an int64 in this case.
573
		return 0, ErrIntegerTooLarge
574
	}
575
	var ret int64
576
	for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
577
		ret <<= 8
578
		ret |= int64(bytes[bytesRead])
579
	}
580
	// Shift up and down in order to sign extend the result.
581
	ret <<= 64 - uint8(len(bytes))*8
582
	ret >>= 64 - uint8(len(bytes))*8
583
	return ret, nil
584
}
585

586
// parseInt treats the given bytes as a big-endian, signed integer and returns
587
// the result.
588
func parseInt(bytes []byte) (int, error) {
589
	ret64, err := parseInt64(bytes)
590
	if err != nil {
591
		return 0, err
592
	}
593
	if ret64 != int64(int(ret64)) {
594
		return 0, ErrIntegerTooLarge
595
	}
596
	return int(ret64), nil
597
}
598

599
// parseLength parses and calculates an snmp packet length
600
// and returns an error when invalid data is detected
601
//
602
// http://luca.ntop.org/Teaching/Appunti/asn1.html
603
//
604
// Length octets. There are two forms: short (for lengths between 0 and 127),
605
// and long definite (for lengths between 0 and 2^1008 -1).
606
//
607
//   - Short form. One octet. Bit 8 has value "0" and bits 7-1 give the length.
608
//   - Long form. Two to 127 octets. Bit 8 of first octet has value "1" and bits
609
//     7-1 give the number of additional length octets. Second and following
610
//     octets give the length, base 256, most significant digit first.
611
func parseLength(bytes []byte) (int, int, error) {
612
	var cursor, length int
613
	switch {
614
	case len(bytes) <= 2:
615
		// handle null octet strings ie "0x04 0x00"
616
		cursor = len(bytes)
617
		length = len(bytes)
618
	case int(bytes[1]) <= 127:
619
		length = int(bytes[1])
620
		length += 2
621
		cursor += 2
622
	default:
623
		numOctets := int(bytes[1]) & 127
624
		for i := 0; i < numOctets; i++ {
625
			length <<= 8
626
			if len(bytes) < 2+i+1 {
627
				// Invalid data detected, return an error
628
				return 0, 0, ErrInvalidPacketLength
629
			}
630
			length += int(bytes[2+i])
631
			if length < 0 {
632
				// Invalid length due to overflow, return an error
633
				return 0, 0, ErrInvalidPacketLength
634
			}
635
		}
636
		length += 2 + numOctets
637
		cursor += 2 + numOctets
638
	}
639
	if length < 0 {
640
		// Invalid data detected, return an error
641
		return 0, 0, ErrInvalidPacketLength
642
	}
643
	return length, cursor, nil
644
}
645

646
// parseObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and
647
// returns it. An object identifier is a sequence of variable length integers
648
// that are assigned in a hierarchy.
649
func parseObjectIdentifier(src []byte) (string, error) {
650
	if len(src) == 0 {
651
		return "", ErrInvalidOidLength
652
	}
653

654
	out := new(bytes.Buffer)
655

656
	out.WriteByte('.')
657
	out.WriteString(strconv.FormatInt(int64(int(src[0])/40), 10))
658
	out.WriteByte('.')
659
	out.WriteString(strconv.FormatInt(int64(int(src[0])%40), 10))
660

661
	var v int64
662
	var err error
663
	for offset := 1; offset < len(src); {
664
		out.WriteByte('.')
665
		v, offset, err = parseBase128Int(src, offset)
666
		if err != nil {
667
			return "", err
668
		}
669
		out.WriteString(strconv.FormatInt(v, 10))
670
	}
671
	return out.String(), nil
672
}
673

674
func parseRawField(logger Logger, data []byte, msg string) (interface{}, int, error) {
675
	if len(data) == 0 {
676
		return nil, 0, fmt.Errorf("empty data passed to parseRawField")
677
	}
678
	logger.Printf("parseRawField: %s", msg)
679
	switch Asn1BER(data[0]) {
680
	case Integer:
681
		length, cursor, err := parseLength(data)
682
		if err != nil {
683
			return nil, 0, err
684
		}
685
		if length > len(data) {
686
			return nil, 0, fmt.Errorf("not enough data for Integer (%d vs %d): %x", length, len(data), data)
687
		}
688
		if cursor > length {
689
			return nil, 0, fmt.Errorf("invalid cursor position for Integer %x (data %d length %d cursor %d)", data, len(data), length, cursor)
690
		}
691
		i, err := parseInt(data[cursor:length])
692
		if err != nil {
693
			return nil, 0, fmt.Errorf("unable to parse raw INTEGER: %x err: %w", data, err)
694
		}
695
		return i, length, nil
696
	case OctetString:
697
		length, cursor, err := parseLength(data)
698
		if err != nil {
699
			return nil, 0, err
700
		}
701
		if length > len(data) {
702
			return nil, 0, fmt.Errorf("not enough data for OctetString (%d vs %d): %x", length, len(data), data)
703
		}
704
		if cursor > length {
705
			return nil, 0, fmt.Errorf("invalid cursor position for OctetString %x (data %d length %d cursor %d)", data, len(data), length, cursor)
706
		}
707
		return string(data[cursor:length]), length, nil
708
	case ObjectIdentifier:
709
		length, cursor, err := parseLength(data)
710
		if err != nil {
711
			return nil, 0, err
712
		}
713
		if length > len(data) {
714
			return nil, 0, fmt.Errorf("not enough data for OID (%d vs %d): %x", length, len(data), data)
715
		}
716
		if cursor > length {
717
			return nil, 0, fmt.Errorf("invalid cursor position for OID %x (data %d length %d cursor %d)", data, len(data), length, cursor)
718
		}
719
		oid, err := parseObjectIdentifier(data[cursor:length])
720
		return oid, length, err
721
	case IPAddress:
722
		length, _, err := parseLength(data)
723
		if err != nil {
724
			return nil, 0, err
725
		}
726
		if len(data) < 2 {
727
			return nil, 0, fmt.Errorf("not enough data for ipv4 address: %x", data)
728
		}
729

730
		switch data[1] {
731
		case 0: // real life, buggy devices returning bad data
732
			return nil, length, nil
733
		case 4: // IPv4
734
			if len(data) < 6 {
735
				return nil, 0, fmt.Errorf("not enough data for ipv4 address: %x", data)
736
			}
737
			return net.IPv4(data[2], data[3], data[4], data[5]).String(), length, nil
738
		default:
739
			return nil, 0, fmt.Errorf("got ipaddress len %d, expected 4", data[1])
740
		}
741
	case TimeTicks:
742
		length, cursor, err := parseLength(data)
743
		if err != nil {
744
			return nil, 0, err
745
		}
746
		if length > len(data) {
747
			return nil, 0, fmt.Errorf("not enough data for TimeTicks (%d vs %d): %x", length, len(data), data)
748
		}
749
		if cursor > length {
750
			return nil, 0, fmt.Errorf("invalid cursor position for TimeTicks %x (data %d length %d cursor %d)", data, len(data), length, cursor)
751
		}
752
		ret, err := parseUint(data[cursor:length])
753
		if err != nil {
754
			return nil, 0, fmt.Errorf("error in parseUint: %w", err)
755
		}
756
		return ret, length, nil
757
	}
758

759
	return nil, 0, fmt.Errorf("unknown field type: %x", data[0])
760
}
761

762
// parseUint64 treats the given bytes as a big-endian, unsigned integer and returns
763
// the result.
764
func parseUint64(bytes []byte) (uint64, error) {
765
	var ret uint64
766
	if len(bytes) > 9 || (len(bytes) > 8 && bytes[0] != 0x0) {
767
		// We'll overflow a uint64 in this case.
768
		return 0, ErrIntegerTooLarge
769
	}
770
	for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
771
		ret <<= 8
772
		ret |= uint64(bytes[bytesRead])
773
	}
774
	return ret, nil
775
}
776

777
// parseUint32 treats the given bytes as a big-endian, signed integer and returns
778
// the result.
779
func parseUint32(bytes []byte) (uint32, error) {
780
	ret, err := parseUint(bytes)
781
	if err != nil {
782
		return 0, err
783
	}
784
	return uint32(ret), nil
785
}
786

787
// parseUint treats the given bytes as a big-endian, signed integer and returns
788
// the result.
789
func parseUint(bytes []byte) (uint, error) {
790
	ret64, err := parseUint64(bytes)
791
	if err != nil {
792
		return 0, err
793
	}
794
	if ret64 != uint64(uint(ret64)) {
795
		return 0, ErrIntegerTooLarge
796
	}
797
	return uint(ret64), nil
798
}
799

800
func parseFloat32(bytes []byte) (float32, error) {
801
	if len(bytes) > 4 {
802
		// We'll overflow a uint64 in this case.
803
		return 0, ErrFloatTooLarge
804
	}
805
	if len(bytes) < 4 {
806
		// We'll cause a panic in binary.BigEndian.Uint32() in this case
807
		return 0, ErrFloatBufferTooShort
808
	}
809
	return math.Float32frombits(binary.BigEndian.Uint32(bytes)), nil
810
}
811

812
func parseFloat64(bytes []byte) (float64, error) {
813
	if len(bytes) > 8 {
814
		// We'll overflow a uint64 in this case.
815
		return 0, ErrFloatTooLarge
816
	}
817
	if len(bytes) < 8 {
818
		// We'll cause a panic in binary.BigEndian.Uint64() in this case
819
		return 0, ErrFloatBufferTooShort
820
	}
821
	return math.Float64frombits(binary.BigEndian.Uint64(bytes)), nil
822
}
823

824
// -- Bit String ---------------------------------------------------------------
825

826
// BitStringValue is the structure to use when you want an ASN.1 BIT STRING type. A
827
// bit string is padded up to the nearest byte in memory and the number of
828
// valid bits is recorded. Padding bits will be zero.
829
type BitStringValue struct {
830
	Bytes     []byte // bits packed into bytes.
831
	BitLength int    // length in bits.
832
}
833

834
// At returns the bit at the given index. If the index is out of range it
835
// returns false.
836
func (b BitStringValue) At(i int) int {
837
	if i < 0 || i >= b.BitLength {
838
		return 0
839
	}
840
	x := i / 8
841
	y := 7 - uint(i%8)
842
	return int(b.Bytes[x]>>y) & 1
843
}
844

845
// RightAlign returns a slice where the padding bits are at the beginning. The
846
// slice may share memory with the BitString.
847
func (b BitStringValue) RightAlign() []byte {
848
	shift := uint(8 - (b.BitLength % 8))
849
	if shift == 8 || len(b.Bytes) == 0 {
850
		return b.Bytes
851
	}
852

853
	a := make([]byte, len(b.Bytes))
854
	a[0] = b.Bytes[0] >> shift
855
	for i := 1; i < len(b.Bytes); i++ {
856
		a[i] = b.Bytes[i-1] << (8 - shift)
857
		a[i] |= b.Bytes[i] >> shift
858
	}
859

860
	return a
861
}
862

863
// -- SnmpVersion --------------------------------------------------------------
864

865
func (s SnmpVersion) String() string {
866
	switch s {
867
	case Version1:
868
		return "1"
869
	case Version2c:
870
		return "2c"
871
	case Version3:
872
		return "3"
873
	default:
874
		return "3"
875
	}
876
}
877

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

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

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

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