关于Snmp的Trap代码开发之坑

最近是被这个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.
     *
     * <p> 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))); 这个方法来设置下,结果还一样,可能还有更好办法。

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

 

时间: 2024-08-29 19:54:41

关于Snmp的Trap代码开发之坑的相关文章

插件开发之360 DroidPlugin源码分析(四)Activity预注册占坑

请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52258434 在了解系统的activity,service,broadcastReceiver的启动过程后,今天将分析下360 DroidPlugin是如何预注册占坑的?本篇文章主要分析Activity预注册占坑,Activity占了坑后又是什么时候开始瞒天过海欺骗AMS的?先看下Agenda: AndroidMainfest.xml中概览 Activity中关键方

插件开发之360 DroidPlugin源码分析(五)Service预注册占坑

请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52264977 在了解系统的activity,service,broadcastReceiver的启动过程后,今天将分析下360 DroidPlugin是如何预注册占坑的?本篇文章主要分析Service预注册占坑,Service占了坑后又是什么时候开始瞒天过海欺骗AMS的?先看下Agenda: AndroidMainfest.xml中概览 Service中关键方法被h

iOS开发之17个常用代码整理

1.判断邮箱格式是否正确的代码 //利用正则表达式验证 -(BOOL)isValidateEmail:(NSString *)email { NSString *emailRegex = @"[A-Z0-9a-z._%+-][email protected][A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"; NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES%@&quo

移动平台前端开发之WebApp代码技巧

1.首先我们来看看webkit内核中的一些私有的meta标签,这些meta标签在开发webapp时起到非常重要的作用 <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;" name="viewport" /> <meta content="yes" name="apple-mobile-web

iOS开发之XML解析代码

iOS开发之XML解析代码 //1.加载和解析XML文件 NSString *path = [[NSBundle mainBundle] pathForResource:@"xml.txt" ofType:nil]; NSData *data = [[NSData alloc] initWithContentsOfFile:path]; // GDataXMLDocument 表示XML文档对象 // initWithData 使用NSData初始化, 就是解析 GDataXMLDoc

IOS开发之TableView、多个TableViewCell、自定义Cell、Cell上画画(故事板+代码方式)

最近要做一个项目,有个账户设置界面,看了微博.微信.QQ,他们的账号设置都比较原生态没做什么处理.春雨医生的账号不错,做了许多处理.不说废话直接上代码. 第一步: //UserTableViewCell.h这里定义第一种Cell #import <UIKit/UIKit.h> @interface UserTableViewCell : UITableViewCell @property (weak, nonatomic) IBOutlet UIImageView *userviewcelli

李洪强iOS开发之RunLoop的原理和核心机制

李洪强iOS开发之RunLoop的原理和核心机制 搞iOS之后一直没有深入研究过RunLoop,非常的惭愧.刚好前一阵子负责性能优化项目,需要利用RunLoop做性能优化和性能检测,趁着这个机会深入研究了RunLoop的原理和特性. RunLoop的定义 当有持续的异步任务需求时,我们会创建一个独立的生命周期可控的线程.RunLoop就是控制线程生命周期并接收事件进行处理的机制. RunLoop是iOS事件响应与任务处理最核心的机制,它贯穿iOS整个系统. Foundation: NSRunLo

Cocos2d-x 3.x游戏开发之旅

Cocos2d-x 3.x游戏开发之旅 钟迪龙 著   ISBN 978-7-121-24276-2 2014年10月出版 定价:79.00元 516页 16开 内容提要 <Cocos2d-x 3.x游戏开发之旅>是<Cocos2d-x游戏开发之旅>的升级版,修改了Cocos2d-x 2.0版进阶到3.0版后的一些内容,新增了对CocoStudio.UI编辑器.Cocos2d-x 3.x新特性以及网络方面的知识点.主要介绍常用的API使用方式:如何通过官方Demo获取更多关于Coc

Android安全开发之ZIP文件目录遍历

1.ZIP文件目录遍历简介 因为ZIP压缩包文件中允许存在"../"的字符串,攻击者可以利用多个"../"在解压时改变ZIP包中某个文件的存放位置,覆盖掉应用原有的文件.如果被覆盖掉的文件是动态链接so.dex或者odex文件,轻则产生本地拒绝服务漏洞,影响应用的可用性,重则可能造成任意代码执行漏洞,危害用户的设备安全和信息安全.比如近段时间发现的"寄生兽"漏洞.海豚浏览器远程命令执行漏洞.三星默认输入法远程代码执行漏洞等都与ZIP文件目录遍历有