/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package com.cloud.network.element;
import java.util.ArrayList;
import java.util.List;
// Used for translation between MidoNet firewall rules and
// CloudStack firewall rules
import org.midonet.client.dto.DtoRule;
import org.midonet.client.resource.Rule;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.cloud.agent.api.to.FirewallRuleTO;
import com.cloud.agent.api.to.NetworkACLTO;
import com.cloud.agent.api.to.PortForwardingRuleTO;
public class SimpleFirewallRule {
public List<String> sourceCidrs;
public String protocol;
public String dstIp;
public int dstPortStart = 0;
public int dstPortEnd = 0;
public int icmpType = 0;
public int icmpCode = 0;
private static BiMap<Integer, String> protocolNumberToString;
static {
protocolNumberToString = HashBiMap.create();
protocolNumberToString.put(1, "icmp");
protocolNumberToString.put(6, "tcp");
protocolNumberToString.put(17, "udp");
protocolNumberToString.put(0, "none");
}
public SimpleFirewallRule(FirewallRuleTO rule) {
// Destination IP (confusingly called SourceIP in FirewallRule attributes)
dstIp = rule.getSrcIp();
protocol = rule.getProtocol();
if ("icmp".equals(protocol)) {
icmpType = rule.getIcmpType();
icmpCode = rule.getIcmpCode();
} else {
int[] portNumbers = rule.getSrcPortRange();
// if port start and end are not set, they
// should be 0,0, and that's already the case
if (portNumbers != null && portNumbers.length == 2) {
dstPortStart = portNumbers[0];
dstPortEnd = portNumbers[1];
}
}
sourceCidrs = rule.getSourceCidrList();
// If no CIDRs specified, it is an "all sources" rule
if (sourceCidrs == null || sourceCidrs.isEmpty()) {
sourceCidrs = new ArrayList<String>();
sourceCidrs.add("0.0.0.0/0");
}
}
public SimpleFirewallRule(NetworkACLTO rule) {
dstIp = "null";
protocol = rule.getProtocol();
if ("icmp".equals(protocol)) {
icmpType = rule.getIcmpType();
icmpCode = rule.getIcmpCode();
} else {
int[] portNumbers = rule.getSrcPortRange();
// if port start and end are not set, they
// should be 0,0, and that's already the case
if (portNumbers != null && portNumbers.length == 2) {
dstPortStart = portNumbers[0];
dstPortEnd = portNumbers[1];
}
}
sourceCidrs = rule.getSourceCidrList();
// If no CIDRs specified, it is an "all sources" rule
if (sourceCidrs == null || sourceCidrs.isEmpty()) {
sourceCidrs = new ArrayList<String>();
sourceCidrs.add("0.0.0.0/0");
}
}
public SimpleFirewallRule(PortForwardingRuleTO rule) {
dstIp = rule.getSrcIp();
protocol = rule.getProtocol();
int[] srcPortNumbers = rule.getSrcPortRange();
int[] dstPortNumbers = rule.getDstPortRange();
// if port start and end are not set, they
// should be 0,0, and that's already the case
if (srcPortNumbers != null && srcPortNumbers.length == 2 && dstPortNumbers != null && dstPortNumbers.length == 2) {
dstPortStart = dstPortNumbers[0];
dstPortEnd = srcPortNumbers[0];
}
sourceCidrs = new ArrayList<String>();
sourceCidrs.add(rule.getDstIp());
}
public SimpleFirewallRule(Rule rule) {
String sourceIP = rule.getNwSrcAddress();
int sourceLength = rule.getNwSrcLength();
sourceCidrs = new ArrayList<String>();
/*
* Only one IP in the CIDR list
* Port Forwarding Rules don't have sourceCidrs, but they do have
* targets. Use those instead if they exist.
*/
DtoRule.DtoNatTarget[] targets = rule.getNatTargets();
if (targets != null) {
sourceCidrs.add(targets[0].addressFrom);
} else {
sourceCidrs.add(String.format("%s/%d", sourceIP, sourceLength));
}
int protoNum = rule.getNwProto();
protocol = SimpleFirewallRule.protocolNumberToString(protoNum);
dstIp = rule.getNwDstAddress();
if ("icmp".equals(protocol)) {
if (rule.getTpSrc() != null && rule.getTpDst() != null) {
icmpType = rule.getTpSrc().start;
icmpCode = rule.getTpDst().start;
} else {
icmpType = -1;
icmpCode = -1;
}
} else {
/*
* If this is port forwarding, we want to take the start
* port for the public port range, and the start port for
* the private port range to uniquely identify this rule.
*/
if (targets != null) {
dstPortStart = targets[0].portFrom;
} else {
dstPortStart = rule.getTpDst().start;
}
dstPortEnd = rule.getTpDst().end;
}
// cidr, protocol, dstIp, dstPortStart, dstPortEnd, icmpType, icmpCode);
}
public static String protocolNumberToString(int protocolNumber) {
return protocolNumberToString.get(protocolNumber);
}
public static int stringToProtocolNumber(String protoString) {
return protocolNumberToString.inverse().get(protoString);
}
public int getFieldOne() {
if (protocol.equals("icmp")) {
return icmpType;
} else {
return dstPortStart;
}
}
public int getFieldTwo() {
if (protocol.equals("icmp")) {
return icmpCode;
} else {
return dstPortEnd;
}
}
public String[] toStringArray() {
List<String> stringRules = new ArrayList<String>();
// Create a rule string per source CIDR, since each MidoNet
// rule is for one CIDR
for (String sourceCidr : sourceCidrs) {
// Follows the rule String format defined in SetFirewallRulesCommand.java::generateFirewallRules()
int field1 = getFieldOne();
int field2 = getFieldTwo();
String stringRule = String.format("%s:%s:%d:%d:%s:", dstIp, protocol, field1, field2, sourceCidr);
stringRules.add(stringRule);
}
String[] stringArray = new String[stringRules.size()];
return stringRules.toArray(stringArray);
}
}