gosnmp
/
gosnmp.go
695 строк · 22.2 Кб
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
9package gosnmp
10
11import (
12"context"
13"crypto/rand"
14"fmt"
15"math"
16"math/big"
17"net"
18"strconv"
19"sync/atomic"
20"syscall"
21"time"
22)
23
24const (
25// MaxOids is the maximum number of OIDs permitted in a single call,
26// otherwise error. MaxOids too high can cause remote devices to fail
27// strangely. 60 seems to be a common value that works, but you will want
28// to change this in the GoSNMP struct
29MaxOids = 60
30
31// Base OID for MIB-2 defined SNMP variables
32baseOid = ".1.3.6.1.2.1"
33
34// Max oid sub-identifier value
35// https://tools.ietf.org/html/rfc2578#section-7.1.3
36MaxObjectSubIdentifierValue = 4294967295
37
38// Java SNMP uses 50, snmp-net uses 10
39defaultMaxRepetitions = 50
40
41// "udp" and "tcp" are used regularly, prevent 'goconst' complaints
42udp = "udp"
43tcp = "tcp"
44)
45
46// GoSNMP represents GoSNMP library state.
47type GoSNMP struct {
48// Conn is net connection to use, typically established using GoSNMP.Connect().
49Conn net.Conn
50
51// Target is an ipv4 address.
52Target string
53
54// Port is a port.
55Port uint16
56
57// Transport is the transport protocol to use ("udp" or "tcp"); if unset "udp" will be used.
58Transport string
59
60// Community is an SNMP Community string.
61Community string
62
63// Version is an SNMP Version.
64Version SnmpVersion
65
66// Context allows for overall deadlines and cancellation.
67Context context.Context
68
69// Timeout is the timeout for one SNMP request/response.
70Timeout time.Duration
71
72// Set the number of retries to attempt.
73Retries int
74
75// Double timeout in each retry.
76ExponentialTimeout bool
77
78// Logger is the GoSNMP.Logger to use for debugging.
79// For verbose logging to stdout:
80// x.Logger = NewLogger(log.New(os.Stdout, "", 0))
81// For Release builds, you can turn off logging entirely by using the go build tag "gosnmp_nodebug" even if the logger was installed.
82Logger Logger
83
84// Message hook methods allow passing in a functions at various points in the packet handling.
85// For example, this can be used to collect packet timing, add metrics, or implement tracing.
86/*
87
88*/
89// PreSend is called before a packet is sent.
90PreSend func(*GoSNMP)
91
92// OnSent is called when a packet is sent.
93OnSent func(*GoSNMP)
94
95// OnRecv is called when a packet is received.
96OnRecv func(*GoSNMP)
97
98// OnRetry is called when a retry attempt is done.
99OnRetry func(*GoSNMP)
100
101// OnFinish is called when the request completed.
102OnFinish func(*GoSNMP)
103
104// MaxOids is the maximum number of oids allowed in a Get().
105// (default: MaxOids)
106MaxOids int
107
108// MaxRepetitions sets the GETBULK max-repetitions used by BulkWalk*
109// Unless MaxRepetitions is specified it will use defaultMaxRepetitions (50)
110// This may cause issues with some devices, if so set MaxRepetitions lower.
111// See comments in https://github.com/gosnmp/gosnmp/issues/100
112MaxRepetitions uint32
113
114// NonRepeaters sets the GETBULK max-repeaters used by BulkWalk*.
115// (default: 0 as per RFC 1905)
116NonRepeaters int
117
118// UseUnconnectedUDPSocket if set, changes net.Conn to be unconnected UDP socket.
119// Some multi-homed network gear isn't smart enough to send SNMP responses
120// from the address it received the requests on. To work around that,
121// we open unconnected UDP socket and use sendto/recvfrom.
122UseUnconnectedUDPSocket bool
123
124// If Control is not nil, it is called after creating the network
125// connection but before actually dialing.
126//
127// Can be used when UseUnconnectedUDPSocket is set to false or when using TCP
128// in scenario where specific options on the underlying socket are nedded.
129// Refer to https://pkg.go.dev/net#Dialer
130Control func(network, address string, c syscall.RawConn) error
131
132// LocalAddr is the local address in the format "address:port" to use when connecting an Target address.
133// If the port parameter is empty or "0", as in
134// "127.0.0.1:" or "[::1]:0", a port number is automatically (random) chosen.
135LocalAddr string
136
137// netsnmp has '-C APPOPTS - set various application specific behaviours'
138//
139// - 'c: do not check returned OIDs are increasing' - use AppOpts = map[string]interface{"c":true} with
140// Walk() or BulkWalk(). The library user needs to implement their own policy for terminating walks.
141// - 'p,i,I,t,E' -> pull requests welcome
142AppOpts map[string]interface{}
143
144// Internal - used to sync requests to responses.
145requestID uint32
146random uint32
147
148rxBuf *[rxBufSize]byte // has to be pointer due to https://github.com/golang/go/issues/11728
149
150// MsgFlags is an SNMPV3 MsgFlags.
151MsgFlags SnmpV3MsgFlags
152
153// SecurityModel is an SNMPV3 Security Model.
154SecurityModel SnmpV3SecurityModel
155
156// SecurityParameters is an SNMPV3 Security Model parameters struct.
157SecurityParameters SnmpV3SecurityParameters
158
159// TrapSecurityParametersTable is a mapping of identifiers to corresponding SNMP V3 Security Model parameters
160// right now only supported for receiving traps, variable name to make that clear
161TrapSecurityParametersTable *SnmpV3SecurityParametersTable
162
163// ContextEngineID is SNMPV3 ContextEngineID in ScopedPDU.
164ContextEngineID string
165
166// ContextName is SNMPV3 ContextName in ScopedPDU
167ContextName string
168
169// Internal - used to sync requests to responses - snmpv3.
170msgID uint32
171
172// Internal - we use to send packets if using unconnected socket.
173uaddr *net.UDPAddr
174}
175
176// Default connection settings
177//
178//nolint:gochecknoglobals
179var Default = &GoSNMP{
180Port: 161,
181Transport: udp,
182Community: "public",
183Version: Version2c,
184Timeout: time.Duration(2) * time.Second,
185Retries: 3,
186ExponentialTimeout: true,
187MaxOids: MaxOids,
188}
189
190// SnmpPDU will be used when doing SNMP Set's
191type SnmpPDU struct {
192// The value to be set by the SNMP set, or the value when
193// sending a trap
194Value interface{}
195
196// Name is an oid in string format eg ".1.3.6.1.4.9.27"
197Name string
198
199// The type of the value eg Integer
200Type Asn1BER
201}
202
203const AsnContext = 0x80
204const AsnExtensionID = 0x1F
205const AsnExtensionTag = (AsnContext | AsnExtensionID) // 0x9F
206
207//go:generate stringer -type Asn1BER
208
209// Asn1BER is the type of the SNMP PDU
210type Asn1BER byte
211
212// Asn1BER's - http://www.ietf.org/rfc/rfc1442.txt
213const (
214EndOfContents Asn1BER = 0x00
215UnknownType Asn1BER = 0x00
216Boolean Asn1BER = 0x01
217Integer Asn1BER = 0x02
218BitString Asn1BER = 0x03
219OctetString Asn1BER = 0x04
220Null Asn1BER = 0x05
221ObjectIdentifier Asn1BER = 0x06
222ObjectDescription Asn1BER = 0x07
223IPAddress Asn1BER = 0x40
224Counter32 Asn1BER = 0x41
225Gauge32 Asn1BER = 0x42
226TimeTicks Asn1BER = 0x43
227Opaque Asn1BER = 0x44
228NsapAddress Asn1BER = 0x45
229Counter64 Asn1BER = 0x46
230Uinteger32 Asn1BER = 0x47
231OpaqueFloat Asn1BER = 0x78
232OpaqueDouble Asn1BER = 0x79
233NoSuchObject Asn1BER = 0x80
234NoSuchInstance Asn1BER = 0x81
235EndOfMibView Asn1BER = 0x82
236)
237
238//go:generate stringer -type SNMPError
239
240// SNMPError is the type for standard SNMP errors.
241type SNMPError uint8
242
243// SNMP Errors
244const (
245NoError SNMPError = iota // No error occurred. This code is also used in all request PDUs, since they have no error status to report.
246TooBig // The size of the Response-PDU would be too large to transport.
247NoSuchName // The name of a requested object was not found.
248BadValue // A value in the request didn't match the structure that the recipient of the request had for the object. For example, an object in the request was specified with an incorrect length or type.
249ReadOnly // An attempt was made to set a variable that has an Access value indicating that it is read-only.
250GenErr // An error occurred other than one indicated by a more specific error code in this table.
251NoAccess // Access was denied to the object for security reasons.
252WrongType // The object type in a variable binding is incorrect for the object.
253WrongLength // A variable binding specifies a length incorrect for the object.
254WrongEncoding // A variable binding specifies an encoding incorrect for the object.
255WrongValue // The value given in a variable binding is not possible for the object.
256NoCreation // A specified variable does not exist and cannot be created.
257InconsistentValue // A variable binding specifies a value that could be held by the variable but cannot be assigned to it at this time.
258ResourceUnavailable // An attempt to set a variable required a resource that is not available.
259CommitFailed // An attempt to set a particular variable failed.
260UndoFailed // An attempt to set a particular variable as part of a group of variables failed, and the attempt to then undo the setting of other variables was not successful.
261AuthorizationError // A problem occurred in authorization.
262NotWritable // The variable cannot be written or created.
263InconsistentName // The name in a variable binding specifies a variable that does not exist.
264)
265
266//
267// Public Functions (main interface)
268//
269
270// Connect creates and opens a socket. Because UDP is a connectionless
271// protocol, you won't know if the remote host is responding until you send
272// packets. Neither will you know if the host is regularly disappearing and reappearing.
273//
274// For historical reasons (ie this is part of the public API), the method won't
275// be renamed to Dial().
276func (x *GoSNMP) Connect() error {
277return x.connect("")
278}
279
280// ConnectIPv4 forces an IPv4-only connection
281func (x *GoSNMP) ConnectIPv4() error {
282return x.connect("4")
283}
284
285// ConnectIPv6 forces an IPv6-only connection
286func (x *GoSNMP) ConnectIPv6() error {
287return x.connect("6")
288}
289
290// connect to address addr on the given network
291//
292// https://golang.org/pkg/net/#Dial gives acceptable network values as:
293//
294// "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), "udp", "udp4" (IPv4-only),"udp6" (IPv6-only), "ip",
295// "ip4" (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and "unixpacket"
296func (x *GoSNMP) connect(networkSuffix string) error {
297err := x.validateParameters()
298if err != nil {
299return err
300}
301
302x.Transport += networkSuffix
303if err = x.netConnect(); err != nil {
304return fmt.Errorf("error establishing connection to host: %w", err)
305}
306
307if x.random == 0 {
308n, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt32)) // returns a uniform random value in [0, 2147483647].
309if err != nil {
310return fmt.Errorf("error occurred while generating random: %w", err)
311}
312x.random = uint32(n.Uint64())
313}
314// http://tools.ietf.org/html/rfc3412#section-6 - msgID only uses the first 31 bits
315// msgID INTEGER (0..2147483647)
316x.msgID = x.random
317
318// RequestID is Integer32 from SNMPV2-SMI and uses all 32 bits
319x.requestID = x.random
320
321x.rxBuf = new([rxBufSize]byte)
322
323return nil
324}
325
326// Performs the real socket opening network operation. This can be used to do a
327// reconnect (needed for TCP)
328func (x *GoSNMP) netConnect() error {
329var err error
330var localAddr net.Addr
331addr := net.JoinHostPort(x.Target, strconv.Itoa(int(x.Port)))
332
333switch x.Transport {
334case "udp", "udp4", "udp6":
335if localAddr, err = net.ResolveUDPAddr(x.Transport, x.LocalAddr); err != nil {
336return err
337}
338if addr4 := localAddr.(*net.UDPAddr).IP.To4(); addr4 != nil {
339x.Transport = "udp4"
340}
341if x.UseUnconnectedUDPSocket {
342x.uaddr, err = net.ResolveUDPAddr(x.Transport, addr)
343if err != nil {
344return err
345}
346x.Conn, err = net.ListenUDP(x.Transport, localAddr.(*net.UDPAddr))
347return err
348}
349case "tcp", "tcp4", "tcp6":
350if localAddr, err = net.ResolveTCPAddr(x.Transport, x.LocalAddr); err != nil {
351return err
352}
353if addr4 := localAddr.(*net.TCPAddr).IP.To4(); addr4 != nil {
354x.Transport = "tcp4"
355}
356}
357dialer := net.Dialer{Timeout: x.Timeout, LocalAddr: localAddr, Control: x.Control}
358x.Conn, err = dialer.DialContext(x.Context, x.Transport, addr)
359return err
360}
361
362func (x *GoSNMP) validateParameters() error {
363if x.Transport == "" {
364x.Transport = udp
365}
366
367if x.MaxOids == 0 {
368x.MaxOids = MaxOids
369} else if x.MaxOids < 0 {
370return fmt.Errorf("field MaxOids cannot be less than 0")
371}
372
373if x.Version == Version3 {
374// TODO: setting the Reportable flag violates rfc3412#6.4 if PDU is of type SNMPv2Trap.
375// See if we can do this smarter and remove bitclear fix from trap.go:57
376x.MsgFlags |= Reportable // tell the snmp server that a report PDU MUST be sent
377
378err := x.validateParametersV3()
379if err != nil {
380return err
381}
382err = x.SecurityParameters.init(x.Logger)
383if err != nil {
384return err
385}
386}
387
388if x.Context == nil {
389x.Context = context.Background()
390}
391return nil
392}
393
394func (x *GoSNMP) MkSnmpPacket(pdutype PDUType, pdus []SnmpPDU, nonRepeaters uint8, maxRepetitions uint32) *SnmpPacket {
395return x.mkSnmpPacket(pdutype, pdus, nonRepeaters, maxRepetitions)
396}
397
398func (x *GoSNMP) mkSnmpPacket(pdutype PDUType, pdus []SnmpPDU, nonRepeaters uint8, maxRepetitions uint32) *SnmpPacket {
399var newSecParams SnmpV3SecurityParameters
400if x.SecurityParameters != nil {
401newSecParams = x.SecurityParameters.Copy()
402}
403return &SnmpPacket{
404Version: x.Version,
405Community: x.Community,
406MsgFlags: x.MsgFlags,
407SecurityModel: x.SecurityModel,
408SecurityParameters: newSecParams,
409ContextEngineID: x.ContextEngineID,
410ContextName: x.ContextName,
411Error: 0,
412ErrorIndex: 0,
413PDUType: pdutype,
414NonRepeaters: nonRepeaters,
415MaxRepetitions: (maxRepetitions & 0x7FFFFFFF),
416Variables: pdus,
417}
418}
419
420// Get sends an SNMP GET request
421func (x *GoSNMP) Get(oids []string) (result *SnmpPacket, err error) {
422oidCount := len(oids)
423if oidCount > x.MaxOids {
424return nil, fmt.Errorf("oid count (%d) is greater than MaxOids (%d)",
425oidCount, x.MaxOids)
426}
427// convert oids slice to pdu slice
428pdus := make([]SnmpPDU, 0, oidCount)
429for _, oid := range oids {
430pdus = append(pdus, SnmpPDU{Name: oid, Type: Null, Value: nil})
431}
432// build up SnmpPacket
433packetOut := x.mkSnmpPacket(GetRequest, pdus, 0, 0)
434return x.send(packetOut, true)
435}
436
437// Set sends an SNMP SET request
438func (x *GoSNMP) Set(pdus []SnmpPDU) (result *SnmpPacket, err error) {
439var packetOut *SnmpPacket
440switch pdus[0].Type {
441// TODO test Gauge32
442case Integer, OctetString, Gauge32, IPAddress, ObjectIdentifier, Counter32, Counter64, Null, TimeTicks, Uinteger32, OpaqueFloat, OpaqueDouble:
443packetOut = x.mkSnmpPacket(SetRequest, pdus, 0, 0)
444default:
445return nil, fmt.Errorf("ERR:gosnmp currently only supports SNMP SETs for Integer, OctetString, Gauge32, IPAddress, ObjectIdentifier, Counter32, Counter64, Null, TimeTicks, Uinteger32, OpaqueFloat, and OpaqueDouble. Not %s", pdus[0].Type)
446}
447return x.send(packetOut, true)
448}
449
450// GetNext sends an SNMP GETNEXT request
451func (x *GoSNMP) GetNext(oids []string) (result *SnmpPacket, err error) {
452oidCount := len(oids)
453if oidCount > x.MaxOids {
454return nil, fmt.Errorf("oid count (%d) is greater than MaxOids (%d)",
455oidCount, x.MaxOids)
456}
457
458// convert oids slice to pdu slice
459pdus := make([]SnmpPDU, 0, oidCount)
460for _, oid := range oids {
461pdus = append(pdus, SnmpPDU{Name: oid, Type: Null, Value: nil})
462}
463
464// Marshal and send the packet
465packetOut := x.mkSnmpPacket(GetNextRequest, pdus, 0, 0)
466
467return x.send(packetOut, true)
468}
469
470// GetBulk sends an SNMP GETBULK request
471//
472// For maxRepetitions greater than 255, use BulkWalk() or BulkWalkAll()
473func (x *GoSNMP) GetBulk(oids []string, nonRepeaters uint8, maxRepetitions uint32) (result *SnmpPacket, err error) {
474if x.Version == Version1 {
475return nil, fmt.Errorf("GETBULK not supported in SNMPv1")
476}
477oidCount := len(oids)
478if oidCount > x.MaxOids {
479return nil, fmt.Errorf("oid count (%d) is greater than MaxOids (%d)",
480oidCount, x.MaxOids)
481}
482
483// convert oids slice to pdu slice
484pdus := make([]SnmpPDU, 0, oidCount)
485for _, oid := range oids {
486pdus = append(pdus, SnmpPDU{Name: oid, Type: Null, Value: nil})
487}
488
489// Marshal and send the packet
490packetOut := x.mkSnmpPacket(GetBulkRequest, pdus, nonRepeaters, maxRepetitions)
491return x.send(packetOut, true)
492}
493
494// SnmpEncodePacket exposes SNMP packet generation to external callers.
495// This is useful for generating traffic for use over separate transport
496// stacks and creating traffic samples for test purposes.
497func (x *GoSNMP) SnmpEncodePacket(pdutype PDUType, pdus []SnmpPDU, nonRepeaters uint8, maxRepetitions uint32) ([]byte, error) {
498err := x.validateParameters()
499if err != nil {
500return []byte{}, err
501}
502
503pkt := x.mkSnmpPacket(pdutype, pdus, nonRepeaters, maxRepetitions)
504
505// Request ID is an atomic counter that wraps to 0 at max int32.
506reqID := (atomic.AddUint32(&(x.requestID), 1) & 0x7FFFFFFF)
507
508pkt.RequestID = reqID
509
510if x.Version == Version3 {
511msgID := (atomic.AddUint32(&(x.msgID), 1) & 0x7FFFFFFF)
512
513pkt.MsgID = msgID
514
515err = x.initPacket(pkt)
516if err != nil {
517return []byte{}, err
518}
519}
520
521var out []byte
522out, err = pkt.marshalMsg()
523if err != nil {
524return []byte{}, err
525}
526
527return out, nil
528}
529
530// SnmpDecodePacket exposes SNMP packet parsing to external callers.
531// This is useful for processing traffic from other sources and
532// building test harnesses.
533func (x *GoSNMP) SnmpDecodePacket(resp []byte) (*SnmpPacket, error) {
534var err error
535
536result := &SnmpPacket{}
537
538err = x.validateParameters()
539if err != nil {
540return result, err
541}
542
543result.Logger = x.Logger
544if x.SecurityParameters != nil {
545result.SecurityParameters = x.SecurityParameters.Copy()
546}
547
548var cursor int
549cursor, err = x.unmarshalHeader(resp, result)
550if err != nil {
551err = fmt.Errorf("unable to decode packet header: %w", err)
552return result, err
553}
554
555if result.Version == Version3 {
556resp, cursor, err = x.decryptPacket(resp, cursor, result)
557if err != nil {
558return result, err
559}
560}
561
562err = x.unmarshalPayload(resp, cursor, result)
563if err != nil {
564err = fmt.Errorf("unable to decode packet body: %w", err)
565return result, err
566}
567
568return result, nil
569}
570
571// SetRequestID sets the base ID value for future requests
572func (x *GoSNMP) SetRequestID(reqID uint32) {
573x.requestID = reqID & 0x7fffffff
574}
575
576// SetMsgID sets the base ID value for future messages
577func (x *GoSNMP) SetMsgID(msgID uint32) {
578x.msgID = msgID & 0x7fffffff
579}
580
581//
582// SNMP Walk functions - Analogous to net-snmp's snmpwalk commands
583//
584
585// WalkFunc is the type of the function called for each data unit visited
586// by the Walk function. If an error is returned processing stops.
587type WalkFunc func(dataUnit SnmpPDU) error
588
589// BulkWalk retrieves a subtree of values using GETBULK. As the tree is
590// walked walkFn is called for each new value. The function immediately returns
591// an error if either there is an underlaying SNMP error (e.g. GetBulk fails),
592// or if walkFn returns an error.
593func (x *GoSNMP) BulkWalk(rootOid string, walkFn WalkFunc) error {
594return x.walk(GetBulkRequest, rootOid, walkFn)
595}
596
597// BulkWalkAll is similar to BulkWalk but returns a filled array of all values
598// rather than using a callback function to stream results. Caution: if you
599// have set x.AppOpts to 'c', BulkWalkAll may loop indefinitely and cause an
600// Out Of Memory - use BulkWalk instead.
601func (x *GoSNMP) BulkWalkAll(rootOid string) (results []SnmpPDU, err error) {
602return x.walkAll(GetBulkRequest, rootOid)
603}
604
605// Walk retrieves a subtree of values using GETNEXT - a request is made for each
606// value, unlike BulkWalk which does this operation in batches. As the tree is
607// walked walkFn is called for each new value. The function immediately returns
608// an error if either there is an underlaying SNMP error (e.g. GetNext fails),
609// or if walkFn returns an error.
610func (x *GoSNMP) Walk(rootOid string, walkFn WalkFunc) error {
611return x.walk(GetNextRequest, rootOid, walkFn)
612}
613
614// WalkAll is similar to Walk but returns a filled array of all values rather
615// than using a callback function to stream results. Caution: if you have set
616// x.AppOpts to 'c', WalkAll may loop indefinitely and cause an Out Of Memory -
617// use Walk instead.
618func (x *GoSNMP) WalkAll(rootOid string) (results []SnmpPDU, err error) {
619return x.walkAll(GetNextRequest, rootOid)
620}
621
622//
623// Public Functions (helpers) - in alphabetical order
624//
625
626// Partition - returns true when dividing a slice into
627// partitionSize lengths, including last partition which may be smaller
628// than partitionSize. This is useful when you have a large array of OIDs
629// to run Get() on. See the tests for example usage.
630//
631// For example for a slice of 8 items to be broken into partitions of
632// length 3, Partition returns true for the currentPosition having
633// the following values:
634//
635// 0 1 2 3 4 5 6 7
636//
637// T T T
638func Partition(currentPosition, partitionSize, sliceLength int) bool {
639if currentPosition < 0 || currentPosition >= sliceLength {
640return false
641}
642if partitionSize == 1 { // redundant, but an obvious optimisation
643return true
644}
645if currentPosition%partitionSize == partitionSize-1 {
646return true
647}
648if currentPosition == sliceLength-1 {
649return true
650}
651return false
652}
653
654// ToBigInt converts SnmpPDU.Value to big.Int, or returns a zero big.Int for
655// non int-like types (eg strings).
656//
657// This is a convenience function to make working with SnmpPDU's easier - it
658// reduces the need for type assertions. A big.Int is convenient, as SNMP can
659// return int32, uint32, and uint64.
660func ToBigInt(value interface{}) *big.Int {
661var val int64
662
663switch value := value.(type) { // shadow
664case int:
665val = int64(value)
666case int8:
667val = int64(value)
668case int16:
669val = int64(value)
670case int32:
671val = int64(value)
672case int64:
673val = value
674case uint:
675val = int64(value)
676case uint8:
677val = int64(value)
678case uint16:
679val = int64(value)
680case uint32:
681val = int64(value)
682case uint64: // beware: int64(MaxUint64) overflow, handle different
683return new(big.Int).SetUint64(value)
684case string:
685// for testing and other apps - numbers may appear as strings
686var err error
687if val, err = strconv.ParseInt(value, 10, 64); err != nil {
688val = 0
689}
690default:
691val = 0
692}
693
694return big.NewInt(val)
695}
696