| package net.floodlightcontroller.firewall; |
| |
| import org.openflow.protocol.OFMatch; |
| |
| import net.floodlightcontroller.packet.Ethernet; |
| import net.floodlightcontroller.packet.IPacket; |
| import net.floodlightcontroller.packet.IPv4; |
| import net.floodlightcontroller.packet.TCP; |
| import net.floodlightcontroller.packet.UDP; |
| |
| public class FirewallRule implements Comparable<FirewallRule> { |
| public int ruleid; |
| |
| public long dpid; |
| public short in_port; |
| public long dl_src; |
| public long dl_dst; |
| public short dl_type; |
| public int nw_src_prefix; |
| public int nw_src_maskbits; |
| public int nw_dst_prefix; |
| public int nw_dst_maskbits; |
| public short nw_proto; |
| public short tp_src; |
| public short tp_dst; |
| |
| public boolean wildcard_dpid; |
| public boolean wildcard_in_port; |
| public boolean wildcard_dl_src; |
| public boolean wildcard_dl_dst; |
| public boolean wildcard_dl_type; |
| public boolean wildcard_nw_src; |
| public boolean wildcard_nw_dst; |
| public boolean wildcard_nw_proto; |
| public boolean wildcard_tp_src; |
| public boolean wildcard_tp_dst; |
| |
| public int priority = 0; |
| |
| public FirewallAction action; |
| |
| public enum FirewallAction { |
| /* |
| * DENY: Deny rule |
| * ALLOW: Allow rule |
| */ |
| DENY, ALLOW |
| } |
| |
| public FirewallRule() { |
| this.in_port = 0; |
| this.dl_src = 0; |
| this.nw_src_prefix = 0; |
| this.nw_src_maskbits = 0; |
| this.dl_dst = 0; |
| this.nw_proto = 0; |
| this.tp_src = 0; |
| this.tp_dst = 0; |
| this.dl_dst = 0; |
| this.nw_dst_prefix = 0; |
| this.nw_dst_maskbits = 0; |
| this.dpid = -1; |
| this.wildcard_dpid = true; |
| this.wildcard_in_port = true; |
| this.wildcard_dl_src = true; |
| this.wildcard_dl_dst = true; |
| this.wildcard_dl_type = true; |
| this.wildcard_nw_src = true; |
| this.wildcard_nw_dst = true; |
| this.wildcard_nw_proto = true; |
| this.wildcard_tp_src = true; |
| this.wildcard_tp_dst = true; |
| this.priority = 0; |
| this.action = FirewallAction.ALLOW; |
| this.ruleid = 0; |
| } |
| |
| /** |
| * Generates a unique ID for the instance |
| * |
| * @return int representing the unique id |
| */ |
| public int genID() { |
| int uid = this.hashCode(); |
| if (uid < 0) { |
| uid = Math.abs(uid); |
| uid = uid * 15551; |
| } |
| return uid; |
| } |
| |
| /** |
| * Comparison method for Collections.sort method |
| * |
| * @param rule |
| * the rule to compare with |
| * @return number representing the result of comparison 0 if equal negative |
| * if less than 'rule' greater than zero if greater priority rule |
| * than 'rule' |
| */ |
| @Override |
| public int compareTo(FirewallRule rule) { |
| return this.priority - rule.priority; |
| } |
| |
| /** |
| * Determines if this instance matches an existing rule instance |
| * |
| * @param r |
| * : the FirewallRule instance to compare with |
| * @return boolean: true if a match is found |
| **/ |
| public boolean isSameAs(FirewallRule r) { |
| if (this.action != r.action |
| || this.wildcard_dl_type != r.wildcard_dl_type |
| || (this.wildcard_dl_type == false && this.dl_type == r.dl_type) |
| || this.wildcard_tp_src != r.wildcard_tp_src |
| || (this.wildcard_tp_src == false && this.tp_src != r.tp_src) |
| || this.wildcard_tp_dst != r.wildcard_tp_dst |
| || (this.wildcard_tp_dst == false &&this.tp_dst != r.tp_dst) |
| || this.wildcard_dpid != r.wildcard_dpid |
| || (this.wildcard_dpid == false && this.dpid != r.dpid) |
| || this.wildcard_in_port != r.wildcard_in_port |
| || (this.wildcard_in_port == false && this.in_port != r.in_port) |
| || this.wildcard_nw_src != r.wildcard_nw_src |
| || (this.wildcard_nw_src == false && (this.nw_src_prefix != r.nw_src_prefix || this.nw_src_maskbits != r.nw_src_maskbits)) |
| || this.wildcard_dl_src != r.wildcard_dl_src |
| || (this.wildcard_dl_src == false && this.dl_src != r.dl_src) |
| || this.wildcard_nw_proto != r.wildcard_nw_proto |
| || (this.wildcard_nw_proto == false && this.nw_proto != r.nw_proto) |
| || this.wildcard_nw_dst != r.wildcard_nw_dst |
| || (this.wildcard_nw_dst == false && (this.nw_dst_prefix != r.nw_dst_prefix || this.nw_dst_maskbits != r.nw_dst_maskbits)) |
| || this.wildcard_dl_dst != r.wildcard_dl_dst |
| || (this.wildcard_dl_dst == false && this.dl_dst != r.dl_dst)) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Matches this rule to a given flow - incoming packet |
| * |
| * @param switchDpid |
| * the Id of the connected switch |
| * @param inPort |
| * the switch port where the packet originated from |
| * @param packet |
| * the Ethernet packet that arrives at the switch |
| * @param wildcards |
| * the pair of wildcards (allow and deny) given by Firewall |
| * module that is used by the Firewall module's matchWithRule |
| * method to derive wildcards for the decision to be taken |
| * @return true if the rule matches the given packet-in, false otherwise |
| */ |
| public boolean matchesFlow(long switchDpid, short inPort, Ethernet packet, |
| WildcardsPair wildcards) { |
| IPacket pkt = packet.getPayload(); |
| |
| // dl_type type |
| IPv4 pkt_ip = null; |
| |
| // nw_proto types |
| TCP pkt_tcp = null; |
| UDP pkt_udp = null; |
| |
| // tp_src and tp_dst (tp port numbers) |
| short pkt_tp_src = 0; |
| short pkt_tp_dst = 0; |
| |
| // switchID matches? |
| if (wildcard_dpid == false && dpid != switchDpid) |
| return false; |
| |
| // in_port matches? |
| if (wildcard_in_port == false && in_port != inPort) |
| return false; |
| if (action == FirewallRule.FirewallAction.DENY) { |
| wildcards.drop &= ~OFMatch.OFPFW_IN_PORT; |
| } else { |
| wildcards.allow &= ~OFMatch.OFPFW_IN_PORT; |
| } |
| |
| // mac address (src and dst) match? |
| if (wildcard_dl_src == false |
| && dl_src != packet.getSourceMAC().toLong()) |
| return false; |
| if (action == FirewallRule.FirewallAction.DENY) { |
| wildcards.drop &= ~OFMatch.OFPFW_DL_SRC; |
| } else { |
| wildcards.allow &= ~OFMatch.OFPFW_DL_SRC; |
| } |
| |
| if (wildcard_dl_dst == false |
| && dl_dst != packet.getDestinationMAC().toLong()) |
| return false; |
| if (action == FirewallRule.FirewallAction.DENY) { |
| wildcards.drop &= ~OFMatch.OFPFW_DL_DST; |
| } else { |
| wildcards.allow &= ~OFMatch.OFPFW_DL_DST; |
| } |
| |
| // dl_type check: ARP, IP |
| |
| // if this is not an ARP rule but the pkt is ARP, |
| // return false match - no need to continue protocol specific check |
| if (wildcard_dl_type == false) { |
| if (dl_type == Ethernet.TYPE_ARP) { |
| if (packet.getEtherType() != Ethernet.TYPE_ARP) |
| return false; |
| else { |
| if (action == FirewallRule.FirewallAction.DENY) { |
| wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE; |
| } else { |
| wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE; |
| } |
| } |
| } else if (dl_type == Ethernet.TYPE_IPv4) { |
| if (packet.getEtherType() != Ethernet.TYPE_IPv4) |
| return false; |
| else { |
| if (action == FirewallRule.FirewallAction.DENY) { |
| wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO; |
| } else { |
| wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO; |
| } |
| // IP packets, proceed with ip address check |
| pkt_ip = (IPv4) pkt; |
| |
| // IP addresses (src and dst) match? |
| if (wildcard_nw_src == false |
| && this.matchIPAddress(nw_src_prefix, |
| nw_src_maskbits, pkt_ip.getSourceAddress()) == false) |
| return false; |
| if (action == FirewallRule.FirewallAction.DENY) { |
| wildcards.drop &= ~OFMatch.OFPFW_NW_SRC_ALL; |
| wildcards.drop |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT); |
| } else { |
| wildcards.allow &= ~OFMatch.OFPFW_NW_SRC_ALL; |
| wildcards.allow |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT); |
| } |
| |
| if (wildcard_nw_dst == false |
| && this.matchIPAddress(nw_dst_prefix, |
| nw_dst_maskbits, |
| pkt_ip.getDestinationAddress()) == false) |
| return false; |
| if (action == FirewallRule.FirewallAction.DENY) { |
| wildcards.drop &= ~OFMatch.OFPFW_NW_DST_ALL; |
| wildcards.drop |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT); |
| } else { |
| wildcards.allow &= ~OFMatch.OFPFW_NW_DST_ALL; |
| wildcards.allow |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT); |
| } |
| |
| // nw_proto check |
| if (wildcard_nw_proto == false) { |
| if (nw_proto == IPv4.PROTOCOL_TCP) { |
| if (pkt_ip.getProtocol() != IPv4.PROTOCOL_TCP) |
| return false; |
| else { |
| pkt_tcp = (TCP) pkt_ip.getPayload(); |
| pkt_tp_src = pkt_tcp.getSourcePort(); |
| pkt_tp_dst = pkt_tcp.getDestinationPort(); |
| } |
| } else if (nw_proto == IPv4.PROTOCOL_UDP) { |
| if (pkt_ip.getProtocol() != IPv4.PROTOCOL_UDP) |
| return false; |
| else { |
| pkt_udp = (UDP) pkt_ip.getPayload(); |
| pkt_tp_src = pkt_udp.getSourcePort(); |
| pkt_tp_dst = pkt_udp.getDestinationPort(); |
| } |
| } else if (nw_proto == IPv4.PROTOCOL_ICMP) { |
| if (pkt_ip.getProtocol() != IPv4.PROTOCOL_ICMP) |
| return false; |
| else { |
| // nothing more needed for ICMP |
| } |
| } |
| if (action == FirewallRule.FirewallAction.DENY) { |
| wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO; |
| } else { |
| wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO; |
| } |
| |
| // TCP/UDP source and destination ports match? |
| if (pkt_tcp != null || pkt_udp != null) { |
| // does the source port match? |
| if (tp_src != 0 && tp_src != pkt_tp_src) |
| return false; |
| if (action == FirewallRule.FirewallAction.DENY) { |
| wildcards.drop &= ~OFMatch.OFPFW_TP_SRC; |
| } else { |
| wildcards.allow &= ~OFMatch.OFPFW_TP_SRC; |
| } |
| |
| // does the destination port match? |
| if (tp_dst != 0 && tp_dst != pkt_tp_dst) |
| return false; |
| if (action == FirewallRule.FirewallAction.DENY) { |
| wildcards.drop &= ~OFMatch.OFPFW_TP_DST; |
| } else { |
| wildcards.allow &= ~OFMatch.OFPFW_TP_DST; |
| } |
| } |
| } |
| |
| } |
| } else { |
| // non-IP packet - not supported - report no match |
| return false; |
| } |
| } |
| if (action == FirewallRule.FirewallAction.DENY) { |
| wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE; |
| } else { |
| wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE; |
| } |
| |
| // all applicable checks passed |
| return true; |
| } |
| |
| /** |
| * Determines if rule's CIDR address matches IP address of the packet |
| * |
| * @param rulePrefix |
| * prefix part of the CIDR address |
| * @param ruleBits |
| * the size of mask of the CIDR address |
| * @param packetAddress |
| * the IP address of the incoming packet to match with |
| * @return true if CIDR address matches the packet's IP address, false |
| * otherwise |
| */ |
| protected boolean matchIPAddress(int rulePrefix, int ruleBits, |
| int packetAddress) { |
| boolean matched = true; |
| |
| int rule_iprng = 32 - ruleBits; |
| int rule_ipint = rulePrefix; |
| int pkt_ipint = packetAddress; |
| // if there's a subnet range (bits to be wildcarded > 0) |
| if (rule_iprng > 0) { |
| // right shift bits to remove rule_iprng of LSB that are to be |
| // wildcarded |
| rule_ipint = rule_ipint >> rule_iprng; |
| pkt_ipint = pkt_ipint >> rule_iprng; |
| // now left shift to return to normal range, except that the |
| // rule_iprng number of LSB |
| // are now zeroed |
| rule_ipint = rule_ipint << rule_iprng; |
| pkt_ipint = pkt_ipint << rule_iprng; |
| } |
| // check if we have a match |
| if (rule_ipint != pkt_ipint) |
| matched = false; |
| |
| return matched; |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 2521; |
| int result = super.hashCode(); |
| result = prime * result + (int) dpid; |
| result = prime * result + in_port; |
| result = prime * result + (int) dl_src; |
| result = prime * result + (int) dl_dst; |
| result = prime * result + dl_type; |
| result = prime * result + nw_src_prefix; |
| result = prime * result + nw_src_maskbits; |
| result = prime * result + nw_dst_prefix; |
| result = prime * result + nw_dst_maskbits; |
| result = prime * result + nw_proto; |
| result = prime * result + tp_src; |
| result = prime * result + tp_dst; |
| result = prime * result + action.ordinal(); |
| result = prime * result + priority; |
| result = prime * result + (new Boolean(wildcard_dpid)).hashCode(); |
| result = prime * result + (new Boolean(wildcard_in_port)).hashCode(); |
| result = prime * result + (new Boolean(wildcard_dl_src)).hashCode(); |
| result = prime * result + (new Boolean(wildcard_dl_dst)).hashCode(); |
| result = prime * result + (new Boolean(wildcard_dl_type)).hashCode(); |
| result = prime * result + (new Boolean(wildcard_nw_src)).hashCode(); |
| result = prime * result + (new Boolean(wildcard_nw_dst)).hashCode(); |
| result = prime * result + (new Boolean(wildcard_nw_proto)).hashCode(); |
| result = prime * result + (new Boolean(wildcard_tp_src)).hashCode(); |
| result = prime * result + (new Boolean(wildcard_tp_dst)).hashCode(); |
| return result; |
| } |
| } |