/** * 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 . * */ package com.cloud.network.rules; import java.util.List; import java.util.Map; import javax.ejb.Local; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import com.cloud.api.commands.ListIpForwardingRulesCmd; import com.cloud.api.commands.ListPortForwardingRulesCmd; import com.cloud.event.EventTypes; import com.cloud.event.EventUtils; import com.cloud.event.EventVO; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.IPAddressVO; import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.NetworkManager; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.rules.FirewallRule.State; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.offering.NetworkOffering.GuestIpType; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.UserContext; import com.cloud.uservm.UserVm; import com.cloud.utils.component.Inject; import com.cloud.utils.component.Manager; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; import com.cloud.vm.Nic; import com.cloud.vm.UserVmVO; 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 FirewallRulesDao _firewallDao; @Inject IPAddressDao _ipAddressDao; @Inject UserVmDao _vmDao; @Inject AccountManager _accountMgr; @Inject NetworkManager _networkMgr; @Override public void detectRulesConflict(FirewallRule newRule, IpAddress ipAddress) throws NetworkRuleConflictException { assert newRule.getSourceIpAddress().equals(ipAddress.getAddress()) : "You passed in an ip address that doesn't match the address in the new rule"; List rules = _firewallDao.listByIpAndNotRevoked(newRule.getSourceIpAddress()); assert (rules.size() >= 1) : "For network rules, we now always first persist the rule and then check for network conflicts so we should at least have one rule at this point."; if (ipAddress.isOneToOneNat() && rules.size() > 1) { throw new NetworkRuleConflictException("There are already rules in existence for the " + newRule.getSourceIpAddress()); } for (FirewallRuleVO rule : rules) { if (rule.getId() == newRule.getId()) { continue; // Skips my own rule. } if (rule.getNetworkId() != newRule.getNetworkId() && rule.getState() != State.Revoke) { throw new NetworkRuleConflictException("New rule is for a different network than what's specified in rule " + rule.getXid()); } if (rule.getProtocol().equals(NetUtils.NAT_PROTO)) { throw new NetworkRuleConflictException("There is already a one to one NAT specified for " + newRule.getSourceIpAddress()); } if ((rule.getSourcePortStart() <= newRule.getSourcePortStart() && rule.getSourcePortEnd() >= newRule.getSourcePortStart()) || (rule.getSourcePortStart() <= newRule.getSourcePortEnd() && rule.getSourcePortEnd() >= newRule.getSourcePortEnd()) || (newRule.getSourcePortStart() <= rule.getSourcePortStart() && newRule.getSourcePortEnd() >= rule.getSourcePortStart()) || (newRule.getSourcePortStart() <= rule.getSourcePortEnd() && newRule.getSourcePortEnd() >= rule.getSourcePortEnd())) { 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 rules"); } } @Override public void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller) throws InvalidParameterValueException, PermissionDeniedException { if (ipAddress == null || ipAddress.getAllocated() == null || ipAddress.getAccountId() == null) { throw new InvalidParameterValueException("Unable to create ip forwarding rule on address " + ipAddress + ", invalid IP address specified."); } if (userVm == null) { return; } _accountMgr.checkAccess(caller, userVm); // validate that IP address and userVM belong to the same account if (ipAddress.getAccountId().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.getDataCenterId()) { 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 PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, Account caller) throws NetworkRuleConflictException { String ipAddr = rule.getSourceIpAddress().addr(); IPAddressVO ipAddress = _ipAddressDao.findById(ipAddr); Ip dstIp = rule.getDestinationIpAddress(); long networkId = rule.getNetworkId(); UserVmVO vm = null; Network network = null; if (vmId != null) { // validate user VM exists vm = _vmDao.findById(vmId); if (vm == null) { throw new InvalidParameterValueException("Unable to create ip forwarding rule on address " + ipAddress + ", invalid virtual machine id specified (" + vmId + ")."); } dstIp = null; List nics = _networkMgr.getNics(vm); for (Nic nic : nics) { Network ntwk = _networkMgr.getNetwork(nic.getNetworkId()); if (ntwk.getGuestType() == GuestIpType.Virtualized) { network = ntwk; dstIp = new Ip(nic.getIp4Address()); break; } } if (network == null) { throw new CloudRuntimeException("Unable to find ip address to map to in " + vmId); } } else { network = _networkMgr.getNetwork(rule.getNetworkId()); if (network == null) { throw new InvalidParameterValueException("Unable to get the network " + rule.getNetworkId()); } } networkId = network.getId(); long accountId = network.getAccountId(); long domainId = network.getDomainId(); checkIpAndUserVm(ipAddress, vm, caller); PortForwardingRuleVO newRule = new PortForwardingRuleVO(rule.getXid(), rule.getSourceIpAddress(), rule.getSourcePortStart(), rule.getSourcePortEnd(), dstIp, rule.getDestinationPortStart(), rule.getDestinationPortEnd(), rule.getProtocol(), networkId, accountId, domainId); newRule = _forwardingDao.persist(newRule); boolean success = false; try { detectRulesConflict(newRule, ipAddress); if (!_firewallDao.setStateToAdd(newRule)) { throw new CloudRuntimeException("Unable to update the state to add for " + newRule); } success = true; return newRule; } catch (Exception e) { _forwardingDao.remove(newRule.getId()); if (e instanceof NetworkRuleConflictException) { throw (NetworkRuleConflictException)e; } throw new CloudRuntimeException("Unable to add rule for " + newRule.getSourceIpAddress(), e); } finally { // Save and create the event String description; String ruleName = "ip forwarding"; String level = EventVO.LEVEL_INFO; if (success == true) { description = "created new " + ruleName + " rule [" + newRule.getSourceIpAddress() + ":" + newRule.getSourcePortStart() + "]->[" + newRule.getDestinationIpAddress() + ":" + newRule.getDestinationPortStart() + "]" + " " + newRule.getProtocol(); } else { level = EventVO.LEVEL_ERROR; description = "failed to create new " + ruleName + " rule [" + newRule.getSourceIpAddress() + ":" + newRule.getSourcePortStart() + "]->[" + newRule.getDestinationIpAddress() + ":" + newRule.getDestinationPortStart() + "]" + " " + newRule.getProtocol(); } EventUtils.saveEvent(UserContext.current().getUserId(), vm.getAccountId(), level, EventTypes.EVENT_NET_RULE_ADD, description); } } protected void revokeRule(FirewallRuleVO rule, Account caller) { _accountMgr.checkAccess(caller, rule); if (rule.getState() == State.Staged) { if (s_logger.isDebugEnabled()) { s_logger.debug("Found a rule that is still in stage state so just removing it: " + rule); } _firewallDao.remove(rule.getId()); return; } else if (rule.getState() == State.Add) { rule.setState(State.Revoke); _firewallDao.update(rule.getId(), rule); } } @Override public PortForwardingRule revokePortForwardingRule(long ruleId, boolean apply, Account caller) { PortForwardingRuleVO rule = _forwardingDao.findById(ruleId); if (rule == null) { throw new InvalidParameterValueException("Unable to find " + ruleId); } revokeRule(rule, caller); if (apply) { applyPortForwardingRules(rule.getSourceIpAddress(), true); } return rule; } @Override public PortForwardingRule revokePortForwardingRule(String ruleId, Account caller) { // FIXME: Not working yet. return null; } @Override public List listPortForwardingRules(ListPortForwardingRulesCmd cmd) { Ip ipAddress = new Ip(cmd.getIpAddress()); Account caller = UserContext.current().getAccount(); IPAddressVO ipAddressVO = _ipAddressDao.findById(ipAddress.addr()); if (ipAddressVO == null || ipAddressVO.getAllocated() == null) { throw new InvalidParameterValueException("Unable to find IP address " + ipAddress); } List rules = _forwardingDao.listByIpAndNotRevoked(ipAddress); _accountMgr.checkAccess(caller, rules.toArray(new PortForwardingRuleVO[rules.size()])); return rules; } @Override public PortForwardingRule createIpForwardingRuleInDb(String ipAddr, long virtualMachineId) { // TODO Auto-generated method stub return null; } @Override public PortForwardingRule createIpForwardingRuleOnDomr(long ruleId) { // TODO Auto-generated method stub return null; } @Override public boolean deleteIpForwardingRule(Long id) { // TODO Auto-generated method stub return false; } @Override public boolean deletePortForwardingRule(Long id, boolean sysContext) { // TODO Auto-generated method stub return false; } @Override public boolean applyPortForwardingRules(Ip ip, boolean continueOnError) { try { return applyPortForwardingRules(ip, continueOnError, null); } catch (ResourceUnavailableException e) { s_logger.warn("Unable to reapply port forwarding rules for " + ip); return false; } } protected boolean applyPortForwardingRules(Ip ip, boolean continueOnError, Account caller) throws ResourceUnavailableException { List rules = _forwardingDao.listForApplication(ip); if (rules.size() == 0) { s_logger.debug("There are no rules to apply for " + ip); return true; } if (caller != null) { _accountMgr.checkAccess(caller, rules.toArray(new PortForwardingRuleVO[rules.size()])); } return _networkMgr.applyRules(ip, rules, continueOnError); } @Override public List searchForIpForwardingRules(ListIpForwardingRulesCmd cmd){ // String ipAddress = cmd.getPublicIpAddress(); // Filter searchFilter = new Filter(PortForwardingRuleVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal()); // SearchCriteria sc = _firewallRulesDao.createSearchCriteria(); // // if (ipAddress != null) { // sc.addAnd("publicIpAddress", SearchCriteria.Op.EQ, ipAddress); // } // // //search for rules with protocol = nat // sc.addAnd("protocol", SearchCriteria.Op.EQ, NetUtils.NAT_PROTO); // // return _firewallRulesDao.search(sc, searchFilter); return null; } @Override public boolean applyPortForwardingRules(Ip ip, Account caller) throws ResourceUnavailableException { return applyPortForwardingRules(ip, false, caller); } @Override public boolean applyNatRules(Ip ip, Account caller) throws ResourceUnavailableException { // TODO Auto-generated method stub return false; } @Override public boolean applyFirewallRules(Ip ip, Account caller) throws ResourceUnavailableException { // TODO Auto-generated method stub return false; } @Override public boolean configure(String name, Map 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 updateFirewallRule(final PortForwardingRuleVO rule, String oldPrivateIP, String oldPrivatePort) { // // final IPAddressVO ipVO = _ipAddressDao.findById(rule.getSourceIpAddress()); // if (ipVO == null || ipVO.getAllocated() == null) { // return false; // } // // final DomainRouterVO router = _routerMgr.getRouter(ipVO.getAccountId(), ipVO.getDataCenterId()); // Long hostId = router.getHostId(); // if (router == null || router.getHostId() == null) { // return true; // } // // if (rule.isForwarding()) { // return updatePortForwardingRule(rule, router, hostId, oldPrivateIP, oldPrivatePort); // } else if (rule.getGroupId() != null) { // final List fwRules = _rulesDao.listIPForwardingForLB(ipVO.getAccountId(), ipVO.getDataCenterId()); // // return updateLoadBalancerRules(fwRules, router, hostId); // } // return true; // } // // @Override // public List updateFirewallRules(final String publicIpAddress, final List fwRules, final DomainRouterVO router) { // final List result = new ArrayList(); // if (fwRules.size() == 0) { // return result; // } // // if (router == null || router.getHostId() == null) { // return fwRules; // } else { // final HostVO host = _hostDao.findById(router.getHostId()); // return updateFirewallRules(host, router.getInstanceName(), router.getPrivateIpAddress(), fwRules); // } // } // // public List updateFirewallRules(final HostVO host, final String routerName, final String routerIp, final List fwRules) { // final List result = new ArrayList(); // if (fwRules.size() == 0) { // s_logger.debug("There are no firewall rules"); // return result; // } // // Commands cmds = new Commands(OnError.Continue); // final List lbRules = new ArrayList(); // final List fwdRules = new ArrayList(); // // int i=0; // for (PortForwardingRuleVO rule : fwRules) { // // Determine the VLAN ID and netmask of the rule's public IP address // IPAddressVO ip = _ipAddressDao.findById(rule.getSourceIpAddress()); // VlanVO vlan = _vlanDao.findById(new Long(ip.getVlanDbId())); // String vlanNetmask = vlan.getVlanNetmask(); // rule.setVlanNetmask(vlanNetmask); // // if (rule.isForwarding()) { // fwdRules.add(rule); // final SetFirewallRuleCommand cmd = new SetFirewallRuleCommand(routerName, routerIp,rule, false); // cmds.addCommand(cmd); // } else if (rule.getGroupId() != null){ // lbRules.add(rule); // } // // } // if (lbRules.size() > 0) { //at least one load balancer rule // final LoadBalancerConfigurator cfgrtr = new HAProxyConfigurator(); // final String [] cfg = cfgrtr.generateConfiguration(fwRules); // final String [][] addRemoveRules = cfgrtr.generateFwRules(fwRules); // final LoadBalancerCfgCommand cmd = new LoadBalancerCfgCommand(cfg, addRemoveRules, routerName, routerIp); // cmds.addCommand(cmd); // } // if (cmds.size() == 0) { // return result; // } // Answer [] answers = null; // try { // answers = _agentMgr.send(host.getId(), cmds); // } catch (final AgentUnavailableException e) { // s_logger.warn("agent unavailable", e); // } catch (final OperationTimedoutException e) { // s_logger.warn("Timed Out", e); // } // if (answers == null ){ // return result; // } // i=0; // for (final PortForwardingRuleVO rule:fwdRules){ // final Answer ans = answers[i++]; // if (ans != null) { // if (ans.getResult()) { // result.add(rule); // } else { // s_logger.warn("Unable to update firewall rule: " + rule.toString()); // } // } // } // if (i == (answers.length-1)) { // final Answer lbAnswer = answers[i]; // if (lbAnswer.getResult()) { // result.addAll(lbRules); // } else { // s_logger.warn("Unable to update lb rules."); // } // } // return result; // } // // private boolean updatePortForwardingRule(final PortForwardingRuleVO rule, final DomainRouterVO router, Long hostId, String oldPrivateIP, String oldPrivatePort) { // IPAddressVO ip = _ipAddressDao.findById(rule.getSourceIpAddress()); // VlanVO vlan = _vlanDao.findById(new Long(ip.getVlanDbId())); // rule.setVlanNetmask(vlan.getVlanNetmask()); // // final SetFirewallRuleCommand cmd = new SetFirewallRuleCommand(router.getInstanceName(), router.getPrivateIpAddress(), rule, oldPrivateIP, oldPrivatePort); // final Answer ans = _agentMgr.easySend(hostId, cmd); // if (ans == null) { // return false; // } else { // return ans.getResult(); // } // } // // @Override // public List updatePortForwardingRules(final List fwRules, final DomainRouterVO router, Long hostId ){ // final List fwdRules = new ArrayList(); // final List result = new ArrayList(); // // if (fwRules.size() == 0) { // return result; // } // // Commands cmds = new Commands(OnError.Continue); // int i=0; // for (final PortForwardingRuleVO rule: fwRules) { // IPAddressVO ip = _ipAddressDao.findById(rule.getSourceIpAddress()); // VlanVO vlan = _vlanDao.findById(new Long(ip.getVlanDbId())); // String vlanNetmask = vlan.getVlanNetmask(); // rule.setVlanNetmask(vlanNetmask); // if (rule.isForwarding()) { // fwdRules.add(rule); // final SetFirewallRuleCommand cmd = new SetFirewallRuleCommand(router.getInstanceName(), router.getPrivateIpAddress(),rule, false); // cmds.addCommand(cmd); // } // } // try { // _agentMgr.send(hostId, cmds); // } catch (final AgentUnavailableException e) { // s_logger.warn("agent unavailable", e); // } catch (final OperationTimedoutException e) { // s_logger.warn("Timed Out", e); // } // Answer[] answers = cmds.getAnswers(); // if (answers == null ){ // return result; // } // i=0; // for (final PortForwardingRuleVO rule:fwdRules){ // final Answer ans = answers[i++]; // if (ans != null) { // if (ans.getResult()) { // result.add(rule); // } // } // } // return result; // } // // @Override // public PortForwardingRuleVO createPortForwardingRule(CreatePortForwardingRuleCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, NetworkRuleConflictException { // // validate IP Address exists // IPAddressVO ipAddress = _ipAddressDao.findById(cmd.getIpAddress()); // if (ipAddress == null) { // throw new InvalidParameterValueException("Unable to create port forwarding rule on address " + ipAddress + ", invalid IP address specified."); // } // // // validate user VM exists // UserVmVO userVM = _vmDao.findById(cmd.getVirtualMachineId()); // if (userVM == null) { // throw new InvalidParameterValueException("Unable to create port forwarding rule on address " + ipAddress + ", invalid virtual machine id specified (" + cmd.getVirtualMachineId() + ")."); // } // // // validate that IP address and userVM belong to the same account // if ((ipAddress.getAccountId() == null) || (ipAddress.getAccountId().longValue() != userVM.getAccountId())) { // throw new InvalidParameterValueException("Unable to create port 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.getDataCenterId()) { // throw new InvalidParameterValueException("Unable to create port forwarding rule, IP address " + ipAddress + " is not in the same availability zone as virtual machine " + userVM.toString()); // } // // // if an admin account was passed in, or no account was passed in, make sure we honor the accountName/domainId parameters // Account account = UserContext.current().getAccount(); // if (account != null) { // if ((account.getType() == Account.ACCOUNT_TYPE_ADMIN) || (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN)) { // if (!_domainDao.isChildDomain(account.getDomainId(), userVM.getDomainId())) { // throw new PermissionDeniedException("Unable to create port forwarding rule, IP address " + ipAddress + " to virtual machine " + cmd.getVirtualMachineId() + ", permission denied."); // } // } else if (account.getId() != userVM.getAccountId()) { // throw new PermissionDeniedException("Unable to create port forwarding rule, IP address " + ipAddress + " to virtual machine " + cmd.getVirtualMachineId() + ", permission denied."); // } // } // // // set up some local variables // String protocol = cmd.getProtocol(); // String publicPort = cmd.getPublicPort(); // String privatePort = cmd.getPrivatePort(); // // // sanity check that the vm can be applied to the load balancer // ServiceOfferingVO offering = _serviceOfferingDao.findById(userVM.getServiceOfferingId()); // if ((offering == null) || !GuestIpType.Virtualized.equals(offering.getGuestIpType())) { // if (s_logger.isDebugEnabled()) { // s_logger.debug("Unable to create port forwarding rule (" + protocol + ":" + publicPort + "->" + privatePort + ") for virtual machine " + userVM.toString() + ", bad network type (" + ((offering == null) ? "null" : offering.getGuestIpType()) + ")"); // } // // throw new IllegalArgumentException("Unable to create port forwarding rule (" + protocol + ":" + publicPort + "->" + privatePort + ") for virtual machine " + userVM.toString() + ", bad network type (" + ((offering == null) ? "null" : offering.getGuestIpType()) + ")"); // } // // // check for ip address/port conflicts by checking existing forwarding and load balancing rules // List existingRulesOnPubIp = _rulesDao.listIPForwarding(ipAddress.getAddress()); // // // FIXME: The mapped ports should be String, String, List since more than one proto can be mapped... // Map>> mappedPublicPorts = new HashMap>>(); // // if (existingRulesOnPubIp != null) { // for (PortForwardingRuleVO fwRule : existingRulesOnPubIp) { // Ternary> portMappings = mappedPublicPorts.get(fwRule.getSourcePort()); // List protocolList = null; // if (portMappings == null) { // protocolList = new ArrayList(); // } else { // protocolList = portMappings.third(); // } // protocolList.add(fwRule.getProtocol()); // mappedPublicPorts.put(fwRule.getSourcePort(), new Ternary>(fwRule.getDestinationIpAddress(), fwRule.getDestinationPort(), protocolList)); // } // } // // Ternary> privateIpPort = mappedPublicPorts.get(publicPort); // if (privateIpPort != null) { // if (privateIpPort.first().equals(userVM.getGuestIpAddress()) && privateIpPort.second().equals(privatePort)) { // List protocolList = privateIpPort.third(); // for (String mappedProtocol : protocolList) { // if (mappedProtocol.equalsIgnoreCase(protocol)) { // if (s_logger.isDebugEnabled()) { // s_logger.debug("skipping the creating of firewall rule " + ipAddress + ":" + publicPort + " to " + userVM.getGuestIpAddress() + ":" + privatePort + "; rule already exists."); // } // // already mapped // throw new NetworkRuleConflictException("An existing port forwarding service rule for " + ipAddress + ":" + publicPort // + " already exists, found while trying to create mapping to " + userVM.getGuestIpAddress() + ":" + privatePort + "."); // } // } // } else { // // FIXME: Will we need to refactor this for both assign port forwarding service and create port forwarding rule? // // throw new NetworkRuleConflictException("An existing port forwarding service rule for " + ipAddress + ":" + publicPort // // + " already exists, found while trying to create mapping to " + userVM.getGuestIpAddress() + ":" + privatePort + ((securityGroupId == null) ? "." : " from port forwarding service " // // + securityGroupId.toString() + ".")); // throw new NetworkRuleConflictException("An existing port forwarding service rule for " + ipAddress + ":" + publicPort // + " already exists, found while trying to create mapping to " + userVM.getGuestIpAddress() + ":" + privatePort + "."); // } // } // // PortForwardingRuleVO newFwRule = new PortForwardingRuleVO(); // newFwRule.setEnabled(true); // newFwRule.setForwarding(true); // newFwRule.setPrivatePort(privatePort); // newFwRule.setProtocol(protocol); // newFwRule.setPublicPort(publicPort); // newFwRule.setPublicIpAddress(ipAddress.getAddress()); // newFwRule.setPrivateIpAddress(userVM.getGuestIpAddress()); // // newFwRule.setGroupId(securityGroupId); // newFwRule.setGroupId(null); // // // In 1.0 the rules were always persisted when a user created a rule. When the rules get sent down // // the stopOnError parameter is set to false, so the agent will apply all rules that it can. That // // behavior is preserved here by persisting the rule before sending it to the agent. // _rulesDao.persist(newFwRule); // // boolean success = updateFirewallRule(newFwRule, null, null); // // // Save and create the event // String description; // String ruleName = "ip forwarding"; // String level = EventVO.LEVEL_INFO; // // if (success == true) { // description = "created new " + ruleName + " rule [" + newFwRule.getSourceIpAddress() + ":" + newFwRule.getSourcePort() + "]->[" // + newFwRule.getDestinationIpAddress() + ":" + newFwRule.getDestinationPort() + "]" + " " + newFwRule.getProtocol(); // } else { // level = EventVO.LEVEL_ERROR; // description = "failed to create new " + ruleName + " rule [" + newFwRule.getSourceIpAddress() + ":" + newFwRule.getSourcePort() + "]->[" // + newFwRule.getDestinationIpAddress() + ":" + newFwRule.getDestinationPort() + "]" + " " + newFwRule.getProtocol(); // } // // EventUtils.saveEvent(UserContext.current().getUserId(), userVM.getAccountId(), level, EventTypes.EVENT_NET_RULE_ADD, description); // // return newFwRule; // } // // @Override @DB // public boolean deletePortForwardingRule(Long id, boolean sysContext) { // Long ruleId = id; // Long userId = null; // Account account = null; // if(sysContext){ // userId = User.UID_SYSTEM; // account = _accountDao.findById(User.UID_SYSTEM); // }else{ // userId = UserContext.current().getUserId(); // account = UserContext.current().getAccount(); // } // // // //verify input parameters here // PortForwardingRuleVO rule = _firewallRulesDao.findById(ruleId); // if (rule == null) { // throw new InvalidParameterValueException("Unable to find port forwarding rule " + ruleId); // } // // String publicIp = rule.getSourceIpAddress(); // String privateIp = rule.getDestinationIpAddress(); // // IPAddressVO ipAddress = _ipAddressDao.findById(publicIp); // if (ipAddress == null) { // throw new InvalidParameterValueException("Unable to find IP address for port forwarding rule " + ruleId); // } // // // although we are not writing these values to the DB, we will check // // them out of an abundance // // of caution (may not be warranted) // String privatePort = rule.getDestinationPort(); // String publicPort = rule.getSourcePort(); // if (!NetUtils.isValidPort(publicPort) || !NetUtils.isValidPort(privatePort)) { // throw new InvalidParameterValueException("Invalid value for port"); // } // // String proto = rule.getProtocol(); // if (!NetUtils.isValidProto(proto)) { // throw new InvalidParameterValueException("Invalid protocol"); // } // // Account ruleOwner = _accountDao.findById(ipAddress.getAccountId()); // if (ruleOwner == null) { // throw new InvalidParameterValueException("Unable to find owning account for port forwarding rule " + ruleId); // } // // // if an admin account was passed in, or no account was passed in, make sure we honor the accountName/domainId parameters // if (account != null) { // if (isAdmin(account.getType())) { // if (!_domainDao.isChildDomain(account.getDomainId(), ruleOwner.getDomainId())) { // throw new PermissionDeniedException("Unable to delete port forwarding rule " + ruleId + ", permission denied."); // } // } else if (account.getId() != ruleOwner.getId()) { // throw new PermissionDeniedException("Unable to delete port forwarding rule " + ruleId + ", permission denied."); // } // } // // Transaction txn = Transaction.currentTxn(); // boolean locked = false; // boolean success = false; // try { // // IPAddressVO ipVO = _ipAddressDao.acquireInLockTable(publicIp); // if (ipVO == null) { // // throw this exception because hackers can use the api to probe for allocated ips // throw new PermissionDeniedException("User does not own supplied address"); // } // // locked = true; // txn.start(); // List fwdings = _firewallRulesDao.listIPForwardingForUpdate(publicIp, publicPort, proto); // PortForwardingRuleVO fwRule = null; // if (fwdings.size() == 0) { // throw new InvalidParameterValueException("No such rule"); // } else if (fwdings.size() == 1) { // fwRule = fwdings.get(0); // if (fwRule.getDestinationIpAddress().equalsIgnoreCase(privateIp) && fwRule.getDestinationPort().equals(privatePort)) { // _firewallRulesDao.expunge(fwRule.getId()); // } else { // throw new InvalidParameterValueException("No such rule"); // } // } else { // throw new CloudRuntimeException("Multiple matches. Please contact support"); // } // fwRule.setEnabled(false); // success = updateFirewallRule(fwRule, null, null); // // String description; // String type = EventTypes.EVENT_NET_RULE_DELETE; // String level = EventVO.LEVEL_INFO; // String ruleName = rule.isForwarding() ? "ip forwarding" : "load balancer"; // // if (success) { // description = "deleted " + ruleName + " rule [" + publicIp + ":" + rule.getSourcePort() + "]->[" + rule.getDestinationIpAddress() + ":" // + rule.getDestinationPort() + "] " + rule.getProtocol(); // } else { // level = EventVO.LEVEL_ERROR; // description = "Error while deleting " + ruleName + " rule [" + publicIp + ":" + rule.getSourcePort() + "]->[" + rule.getDestinationIpAddress() + ":" // + rule.getDestinationPort() + "] " + rule.getProtocol(); // } // EventUtils.saveEvent(userId, ipAddress.getAccountId(), level, type, description); // txn.commit(); // }catch (Exception ex) { // txn.rollback(); // s_logger.error("Unexpected exception deleting port forwarding rule " + ruleId, ex); // return false; // }finally { // if (locked) { // _ipAddressDao.releaseFromLockTable(publicIp); // } // txn.close(); // } // return success; // } // @Override @DB // public PortForwardingRule createIpForwardingRuleOnDomr(long ruleId) { // Transaction txn = Transaction.currentTxn(); // txn.start(); // boolean success = false; // PortForwardingRuleVO rule = null; // IPAddressVO ipAddress = null; // boolean locked = false; // try { // //get the rule // rule = _rulesDao.findById(ruleId); // // if(rule == null){ // throw new PermissionDeniedException("Cannot create ip forwarding rule in db"); // } // // //get ip address // ipAddress = _ipAddressDao.findById(rule.getSourceIpAddress()); // if (ipAddress == null) { // throw new InvalidParameterValueException("Unable to create ip forwarding rule on address " + ipAddress + ", invalid IP address specified."); // } // // //sync point // ipAddress = _ipAddressDao.acquireInLockTable(ipAddress.getAddress()); // // if(ipAddress == null){ // s_logger.warn("Unable to acquire lock on ipAddress for creating 1-1 NAT rule"); // return rule; // }else{ // locked = true; // } // // //get the domain router object // DomainRouterVO router = _routerMgr.getRouter(ipAddress.getAccountId(), ipAddress.getDataCenterId()); // success = createOrDeleteIpForwardingRuleOnDomr(rule,router,rule.getDestinationIpAddress(),true); //true +> create // // if(!success){ // //corner case; delete record from db as domR rule creation failed // _rulesDao.remove(ruleId); // throw new PermissionDeniedException("Cannot create ip forwarding rule on domr, hence deleting created record in db"); // } // // //update the user_ip_address record // ipAddress.setOneToOneNat(true); // _ipAddressDao.update(ipAddress.getAddress(),ipAddress); // // // Save and create the event // String description; // String ruleName = "ip forwarding"; // String level = EventVO.LEVEL_INFO; // // description = "created new " + ruleName + " rule [" + rule.getSourceIpAddress() + "]->[" // + rule.getDestinationIpAddress() + "]" + ":" + rule.getProtocol(); // // EventUtils.saveEvent(UserContext.current().getUserId(), ipAddress.getAccountId(), level, EventTypes.EVENT_NET_RULE_ADD, description); // txn.commit(); // } catch (Exception e) { // txn.rollback(); // throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage()); // }finally{ // if(locked){ // _ipAddressDao.releaseFromLockTable(ipAddress.getAddress()); // } // } // return rule; // } // // @Override @DB // public PortForwardingRule createIpForwardingRuleInDb(String ipAddr, long virtualMachineId) { // // Transaction txn = Transaction.currentTxn(); // txn.start(); // UserVmVO userVM = null; // PortForwardingRuleVO newFwRule = null; // boolean locked = false; // try { // // validate IP Address exists // IPAddressVO ipAddress = _ipAddressDao.findById(ipAddr); // if (ipAddress == null) { // throw new InvalidParameterValueException("Unable to create ip forwarding rule on address " + ipAddress + ", invalid IP address specified."); // } // // // validate user VM exists // userVM = _vmDao.findById(virtualMachineId); // if (userVM == null) { // throw new InvalidParameterValueException("Unable to create ip forwarding rule on address " + ipAddress + ", invalid virtual machine id specified (" + virtualMachineId + ")."); // } // // //sync point; cannot lock on rule ; hence sync on vm // userVM = _vmDao.acquireInLockTable(userVM.getId()); // // if(userVM == null){ // s_logger.warn("Unable to acquire lock on user vm for creating 1-1 NAT rule"); // return newFwRule; // }else{ // locked = true; // } // // // validate that IP address and userVM belong to the same account // if ((ipAddress.getAccountId() == null) || (ipAddress.getAccountId().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.getDataCenterId()) { // throw new InvalidParameterValueException("Unable to create ip forwarding rule, IP address " + ipAddress + " is not in the same availability zone as virtual machine " + userVM.toString()); // } // // // if an admin account was passed in, or no account was passed in, make sure we honor the accountName/domainId parameters // Account account = UserContext.current().getAccount(); // if (account != null) { // if ((account.getType() == Account.ACCOUNT_TYPE_ADMIN) || (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN)) { // if (!_domainDao.isChildDomain(account.getDomainId(), userVM.getDomainId())) { // throw new PermissionDeniedException("Unable to create ip forwarding rule, IP address " + ipAddress + " to virtual machine " + virtualMachineId + ", permission denied."); // } // } else if (account.getId() != userVM.getAccountId()) { // throw new PermissionDeniedException("Unable to create ip forwarding rule, IP address " + ipAddress + " to virtual machine " + virtualMachineId + ", permission denied."); // } // } // // // check for ip address/port conflicts by checking existing forwarding and load balancing rules // List existingNatRules = _rulesDao.findByPublicIpPrivateIpForNatRule(ipAddr, userVM.getGuestIpAddress()); // // if(existingNatRules.size() > 0){ // throw new NetworkRuleConflictException("The specified rule for public ip:"+ipAddr+" vm id:"+virtualMachineId+" already exists"); // } // // //if given ip address is already source nat, return error // if(ipAddress.isSourceNat()){ // throw new PermissionDeniedException("Cannot create a static nat rule for the ip:"+ipAddress.getAddress()+" ,this is already a source nat ip address"); // } // // //if given ip address is already static nat, return error // if(ipAddress.isOneToOneNat()){ // throw new PermissionDeniedException("Cannot create a static nat rule for the ip:"+ipAddress.getAddress()+" ,this is already a static nat ip address"); // } // // newFwRule = new PortForwardingRuleVO(); // newFwRule.setEnabled(true); // newFwRule.setForwarding(true); // newFwRule.setPrivatePort(null); // newFwRule.setProtocol(NetUtils.NAT_PROTO);//protocol cannot be null; adding this as a NAT // newFwRule.setPublicPort(null); // newFwRule.setPublicIpAddress(ipAddress.getAddress()); // newFwRule.setPrivateIpAddress(userVM.getGuestIpAddress()); // newFwRule.setGroupId(null); // // _rulesDao.persist(newFwRule); // txn.commit(); // } catch (Exception e) { // s_logger.warn("Unable to create new firewall rule for 1:1 NAT"); // txn.rollback(); // throw new ServerApiException(BaseCmd.INTERNAL_ERROR,"Unable to create new firewall rule for 1:1 NAT:"+e.getMessage()); // }finally{ // if(locked) { // _vmDao.releaseFromLockTable(userVM.getId()); // } // } // // return newFwRule; // } // // @Override @DB // public boolean deleteIpForwardingRule(Long id) { // Long ruleId = id; // Long userId = UserContext.current().getUserId(); // Account account = UserContext.current().getAccount(); // // //verify input parameters here // PortForwardingRuleVO rule = _firewallRulesDao.findById(ruleId); // if (rule == null) { // throw new InvalidParameterValueException("Unable to find port forwarding rule " + ruleId); // } // // String publicIp = rule.getSourceIpAddress(); // // // IPAddressVO ipAddress = _ipAddressDao.findById(publicIp); // if (ipAddress == null) { // throw new InvalidParameterValueException("Unable to find IP address for ip forwarding rule " + ruleId); // } // // // although we are not writing these values to the DB, we will check // // them out of an abundance // // of caution (may not be warranted) // // Account ruleOwner = _accountDao.findById(ipAddress.getAccountId()); // if (ruleOwner == null) { // throw new InvalidParameterValueException("Unable to find owning account for ip forwarding rule " + ruleId); // } // // // if an admin account was passed in, or no account was passed in, make sure we honor the accountName/domainId parameters // if (account != null) { // if (isAdmin(account.getType())) { // if (!_domainDao.isChildDomain(account.getDomainId(), ruleOwner.getDomainId())) { // throw new PermissionDeniedException("Unable to delete ip forwarding rule " + ruleId + ", permission denied."); // } // } else if (account.getId() != ruleOwner.getId()) { // throw new PermissionDeniedException("Unable to delete ip forwarding rule " + ruleId + ", permission denied."); // } // } // // Transaction txn = Transaction.currentTxn(); // boolean locked = false; // boolean success = false; // try { // // ipAddress = _ipAddressDao.acquireInLockTable(publicIp); // if (ipAddress == null) { // throw new PermissionDeniedException("Unable to obtain lock on record for deletion"); // } // // locked = true; // txn.start(); // // final DomainRouterVO router = _routerMgr.getRouter(ipAddress.getAccountId(), ipAddress.getDataCenterId()); // success = createOrDeleteIpForwardingRuleOnDomr(rule, router, rule.getDestinationIpAddress(), false); // _firewallRulesDao.remove(ruleId); // // //update the ip_address record // ipAddress.setOneToOneNat(false); // _ipAddressDao.persist(ipAddress); // // String description; // String type = EventTypes.EVENT_NET_RULE_DELETE; // String level = EventVO.LEVEL_INFO; // String ruleName = rule.isForwarding() ? "ip forwarding" : "load balancer"; // // if (success) { // description = "deleted " + ruleName + " rule [" + publicIp +"]->[" + rule.getDestinationIpAddress() + "] " + rule.getProtocol(); // } else { // level = EventVO.LEVEL_ERROR; // description = "Error while deleting " + ruleName + " rule [" + publicIp + "]->[" + rule.getDestinationIpAddress() +"] " + rule.getProtocol(); // } // EventUtils.saveEvent(userId, ipAddress.getAccountId(), level, type, description); // txn.commit(); // }catch (Exception ex) { // txn.rollback(); // s_logger.error("Unexpected exception deleting port forwarding rule " + ruleId, ex); // return false; // }finally { // if (locked) { // _ipAddressDao.releaseFromLockTable(publicIp); // } // txn.close(); // } // return success; // } // // private boolean createOrDeleteIpForwardingRuleOnDomr(PortForwardingRuleVO fwRule, DomainRouterVO router, String guestIp, boolean create){ // // Commands cmds = new Commands(OnError.Continue); // final SetFirewallRuleCommand cmd = new SetFirewallRuleCommand(router.getInstanceName(), router.getPrivateIpAddress(),fwRule, create); // cmds.addCommand(cmd); // try { // _agentMgr.send(router.getHostId(), cmds); // } catch (final AgentUnavailableException e) { // s_logger.warn("agent unavailable", e); // } catch (final OperationTimedoutException e) { // s_logger.warn("Timed Out", e); // } // Answer[] answers = cmds.getAnswers(); // if (answers == null || answers[0].getResult() == false ){ // return false; // }else{ // return true; // } // } // @Override // public PortForwardingRuleVO updatePortForwardingRule(UpdatePortForwardingRuleCmd cmd) throws InvalidParameterValueException, PermissionDeniedException{ // String publicIp = cmd.getPublicIp(); // String privateIp = cmd.getPrivateIp(); // String privatePort = cmd.getPrivatePort(); // String publicPort = cmd.getPublicPort(); // String protocol = cmd.getProtocol(); // Long vmId = cmd.getVirtualMachineId(); // Long userId = UserContext.current().getUserId(); // Account account = UserContext.current().getAccount(); // UserVmVO userVM = null; // // if (userId == null) { // userId = Long.valueOf(User.UID_SYSTEM); // } // // IPAddressVO ipAddressVO = findIPAddressById(publicIp); // if (ipAddressVO == null) { // throw new InvalidParameterValueException("Unable to find IP address " + publicIp); // } // // if (ipAddressVO.getAccountId() == null) { // throw new InvalidParameterValueException("Unable to update port forwarding rule, owner of IP address " + publicIp + " not found."); // } // // if (privateIp != null) { // if (!NetUtils.isValidIp(privateIp)) { // throw new InvalidParameterValueException("Invalid private IP address specified: " + privateIp); // } // Criteria c = new Criteria(); // c.addCriteria(Criteria.ACCOUNTID, new Object[] {ipAddressVO.getAccountId()}); // c.addCriteria(Criteria.DATACENTERID, ipAddressVO.getDataCenterId()); // c.addCriteria(Criteria.IPADDRESS, privateIp); // List userVMs = searchForUserVMs(c); // if ((userVMs == null) || userVMs.isEmpty()) { // throw new ServerApiException(BaseCmd.PARAM_ERROR, "Invalid private IP address specified: " + privateIp + ", no virtual machine instances running with that address."); // } // userVM = userVMs.get(0); // } else if (vmId != null) { // userVM = findUserVMInstanceById(vmId); // if (userVM == null) { // throw new InvalidParameterValueException("Unable to find virtual machine with id " + vmId); // } // // if ((ipAddressVO.getAccountId() == null) || (ipAddressVO.getAccountId().longValue() != userVM.getAccountId())) { // throw new PermissionDeniedException("Unable to update port forwarding rule on IP address " + publicIp + ", permission denied."); // } // // if (ipAddressVO.getDataCenterId() != userVM.getDataCenterId()) { // throw new PermissionDeniedException("Unable to update port forwarding rule, IP address " + publicIp + " is not in the same availability zone as virtual machine " + userVM.toString()); // } // // privateIp = userVM.getGuestIpAddress(); // } else { // throw new InvalidParameterValueException("No private IP address (privateip) or virtual machine instance id (virtualmachineid) specified, unable to update port forwarding rule"); // } // // // if an admin account was passed in, or no account was passed in, make sure we honor the accountName/domainId parameters // if (account != null) { // if (isAdmin(account.getType())) { // if (!_domainDao.isChildDomain(account.getDomainId(), ipAddressVO.getDomainId())) { // throw new PermissionDeniedException("Unable to update port forwarding rule on IP address " + publicIp + ", permission denied."); // } // } else if (account.getId() != ipAddressVO.getAccountId()) { // throw new PermissionDeniedException("Unable to update port forwarding rule on IP address " + publicIp + ", permission denied."); // } // } // // List fwRules = _firewallRulesDao.listIPForwardingForUpdate(publicIp, publicPort, protocol); // if ((fwRules != null) && (fwRules.size() == 1)) { // PortForwardingRuleVO fwRule = fwRules.get(0); // String oldPrivateIP = fwRule.getDestinationIpAddress(); // String oldPrivatePort = fwRule.getDestinationPort(); // fwRule.setPrivateIpAddress(privateIp); // fwRule.setPrivatePort(privatePort); // _firewallRulesDao.update(fwRule.getId(), fwRule); // _networkMgr.updateFirewallRule(fwRule, oldPrivateIP, oldPrivatePort); // return fwRule; // }else{ // s_logger.warn("Unable to find the rule to be updated for public ip:public port"+publicIp+":"+publicPort+ "private ip:private port:"+privateIp+":"+privatePort); // throw new InvalidParameterValueException("Unable to find the rule to be updated for public ip:public port"+publicIp+":"+publicPort+ " private ip:private port:"+privateIp+":"+privatePort); // } // } // // @Override // public PortForwardingRuleVO findForwardingRuleById(Long ruleId) { // return _firewallRulesDao.findById(ruleId); // } }