/**
* Copyright (c) <2013> <Radware Ltd.> and others. All rights reserved.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License
* v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
* @author Gera Goft
* @author Konstantin Pozdeev
* @version 0.1
*/
package org.opendaylight.defense4all.core;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import org.apache.mina.filter.firewall.Subnet;
import org.opendaylight.defense4all.core.ProtocolPort.DFProtocol;
import org.opendaylight.defense4all.framework.core.ExceptionControlApp;
import org.opendaylight.defense4all.framework.core.FMHolder;
import org.opendaylight.defense4all.framework.core.HealthTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Traffic {
static Logger log = LoggerFactory.getLogger(Traffic.class);
public enum TrafficMatch {
MATCH,
CONTAIN,
NO
}
public enum TrafficDirection {
INVALID,
INBOUND, // Client to server
OUTBOUND // Server to client
}
public int vlan;
public InetAddress dstAddr;
public int dstAddrPrefixLen;
/* Entry key = DPProtocol.name(). value = list of ports.
* Empty hashtable means all protocols. Empty port list means all ports (for that protocol). */
public Hashtable<String,ArrayList<Integer>> protoPorts;
/* Local hashtable for hostname lookups */
public static class NameHash {
private static Hashtable<InetAddress,String> nameHash = null;
private static Hashtable<String,InetAddress> addrHash = null;
private static void initIfNeeded() {
if ( nameHash == null ) {
nameHash = new Hashtable<InetAddress,String>();
}
if ( addrHash == null ) {
addrHash = new Hashtable<String,InetAddress>();
}
}
public static String getHostName(InetAddress addr) {
initIfNeeded();
if ( nameHash.containsKey(addr)) {
return nameHash.get(addr) ;
} else {
String name = addr.getHostName();
nameHash.put(addr, name);
addrHash.put(name, addr);
return name;
}
}
public static InetAddress getHostAddr(String name) {
initIfNeeded();
if ( addrHash.containsKey(name)) {
return addrHash.get(name) ;
} else {
InetAddress addr=null;
try {
addr = InetAddress.getByName(name);
if (addr == null)
addr = InetAddress.getLocalHost();
} catch (UnknownHostException e) {};
nameHash.put(addr, name);
addrHash.put(name, addr);
return addr;
}
}
public static void reset() {
if (nameHash != null )
nameHash.clear();
if (addrHash != null )
addrHash.clear();
}
}
//protected static Hashtable<dstAddr,String> nameHash;
public Traffic() {vlan = 0; dstAddr = null; dstAddrPrefixLen = 0; protoPorts = new Hashtable<String,ArrayList<Integer>>();}
public Traffic(int vlan, InetAddress dstAddr, int dstAddrPrefixLen) {
this();
this.vlan = vlan; this.dstAddr = dstAddr; this.dstAddrPrefixLen = dstAddrPrefixLen;
}
public Traffic(Traffic other) {
this();
this.vlan = other.vlan; this.dstAddr = other.dstAddr; this.dstAddrPrefixLen = other.dstAddrPrefixLen;
this.protoPorts = other.protoPorts;
}
public void addProtocolPort(DFProtocol dfProtocol, int port) {
ArrayList<Integer> ports = protoPorts.get(dfProtocol.name());
if(ports == null) { // No such protocol
ports = new ArrayList<Integer>();
protoPorts.put(dfProtocol.name(), ports);
}
if(port != 0) ports.add(port);
}
public void setProtocolPort(DFProtocol dfProtocol, int port) {
protoPorts.clear();
ArrayList<Integer> ports = new ArrayList<Integer>();
protoPorts.put(dfProtocol.name(), ports);
if(port != 0) ports.add(port);
}
public TrafficMatch match(int vlan, InetAddress dstAddr, DFProtocol dfProtocol, int dstPort) throws ExceptionControlApp {
if(this.vlan != vlan) return TrafficMatch.NO;
if(this.dstAddr == null || dstAddr == null) return TrafficMatch.NO;
TrafficMatch dstAddrMatch;
TrafficMatch protoMatch;
TrafficMatch portMatch;
/* Check dstAddr match or containment. If neither return immediately with TrafficMatch.NO */
if(this.dstAddr.equals(dstAddr)) {
dstAddrMatch = TrafficMatch.MATCH;
} else {
Subnet subnet = null;
try {
subnet = new Subnet(this.dstAddr, dstAddrPrefixLen);
} catch (Throwable e) {
log.error("Failed to construct Subnet. " + this.dstAddr + ". " + e.getLocalizedMessage());
FMHolder.get().getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
throw new ExceptionControlApp("Failed to construct Subnet. + ", e);
}
// Resolve destination address match
if(! subnet.inSubnet(dstAddr))
return TrafficMatch.NO;
dstAddrMatch = TrafficMatch.CONTAIN;
}
/* Empty protocols hashtable means all protocols. Empty port list means all ports (for that protocol) */
if(protoPorts==null || protoPorts.isEmpty()) return TrafficMatch.CONTAIN;// Regardless whether dstAddr contains or matches
/* Check protocol match/containment */
List<Integer> ports = protoPorts.get(dfProtocol.name());
if(ports == null) return TrafficMatch.NO; // Did not find the matched protocol in the existing ones.
protoMatch = (protoPorts.size() > 1) ? TrafficMatch.CONTAIN : TrafficMatch.MATCH;
if(dfProtocol != DFProtocol.TCP && dfProtocol != DFProtocol.UDP) { // Ports only in L4 protocols
if(dstAddrMatch == TrafficMatch.MATCH && protoMatch == TrafficMatch.MATCH)
return TrafficMatch.MATCH;
else
return TrafficMatch.CONTAIN;
}
/* Compare ports (of the tcp or udp protocol) */
if(ports.isEmpty() || (ports.size() == 1 && ports.get(0) == 0 ))
portMatch = (dstPort == 0) ? TrafficMatch.MATCH : TrafficMatch.CONTAIN;
else {
if(!ports.contains(dstPort)) return TrafficMatch.NO; // No match with any monitored port in the matched protocol
portMatch = (ports.size() > 1) ? TrafficMatch.CONTAIN : TrafficMatch.MATCH;
}
/* Finally, check dstAddr, proto and port match or containment */
if(dstAddrMatch == TrafficMatch.MATCH && protoMatch == TrafficMatch.MATCH && portMatch == TrafficMatch.MATCH)
return TrafficMatch.MATCH;
else
return TrafficMatch.CONTAIN;
}
}