package org.batfish.datamodel; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import com.fasterxml.jackson.annotation.JsonPropertyDescription; public class HeaderSpace implements Serializable { /** * */ private static final long serialVersionUID = 1L; private static boolean rangesContain(Collection<SubRange> ranges, int num) { for (SubRange range : ranges) { if (range.getStart() <= num && num <= range.getEnd()) { return true; } } return false; } private static boolean wildcardsContain(Collection<IpWildcard> wildcards, Ip ip) { for (IpWildcard wildcard : wildcards) { if (wildcard.contains(ip)) { return true; } } return false; } private SortedSet<Integer> _dscps; private SortedSet<IpWildcard> _dstIps; private SortedSet<SubRange> _dstPorts; private SortedSet<Protocol> _dstProtocols; private SortedSet<Integer> _ecns; private SortedSet<SubRange> _fragmentOffsets; private SortedSet<SubRange> _icmpCodes; private SortedSet<SubRange> _icmpTypes; private SortedSet<IpProtocol> _ipProtocols; private boolean _negate; private SortedSet<Integer> _notDscps; private SortedSet<IpWildcard> _notDstIps; private SortedSet<SubRange> _notDstPorts; private SortedSet<Protocol> _notDstProtocols; private SortedSet<Integer> _notEcns; private SortedSet<SubRange> _notFragmentOffsets; private SortedSet<SubRange> _notIcmpCodes; private SortedSet<SubRange> _notIcmpTypes; private SortedSet<IpProtocol> _notIpProtocols; private SortedSet<SubRange> _notPacketLengths; private SortedSet<IpWildcard> _notSrcIps; private SortedSet<SubRange> _notSrcPorts; private SortedSet<Protocol> _notSrcProtocols; private SortedSet<SubRange> _packetLengths; private SortedSet<IpWildcard> _srcIps; private SortedSet<IpWildcard> _srcOrDstIps; private SortedSet<SubRange> _srcOrDstPorts; private SortedSet<Protocol> _srcOrDstProtocols; private SortedSet<SubRange> _srcPorts; private SortedSet<Protocol> _srcProtocols; private SortedSet<State> _states; private List<TcpFlags> _tcpFlags; public HeaderSpace() { _dscps = new TreeSet<>(); _dstIps = new TreeSet<>(); _dstPorts = new TreeSet<>(); _dstProtocols = new TreeSet<>(); _ecns = new TreeSet<>(); _fragmentOffsets = new TreeSet<>(); _ipProtocols = new TreeSet<>(); _packetLengths = new TreeSet<>(); _srcIps = new TreeSet<>(); _srcOrDstIps = new TreeSet<>(); _srcOrDstPorts = new TreeSet<>(); _srcOrDstProtocols = new TreeSet<>(); _srcPorts = new TreeSet<>(); _srcProtocols = new TreeSet<>(); _icmpTypes = new TreeSet<>(); _icmpCodes = new TreeSet<>(); _states = new TreeSet<>(); _tcpFlags = new ArrayList<>(); _notDscps = new TreeSet<>(); _notDstIps = new TreeSet<>(); _notDstPorts = new TreeSet<>(); _notDstProtocols = new TreeSet<>(); _notEcns = new TreeSet<>(); _notFragmentOffsets = new TreeSet<>(); _notIcmpCodes = new TreeSet<>(); _notIcmpTypes = new TreeSet<>(); _notIpProtocols = new TreeSet<>(); _notPacketLengths = new TreeSet<>(); _notSrcIps = new TreeSet<>(); _notSrcPorts = new TreeSet<>(); _notSrcProtocols = new TreeSet<>(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } HeaderSpace other = (HeaderSpace) obj; if (!_dscps.equals(other._dscps)) { return false; } if (!_dstIps.equals(other._dstIps)) { return false; } if (!_dstPorts.equals(other._dstPorts)) { return false; } if (!_dstProtocols.equals(other._dstProtocols)) { return false; } if (!_ecns.equals(other._ecns)) { return false; } if (!_fragmentOffsets.equals(other._fragmentOffsets)) { return false; } if (!_icmpCodes.equals(other._icmpCodes)) { return false; } if (!_icmpTypes.equals(other._icmpTypes)) { return false; } if (!_ipProtocols.equals(other._ipProtocols)) { return false; } if (_negate != other._negate) { return false; } if (!_notDscps.equals(other._notDscps)) { return false; } if (!_notDstIps.equals(other._notDstIps)) { return false; } if (!_notDstPorts.equals(other._notDstPorts)) { return false; } if (!_notDstProtocols.equals(other._notDstProtocols)) { return false; } if (!_notEcns.equals(other._notEcns)) { return false; } if (!_notFragmentOffsets.equals(other._notFragmentOffsets)) { return false; } if (!_notIcmpCodes.equals(other._notIcmpCodes)) { return false; } if (!_notIcmpTypes.equals(other._notIcmpTypes)) { return false; } if (!_notIpProtocols.equals(other._notIpProtocols)) { return false; } if (!_notPacketLengths.equals(other._notPacketLengths)) { return false; } if (!_notSrcIps.equals(other._notSrcIps)) { return false; } if (!_notSrcPorts.equals(other._notSrcPorts)) { return false; } if (!_notSrcProtocols.equals(other._notSrcProtocols)) { return false; } if (!_packetLengths.equals(other._packetLengths)) { return false; } if (!_srcIps.equals(other._srcIps)) { return false; } if (!_srcOrDstIps.equals(other._srcOrDstIps)) { return false; } if (!_srcOrDstPorts.equals(other._srcOrDstPorts)) { return false; } if (!_srcOrDstProtocols.equals(other._srcOrDstProtocols)) { return false; } if (!_srcPorts.equals(other._srcPorts)) { return false; } if (!_srcProtocols.equals(other._srcProtocols)) { return false; } if (!_states.equals(other._states)) { return false; } if (!_tcpFlags.equals(other._tcpFlags)) { return false; } return true; } @JsonPropertyDescription("A set of acceptable DSCP values for a packet") public SortedSet<Integer> getDscps() { return _dscps; } @JsonPropertyDescription("A space of acceptable destination IP addresses for a packet") public SortedSet<IpWildcard> getDstIps() { return _dstIps; } @JsonPropertyDescription("A set of acceptable destination port ranges for a TCP/UDP packet") public SortedSet<SubRange> getDstPorts() { return _dstPorts; } public SortedSet<Protocol> getDstProtocols() { return _dstProtocols; } @JsonPropertyDescription("A set of acceptable ECN values for a packet") public SortedSet<Integer> getEcns() { return _ecns; } @JsonPropertyDescription("A set of acceptable fragment offsets for a UDP packet") public SortedSet<SubRange> getFragmentOffsets() { return _fragmentOffsets; } @JsonPropertyDescription("A set of acceptable ICMP code ranges for an ICMP packet") public SortedSet<SubRange> getIcmpCodes() { return _icmpCodes; } @JsonPropertyDescription("A set of acceptable ICMP type ranges for an ICMP packet") public SortedSet<SubRange> getIcmpTypes() { return _icmpTypes; } @JsonPropertyDescription("A set of acceptable IP protocols for a packet") public SortedSet<IpProtocol> getIpProtocols() { return _ipProtocols; } @JsonPropertyDescription("Determines whether to match the complement of the stated criteria of this header space") public boolean getNegate() { return _negate; } @JsonPropertyDescription("A set of unacceptable DSCP values for a packet") public SortedSet<Integer> getNotDscps() { return _notDscps; } @JsonPropertyDescription("A space of unacceptable destination IP addresses for a packet") public SortedSet<IpWildcard> getNotDstIps() { return _notDstIps; } @JsonPropertyDescription("A set of unacceptable destination port ranges for a TCP/UDP packet") public SortedSet<SubRange> getNotDstPorts() { return _notDstPorts; } public SortedSet<Protocol> getNotDstProtocols() { return _notDstProtocols; } @JsonPropertyDescription("A set of unacceptable ECN values for a packet") public SortedSet<Integer> getNotEcns() { return _notEcns; } @JsonPropertyDescription("A set of unacceptable fragment offsets for a UDP packet") public SortedSet<SubRange> getNotFragmentOffsets() { return _notFragmentOffsets; } @JsonPropertyDescription("A set of unacceptable ICMP code ranges for an ICMP packet") public SortedSet<SubRange> getNotIcmpCodes() { return _notIcmpCodes; } @JsonPropertyDescription("A set of unacceptable ICMP type ranges for an ICMP packet") public SortedSet<SubRange> getNotIcmpTypes() { return _notIcmpTypes; } @JsonPropertyDescription("A set of unacceptable IP protocols for a packet") public SortedSet<IpProtocol> getNotIpProtocols() { return _notIpProtocols; } public SortedSet<SubRange> getNotPacketLengths() { return _notPacketLengths; } @JsonPropertyDescription("A space of unacceptable source IP addresses for a packet") public SortedSet<IpWildcard> getNotSrcIps() { return _notSrcIps; } @JsonPropertyDescription("A set of unacceptable source port ranges for a TCP/UDP packet") public SortedSet<SubRange> getNotSrcPorts() { return _notSrcPorts; } public SortedSet<Protocol> getNotSrcProtocols() { return _notSrcProtocols; } public SortedSet<SubRange> getPacketLengths() { return _packetLengths; } @JsonPropertyDescription("A space of acceptable source IP addresses for a packet") public SortedSet<IpWildcard> getSrcIps() { return _srcIps; } @JsonPropertyDescription("A space of IP addresses within which either the source or the destination IP of a packet must fall for acceptance") public SortedSet<IpWildcard> getSrcOrDstIps() { return _srcOrDstIps; } @JsonPropertyDescription("A set of ranges within which either the source or the destination port of a TCP/UDP packet must fall for acceptance") public SortedSet<SubRange> getSrcOrDstPorts() { return _srcOrDstPorts; } public SortedSet<Protocol> getSrcOrDstProtocols() { return _srcOrDstProtocols; } @JsonPropertyDescription("A set of acceptable source port ranges for a TCP/UDP packet") public SortedSet<SubRange> getSrcPorts() { return _srcPorts; } public SortedSet<Protocol> getSrcProtocols() { return _srcProtocols; } @JsonPropertyDescription("A set of acceptable abstract firewall states for a packet to match") public SortedSet<State> getStates() { return _states; } @JsonPropertyDescription("A set of acceptable TCP flag bitmasks for a TCP packet to match") public List<TcpFlags> getTcpFlags() { return _tcpFlags; } @Override public int hashCode() { // TODO: implement better hashcode return 0; } public boolean matches(Flow flow) { if (!_dscps.isEmpty() && !_dscps.contains(flow.getDscp())) { return false; } if (!_notDscps.isEmpty() && _notDscps.contains(flow.getDscp())) { return false; } if (!_dstIps.isEmpty() && !wildcardsContain(_dstIps, flow.getDstIp())) { return false; } if (!_notDstIps.isEmpty() && wildcardsContain(_notDstIps, flow.getDstIp())) { return false; } if (!_dstPorts.isEmpty() && !rangesContain(_dstPorts, flow.getDstPort())) { return false; } if (!_notDstPorts.isEmpty() && rangesContain(_notDstPorts, flow.getDstPort())) { return false; } if (!_dstProtocols.isEmpty()) { boolean match = false; for (Protocol dstProtocol : _dstProtocols) { if (dstProtocol.getIpProtocol().equals(flow.getIpProtocol())) { match = true; Integer dstPort = dstProtocol.getPort(); if (dstPort != null && !dstPort.equals(flow.getDstPort())) { match = false; } if (match) { break; } } } if (!match) { return false; } } if (!_notDstProtocols.isEmpty()) { boolean match = false; for (Protocol notDstProtocol : _notDstProtocols) { if (notDstProtocol.getIpProtocol().equals(flow.getIpProtocol())) { match = true; Integer dstPort = notDstProtocol.getPort(); if (dstPort != null && !dstPort.equals(flow.getDstPort())) { match = false; } if (match) { return false; } } } } if (!_fragmentOffsets.isEmpty() && !rangesContain(_fragmentOffsets, flow.getFragmentOffset())) { return false; } if (!_notFragmentOffsets.isEmpty() && rangesContain(_notFragmentOffsets, flow.getFragmentOffset())) { return false; } if (!_icmpCodes.isEmpty() && !rangesContain(_icmpCodes, flow.getIcmpCode())) { return false; } if (!_notIcmpCodes.isEmpty() && rangesContain(_notIcmpCodes, flow.getFragmentOffset())) { return false; } if (!_icmpTypes.isEmpty() && !rangesContain(_icmpTypes, flow.getIcmpType())) { return false; } if (!_notIcmpTypes.isEmpty() && rangesContain(_notIcmpTypes, flow.getFragmentOffset())) { return false; } if (!_ipProtocols.isEmpty() && !_ipProtocols.contains(flow.getIpProtocol())) { return false; } if (!_notIpProtocols.isEmpty() && _notIpProtocols.contains(flow.getIpProtocol())) { return false; } if (!_packetLengths.isEmpty() && !rangesContain(_packetLengths, flow.getPacketLength())) { return false; } if (!_notPacketLengths.isEmpty() && rangesContain(_notPacketLengths, flow.getPacketLength())) { return false; } if (!_srcOrDstIps.isEmpty() && !(wildcardsContain(_srcOrDstIps, flow.getSrcIp()) || wildcardsContain(_srcOrDstIps, flow.getDstIp()))) { return false; } if (!_srcOrDstPorts.isEmpty() && !(rangesContain(_srcOrDstPorts, flow.getSrcPort()) || rangesContain(_srcOrDstPorts, flow.getDstPort()))) { return false; } if (!_srcOrDstProtocols.isEmpty()) { boolean match = false; for (Protocol protocol : _srcOrDstProtocols) { if (protocol.getIpProtocol().equals(flow.getIpProtocol())) { match = true; Integer port = protocol.getPort(); if (port != null && !port.equals(flow.getDstPort()) && !port.equals(flow.getSrcPort())) { match = false; } if (match) { break; } } } if (!match) { return false; } } if (!_srcIps.isEmpty() && !wildcardsContain(_srcIps, flow.getSrcIp())) { return false; } if (!_notSrcIps.isEmpty() && wildcardsContain(_notSrcIps, flow.getSrcIp())) { return false; } if (!_srcPorts.isEmpty() && !rangesContain(_srcPorts, flow.getSrcPort())) { return false; } if (!_notSrcPorts.isEmpty() && rangesContain(_notSrcPorts, flow.getSrcPort())) { return false; } if (!_srcProtocols.isEmpty()) { boolean match = false; for (Protocol srcProtocol : _srcProtocols) { if (srcProtocol.getIpProtocol().equals(flow.getIpProtocol())) { match = true; Integer srcPort = srcProtocol.getPort(); if (srcPort != null && !srcPort.equals(flow.getSrcPort())) { match = false; } if (match) { break; } } } if (!match) { return false; } } if (!_notSrcProtocols.isEmpty()) { boolean match = false; for (Protocol notSrcProtocol : _notSrcProtocols) { if (notSrcProtocol.getIpProtocol().equals(flow.getIpProtocol())) { match = true; Integer srcPort = notSrcProtocol.getPort(); if (srcPort != null && !srcPort.equals(flow.getSrcPort())) { match = false; } if (match) { return false; } } } } if (!_states.isEmpty() && !_states.contains(flow.getState())) { return false; } if (!_tcpFlags.isEmpty()) { boolean matchTcpFlags = false; for (TcpFlags tcpFlags : _tcpFlags) { if (tcpFlags.getUseAck() && tcpFlags.getAck() ^ (flow.getTcpFlagsAck() == 0)) { continue; } if (tcpFlags.getUseCwr() && tcpFlags.getCwr() ^ (flow.getTcpFlagsCwr() == 0)) { continue; } if (tcpFlags.getUseEce() && tcpFlags.getEce() ^ (flow.getTcpFlagsEce() == 0)) { continue; } if (tcpFlags.getUseFin() && tcpFlags.getFin() ^ (flow.getTcpFlagsFin() == 0)) { continue; } if (tcpFlags.getUsePsh() && tcpFlags.getPsh() ^ (flow.getTcpFlagsPsh() == 0)) { continue; } if (tcpFlags.getUseRst() && tcpFlags.getRst() ^ (flow.getTcpFlagsRst() == 0)) { continue; } if (tcpFlags.getUseSyn() && tcpFlags.getSyn() ^ (flow.getTcpFlagsSyn() == 0)) { continue; } if (tcpFlags.getUseUrg() && tcpFlags.getUrg() ^ (flow.getTcpFlagsUrg() == 0)) { continue; } matchTcpFlags = true; break; } if (!matchTcpFlags) { return false; } } return true; } public void setDscps(SortedSet<Integer> dscps) { _dscps = dscps; } public void setDstIps(SortedSet<IpWildcard> dstIps) { _dstIps = dstIps; } public void setDstPorts(SortedSet<SubRange> dstPorts) { _dstPorts = dstPorts; } public void setDstProtocols(SortedSet<Protocol> dstProtocols) { _dstProtocols = dstProtocols; } public void setEcns(SortedSet<Integer> ecns) { _ecns = ecns; } public void setFragmentOffsets(SortedSet<SubRange> fragmentOffsets) { _fragmentOffsets = fragmentOffsets; } public void setIcmpCodes(SortedSet<SubRange> icmpCodes) { _icmpCodes = icmpCodes; } public void setIcmpTypes(SortedSet<SubRange> icmpTypes) { _icmpTypes = icmpTypes; } public void setIpProtocols(SortedSet<IpProtocol> ipProtocols) { _ipProtocols = ipProtocols; } public void setNegate(boolean negate) { _negate = negate; } public void setNotDscps(SortedSet<Integer> notDscps) { _notDscps = notDscps; } public void setNotDstIps(SortedSet<IpWildcard> notDstIps) { _notDstIps = notDstIps; } public void setNotDstPorts(SortedSet<SubRange> notDstPorts) { _notDstPorts = notDstPorts; } public void setNotDstProtocols(SortedSet<Protocol> notDstProtocols) { _notDstProtocols = notDstProtocols; } public void setNotEcns(SortedSet<Integer> notEcns) { _notEcns = notEcns; } public void setNotFragmentOffsets(SortedSet<SubRange> notFragmentOffsets) { _notFragmentOffsets = notFragmentOffsets; } public void setNotIcmpCodes(SortedSet<SubRange> notIcmpCodes) { _notIcmpCodes = notIcmpCodes; } public void setNotIcmpTypes(SortedSet<SubRange> notIcmpTypes) { _notIcmpTypes = notIcmpTypes; } public void setNotIpProtocols(SortedSet<IpProtocol> notIpProtocols) { _notIpProtocols = notIpProtocols; } public void setNotPacketLengths(SortedSet<SubRange> notPacketLengths) { _notPacketLengths = notPacketLengths; } public void setNotSrcIps(SortedSet<IpWildcard> notSrcIps) { _notSrcIps = notSrcIps; } public void setNotSrcPorts(SortedSet<SubRange> notSrcPorts) { _notSrcPorts = notSrcPorts; } public void setNotSrcProtocols(SortedSet<Protocol> notSrcProtocols) { _notSrcProtocols = notSrcProtocols; } public void setPacketLengths(SortedSet<SubRange> packetLengths) { _packetLengths = packetLengths; } public void setSrcIps(SortedSet<IpWildcard> srcIps) { _srcIps = srcIps; } public void setSrcOrDstIps(SortedSet<IpWildcard> srcOrDstIps) { _srcOrDstIps = srcOrDstIps; } public void setSrcOrDstPorts(SortedSet<SubRange> srcOrDstPorts) { _srcOrDstPorts = srcOrDstPorts; } public void setSrcOrDstProtocols(SortedSet<Protocol> srcOrDstProtocols) { _srcOrDstProtocols = srcOrDstProtocols; } public void setSrcPorts(SortedSet<SubRange> srcPorts) { _srcPorts = srcPorts; } public void setSrcProtocols(SortedSet<Protocol> srcProtocols) { _srcProtocols = srcProtocols; } public void setStates(SortedSet<State> states) { _states = states; } public void setTcpFlags(List<TcpFlags> tcpFlags) { _tcpFlags = tcpFlags; } @Override public String toString() { return "[Protocols:" + _ipProtocols.toString() + ", SrcIps:" + _srcIps + ", NotSrcIps:" + _notSrcIps + ", DstIps:" + _dstIps + ", NotDstIps:" + _notDstIps + ", SrcOrDstIps:" + _srcOrDstIps + ", SrcPorts:" + _srcPorts + ", NotSrcPorts:" + _notSrcPorts + ", DstPorts:" + _dstPorts + ", NotDstPorts:" + _notDstPorts + ", SrcOrDstPorts:" + _srcOrDstPorts + ", SrcProtocols:" + _srcProtocols + ", NotSrcProtocols:" + _notSrcProtocols + ", DstProtocols:" + _dstProtocols + ", NotDstProtocols:" + _notDstProtocols + ", SrcOrDstProtocols:" + _srcOrDstProtocols + ", Dscps: " + _dscps.toString() + ", NotDscps: " + _notDscps.toString() + ", Ecns: " + _ecns.toString() + ", NotEcns: " + _notEcns.toString() + ", FragmentOffsets: " + _fragmentOffsets.toString() + ", NotFragmentOffsets: " + _notFragmentOffsets.toString() + ", IcmpType:" + _icmpTypes + ", NotIcmpType:" + _notIcmpTypes + ", IcmpCode:" + _icmpCodes + ", NotIcmpCode:" + _notIcmpCodes + ", PacketLengths:" + _packetLengths.toString() + ", NotPacketLengths:" + _notPacketLengths + ", States:" + _states.toString() + ", TcpFlags:" + _tcpFlags.toString() + "]"; } public final boolean unrestricted() { boolean ret = _dscps.isEmpty() && _notDscps.isEmpty() && _dstIps.isEmpty() && _notDstIps.isEmpty() && _dstPorts.isEmpty() && _notDstPorts.isEmpty() && _dstProtocols.isEmpty() && _notDstProtocols.isEmpty() && _ecns.isEmpty() && _notEcns.isEmpty() && _fragmentOffsets.isEmpty() && _notFragmentOffsets.isEmpty() && _icmpCodes.isEmpty() && _notIcmpCodes.isEmpty() && _icmpTypes.isEmpty() && _notIcmpTypes.isEmpty() && _ipProtocols.isEmpty() && _notIpProtocols.isEmpty() && _packetLengths.isEmpty() && _notPacketLengths.isEmpty() && _srcIps.isEmpty() && _notSrcIps.isEmpty() && _srcOrDstIps.isEmpty() && _srcOrDstPorts.isEmpty() && _srcOrDstProtocols.isEmpty() && _srcPorts.isEmpty() && _notSrcPorts.isEmpty() && _srcProtocols.isEmpty() && _notSrcProtocols.isEmpty() && _states.isEmpty() && _tcpFlags.isEmpty(); return ret; } }