VPC: moved NetworkACL manager to the vpc folder
Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/b770c8b9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/b770c8b9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/b770c8b9 Branch: refs/heads/vpc Commit: b770c8b9793315b103f80221b770c9098bcf1ca6 Parents: 4e7b65e Author: Alena Prokharchyk <[email protected]> Authored: Mon Jun 25 11:48:13 2012 -0700 Committer: Alena Prokharchyk <[email protected]> Committed: Mon Jun 25 20:57:50 2012 -0700 ---------------------------------------------------------------------- .../configuration/DefaultComponentLibrary.java | 2 +- .../network/firewall/NetworkACLManagerImpl.java | 371 --------------- .../cloud/network/vpc/NetworkACLManagerImpl.java | 370 ++++++++++++++ 3 files changed, 371 insertions(+), 372 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/b770c8b9/server/src/com/cloud/configuration/DefaultComponentLibrary.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index f566dd8..a4012b7 100755 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -106,7 +106,6 @@ import com.cloud.network.element.NetscalerLoadBalancerElementService; import com.cloud.network.element.VirtualRouterElement; import com.cloud.network.element.VirtualRouterElementService; import com.cloud.network.firewall.FirewallManagerImpl; -import com.cloud.network.firewall.NetworkACLManagerImpl; import com.cloud.network.lb.ElasticLoadBalancerManagerImpl; import com.cloud.network.lb.LoadBalancingRulesManagerImpl; import com.cloud.network.lb.dao.ElasticLbVmMapDaoImpl; @@ -124,6 +123,7 @@ import com.cloud.network.security.dao.SecurityGroupRulesDaoImpl; import com.cloud.network.security.dao.SecurityGroupVMMapDaoImpl; import com.cloud.network.security.dao.SecurityGroupWorkDaoImpl; import com.cloud.network.security.dao.VmRulesetLogDaoImpl; +import com.cloud.network.vpc.NetworkACLManagerImpl; import com.cloud.network.vpc.VpcManagerImpl; import com.cloud.network.vpc.Dao.PrivateIpDaoImpl; import com.cloud.network.vpc.Dao.VpcDaoImpl; http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/b770c8b9/server/src/com/cloud/network/firewall/NetworkACLManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/network/firewall/NetworkACLManagerImpl.java b/server/src/com/cloud/network/firewall/NetworkACLManagerImpl.java deleted file mode 100644 index 50613f6..0000000 --- a/server/src/com/cloud/network/firewall/NetworkACLManagerImpl.java +++ /dev/null @@ -1,371 +0,0 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by 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. -// -// Automatically generated by addcopyright.py at 04/03/2012 -package com.cloud.network.firewall; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; - -import javax.ejb.Local; -import javax.naming.ConfigurationException; - -import org.apache.log4j.Logger; - -import com.cloud.acl.SecurityChecker.AccessType; -import com.cloud.api.commands.ListNetworkACLsCmd; -import com.cloud.event.ActionEvent; -import com.cloud.event.EventTypes; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.NetworkRuleConflictException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.network.Network; -import com.cloud.network.Network.Capability; -import com.cloud.network.Network.Service; -import com.cloud.network.NetworkManager; -import com.cloud.network.Networks; -import com.cloud.network.dao.FirewallRulesDao; -import com.cloud.network.rules.FirewallManager; -import com.cloud.network.rules.FirewallRule; -import com.cloud.network.rules.FirewallRule.Purpose; -import com.cloud.network.rules.FirewallRule.TrafficType; -import com.cloud.network.rules.FirewallRuleVO; -import com.cloud.network.rules.NetworkACL; -import com.cloud.network.vpc.Vpc; -import com.cloud.network.vpc.VpcManager; -import com.cloud.projects.Project.ListProjectResourcesCriteria; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.UserContext; -import com.cloud.utils.Ternary; -import com.cloud.utils.component.Inject; -import com.cloud.utils.component.Manager; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.Filter; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.net.NetUtils; - -/** - * @author Alena Prokharchyk - */ - -@Local(value = { NetworkACLService.class}) -public class NetworkACLManagerImpl implements Manager,NetworkACLService{ - String _name; - private static final Logger s_logger = Logger.getLogger(NetworkACLManagerImpl.class); - - - @Inject - AccountManager _accountMgr; - @Inject - FirewallManager _firewallMgr; - @Inject - FirewallRulesDao _firewallDao; - @Inject - NetworkManager _networkMgr; - @Inject - VpcManager _vpcMgr; - - - @Override - public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { - _name = name; - return true; - } - - @Override - public boolean start() { - return true; - } - - - @Override - public boolean stop() { - return true; - } - - - @Override - public String getName() { - return _name; - } - - @Override - public boolean applyNetworkACLs(long networkId, Account caller) throws ResourceUnavailableException { - List<FirewallRuleVO> rules = _firewallDao.listByNetworkAndPurpose(networkId, Purpose.NetworkACL); - return _firewallMgr.applyFirewallRules(rules, false, caller); - } - - @Override - public NetworkACL createNetworkACL(NetworkACL acl) throws NetworkRuleConflictException { - return createNetworkACL(UserContext.current().getCaller(), acl.getXid(), acl.getSourcePortStart(), - acl.getSourcePortEnd(), acl.getProtocol(), acl.getSourceCidrList(), acl.getIcmpCode(), - acl.getIcmpType(), null, acl.getType(), acl.getNetworkId(), acl.getTrafficType()); - } - - @DB - @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_OPEN, eventDescription = "creating firewall rule", create = true) - protected NetworkACL createNetworkACL(Account caller, String xId, Integer portStart, - Integer portEnd, String protocol, List<String> sourceCidrList, Integer icmpCode, Integer icmpType, - Long relatedRuleId, FirewallRule.FirewallRuleType type, long networkId, TrafficType trafficType) throws NetworkRuleConflictException { - - Network network = _networkMgr.getNetwork(networkId); - if (network == null) { - throw new InvalidParameterValueException("Can't find network by id"); - } - - if (network.getVpcId() == null) { - throw new UnsupportedOperationException("Network ACL rules are supported just for VPC networks"); - } - - Vpc vpc = _vpcMgr.getVpc(network.getVpcId()); - Account aclOwner = _accountMgr.getAccount(vpc.getAccountId()); - - _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network); - - - if (!_networkMgr.areServicesSupportedInNetwork(networkId, Service.Firewall)) { - throw new InvalidParameterValueException("Service " + Service.Firewall + " is not supported in network " + network); - } - - // icmp code and icmp type can't be passed in for any other protocol rather than icmp - if (!protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (icmpCode != null || icmpType != null)) { - throw new InvalidParameterValueException("Can specify icmpCode and icmpType for ICMP protocol only"); - } - - if (protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (portStart != null || portEnd != null)) { - throw new InvalidParameterValueException("Can't specify start/end port when protocol is ICMP"); - } - - validateNetworkACL(caller, network, portStart, portEnd, protocol); - - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - FirewallRuleVO newRule = new FirewallRuleVO(xId, null, portStart, portEnd, protocol.toLowerCase(), networkId, - aclOwner.getAccountId(), aclOwner.getDomainId(), Purpose.NetworkACL, sourceCidrList, icmpCode, icmpType, - relatedRuleId, trafficType); - newRule.setType(type); - newRule = _firewallDao.persist(newRule); - - if (type == FirewallRule.FirewallRuleType.User) { - detectNetworkACLConflict(newRule); - } - - if (!_firewallDao.setStateToAdd(newRule)) { - throw new CloudRuntimeException("Unable to update the state to add for " + newRule); - } - UserContext.current().setEventDetails("Rule Id: " + newRule.getId()); - - txn.commit(); - - return newRule; - } - - - protected void validateNetworkACL(Account caller, Network network, Integer portStart, Integer portEnd, - String proto) { - - if (portStart != null && !NetUtils.isValidPort(portStart)) { - throw new InvalidParameterValueException("publicPort is an invalid value: " + portStart); - } - if (portEnd != null && !NetUtils.isValidPort(portEnd)) { - throw new InvalidParameterValueException("Public port range is an invalid value: " + portEnd); - } - - // start port can't be bigger than end port - if (portStart != null && portEnd != null && portStart > portEnd) { - throw new InvalidParameterValueException("Start port can't be bigger than end port"); - } - - if (network.getTrafficType() != Networks.TrafficType.Guest) { - throw new InvalidParameterValueException("Network ACL can be created just for networks of type " + Networks.TrafficType.Guest); - } - - // Verify that the network guru supports the protocol specified - Map<Network.Capability, String> caps = _networkMgr.getNetworkServiceCapabilities(network.getId(), Service.Firewall); - - - if (caps != null) { - String supportedProtocols = caps.get(Capability.SupportedProtocols).toLowerCase(); - if (!supportedProtocols.contains(proto.toLowerCase())) { - throw new InvalidParameterValueException("Protocol " + proto + " is not supported by the network " + network); - } - - String firewallType = caps.get(Capability.FirewallType); - if (!firewallType.equalsIgnoreCase("networkacl")) { - throw new UnsupportedOperationException("Network ACLS are not supported in network " + network); - } - } else { - throw new InvalidParameterValueException("No capabilities are found for network " + network); - } - } - - protected void detectNetworkACLConflict(NetworkACL newRule) throws NetworkRuleConflictException { - - List<FirewallRuleVO> rules = _firewallDao.listByNetworkPurposeTrafficTypeAndNotRevoked(newRule.getNetworkId(), Purpose.NetworkACL, newRule.getTrafficType()); - assert (rules.size() >= 1) : "For network ACLs, we now always first persist the rule and then check for " + - "network conflicts so we should at least have one rule at this point."; - - for (FirewallRuleVO rule : rules) { - if (rule.getId() == newRule.getId()) { - continue; // Skips my own rule. - } - - // if rules cidrs are different, we can skip port ranges verification - boolean duplicatedCidrs = false; - // Verify that the rules have different cidrs - List<String> ruleCidrList = rule.getSourceCidrList(); - List<String> newRuleCidrList = newRule.getSourceCidrList(); - - if (ruleCidrList == null || newRuleCidrList == null) { - continue; - } - - Collection<String> similar = new HashSet<String>(ruleCidrList); - similar.retainAll(newRuleCidrList); - - if (similar.size() > 0) { - duplicatedCidrs = true; - } - - - if (newRule.getProtocol().equalsIgnoreCase(NetUtils.ICMP_PROTO) && newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())) { - if (newRule.getIcmpCode().longValue() == rule.getIcmpCode().longValue() - && newRule.getIcmpType().longValue() == rule.getIcmpType().longValue() - && newRule.getProtocol().equalsIgnoreCase(rule.getProtocol()) && duplicatedCidrs) { - throw new InvalidParameterValueException("New network ACL conflicts with existing network ACL id=" + rule.getId()); - } - } - - boolean notNullPorts = (newRule.getSourcePortStart() != null && newRule.getSourcePortEnd() != null && - rule.getSourcePortStart() != null && rule.getSourcePortEnd() != null); - if (!notNullPorts) { - continue; - } else if (duplicatedCidrs - && ((rule.getSourcePortStart().intValue() <= newRule.getSourcePortStart().intValue() && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortStart().intValue()) - || (rule.getSourcePortStart().intValue() <= newRule.getSourcePortEnd().intValue() && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortEnd().intValue()) - || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortStart().intValue() && newRule.getSourcePortEnd().intValue() >= rule.getSourcePortStart().intValue()) - || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortEnd().intValue() && newRule.getSourcePortEnd().intValue() >= rule.getSourcePortEnd().intValue()))) { - - throw new NetworkRuleConflictException("The range specified, " + newRule.getSourcePortStart() + "-" - + newRule.getSourcePortEnd() + ", conflicts with rule " + rule.getId() - + " which has " + rule.getSourcePortStart() + "-" + rule.getSourcePortEnd()); - - } - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("No network rule conflicts detected for " + newRule + " against " + (rules.size() - 1) + " existing network ACLs"); - } - } - - @Override - public boolean revokeNetworkACL(long ruleId, boolean apply) { - Account caller = UserContext.current().getCaller(); - long userId = UserContext.current().getCallerUserId(); - return revokeNetworkACL(ruleId, apply, caller, userId); - } - - @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_CLOSE, eventDescription = "revoking firewall rule", async = true) - protected boolean revokeNetworkACL(long ruleId, boolean apply, Account caller, long userId) { - - FirewallRuleVO rule = _firewallDao.findById(ruleId); - if (rule == null || rule.getPurpose() != Purpose.NetworkACL) { - throw new InvalidParameterValueException("Unable to find " + ruleId + " having purpose " + Purpose.NetworkACL); - } - - _accountMgr.checkAccess(caller, null, true, rule); - - _firewallMgr.revokeRule(rule, caller, userId, false); - - boolean success = false; - - if (apply) { - List<FirewallRuleVO> rules = _firewallDao.listByNetworkAndPurpose(rule.getNetworkId(), Purpose.NetworkACL); - return _firewallMgr.applyFirewallRules(rules, false, caller); - } else { - success = true; - } - - return success; - } - - @Override - public NetworkACL getNetworkACL(long ACLId) { - FirewallRuleVO rule = _firewallDao.findById(ACLId); - if (rule != null && rule.getPurpose() == Purpose.NetworkACL) { - return rule; - } - return null; - } - - @Override - public List<? extends NetworkACL> listNetworkACLs(ListNetworkACLsCmd cmd) { - Long networkId = cmd.getNetworkId(); - Long id = cmd.getId(); - String trafficType = cmd.getTrafficType(); - - Account caller = UserContext.current().getCaller(); - List<Long> permittedAccounts = new ArrayList<Long>(); - - Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = - new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null); - _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, - domainIdRecursiveListProject, cmd.listAll(), false); - Long domainId = domainIdRecursiveListProject.first(); - Boolean isRecursive = domainIdRecursiveListProject.second(); - ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); - - Filter filter = new Filter(FirewallRuleVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal()); - SearchBuilder<FirewallRuleVO> sb = _firewallDao.createSearchBuilder(); - _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); - - sb.and("id", sb.entity().getId(), Op.EQ); - sb.and("network", sb.entity().getNetworkId(), Op.EQ); - sb.and("purpose", sb.entity().getPurpose(), Op.EQ); - sb.and("trafficType", sb.entity().getTrafficType(), Op.EQ); - - SearchCriteria<FirewallRuleVO> sc = sb.create(); - _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); - - if (id != null) { - sc.setParameters("id", id); - } - - if (networkId != null) { - sc.setParameters("networkId", networkId); - } - - if (trafficType != null) { - sc.setParameters("trafficType", trafficType); - } - - sc.setParameters("purpose", Purpose.NetworkACL); - - return _firewallDao.search(sc, filter); - } - - - @Override - public List<? extends NetworkACL> listNetworkACLs(long guestNtwkId) { - return _firewallDao.listByNetworkAndPurpose(guestNtwkId, Purpose.NetworkACL); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/b770c8b9/server/src/com/cloud/network/vpc/NetworkACLManagerImpl.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/network/vpc/NetworkACLManagerImpl.java b/server/src/com/cloud/network/vpc/NetworkACLManagerImpl.java new file mode 100644 index 0000000..be30e8c --- /dev/null +++ b/server/src/com/cloud/network/vpc/NetworkACLManagerImpl.java @@ -0,0 +1,370 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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. +// +// Automatically generated by addcopyright.py at 04/03/2012 +package com.cloud.network.vpc; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; + +import com.cloud.acl.SecurityChecker.AccessType; +import com.cloud.api.commands.ListNetworkACLsCmd; +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.network.Network.Capability; +import com.cloud.network.Network.Service; +import com.cloud.network.NetworkManager; +import com.cloud.network.Networks; +import com.cloud.network.dao.FirewallRulesDao; +import com.cloud.network.firewall.NetworkACLService; +import com.cloud.network.rules.FirewallManager; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRule.TrafficType; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.network.rules.NetworkACL; +import com.cloud.projects.Project.ListProjectResourcesCriteria; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.UserContext; +import com.cloud.utils.Ternary; +import com.cloud.utils.component.Inject; +import com.cloud.utils.component.Manager; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; + +/** + * @author Alena Prokharchyk + */ + +@Local(value = { NetworkACLService.class}) +public class NetworkACLManagerImpl implements Manager,NetworkACLService{ + String _name; + private static final Logger s_logger = Logger.getLogger(NetworkACLManagerImpl.class); + + + @Inject + AccountManager _accountMgr; + @Inject + FirewallManager _firewallMgr; + @Inject + FirewallRulesDao _firewallDao; + @Inject + NetworkManager _networkMgr; + @Inject + VpcManager _vpcMgr; + + + @Override + public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { + _name = name; + return true; + } + + @Override + public boolean start() { + return true; + } + + + @Override + public boolean stop() { + return true; + } + + + @Override + public String getName() { + return _name; + } + + @Override + public boolean applyNetworkACLs(long networkId, Account caller) throws ResourceUnavailableException { + List<FirewallRuleVO> rules = _firewallDao.listByNetworkAndPurpose(networkId, Purpose.NetworkACL); + return _firewallMgr.applyFirewallRules(rules, false, caller); + } + + @Override + public NetworkACL createNetworkACL(NetworkACL acl) throws NetworkRuleConflictException { + return createNetworkACL(UserContext.current().getCaller(), acl.getXid(), acl.getSourcePortStart(), + acl.getSourcePortEnd(), acl.getProtocol(), acl.getSourceCidrList(), acl.getIcmpCode(), + acl.getIcmpType(), null, acl.getType(), acl.getNetworkId(), acl.getTrafficType()); + } + + @DB + @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_OPEN, eventDescription = "creating firewall rule", create = true) + protected NetworkACL createNetworkACL(Account caller, String xId, Integer portStart, + Integer portEnd, String protocol, List<String> sourceCidrList, Integer icmpCode, Integer icmpType, + Long relatedRuleId, FirewallRule.FirewallRuleType type, long networkId, TrafficType trafficType) throws NetworkRuleConflictException { + + Network network = _networkMgr.getNetwork(networkId); + if (network == null) { + throw new InvalidParameterValueException("Can't find network by id"); + } + + if (network.getVpcId() == null) { + throw new UnsupportedOperationException("Network ACL rules are supported just for VPC networks"); + } + + Vpc vpc = _vpcMgr.getVpc(network.getVpcId()); + Account aclOwner = _accountMgr.getAccount(vpc.getAccountId()); + + _accountMgr.checkAccess(caller, AccessType.UseNetwork, false, network); + + + if (!_networkMgr.areServicesSupportedInNetwork(networkId, Service.Firewall)) { + throw new InvalidParameterValueException("Service " + Service.Firewall + " is not supported in network " + network); + } + + // icmp code and icmp type can't be passed in for any other protocol rather than icmp + if (!protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (icmpCode != null || icmpType != null)) { + throw new InvalidParameterValueException("Can specify icmpCode and icmpType for ICMP protocol only"); + } + + if (protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (portStart != null || portEnd != null)) { + throw new InvalidParameterValueException("Can't specify start/end port when protocol is ICMP"); + } + + validateNetworkACL(caller, network, portStart, portEnd, protocol); + + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + FirewallRuleVO newRule = new FirewallRuleVO(xId, null, portStart, portEnd, protocol.toLowerCase(), networkId, + aclOwner.getAccountId(), aclOwner.getDomainId(), Purpose.NetworkACL, sourceCidrList, icmpCode, icmpType, + relatedRuleId, trafficType); + newRule.setType(type); + newRule = _firewallDao.persist(newRule); + + if (type == FirewallRule.FirewallRuleType.User) { + detectNetworkACLConflict(newRule); + } + + if (!_firewallDao.setStateToAdd(newRule)) { + throw new CloudRuntimeException("Unable to update the state to add for " + newRule); + } + UserContext.current().setEventDetails("Rule Id: " + newRule.getId()); + + txn.commit(); + + return newRule; + } + + + protected void validateNetworkACL(Account caller, Network network, Integer portStart, Integer portEnd, + String proto) { + + if (portStart != null && !NetUtils.isValidPort(portStart)) { + throw new InvalidParameterValueException("publicPort is an invalid value: " + portStart); + } + if (portEnd != null && !NetUtils.isValidPort(portEnd)) { + throw new InvalidParameterValueException("Public port range is an invalid value: " + portEnd); + } + + // start port can't be bigger than end port + if (portStart != null && portEnd != null && portStart > portEnd) { + throw new InvalidParameterValueException("Start port can't be bigger than end port"); + } + + if (network.getTrafficType() != Networks.TrafficType.Guest) { + throw new InvalidParameterValueException("Network ACL can be created just for networks of type " + Networks.TrafficType.Guest); + } + + // Verify that the network guru supports the protocol specified + Map<Network.Capability, String> caps = _networkMgr.getNetworkServiceCapabilities(network.getId(), Service.Firewall); + + + if (caps != null) { + String supportedProtocols = caps.get(Capability.SupportedProtocols).toLowerCase(); + if (!supportedProtocols.contains(proto.toLowerCase())) { + throw new InvalidParameterValueException("Protocol " + proto + " is not supported by the network " + network); + } + + String firewallType = caps.get(Capability.FirewallType); + if (!firewallType.equalsIgnoreCase("networkacl")) { + throw new UnsupportedOperationException("Network ACLS are not supported in network " + network); + } + } else { + throw new InvalidParameterValueException("No capabilities are found for network " + network); + } + } + + protected void detectNetworkACLConflict(NetworkACL newRule) throws NetworkRuleConflictException { + + List<FirewallRuleVO> rules = _firewallDao.listByNetworkPurposeTrafficTypeAndNotRevoked(newRule.getNetworkId(), Purpose.NetworkACL, newRule.getTrafficType()); + assert (rules.size() >= 1) : "For network ACLs, we now always first persist the rule and then check for " + + "network conflicts so we should at least have one rule at this point."; + + for (FirewallRuleVO rule : rules) { + if (rule.getId() == newRule.getId()) { + continue; // Skips my own rule. + } + + // if rules cidrs are different, we can skip port ranges verification + boolean duplicatedCidrs = false; + // Verify that the rules have different cidrs + List<String> ruleCidrList = rule.getSourceCidrList(); + List<String> newRuleCidrList = newRule.getSourceCidrList(); + + if (ruleCidrList == null || newRuleCidrList == null) { + continue; + } + + Collection<String> similar = new HashSet<String>(ruleCidrList); + similar.retainAll(newRuleCidrList); + + if (similar.size() > 0) { + duplicatedCidrs = true; + } + + + if (newRule.getProtocol().equalsIgnoreCase(NetUtils.ICMP_PROTO) && newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())) { + if (newRule.getIcmpCode().longValue() == rule.getIcmpCode().longValue() + && newRule.getIcmpType().longValue() == rule.getIcmpType().longValue() + && newRule.getProtocol().equalsIgnoreCase(rule.getProtocol()) && duplicatedCidrs) { + throw new InvalidParameterValueException("New network ACL conflicts with existing network ACL id=" + rule.getId()); + } + } + + boolean notNullPorts = (newRule.getSourcePortStart() != null && newRule.getSourcePortEnd() != null && + rule.getSourcePortStart() != null && rule.getSourcePortEnd() != null); + if (!notNullPorts) { + continue; + } else if (duplicatedCidrs + && ((rule.getSourcePortStart().intValue() <= newRule.getSourcePortStart().intValue() && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortStart().intValue()) + || (rule.getSourcePortStart().intValue() <= newRule.getSourcePortEnd().intValue() && rule.getSourcePortEnd().intValue() >= newRule.getSourcePortEnd().intValue()) + || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortStart().intValue() && newRule.getSourcePortEnd().intValue() >= rule.getSourcePortStart().intValue()) + || (newRule.getSourcePortStart().intValue() <= rule.getSourcePortEnd().intValue() && newRule.getSourcePortEnd().intValue() >= rule.getSourcePortEnd().intValue()))) { + + throw new NetworkRuleConflictException("The range specified, " + newRule.getSourcePortStart() + "-" + + newRule.getSourcePortEnd() + ", conflicts with rule " + rule.getId() + + " which has " + rule.getSourcePortStart() + "-" + rule.getSourcePortEnd()); + + } + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("No network rule conflicts detected for " + newRule + " against " + (rules.size() - 1) + " existing network ACLs"); + } + } + + @Override + public boolean revokeNetworkACL(long ruleId, boolean apply) { + Account caller = UserContext.current().getCaller(); + long userId = UserContext.current().getCallerUserId(); + return revokeNetworkACL(ruleId, apply, caller, userId); + } + + @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_CLOSE, eventDescription = "revoking firewall rule", async = true) + protected boolean revokeNetworkACL(long ruleId, boolean apply, Account caller, long userId) { + + FirewallRuleVO rule = _firewallDao.findById(ruleId); + if (rule == null || rule.getPurpose() != Purpose.NetworkACL) { + throw new InvalidParameterValueException("Unable to find " + ruleId + " having purpose " + Purpose.NetworkACL); + } + + _accountMgr.checkAccess(caller, null, true, rule); + + _firewallMgr.revokeRule(rule, caller, userId, false); + + boolean success = false; + + if (apply) { + List<FirewallRuleVO> rules = _firewallDao.listByNetworkAndPurpose(rule.getNetworkId(), Purpose.NetworkACL); + return _firewallMgr.applyFirewallRules(rules, false, caller); + } else { + success = true; + } + + return success; + } + + @Override + public NetworkACL getNetworkACL(long ACLId) { + FirewallRuleVO rule = _firewallDao.findById(ACLId); + if (rule != null && rule.getPurpose() == Purpose.NetworkACL) { + return rule; + } + return null; + } + + @Override + public List<? extends NetworkACL> listNetworkACLs(ListNetworkACLsCmd cmd) { + Long networkId = cmd.getNetworkId(); + Long id = cmd.getId(); + String trafficType = cmd.getTrafficType(); + + Account caller = UserContext.current().getCaller(); + List<Long> permittedAccounts = new ArrayList<Long>(); + + Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = + new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null); + _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, + domainIdRecursiveListProject, cmd.listAll(), false); + Long domainId = domainIdRecursiveListProject.first(); + Boolean isRecursive = domainIdRecursiveListProject.second(); + ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third(); + + Filter filter = new Filter(FirewallRuleVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal()); + SearchBuilder<FirewallRuleVO> sb = _firewallDao.createSearchBuilder(); + _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + + sb.and("id", sb.entity().getId(), Op.EQ); + sb.and("network", sb.entity().getNetworkId(), Op.EQ); + sb.and("purpose", sb.entity().getPurpose(), Op.EQ); + sb.and("trafficType", sb.entity().getTrafficType(), Op.EQ); + + SearchCriteria<FirewallRuleVO> sc = sb.create(); + _accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria); + + if (id != null) { + sc.setParameters("id", id); + } + + if (networkId != null) { + sc.setParameters("networkId", networkId); + } + + if (trafficType != null) { + sc.setParameters("trafficType", trafficType); + } + + sc.setParameters("purpose", Purpose.NetworkACL); + + return _firewallDao.search(sc, filter); + } + + + @Override + public List<? extends NetworkACL> listNetworkACLs(long guestNtwkId) { + return _firewallDao.listByNetworkAndPurpose(guestNtwkId, Purpose.NetworkACL); + } + +}
