mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	status 11537: resolved fixed Reviewed-by: edison@cloud.com Conflicts: server/src/com/cloud/network/firewall/FirewallManagerImpl.java server/src/com/cloud/vm/UserVmManagerImpl.java
		
			
				
	
	
		
			1129 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			Java
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1129 lines
		
	
	
		
			45 KiB
		
	
	
	
		
			Java
		
	
	
		
			Executable File
		
	
	
	
	
| /**
 | |
|  *  Copyright (C) 2010 Cloud.com, Inc.  All rights reserved.
 | |
|  * 
 | |
|  * This software is licensed under the GNU General Public License v3 or later.
 | |
|  * 
 | |
|  * It is free software: you can redistribute it and/or modify
 | |
|  * it under the terms of the GNU General Public License as published by
 | |
|  * the Free Software Foundation, either version 3 of the License, or any later version.
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  * 
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  * 
 | |
|  */
 | |
| package com.cloud.network.rules;
 | |
| 
 | |
| import java.util.ArrayList;
 | |
| import java.util.HashSet;
 | |
| import java.util.List;
 | |
| import java.util.Map;
 | |
| import java.util.Set;
 | |
| 
 | |
| import javax.ejb.Local;
 | |
| import javax.naming.ConfigurationException;
 | |
| 
 | |
| import org.apache.log4j.Logger;
 | |
| 
 | |
| import com.cloud.api.commands.ListPortForwardingRulesCmd;
 | |
| import com.cloud.domain.Domain;
 | |
| import com.cloud.domain.DomainVO;
 | |
| import com.cloud.domain.dao.DomainDao;
 | |
| import com.cloud.event.ActionEvent;
 | |
| import com.cloud.event.EventTypes;
 | |
| import com.cloud.event.UsageEventVO;
 | |
| import com.cloud.event.dao.EventDao;
 | |
| import com.cloud.event.dao.UsageEventDao;
 | |
| import com.cloud.exception.InvalidParameterValueException;
 | |
| import com.cloud.exception.NetworkRuleConflictException;
 | |
| import com.cloud.exception.ResourceUnavailableException;
 | |
| import com.cloud.network.IPAddressVO;
 | |
| import com.cloud.network.IpAddress;
 | |
| import com.cloud.network.Network;
 | |
| import com.cloud.network.Network.Service;
 | |
| import com.cloud.network.NetworkManager;
 | |
| import com.cloud.network.dao.FirewallRulesCidrsDao;
 | |
| import com.cloud.network.dao.FirewallRulesDao;
 | |
| import com.cloud.network.dao.IPAddressDao;
 | |
| import com.cloud.network.rules.FirewallRule.Purpose;
 | |
| import com.cloud.network.rules.dao.PortForwardingRulesDao;
 | |
| import com.cloud.user.Account;
 | |
| import com.cloud.user.AccountManager;
 | |
| import com.cloud.user.DomainManager;
 | |
| import com.cloud.user.UserContext;
 | |
| import com.cloud.uservm.UserVm;
 | |
| import com.cloud.utils.Pair;
 | |
| 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.JoinBuilder;
 | |
| 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.Ip;
 | |
| import com.cloud.vm.Nic;
 | |
| import com.cloud.vm.UserVmVO;
 | |
| import com.cloud.vm.VirtualMachine;
 | |
| import com.cloud.vm.dao.UserVmDao;
 | |
| 
 | |
| @Local(value = { RulesManager.class, RulesService.class })
 | |
| public class RulesManagerImpl implements RulesManager, RulesService, Manager {
 | |
|     private static final Logger s_logger = Logger.getLogger(RulesManagerImpl.class);
 | |
|     String _name;
 | |
| 
 | |
|     @Inject
 | |
|     PortForwardingRulesDao _forwardingDao;
 | |
|     @Inject
 | |
|     FirewallRulesCidrsDao _firewallCidrsDao;
 | |
|     @Inject
 | |
|     FirewallRulesDao _firewallDao;
 | |
|     @Inject
 | |
|     IPAddressDao _ipAddressDao;
 | |
|     @Inject
 | |
|     UserVmDao _vmDao;
 | |
|     @Inject
 | |
|     AccountManager _accountMgr;
 | |
|     @Inject
 | |
|     NetworkManager _networkMgr;
 | |
|     @Inject
 | |
|     EventDao _eventDao;
 | |
|     @Inject
 | |
|     UsageEventDao _usageEventDao;
 | |
|     @Inject
 | |
|     DomainDao _domainDao;
 | |
|     @Inject
 | |
|     FirewallManager _firewallMgr;
 | |
|     @Inject
 | |
|     DomainManager _domainMgr;
 | |
| 
 | |
|     @Override
 | |
|     public void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller) {
 | |
|         if (ipAddress == null || ipAddress.getAllocatedTime() == null || ipAddress.getAllocatedToAccountId() == null) {
 | |
|             throw new InvalidParameterValueException("Unable to create ip forwarding rule on address " + ipAddress + ", invalid IP address specified.");
 | |
|         }
 | |
| 
 | |
|         if (userVm == null) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         if (userVm.getState() == VirtualMachine.State.Destroyed || userVm.getState() == VirtualMachine.State.Expunging) {
 | |
|             throw new InvalidParameterValueException("Invalid user vm: " + userVm.getId());
 | |
|         }
 | |
| 
 | |
|         _accountMgr.checkAccess(caller, null, ipAddress);
 | |
|         _accountMgr.checkAccess(caller, null, userVm);
 | |
| 
 | |
|         // validate that IP address and userVM belong to the same account
 | |
|         if (ipAddress.getAllocatedToAccountId().longValue() != userVm.getAccountId()) {
 | |
|             throw new InvalidParameterValueException("Unable to create ip forwarding rule, IP address " + ipAddress + " owner is not the same as owner of virtual machine " + userVm.toString());
 | |
|         }
 | |
| 
 | |
|         // validate that userVM is in the same availability zone as the IP address
 | |
|         if (ipAddress.getDataCenterId() != userVm.getDataCenterIdToDeployIn()) {
 | |
|             throw new InvalidParameterValueException("Unable to create ip forwarding rule, IP address " + ipAddress + " is not in the same availability zone as virtual machine " + userVm.toString());
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public void checkRuleAndUserVm(FirewallRule rule, UserVm userVm, Account caller) {
 | |
|         if (userVm == null || rule == null) {
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         _accountMgr.checkAccess(caller, null, rule);
 | |
|         _accountMgr.checkAccess(caller, null, userVm);
 | |
| 
 | |
|         if (userVm.getState() == VirtualMachine.State.Destroyed || userVm.getState() == VirtualMachine.State.Expunging) {
 | |
|             throw new InvalidParameterValueException("Invalid user vm: " + userVm.getId());
 | |
|         }
 | |
| 
 | |
|         if (rule.getAccountId() != userVm.getAccountId()) {
 | |
|             throw new InvalidParameterValueException("Rule id=" + rule.getId() + " and vm id=" + userVm.getId() + " belong to different accounts");
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override @DB
 | |
|     @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_ADD, eventDescription = "creating forwarding rule", create = true)
 | |
|     public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, boolean openFirewall) throws NetworkRuleConflictException {
 | |
|         UserContext ctx = UserContext.current();
 | |
|         Account caller = ctx.getCaller();
 | |
| 
 | |
|         Long ipAddrId = rule.getSourceIpAddressId();
 | |
| 
 | |
|         IPAddressVO ipAddress = _ipAddressDao.findById(ipAddrId);
 | |
|         
 | |
|         // Validate ip address
 | |
|         if (ipAddress == null) {
 | |
|             throw new InvalidParameterValueException("Unable to create port forwarding rule; ip id=" + ipAddrId + " doesn't exist in the system");
 | |
|         } else if (ipAddress.isOneToOneNat()) {
 | |
|             throw new InvalidParameterValueException("Unable to create port forwarding rule; ip id=" + ipAddrId + " has static nat enabled");
 | |
|         } 
 | |
|         
 | |
|         _firewallMgr.validateFirewallRule(caller, ipAddress, rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), Purpose.PortForwarding);
 | |
|         
 | |
|         Long networkId = ipAddress.getAssociatedWithNetworkId();
 | |
|         Long accountId = ipAddress.getAccountId();
 | |
|         Long domainId = ipAddress.getDomainId();
 | |
|         
 | |
|         // start port can't be bigger than end port
 | |
|         if (rule.getDestinationPortStart() > rule.getDestinationPortEnd()) {
 | |
|             throw new InvalidParameterValueException("Start port can't be bigger than end port");
 | |
|         }
 | |
|         
 | |
|         // check that the port ranges are of equal size
 | |
|         if ((rule.getDestinationPortEnd() - rule.getDestinationPortStart()) != (rule.getSourcePortEnd() - rule.getSourcePortStart())) {
 | |
|             throw new InvalidParameterValueException("Source port and destination port ranges should be of equal sizes.");
 | |
|         }
 | |
|         
 | |
|         // validate user VM exists
 | |
|         UserVm vm = _vmDao.findById(vmId);
 | |
|         if (vm == null) {
 | |
|             throw new InvalidParameterValueException("Unable to create port forwarding rule on address " + ipAddress + ", invalid virtual machine id specified (" + vmId + ").");
 | |
|         } else {
 | |
|             checkRuleAndUserVm(rule, vm, caller);
 | |
|         }
 | |
| 
 | |
|         // Verify that vm has nic in the network
 | |
|         Ip dstIp = rule.getDestinationIpAddress();
 | |
|         Nic guestNic = _networkMgr.getNicInNetwork(vmId, networkId);
 | |
|         if (guestNic == null || guestNic.getIp4Address() == null) {
 | |
|             throw new InvalidParameterValueException("Vm doesn't belong to network associated with ipAddress");
 | |
|         } else {
 | |
|             dstIp = new Ip(guestNic.getIp4Address());
 | |
|         }
 | |
| 
 | |
|         Transaction txn = Transaction.currentTxn();
 | |
|         txn.start();
 | |
|         
 | |
|         PortForwardingRuleVO newRule = new PortForwardingRuleVO(rule.getXid(), rule.getSourceIpAddressId(), rule.getSourcePortStart(), rule.getSourcePortEnd(), dstIp, rule.getDestinationPortStart(),
 | |
|                 rule.getDestinationPortEnd(), rule.getProtocol().toLowerCase(), networkId, accountId, domainId, vmId);
 | |
|         newRule = _forwardingDao.persist(newRule);
 | |
|         
 | |
|         //create firewallRule for 0.0.0.0/0 cidr
 | |
|         if (openFirewall) {
 | |
|             _firewallMgr.createRuleForAllCidrs(ipAddrId, caller, rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), null, null, newRule.getId());
 | |
|         }
 | |
| 
 | |
|         try {
 | |
|             _firewallMgr.detectRulesConflict(newRule, ipAddress);
 | |
|             if (!_firewallDao.setStateToAdd(newRule)) {
 | |
|                 throw new CloudRuntimeException("Unable to update the state to add for " + newRule);
 | |
|             }
 | |
|             UserContext.current().setEventDetails("Rule Id: " + newRule.getId());
 | |
|             UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_RULE_ADD, newRule.getAccountId(), ipAddress.getDataCenterId(), newRule.getId(), null);
 | |
|             _usageEventDao.persist(usageEvent);
 | |
|             txn.commit();
 | |
|             return newRule;
 | |
|         } catch (Exception e) {
 | |
|             
 | |
|             txn.start();
 | |
|             //no need to apply the rule as it wasn't programmed on the backend yet
 | |
|             _firewallMgr.revokeRelatedFirewallRule(newRule.getId(), false);
 | |
|             _forwardingDao.remove(newRule.getId());
 | |
|             
 | |
|             txn.commit();
 | |
|             
 | |
|             if (e instanceof NetworkRuleConflictException) {
 | |
|                 throw (NetworkRuleConflictException) e;
 | |
|             }
 | |
|             throw new CloudRuntimeException("Unable to add rule for the ip id=" + ipAddrId, e);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override @DB
 | |
|     @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_ADD, eventDescription = "creating static nat rule", create = true)
 | |
|     public StaticNatRule createStaticNatRule(StaticNatRule rule, boolean openFirewall) throws NetworkRuleConflictException {
 | |
|         Account caller = UserContext.current().getCaller();
 | |
| 
 | |
|         Long ipAddrId = rule.getSourceIpAddressId();
 | |
| 
 | |
|         IPAddressVO ipAddress = _ipAddressDao.findById(ipAddrId);
 | |
|         
 | |
|         // Validate ip address
 | |
|         if (ipAddress == null) {
 | |
|             throw new InvalidParameterValueException("Unable to create static nat rule; ip id=" + ipAddrId + " doesn't exist in the system");
 | |
|         } else if (ipAddress.isSourceNat() || !ipAddress.isOneToOneNat() || ipAddress.getAssociatedWithVmId() == null) {
 | |
|             throw new NetworkRuleConflictException("Can't do static nat on ip address: " + ipAddress.getAddress());
 | |
|         } 
 | |
|         
 | |
|         _firewallMgr.validateFirewallRule(caller, ipAddress, rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), Purpose.StaticNat);
 | |
|         
 | |
|         Long networkId = ipAddress.getAssociatedWithNetworkId();
 | |
|         Long accountId = ipAddress.getAccountId();
 | |
|         Long domainId = ipAddress.getDomainId();
 | |
| 
 | |
| 
 | |
|         String dstIp = _networkMgr.getIpInNetwork(ipAddress.getAssociatedWithVmId(), networkId);
 | |
| 
 | |
|         Transaction txn = Transaction.currentTxn();
 | |
|         txn.start();
 | |
|         
 | |
| 
 | |
|         FirewallRuleVO newRule = new FirewallRuleVO(rule.getXid(), rule.getSourceIpAddressId(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol().toLowerCase(), 
 | |
|                 networkId, accountId, domainId, rule.getPurpose(), null, null, null, null);
 | |
| 
 | |
|         newRule = _firewallDao.persist(newRule);
 | |
|         
 | |
|         //create firewallRule for 0.0.0.0/0 cidr
 | |
|         if (openFirewall) {
 | |
|             _firewallMgr.createRuleForAllCidrs(ipAddrId, caller, rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), null, null, newRule.getId());
 | |
|         }
 | |
|         
 | |
| 
 | |
|         try {
 | |
|             _firewallMgr.detectRulesConflict(newRule, ipAddress);
 | |
|             if (!_firewallDao.setStateToAdd(newRule)) {
 | |
|                 throw new CloudRuntimeException("Unable to update the state to add for " + newRule);
 | |
|             }
 | |
|             UserContext.current().setEventDetails("Rule Id: " + newRule.getId());
 | |
|             UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_RULE_ADD, newRule.getAccountId(), 0, newRule.getId(), null);
 | |
|             _usageEventDao.persist(usageEvent);
 | |
| 
 | |
|             txn.commit();
 | |
|             StaticNatRule staticNatRule = new StaticNatRuleImpl(newRule, dstIp);
 | |
| 
 | |
|             return staticNatRule;
 | |
|         } catch (Exception e) {
 | |
|             
 | |
|             txn.start();
 | |
|             //no need to apply the rule as it wasn't programmed on the backend yet
 | |
|             _firewallMgr.revokeRelatedFirewallRule(newRule.getId(), false);
 | |
|             _forwardingDao.remove(newRule.getId()); 
 | |
|             txn.commit();
 | |
|             
 | |
|             if (e instanceof NetworkRuleConflictException) {
 | |
|                 throw (NetworkRuleConflictException) e;
 | |
|             }
 | |
|             throw new CloudRuntimeException("Unable to add static nat rule for the ip id=" + newRule.getSourceIpAddressId(), e);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean enableStaticNat(long ipId, long vmId) throws NetworkRuleConflictException {
 | |
| 
 | |
|         Account caller = UserContext.current().getCaller();
 | |
| 
 | |
|         // Verify input parameters
 | |
|         UserVmVO vm = _vmDao.findById(vmId);
 | |
|         if (vm == null) {
 | |
|             throw new InvalidParameterValueException("Can't enable static nat for the address id=" + ipId + ", invalid virtual machine id specified (" + vmId + ").");
 | |
|         }
 | |
| 
 | |
|         IPAddressVO ipAddress = _ipAddressDao.findById(ipId);
 | |
|         if (ipAddress == null) {
 | |
|             throw new InvalidParameterValueException("Unable to find ip address by id " + ipId);
 | |
|         }
 | |
| 
 | |
|         // Check permissions
 | |
|         checkIpAndUserVm(ipAddress, vm, caller);
 | |
| 
 | |
|         // Verify that the ip is associated with the network and firewallService is supported for the network
 | |
|         Long networkId = ipAddress.getAssociatedWithNetworkId();
 | |
|         if (networkId == null) {
 | |
|             throw new InvalidParameterValueException("Unable to enable static nat for the ipAddress id=" + ipId + " as ip is not associated with any network");
 | |
|         }
 | |
| 
 | |
|         // Check that vm has a nic in the network
 | |
|         Nic guestNic = _networkMgr.getNicInNetwork(vmId, networkId);
 | |
|         if (guestNic == null) {
 | |
|             throw new InvalidParameterValueException("Vm doesn't belong to the network " + networkId);
 | |
|         }
 | |
| 
 | |
|         Network network = _networkMgr.getNetwork(networkId);
 | |
|         if (!_networkMgr.isServiceSupported(network.getNetworkOfferingId(), Service.Firewall)) {
 | |
|             throw new InvalidParameterValueException("Unable to create static nat rule; Firewall service is not supported in network id=" + networkId);
 | |
|         }
 | |
| 
 | |
|         // Verify ip address parameter
 | |
|         if (ipAddress.isSourceNat()) {
 | |
|             throw new InvalidParameterValueException("Can't enable static, ip address id=" + ipId + " is a sourceNat ip address");
 | |
|         }
 | |
| 
 | |
|         if (!ipAddress.isOneToOneNat()) {
 | |
|             List<FirewallRuleVO> rules = _firewallDao.listByIpAndPurposeAndNotRevoked(ipId, Purpose.PortForwarding);
 | |
|             if (rules != null && !rules.isEmpty()) {
 | |
|                 throw new NetworkRuleConflictException("Failed to enable static nat for the ip address id=" + ipId + " as it already has firewall rules assigned");
 | |
|             }
 | |
|         } else {
 | |
|             if (ipAddress.getAssociatedWithVmId() != null && ipAddress.getAssociatedWithVmId().longValue() != vmId) {
 | |
|                 throw new NetworkRuleConflictException("Failed to enable static for the ip address id=" + ipId + " and vm id=" + vmId + " as it's already assigned to antoher vm");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // If there is public ip address already associated with the vm, throw an exception
 | |
|         IPAddressVO ip = _ipAddressDao.findByAssociatedVmId(vmId);
 | |
| 
 | |
|         if (ip != null) {
 | |
|             throw new InvalidParameterValueException("Failed to enable static nat for the ip address id=" + ipId + " as vm id=" + " is already associated with ip id=" + ip.getId());
 | |
|         }
 | |
| 
 | |
|         ipAddress.setOneToOneNat(true);
 | |
|         ipAddress.setAssociatedWithVmId(vmId);
 | |
| 
 | |
|         if (_ipAddressDao.update(ipAddress.getId(), ipAddress)) {
 | |
|             //enable static nat on the backend
 | |
|             s_logger.trace("Enabling static nat for ip address " + ipAddress + " and vm id=" + vmId + " on the backend");
 | |
|             if (applyStaticNatForIp(ipId, false, caller, false)) {
 | |
|                 return true;
 | |
|             } else {
 | |
|                 ipAddress.setOneToOneNat(false);
 | |
|                 ipAddress.setAssociatedWithVmId(null);
 | |
|                 _ipAddressDao.update(ipAddress.getId(), ipAddress);
 | |
|                 s_logger.warn("Failed to enable static nat rule for ip address " + ipId + " on the backend");
 | |
|                 return false;
 | |
|             }
 | |
|         } else {
 | |
|             s_logger.warn("Failed to update ip address " + ipAddress + " in the DB as a part of enableStaticNat");
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     @Override
 | |
|     @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_DELETE, eventDescription = "revoking forwarding rule", async = true)
 | |
|     public boolean revokePortForwardingRule(long ruleId, boolean apply) {
 | |
|         UserContext ctx = UserContext.current();
 | |
|         Account caller = ctx.getCaller();
 | |
| 
 | |
|         PortForwardingRuleVO rule = _forwardingDao.findById(ruleId);
 | |
|         if (rule == null) {
 | |
|             throw new InvalidParameterValueException("Unable to find " + ruleId);
 | |
|         }
 | |
| 
 | |
|         _accountMgr.checkAccess(caller, null, rule);
 | |
| 
 | |
|         return revokePortForwardingRuleInternal(ruleId, caller, ctx.getCallerUserId(), apply);
 | |
|     }
 | |
| 
 | |
|     private boolean revokePortForwardingRuleInternal(long ruleId, Account caller, long userId, boolean apply) {
 | |
|         PortForwardingRuleVO rule = _forwardingDao.findById(ruleId);
 | |
| 
 | |
|         _firewallMgr.revokeRule(rule, caller, userId, true);
 | |
| 
 | |
|         boolean success = false;
 | |
| 
 | |
|         if (apply) {
 | |
|             success = applyPortForwardingRules(rule.getSourceIpAddressId(), true, caller);
 | |
|         } else {
 | |
|             success = true;
 | |
|         }
 | |
| 
 | |
|         return success;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_DELETE, eventDescription = "revoking forwarding rule", async = true)
 | |
|     public boolean revokeStaticNatRule(long ruleId, boolean apply) {
 | |
|         UserContext ctx = UserContext.current();
 | |
|         Account caller = ctx.getCaller();
 | |
| 
 | |
|         FirewallRuleVO rule = _firewallDao.findById(ruleId);
 | |
|         if (rule == null) {
 | |
|             throw new InvalidParameterValueException("Unable to find " + ruleId);
 | |
|         }
 | |
| 
 | |
|         _accountMgr.checkAccess(caller, null, rule);
 | |
| 
 | |
|         return revokeStaticNatRuleInternal(ruleId, caller, ctx.getCallerUserId(), apply);
 | |
|     }
 | |
| 
 | |
|     private boolean revokeStaticNatRuleInternal(long ruleId, Account caller, long userId, boolean apply) {
 | |
|         FirewallRuleVO rule = _firewallDao.findById(ruleId);
 | |
| 
 | |
|         _firewallMgr.revokeRule(rule, caller, userId, true);
 | |
| 
 | |
|         boolean success = false;
 | |
| 
 | |
|         if (apply) {
 | |
|             success = applyStaticNatRules(rule.getSourceIpAddressId(), true, caller);
 | |
|         } else {
 | |
|             success = true;
 | |
|         }
 | |
| 
 | |
|         return success;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean revokePortForwardingRulesForVm(long vmId) {
 | |
|         boolean success = true;
 | |
|         UserVmVO vm = _vmDao.findByIdIncludingRemoved(vmId);
 | |
|         if (vm == null) {
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         List<PortForwardingRuleVO> rules = _forwardingDao.listByVm(vmId);
 | |
|         Set<Long> ipsToReprogram = new HashSet<Long>();
 | |
| 
 | |
|         if (rules == null || rules.isEmpty()) {
 | |
|             s_logger.debug("No port forwarding rules are found for vm id=" + vmId);
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         for (PortForwardingRuleVO rule : rules) {
 | |
|             // Mark port forwarding rule as Revoked, but don't revoke it yet (apply=false)
 | |
|             revokePortForwardingRuleInternal(rule.getId(), _accountMgr.getSystemAccount(), Account.ACCOUNT_ID_SYSTEM, false);
 | |
|             ipsToReprogram.add(rule.getSourceIpAddressId());
 | |
|         }
 | |
| 
 | |
|         // apply rules for all ip addresses
 | |
|         for (Long ipId : ipsToReprogram) {
 | |
|             s_logger.debug("Applying port forwarding rules for ip address id=" + ipId + " as a part of vm expunge");
 | |
|             if (!applyPortForwardingRules(ipId, true, _accountMgr.getSystemAccount())) {
 | |
|                 s_logger.warn("Failed to apply port forwarding rules for ip id=" + ipId);
 | |
|                 success = false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return success;
 | |
|     }
 | |
|     
 | |
|     @Override
 | |
|     public boolean revokeStaticNatRulesForVm(long vmId) {
 | |
|         boolean success = true;
 | |
| 
 | |
|         UserVmVO vm = _vmDao.findByIdIncludingRemoved(vmId);
 | |
|         if (vm == null) {
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         List<FirewallRuleVO> rules = _firewallDao.listStaticNatByVmId(vm.getId());
 | |
|         Set<Long> ipsToReprogram = new HashSet<Long>();
 | |
| 
 | |
|         if (rules == null || rules.isEmpty()) {
 | |
|             s_logger.debug("No static nat rules are found for vm id=" + vmId);
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         for (FirewallRuleVO rule : rules) {
 | |
|             // mark static nat as Revoked, but don't revoke it yet (apply = false)
 | |
|             revokeStaticNatRuleInternal(rule.getId(), _accountMgr.getSystemAccount(), Account.ACCOUNT_ID_SYSTEM, false);
 | |
|             ipsToReprogram.add(rule.getSourceIpAddressId());
 | |
|         }
 | |
| 
 | |
|         // apply rules for all ip addresses
 | |
|         for (Long ipId : ipsToReprogram) {
 | |
|             s_logger.debug("Applying static nat rules for ip address id=" + ipId + " as a part of vm expunge");
 | |
|             if (!applyStaticNatRules(ipId, true, _accountMgr.getSystemAccount())) {
 | |
|                 success = false;
 | |
|                 s_logger.warn("Failed to apply static nat rules for ip id=" + ipId);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return success;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<? extends PortForwardingRule> listPortForwardingRulesForApplication(long ipId) {
 | |
|         return _forwardingDao.listForApplication(ipId);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<? extends PortForwardingRule> listPortForwardingRules(ListPortForwardingRulesCmd cmd) {
 | |
|         Account caller = UserContext.current().getCaller();
 | |
|         Long ipId = cmd.getIpAddressId();
 | |
|         Long id = cmd.getId();
 | |
|         String path = null;
 | |
| 
 | |
|         Pair<String, Long> accountDomainPair = _accountMgr.finalizeAccountDomainForList(caller, cmd.getAccountName(), cmd.getDomainId());
 | |
|         String accountName = accountDomainPair.first();
 | |
|         Long domainId = accountDomainPair.second();
 | |
| 
 | |
|         if (ipId != null) {
 | |
|             IPAddressVO ipAddressVO = _ipAddressDao.findById(ipId);
 | |
|             if (ipAddressVO == null || !ipAddressVO.readyToUse()) {
 | |
|                 throw new InvalidParameterValueException("Ip address id=" + ipId + " not ready for port forwarding rules yet");
 | |
|             }
 | |
|             _accountMgr.checkAccess(caller, null, ipAddressVO);
 | |
|         }
 | |
| 
 | |
|         if (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) {
 | |
|             Domain domain = _domainMgr.getDomain(caller.getDomainId());
 | |
|             path = domain.getPath();
 | |
|         }
 | |
| 
 | |
|         Filter filter = new Filter(PortForwardingRuleVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal());
 | |
|         SearchBuilder<PortForwardingRuleVO> sb = _forwardingDao.createSearchBuilder();
 | |
|         sb.and("id", sb.entity().getId(), Op.EQ);
 | |
|         sb.and("ip", sb.entity().getSourceIpAddressId(), Op.EQ);
 | |
|         sb.and("accountId", sb.entity().getAccountId(), Op.EQ);
 | |
|         sb.and("domainId", sb.entity().getDomainId(), Op.EQ);
 | |
|         sb.and("purpose", sb.entity().getPurpose(), Op.EQ);
 | |
| 
 | |
|         if (path != null) {
 | |
|             // for domain admin we should show only subdomains information
 | |
|             SearchBuilder<DomainVO> domainSearch = _domainDao.createSearchBuilder();
 | |
|             domainSearch.and("path", domainSearch.entity().getPath(), SearchCriteria.Op.LIKE);
 | |
|             sb.join("domainSearch", domainSearch, sb.entity().getDomainId(), domainSearch.entity().getId(), JoinBuilder.JoinType.INNER);
 | |
|         }
 | |
| 
 | |
|         SearchCriteria<PortForwardingRuleVO> sc = sb.create();
 | |
| 
 | |
|         if (id != null) {
 | |
|             sc.setParameters("id", id);
 | |
|         }
 | |
| 
 | |
|         if (ipId != null) {
 | |
|             sc.setParameters("ip", ipId);
 | |
|         }
 | |
| 
 | |
|         if (domainId != null) {
 | |
|             sc.setParameters("domainId", domainId);
 | |
|             if (accountName != null) {
 | |
|                 Account account = _accountMgr.getActiveAccountByName(accountName, domainId);
 | |
|                 sc.setParameters("accountId", account.getId());
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         sc.setParameters("purpose", Purpose.PortForwarding);
 | |
| 
 | |
|         if (path != null) {
 | |
|             sc.setJoinParameters("domainSearch", "path", path + "%");
 | |
|         }
 | |
| 
 | |
|         return _forwardingDao.search(sc, filter);
 | |
|     }
 | |
|     
 | |
|     @Override
 | |
|     public List<String> getSourceCidrs(long ruleId){
 | |
|         return _firewallCidrsDao.getSourceCidrs(ruleId);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean applyPortForwardingRules(long ipId, boolean continueOnError, Account caller) {
 | |
|         List<PortForwardingRuleVO> rules = _forwardingDao.listForApplication(ipId);
 | |
|         
 | |
|         if (rules.size() == 0) {
 | |
|             s_logger.debug("There are no firwall rules to apply for ip id=" + ipId);
 | |
|             return true;
 | |
|         }
 | |
|         
 | |
| 
 | |
|         if (caller != null) {
 | |
|             _accountMgr.checkAccess(caller, null, rules.toArray(new PortForwardingRuleVO[rules.size()]));
 | |
|         }
 | |
| 
 | |
|         try {
 | |
|             if (!_firewallMgr.applyRules(rules, continueOnError)) {
 | |
|                 return false;
 | |
|             }
 | |
|         } catch (ResourceUnavailableException ex) {
 | |
|             s_logger.warn("Failed to apply firewall rules due to ", ex);
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean applyStaticNatRules(long sourceIpId, boolean continueOnError, Account caller) {
 | |
|         List<? extends FirewallRule> rules = _firewallDao.listByIpAndPurpose(sourceIpId, Purpose.StaticNat);
 | |
|         List<StaticNatRule> staticNatRules = new ArrayList<StaticNatRule>();
 | |
| 
 | |
|         if (rules.size() == 0) {
 | |
|             s_logger.debug("There are no firwall rules to apply for ip id=" + sourceIpId);
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         for (FirewallRule rule : rules) {
 | |
|             IpAddress sourceIp = _ipAddressDao.findById(rule.getSourceIpAddressId());
 | |
| 
 | |
|             UserVmVO vm = _vmDao.findById(sourceIp.getAssociatedWithVmId());
 | |
| 
 | |
|             Long networkId = sourceIp.getAssociatedWithNetworkId();
 | |
|             if (networkId == null) {
 | |
|                 throw new CloudRuntimeException("Ip address is not associated with any network");
 | |
|             }
 | |
| 
 | |
|             Network network = _networkMgr.getNetwork(networkId);
 | |
| 
 | |
|             if (network == null) {
 | |
|                 throw new CloudRuntimeException("Unable to find ip address to map to in vm id=" + vm.getId());
 | |
|             }
 | |
| 
 | |
|             Nic guestNic = _networkMgr.getNicInNetworkIncludingRemoved(vm.getId(), networkId);
 | |
|             FirewallRuleVO ruleVO = _firewallDao.findById(rule.getId());
 | |
| 
 | |
|             staticNatRules.add(new StaticNatRuleImpl(ruleVO, guestNic.getIp4Address()));
 | |
|         }
 | |
| 
 | |
|         if (caller != null) {
 | |
|             _accountMgr.checkAccess(caller, null, staticNatRules.toArray(new StaticNatRule[staticNatRules.size()]));
 | |
|         }
 | |
| 
 | |
|         try {
 | |
|             if (!_firewallMgr.applyRules(staticNatRules, continueOnError)) {
 | |
|                 return false;
 | |
|             }
 | |
|         } catch (ResourceUnavailableException ex) {
 | |
|             s_logger.warn("Failed to apply static nat rules due to ", ex);
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean applyPortForwardingRulesForNetwork(long networkId, boolean continueOnError, Account caller) {
 | |
|         List<PortForwardingRuleVO> rules = listByNetworkId(networkId);
 | |
|         if (rules.size() == 0) {
 | |
|             s_logger.debug("There are no port forwarding rules to apply for network id=" + networkId);
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         if (caller != null) {
 | |
|             _accountMgr.checkAccess(caller, null, rules.toArray(new PortForwardingRuleVO[rules.size()]));
 | |
|         }
 | |
| 
 | |
|         try {
 | |
|             if (!_firewallMgr.applyRules(rules, continueOnError)) {
 | |
|                 return false;
 | |
|             }
 | |
|         } catch (ResourceUnavailableException ex) {
 | |
|             s_logger.warn("Failed to apply firewall rules due to ", ex);
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean applyStaticNatRulesForNetwork(long networkId, boolean continueOnError, Account caller) {
 | |
|         List<FirewallRuleVO> rules = _firewallDao.listByNetworkAndPurpose(networkId, Purpose.StaticNat);
 | |
|         List<StaticNatRule> staticNatRules = new ArrayList<StaticNatRule>();
 | |
| 
 | |
|         if (rules.size() == 0) {
 | |
|             s_logger.debug("There are no static nat rules to apply for network id=" + networkId);
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         if (caller != null) {
 | |
|             _accountMgr.checkAccess(caller, null, rules.toArray(new FirewallRule[rules.size()]));
 | |
|         }
 | |
| 
 | |
|         for (FirewallRuleVO rule : rules) {
 | |
|             staticNatRules.add(buildStaticNatRule(rule));
 | |
|         }
 | |
| 
 | |
|         try {
 | |
|             if (!_firewallMgr.applyRules(staticNatRules, continueOnError)) {
 | |
|                 return false;
 | |
|             }
 | |
|         } catch (ResourceUnavailableException ex) {
 | |
|             s_logger.warn("Failed to apply firewall rules due to ", ex);
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     @Override
 | |
|     public boolean applyStaticNatsForNetwork(long networkId, boolean continueOnError, Account caller) {
 | |
|         List<IPAddressVO> ips = _ipAddressDao.listStaticNatPublicIps(networkId);
 | |
|         if (ips.isEmpty()) {
 | |
|             s_logger.debug("There are no static nat to apply for network id=" + networkId);
 | |
|             return true;
 | |
|         }
 | |
|         
 | |
|         if (caller != null) {
 | |
|             _accountMgr.checkAccess(caller, null, ips.toArray(new IPAddressVO[ips.size()]));
 | |
|         }
 | |
|         
 | |
|         List<StaticNat> staticNats = new ArrayList<StaticNat>();
 | |
|         for (IPAddressVO ip : ips) {
 | |
|             // Get nic IP4 address
 | |
|             String dstIp = _networkMgr.getIpInNetwork(ip.getAssociatedWithVmId(), networkId);
 | |
|             StaticNatImpl staticNat = new StaticNatImpl(ip.getAccountId(), ip.getDomainId(), networkId, ip.getId(), dstIp, false);
 | |
|             staticNats.add(staticNat);
 | |
|         }
 | |
|         
 | |
|         try {
 | |
|             if (!_networkMgr.applyStaticNats(staticNats, continueOnError)) {
 | |
|                 return false;
 | |
|             }
 | |
|         } catch (ResourceUnavailableException ex) {
 | |
|             s_logger.warn("Failed to create static nat rule due to ", ex);
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<? extends FirewallRule> searchStaticNatRules(Long ipId, Long id, Long vmId, Long start, Long size, String accountName, Long domainId) {
 | |
|         Account caller = UserContext.current().getCaller();
 | |
|         String path = null;
 | |
| 
 | |
|         Pair<String, Long> accountDomainPair = _accountMgr.finalizeAccountDomainForList(caller, accountName, domainId);
 | |
|         accountName = accountDomainPair.first();
 | |
|         domainId = accountDomainPair.second();
 | |
| 
 | |
|         if (ipId != null) {
 | |
|             IPAddressVO ipAddressVO = _ipAddressDao.findById(ipId);
 | |
|             if (ipAddressVO == null || !ipAddressVO.readyToUse()) {
 | |
|                 throw new InvalidParameterValueException("Ip address id=" + ipId + " not ready for port forwarding rules yet");
 | |
|             }
 | |
|             _accountMgr.checkAccess(caller, null, ipAddressVO);
 | |
|         }
 | |
| 
 | |
|         if (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) {
 | |
|             Domain domain = _domainMgr.getDomain(caller.getDomainId());
 | |
|             path = domain.getPath();
 | |
|         }
 | |
| 
 | |
|         Filter filter = new Filter(PortForwardingRuleVO.class, "id", false, start, size);
 | |
|         SearchBuilder<FirewallRuleVO> sb = _firewallDao.createSearchBuilder();
 | |
|         sb.and("ip", sb.entity().getSourceIpAddressId(), Op.EQ);
 | |
|         sb.and("accountId", sb.entity().getAccountId(), Op.EQ);
 | |
|         sb.and("domainId", sb.entity().getDomainId(), Op.EQ);
 | |
|         sb.and("purpose", sb.entity().getPurpose(), Op.EQ);
 | |
|         sb.and("id", sb.entity().getId(), Op.EQ);
 | |
| 
 | |
|         if (path != null) {
 | |
|             // for domain admin we should show only subdomains information
 | |
|             SearchBuilder<DomainVO> domainSearch = _domainDao.createSearchBuilder();
 | |
|             domainSearch.and("path", domainSearch.entity().getPath(), SearchCriteria.Op.LIKE);
 | |
|             sb.join("domainSearch", domainSearch, sb.entity().getDomainId(), domainSearch.entity().getId(), JoinBuilder.JoinType.INNER);
 | |
|         }
 | |
| 
 | |
|         if (vmId != null) {
 | |
|             SearchBuilder<IPAddressVO> ipSearch = _ipAddressDao.createSearchBuilder();
 | |
|             ipSearch.and("associatedWithVmId", ipSearch.entity().getAssociatedWithVmId(), Op.EQ);
 | |
|             sb.join("ipSearch", ipSearch, sb.entity().getSourceIpAddressId(), ipSearch.entity().getId(), JoinBuilder.JoinType.INNER);
 | |
|         }
 | |
| 
 | |
|         SearchCriteria<FirewallRuleVO> sc = sb.create();
 | |
| 
 | |
|         if (id != null) {
 | |
|             sc.setParameters("id", id);
 | |
|         }
 | |
| 
 | |
|         if (ipId != null) {
 | |
|             sc.setParameters("ip", ipId);
 | |
|         }
 | |
| 
 | |
|         if (domainId != null) {
 | |
|             sc.setParameters("domainId", domainId);
 | |
|             if (accountName != null) {
 | |
|                 Account account = _accountMgr.getActiveAccountByName(accountName, domainId);
 | |
|                 sc.setParameters("accountId", account.getId());
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         sc.setParameters("purpose", Purpose.StaticNat);
 | |
| 
 | |
|         if (path != null) {
 | |
|             sc.setJoinParameters("domainSearch", "path", path + "%");
 | |
|         }
 | |
| 
 | |
|         if (vmId != null) {
 | |
|             sc.setJoinParameters("ipSearch", "associatedWithVmId", vmId);
 | |
|         }
 | |
| 
 | |
|         return _firewallDao.search(sc, filter);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_ADD, eventDescription = "applying port forwarding rule", async = true)
 | |
|     public boolean applyPortForwardingRules(long ipId, Account caller) throws ResourceUnavailableException {
 | |
|         return applyPortForwardingRules(ipId, false, caller);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_ADD, eventDescription = "applying static nat rule", async = true)
 | |
|     public boolean applyStaticNatRules(long ipId, Account caller) throws ResourceUnavailableException {
 | |
|         return applyStaticNatRules(ipId, false, caller);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean revokeAllPFAndStaticNatRulesForIp(long ipId, long userId, Account caller) throws ResourceUnavailableException {
 | |
|         List<FirewallRule> rules = new ArrayList<FirewallRule>();
 | |
| 
 | |
|         List<PortForwardingRuleVO> pfRules = _forwardingDao.listByIpAndNotRevoked(ipId);
 | |
|         if (s_logger.isDebugEnabled()) {
 | |
|             s_logger.debug("Releasing " + pfRules.size() + " port forwarding rules for ip id=" + ipId);
 | |
|         }
 | |
| 
 | |
|         for (PortForwardingRuleVO rule : pfRules) {
 | |
|             // Mark all PF rules as Revoke, but don't revoke them yet
 | |
|             revokePortForwardingRuleInternal(rule.getId(), caller, userId, false);
 | |
|         }
 | |
| 
 | |
|         List<FirewallRuleVO> staticNatRules = _firewallDao.listByIpAndPurposeAndNotRevoked(ipId, Purpose.StaticNat);
 | |
|         if (s_logger.isDebugEnabled()) {
 | |
|             s_logger.debug("Releasing " + staticNatRules.size() + " static nat rules for ip id=" + ipId);
 | |
|         }
 | |
| 
 | |
|         
 | |
|         for (FirewallRuleVO rule : staticNatRules) {
 | |
|             // Mark all static nat rules as Revoke, but don't revoke them yet
 | |
|             revokeStaticNatRuleInternal(rule.getId(), caller, userId, false);
 | |
|         }
 | |
| 
 | |
|         //revoke static nat for the ip address
 | |
|         boolean staticNatRevoked = applyStaticNatForIp(ipId, false, caller, true);
 | |
| 
 | |
|         // revoke all port forwarding rules
 | |
|         applyPortForwardingRules(ipId, true, caller);
 | |
| 
 | |
|         // revoke all all static nat rules
 | |
|         applyStaticNatRules(ipId, true, caller);
 | |
| 
 | |
|         // Now we check again in case more rules have been inserted.
 | |
|         rules.addAll(_forwardingDao.listByIpAndNotRevoked(ipId));
 | |
|         rules.addAll(_firewallDao.listByIpAndPurposeAndNotRevoked(ipId, Purpose.StaticNat));
 | |
| 
 | |
|         if (s_logger.isDebugEnabled()) {
 | |
|             s_logger.debug("Successfully released rules for ip id=" + ipId + " and # of rules now = " + rules.size());
 | |
|         }
 | |
| 
 | |
|         return (rules.size() == 0 && staticNatRevoked);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean revokeAllRulesForNetwork(long networkId, long userId, Account caller) throws ResourceUnavailableException {
 | |
|         List<FirewallRule> rules = new ArrayList<FirewallRule>();
 | |
| 
 | |
|         List<PortForwardingRuleVO> pfRules = _forwardingDao.listByNetwork(networkId);
 | |
|         if (s_logger.isDebugEnabled()) {
 | |
|             s_logger.debug("Releasing " + pfRules.size() + " port forwarding rules for network id=" + networkId);
 | |
|         }
 | |
| 
 | |
|         List<FirewallRuleVO> staticNatRules = _firewallDao.listByNetworkAndPurpose(networkId, Purpose.StaticNat);
 | |
|         if (s_logger.isDebugEnabled()) {
 | |
|             s_logger.debug("Releasing " + staticNatRules.size() + " static nat rules for network id=" + networkId);
 | |
|         }
 | |
| 
 | |
|         // Mark all pf rules (Active and non-Active) to be revoked, but don't revoke it yet - pass apply=false
 | |
|         for (PortForwardingRuleVO rule : pfRules) {
 | |
|             revokePortForwardingRuleInternal(rule.getId(), caller, userId, false);
 | |
|         }
 | |
| 
 | |
|         // Mark all static nat rules (Active and non-Active) to be revoked, but don't revoke it yet - pass apply=false
 | |
|         for (FirewallRuleVO rule : staticNatRules) {
 | |
|             revokeStaticNatRuleInternal(rule.getId(), caller, userId, false);
 | |
|         }
 | |
| 
 | |
|         // revoke all PF rules for the network
 | |
|         applyPortForwardingRulesForNetwork(networkId, true, caller);
 | |
| 
 | |
|         // revoke all all static nat rules for the network
 | |
|         applyStaticNatRulesForNetwork(networkId, true, caller);
 | |
| 
 | |
|         // Now we check again in case more rules have been inserted.
 | |
|         rules.addAll(_forwardingDao.listByNetworkAndNotRevoked(networkId));
 | |
|         rules.addAll(_firewallDao.listByNetworkAndPurposeAndNotRevoked(networkId, Purpose.StaticNat));
 | |
| 
 | |
|         if (s_logger.isDebugEnabled()) {
 | |
|             s_logger.debug("Successfully released rules for network id=" + networkId + " and # of rules now = " + rules.size());
 | |
|         }
 | |
| 
 | |
|         return rules.size() == 0;
 | |
|     }
 | |
| 
 | |
|     @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 List<? extends FirewallRule> listFirewallRulesByIp(long ipId) {
 | |
|         return null;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean releasePorts(long ipId, String protocol, FirewallRule.Purpose purpose, int... ports) {
 | |
|         return _firewallDao.releasePorts(ipId, protocol, purpose, ports);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     @DB
 | |
|     public FirewallRuleVO[] reservePorts(IpAddress ip, String protocol, FirewallRule.Purpose purpose, boolean openFirewall, Account caller, int... ports) throws NetworkRuleConflictException {
 | |
|         FirewallRuleVO[] rules = new FirewallRuleVO[ports.length];
 | |
| 
 | |
|         Transaction txn = Transaction.currentTxn();
 | |
|         txn.start();
 | |
|         for (int i = 0; i < ports.length; i++) {
 | |
|             
 | |
|             rules[i] = new FirewallRuleVO(null, ip.getId(), ports[i], protocol, ip.getAssociatedWithNetworkId(), ip.getAllocatedToAccountId(), ip.getAllocatedInDomainId(), purpose, null, null, null, null);
 | |
|             rules[i] = _firewallDao.persist(rules[i]);
 | |
|             
 | |
|             if (openFirewall) {
 | |
|                 _firewallMgr.createRuleForAllCidrs(ip.getId(), caller, ports[i], ports[i], protocol, null, null, rules[i].getId());
 | |
|             }
 | |
|         }
 | |
|         txn.commit();
 | |
| 
 | |
|         boolean success = false;
 | |
|         try {
 | |
|             for (FirewallRuleVO newRule : rules) {
 | |
|                 _firewallMgr.detectRulesConflict(newRule, ip);
 | |
|             }
 | |
|             success = true;
 | |
|             return rules;
 | |
|         } finally {
 | |
|             if (!success) {
 | |
|                 txn.start();
 | |
| 
 | |
|                 for (FirewallRuleVO newRule : rules) {
 | |
|                     _forwardingDao.remove(newRule.getId());
 | |
|                 }
 | |
|                 txn.commit();
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<? extends PortForwardingRule> gatherPortForwardingRulesForApplication(List<? extends IpAddress> addrs) {
 | |
|         List<PortForwardingRuleVO> allRules = new ArrayList<PortForwardingRuleVO>();
 | |
| 
 | |
|         for (IpAddress addr : addrs) {
 | |
|             if (!addr.readyToUse()) {
 | |
|                 if (s_logger.isDebugEnabled()) {
 | |
|                     s_logger.debug("Skipping " + addr + " because it is not ready for propation yet.");
 | |
|                 }
 | |
|                 continue;
 | |
|             }
 | |
|             allRules.addAll(_forwardingDao.listForApplication(addr.getId()));
 | |
|         }
 | |
| 
 | |
|         if (s_logger.isDebugEnabled()) {
 | |
|             s_logger.debug("Found " + allRules.size() + " rules to apply for the addresses.");
 | |
|         }
 | |
| 
 | |
|         return allRules;
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public List<PortForwardingRuleVO> listByNetworkId(long networkId) {
 | |
|         return _forwardingDao.listByNetwork(networkId);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public boolean disableStaticNat(long ipId) throws ResourceUnavailableException {
 | |
|         boolean success = true;
 | |
| 
 | |
|         Account caller = UserContext.current().getCaller();
 | |
| 
 | |
|         IPAddressVO ipAddress = _ipAddressDao.findById(ipId);
 | |
|         checkIpAndUserVm(ipAddress, null, caller);
 | |
| 
 | |
|         if (!ipAddress.isOneToOneNat()) {
 | |
|             throw new InvalidParameterValueException("One to one nat is not enabled for the ip id=" + ipId);
 | |
|         }
 | |
| 
 | |
|         if (!revokeAllPFAndStaticNatRulesForIp(ipId, UserContext.current().getCallerUserId(), caller)) {
 | |
|             s_logger.warn("Unable to revoke all static nat rules for ip " + ipAddress);
 | |
|             success = false;
 | |
|         }
 | |
|         
 | |
|         if (success) {
 | |
|             ipAddress.setOneToOneNat(false);
 | |
|             ipAddress.setAssociatedWithVmId(null);
 | |
|             _ipAddressDao.update(ipAddress.getId(), ipAddress);
 | |
|             return true;
 | |
|         } else {
 | |
|             s_logger.warn("Failed to disable one to one nat for the ip address id" + ipId);
 | |
|             return false;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public PortForwardingRule getPortForwardigRule(long ruleId) {
 | |
|         return _forwardingDao.findById(ruleId);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public FirewallRule getFirewallRule(long ruleId) {
 | |
|         return _firewallDao.findById(ruleId);
 | |
|     }
 | |
| 
 | |
|     @Override
 | |
|     public StaticNatRule buildStaticNatRule(FirewallRule rule) {
 | |
|         IpAddress ip = _ipAddressDao.findById(rule.getSourceIpAddressId());
 | |
|         FirewallRuleVO ruleVO = _firewallDao.findById(rule.getId());
 | |
| 
 | |
|         if (ip == null || !ip.isOneToOneNat() || ip.getAssociatedWithVmId() == null) {
 | |
|             throw new InvalidParameterValueException("Source ip address of the rule id=" + rule.getId() + " is not static nat enabled");
 | |
|         }
 | |
| 
 | |
|         String dstIp = _networkMgr.getIpInNetwork(ip.getAssociatedWithVmId(), rule.getNetworkId());
 | |
| 
 | |
|         return new StaticNatRuleImpl(ruleVO, dstIp);
 | |
|     }
 | |
|     
 | |
|     @Override
 | |
|     public boolean applyStaticNatForIp(long sourceIpId, boolean continueOnError, Account caller, boolean forRevoke) {
 | |
|         
 | |
|         List<StaticNat> staticNats = new ArrayList<StaticNat>();
 | |
|         IpAddress sourceIp = _ipAddressDao.findById(sourceIpId);
 | |
|         
 | |
|         if (!sourceIp.isOneToOneNat()) {
 | |
|             s_logger.debug("Source ip id=" + sourceIpId + " is not one to one nat");
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         Long networkId = sourceIp.getAssociatedWithNetworkId();
 | |
|         if (networkId == null) {
 | |
|             throw new CloudRuntimeException("Ip address is not associated with any network");
 | |
|         }
 | |
|         
 | |
|         UserVmVO vm = _vmDao.findById(sourceIp.getAssociatedWithVmId());
 | |
|         Network network = _networkMgr.getNetwork(networkId);
 | |
|         if (network == null) {
 | |
|             throw new CloudRuntimeException("Unable to find ip address to map to in vm id=" + vm.getId());
 | |
|         }
 | |
|         
 | |
|         if (caller != null) {
 | |
|             _accountMgr.checkAccess(caller, null, sourceIp);
 | |
|         }
 | |
| 
 | |
|         //create new static nat rule
 | |
|         // Get nic IP4 address
 | |
|         
 | |
|         String dstIp;
 | |
|         if (forRevoke) {
 | |
|             dstIp = _networkMgr.getIpInNetworkIncludingRemoved(sourceIp.getAssociatedWithVmId(), networkId);
 | |
|         } else {
 | |
|             dstIp = _networkMgr.getIpInNetwork(sourceIp.getAssociatedWithVmId(), networkId);
 | |
|         }
 | |
|         
 | |
|         StaticNatImpl staticNat = new StaticNatImpl(sourceIp.getAccountId(), sourceIp.getDomainId(), networkId, sourceIpId, dstIp, forRevoke);
 | |
|         staticNats.add(staticNat);
 | |
|         
 | |
|         try {
 | |
|             if (!_networkMgr.applyStaticNats(staticNats, continueOnError)) {
 | |
|                 return false;
 | |
|             }
 | |
|         } catch (ResourceUnavailableException ex) {
 | |
|             s_logger.warn("Failed to create static nat rule due to ", ex);
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| }
 |