/** * Copyright 2012 Radware and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * ### class description ### * * @author Gera Goft * @version 0.1 */ package com.radware.defenseflow.dp; import java.io.RandomAccessFile; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import me.prettyprint.cassandra.serializers.StringSerializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.opendaylight.defense4all.core.AMS; import org.opendaylight.defense4all.core.DFAppModule; import org.opendaylight.defense4all.core.DFAppRoot; import org.opendaylight.defense4all.core.Mitigation; import org.opendaylight.defense4all.core.PN; import org.opendaylight.defense4all.core.Traffic; import org.opendaylight.defense4all.core.DFAppRoot.RepoMajor; import org.opendaylight.defense4all.core.Traffic.TrafficMatch; import org.opendaylight.defense4all.framework.core.ExceptionControlApp; import org.opendaylight.defense4all.framework.core.FMHolder; import org.opendaylight.defense4all.framework.core.HealthTracker; import org.opendaylight.defense4all.framework.core.Repo; import org.opendaylight.defense4all.framework.core.RepoFactory; import org.opendaylight.defense4all.framework.core.FrameworkMain.ResetLevel; import com.radware.defenseflow.dp.DPRep.RepoMinor; public class DPEventMgr extends DFAppModule { /** * Decoupled actions for ActionSwitcher */ protected static final int ACTION_INVALID = -1; // Already defined in Module. Brought here for brevity protected static final int ACTION_RESERVED = 0; // Already defined in Module. Brought here for brevity protected static final int ACTION_PROCESS_SYSLOGS = 1; private Logger log = LoggerFactory.getLogger(this.getClass()); public DPRep amsRep; /* Rep and cache of all monitored traffics. */ public Repo<String> monitoredTrafficRepo = null; protected ConcurrentHashMap<String,MonitoredTraffic> monitoredTraffics = null; String rsyslogDFPipe; protected Hashtable<String,String> dpNames; /* Constructor for Spring */ public DPEventMgr() { super(); monitoredTraffics = new ConcurrentHashMap<String,MonitoredTraffic>(); dpNames = new Hashtable<String,String>(); } /* Setters for Spring */ public void setRsyslogDFPipe(String rsyslogDFPipe) {this.rsyslogDFPipe = rsyslogDFPipe;} public void setAmsRep(DPRep amsRep) {this.amsRep = amsRep;} /** Post-constructor initialization * @throws ExceptionControlApp */ @Override public void init() throws ExceptionControlApp { super.init(); /* DPEventMgr Repos */ RepoFactory rf = fMain.getRepoFactory(); String rMajor = RepoMajor.DF_AMS_REP.name(); try { monitoredTrafficRepo = (Repo<String>) rf.getOrCreateRepo(rMajor, RepoMinor.MONITORED_TRAFFIC.name(), StringSerializer.get(), true, MonitoredTraffic.getRCDs()); } catch (Throwable e) { log.error("Failed to getOrCreateRepo for monitored traffic.", e); fMain.getHealthTracker().reportHealthIssue(HealthTracker.SIGNIFICANT_HEALTH_ISSUE); throw new ExceptionControlApp("Failed to getOrCreateRepo for monitored traffic.", e); } /* Load monitored traffics */ Hashtable<String,Hashtable<String,Object>> monitoredTrafficTable = monitoredTrafficRepo.getTable(); if(monitoredTrafficTable == null) { log.error("Failed to init - received null monitoredTraffic table"); fMain.getHealthTracker().reportHealthIssue(HealthTracker.SIGNIFICANT_HEALTH_ISSUE); throw new ExceptionControlApp("Failed to init - received null monitoredTraffic table"); } Iterator<Map.Entry<String,Hashtable<String,Object>>> iter = monitoredTrafficTable.entrySet().iterator(); Map.Entry<String,Hashtable<String,Object>> entry; MonitoredTraffic monitoredTraffic; while(iter.hasNext()) { entry = iter.next(); try { monitoredTraffic = new MonitoredTraffic(entry.getValue()); } catch (ExceptionControlApp e) {continue;} monitoredTraffics.put(monitoredTraffic.key, monitoredTraffic); } /* Initialize Linux pipe file from which to draw DP syslogs deposited by rsyslogd. */ if(fMain.isDebugRun()) { try { Runtime runtime = Runtime.getRuntime(); // runtime.exec("dd if=" + rsyslogDFPipe + " iflag=nonblock of=/dev/null > /dev/null"); runtime.exec("mkfifo " + rsyslogDFPipe); runtime.exec("sudo service rsyslog restart"); // Make sure rsyslogd picks up the latest creation of DF syslog pipe } catch (Throwable e1) {} } try { addBackgroundTask(ACTION_PROCESS_SYSLOGS, null); } catch (Exception e) { log.error("Failed to instantiate periodic task to read syslogs from DPs", e); fMain.getHealthTracker().reportHealthIssue(HealthTracker.SIGNIFICANT_HEALTH_ISSUE); } } /** Pre-shutdown cleanup */ @Override public void finit() { super.finit(); Iterator<Map.Entry<String,MonitoredTraffic>> iter = monitoredTraffics.entrySet().iterator(); Map.Entry<String,MonitoredTraffic> entry; MonitoredTraffic monitoredTraffic; Hashtable<String,Object> row; String trafficKey = null; while(iter.hasNext()) { entry = iter.next(); try { monitoredTraffic = entry.getValue(); trafficKey = monitoredTraffic.key; row = monitoredTraffic.toRow(); monitoredTrafficRepo.setRow(entry.getKey(), row); } catch (ExceptionControlApp e) { log.error("Failed to record monitored traffic in repo - " + trafficKey, e); } } } /** Reset * @throws ExceptionControlApp */ @Override public void reset(ResetLevel resetLevel) throws ExceptionControlApp { super.reset(resetLevel); monitoredTrafficRepo.truncate(); monitoredTraffics.clear(); } /** * #### method description #### * @param param_name param description * @return return description * @throws exception_type circumstances description */ public void addAMS(String amsKey) { try { String dpAddrStr = (String) dfAppRoot.amsRepo.getCellValue(amsKey, AMS.MGMT_IP_ADDR_STRING); String dpLabel = (String) dfAppRoot.amsRepo.getCellValue(amsKey, AMS.LABEL); if(dpAddrStr != null && dpLabel != null) dpNames.put(dpAddrStr, dpLabel); } catch (Throwable e) { log.error("Failed to retrieve from amsRepo dpAddr or dpLabel for " + amsKey); FMHolder.get().getFR().logRecord(DFAppRoot.FR_DF_FAILURE, "Failed to add AMS " + amsKey); } } /** * #### method description #### * @param param_name param description * @return return description * @throws exception_type circumstances description */ public void removeAMS(String amsKey) { try { String dpAddrStr = (String) dfAppRoot.amsRepo.getCellValue(amsKey, AMS.MGMT_IP_ADDR_STRING); if(dpAddrStr != null ) dpNames.remove(dpAddrStr); } catch (Throwable e) { log.error("Failed to retrieve from amsRepo dpAddr for " + amsKey); FMHolder.get().getFR().logRecord(DFAppRoot.FR_DF_FAILURE, "Failed to remove AMS " + amsKey); } } /** * #### method description #### * @param param_name param description * @return return description * @throws exception_type circumstances description */ public void addPN(String pnKey) {} /** * #### method description #### * @param param_name param description * @return return description * @throws exception_type circumstances description */ public void removePN(String pnKey) {} /** * #### method description #### * @param param_name param description * @return return description * @throws ExceptionControlApp * @throws exception_type circumstances description */ public void startMonitoring(String mitigationKey) { Mitigation mitigation; String key = null; boolean monitoredTrafficsSet = false; boolean monitoredTrafficRowSet = false; try { Hashtable<String,Object> mitigationRow = dfAppRoot.mitigationsRepo.getRow(mitigationKey); mitigation = new Mitigation(mitigationRow); /* Construct PN and retrieve the vlan from it */ Hashtable<String,Object> pnRow = dfAppRoot.pNsRepo.getRow(mitigation.pnKey); PN pn = new PN(pnRow); int vlan = pn.retrieveVlanFromProps(); Traffic traffic = new Traffic(vlan, mitigation.dstAddr, pn.dstAddrPrefixLen); traffic.addProtocolPort(mitigation.protocolPort.protocol, mitigation.protocolPort.port); key = MonitoredTraffic.generateKey(mitigation.dstAddr.getHostName(), mitigation.protocolPort); MonitoredTraffic monitoredTraffic = new MonitoredTraffic(key, mitigation.pnKey, mitigationKey, traffic); monitoredTraffics.put(key, monitoredTraffic); monitoredTrafficsSet = true; monitoredTrafficRepo.setRow(key, monitoredTraffic.toRow()); monitoredTrafficRowSet = true; log.debug( "Starting to monitor security events from DefensePros " + "for traffic " + monitoredTraffic.toString()); /* Remember the key of the monitoredTraffic (to be used in removal of this monitoredTraffic) */ mitigation.monitoredTrafficKey = key; dfAppRoot.mitigationsRepo.setRow(mitigationKey, mitigation.toRow()); } catch (Throwable e) { log.error("Excepted starting monitoring for " + mitigationKey, e); FMHolder.get().getFR().logRecord(DFAppRoot.FR_DF_FAILURE, "Failed to start monitoring AMS for mitigated traffic."); fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE); try { if(key != null && monitoredTrafficsSet) monitoredTraffics.remove(key); if(key != null && monitoredTrafficRowSet) monitoredTrafficRepo.deleteRow(key); } catch (Throwable e2) { log.error("Failed to clean up after excepting trying to start monitoring " + mitigationKey, e2); FMHolder.get().getFR().logRecord(DFAppRoot.FR_DF_FAILURE, "Failed to stop monitoring AMS for mitigated traffic."); } } } /** * #### method description #### * @param param_name param description * @return return description * @throws ExceptionControlApp * @throws exception_type circumstances description */ public void stopMonitoring(String mitigationKey) { try { String key = (String) dfAppRoot.mitigationsRepo.getCellValue(mitigationKey,Mitigation.MONITORED_TRAFFIC_KEY); MonitoredTraffic monitoredTraffic = monitoredTraffics.remove(key); if(monitoredTraffic != null) log.debug( "Stopping to monitor security events from DefensePros " + "for traffic " + monitoredTraffic.toString()); monitoredTrafficRepo.deleteRow(key); } catch (Throwable e) { log.error("Failed to stopMonitoring.", e); // FMHolder.get().getFR().logRecord(DFAppRoot.FR_DF_FAILURE, "DPRep failed to properly stop monitoring through " // + "DPs for mitigated traffic " + mitigationKey); fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE); } } /** * #### method description #### * @param param_name param description * @return return description * @throws exception_type circumstances description */ public boolean check() { return true; } /* #### method description #### * * @param s * @return */ protected void backgroundProcessSyslogs() { /*BufferedReader bufferedReader = null;*/ String syslogMsg; RandomAccessFile pipeReader = null; while(true) { try { pipeReader = new RandomAccessFile(rsyslogDFPipe, "r"); } catch (Throwable e) { log.error("Failed to open rsyslog pipe.", e); FMHolder.get().getFR().logRecord(DFAppRoot.FR_DF_FAILURE,"Failed to read AMS syslogs. "); fMain.getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE); try { Thread.sleep(10000); } catch (Throwable e1) {/* Ignore */} continue; } try { while ( null != (syslogMsg = pipeReader.readLine()) ) { log.debug("DP SYSLOG msg: " + syslogMsg); if (syslogMsg == null || syslogMsg.length() == 0) continue; DPEvent dpEvent; try { dpEvent = DPEvent.fromString(syslogMsg); log.debug("DP SYSLOG Event: " + (dpEvent == null ? "null dp event" : dpEvent.toString())); } catch (ExceptionControlApp e) { log.error("Failed to parse syslogMsg into dpEvent.", e); FMHolder.get().getFR().logRecord(DFAppRoot.FR_DF_FAILURE,"Failed to parse AMS syslog message: " + syslogMsg); fMain.getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE); continue; } if (dpEvent == null) continue; // Not a DP message /* Strive to associate dp names to returned addresses */ String dpName = dpNames.get(dpEvent.dpAddrStr); if(dpName == null) continue; // Not a monitored DP dpEvent.dpName = dpName; /* Check if it is a security event */ DPSecEvent dpSecurityEvent = null; try { dpSecurityEvent = DPSecEvent.fromString(dpEvent.msg); if(dpSecurityEvent != null) log.info("DP SYSLOG Event: " + dpSecurityEvent.toString()); } catch (ExceptionControlApp e) { log.error("Failed to process syslogMsg into dpEvent.", e); FMHolder.get().getFR().logRecord(DFAppRoot.FR_DF_FAILURE,"Failed to parse AMS syslog security message: "+syslogMsg); fMain.getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE); continue; } if (dpSecurityEvent == null) { fMain.getFR().logRecord(DFAppRoot.FR_AMS_OPERATIONAL, dpEvent.toString()); // Record as operational event } else { // Process security event try { processSecEvent(dpSecurityEvent); } catch (Throwable e) { continue; /* Ignore*/ } } } pipeReader.close(); } catch (Throwable e) { log.error("Failed to read from rsyslog pipe.", e); FMHolder.get().getFR().logRecord(DFAppRoot.FR_DF_FAILURE,"Failed to read AMS syslogs."); fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE); try { Thread.sleep(1000); pipeReader.close(); } catch (Throwable e1) {/* Ignore */} continue; } } } protected void processSecEvent(DPSecEvent secEvent) { Iterator<Map.Entry<String,MonitoredTraffic>> iter = monitoredTraffics.entrySet().iterator(); TrafficMatch trafficMatch; MonitoredTraffic monitoredTraffic; Map.Entry<String,MonitoredTraffic> entry; while(iter.hasNext()) { entry = iter.next(); monitoredTraffic = entry.getValue(); if(monitoredTraffic == null) { log.error("Null monitoredTraffic for key " + entry.getKey()); fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE); continue; } /* Check if this is a monitored security event - dst_addr, protocol, dst_port */ try { trafficMatch = monitoredTraffic.traffic.match(secEvent.vlan, secEvent.dstAddress,secEvent.dpProtocol.toDFProtocol(),secEvent.dstPort); } catch (ExceptionControlApp e) { String msg = "Failed to match AMS security syslog message to monitored traffic."; log.error(msg,e); FMHolder.get().getFR().logRecord(DFAppRoot.FR_DF_FAILURE, msg); fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE); continue; } if(trafficMatch == TrafficMatch.NO) continue; /* Record this security event. */ //fMain.getFR().logRecord(DFAppRoot.FR_AMS_SECURITY,secEvent.toString()); /* Construct AttackReport and deliver to the DPBasedDetector. */ /* TODO: Refine attack reporting when TrafficMatch.CONTAIN, so as to allow diversion refinements accordingly */ long currentTime = System.currentTimeMillis() / 1000; AttackReport attackReport = new AttackReport(currentTime, monitoredTraffic, secEvent); amsRep.dpBasedDetector.handleAttackReport(attackReport); } } @Override protected void actionSwitcher(int actionCode, Object param) { switch(actionCode) { case ACTION_RESERVED: break; case ACTION_PROCESS_SYSLOGS: backgroundProcessSyslogs(); break; default: } } public void test() {} }