summaryrefslogtreecommitdiff
path: root/src/main/java/com/nis/server/SNMPTrapServer.java
blob: 03666e645817c8f9b54652f1fa9ca91497e622af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
package com.nis.server;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.nis.entity.*;
import com.nis.service.AlertRuleService;
import com.nis.service.SysConfigService;
import com.nis.util.DateUtil;

import org.apache.commons.lang3.StringUtils;
import org.snmp4j.*;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.smi.*;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;




/**
 * 本类用于监听代理进程的Trap信息
 * 1.加载alert_rule表内置规则(有且只有一条)
 * 2.启动snmp_server
 * 3.接收trap信息 
 * 4.组装prometheus_alert格式
 * 5.发送到web端接口处理
 * 
 * @author YJS
 * 
 */
@Component
@Order(1)
public class SNMPTrapServer implements CommandResponder,ApplicationRunner{// implements CommandResponder, extends Service
	private static Log logger = Log.get();
	@Value("${confagent.snmp.trapThredPoolSize}")
	private String snmpTrapThredPoolSize;
	@Value("${confagent.snmp.trapPort}")
	private String snmpTrapPort;
	@Autowired
	private AlertRuleService alertRuleService;
	@Autowired
	private SysConfigService sysConfigService;
	private String alertApi;
	private String alertPathPrefix;
	@Autowired
	private ConfagentMetrics confagentMetrics;
	
	@Override
	public void run(ApplicationArguments args) throws IOException {
		initServer();
	}
	
	public void initServer() throws IOException {
		logger.info("snmpTrapThredPoolSize is {}",snmpTrapThredPoolSize);
		ThreadPool threadPool = ThreadPool.create("Trap", Integer.valueOf(snmpTrapThredPoolSize));
		logger.info("snmpTrapThredPoolSize is {}",snmpTrapThredPoolSize);
		MultiThreadedMessageDispatcher dispatcher = new MultiThreadedMessageDispatcher(threadPool,	new MessageDispatcherImpl());
		Address listenAddress = GenericAddress.parse(System.getProperty("snmp4j.listenAddress", "udp:0.0.0.0/" + snmpTrapPort)); // 本地IP与监听端口
		logger.info("snmpTrapPort is {}",snmpTrapPort);
		TransportMapping transport = null;
		
//	    			 对TCP与UDP协议进行处理
		if (listenAddress instanceof UdpAddress) {
			transport = new DefaultUdpTransportMapping((UdpAddress) listenAddress);
			logger.debug("this listenAddress type is UDP");
		} else {
			transport = new DefaultTcpTransportMapping((TcpAddress) listenAddress);
			logger.debug("this listenAddress type is TCP");
		}
		
		Snmp snmp = new Snmp(dispatcher, transport);
		snmp.getMessageDispatcher().addMessageProcessingModel(new MPv1());
		snmp.getMessageDispatcher().addMessageProcessingModel(new MPv2c());
		snmp.getMessageDispatcher().addMessageProcessingModel(new MPv3());
		USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
		SecurityModels.getInstance().addSecurityModel(usm);
		snmp.listen();
		snmp.addCommandResponder(this);
	}
	 


	
	
	
	/**
	 * 实现CommandResponder的processPdu方法, 用于处理传入的请求、PDU等信息 当接收到trap时,会自动进入这个方法
	 * 
	 * @param respEvnt
	 */
	
	public void processPdu(CommandResponderEvent commandresponderevent)
	{
		try
		{
			//考虑数据库数据可能存在变化 由仅查询一次更改为每次都确认一下数据信息
			//加载alert_rule表内置规则
			AlertRule alertRule=alertRuleService.queryBulidInRule();
			List<SysConfig> sysConfigs = sysConfigService.queryList();
			if(!sysConfigs.isEmpty()) {
				for(SysConfig sysconfig : sysConfigs) {
					if(StrUtil.equals(sysconfig.getParamKey(),AlertManagerEnum.ALERT_API.getValue())) {
						alertApi=sysconfig.getParamValue();
					}else if(StrUtil.equals(sysconfig.getParamKey(),AlertManagerEnum.ALERT_PATH_PREFIX.getValue())){
						alertPathPrefix=sysconfig.getParamValue();
					}
				}
				logger.info("sysconfig alert api info {}",alertApi);
				logger.info("sysconfig alert path prefix info {}",alertPathPrefix);
			}else {
				logger.error("Sysconfig missing alert_api or alert_path_prefix data");
				return;
			}
			logger.info("processPdu start");
			logger.info("alertRule info is {}",JSON.toJSON(alertRule));
			if(alertRule==null) {
				logger.error(" alert rule info is null ");
				return;
			}
			logger.info((new StringBuilder("receive snmp event:")).append(commandresponderevent.getPDU()).toString());
			UdpAddress udpaddress = (UdpAddress)commandresponderevent.getPeerAddress();
			String s = udpaddress.getInetAddress().getHostAddress();
			PDU pdu = commandresponderevent.getPDU();
			logger.info((new StringBuilder("receive TRap:")).append(pdu).toString());
			TrapMessage trapmessageinfo = new TrapMessage();
			trapmessageinfo.setAgentSendIP(s);
			setOIDList(trapmessageinfo, pdu);
			setValueList(trapmessageinfo, pdu);
			trapmessageinfo.setOriginalPDU(pdu);
			if (pdu instanceof PDUv1)
			{
				PDUv1 pduv1 = (PDUv1)pdu;
				trapmessageinfo.setTrapVersion(1);
				String s1 = pduv1.getEnterprise().toString();
				trapmessageinfo.setTrapOID(s1);
				trapmessageinfo.setPduAgentIP(s);
				trapmessageinfo.setTrapV1SpecificType(pduv1.getSpecificTrap());
				trapmessageinfo.setTrapV1GenericType(pduv1.getGenericTrap());
				trapmessageinfo.setTrapName(trapmessageinfo.getTrapOID());
				switch (pduv1.getGenericTrap())
				{
				case 0: // '\0'
//					trapmessageinfo.setTrapName("设备冷启动");
					trapmessageinfo.setTrapName("Device Cold Start");
					break;

				case 1: // '\001'
//					trapmessageinfo.setTrapName("设备热启动");
					trapmessageinfo.setTrapName("Device Hot Start");
					break;

				case 2: // '\002'
//					trapmessageinfo.setTrapName("接口关闭");
					trapmessageinfo.setTrapName("The Interface Is Closed");
					break;

				case 3: // '\003'
//					trapmessageinfo.setTrapName("接口启用");
					trapmessageinfo.setTrapName("Interface Enabled");
					break;

				case 4: // '\004'
//					trapmessageinfo.setTrapName("SNMP认证失败");
					trapmessageinfo.setTrapName("SNMP Authentication Failed");
					break;

				case 5: // '\005'
//					trapmessageinfo.setTrapName("EGP邻居丢失");
					trapmessageinfo.setTrapName("EGP Neighbor Lost");
					break;
				}
			} else
			{
				trapmessageinfo.setTrapVersion(2);
				Variable variable = trapmessageinfo.getOIDValue(SnmpConstants.snmpTrapAddress.toString());
				logger.info("pdu.snmpTrapAddress() =-=-= "+variable);
				if (variable != null)
					trapmessageinfo.setPduAgentIP(variable.toString());
				Variable variable1 = trapmessageinfo.getOIDValue(SnmpConstants.snmpTrapOID.toString());
				if (variable1 != null)
					trapmessageinfo.setTrapOID(variable1.toString());
				trapmessageinfo.setTrapName(trapmessageinfo.getTrapOID());
				if (variable1 != null)
					if (variable1.equals(SnmpConstants.coldStart))
//						trapmessageinfo.setTrapName("设备冷启动");
						trapmessageinfo.setTrapName("Device Cold Start");
					else
					if (variable1.equals(SnmpConstants.warmStart))
//						trapmessageinfo.setTrapName("设备热启动");
						trapmessageinfo.setTrapName("Device Hot Start");
					else
					if (variable1.equals(SnmpConstants.linkDown))
//						trapmessageinfo.setTrapName("接口关闭");
						trapmessageinfo.setTrapName("The Interface Is Closed");
					else
					if (variable1.equals(SnmpConstants.linkUp))
//						trapmessageinfo.setTrapName("接口启用");
						trapmessageinfo.setTrapName("Interface Enabled");
					else
					if (variable1.equals(SnmpConstants.authenticationFailure))
//						trapmessageinfo.setTrapName("SNMP认证失败");
						trapmessageinfo.setTrapName("SNMP Authentication Failed");
					/*else //系统默认的类别不能匹配时,再使用自定义的trap信息库。是否需要分别自定义snmpV1和snmpValue2的trap信息库(定义到文件或者定义到数据库,必须体统重新加载的界面接口)
					if(getTrapName(variable1)!=null &&!variable1.equals("")){
						trapmessageinfo.setTrapName(getTrapName(variable1));
					}else{
//						throw new Exception("未被定义的SNMPTRAP类型!");
						throw new Exception("Undefined SNMPTRAP type!");
					}*/
			}
			StringBuffer trapInfo = new StringBuffer();
			trapInfo.append("trapmessageinfo.getTrapName():"+trapmessageinfo.getTrapName());
			trapInfo.append("; trapmessageinfo.getAgentSendIP():"+trapmessageinfo.getAgentSendIP());
			trapInfo.append("; trapmessageinfo.getOriginalPDU():"+trapmessageinfo.getOriginalPDU());
			trapInfo.append("; trapmessageinfo.getTrapVersion():"+trapmessageinfo.getTrapVersion());
			trapInfo.append("; trapmessageinfo.getTrapOID():"+trapmessageinfo.getTrapOID());
			trapInfo.append("; trapmessageinfo.getPduAgentIP():"+trapmessageinfo.getPduAgentIP());
			trapInfo.append("; trapmessageinfo.getTrapV1GenericType():"+trapmessageinfo.getTrapV1GenericType());
			trapInfo.append("; trapmessageinfo.getTrapV1SpecificType():"+trapmessageinfo.getTrapV1SpecificType());
			logger.info("agent IP:"+s+"  trap message:"+trapInfo.toString());
			
			// 组装prometheus_alert格式
			Integer alertName = alertRule.getId();
			String severity = alertRule.getSeverity();
			String asset = trapmessageinfo.getAgentSendIP();
			String oid = trapmessageinfo.getTrapOID();
			String value=trapmessageinfo.getOriginalPDU().getVariableBindings().toString();
			
			StringBuilder description = new StringBuilder();
			description.append("version:"+trapmessageinfo.getTrapVersion());
			description.append(",agentip:"+trapmessageinfo.getAgentSendIP());
			description.append(",oid:"+trapmessageinfo.getTrapOID());
			description.append(",value:"+value);
			String trapName = trapmessageinfo.getTrapName();
			if(trapName!=null&&trapName.length()>0) {
				description.append(",trapName:"+trapName);
			}
			StringBuilder summary=new StringBuilder("snmptrap:");
			summary.append(trapmessageinfo.getAgentSendIP()+"(");
			summary.append(trapmessageinfo.getTrapOID()+":"+value+")");
			boolean snmptrap=true;
			SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
			String startsAt = sdf.format(DateUtil.getUTCTimeByConfigTimeZone());
			
			JSONObject labels =new JSONObject();
			labels.put("alertname", alertName.toString());
			labels.put("severity",severity);
			labels.put("asset", asset);
			labels.put("trapOID", oid);
			
			JSONObject annotations =new JSONObject();
			annotations.put("description", description.toString());
			annotations.put("summary", summary.toString());
			
			JSONObject result =new JSONObject();
			result.put("labels", labels);
			result.put("annotations", annotations);
			result.put("snmptrap", snmptrap);
			result.put("startsAt", startsAt);
			
			JSONArray mess =new JSONArray();
			mess.add(result);
			
			logger.info("send alert info is {}",JSON.toJSON(mess));
			
			// 将告警信息发送到web端处理
			RestTemplate restTemplate=new RestTemplate();
			restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_JSON);
			HttpEntity entity =new HttpEntity(mess,headers);
//			String url="http://"+alertApi+alertPathPrefix+"/api/v1/alerts";
			if(StringUtils.isNotBlank(alertApi)) {
				String[] alertApis = alertApi.split(":");
				alertApi=alertApis[0];
				Integer alertPort=Integer.valueOf(alertApis[1]);
				String  url = UrlBuilder.create().setScheme("http").setHost(alertApi).setPort(alertPort).appendPath(alertPathPrefix+"/api/v1/alerts").toString();
				Object postForEntity = restTemplate.postForEntity(url, entity,Object.class);
				logger.info("post success info {}",JSON.toJSON(postForEntity));
				confagentMetrics.snmpCounter.increment();
			}
		}
		catch (Exception exception)
		{
			logger.error("Error parsing UDP trap: {}",ExceptionUtil.getMessage(exception));
		}finally{
			
		}
	}
	
	public String getTrapName(Variable variable1){
		String trapName = "";
		Map allTrapTypeDefine = new HashMap();
		trapName = allTrapTypeDefine.get(variable1.toString()).toString();
		return trapName;
	}

	void setOIDList(TrapMessage trapmessageinfo, PDU pdu)
	{
		Vector vector = pdu.getVariableBindings();
		String s;

		for (Iterator iterator = vector.iterator(); iterator.hasNext(); trapmessageinfo.getTrapPDUOIDs().add(s))
		{
			VariableBinding variablebinding = (VariableBinding)iterator.next();
			s = variablebinding.getOid().toString();
		}

	}

	void setValueList(TrapMessage trapmessageinfo, PDU pdu)
	{
		Vector vector = pdu.getVariableBindings();
		Variable variable;
		for (Iterator iterator = vector.iterator(); iterator.hasNext(); trapmessageinfo.getTrapPDUOIDValues().add(variable))
		{
			VariableBinding variablebinding = (VariableBinding)iterator.next();
			variable = variablebinding.getVariable();
		}

	}



	/** 
	 * 将十进六制转换成为中文 
	 */
	private static String hexString = "0123456789ABCDEF";
	
}