CLOUDSTACK-306: Implement SRX firewall

Use SRX firewall filter as SRX firewall. The old security policy mechanism
cannot be used as IP based. This would enable SRX's ability to control traffic
for F5 behind it.
This commit is contained in:
Sheng Yang 2013-01-04 18:56:47 -08:00
parent c7563cb7bd
commit 717f9dcd4d
9 changed files with 445 additions and 42 deletions

View File

@ -58,6 +58,7 @@ public class FirewallRuleTO {
this(id,null,srcIp,protocol,srcPortStart,srcPortEnd,revoked,alreadyAdded,purpose,sourceCidr,icmpType,icmpCode);
}
public FirewallRuleTO(long id,String srcVlanTag, String srcIp, String protocol, Integer srcPortStart, Integer srcPortEnd, boolean revoked, boolean alreadyAdded, FirewallRule.Purpose purpose, List<String> sourceCidr,Integer icmpType,Integer icmpCode) {
this.id = id;
this.srcVlanTag = srcVlanTag;
this.srcIp = srcIp;
this.protocol = protocol;

View File

@ -47,6 +47,11 @@ public class StaticNatRuleTO extends FirewallRuleTO{
super(id, srcIp, protocol, srcPortStart, srcPortEnd, revoked, alreadyAdded, FirewallRule.Purpose.StaticNat, null,0,0);
this.dstIp = dstIp;
}
public StaticNatRuleTO(long id,String srcVlanTag, String srcIp, Integer srcPortStart, Integer srcPortEnd, String dstIp, Integer dstPortStart, Integer dstPortEnd, String protocol, boolean revoked, boolean alreadyAdded) {
super(id, srcVlanTag, srcIp, protocol, srcPortStart, srcPortEnd, revoked, alreadyAdded, FirewallRule.Purpose.StaticNat, null,0,0);
this.dstIp = dstIp;
}
public String getDstIp() {
return dstIp;

View File

@ -268,7 +268,7 @@ public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceMan
// Set capabilities for Firewall service
Map<Capability, String> firewallCapabilities = new HashMap<Capability, String>();
firewallCapabilities.put(Capability.SupportedProtocols, "tcp,udp");
firewallCapabilities.put(Capability.SupportedProtocols, "tcp,udp,icmp");
firewallCapabilities.put(Capability.MultipleIps, "true");
firewallCapabilities.put(Capability.TrafficStatistics, "per public ip");
capabilities.put(Service.Firewall, firewallCapabilities);

View File

@ -55,6 +55,7 @@ import com.cloud.agent.api.routing.IpAssocAnswer;
import com.cloud.agent.api.routing.IpAssocCommand;
import com.cloud.agent.api.routing.NetworkElementCommand;
import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand;
import com.cloud.agent.api.routing.SetFirewallRulesCommand;
import com.cloud.agent.api.routing.SetPortForwardingRulesCommand;
import com.cloud.agent.api.routing.SetStaticNatRulesCommand;
import com.cloud.agent.api.routing.VpnUsersCfgCommand;
@ -64,6 +65,7 @@ import com.cloud.agent.api.to.IpAddressTO;
import com.cloud.agent.api.to.PortForwardingRuleTO;
import com.cloud.agent.api.to.StaticNatRuleTO;
import com.cloud.host.Host;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.FirewallRule.Purpose;
import com.cloud.resource.ServerResource;
import com.cloud.utils.NumbersUtil;
@ -75,7 +77,6 @@ public class JuniperSrxResource implements ServerResource {
private String _name;
private String _zoneId;
private String _physicalNetworkId;
private String _ip;
private String _username;
private String _password;
@ -89,6 +90,7 @@ public class JuniperSrxResource implements ServerResource {
private Integer _timeoutInSeconds;
private String _publicZone;
private String _privateZone;
private String _publicZoneInputFilterName;
private String _publicInterface;
private String _usageInterface;
private String _privateInterface;
@ -159,6 +161,9 @@ public class JuniperSrxResource implements ServerResource {
ACCESS_PROFILE_ADD("access-profile-add.xml"),
ACCESS_PROFILE_GETONE("access-profile-getone.xml"),
ACCESS_PROFILE_GETALL("access-profile-getall.xml"),
FIREWALL_FILTER_TERM_ADD("firewall-filter-term-add.xml"),
FIREWALL_FILTER_TERM_GETONE("firewall-filter-term-getone.xml"),
TEMPLATE_ENTRY("template-entry.xml"),
OPEN_CONFIGURATION("open-configuration.xml"),
CLOSE_CONFIGURATION("close-configuration.xml"),
COMMIT("commit.xml"),
@ -231,12 +236,74 @@ public class JuniperSrxResource implements ServerResource {
}
}
public class FirewallFilterTerm {
private String name;
private List<String> sourceCidrs;
private String destIp;
private String portRange;
private String protocol;
private String icmpType;
private String icmpCode;
private String countName;
private FirewallFilterTerm(String name, List<String> sourceCidrs, String destIp, String protocol, Integer startPort, Integer endPort,
Integer icmpType, Integer icmpCode, String countName) {
this.name = name;
this.sourceCidrs = sourceCidrs;
this.destIp = destIp;
this.protocol = protocol;
if (protocol.equals("tcp") || protocol.equals("udp")) {
this.portRange = String.valueOf(startPort) + "-" + String.valueOf(endPort);
} else if (protocol.equals("icmp")) {
this.icmpType = String.valueOf(icmpType);
this.icmpCode = String.valueOf(icmpCode);
} else {
assert protocol.equals("any");
}
this.countName = countName;
}
public String getName() {
return name;
}
public List<String> getSourceCidrs() {
return sourceCidrs;
}
public String getDestIp() {
return destIp;
}
public String getPortRange() {
return portRange;
}
public String getProtocol() {
return protocol;
}
public String getIcmpType() {
return icmpType;
}
public String getIcmpCode() {
return icmpCode;
}
public String getCountName() {
return countName;
}
}
private enum SrxCommand {
LOGIN, OPEN_CONFIGURATION, CLOSE_CONFIGURATION, COMMIT, ROLLBACK, CHECK_IF_EXISTS, CHECK_IF_IN_USE, ADD, DELETE, GET_ALL;
}
private enum Protocol {
tcp, udp, any;
tcp, udp, icmp, any;
}
private enum RuleMatchCondition {
@ -277,6 +344,8 @@ public class JuniperSrxResource implements ServerResource {
return execute((SetStaticNatRulesCommand) cmd);
} else if (cmd instanceof SetPortForwardingRulesCommand) {
return execute((SetPortForwardingRulesCommand) cmd);
} else if (cmd instanceof SetFirewallRulesCommand) {
return execute((SetFirewallRulesCommand) cmd);
} else if (cmd instanceof ExternalNetworkResourceUsageCommand) {
return execute((ExternalNetworkResourceUsageCommand) cmd);
} else if (cmd instanceof RemoteAccessVpnCfgCommand) {
@ -300,11 +369,6 @@ public class JuniperSrxResource implements ServerResource {
throw new ConfigurationException("Unable to find zone");
}
_physicalNetworkId = (String) params.get("physicalNetworkId");
if (_physicalNetworkId == null) {
throw new ConfigurationException("Unable to find physical network id in the configuration parameters");
}
_ip = (String) params.get("ip");
if (_ip == null) {
throw new ConfigurationException("Unable to find IP");
@ -325,8 +389,6 @@ public class JuniperSrxResource implements ServerResource {
throw new ConfigurationException("Unable to find public interface.");
}
_usageInterface = (String) params.get("usageinterface");
_privateInterface = (String) params.get("privateinterface");
if (_privateInterface == null) {
throw new ConfigurationException("Unable to find private interface.");
@ -364,6 +426,8 @@ public class JuniperSrxResource implements ServerResource {
throw new ConfigurationException("Unable to open a connection to the SRX.");
}
_publicZoneInputFilterName = _publicZone;
_usageFilterVlanInput = new UsageFilter("vlan-input", null, "vlan-input");
_usageFilterVlanOutput = new UsageFilter("vlan-output", null, "vlan-output");
_usageFilterIPInput = new UsageFilter(_publicZone, "destination-address", "-i");
@ -712,6 +776,50 @@ public class JuniperSrxResource implements ServerResource {
s_logger.debug(msg);
}
/* security policies */
private synchronized Answer execute(SetFirewallRulesCommand cmd) {
refreshSrxConnection();
return execute(cmd, _numRetries);
}
private Answer execute(SetFirewallRulesCommand cmd, int numRetries) {
FirewallRuleTO[] rules = cmd.getRules();
try {
openConfiguration();
for (FirewallRuleTO rule : rules) {
int startPort = 0, endPort = 0;
if (rule.getSrcPortRange() != null) {
startPort = rule.getSrcPortRange()[0];
endPort = rule.getSrcPortRange()[1];
}
FirewallFilterTerm term = new FirewallFilterTerm(genIpIdentifier(rule.getSrcIp()) + "-" + String.valueOf(rule.getId()), rule.getSourceCidrList(),
rule.getSrcIp(), rule.getProtocol(), startPort, endPort,
rule.getIcmpType(), rule.getIcmpCode(), genIpIdentifier(rule.getSrcIp()) + _usageFilterIPInput.getCounterIdentifier());
if (!rule.revoked()) {
manageFirewallFilter(SrxCommand.ADD, term, _publicZoneInputFilterName);
} else {
manageFirewallFilter(SrxCommand.DELETE, term, _publicZoneInputFilterName);
}
}
commitConfiguration();
return new Answer(cmd);
} catch (ExecutionException e) {
s_logger.error(e);
closeConfiguration();
if (numRetries > 0 && refreshSrxConnection()) {
int numRetriesRemaining = numRetries - 1;
s_logger.debug("Retrying SetFirewallRulesCommand. Number of retries remaining: " + numRetriesRemaining);
return execute(cmd, numRetriesRemaining);
} else {
return new Answer(cmd, e);
}
}
}
/*
* Static NAT
*/
@ -766,7 +874,6 @@ public class JuniperSrxResource implements ServerResource {
private void addStaticNatRule(Long publicVlanTag, String publicIp, String privateIp, List<FirewallRuleTO> rules) throws ExecutionException {
manageProxyArp(SrxCommand.ADD, publicVlanTag, publicIp);
manageStaticNatRule(SrxCommand.ADD, publicIp, privateIp);
manageUsageFilter(SrxCommand.ADD, _usageFilterIPInput, publicIp, null, genIpFilterTermName(publicIp));
manageAddressBookEntry(SrxCommand.ADD, _privateZone, privateIp, null);
// Add a new security policy with the current set of applications
@ -778,7 +885,6 @@ public class JuniperSrxResource implements ServerResource {
private void removeStaticNatRule(Long publicVlanTag, String publicIp, String privateIp) throws ExecutionException {
manageStaticNatRule(SrxCommand.DELETE, publicIp, privateIp);
manageProxyArp(SrxCommand.DELETE, publicVlanTag, publicIp);
manageUsageFilter(SrxCommand.DELETE, _usageFilterIPInput, publicIp, null, genIpFilterTermName(publicIp));
// Remove any existing security policy and clean up applications
removeSecurityPolicyAndApplications(SecurityPolicyType.STATIC_NAT, privateIp);
@ -2781,6 +2887,108 @@ public class JuniperSrxResource implements ServerResource {
}
}
private String genNameValueEntry(String name, String value) {
String xml = SrxXml.TEMPLATE_ENTRY.getXml();
xml = replaceXmlValue(xml, "name", name);
xml = replaceXmlValue(xml, "value", value);
return xml;
}
private String genMultipleEntries(String name, List<String> values) {
String result = "";
for (String value : values) {
result = result + genNameValueEntry(name, value);
}
return result;
}
private String genPortRangeEntry(String protocol, String portRange) {
String result = "";
result = result + genNameValueEntry("protocol", protocol);
result = result + genNameValueEntry("destination-port", portRange);
return result;
}
private String genIcmpEntries(String icmpType, String icmpCode) {
String result = "";
result = result + genNameValueEntry("protocol", "icmp");
if (icmpType.equals("-1")) {
result = result + genNameValueEntry("icmp-type", "0-255");
} else {
result = result + genNameValueEntry("icmp-type", icmpType);
}
if (icmpCode.equals("-1")) {
result = result + genNameValueEntry("icmp-code", "0-255");
} else {
result = result + genNameValueEntry("icmp-code", icmpCode);
}
return result;
}
private boolean manageFirewallFilter(SrxCommand command, FirewallFilterTerm term, String filterName) throws ExecutionException {
String xml;
switch(command) {
case CHECK_IF_EXISTS:
xml = SrxXml.FIREWALL_FILTER_TERM_GETONE.getXml();
xml = setDelete(xml, false);
xml = replaceXmlValue(xml, "filter-name", filterName);
xml = replaceXmlValue(xml, "term-name", term.getName());
return sendRequestAndCheckResponse(command, xml, "name", term.getName());
case ADD:
if (manageFirewallFilter(SrxCommand.CHECK_IF_EXISTS, term, filterName)) {
return true;
}
xml = SrxXml.FIREWALL_FILTER_TERM_ADD.getXml();
xml = replaceXmlValue(xml, "filter-name", filterName);
xml = replaceXmlValue(xml, "term-name", term.getName());
xml = replaceXmlValue(xml, "source-address-entries", genMultipleEntries("source-address", term.getSourceCidrs()));
xml = replaceXmlValue(xml, "dest-ip-address", term.getDestIp());
String protocol = term.getProtocol();
if (protocol.equals("tcp") || protocol.equals("udp")) {
xml = replaceXmlValue(xml, "protocol-options", genPortRangeEntry(protocol, term.getPortRange()));
} else if (protocol.equals("icmp")) {
xml = replaceXmlValue(xml, "protocol-options", genIcmpEntries(term.getIcmpType(), term.getIcmpCode()));
} else {
assert protocol.equals("any");
xml = replaceXmlValue(xml, "protocol-options", "");
}
xml = replaceXmlValue(xml, "count-name", term.getCountName());
if (!sendRequestAndCheckResponse(command, xml)) {
throw new ExecutionException("Failed to add firewall filter: " + term.getName());
} else {
return true;
}
case DELETE:
if (!manageFirewallFilter(SrxCommand.CHECK_IF_EXISTS, term, filterName)) {
return true;
}
xml = SrxXml.FIREWALL_FILTER_TERM_GETONE.getXml();
xml = setDelete(xml, true);
xml = replaceXmlValue(xml, "filter-name", filterName);
xml = replaceXmlValue(xml, "term-name", term.getName());
if (!sendRequestAndCheckResponse(command, xml)) {
throw new ExecutionException("Failed to delete firewall filter: " + term.getName());
} else {
return true;
}
default:
s_logger.debug("Unrecognized command.");
return false;
}
}
/*
* Usage
*/
@ -2913,6 +3121,10 @@ public class JuniperSrxResource implements ServerResource {
}
UsageFilter filter = getUsageFilter(counterName);
if (filter == null) {
s_logger.debug("Failed to parse counter name in usage answer: " + counterName);
return;
}
String usageAnswerKey = getUsageAnswerKey(filter, counterName);
Map<String, long[]> bytesMap = getBytesMap(answer, filter, usageAnswerKey);
updateBytesMap(bytesMap, filter, usageAnswerKey, byteCount);
@ -2981,6 +3193,11 @@ public class JuniperSrxResource implements ServerResource {
}
private boolean checkResponse(String xmlResponse, boolean errorKeyAndValue, String key, String value) {
if (xmlResponse == null) {
s_logger.error("Failed to communicate with SRX!");
return false;
}
if (!xmlResponse.contains("authentication-response")) {
s_logger.debug("Checking response: " + xmlResponse);
} else {

View File

@ -0,0 +1,25 @@
<rpc>
<load-configuration>
<configuration>
<firewall>
<filter>
<name>%filter-name%</name>
<term>
<name>%term-name%</name>
<from>
%source-address-entries%
<destination-address>
<name>%dest-ip-address%</name>
</destination-address>
%protocol-options%
</from>
<then>
<count>%count-name%</count>
<accept/>
</then>
</term>
</filter>
</firewall>
</configuration>
</load-configuration>
</rpc>

View File

@ -0,0 +1,14 @@
<rpc>
<load-configuration>
<configuration>
<firewall>
<filter>
<name>%filter-name%</name>
<term %delete%>
<name>%term-name%</name>
</term>
</filter>
</firewall>
</configuration>
</load-configuration>
</rpc>

View File

@ -0,0 +1,3 @@
<%name%>
<name>%value%</name>
</%name%>

View File

@ -22,6 +22,7 @@ import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.host.Host;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.PortForwardingRule;
import com.cloud.resource.ServerResource;
import com.cloud.utils.component.Manager;
@ -94,4 +95,12 @@ public interface ExternalFirewallDeviceManager extends Manager {
*/
public boolean manageGuestNetworkWithExternalFirewall(boolean add, Network guestConfig) throws ResourceUnavailableException, InsufficientCapacityException;
/**
* applies port forwarding rules
* @param network guest network if
* @param rules load balancer rules
* @return true if successfully applied rules
* @throws ResourceUnavailableException
*/
public boolean applyPortForwardingRules(Network network, List<? extends PortForwardingRule> rules) throws ResourceUnavailableException;
}

View File

@ -34,9 +34,11 @@ import com.cloud.agent.api.StartupExternalLoadBalancerCommand;
import com.cloud.agent.api.routing.IpAssocCommand;
import com.cloud.agent.api.routing.NetworkElementCommand;
import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand;
import com.cloud.agent.api.routing.SetFirewallRulesCommand;
import com.cloud.agent.api.routing.SetPortForwardingRulesCommand;
import com.cloud.agent.api.routing.SetStaticNatRulesCommand;
import com.cloud.agent.api.routing.VpnUsersCfgCommand;
import com.cloud.agent.api.to.FirewallRuleTO;
import com.cloud.agent.api.to.IpAddressTO;
import com.cloud.agent.api.to.PortForwardingRuleTO;
import com.cloud.agent.api.to.StaticNatRuleTO;
@ -65,6 +67,7 @@ import com.cloud.network.Network.Capability;
import com.cloud.network.Network.Service;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.dao.ExternalFirewallDeviceDao;
import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.InlineLoadBalancerNicMapDao;
import com.cloud.network.dao.LoadBalancerDao;
@ -78,14 +81,17 @@ import com.cloud.network.dao.VpnUserDao;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.FirewallRule.Purpose;
import com.cloud.network.rules.PortForwardingRule;
import com.cloud.network.rules.StaticNat;
import com.cloud.network.rules.StaticNatRule;
import com.cloud.network.rules.dao.PortForwardingRulesDao;
import com.cloud.offering.NetworkOffering;
import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.resource.ResourceManager;
import com.cloud.resource.ResourceState;
import com.cloud.resource.ResourceStateAdapter;
import com.cloud.resource.ServerResource;
import com.cloud.resource.UnableDeleteHostException;
import com.cloud.resource.ResourceStateAdapter.DeleteHostAnswer;
import com.cloud.server.api.response.ExternalFirewallResponse;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
@ -98,6 +104,7 @@ import com.cloud.utils.db.DB;
import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.Ip;
import com.cloud.utils.net.NetUtils;
import com.cloud.utils.net.UrlUtil;
import com.cloud.vm.Nic.ReservationStrategy;
@ -133,6 +140,7 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
@Inject NetworkExternalFirewallDao _networkExternalFirewallDao;
@Inject VpnUserDao _vpnUsersDao;
@Inject HostDetailsDao _hostDetailDao;
@Inject FirewallRulesDao _fwRulesDao;
private static final org.apache.log4j.Logger s_logger = Logger.getLogger(ExternalFirewallDeviceManagerImpl.class);
private long _defaultFwCapacity;
@ -236,14 +244,26 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
throw new InvalidParameterValueException("Could not find an external firewall with ID: " + hostId);
}
DetailVO fwHostDetails = _hostDetailDao.findDetail(hostId, ApiConstants.FIREWALL_DEVICE_ID);
long fwDeviceId = Long.parseLong(fwHostDetails.getValue());
// check if any networks are using this balancer device
List<NetworkExternalFirewallVO> networks = _networkExternalFirewallDao.listByFirewallDeviceId(fwDeviceId);
if ((networks != null) && !networks.isEmpty()) {
throw new CloudRuntimeException("Delete can not be done as there are networks using the firewall device ");
}
try {
if (_resourceMgr.maintain(hostId) && _resourceMgr.deleteHost(hostId, false, false)) {
return true;
} else {
return false;
}
} catch (AgentUnavailableException e) {
s_logger.debug(e);
// put the host in maintenance state in order for it to be deleted
externalFirewall.setResourceState(ResourceState.Maintenance);
_hostDao.update(hostId, externalFirewall);
_resourceMgr.deleteHost(hostId, false, false);
// delete the external load balancer entry
_externalFirewallDeviceDao.remove(fwDeviceId);
return true;
} catch (Exception e) {
s_logger.debug("Failed to delete external firewall device due to " + e.getMessage());
return false;
}
}
@ -316,6 +336,32 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
" to implement the network", DataCenter.class, network.getDataCenterId());
}
@DB
protected boolean freeFirewallForNetwork(Network network) {
Transaction txn = Transaction.currentTxn();
GlobalLock deviceMapLock = GlobalLock.getInternLock("NetworkFirewallDeviceMap");
try {
if (deviceMapLock.lock(120)) {
try {
NetworkExternalFirewallVO fwDeviceForNetwork = _networkExternalFirewallDao.findByNetworkId(network.getId());
if (fwDeviceForNetwork != null) {
_networkExternalFirewallDao.remove(fwDeviceForNetwork.getId());
}
} catch (Exception exception) {
txn.rollback();
s_logger.error("Failed to release firewall device for the network" + network.getId() + " due to " + exception.getMessage());
return false;
} finally {
deviceMapLock.unlock();
}
}
} finally {
deviceMapLock.releaseRef();
}
txn.commit();
return true;
}
public String getExternalNetworkResourceGuid(long physicalNetworkId, String deviceName, String ip) {
return physicalNetworkId + "-" + deviceName + "-" + ip;
}
@ -422,15 +468,21 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
cmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, String.valueOf(guestVlanTag));
Answer answer = _agentMgr.easySend(externalFirewall.getId(), cmd);
List<String> reservedIpAddressesForGuestNetwork = _nicDao.listIpAddressInNetwork(network.getId());
if (answer == null || !answer.getResult()) {
String action = add ? "implement" : "shutdown";
String answerDetails = (answer != null) ? answer.getDetails() : "answer was null";
String msg = "External firewall was unable to " + action + " the guest network on the external firewall in zone " + zone.getName() + " due to " + answerDetails;
s_logger.error(msg);
if (!add && (!reservedIpAddressesForGuestNetwork.contains(network.getGateway()))) {
// If we failed the implementation as well, then just return, no complain
s_logger.error("Skip the shutdown of guest network on SRX because it seems we didn't implement it as well");
return true;
}
throw new ResourceUnavailableException(msg, DataCenter.class, zoneId);
}
List<String> reservedIpAddressesForGuestNetwork = _nicDao.listIpAddressInNetwork(network.getId());
if (add && (!reservedIpAddressesForGuestNetwork.contains(network.getGateway()))) {
// Insert a new NIC for this guest network to reserve the gateway address
savePlaceholderNic(network, network.getGateway());
@ -447,6 +499,19 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
}
}
// on network shutdown, delete placeHolder nics used for the firewall device
if (!add) {
List<NicVO> guestIps = _nicDao.listByNetworkId(network.getId());
for (NicVO guestIp : guestIps) {
// only external firewall and external load balancer will create NicVO with PlaceHolder reservation strategy
if (guestIp.getReservationStrategy().equals(ReservationStrategy.PlaceHolder) && guestIp.getIp4Address().equals(network.getGateway())) {
_nicDao.remove(guestIp.getId());
}
}
freeFirewallForNetwork(network);
}
String action = add ? "implemented" : "shut down";
s_logger.debug("External firewall has " + action + " the guest network for account " + account.getAccountName() + "(id = " + account.getAccountId() + ") with VLAN tag " + guestVlanTag);
@ -456,6 +521,37 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
@Override
public boolean applyFirewallRules(Network network, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
// Find the external firewall in this zone
long zoneId = network.getDataCenterId();
DataCenterVO zone = _dcDao.findById(zoneId);
ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network);
// During destroy, device reference may already been clean up, then we just return true
if (fwDeviceVO == null) {
return true;
}
HostVO externalFirewall = _hostDao.findById(fwDeviceVO.getHostId());
assert(externalFirewall != null);
if (network.getState() == Network.State.Allocated) {
s_logger.debug("External firewall was asked to apply firewall rules for network with ID " + network.getId() + "; this network is not implemented. Skipping backend commands.");
return true;
}
List<FirewallRuleTO> rulesTO = new ArrayList<FirewallRuleTO>();
for (FirewallRule rule : rules) {
IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId());
FirewallRuleTO ruleTO = new FirewallRuleTO(rule, null, sourceIp.getAddress().addr());
rulesTO.add(ruleTO);
}
//Firewall rules configured for staticNAT/PF
sendFirewallRules(rulesTO, zone, externalFirewall.getId());
return true;
}
public boolean applyStaticNatRules(Network network, List<? extends StaticNat> rules) throws ResourceUnavailableException {
long zoneId = network.getDataCenterId();
DataCenterVO zone = _dcDao.findById(zoneId);
ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network);
@ -469,32 +565,34 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
}
List<StaticNatRuleTO> staticNatRules = new ArrayList<StaticNatRuleTO>();
List<PortForwardingRuleTO> portForwardingRules = new ArrayList<PortForwardingRuleTO>();
for (FirewallRule rule : rules) {
for (StaticNat rule : rules) {
IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId());
Vlan vlan = _vlanDao.findById(sourceIp.getVlanId());
if (rule.getPurpose() == Purpose.StaticNat) {
StaticNatRule staticNatRule = (StaticNatRule) rule;
StaticNatRuleTO ruleTO = new StaticNatRuleTO(staticNatRule, vlan.getVlanTag(), sourceIp.getAddress().addr(), staticNatRule.getDestIpAddress());
staticNatRules.add(ruleTO);
} else if (rule.getPurpose() == Purpose.PortForwarding) {
PortForwardingRuleTO ruleTO = new PortForwardingRuleTO((PortForwardingRule) rule, vlan.getVlanTag(), sourceIp.getAddress().addr());
portForwardingRules.add(ruleTO);
}
StaticNatRuleTO ruleTO = new StaticNatRuleTO(0,vlan.getVlanTag(), sourceIp.getAddress().addr(), -1, -1, rule.getDestIpAddress(), -1, -1, "any", rule.isForRevoke(), false);
staticNatRules.add(ruleTO);
}
// Apply static nat rules
applyStaticNatRules(staticNatRules, zone, externalFirewall.getId());
// apply port forwarding rules
applyPortForwardingRules(portForwardingRules, zone, externalFirewall.getId());
sendStaticNatRules(staticNatRules, zone, externalFirewall.getId());
return true;
}
protected void sendFirewallRules(List<FirewallRuleTO> firewallRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException {
if (!firewallRules.isEmpty()) {
SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(firewallRules);
Answer answer = _agentMgr.easySend(externalFirewallId, cmd);
if (answer == null || !answer.getResult()) {
String details = (answer != null) ? answer.getDetails() : "details unavailable";
String msg = "External firewall was unable to apply static nat rules to the SRX appliance in zone " + zone.getName() + " due to: " + details + ".";
s_logger.error(msg);
throw new ResourceUnavailableException(msg, DataCenter.class, zone.getId());
}
}
}
protected void applyStaticNatRules(List<StaticNatRuleTO> staticNatRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException {
protected void sendStaticNatRules(List<StaticNatRuleTO> staticNatRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException {
if (!staticNatRules.isEmpty()) {
SetStaticNatRulesCommand cmd = new SetStaticNatRulesCommand(staticNatRules, null);
Answer answer = _agentMgr.easySend(externalFirewallId, cmd);
@ -507,7 +605,7 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
}
}
protected void applyPortForwardingRules(List<PortForwardingRuleTO> portForwardingRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException {
protected void sendPortForwardingRules(List<PortForwardingRuleTO> portForwardingRules, DataCenter zone, long externalFirewallId) throws ResourceUnavailableException {
if (!portForwardingRules.isEmpty()) {
SetPortForwardingRulesCommand cmd = new SetPortForwardingRulesCommand(portForwardingRules);
Answer answer = _agentMgr.easySend(externalFirewallId, cmd);
@ -648,7 +746,38 @@ public abstract class ExternalFirewallDeviceManagerImpl extends AdapterBase impl
@Override
public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException {
// TODO Auto-generated method stub
return null;
if (host.getType() != com.cloud.host.Host.Type.ExternalFirewall) {
return null;
}
return new DeleteHostAnswer(true);
}
@Override
public boolean applyPortForwardingRules(Network network, List<? extends PortForwardingRule> rules) throws ResourceUnavailableException {
// Find the external firewall in this zone
long zoneId = network.getDataCenterId();
DataCenterVO zone = _dcDao.findById(zoneId);
ExternalFirewallDeviceVO fwDeviceVO = getExternalFirewallForNetwork(network);
HostVO externalFirewall = _hostDao.findById(fwDeviceVO.getHostId());
assert(externalFirewall != null);
if (network.getState() == Network.State.Allocated) {
s_logger.debug("External firewall was asked to apply firewall rules for network with ID " + network.getId() + "; this network is not implemented. Skipping backend commands.");
return true;
}
List<PortForwardingRuleTO> pfRules = new ArrayList<PortForwardingRuleTO>();
for (PortForwardingRule rule : rules) {
IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId());
Vlan vlan = _vlanDao.findById(sourceIp.getVlanId());
PortForwardingRuleTO ruleTO = new PortForwardingRuleTO(rule, vlan.getVlanTag(), sourceIp.getAddress().addr());
pfRules.add(ruleTO);
}
sendPortForwardingRules(pfRules, zone, externalFirewall.getId());
return true;
}
}