| /* |
| * Copyright 2015-present Open Networking Laboratory |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * Originally created by Pengfei Lu, Network and Cloud Computing Laboratory, Dalian University of Technology, China |
| * Advisers: Keqiu Li, Heng Qi and Haisheng Yu |
| * This work is supported by the State Key Program of National Natural Science of China(Grant No. 61432002) |
| * and Prospective Research Project on Future Networks in Jiangsu Future Networks Innovation Institute. |
| */ |
| package org.onosproject.acl; |
| |
| import com.google.common.base.MoreObjects; |
| import org.onlab.packet.IPv4; |
| import org.onlab.packet.Ip4Prefix; |
| import org.onosproject.core.IdGenerator; |
| |
| import java.util.Objects; |
| |
| import static com.google.common.base.Preconditions.checkNotNull; |
| import static com.google.common.base.Preconditions.checkState; |
| |
| /** |
| * ACL rule class. |
| */ |
| public final class AclRule { |
| |
| private final RuleId id; |
| |
| private final Ip4Prefix srcIp; |
| private final Ip4Prefix dstIp; |
| private final byte ipProto; |
| private final short dstTpPort; |
| private final Action action; |
| |
| private static IdGenerator idGenerator; |
| |
| /** |
| * Enum type for ACL rule's action. |
| */ |
| public enum Action { |
| DENY, ALLOW |
| } |
| |
| /** |
| * Constructor for serializer. |
| */ |
| private AclRule() { |
| this.id = null; |
| this.srcIp = null; |
| this.dstIp = null; |
| this.ipProto = 0; |
| this.dstTpPort = 0; |
| this.action = null; |
| } |
| |
| /** |
| * Create a new ACL rule. |
| * |
| * @param srcIp source IP address |
| * @param dstIp destination IP address |
| * @param ipProto IP protocol |
| * @param dstTpPort destination transport layer port |
| * @param action ACL rule's action |
| */ |
| private AclRule(Ip4Prefix srcIp, Ip4Prefix dstIp, byte ipProto, |
| short dstTpPort, Action action) { |
| checkState(idGenerator != null, "Id generator is not bound."); |
| this.id = RuleId.valueOf(idGenerator.getNewId()); |
| this.srcIp = srcIp; |
| this.dstIp = dstIp; |
| this.ipProto = ipProto; |
| this.dstTpPort = dstTpPort; |
| this.action = action; |
| } |
| |
| /** |
| * Check if the first CIDR address is in (or the same as) the second CIDR address. |
| */ |
| private boolean checkCidrInCidr(Ip4Prefix cidrAddr1, Ip4Prefix cidrAddr2) { |
| if (cidrAddr2 == null) { |
| return true; |
| } else if (cidrAddr1 == null) { |
| return false; |
| } |
| if (cidrAddr1.prefixLength() < cidrAddr2.prefixLength()) { |
| return false; |
| } |
| int offset = 32 - cidrAddr2.prefixLength(); |
| |
| int cidr1Prefix = cidrAddr1.address().toInt(); |
| int cidr2Prefix = cidrAddr2.address().toInt(); |
| cidr1Prefix = cidr1Prefix >> offset; |
| cidr2Prefix = cidr2Prefix >> offset; |
| cidr1Prefix = cidr1Prefix << offset; |
| cidr2Prefix = cidr2Prefix << offset; |
| |
| return (cidr1Prefix == cidr2Prefix); |
| } |
| |
| /** |
| * Check if this ACL rule match the given ACL rule. |
| * |
| * @param r ACL rule to check against |
| * @return true if this ACL rule matches the given ACL ruleule. |
| */ |
| public boolean checkMatch(AclRule r) { |
| return (this.dstTpPort == r.dstTpPort || r.dstTpPort == 0) |
| && (this.ipProto == r.ipProto || r.ipProto == 0) |
| && (checkCidrInCidr(this.srcIp(), r.srcIp())) |
| && (checkCidrInCidr(this.dstIp(), r.dstIp())); |
| } |
| |
| /** |
| * Returns a new ACL rule builder. |
| * |
| * @return ACL rule builder |
| */ |
| public static Builder builder() { |
| return new Builder(); |
| } |
| |
| /** |
| * Builder of an ACL rule. |
| */ |
| public static final class Builder { |
| |
| private Ip4Prefix srcIp = null; |
| private Ip4Prefix dstIp = null; |
| private byte ipProto = 0; |
| private short dstTpPort = 0; |
| private Action action = Action.DENY; |
| |
| private Builder() { |
| // Hide constructor |
| } |
| |
| /** |
| * Sets the source IP address for the ACL rule that will be built. |
| * |
| * @param srcIp source IP address to use for built ACL rule |
| * @return this builder |
| */ |
| public Builder srcIp(Ip4Prefix srcIp) { |
| this.srcIp = srcIp; |
| return this; |
| } |
| |
| /** |
| * Sets the destination IP address for the ACL rule that will be built. |
| * |
| * @param dstIp destination IP address to use for built ACL rule |
| * @return this builder |
| */ |
| public Builder dstIp(Ip4Prefix dstIp) { |
| this.dstIp = dstIp; |
| return this; |
| } |
| |
| /** |
| * Sets the IP protocol for the ACL rule that will be built. |
| * |
| * @param ipProto IP protocol to use for built ACL rule |
| * @return this builder |
| */ |
| public Builder ipProto(byte ipProto) { |
| this.ipProto = ipProto; |
| return this; |
| } |
| |
| /** |
| * Sets the destination transport layer port for the ACL rule that will be built. |
| * |
| * @param dstTpPort destination transport layer port to use for built ACL rule |
| * @return this builder |
| */ |
| public Builder dstTpPort(short dstTpPort) { |
| if ((ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP)) { |
| this.dstTpPort = dstTpPort; |
| } |
| return this; |
| } |
| |
| /** |
| * Sets the action for the ACL rule that will be built. |
| * |
| * @param action action to use for built ACL rule |
| * @return this builder |
| */ |
| public Builder action(Action action) { |
| this.action = action; |
| return this; |
| } |
| |
| /** |
| * Builds an ACL rule from the accumulated parameters. |
| * |
| * @return ACL rule instance |
| */ |
| public AclRule build() { |
| checkState(srcIp != null && dstIp != null, "Either srcIp or dstIp must be assigned."); |
| checkState(ipProto == 0 || ipProto == IPv4.PROTOCOL_ICMP |
| || ipProto == IPv4.PROTOCOL_TCP || ipProto == IPv4.PROTOCOL_UDP, |
| "ipProto must be assigned to TCP, UDP, or ICMP."); |
| return new AclRule(srcIp, dstIp, ipProto, dstTpPort, action); |
| } |
| |
| } |
| |
| /** |
| * Binds an id generator for unique ACL rule id generation. |
| * <p> |
| * Note: A generator cannot be bound if there is already a generator bound. |
| * |
| * @param newIdGenerator id generator |
| */ |
| public static void bindIdGenerator(IdGenerator newIdGenerator) { |
| checkState(idGenerator == null, "Id generator is already bound."); |
| idGenerator = checkNotNull(newIdGenerator); |
| } |
| |
| public RuleId id() { |
| return id; |
| } |
| |
| public Ip4Prefix srcIp() { |
| return srcIp; |
| } |
| |
| public Ip4Prefix dstIp() { |
| return this.dstIp; |
| } |
| |
| public byte ipProto() { |
| return ipProto; |
| } |
| |
| public short dstTpPort() { |
| return dstTpPort; |
| } |
| |
| public Action action() { |
| return action; |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hash(action, id.fingerprint(), ipProto, srcIp, dstIp, dstTpPort); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj instanceof AclRule) { |
| AclRule that = (AclRule) obj; |
| return Objects.equals(id, that.id) && |
| Objects.equals(srcIp, that.srcIp) && |
| Objects.equals(dstIp, that.dstIp) && |
| Objects.equals(ipProto, that.ipProto) && |
| Objects.equals(dstTpPort, that.dstTpPort) && |
| Objects.equals(action, that.action); |
| } |
| return false; |
| } |
| |
| @Override |
| public String toString() { |
| return MoreObjects.toStringHelper(this) |
| .omitNullValues() |
| .add("id", id) |
| .add("srcIp", srcIp) |
| .add("dstIp", dstIp) |
| .add("ipProto", ipProto) |
| .add("dstTpPort", dstTpPort) |
| .add("action", action) |
| .toString(); |
| } |
| |
| } |