Skip to content

Instantly share code, notes, and snippets.

@kevsersrca
Last active September 13, 2019 11:12
Show Gist options
  • Save kevsersrca/be08e046fdc87031191d1ba84ed78bfd to your computer and use it in GitHub Desktop.
Save kevsersrca/be08e046fdc87031191d1ba84ed78bfd to your computer and use it in GitHub Desktop.
Golang Snmp Trials 🐰
package main
import (
"log"
"net"
"time"
"gopkg.in/errgo.v1"
"github.com/posteo/go-agentx"
"github.com/posteo/go-agentx/pdu"
"github.com/posteo/go-agentx/value"
)
func main() {
client := &agentx.Client{
Net: "tcp",
Address: "localhost:161",
Timeout: 1 * time.Minute,
ReconnectInterval: 1 * time.Second,
}
if err := client.Open(); err != nil {
log.Fatalf(errgo.Details(err))
}
session, err := client.Session()
if err != nil {
log.Fatalf(errgo.Details(err))
}
listHandler := &agentx.ListHandler{}
item := listHandler.Add("1.3.6.1.4.1.45995.3.1")
item.Type = pdu.VariableTypeInteger
item.Value = int32(-123)
item = listHandler.Add("1.3.6.1.4.1.45995.3.2")
item.Type = pdu.VariableTypeOctetString
item.Value = "echo test"
item = listHandler.Add("1.3.6.1.4.1.45995.3.3")
item.Type = pdu.VariableTypeNull
item.Value = nil
item = listHandler.Add("1.3.6.1.4.1.45995.3.4")
item.Type = pdu.VariableTypeObjectIdentifier
item.Value = "1.3.6.1.4.1.45995.1.5"
item = listHandler.Add("1.3.6.1.4.1.45995.3.5")
item.Type = pdu.VariableTypeIPAddress
item.Value = net.IP{10, 10, 10, 10}
item = listHandler.Add("1.3.6.1.4.1.45995.3.6")
item.Type = pdu.VariableTypeCounter32
item.Value = uint32(123)
item = listHandler.Add("1.3.6.1.4.1.45995.3.7")
item.Type = pdu.VariableTypeGauge32
item.Value = uint32(123)
item = listHandler.Add("1.3.6.1.4.1.45995.3.8")
item.Type = pdu.VariableTypeTimeTicks
item.Value = 123 * time.Second
item = listHandler.Add("1.3.6.1.4.1.45995.3.9")
item.Type = pdu.VariableTypeOpaque
item.Value = []byte{1, 2, 3}
item = listHandler.Add("1.3.6.1.4.1.45995.3.10")
item.Type = pdu.VariableTypeCounter64
item.Value = uint64(12345678901234567890)
session.Handler = listHandler
if err := session.Register(127, value.MustParseOID("1.3.6.1.4.1.45995.3")); err != nil {
log.Fatalf(errgo.Details(err))
}
for {
time.Sleep(100 * time.Millisecond)
}
}
@kevsersrca
Copy link
Author

package main

import (
	"fmt"
	"log"

	g "github.com/soniah/gosnmp"
)

func main() {

	// Default is a pointer to a GoSNMP struct that contains sensible defaults
	// eg port 161, community public, etc
	g.Default.Target = "127.0.0.1"
	err := g.Default.Connect()
	if err != nil {
		log.Fatalf("Connect() err: %v", err)
	}
	defer g.Default.Conn.Close()

	oids := []string{"1.3.6.1.2.1.1.4.0", "1.3.6.1.2.1.1.7.0", ".1.3.6.1.2.1.1.3.0", ".1.3.6.1.2.1.3.2.1.10", ".1.3.6.1.2.1.3.2.1.16"}
	result, err2 := g.Default.Get(oids) // Get() accepts up to g.MAX_OIDS
	if err2 != nil {
		log.Fatalf("Get() err: %v", err2)
	}

	for i, variable := range result.Variables {
		fmt.Printf("%d: oid: %s ", i, variable.Name)

		// the Value of each variable returned by Get() implements
		// interface{}. You could do a type switch...
		switch variable.Type {
		case g.OctetString:
			fmt.Printf("string: %s\n", string(variable.Value.([]byte)))
		default:
			// ... or often you're just interested in numeric values.
			// ToBigInt() will return the Value as a BigInt, for plugging
			// into your calculations.
			fmt.Printf("number: %d\n", g.ToBigInt(variable.Value))
		}
	}
}

@kevsersrca
Copy link
Author

package main

import (
	"bytes"
	"flag"
	"fmt"
	"math/big"
	"os"
	"regexp"
	"strconv"
	"time"

	"github.com/k-sone/snmpgo"
)

var sysDescr *snmpgo.Oid = snmpgo.MustNewOid("1.3.6.1.2.1.1.1")
var ifAdminStatus *snmpgo.Oid = snmpgo.MustNewOid("1.3.6.1.2.1.2.2.1.7")
var ifName *snmpgo.Oid = snmpgo.MustNewOid("1.3.6.1.2.1.31.1.1.1.1")
var ifHCInOctets *snmpgo.Oid = snmpgo.MustNewOid("1.3.6.1.2.1.31.1.1.1.6")
var ifHCOutOctets *snmpgo.Oid = snmpgo.MustNewOid("1.3.6.1.2.1.31.1.1.1.10")

var delay time.Duration = 30 * time.Second
var iterations int = -1
var maxRepetitions int
var errMessage string
var ifRegexp *regexp.Regexp
var noHeader bool

func usage(msg string, code int) {
	errMessage = msg
	flag.Usage()
	os.Exit(code)
}

func parseArgs() (*snmpgo.SNMPArguments, []string) {
	flag.Usage = func() {
		if errMessage != "" {
			fmt.Fprintf(os.Stderr, "%s\n", errMessage)
		}
		fmt.Fprintf(os.Stderr, "Usage of %s: [OPTIONS] AGENT [DELAY [COUNT]]\n\n", os.Args[0])
		fmt.Fprintf(os.Stderr, "AGENT:\n  hostname:port or ip-address:port\n")
		fmt.Fprintf(os.Stderr, "DELAY:\n  the delay between updates in seconds (default: 10)\n")
		fmt.Fprintf(os.Stderr, "COUNT:\n  the number of updates (default: infinity)\n")
		fmt.Fprintf(os.Stderr, "OPTIONS:\n")
		flag.PrintDefaults()
	}

	protocol := flag.String("p", "udp", "Protocol (udp|udp6|tcp|tcp6)")
	timeout := flag.Uint("t", 5, "Request timeout (number of seconds)")
	retries := flag.Uint("r", 1, "Number of retries")
	version := flag.String("v", "2c", "SNMP version to use (2c|3)")
	community := flag.String("c", "", "Community")
	username := flag.String("u", "", "Security name")
	seclevel := flag.String("l", "NoAuthNoPriv", "Security level (NoAuthNoPriv|AuthNoPriv|AuthPriv)")
	authproto := flag.String("a", "", "Authentication protocol (MD5|SHA)")
	authpass := flag.String("A", "", "Authentication protocol pass phrase")
	privproto := flag.String("x", "", "Privacy protocol (DES|AES)")
	privpass := flag.String("X", "", "Privacy protocol pass phrase")
	secengine := flag.String("e", "", "Security engine ID")
	contextengine := flag.String("E", "", "Context engine ID")
	contextname := flag.String("n", "", "Context name")
	ifRegString := flag.String("ifreg", "", "Regular expression that specifies the interface")
	flag.IntVar(&maxRepetitions, "Cr", 10, "Max repetitions")
	flag.BoolVar(&noHeader, "noheader", false, "Disable header line")

	flag.Parse()

	args := &snmpgo.SNMPArguments{
		Network:          *protocol,
		Address:          flag.Arg(0),
		Timeout:          time.Duration(*timeout) * time.Second,
		Retries:          *retries,
		Community:        *community,
		UserName:         *username,
		AuthPassword:     *authpass,
		AuthProtocol:     snmpgo.AuthProtocol(*authproto),
		PrivPassword:     *privpass,
		PrivProtocol:     snmpgo.PrivProtocol(*privproto),
		SecurityEngineId: *secengine,
		ContextEngineId:  *contextengine,
		ContextName:      *contextname,
	}

	switch *version {
	case "2c":
		args.Version = snmpgo.V2c
	case "3":
		args.Version = snmpgo.V3
	default:
		usage(fmt.Sprintf("Illegal Version, value `%s`", *version), 2)
	}

	switch *seclevel {
	case "NoAuthNoPriv":
		args.SecurityLevel = snmpgo.NoAuthNoPriv
	case "AuthNoPriv":
		args.SecurityLevel = snmpgo.AuthNoPriv
	case "AuthPriv":
		args.SecurityLevel = snmpgo.AuthPriv
	default:
		usage(fmt.Sprintf("Illegal SecurityLevel, value `%s`", *seclevel), 2)
	}

	if *ifRegString != "" {
		var err error
		if ifRegexp, err = regexp.Compile(*ifRegString); err != nil {
			usage(fmt.Sprintf("Illegal Regular expression - %s", err), 2)
		}
	}

	return args, flag.Args()
}

type ifInfo struct {
	descr     string
	IfList    []int
	IfName    map[int]string
	IfIn      map[int]*big.Int
	IfOut     map[int]*big.Int
	LastIfIn  map[int]*big.Int
	LastIfOut map[int]*big.Int
	Time      time.Time
	LastTime  time.Time
}

func newIfInfo() *ifInfo {
	return &ifInfo{
		IfList:    make([]int, 0),
		IfName:    make(map[int]string),
		IfIn:      make(map[int]*big.Int),
		IfOut:     make(map[int]*big.Int),
		LastIfIn:  make(map[int]*big.Int),
		LastIfOut: make(map[int]*big.Int),
	}
}

func getIfInfo(snmp *snmpgo.SNMP) (*ifInfo, error) {
	pdu, err := snmp.GetBulkWalk(snmpgo.Oids{sysDescr, ifAdminStatus, ifName}, 1, maxRepetitions)
	if err != nil {
		return nil, err
	}

	if pdu.ErrorStatus() != snmpgo.NoError {
		return nil, fmt.Errorf(
			"failed to get system information - %s(%d)", pdu.ErrorStatus(), pdu.ErrorIndex())
	}

	info := newIfInfo()
	if descrs := pdu.VarBinds().MatchBaseOids(sysDescr); len(descrs) > 0 {
		info.descr = descrs[0].Variable.String()
	}

	ifNameDepth := len(ifName.Value)
	for _, varBind := range pdu.VarBinds().MatchBaseOids(ifName) {
		// get interface number and name
		if len(varBind.Oid.Value) != ifNameDepth+1 {
			continue
		}
		ifNum := varBind.Oid.Value[ifNameDepth]
		ifName := varBind.Variable.String()

		if ifRegexp != nil && !ifRegexp.MatchString(ifName) {
			continue
		}

		// get admin status
		oid, err := ifAdminStatus.AppendSubIds([]int{ifNum})
		if err != nil {
			return nil, err
		}

		// check admin status("1" is up)
		if adms := pdu.VarBinds().MatchOid(oid); adms == nil || adms.Variable.String() != "1" {
			continue
		}

		info.IfList = append(info.IfList, ifNum)
		info.IfName[ifNum] = ifName
		info.IfIn[ifNum] = nil
		info.IfOut[ifNum] = nil
		info.LastIfIn[ifNum] = nil
		info.LastIfOut[ifNum] = nil
	}

	if len(info.IfList) == 0 {
		return nil, fmt.Errorf("no interface")
	}

	return info, nil
}

func getIfTraffic(snmp *snmpgo.SNMP, info *ifInfo) error {
	pdu, err := snmp.GetBulkWalk(snmpgo.Oids{ifHCInOctets, ifHCOutOctets}, 0, maxRepetitions)
	if err != nil {
		return err
	}

	if pdu.ErrorStatus() != snmpgo.NoError {
		return fmt.Errorf(
			"failed to get network traffic - %s(%d)", pdu.ErrorStatus(), pdu.ErrorIndex())
	}

	for _, ifNum := range info.IfList {
		oid, err := ifHCInOctets.AppendSubIds([]int{ifNum})
		if err != nil {
			return err
		}
		if in := pdu.VarBinds().MatchOid(oid); in != nil {
			count, err := in.Variable.BigInt()
			if err != nil {
				return err
			}
			info.LastIfIn[ifNum], info.IfIn[ifNum] = info.IfIn[ifNum], count
		} else {
			info.LastIfIn[ifNum], info.IfIn[ifNum] = info.IfIn[ifNum], nil
		}

		oid, err = ifHCOutOctets.AppendSubIds([]int{ifNum})
		if err != nil {
			return err
		}
		if out := pdu.VarBinds().MatchOid(oid); out != nil {
			count, err := out.Variable.BigInt()
			if err != nil {
				return err
			}
			info.LastIfOut[ifNum], info.IfOut[ifNum] = info.IfOut[ifNum], count
		} else {
			info.LastIfOut[ifNum], info.IfOut[ifNum] = info.IfOut[ifNum], nil
		}
	}

	info.LastTime, info.Time = info.Time, time.Now()
	return nil
}

func printHeader(info *ifInfo) {
	var buf bytes.Buffer

	if info.descr != "" {
		buf.WriteString(info.descr)
		buf.WriteString("\n")
	}
	for _, ifNum := range info.IfList {
		buf.WriteString(fmt.Sprintf("%-23s ", info.IfName[ifNum]))
	}
	buf.WriteString("\n")
	for _ = range info.IfList {
		buf.WriteString("in          out         ")
	}
	fmt.Println(buf.String())
}

func printTraffic(info *ifInfo) {
	// TODO wrap around support
	var buf bytes.Buffer
	for _, ifNum := range info.IfList {
		var in, out big.Int
		if info.IfIn[ifNum] != nil && info.LastIfIn[ifNum] != nil {
			in.Sub(info.IfIn[ifNum], info.LastIfIn[ifNum])
			buf.WriteString(fmt.Sprintf("%-11d ", in.Uint64()))
		} else {
			buf.WriteString("-           ")
		}
		if info.IfOut[ifNum] != nil && info.LastIfOut[ifNum] != nil {
			out.Sub(info.IfOut[ifNum], info.LastIfOut[ifNum])
			buf.WriteString(fmt.Sprintf("%-11d ", out.Uint64()))
		} else {
			buf.WriteString("-           ")
		}
	}
	fmt.Println(buf.String())
}

func main() {
	snmpArgs, cmdArgs := parseArgs()
	if l := len(cmdArgs); l < 1 {
		usage("required AGENT", 2)
	} else {
		if l > 1 {
			if num, err := strconv.Atoi(cmdArgs[1]); err != nil || num < 1 {
				usage(fmt.Sprintf("Illegal delay, value `%s`", cmdArgs[1]), 2)
			} else {
				delay = time.Duration(num) * time.Second
			}
		}
		if l > 2 {
			if num, err := strconv.Atoi(cmdArgs[2]); err != nil || num < 1 {
				usage(fmt.Sprintf("Illegal iterations, value `%s`", cmdArgs[2]), 2)
			} else {
				iterations = num
			}
		}
	}

	snmp, err := snmpgo.NewSNMP(*snmpArgs)
	if err != nil {
		usage(err.Error(), 2)
	}

	if err = snmp.Open(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
	defer snmp.Close()

	info, err := getIfInfo(snmp)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	if !noHeader {
		printHeader(info)
	}

	start := time.Now()
	for i := 0; ; i++ {
		if err := getIfTraffic(snmp, info); err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}

		printTraffic(info)

		if iterations > 0 && i >= iterations {
			break
		}

		start = start.Add(delay)
		if d := start.Sub(info.Time); d > 0 {
			time.Sleep(d)
		}
	}
}

@kevsersrca
Copy link
Author

package main

import (
	"fmt"
	"log"
	"os"
	"sync"
	"time"

	"github.com/soniah/gosnmp"
)

var wg sync.WaitGroup

const (
	devClientCount string = ".1.3.6.1.4.1.29671.1.1.4.1.5"
	devName               = ".1.3.6.1.4.1.29671.1.1.4.1.2"
)

func main() {
	client := &gosnmp.GoSNMP{
		Target:    "159.253.41.211",
		Port:     161,
		Community: "public",
		Version:   gosnmp.Version2c,
		Timeout:   time.Duration(2) * time.Second,
	}
	err := client.Connect()
	if err != nil {
		log.Fatalf("Connect() err: %v", err)
	}
	fmt.Println("connected")
	defer client.Conn.Close()
	wg.Add(1)
	go walk(devClientCount, client)

	wg.Add(1)
	go walk(devClientCount, client)

	wg.Wait()
}

func walk(oid string, client *gosnmp.GoSNMP) {
	defer wg.Done()
	err := client.BulkWalk(oid, printValue)
	if err != nil {
		fmt.Printf("Walk Error: %v\n", err)
		os.Exit(1)
	}
}

func printValue(pdu gosnmp.SnmpPDU) error {
	fmt.Printf("%s = ", pdu.Name)

	switch pdu.Type {
	case gosnmp.OctetString:
		b := pdu.Value.([]byte)
		fmt.Println("STRING: %s\n", string(b))
	default:
		fmt.Println("INTEGER %d: %d\n", pdu.Type, gosnmp.ToBigInt(pdu.Value))
	}
	return nil
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment