博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于Snmp的Trap代码开发之坑
阅读量:6270 次
发布时间:2019-06-22

本文共 7571 字,大约阅读时间需要 25 分钟。

  最近是被这个snmp的trap给坑了,其实回想起来主要是对这个不了解。特别是对snmp协议研究不够深入,

真的不想看这些协议东西,只想大概知道。结果在开发snmp trap时候被坑了,下面列下自己踩到的坑:

1、snmp的trap的中文问题

本来在自己的机器上运行挺好,但是测试说发现乱码,内心直呼不可能吧,结果还真是,原来的代码如下:

if (val_type.equals("OCTET STRING")){    //字符串类型转码,防止里面有中文内容   strValue = new String(((OctetString)recVB.getVariable()).getValue(), charsetCode);} else {    strValue = new String (recVB.getVariable().toString());}

 charsetCode 为配置的消息编码类型, 这里说明下java的String都是Unicode编码的,

说明下:

如果想获得这个字符串的byte[] 可以通过类似:String.getBytes("UTF-8")来获得。

如果这样String.getBytes(); 就会依赖于JVM的字符集编码,WINDOWS下一般为GBK。

(要想改变JVM缺省字符集编码, 启动JVM时用选项-Dfile.encodeing=UTF-8)

 

注意千万不要在程序里面设置没有用的如下设置:

System.getProperties().setProperty("file.encoding", "GBK");

这样来解决默认编码的问题是不可行的!!!不可行的!!!不可行的!!!

  

getBytes() ---->StringCoding.encode()-->  String csn = Charset.defaultCharset().name();

/**     * Returns the default charset of this Java virtual machine.     *     * 

The default charset is determined during virtual-machine startup and * typically depends upon the locale and charset of the underlying * operating system. * * @return A charset object for the default charset * * @since 1.5 */ public static Charset defaultCharset() { if (defaultCharset == null) { synchronized (Charset.class) { String csn = AccessController.doPrivileged( new GetPropertyAction("file.encoding")); Charset cs = lookup(csn); if (cs != null) defaultCharset = cs; else defaultCharset = forName("UTF-8"); } } return defaultCharset; }

看到了吧,这个是个静态的方法,只要第一次运行defaultCharset 这个不为空了之后,后面就和file.encoding无关了,所以你基本上你无法保证

你在第一次调用之前设置,比如java其他类库会不会已经调用了getBytes(),只要一旦调用编码就固定了。

这个问题导致我在客户端测试的时候,配置的编码和实际发送的编码不一致,后来自己知道可以通过-Dfile.encodeing=UTF-8选项运行了。

有个简单的办法,可以把getBytes的内容打印出来就可以大概知道汉字是什么编码的:

 System.out.println("bytes:"+Arrays.toString(strTmp.getBytes()));

GBK都是2个字节的,而UTF-8一般是2个或三个字节表示一个汉字。

 

2、配置文件里面项目大小写

     flume的配置文件,在读取的时候是区分大小写的,所以这个不要写错了,或者在程序中忽视,自己竟然被坑到了,下次对配置还是忽略大小写的好。

3、Trap 的V3 版本会丢弃包问题

   开发同事在测试中,说V3的Trap消息运行一会会丢包,严格来说不是丢包,是说运行一段时间后,V1、V2版本的消息正常接收,SNMP Trap的V3

版本的消息无法接收到,真坑,看了下Snmp4J,找不到在哪里把日志启动起来,╮(╯▽╰)╭,在初始化的地方用:

org.snmp4j.log.LogFactory.setLogFactory(new ConsoleLogFactory()); 来进行初始化下,结果在不接受V3的Trap包的时候,会打印出来:

 1.3.6.1.6.3.15.1.1.2.0=0这条莫名其妙的记录,有记录就好,然后我顺着这条线索查下去,了解的SNMP的时间窗口,这个对应的含义是:

IdNotInTimeWindow 后来继续查SNMP4J的源码,发现在USM中有这样一段相关代码:

if (securityLevel >= 2) {                if (statusInfo != null) {                    int authParamsPos = usmSecurityParameters.getAuthParametersPosition()                            + usmSecurityParameters.getSecurityParametersPosition();                    boolean authentic = auth.isAuthentic(user.getAuthenticationKey(), message, 0, message.length,                            new ByteArrayWindow(message, authParamsPos, 12));                    if (!(authentic)) {                        if (logger.isDebugEnabled()) {                            logger.debug("RFC3414 §3.2.6 Wrong digest -> authentication failure: "                                    + usmSecurityParameters.getAuthenticationParameters().toHexString());                        }                        CounterEvent event = new CounterEvent(this, SnmpConstants.usmStatsWrongDigests);                        fireIncrementCounter(event);                        statusInfo.setSecurityLevel(new Integer32(1));                        statusInfo.setErrorIndication(new VariableBinding(event.getOid(), event.getCurrentValue()));                        return 1408;                    }                    usmSecurityStateReference.setAuthenticationKey(user.getAuthenticationKey());                    usmSecurityStateReference.setPrivacyKey(user.getPrivacyKey());                    usmSecurityStateReference.setAuthenticationProtocol(auth);                    usmSecurityStateReference.setPrivacyProtocol(priv);                    int status = this.timeTable.checkTime(                            new UsmTimeEntry(securityEngineID, usmSecurityParameters.getAuthoritativeEngineBoots(),                                    usmSecurityParameters.getAuthoritativeEngineTime()));                    switch (status) {                    case 1411:                        logger.debug("RFC3414 §3.2.7.a Not in time window; engineID='" + securityEngineID                                + "', engineBoots=" + usmSecurityParameters.getAuthoritativeEngineBoots()                                + ", engineTime=" + usmSecurityParameters.getAuthoritativeEngineTime());                        CounterEvent event = new CounterEvent(this, SnmpConstants.usmStatsNotInTimeWindows);                        fireIncrementCounter(event);                        statusInfo.setSecurityLevel(new Integer32(2));                        statusInfo.setErrorIndication(new VariableBinding(event.getOid(), event.getCurrentValue()));                        return status;                    case 1410:                        if (logger.isDebugEnabled()) {                            logger.debug("RFC3414 §3.2.7.b - Unkown engine ID: " + securityEngineID);                        }                        CounterEvent event = new CounterEvent(this, SnmpConstants.usmStatsNotInTimeWindows);                        fireIncrementCounter(event);                        statusInfo.setSecurityLevel(new Integer32(2));                        statusInfo.setErrorIndication(new VariableBinding(event.getOid(), event.getCurrentValue()));                        return status;                    }                }

 

重点在于:  int status = this.timeTable.checkTime(                         

  new UsmTimeEntry(securityEngineID, usmSecurityParameters.getAuthoritativeEngineBoots(),  usmSecurityParameters.getAuthoritativeEngineTime())); 

通过这句话检查是否在时间窗口内,如果不在时间窗口内直接就抛出去。

这句话又调用了其他的方法,来让我们看下:在UsmTimeTable.java里面

public synchronized int checkTime(UsmTimeEntry entry) {        int now = (int) (System.currentTimeMillis() / 1000L);        if (this.localTime.getEngineID().equals(entry.getEngineID())) {            if ((this.localTime.getEngineBoots() == 2147483647)                    || (this.localTime.getEngineBoots() != entry.getEngineBoots())                    || (Math.abs(now + this.localTime.getTimeDiff() - entry.getLatestReceivedTime()) > 150)) {                if (logger.isDebugEnabled()) {                    logger.debug(                            "CheckTime: received message outside time window (authorative):"                                    + ((this.localTime.getEngineBoots() != entry.getEngineBoots())                                            ? "engineBoots differ"                                            : new StringBuffer().append("")                                                    .append(Math.abs(now + this.localTime.getTimeDiff()                                                            - entry.getLatestReceivedTime()))                                                    .append(" > 150").toString()));                }                return 1411;            }            if (logger.isDebugEnabled()) {                logger.debug("CheckTime: time ok (authorative)");            }            return 0;        }

这个函数就是检查时间窗函数,注意了,getEngineBoots获取的是引擎运行次数,在第一次收到消息后,每秒增加一次,getEngineID标示引擎ID,好像一个用户一个引擎。

然后判断下这个时间:getLastestReceivedTime()注意这个时间是Snmp的Report消息的时候汇报时间,如果从开始收到第一条消息到150s内还没有汇报,则认为是不在时间窗口的丢弃掉。

尝试通过:  snmpListener.getUSM().getTimeTable().getEntry(new OctetString(securityName)).setLatestReceivedTime(((int) (System.currentTimeMillis() / 1000L))); 这个方法来设置下,结果还一样,可能还有更好办法。

 

不过既然是协议的要求,这种防止攻击的机制,那么就暂时保留吧。

 

 

转载地址:http://vmppa.baihongyu.com/

你可能感兴趣的文章
Android 使用AIDL实现进程间的通信
查看>>
机器学习(Machine Learning)&深度学习(Deep Learning)资料
查看>>
jquery的图片轮播 模板类型
查看>>
C# 获取文件名及扩展名
查看>>
Web安全学习计划
查看>>
输出有序数组的连续序列范围
查看>>
zinnia项目功能分析
查看>>
windows cmd for paramiko
查看>>
SQL经典面试题集锦
查看>>
View学习(一)-DecorView,measureSpec与LayoutParams
查看>>
色彩力量!21款你应该知道的优秀品牌设计
查看>>
SDUT 3503 有两个正整数,求N!的K进制的位数
查看>>
【.Net】C# 根据绝对路径获取 带后缀文件名、后缀名、文件名、不带文件名的文件路径...
查看>>
Redis常用命令速查 <第二篇>
查看>>
CSS规范
查看>>
使用FastDateFormat来代替JDK自带的DateFormat
查看>>
Python爬虫从入门到放弃(十六)之 Scrapy框架中Item Pipeline用法
查看>>
Android源代码解析之(三)--&gt;异步任务AsyncTask
查看>>
(zhuan) 自然语言处理中的Attention Model:是什么及为什么
查看>>
C#中使用RabbitMQ收发队列消息
查看>>