LinuxSuRen / LinuxSuRen/api-testing
Support to provide a SNMP mock server
Đang mở
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- Go
- Star
- 369
- Fork
- 67
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Mô tả
Below is a sample code:
package main
import (
"encoding/binary"
"fmt"
"net"
"strconv"
"strings"
"github.com/gosnmp/gosnmp"
)
const (
// SNMP 版本号
SNMPVersion = 1
// 固定的 OID 和值
OID = ".1.3.6.1.4.1.5105.100.1.9.4.15.0" // sysDescr
Value = "My SNMP Server"
)
// sendSNMPRequest 发送 SNMP 请求并接收响应
func sendSNMPRequest(target string, community string, oid string) ([]byte, error) {
// 创建 SNMP 客户端
gosnmp.Default.Target = target
gosnmp.Default.Port = 161
gosnmp.Default.Community = community
gosnmp.Default.Version = gosnmp.Version2c
// 创建 PDU
pdu := gosnmp.SnmpPDU{
Name: oid,
Type: gosnmp.OctetString,
Value: Value,
}
// 创建请求
request := &gosnmp.SnmpPacket{
Version: gosnmp.Version2c,
Community: community,
Error: gosnmp.NoError,
ErrorIndex: 0,
PDUType: gosnmp.GetRequest,
Variables: []gosnmp.SnmpPDU{pdu},
}
// 编码请求
req, err := request.MarshalMsg()
if err != nil {
return nil, fmt.Errorf("failed to marshal SNMP request: %v", err)
}
// 发送请求并接收响应
conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", target, 161))
if err != nil {
return nil, fmt.Errorf("failed to dial UDP: %v", err)
}
defer conn.Close()
_, err = conn.Write(req)
if err != nil {
return nil, fmt.Errorf("failed to send SNMP request: %v", err)
}
buffer := make([]byte, 4096) // Increased buffer size
n, err := conn.Read(buffer)
if err != nil {
return nil, fmt.Errorf("failed to read SNMP response: %v", err)
}
return buffer[:n], nil
}
func main() {
pc, err := net.ListenPacket("udp", ":161")
if err != nil {
fmt.Println("Failed to listen on UDP port 161:", err)
return
}
defer pc.Close()
fmt.Println("SNMP server listening on UDP port 161...")
buffer := make([]byte, 4096) // Increased buffer size
for {
// 读取客户端请求
n, addr, err := pc.ReadFrom(buffer)
if err != nil {
fmt.Println("Failed to read UDP packet:", err)
continue
}
// 解析 SNMP 请求
req := buffer[:n]
fmt.Printf("Received SNMP request from %s: %X\n", addr, req)
// 生成 SNMP 响应
resp := generateSNMPResponse(req)
if resp == nil {
fmt.Println("Failed to generate SNMP response")
continue
}
// 发送响应
_, err = pc.WriteTo(resp, addr)
if err != nil {
fmt.Println("Failed to send SNMP response:", err)
continue
} else {
fmt.Printf("Sent SNMP response to %s: %X\n", addr, resp)
}
}
// 测试发送 SNMP 请求
//resp, err := sendSNMPRequest("192.168.12.109", "public", ".1.3.6.1.4.1.5105.100.1.9.4.15.0")
//if err != nil {
// fmt.Println("Failed to send SNMP request:", err)
//} else {
// fmt.Printf("Received SNMP response: %X\n", resp)
//}
}
// generateSNMPResponse 生成 SNMP 响应数据
func generateSNMPResponse(req []byte) []byte {
// 解析请求
// 这里仅处理简单的 GET 请求
if len(req) < 4 {
fmt.Println("Invalid SNMP request length")
return nil
}
// 提取社区字符串
communityLen := req[6]
community := string(req[7 : 7+communityLen]) // 提取社区字符串
fmt.Printf("Received SNMP request with community: %s\n", community)
// 提取请求 ID
requestId := binary.BigEndian.Uint32(req[7+communityLen+2+2 : 7+communityLen+2+2+4])
fmt.Printf("Received SNMP request with ID %d\n", requestId)
// 使用 gosnmp 库构建响应
gosnmp.Default.Target = "192.168.123.58"
gosnmp.Default.Port = 161
gosnmp.Default.Community = community
gosnmp.Default.Version = gosnmp.Version2c
// 创建 PDU
pdu := gosnmp.SnmpPDU{
Name: OID,
Type: gosnmp.OctetString,
Value: Value,
}
// 创建响应
response := &gosnmp.SnmpPacket{
Version: gosnmp.Version2c,
Community: community,
//ErrorStatus: gosnmp.NoError,
Error: gosnmp.NoError,
ErrorIndex: 0,
RequestID: requestId,
PDUType: gosnmp.GetResponse,
Variables: []gosnmp.SnmpPDU{pdu},
}
// 编码响应
resp, err := response.MarshalMsg()
if err != nil {
fmt.Println("Failed to marshal SNMP response:", err)
return nil
}
fmt.Printf("Generated SNMP response: %X\n", resp)
return resp
}
// encodeOID 编码 OID
func encodeOID(oid string) []byte {
// 使用 BER 编码来编码 OID
parts := splitOID(oid)
encoded := make([]byte, 0)
first := parts[0]*40 + parts[1]
encoded = append(encoded, byte(first))
for _, part := range parts[2:] {
encoded = append(encoded, encodeVarInt(part)...)
}
return encoded
}
// encodeVarInt 使用 BER 编码来编码一个整数
func encodeVarInt(value int) []byte {
if value < 128 {
return []byte{byte(value)}
}
encoded := make([]byte, 0)
for value > 0 {
encoded = append([]byte{byte(value%128 | 0x80)}, encoded...)
value /= 128
}
encoded[len(encoded)-1] &= 0x7F
return encoded
}
// encodeValue 编码值
func encodeValue(value string) []byte {
// 使用 BER 编码来编码值
encoded := make([]byte, 0)
encoded = append(encoded, byte(0x04)) // 字符串类型
encoded = append(encoded, byte(len(value))) // 字符串长度
encoded = append(encoded, []byte(value)...) // 字符串值
return encoded
}
// splitOID 分割 OID 字符串为整数数组
func splitOID(oid string) []int {
parts := make([]int, 0)
for _, part := range strings.Split(oid, ".") {
num, _ := strconv.Atoi(part)
parts = append(parts, num)
}
return parts
}
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu bằng cách xác định các entry point của mock-server trong repository và các protocol handler hiện có, sau đó so sánh cấu trúc của chúng với các hàm main và generateSNMPResponse của sample. Xác định cách các request và response SNMP nên được tích hợp với mock configuration và các test hiện có. Hoàn thành khi có một đường đi cho SNMP mock-server được tài liệu hóa và có thể kiểm thử, xử lý hành vi được yêu cầu mà không phụ thuộc vào các địa chỉ hard-coded của sample.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- go
- Lĩnh vực
- api, testing
- Loại issue
- Tính năng
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Đình trệ
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 35/100