From e5ca5dddf9851d92ad5036dd2b9c49ba5b934261 Mon Sep 17 00:00:00 2001 From: abhishek Date: Tue, 9 Nov 2010 15:35:19 -0800 Subject: [PATCH] renaming the ip forwarding commands to port forwarding commands, and beginning to work on Keshav's request to modify the current 1-1 NAT to be compatible with the Amazon apis --- client/tomcatconf/commands.properties.in | 6 +- .../api/routing/SetFirewallRuleCommand.java | 14 ++- scripts/network/domr/firewall.sh | 42 ++++++- ....java => CreatePortForwardingRuleCmd.java} | 0 ....java => DeletePortForwardingRuleCmd.java} | 0 ....java => UpdatePortForwardingRuleCmd.java} | 4 +- .../src/com/cloud/network/NetworkManager.java | 12 +- .../com/cloud/network/NetworkManagerImpl.java | 106 +++++++++++++++++- .../com/cloud/server/ManagementServer.java | 6 +- .../cloud/server/ManagementServerImpl.java | 4 +- 10 files changed, 172 insertions(+), 22 deletions(-) rename server/src/com/cloud/api/commands/{CreateIPForwardingRuleCmd.java => CreatePortForwardingRuleCmd.java} (100%) rename server/src/com/cloud/api/commands/{DeleteIPForwardingRuleCmd.java => DeletePortForwardingRuleCmd.java} (100%) rename server/src/com/cloud/api/commands/{UpdateIPForwardingRuleCmd.java => UpdatePortForwardingRuleCmd.java} (97%) diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index c0a522dc086..c347dc11073 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -103,9 +103,9 @@ listPublicIpAddresses=com.cloud.api.commands.ListPublicIpAddressesCmd;15 #### firewall commands listPortForwardingRules=com.cloud.api.commands.ListPortForwardingRulesCmd;15 -createPortForwardingRule=com.cloud.api.commands.CreateIPForwardingRuleCmd;15 -deletePortForwardingRule=com.cloud.api.commands.DeleteIPForwardingRuleCmd;15 -updatePortForwardingRule=com.cloud.api.commands.UpdateIPForwardingRuleCmd;15 +createPortForwardingRule=com.cloud.api.commands.CreatePortForwardingRuleCmd;15 +deletePortForwardingRule=com.cloud.api.commands.DeletePortForwardingRuleCmd;15 +updatePortForwardingRule=com.cloud.api.commands.UpdatePortForwardingRuleCmd;15 #### load balancer commands createLoadBalancerRule=com.cloud.api.commands.CreateLoadBalancerRuleCmd;15 diff --git a/core/src/com/cloud/agent/api/routing/SetFirewallRuleCommand.java b/core/src/com/cloud/agent/api/routing/SetFirewallRuleCommand.java index c46d78d8138..89d44032934 100755 --- a/core/src/com/cloud/agent/api/routing/SetFirewallRuleCommand.java +++ b/core/src/com/cloud/agent/api/routing/SetFirewallRuleCommand.java @@ -25,6 +25,8 @@ public class SetFirewallRuleCommand extends RoutingCommand { String routerIpAddress; String oldPrivateIP = null; String oldPrivatePort = null; + String guestIp = null; + String portRange = null; protected SetFirewallRuleCommand() { } @@ -37,10 +39,12 @@ public class SetFirewallRuleCommand extends RoutingCommand { this.oldPrivatePort = oldPrivatePort; } - public SetFirewallRuleCommand(String routerName, String routerIpAddress, FirewallRuleVO rule) { + public SetFirewallRuleCommand(String routerName, String routerIpAddress, String guestIp, FirewallRuleVO rule, String portRange) { this.routerName = routerName; this.routerIpAddress = routerIpAddress; + this.guestIp = guestIp; this.rule = rule; + this.portRange = portRange; } @Override @@ -96,4 +100,12 @@ public class SetFirewallRuleCommand extends RoutingCommand { return this.oldPrivatePort; } + public String getPortRange(){ + return this.portRange; + } + + public String getGuestIp(){ + return this.guestIp; + } + } diff --git a/scripts/network/domr/firewall.sh b/scripts/network/domr/firewall.sh index 56ee70facbc..c4d5d3052f9 100755 --- a/scripts/network/domr/firewall.sh +++ b/scripts/network/domr/firewall.sh @@ -87,6 +87,31 @@ icmp_entry() { } + +#Add 1:1 NAT entry +add_one_to_one_nat_entry() { + local guestIp=$1 + local publicIp=$2 + local dIp=$3 + local portRange=$4 + local op=$5 + ssh -p 3922 -o StrictHostKeyChecking=no -i $cert root@$dIp "\ + iptables -t nat $op PREROUTING -i eth2 -d $publicIp -j DNAT --to-destination $guestIp + iptables -t nat $op POSTROUTING -o eth2 -s $guestIp -j SNAT --to-source $publicIp":"$portRange + if [ "$op" == "-A" ] + then + iptables -P FORWARD DROP + else + iptables -P FORWARD ACCEPT + fi + iptables $op FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT + iptables $op FORWARD -i eth2 -o eth0 -d $guestIp -m state --state NEW -j ACCEPT + iptables $op FORWARD -i eth0 -o eth2 -s $guestIp -m state --state NEW -j ACCEPT + " + + return $? +} + reverse_op() { local op=$1 @@ -110,11 +135,13 @@ wflag= xflag= nflag= Nflag= +Gflag= +Rflag= op="" oldPrivateIP="" oldPrivatePort="" -while getopts 'ADr:i:P:p:t:l:d:w:x:n:N:' OPTION +while getopts 'ADr:i:P:p:t:l:d:w:x:n:N:G:R:' OPTION do case $OPTION in A) Aflag=1 @@ -156,6 +183,11 @@ do N) Nflag=1 netmask="$OPTARG" ;; + G) Gflag=1 + guestIp="$OPTARG" + ;; + R) Rflag=1 + portRange="$OPTARG" ?) usage exit 2 ;; @@ -192,6 +224,14 @@ then exit 2 fi +#1:1 NAT +if [ "$Gflag$Rflag" == "11" ] + then + add_one_to_one_nat_entry $guestIp $publicIp $domRIp $portRange $op + fi + exit $? +fi + reverseOp=$(reverse_op $op) case $protocol in diff --git a/server/src/com/cloud/api/commands/CreateIPForwardingRuleCmd.java b/server/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java similarity index 100% rename from server/src/com/cloud/api/commands/CreateIPForwardingRuleCmd.java rename to server/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java diff --git a/server/src/com/cloud/api/commands/DeleteIPForwardingRuleCmd.java b/server/src/com/cloud/api/commands/DeletePortForwardingRuleCmd.java similarity index 100% rename from server/src/com/cloud/api/commands/DeleteIPForwardingRuleCmd.java rename to server/src/com/cloud/api/commands/DeletePortForwardingRuleCmd.java diff --git a/server/src/com/cloud/api/commands/UpdateIPForwardingRuleCmd.java b/server/src/com/cloud/api/commands/UpdatePortForwardingRuleCmd.java similarity index 97% rename from server/src/com/cloud/api/commands/UpdateIPForwardingRuleCmd.java rename to server/src/com/cloud/api/commands/UpdatePortForwardingRuleCmd.java index b9c688a057b..35dea1922fe 100644 --- a/server/src/com/cloud/api/commands/UpdateIPForwardingRuleCmd.java +++ b/server/src/com/cloud/api/commands/UpdatePortForwardingRuleCmd.java @@ -19,10 +19,10 @@ import com.cloud.exception.PermissionDeniedException; import com.cloud.network.FirewallRuleVO; import com.cloud.network.IPAddressVO; import com.cloud.user.Account; - + @Implementation(description="Updates a port forwarding rule. Only the private port and the virtual machine can be updated.") public class UpdateIPForwardingRuleCmd extends BaseAsyncCmd { - public static final Logger s_logger = Logger.getLogger(UpdateIPForwardingRuleCmd.class.getName()); + public static final Logger s_logger = Logger.getLogger(UpdateIPForwardingRuleCmd.class.getName()); private static final String s_name = "updateportforwardingruleresponse"; ///////////////////////////////////////////////////// diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 998e57b31bc..dce23943464 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -23,10 +23,11 @@ import java.util.Map; import com.cloud.api.commands.AddVpnUserCmd; import com.cloud.api.commands.AssignToLoadBalancerRuleCmd; import com.cloud.api.commands.AssociateIPAddrCmd; -import com.cloud.api.commands.CreateIPForwardingRuleCmd; +import com.cloud.api.commands.CreateIpForwardingRuleCmd; +import com.cloud.api.commands.CreatePortForwardingRuleCmd; import com.cloud.api.commands.CreateLoadBalancerRuleCmd; import com.cloud.api.commands.CreateRemoteAccessVpnCmd; -import com.cloud.api.commands.DeleteIPForwardingRuleCmd; +import com.cloud.api.commands.DeletePortForwardingRuleCmd; import com.cloud.api.commands.DeleteLoadBalancerRuleCmd; import com.cloud.api.commands.DeleteRemoteAccessVpnCmd; import com.cloud.api.commands.DisassociateIPAddrCmd; @@ -211,7 +212,7 @@ public interface NetworkManager { * @param cmd the command specifying the ip address, public port, protocol, private port, and virtual machine id. * @return the newly created FirewallRuleVO if successful, null otherwise. */ - public FirewallRuleVO createPortForwardingRule(CreateIPForwardingRuleCmd cmd) throws NetworkRuleConflictException; + public FirewallRuleVO createPortForwardingRule(CreatePortForwardingRuleCmd cmd) throws NetworkRuleConflictException; /** * List port forwarding rules assigned to an ip address @@ -304,7 +305,7 @@ public interface NetworkManager { public boolean disassociateIpAddress(DisassociateIPAddrCmd cmd); - public boolean deleteIpForwardingRule(DeleteIPForwardingRuleCmd cmd); + public boolean deleteIpForwardingRule(DeletePortForwardingRuleCmd cmd); List setupNetworkConfiguration(Account owner, NetworkOfferingVO offering, DeploymentPlan plan); List setupNetworkConfiguration(Account owner, NetworkOfferingVO offering, NetworkConfiguration predefined, DeploymentPlan plan); @@ -360,4 +361,7 @@ public interface NetworkManager { NetworkConfiguration getNetworkConfiguration(long id); String getNextAvailableMacAddressInNetwork(long networkConfigurationId) throws InsufficientAddressCapacityException; + String getNextAvailableMacAddressInNetwork(long networkConfigurationId); + + FirewallRuleVO createIpForwardingRule(CreateIpForwardingRuleCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, NetworkRuleConflictException; } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 313097bffb9..d6517012391 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -49,10 +49,11 @@ import com.cloud.api.ServerApiException; import com.cloud.api.commands.AddVpnUserCmd; import com.cloud.api.commands.AssignToLoadBalancerRuleCmd; import com.cloud.api.commands.AssociateIPAddrCmd; -import com.cloud.api.commands.CreateIPForwardingRuleCmd; +import com.cloud.api.commands.CreateIpForwardingRuleCmd; +import com.cloud.api.commands.CreatePortForwardingRuleCmd; import com.cloud.api.commands.CreateLoadBalancerRuleCmd; import com.cloud.api.commands.CreateRemoteAccessVpnCmd; -import com.cloud.api.commands.DeleteIPForwardingRuleCmd; +import com.cloud.api.commands.DeletePortForwardingRuleCmd; import com.cloud.api.commands.DeleteLoadBalancerRuleCmd; import com.cloud.api.commands.DeleteRemoteAccessVpnCmd; import com.cloud.api.commands.DisassociateIPAddrCmd; @@ -894,7 +895,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag if (rule.isForwarding()) { fwdRules.add(rule); - final SetFirewallRuleCommand cmd = new SetFirewallRuleCommand(routerName, routerIp, rule); + final SetFirewallRuleCommand cmd = new SetFirewallRuleCommand(routerName, routerIp, null, rule, null); cmds.addCommand(cmd); } else { lbRules.add(rule); @@ -973,7 +974,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag rule.setVlanNetmask(vlanNetmask); if (rule.isForwarding()) { fwdRules.add(rule); - final SetFirewallRuleCommand cmd = new SetFirewallRuleCommand(router.getInstanceName(), router.getPrivateIpAddress(), rule); + final SetFirewallRuleCommand cmd = new SetFirewallRuleCommand(router.getInstanceName(), router.getPrivateIpAddress(), null, rule, null); cmds.addCommand(cmd); } } @@ -1001,7 +1002,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } @Override - public FirewallRuleVO createPortForwardingRule(CreateIPForwardingRuleCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, NetworkRuleConflictException { + public FirewallRuleVO createPortForwardingRule(CreatePortForwardingRuleCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, NetworkRuleConflictException { // validate IP Address exists IPAddressVO ipAddress = _ipAddressDao.findById(cmd.getIpAddress()); if (ipAddress == null) { @@ -2509,7 +2510,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } @Override @DB - public boolean deleteIpForwardingRule(DeleteIPForwardingRuleCmd cmd) { + public boolean deleteIpForwardingRule(DeletePortForwardingRuleCmd cmd) { Long ruleId = cmd.getId(); Long userId = UserContext.current().getUserId(); Account account = UserContext.current().getAccount(); @@ -2935,4 +2936,97 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag public NetworkConfiguration getNetworkConfiguration(long id) { return _networkConfigDao.findById(id); } + + @Override + public FirewallRuleVO createIpForwardingRule(CreateIpForwardingRuleCmd cmd) throws InvalidParameterValueException, PermissionDeniedException, NetworkRuleConflictException { + // validate IP Address exists + IPAddressVO ipAddress = _ipAddressDao.findById(cmd.getIpAddress()); + if (ipAddress == null) { + throw new InvalidParameterValueException("Unable to create ip 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 ip 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 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 " + cmd.getVirtualMachineId() + ", permission denied."); + } + } else if (account.getId() != userVM.getAccountId()) { + throw new PermissionDeniedException("Unable to create ip forwarding rule, IP address " + ipAddress + " to virtual machine " + cmd.getVirtualMachineId() + ", permission denied."); + } + } + + // 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 (FirewallRuleVO fwRule : existingRulesOnPubIp) { + Ternary> portMappings = mappedPublicPorts.get(fwRule.getPublicPort()); + List protocolList = null; + if (portMappings == null) { + protocolList = new ArrayList(); + } else { + protocolList = portMappings.third(); + } + protocolList.add(fwRule.getProtocol()); + mappedPublicPorts.put(fwRule.getPublicPort(), new Ternary>(fwRule.getPrivateIpAddress(), fwRule.getPrivatePort(), protocolList)); + } + } + + FirewallRuleVO newFwRule = new FirewallRuleVO(); + 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.getPublicIpAddress() + ":" + newFwRule.getPublicPort() + "]->[" + + newFwRule.getPrivateIpAddress() + ":" + newFwRule.getPrivatePort() + "]" + " " + newFwRule.getProtocol(); + } else { + level = EventVO.LEVEL_ERROR; + description = "failed to create new " + ruleName + " rule [" + newFwRule.getPublicIpAddress() + ":" + newFwRule.getPublicPort() + "]->[" + + newFwRule.getPrivateIpAddress() + ":" + newFwRule.getPrivatePort() + "]" + " " + newFwRule.getProtocol(); + } + + EventUtils.saveEvent(UserContext.current().getUserId(), userVM.getAccountId(), level, EventTypes.EVENT_NET_RULE_ADD, description); + + return newFwRule; + } } diff --git a/server/src/com/cloud/server/ManagementServer.java b/server/src/com/cloud/server/ManagementServer.java index 651b135d4e5..73db6a9fec3 100755 --- a/server/src/com/cloud/server/ManagementServer.java +++ b/server/src/com/cloud/server/ManagementServer.java @@ -75,7 +75,7 @@ import com.cloud.api.commands.StartSystemVm2Cmd; import com.cloud.api.commands.StopSystemVm2Cmd; import com.cloud.api.commands.StopSystemVmCmd; import com.cloud.api.commands.UpdateDomainCmd; -import com.cloud.api.commands.UpdateIPForwardingRuleCmd; +import com.cloud.api.commands.UpdatePortForwardingRuleCmd; import com.cloud.api.commands.UpdateIsoCmd; import com.cloud.api.commands.UpdateIsoPermissionsCmd; import com.cloud.api.commands.UpdateTemplateCmd; @@ -552,10 +552,10 @@ public interface ManagementServer { /** * Update an existing port forwarding rule on the given public IP / public port for the given protocol - * @param cmd - the UpdateIPForwardingRuleCmd command that wraps publicIp, privateIp, publicPort, privatePort, protocol of the rule to update + * @param cmd - the UpdatePortForwardingRuleCmd command that wraps publicIp, privateIp, publicPort, privatePort, protocol of the rule to update * @return the new firewall rule if updated, null if no rule on public IP / public port of that protocol could be found */ - FirewallRuleVO updatePortForwardingRule(UpdateIPForwardingRuleCmd cmd); + FirewallRuleVO updatePortForwardingRule(UpdatePortForwardingRuleCmd cmd); /** * Find a firewall rule by rule id diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 6f3cbfe163c..635f2b6fed6 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -125,7 +125,7 @@ import com.cloud.api.commands.StartSystemVm2Cmd; import com.cloud.api.commands.StopSystemVm2Cmd; import com.cloud.api.commands.StopSystemVmCmd; import com.cloud.api.commands.UpdateDomainCmd; -import com.cloud.api.commands.UpdateIPForwardingRuleCmd; +import com.cloud.api.commands.UpdatePortForwardingRuleCmd; import com.cloud.api.commands.UpdateIsoCmd; import com.cloud.api.commands.UpdateIsoPermissionsCmd; import com.cloud.api.commands.UpdateTemplateCmd; @@ -2567,7 +2567,7 @@ public class ManagementServerImpl implements ManagementServer { } @Override - public FirewallRuleVO updatePortForwardingRule(UpdateIPForwardingRuleCmd cmd) throws InvalidParameterValueException, PermissionDeniedException{ + public FirewallRuleVO updatePortForwardingRule(UpdatePortForwardingRuleCmd cmd) throws InvalidParameterValueException, PermissionDeniedException{ String publicIp = cmd.getPublicIp(); String privateIp = cmd.getPrivateIp(); String privatePort = cmd.getPrivatePort();