package snmp import ( "flag" "fmt" "log" "net" "os" "path/filepath" "strings" "time" g "github.com/gosnmp/gosnmp" "github.com/slayercat/GoSNMPServer" "github.com/slayercat/GoSNMPServer/mibImps" ) type SNMPService struct { ListenAddr string ListenPort uint16 UserName string AuthPass string AuthProto string PrivPass string PrivProto string EngineID string TrapPort uint16 TrapListen bool TrapBool bool TrapTick uint16 TimeOut uint16 TrapTarget string ListenHost string TrapHost string SysDescr string SysService int } func (s *SNMPService) getAuthProto() g.SnmpV3AuthProtocol { switch s.AuthProto { case "NoAuth": return g.NoAuth case "MD5": return g.MD5 case "SHA": return g.SHA default: } return g.MD5 } func (s *SNMPService) getPrivProto() g.SnmpV3PrivProtocol { switch s.PrivProto { case "NoPriv": return g.NoPriv case "DES": return g.DES case "AES": return g.AES case "AES192": return g.AES192 case "AES256": return g.AES256 default: } return g.DES } func (s *SNMPService) setSecParamsList() []g.UsmSecurityParameters { var secParamsList = []g.UsmSecurityParameters{ { UserName: s.UserName, AuthenticationProtocol: s.getAuthProto(), AuthenticationPassphrase: s.AuthPass, PrivacyProtocol: s.getPrivProto(), PrivacyPassphrase: s.PrivPass, AuthoritativeEngineID: s.EngineID, }, // { // UserName: "myuser2", // AuthenticationProtocol: g.SHA, // AuthenticationPassphrase: "mypassword2", // PrivacyProtocol: g.DES, // PrivacyPassphrase: "myprivacy2", // AuthoritativeEngineID: s.EngineID, // }, // { // UserName: "myuser2", // AuthenticationProtocol: g.MD5, // AuthenticationPassphrase: "mypassword2", // PrivacyProtocol: g.AES, // PrivacyPassphrase: "myprivacy2", // AuthoritativeEngineID: s.EngineID, // }, } return secParamsList } func (s *SNMPService) StartSNMPServer() { // 设置引擎启动次数和引varvar var engineBoots uint32 = 1 //var engineTime uint32 = uint32(time.Now().Unix() % 2147483647) // 使用当前时间初始化 //var engineTime uint32 = 3600 // 使用当前时间初始化 master := GoSNMPServer.MasterAgent{ Logger: GoSNMPServer.NewDefaultLogger(), SecurityConfig: GoSNMPServer.SecurityConfig{ NoSecurity: true, AuthoritativeEngineBoots: engineBoots, // OnGetAuthoritativeEngineTime: func() uint32 { // return engineTime // }, //AuthoritativeEngineID: GoSNMPServer.SNMPEngineID{EngineIDData: "0x800007DB03360102101100"}, Users: s.setSecParamsList(), }, SubAgents: []*GoSNMPServer.SubAgent{ { UserErrorMarkPacket: false, CommunityIDs: []string{"public", "private"}, // SNMPv1 and SNMPv2c community strings OIDs: s.handleOIDs(), //OIDs: mibImps.All(), }, }, } server := GoSNMPServer.NewSNMPServer(master) err := server.ListenUDP("udp", s.ListenHost) if err != nil { log.Fatalf("Error in listen: %+v", err) } server.ServeForever() } func (s *SNMPService) handleOIDs() []*GoSNMPServer.PDUValueControlItem { customOIDs := []*GoSNMPServer.PDUValueControlItem{ { OID: "1.3.6.1.2.1.1.1.0", Type: g.OctetString, OnGet: func() (value interface{}, err error) { return s.SysDescr, nil }, OnSet: func(value interface{}) error { // 将[]uint8转换为string if v, ok := value.([]uint8); ok { s.SysDescr = string(v) log.Printf("Set request for OID 1.3.6.1.2.1.1.1.0 with value %v", s.SysDescr) return nil } return nil }, }, { OID: "1.3.6.1.2.1.1.3.0", Type: g.TimeTicks, OnGet: func() (value interface{}, err error) { return uint32(time.Now().Unix()), nil }, }, { OID: "1.3.6.1.2.1.1.7.0", Type: g.Integer, OnGet: func() (value interface{}, err error) { return s.SysService, nil }, OnSet: func(value interface{}) error { // 将[]uint8转换为string if v, ok := value.(int); ok { s.SysService = v log.Printf("Set request for OID 1.3.6.1.2.1.1.7.0 with value %v", s.SysService) return nil } return nil }, }, } // 获取mibImps.All()返回的OID列表 mibOIDs := mibImps.All() // 使用Map来检测并移除重复的OID oidMap := make(map[string]*GoSNMPServer.PDUValueControlItem) for _, oid := range customOIDs { oidMap[oid.OID] = oid } for _, oid := range mibOIDs { if _, exists := oidMap[oid.OID]; !exists { oidMap[oid.OID] = oid } else { log.Printf("Duplicate OID found: %s", oid.OID) } } // 将Map转换为Slice allOIDs := make([]*GoSNMPServer.PDUValueControlItem, 0, len(oidMap)) for _, oid := range oidMap { allOIDs = append(allOIDs, oid) } return allOIDs } func (s *SNMPService) StartTrapServer() { flag.Usage = func() { fmt.Printf("Usage:\n") fmt.Printf(" %s\n", filepath.Base(os.Args[0])) flag.PrintDefaults() } tl := g.NewTrapListener() tl.OnNewTrap = s.MyTrapHandler usmTable := g.NewSnmpV3SecurityParametersTable(g.NewLogger(log.New(os.Stdout, "", 0))) for i := range s.setSecParamsList() { sp := &s.setSecParamsList()[i] // 使用指针 err := usmTable.Add(sp.UserName, sp) if err != nil { usmTable.Logger.Print(err) } } // 设置引擎启动次数和引varvar //var engineBoots uint32 = 1 // var engineTime uint32 = uint32(time.Now().Unix() % 2147483647) // 使用当前时间初始化 //var engineTime uint32 = 3600 // 使用当前时间初始化 gs := &g.GoSNMP{ Target: s.TrapTarget, Port: s.TrapPort, Transport: "udp", Timeout: time.Duration(s.TimeOut) * time.Second, // 设置超时时间为x秒 Version: g.Version3, // Always using version3 for traps, only option that works with all SNMP versions simultaneously MsgFlags: g.NoAuthNoPriv, SecurityModel: g.UserSecurityModel, SecurityParameters: &g.UsmSecurityParameters{ UserName: s.UserName, AuthoritativeEngineID: s.EngineID, AuthoritativeEngineBoots: 1, //AuthoritativeEngineTime: 3600, AuthenticationProtocol: s.getAuthProto(), AuthenticationPassphrase: s.AuthPass, PrivacyProtocol: s.getPrivProto(), PrivacyPassphrase: s.PrivPass, }, //TrapSecurityParametersTable: usmTable, ContextEngineID: s.EngineID, ContextName: "v3test", } tl.Params = gs tl.Params.Logger = g.NewLogger(log.New(os.Stdout, "", 0)) // 定时发送Trap if s.TrapBool { go s.SendPeriodicTraps(gs) } go s.monitorNetwork(gs) if s.TrapListen { err := tl.Listen(s.TrapHost) if err != nil { log.Panicf("error in listen: %s", err) } } } func (s *SNMPService) MyTrapHandler(packet *g.SnmpPacket, addr *net.UDPAddr) { log.Printf("got trapdata from %s\n", addr.IP) for _, v := range packet.Variables { switch v.Type { case g.OctetString: b := v.Value.([]byte) fmt.Printf("OID: %s, string: %x\n", v.Name, b) default: log.Printf("trap: %+v\n", v) } } } func (s *SNMPService) SendPeriodicTraps(gs *g.GoSNMP) { err := gs.Connect() if err != nil { log.Fatalf("Connect() err: %v", err) } defer gs.Conn.Close() ticker := time.NewTicker(time.Duration(s.TrapTick) * time.Second) // 每10秒发送一次Trap defer ticker.Stop() for range ticker.C { // 每x秒发送一次Trap trap := g.SnmpTrap{ Variables: []g.SnmpPDU{ { Name: ".1.3.6.1.2.1.1.3.0", Type: g.TimeTicks, Value: uint32(time.Now().Unix()), }, { Name: ".1.3.6.1.6.3.1.1.4.1.0", Type: g.ObjectIdentifier, Value: ".1.3.6.1.6.3.1.1.5.1", }, }, } _, err = gs.SendTrap(trap) if err != nil { log.Printf("error sending trap: %s", err) } else { log.Printf("trap sent successfully") } } } // 1. 设备链路连接失败时发送Trap (LinkDown) func (s *SNMPService) sendLinkDownTrap(gs *g.GoSNMP, ifIndex int, ifDescr string) { trap := g.SnmpTrap{ Variables: []g.SnmpPDU{ { Name: ".1.3.6.1.2.1.2.2.1.1", // ifIndex Type: g.Integer, Value: ifIndex, }, { Name: ".1.3.6.1.2.1.2.2.1.2", // ifDescr Type: g.OctetString, Value: ifDescr, }, { Name: ".1.3.6.1.6.3.1.1.5.3", // linkDown Type: g.ObjectIdentifier, Value: ".1.3.6.1.6.3.1.1.5.3", }, }, } _, err := gs.SendTrap(trap) if err != nil { log.Printf("error sending LinkDown trap: %s", err) } else { log.Printf("LinkDown trap sent successfully") } } // 2. 设备链路恢复正常时发送Trap (LinkUp) func (s *SNMPService) sendLinkUpTrap(gs *g.GoSNMP, ifIndex int, ifDescr string) { trap := g.SnmpTrap{ Variables: []g.SnmpPDU{ { Name: ".1.3.6.1.2.1.2.2.1.1", // ifIndex Type: g.Integer, Value: ifIndex, }, { Name: ".1.3.6.1.2.1.2.2.1.2", // ifDescr Type: g.OctetString, Value: ifDescr, }, { Name: ".1.3.6.1.6.3.1.1.5.4", // linkUp Type: g.ObjectIdentifier, Value: ".1.3.6.1.6.3.1.1.5.4", }, }, } _, err := gs.SendTrap(trap) if err != nil { log.Printf("error sending LinkUp trap: %s", err) } else { log.Printf("LinkUp trap sent successfully") } } // 3. 设备鉴权失败时发送Trap (AuthenticationFailure) func (s *SNMPService) sendAuthFailureTrap(gs *g.GoSNMP, username, descr string) { trap := g.SnmpTrap{ Variables: []g.SnmpPDU{ { Name: ".1.3.6.1.6.3.1.1.5.5", // authenticationFailure Type: g.ObjectIdentifier, Value: ".1.3.6.1.6.3.1.1.5.5", }, { Name: ".1.3.6.1.4.1.2021.251.1", // 自定义OID,用于记录失败的用户名 Type: g.OctetString, Value: username, }, { Name: ".1.3.6.1.4.1.2021.252.1", // 自定义OID,用于记录描述 Type: g.OctetString, Value: descr, }, }, } _, err := gs.SendTrap(trap) if err != nil { log.Printf("error sending AuthenticationFailure trap: %s", err) } else { log.Printf("AuthenticationFailure trap sent successfully") } } func (s *SNMPService) monitorNetwork(gs *g.GoSNMP) { // 假设有一个函数 checkLinkStatus 返回链路状态 for { serviceStatus := s.checkServiceStatus() switch strings.ToUpper(serviceStatus) { case "LINK_DOWN": index := 1 ifDescr := fmt.Sprintf("Link(index=%d) DOWN", index) s.sendLinkDownTrap(gs, index, ifDescr) // 假设接口索引为1 s.SysService = 0 case "LINK_UP": index := 1 ifDescr := fmt.Sprintf("Link(index=%d) UP", index) s.sendLinkUpTrap(gs, index, ifDescr) // 假设接口索引为1 s.SysService = 0 case "AUTH_FAILURE": descr := "Authentication Failure" s.sendAuthFailureTrap(gs, s.UserName, descr) s.SysService = 0 default: } time.Sleep(10 * time.Second) // 每10秒检查一次 } } func (s *SNMPService) checkServiceStatus() string { switch s.SysService { case 1: return "LINK_DOWN" case 2: return "LINK_UP" case 3: return "AUTH_FAILURE" default: } return "NORMAL" }