From 6b9603bc4cd6157829d78904ef8a63bfc23049a2 Mon Sep 17 00:00:00 2001 From: alena Date: Tue, 9 Aug 2011 15:20:20 -0700 Subject: [PATCH] bug 10561: intermidiate checkin for FirewallRuleFeature 1) Added new apis: createFirewallRule, deleteFirewallRule, listFirewallRules 2) Modified existing apis - added boolean openFirewall parameter to createPortForwardingRule/createIpForwardingRule/createRemoteAccessVpn. If parameter is set to true, open firewall on the domR before creating an actual PF rule there Modified backend calls appropriately. 3) Schema changes for firewall_rules table: * startPort/endPort can be null now * added icmp_type, icmp_code fields (can be not null only when protocol is icmp) 4) Added new manager - FirewallManagerImpl Conflicts: api/src/com/cloud/api/BaseCmd.java client/tomcatconf/commands.properties.in server/src/com/cloud/api/ApiResponseHelper.java server/src/com/cloud/configuration/DefaultComponentLibrary.java server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java server/src/com/cloud/network/rules/RulesManagerImpl.java --- .../cloud/agent/api/to/FirewallRuleTO.java | 22 +- api/src/com/cloud/api/ApiConstants.java | 1 + api/src/com/cloud/api/BaseCmd.java | 40 +- api/src/com/cloud/api/ResponseGenerator.java | 4 + .../api/commands/CreateFirewallRuleCmd.java | 283 ++++++++++ .../commands/CreateIpForwardingRuleCmd.java | 43 +- .../commands/CreateLoadBalancerRuleCmd.java | 31 +- .../commands/CreatePortForwardingRuleCmd.java | 37 +- .../commands/CreateRemoteAccessVpnCmd.java | 19 +- .../api/commands/DeleteFirewallRuleCmd.java | 112 ++++ .../api/commands/ListFirewallRulesCmd.java | 98 ++++ .../cloud/api/response/FirewallResponse.java | 97 ++++ .../api/response/FirewallRuleResponse.java | 2 - api/src/com/cloud/event/EventTypes.java | 2 + .../network/firewall/FirewallService.java | 25 + .../cloud/network/lb/LoadBalancingRule.java | 14 +- .../network/lb/LoadBalancingRulesService.java | 3 +- .../com/cloud/network/rules/FirewallRule.java | 12 +- .../com/cloud/network/rules/LoadBalancer.java | 2 - .../network/rules/PortForwardingRule.java | 6 - .../com/cloud/network/rules/RulesService.java | 7 +- .../cloud/network/rules/StaticNatRule.java | 4 +- .../network/vpn/RemoteAccessVpnService.java | 4 +- client/tomcatconf/commands.properties.in | 10 +- .../xen/resource/CitrixResourceBase.java | 22 +- server/src/com/cloud/api/ApiDBUtils.java | 2 +- .../src/com/cloud/api/ApiResponseHelper.java | 38 +- .../DefaultComponentLibrary.java | 2 + .../cloud/network/FirewallRulesCidrsVO.java | 8 +- .../src/com/cloud/network/LoadBalancerVO.java | 16 +- .../com/cloud/network/NetworkManagerImpl.java | 51 +- .../cloud/network/dao/FirewallRulesDao.java | 4 +- .../network/dao/FirewallRulesDaoImpl.java | 49 ++ .../network/dao/LoadBalancerDaoImpl.java | 45 -- .../network/element/VirtualRouterElement.java | 2 +- .../network/firewall/FirewallManagerImpl.java | 499 ++++++++++++++++++ .../lb/LoadBalancingRulesManagerImpl.java | 58 +- .../VirtualNetworkApplianceManagerImpl.java | 34 +- .../cloud/network/rules/FirewallManager.java | 58 ++ .../cloud/network/rules/FirewallRuleVO.java | 51 +- .../network/rules/PortForwardingRuleVO.java | 25 +- .../com/cloud/network/rules/RulesManager.java | 23 +- .../cloud/network/rules/RulesManagerImpl.java | 278 ++-------- .../network/rules/StaticNatRuleImpl.java | 21 +- .../rules/dao/PortForwardingRulesDaoImpl.java | 51 +- .../vpn/RemoteAccessVpnManagerImpl.java | 26 +- .../SecondaryStorageManagerImpl.java | 2 +- setup/db/create-schema.sql | 6 +- utils/src/com/cloud/utils/net/NetUtils.java | 2 + 49 files changed, 1764 insertions(+), 487 deletions(-) create mode 100644 api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java create mode 100644 api/src/com/cloud/api/commands/DeleteFirewallRuleCmd.java create mode 100644 api/src/com/cloud/api/commands/ListFirewallRulesCmd.java create mode 100644 api/src/com/cloud/api/response/FirewallResponse.java create mode 100644 api/src/com/cloud/network/firewall/FirewallService.java create mode 100644 server/src/com/cloud/network/firewall/FirewallManagerImpl.java create mode 100644 server/src/com/cloud/network/rules/FirewallManager.java diff --git a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java index 8b0fce0295d..236f0562524 100644 --- a/api/src/com/cloud/agent/api/to/FirewallRuleTO.java +++ b/api/src/com/cloud/agent/api/to/FirewallRuleTO.java @@ -17,6 +17,9 @@ */ package com.cloud.agent.api.to; +import java.util.ArrayList; +import java.util.List; + import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.State; import com.cloud.utils.net.NetUtils; @@ -53,10 +56,25 @@ public class FirewallRuleTO { protected FirewallRuleTO() { } - public FirewallRuleTO(long id, String srcIp, String protocol, int srcPortStart, int srcPortEnd, boolean revoked, boolean alreadyAdded, FirewallRule.Purpose purpose) { + public FirewallRuleTO(long id, String srcIp, String protocol, Integer srcPortStart, Integer srcPortEnd, boolean revoked, boolean alreadyAdded, FirewallRule.Purpose purpose) { this.srcIp = srcIp; this.protocol = protocol; - this.srcPortRange = new int[] {srcPortStart, srcPortEnd}; + + if (srcPortStart != null) { + List portRange = new ArrayList(); + portRange.add(srcPortStart); + if (srcPortEnd != null) { + portRange.add(srcPortEnd); + } + + srcPortRange = new int[portRange.size()]; + int i = 0; + for (Integer port : portRange) { + srcPortRange[i] = port.intValue(); + i ++; + } + } + this.revoked = revoked; this.alreadyAdded = alreadyAdded; this.purpose = purpose; diff --git a/api/src/com/cloud/api/ApiConstants.java b/api/src/com/cloud/api/ApiConstants.java index 0d9654c4f12..a312238d9b3 100755 --- a/api/src/com/cloud/api/ApiConstants.java +++ b/api/src/com/cloud/api/ApiConstants.java @@ -254,4 +254,5 @@ public class ApiConstants { public static final String REDUNDANT_ROUTER = "redundantrouter"; public static final String IP_NETWORK_LIST = "iptonetworklist"; public static final String KEYBOARD="keyboard"; + public static final String OPEN_FIREWALL="openfirewall"; } diff --git a/api/src/com/cloud/api/BaseCmd.java b/api/src/com/cloud/api/BaseCmd.java index bf5cc370c97..45d01700b20 100755 --- a/api/src/com/cloud/api/BaseCmd.java +++ b/api/src/com/cloud/api/BaseCmd.java @@ -25,6 +25,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; +<<<<<<< HEAD import org.apache.log4j.Logger; @@ -56,6 +57,39 @@ import com.cloud.utils.Pair; import com.cloud.utils.component.ComponentLocator; import com.cloud.vm.BareMetalVmService; import com.cloud.vm.UserVmService; +======= + +import org.apache.log4j.Logger; + +import com.cloud.configuration.ConfigurationService; +import com.cloud.consoleproxy.ConsoleProxyService; +import com.cloud.dao.EntityManager; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.NetworkService; +import com.cloud.network.VirtualNetworkApplianceService; +import com.cloud.network.firewall.FirewallService; +import com.cloud.network.lb.LoadBalancingRulesService; +import com.cloud.network.rules.RulesService; +import com.cloud.network.security.SecurityGroupService; +import com.cloud.network.vpn.RemoteAccessVpnService; +import com.cloud.resource.ResourceService; +import com.cloud.server.ManagementService; +import com.cloud.storage.StorageService; +import com.cloud.storage.snapshot.SnapshotService; +import com.cloud.template.TemplateService; +import com.cloud.user.Account; +import com.cloud.user.AccountService; +import com.cloud.user.UserContext; +import com.cloud.utils.Pair; +import com.cloud.utils.component.ComponentLocator; +import com.cloud.vm.UserVmService; +import com.cloud.vm.BareMetalVmService; +>>>>>>> 32445e6... bug 10561: intermidiate checkin for FirewallRuleFeature public abstract class BaseCmd { private static final Logger s_logger = Logger.getLogger(BaseCmd.class.getName()); @@ -117,7 +151,8 @@ public abstract class BaseCmd { public static LoadBalancingRulesService _lbService; public static RemoteAccessVpnService _ravService; public static BareMetalVmService _bareMetalVmService; - public static ProjectService _projectService; + public static ProjectService _projectService; + public static FirewallService _firewallService; static void setComponents(ResponseGenerator generator) { ComponentLocator locator = ComponentLocator.getLocator(ManagementService.Name); @@ -139,7 +174,8 @@ public abstract class BaseCmd { _ravService = locator.getManager(RemoteAccessVpnService.class); _responseGenerator = generator; _bareMetalVmService = locator.getManager(BareMetalVmService.class); - _projectService = locator.getManager(ProjectService.class); + _projectService = locator.getManager(ProjectService.class); + _firewallService = locator.getManager(FirewallService.class); } public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException; diff --git a/api/src/com/cloud/api/ResponseGenerator.java b/api/src/com/cloud/api/ResponseGenerator.java index 8577a52ea17..3122ed217f7 100755 --- a/api/src/com/cloud/api/ResponseGenerator.java +++ b/api/src/com/cloud/api/ResponseGenerator.java @@ -32,6 +32,7 @@ import com.cloud.api.response.DomainResponse; import com.cloud.api.response.DomainRouterResponse; import com.cloud.api.response.EventResponse; import com.cloud.api.response.ExtractResponse; +import com.cloud.api.response.FirewallResponse; import com.cloud.api.response.FirewallRuleResponse; import com.cloud.api.response.HostResponse; import com.cloud.api.response.IPAddressResponse; @@ -76,6 +77,7 @@ import com.cloud.network.Network; import com.cloud.network.RemoteAccessVpn; import com.cloud.network.VpnUser; import com.cloud.network.router.VirtualRouter; +import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.LoadBalancer; import com.cloud.network.rules.PortForwardingRule; import com.cloud.network.rules.StaticNatRule; @@ -207,5 +209,7 @@ public interface ResponseGenerator { List createIsoResponses(VirtualMachineTemplate iso, long zoneId, boolean readyOnly); List createTemplateResponses(long templateId, Long vmId); + + FirewallResponse createFirewallResponse(FirewallRule fwRule); } diff --git a/api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java b/api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java new file mode 100644 index 00000000000..346f4e4c2cb --- /dev/null +++ b/api/src/com/cloud/api/commands/CreateFirewallRuleCmd.java @@ -0,0 +1,283 @@ +/** + * 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.api.commands; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseAsyncCmd; +import com.cloud.api.BaseAsyncCreateCmd; +import com.cloud.api.BaseCmd; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.ServerApiException; +import com.cloud.api.response.FirewallResponse; +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.IpAddress; +import com.cloud.network.rules.FirewallRule; +import com.cloud.user.Account; +import com.cloud.user.UserContext; +import com.cloud.utils.net.NetUtils; + +@Implementation(description = "Creates a firewall rule for a given ip address", responseObject = FirewallResponse.class) +public class CreateFirewallRuleCmd extends BaseAsyncCreateCmd implements FirewallRule { + public static final Logger s_logger = Logger.getLogger(CreateFirewallRuleCmd.class.getName()); + + private static final String s_name = "createfirewallruleresponse"; + + // /////////////////////////////////////////////////// + // ////////////// API parameters ///////////////////// + // /////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.IP_ADDRESS_ID, type = CommandType.LONG, required = true, description = "the IP address id of the port forwarding rule") + private Long ipAddressId; + + @Parameter(name = ApiConstants.PROTOCOL, type = CommandType.STRING, required = true, description = "the protocol for the firewall rule. Valid values are TCP/UDP/ICMP.") + private String protocol; + + @Parameter(name = ApiConstants.START_PORT, type = CommandType.INTEGER, description = "the starting port of firewall rule") + private Integer publicStartPort; + + @Parameter(name = ApiConstants.END_PORT, type = CommandType.INTEGER, description = "the ending port of firewall rule") + private Integer publicEndPort; + + @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the cidr list to forward traffic from") + private List cidrlist; + + @Parameter(name = ApiConstants.ICMP_TYPE, type = CommandType.INTEGER, description = "type of the icmp message being sent") + private Integer icmpType; + + @Parameter(name = ApiConstants.ICMP_CODE, type = CommandType.INTEGER, description = "error code for this icmp message") + private Integer icmpCode; + + + // /////////////////////////////////////////////////// + // ///////////////// Accessors /////////////////////// + // /////////////////////////////////////////////////// + + public Long getIpAddressId() { + return ipAddressId; + } + + @Override + public String getProtocol() { + return protocol.trim(); + } + + public List getSourceCidrList() { + if (cidrlist != null) { + return cidrlist; + } else { + List oneCidrList = new ArrayList(); + oneCidrList.add(NetUtils.ALL_CIDRS); + return oneCidrList; + } + + } + + // /////////////////////////////////////////////////// + // ///////////// API Implementation/////////////////// + // /////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public void setSourceCidrList(List cidrs){ + cidrlist = cidrs; + } + + @Override + public void execute() throws ResourceUnavailableException { + UserContext callerContext = UserContext.current(); + boolean success = false; + FirewallRule rule = _entityMgr.findById(FirewallRule.class, getEntityId()); + try { + UserContext.current().setEventDetails("Rule Id: " + getEntityId()); + success = _firewallService.applyFirewallRules(rule.getSourceIpAddressId(), callerContext.getCaller()); + + // State is different after the rule is applied, so get new object here + rule = _entityMgr.findById(FirewallRule.class, getEntityId()); + FirewallResponse fwResponse = new FirewallResponse(); + if (rule != null) { + fwResponse = _responseGenerator.createFirewallResponse(rule); + setResponseObject(fwResponse); + } + fwResponse.setResponseName(getCommandName()); + } finally { + if (!success || rule == null) { + _firewallService.revokeFirewallRule(getEntityId(), true); + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to create firewall rule"); + } + } + } + + @Override + public long getId() { + throw new UnsupportedOperationException("database id can only provided by VO objects"); + } + + @Override + public String getXid() { + // FIXME: We should allow for end user to specify Xid. + return null; + } + + @Override + public long getSourceIpAddressId() { + return ipAddressId; + } + + @Override + public Integer getSourcePortStart() { + if (publicStartPort != null) { + return publicStartPort.intValue(); + } + return null; + } + + @Override + public Integer getSourcePortEnd() { + if (publicEndPort == null) { + if (publicStartPort != null) { + return publicStartPort.intValue(); + } + } else { + return publicEndPort.intValue(); + } + + return null; + } + + @Override + public Purpose getPurpose() { + return Purpose.Firewall; + } + + @Override + public State getState() { + throw new UnsupportedOperationException("Should never call me to find the state"); + } + + @Override + public long getNetworkId() { + throw new UnsupportedOperationException("Not yet implemented"); + } + + @Override + public long getEntityOwnerId() { + Account account = UserContext.current().getCaller(); + + if (account != null) { + return account.getId(); + } + + return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked + } + + @Override + public long getDomainId() { + IpAddress ip = _networkService.getIp(ipAddressId); + return ip.getDomainId(); + } + + @Override + public void create() { + if (getSourceCidrList() != null) { + for (String cidr: getSourceCidrList()){ + if (!NetUtils.isValidCIDR(cidr)){ + throw new ServerApiException(BaseCmd.PARAM_ERROR, "Source cidrs formatting error " + cidr); + } + } + } + + try { + FirewallRule result = _firewallService.createFirewallRule(this); + setEntityId(result.getId()); + } catch (NetworkRuleConflictException ex) { + s_logger.info("Network rule conflict: " + ex.getMessage()); + s_logger.trace("Network Rule Conflict: ", ex); + throw new ServerApiException(BaseCmd.NETWORK_RULE_CONFLICT_ERROR, ex.getMessage()); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_FIREWALL_OPEN; + } + + @Override + public String getEventDescription() { + IpAddress ip = _networkService.getIp(ipAddressId); + return ("Createing firewall rule for Ip: " + ip.getAddress() + " for protocol:" + this.getProtocol()); + } + + @Override + public long getAccountId() { + IpAddress ip = _networkService.getIp(ipAddressId); + return ip.getAccountId(); + } + + @Override + public String getSyncObjType() { + return BaseAsyncCmd.networkSyncObject; + } + + @Override + public Long getSyncObjId() { + return getIp().getAssociatedWithNetworkId(); + } + + private IpAddress getIp() { + IpAddress ip = _networkService.getIp(ipAddressId); + if (ip == null) { + throw new InvalidParameterValueException("Unable to find ip address by id " + ipAddressId); + } + return ip; + } + + @Override + public Integer getIcmpCode() { + if (icmpCode != null) { + return icmpCode; + } else if (protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO)) { + return -1; + } + return null; + } + + @Override + public Integer getIcmpType() { + if (icmpType != null) { + return icmpType; + } else if (protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO)) { + return -1; + + } + return null; + } + +} diff --git a/api/src/com/cloud/api/commands/CreateIpForwardingRuleCmd.java b/api/src/com/cloud/api/commands/CreateIpForwardingRuleCmd.java index 68a58df50e1..a9cea5109ea 100644 --- a/api/src/com/cloud/api/commands/CreateIpForwardingRuleCmd.java +++ b/api/src/com/cloud/api/commands/CreateIpForwardingRuleCmd.java @@ -18,6 +18,8 @@ package com.cloud.api.commands; +import java.util.List; + import org.apache.log4j.Logger; import com.cloud.api.ApiConstants; @@ -61,6 +63,9 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Sta @Parameter(name=ApiConstants.PROTOCOL, type=CommandType.STRING, required=true, description="the protocol for the rule. Valid values are TCP or UDP.") private String protocol; + @Parameter(name = ApiConstants.OPEN_FIREWALL, type = CommandType.BOOLEAN, description = "if true, firewall rule for source/end pubic port is automatically created; if false - firewall rule has to be created explicitely. Has value true by default") + private Boolean openFirewall; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -77,6 +82,14 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Sta public int getEndPort() { return endPort; } + + public Boolean getOpenFirewall() { + if (openFirewall != null) { + return openFirewall; + } else { + return true; + } + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -89,11 +102,16 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Sta @Override public void execute() throws ResourceUnavailableException{ - boolean result = false; + boolean result = true; FirewallRule rule = null; try { UserContext.current().setEventDetails("Rule Id: "+ getEntityId()); - result = _rulesService.applyStaticNatRules(ipAddressId, UserContext.current().getCaller()); + + if (getOpenFirewall()) { + result = result && _firewallService.applyFirewallRules(rule.getSourceIpAddressId(), UserContext.current().getCaller()); + } + + result = result && _rulesService.applyStaticNatRules(ipAddressId, UserContext.current().getCaller()); rule = _entityMgr.findById(FirewallRule.class, getEntityId()); StaticNatRule staticNatRule = _rulesService.buildStaticNatRule(rule); IpForwardingRuleResponse fwResponse = _responseGenerator.createIpForwardingRuleResponse(staticNatRule); @@ -111,7 +129,7 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Sta public void create() { StaticNatRule rule; try { - rule = _rulesService.createStaticNatRule(this); + rule = _rulesService.createStaticNatRule(this, getOpenFirewall()); } catch (NetworkRuleConflictException e) { s_logger.info("Unable to create Static Nat Rule due to " + e.getMessage()); throw new ServerApiException(BaseCmd.NETWORK_RULE_CONFLICT_ERROR, e.getMessage()); @@ -167,12 +185,12 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Sta } @Override - public int getSourcePortStart() { + public Integer getSourcePortStart() { return startPort; } @Override - public int getSourcePortEnd() { + public Integer getSourcePortEnd() { if (endPort == null) { return startPort; } else { @@ -235,4 +253,19 @@ public class CreateIpForwardingRuleCmd extends BaseAsyncCreateCmd implements Sta } return ip; } + + @Override + public Integer getIcmpCode() { + return null; + } + + @Override + public Integer getIcmpType() { + return null; + } + + @Override + public List getSourceCidrList() { + return null; + } } diff --git a/api/src/com/cloud/api/commands/CreateLoadBalancerRuleCmd.java b/api/src/com/cloud/api/commands/CreateLoadBalancerRuleCmd.java index e7a0d1dbcb5..275ad0a8fcc 100644 --- a/api/src/com/cloud/api/commands/CreateLoadBalancerRuleCmd.java +++ b/api/src/com/cloud/api/commands/CreateLoadBalancerRuleCmd.java @@ -27,7 +27,6 @@ import com.cloud.api.BaseCmd; import com.cloud.api.Implementation; import com.cloud.api.Parameter; import com.cloud.api.ServerApiException; -import com.cloud.api.BaseCmd.CommandType; import com.cloud.api.response.LoadBalancerResponse; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.NetworkRuleConflictException; @@ -65,6 +64,9 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the cidr list to forward traffic from") private List cidrlist; + + @Parameter(name = ApiConstants.OPEN_FIREWALL, type = CommandType.BOOLEAN, description = "if true, firewall rule for source/end pubic port is automatically created; if false - firewall rule has to be created explicitely. Has value true by default") + private Boolean openFirewall; ///////////////////////////////////////////////////// @@ -109,6 +111,14 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer public List getSourceCidrList() { return cidrlist; } + + public Boolean getOpenFirewall() { + if (openFirewall != null) { + return openFirewall; + } else { + return true; + } + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -131,7 +141,7 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer LoadBalancer result = null; try { - result = _lbService.createLoadBalancerRule(this); + result = _lbService.createLoadBalancerRule(this, getOpenFirewall()); } catch (NetworkRuleConflictException e) { s_logger.warn("Exception: ", e); throw new ServerApiException(BaseCmd.NETWORK_RULE_CONFLICT_ERROR, e.getMessage()); @@ -158,12 +168,12 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer } @Override - public int getSourcePortStart() { + public Integer getSourcePortStart() { return publicPort.intValue(); } @Override - public int getSourcePortEnd() { + public Integer getSourcePortEnd() { return publicPort.intValue(); } @@ -210,5 +220,16 @@ public class CreateLoadBalancerRuleCmd extends BaseCmd implements LoadBalancer @Override public long getEntityOwnerId() { return getAccountId(); - } + } + + @Override + public Integer getIcmpCode() { + return null; + } + + @Override + public Integer getIcmpType() { + return null; + } + } diff --git a/api/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java b/api/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java index 89eeb442f28..42f9c93ca36 100644 --- a/api/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java +++ b/api/src/com/cloud/api/commands/CreatePortForwardingRuleCmd.java @@ -29,7 +29,6 @@ import com.cloud.api.BaseCmd; import com.cloud.api.Implementation; import com.cloud.api.Parameter; import com.cloud.api.ServerApiException; -import com.cloud.api.BaseCmd.CommandType; import com.cloud.api.response.FirewallRuleResponse; import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; @@ -75,6 +74,9 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the cidr list to forward traffic from") private List cidrlist; + + @Parameter(name = ApiConstants.OPEN_FIREWALL, type = CommandType.BOOLEAN, description = "if true, firewall rule for source/end pubic port is automatically created; if false - firewall rule has to be created explicitely. Has value true by default") + private Boolean openFirewall; // /////////////////////////////////////////////////// @@ -98,6 +100,14 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P public List getSourceCidrList() { return cidrlist; } + + public Boolean getOpenFirewall() { + if (openFirewall != null) { + return openFirewall; + } else { + return true; + } + } // /////////////////////////////////////////////////// // ///////////// API Implementation/////////////////// @@ -115,11 +125,16 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P @Override public void execute() throws ResourceUnavailableException { UserContext callerContext = UserContext.current(); - boolean success = false; + boolean success = true; PortForwardingRule rule = _entityMgr.findById(PortForwardingRule.class, getEntityId()); try { UserContext.current().setEventDetails("Rule Id: " + getEntityId()); - success = _rulesService.applyPortForwardingRules(rule.getSourceIpAddressId(), callerContext.getCaller()); + + if (getOpenFirewall()) { + success = success && _firewallService.applyFirewallRules(rule.getSourceIpAddressId(), callerContext.getCaller()); + } + + success = success && _rulesService.applyPortForwardingRules(rule.getSourceIpAddressId(), callerContext.getCaller()); // State is different after the rule is applied, so get new object here rule = _entityMgr.findById(PortForwardingRule.class, getEntityId()); @@ -154,12 +169,12 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P } @Override - public int getSourcePortStart() { + public Integer getSourcePortStart() { return publicStartPort.intValue(); } @Override - public int getSourcePortEnd() { + public Integer getSourcePortEnd() { return (publicEndPort == null)? publicStartPort.intValue() : publicEndPort.intValue(); } @@ -219,7 +234,7 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P } } try { - PortForwardingRule result = _rulesService.createPortForwardingRule(this, virtualMachineId); + PortForwardingRule result = _rulesService.createPortForwardingRule(this, virtualMachineId, getOpenFirewall()); setEntityId(result.getId()); } catch (NetworkRuleConflictException ex) { s_logger.info("Network rule conflict: " + ex.getMessage()); @@ -262,5 +277,15 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P } return ip; } + + @Override + public Integer getIcmpCode() { + return null; + } + + @Override + public Integer getIcmpType() { + return null; + } } diff --git a/api/src/com/cloud/api/commands/CreateRemoteAccessVpnCmd.java b/api/src/com/cloud/api/commands/CreateRemoteAccessVpnCmd.java index 84674a3e948..4f62dee3349 100644 --- a/api/src/com/cloud/api/commands/CreateRemoteAccessVpnCmd.java +++ b/api/src/com/cloud/api/commands/CreateRemoteAccessVpnCmd.java @@ -27,6 +27,7 @@ import com.cloud.api.BaseCmd; import com.cloud.api.Implementation; import com.cloud.api.Parameter; import com.cloud.api.ServerApiException; +import com.cloud.api.BaseCmd.CommandType; import com.cloud.api.response.RemoteAccessVpnResponse; import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; @@ -58,6 +59,9 @@ public class CreateRemoteAccessVpnCmd extends BaseAsyncCreateCmd { @Parameter(name="domainid", type=CommandType.LONG, description="an optional domainId for the VPN. If the account parameter is used, domainId must also be used.") private Long domainId; + @Parameter(name = ApiConstants.OPEN_FIREWALL, type = CommandType.BOOLEAN, description = "if true, firewall rule for source/end pubic port is automatically created; if false - firewall rule has to be created explicitely. Has value true by default") + private Boolean openFirewall; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -82,13 +86,20 @@ public class CreateRemoteAccessVpnCmd extends BaseAsyncCreateCmd { this.ipRange = ipRange; } + public Boolean getOpenFirewall() { + if (openFirewall != null) { + return openFirewall; + } else { + return true; + } + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// - - @Override + @Override public String getCommandName() { return s_name; } @@ -125,7 +136,7 @@ public class CreateRemoteAccessVpnCmd extends BaseAsyncCreateCmd { @Override public void create() { try { - RemoteAccessVpn vpn = _ravService.createRemoteAccessVpn(publicIpId, ipRange); + RemoteAccessVpn vpn = _ravService.createRemoteAccessVpn(publicIpId, ipRange, getOpenFirewall()); if (vpn != null) { this.setEntityId(vpn.getServerAddressId()); } else { @@ -141,7 +152,7 @@ public class CreateRemoteAccessVpnCmd extends BaseAsyncCreateCmd { @Override public void execute(){ try { - RemoteAccessVpn result = _ravService.startRemoteAccessVpn(publicIpId); + RemoteAccessVpn result = _ravService.startRemoteAccessVpn(publicIpId, getOpenFirewall()); if (result != null) { RemoteAccessVpnResponse response = _responseGenerator.createRemoteAccessVpnResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/com/cloud/api/commands/DeleteFirewallRuleCmd.java b/api/src/com/cloud/api/commands/DeleteFirewallRuleCmd.java new file mode 100644 index 00000000000..17e67f9a49a --- /dev/null +++ b/api/src/com/cloud/api/commands/DeleteFirewallRuleCmd.java @@ -0,0 +1,112 @@ +/** + * 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.api.commands; + +import org.apache.log4j.Logger; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseAsyncCmd; +import com.cloud.api.BaseCmd; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.ServerApiException; +import com.cloud.api.response.SuccessResponse; +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.rules.FirewallRule; +import com.cloud.user.UserContext; + +@Implementation(description="Deletes a firewall rule", responseObject=SuccessResponse.class) +public class DeleteFirewallRuleCmd extends BaseAsyncCmd { + public static final Logger s_logger = Logger.getLogger(DeleteFirewallRuleCmd.class.getName()); + private static final String s_name = "deletefirewallruleresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ID, type=CommandType.LONG, required=true, description="the ID of the firewall rule") + private Long id; + + // unexposed parameter needed for events logging + @Parameter(name=ApiConstants.ACCOUNT_ID, type=CommandType.LONG, expose=false) + private Long ownerId; + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + @Override + public String getCommandName() { + return s_name; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_FIREWALL_CLOSE; + } + + @Override + public String getEventDescription() { + return ("Deleting firewall rule id=" + id); + } + + @Override + public long getEntityOwnerId() { + if (ownerId == null) { + FirewallRule rule = _entityMgr.findById(FirewallRule.class, id); + if (rule == null) { + throw new InvalidParameterValueException("Unable to find firewall rule by id=" + id); + } else { + ownerId = _entityMgr.findById(FirewallRule.class, id).getAccountId(); + } + } + return ownerId; + } + + @Override + public void execute() throws ResourceUnavailableException { + UserContext.current().setEventDetails("Rule Id: " + id); + boolean result = _firewallService.revokeFirewallRule(id, true); + + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to delete firewall rule"); + } + } + + + @Override + public String getSyncObjType() { + return BaseAsyncCmd.networkSyncObject; + } + + @Override + public Long getSyncObjId() { + return _firewallService.getFirewallRule(id).getNetworkId(); + } +} diff --git a/api/src/com/cloud/api/commands/ListFirewallRulesCmd.java b/api/src/com/cloud/api/commands/ListFirewallRulesCmd.java new file mode 100644 index 00000000000..33c71c2c273 --- /dev/null +++ b/api/src/com/cloud/api/commands/ListFirewallRulesCmd.java @@ -0,0 +1,98 @@ +/** + * 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.api.commands; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import com.cloud.api.ApiConstants; +import com.cloud.api.BaseListCmd; +import com.cloud.api.Implementation; +import com.cloud.api.Parameter; +import com.cloud.api.response.FirewallResponse; +import com.cloud.api.response.ListResponse; +import com.cloud.network.rules.FirewallRule; + +@Implementation(description="Lists all firewall rules for an IP address.", responseObject=FirewallResponse.class) +public class ListFirewallRulesCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(ListPortForwardingRulesCmd.class.getName()); + + private static final String s_name = "listfirewallrulesresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name=ApiConstants.ID, type=CommandType.LONG, description="Lists rule with the specified ID.") + private Long id; + + @Parameter(name=ApiConstants.IP_ADDRESS_ID, type=CommandType.LONG, description="the id of IP address of the firwall services") + private Long ipAddressId; + + @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="account. Must be used with the domainId parameter.") + private String accountName; + + @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, description="the domain ID. If used with the account parameter, lists port forwarding rules for the specified account in this domain.") + private Long domainId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getAccountName() { + return accountName; + } + + public Long getDomainId() { + return domainId; + } + + public Long getIpAddressId() { + return ipAddressId; + } + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public void execute(){ + List result = _firewallService.listFirewallRules(this); + ListResponse response = new ListResponse(); + List fwResponses = new ArrayList(); + + for (FirewallRule fwRule : result) { + FirewallResponse ruleData = _responseGenerator.createFirewallResponse(fwRule); + ruleData.setObjectName("firewallrule"); + fwResponses.add(ruleData); + } + response.setResponses(fwResponses); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } +} diff --git a/api/src/com/cloud/api/response/FirewallResponse.java b/api/src/com/cloud/api/response/FirewallResponse.java new file mode 100644 index 00000000000..cf6f9632e28 --- /dev/null +++ b/api/src/com/cloud/api/response/FirewallResponse.java @@ -0,0 +1,97 @@ +/** + * 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.api.response; + +import com.cloud.api.ApiConstants; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class FirewallResponse extends BaseResponse { + @SerializedName(ApiConstants.ID) @Param(description="the ID of the firewall rule") + private Long id; + + @SerializedName(ApiConstants.PROTOCOL) @Param(description="the protocol of the firewall rule") + private String protocol; + + @SerializedName(ApiConstants.START_PORT) @Param(description="the starting port of firewall rule's port range") + private String startPort; + + @SerializedName(ApiConstants.END_PORT) @Param(description = "the ending port of firewall rule's port range") + private String endPort; + + @SerializedName(ApiConstants.IP_ADDRESS_ID) @Param(description="the public ip address id for the port forwarding rule") + private Long publicIpAddressId; + + @SerializedName(ApiConstants.IP_ADDRESS) @Param(description="the public ip address for the port forwarding rule") + private String publicIpAddress; + + @SerializedName(ApiConstants.STATE) @Param(description="the state of the rule") + private String state; + + @SerializedName(ApiConstants.CIDR_LIST) @Param(description="the cidr list to forward traffic from") + private String cidrList; + + @SerializedName(ApiConstants.ICMP_TYPE) @Param(description= "type of the icmp message being sent") + private Integer icmpType; + + @SerializedName(ApiConstants.ICMP_CODE) @Param(description = "error code for this icmp message") + private Integer icmpCode; + + public void setId(Long id) { + this.id = id; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public void setStartPort(String startPort) { + this.startPort = startPort; + } + + public void setEndPort(String endPort) { + this.endPort = endPort; + } + + public void setPublicIpAddressId(Long publicIpAddressId) { + this.publicIpAddressId = publicIpAddressId; + } + + public void setPublicIpAddress(String publicIpAddress) { + this.publicIpAddress = publicIpAddress; + } + + public void setState(String state) { + this.state = state; + } + + public void setCidrList(String cidrList) { + this.cidrList = cidrList; + } + + public void setIcmpType(Integer icmpType) { + this.icmpType = icmpType; + } + + public void setIcmpCode(Integer icmpCode) { + this.icmpCode = icmpCode; + } + + + +} diff --git a/api/src/com/cloud/api/response/FirewallRuleResponse.java b/api/src/com/cloud/api/response/FirewallRuleResponse.java index 8487265f700..4959c2ff5ab 100644 --- a/api/src/com/cloud/api/response/FirewallRuleResponse.java +++ b/api/src/com/cloud/api/response/FirewallRuleResponse.java @@ -18,8 +18,6 @@ package com.cloud.api.response; import com.cloud.api.ApiConstants; -import com.cloud.api.Parameter; -import com.cloud.api.BaseCmd.CommandType; import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index 2cbc8d5cc5c..07248e30ada 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -61,6 +61,8 @@ public class EventTypes { public static final String EVENT_NETWORK_CREATE = "NETWORK.CREATE"; public static final String EVENT_NETWORK_DELETE = "NETWORK.DELETE"; public static final String EVENT_NETWORK_UPDATE = "NETWORK.UPDATE"; + public static final String EVENT_FIREWALL_OPEN = "FIREWALL.OPEN"; + public static final String EVENT_FIREWALL_CLOSE = "FIREWALL.CLOSE"; // Load Balancers public static final String EVENT_ASSIGN_TO_LOAD_BALANCER_RULE = "LB.ASSIGN.TO.RULE"; diff --git a/api/src/com/cloud/network/firewall/FirewallService.java b/api/src/com/cloud/network/firewall/FirewallService.java new file mode 100644 index 00000000000..9fd665144d7 --- /dev/null +++ b/api/src/com/cloud/network/firewall/FirewallService.java @@ -0,0 +1,25 @@ +package com.cloud.network.firewall; + +import java.util.List; + +import com.cloud.api.commands.ListFirewallRulesCmd; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.rules.FirewallRule; +import com.cloud.user.Account; + +public interface FirewallService { + FirewallRule createFirewallRule(FirewallRule rule) throws NetworkRuleConflictException; + List listFirewallRules(ListFirewallRulesCmd cmd); + + /** + * Revokes a firewall rule + * @param ruleId the id of the rule to revoke. + * @return + */ + boolean revokeFirewallRule(long ruleId, boolean apply); + + boolean applyFirewallRules(long ipId, Account caller) throws ResourceUnavailableException; + + FirewallRule getFirewallRule(long ruleId); +} diff --git a/api/src/com/cloud/network/lb/LoadBalancingRule.java b/api/src/com/cloud/network/lb/LoadBalancingRule.java index f47c09cf281..13099c5b63b 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRule.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRule.java @@ -88,12 +88,12 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer{ } @Override - public int getSourcePortStart() { + public Integer getSourcePortStart() { return lb.getSourcePortStart(); } @Override - public int getSourcePortEnd() { + public Integer getSourcePortEnd() { return lb.getSourcePortEnd(); } @@ -159,4 +159,14 @@ public class LoadBalancingRule implements FirewallRule, LoadBalancer{ return revoked; } } + + @Override + public Integer getIcmpCode() { + return null; + } + + @Override + public Integer getIcmpType() { + return null; + } } diff --git a/api/src/com/cloud/network/lb/LoadBalancingRulesService.java b/api/src/com/cloud/network/lb/LoadBalancingRulesService.java index 1fb20959178..d29b02b5e67 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRulesService.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRulesService.java @@ -30,10 +30,11 @@ import com.cloud.uservm.UserVm; public interface LoadBalancingRulesService { /** * Create a load balancer rule from the given ipAddress/port to the given private port + * @param openFirewall TODO * @param cmd the command specifying the ip address, public port, protocol, private port, and algorithm * @return the newly created LoadBalancerVO if successful, null otherwise */ - LoadBalancer createLoadBalancerRule(LoadBalancer lb) throws NetworkRuleConflictException; + LoadBalancer createLoadBalancerRule(LoadBalancer lb, boolean openFirewall) throws NetworkRuleConflictException; LoadBalancer updateLoadBalancerRule(UpdateLoadBalancerRuleCmd cmd); diff --git a/api/src/com/cloud/network/rules/FirewallRule.java b/api/src/com/cloud/network/rules/FirewallRule.java index a1cd05e8acc..fdd8d96386b 100644 --- a/api/src/com/cloud/network/rules/FirewallRule.java +++ b/api/src/com/cloud/network/rules/FirewallRule.java @@ -17,6 +17,8 @@ */ package com.cloud.network.rules; +import java.util.List; + import com.cloud.acl.ControlledEntity; public interface FirewallRule extends ControlledEntity { @@ -48,12 +50,12 @@ public interface FirewallRule extends ControlledEntity { /** * @return first port of the source port range. */ - int getSourcePortStart(); + Integer getSourcePortStart(); /** * @return last port of the source prot range. If this is null, that means only one port is mapped. */ - int getSourcePortEnd(); + Integer getSourcePortEnd(); /** * @return protocol to open these ports for. @@ -67,4 +69,10 @@ public interface FirewallRule extends ControlledEntity { long getNetworkId(); long getSourceIpAddressId(); + + Integer getIcmpCode(); + + Integer getIcmpType(); + + List getSourceCidrList(); } diff --git a/api/src/com/cloud/network/rules/LoadBalancer.java b/api/src/com/cloud/network/rules/LoadBalancer.java index bc73fd26c8e..173d6cd79cf 100644 --- a/api/src/com/cloud/network/rules/LoadBalancer.java +++ b/api/src/com/cloud/network/rules/LoadBalancer.java @@ -35,6 +35,4 @@ public interface LoadBalancer extends FirewallRule { String getAlgorithm(); - public List getSourceCidrList(); - } diff --git a/api/src/com/cloud/network/rules/PortForwardingRule.java b/api/src/com/cloud/network/rules/PortForwardingRule.java index 25930653deb..aac906291ee 100644 --- a/api/src/com/cloud/network/rules/PortForwardingRule.java +++ b/api/src/com/cloud/network/rules/PortForwardingRule.java @@ -17,8 +17,6 @@ */ package com.cloud.network.rules; -import java.util.List; - import com.cloud.utils.net.Ip; /** @@ -45,8 +43,4 @@ public interface PortForwardingRule extends FirewallRule { */ long getVirtualMachineId(); - /** - * @return source cidr to forward - */ - List getSourceCidrList(); } diff --git a/api/src/com/cloud/network/rules/RulesService.java b/api/src/com/cloud/network/rules/RulesService.java index fa0761c711c..7af02a291fd 100644 --- a/api/src/com/cloud/network/rules/RulesService.java +++ b/api/src/com/cloud/network/rules/RulesService.java @@ -32,10 +32,11 @@ public interface RulesService { * an ip address and a virtual machine. * @param rule rule to be created. * @param vmId vm to be linked to. If specified the destination ip address is ignored. + * @param openFirewall TODO * @return PortForwardingRule if created. * @throws NetworkRuleConflictException if conflicts in the network rules are detected. */ - PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId) throws NetworkRuleConflictException; + PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, boolean openFirewall) throws NetworkRuleConflictException; /** * Revokes a port forwarding rule @@ -60,7 +61,7 @@ public interface RulesService { PortForwardingRule getPortForwardigRule(long ruleId); FirewallRule getFirewallRule(long ruleId); - StaticNatRule createStaticNatRule(StaticNatRule rule) throws NetworkRuleConflictException; + StaticNatRule createStaticNatRule(StaticNatRule rule, boolean openFirewall) throws NetworkRuleConflictException; boolean revokeStaticNatRule(long ruleId, boolean apply); @@ -69,5 +70,5 @@ public interface RulesService { StaticNatRule buildStaticNatRule(FirewallRule rule); List getSourceCidrs(long ruleId); - + } diff --git a/api/src/com/cloud/network/rules/StaticNatRule.java b/api/src/com/cloud/network/rules/StaticNatRule.java index d236d2b7325..682553394a2 100644 --- a/api/src/com/cloud/network/rules/StaticNatRule.java +++ b/api/src/com/cloud/network/rules/StaticNatRule.java @@ -28,9 +28,9 @@ public interface StaticNatRule extends ControlledEntity, FirewallRule{ String getProtocol(); - int getSourcePortStart(); + Integer getSourcePortStart(); - int getSourcePortEnd(); + Integer getSourcePortEnd(); Purpose getPurpose(); diff --git a/api/src/com/cloud/network/vpn/RemoteAccessVpnService.java b/api/src/com/cloud/network/vpn/RemoteAccessVpnService.java index a5628bcc894..bb1a1490b2d 100644 --- a/api/src/com/cloud/network/vpn/RemoteAccessVpnService.java +++ b/api/src/com/cloud/network/vpn/RemoteAccessVpnService.java @@ -28,9 +28,9 @@ import com.cloud.network.VpnUser; public interface RemoteAccessVpnService { - RemoteAccessVpn createRemoteAccessVpn(long vpnServerAddressId, String ipRange) throws NetworkRuleConflictException; + RemoteAccessVpn createRemoteAccessVpn(long vpnServerAddressId, String ipRange, boolean openFirewall) throws NetworkRuleConflictException; void destroyRemoteAccessVpn(long vpnServerAddressId) throws ResourceUnavailableException; - RemoteAccessVpn startRemoteAccessVpn(long vpnServerAddressId) throws ResourceUnavailableException; + RemoteAccessVpn startRemoteAccessVpn(long vpnServerAddressId, boolean openFirewall) throws ResourceUnavailableException; VpnUser addVpnUser(long vpnOwnerId, String userName, String password); boolean removeVpnUser(long vpnOwnerId, String userName); diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index dcd03d5ec14..67a1af26975 100755 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -262,8 +262,14 @@ registerSSHKeyPair=com.cloud.api.commands.RegisterSSHKeyPairCmd;15 createSSHKeyPair=com.cloud.api.commands.CreateSSHKeyPairCmd;15 deleteSSHKeyPair=com.cloud.api.commands.DeleteSSHKeyPairCmd;15 listSSHKeyPairs=com.cloud.api.commands.ListSSHKeyPairsCmd;15 - + #### Projects commands createProject=com.cloud.api.commands.CreateProjectCmd;15 deleteProject=com.cloud.api.commands.DeleteProjectCmd;15 -listProjects=com.cloud.api.commands.ListProjectsCmd;15 +listProjects=com.cloud.api.commands.ListProjectsCmd;15 + +#### +createFirewallRule=com.cloud.api.commands.CreateFirewallRuleCmd;15 +deleteFirewallRule=com.cloud.api.commands.DeleteFirewallRuleCmd;15 +listFirewallRules=com.cloud.api.commands.ListFirewallRulesCmd;15 + diff --git a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java index 365a9aa0333..b939f7ae874 100644 --- a/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java +++ b/core/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java @@ -134,12 +134,14 @@ import com.cloud.agent.api.proxy.CheckConsoleProxyLoadCommand; import com.cloud.agent.api.proxy.ConsoleProxyLoadAnswer; import com.cloud.agent.api.proxy.WatchConsoleProxyLoadCommand; import com.cloud.agent.api.routing.DhcpEntryCommand; -import com.cloud.agent.api.routing.IpAssocCommand; import com.cloud.agent.api.routing.IpAssocAnswer; +import com.cloud.agent.api.routing.IpAssocCommand; import com.cloud.agent.api.routing.LoadBalancerConfigCommand; import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; import com.cloud.agent.api.routing.SavePasswordCommand; +import com.cloud.agent.api.routing.SetFirewallRulesAnswer; +import com.cloud.agent.api.routing.SetFirewallRulesCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesAnswer; import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; import com.cloud.agent.api.routing.SetStaticNatRulesAnswer; @@ -154,8 +156,8 @@ import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer; import com.cloud.agent.api.storage.DestroyCommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; +import com.cloud.agent.api.to.FirewallRuleTO; import com.cloud.agent.api.to.IpAddressTO; -import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.PortForwardingRuleTO; import com.cloud.agent.api.to.StaticNatRuleTO; @@ -496,6 +498,8 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return execute((UpdateHostPasswordCommand)cmd); } else if (cmd instanceof CheckRouterCommand) { return execute((CheckRouterCommand)cmd); + } else if (cmd instanceof SetFirewallRulesCommand) { + return execute((SetFirewallRulesCommand)cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } @@ -6504,4 +6508,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe return new Answer(cmd, success, ""); } + + protected SetFirewallRulesAnswer execute(SetFirewallRulesCommand cmd) { + Connection conn = getConnection(); + + String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); + String[] results = new String[cmd.getRules().length]; + int i = 0; + for (FirewallRuleTO rule : cmd.getRules()) { + //FIXME - Jana, add implementation here + } + + return new SetFirewallRulesAnswer(cmd, results); + } + } diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index 5feb6f503f4..2a7fe1cfa34 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -592,7 +592,7 @@ public class ApiDBUtils { return _consoleProxyDao.findById(id); } - public static List findPortForwardingSourceCidrs(long id){ + public static List findFirewallSourceCidrs(long id){ return _firewallCidrsDao.getSourceCidrs(id); } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index 0fb45aa819f..cb7a3a55219 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -44,6 +44,7 @@ import com.cloud.api.response.DomainResponse; import com.cloud.api.response.DomainRouterResponse; import com.cloud.api.response.EventResponse; import com.cloud.api.response.ExtractResponse; +import com.cloud.api.response.FirewallResponse; import com.cloud.api.response.FirewallRuleResponse; import com.cloud.api.response.HostResponse; import com.cloud.api.response.IPAddressResponse; @@ -720,7 +721,7 @@ public class ApiResponseHelper implements ResponseGenerator { lbResponse.setId(loadBalancer.getId()); lbResponse.setName(loadBalancer.getName()); lbResponse.setDescription(loadBalancer.getDescription()); - List cidrs = ApiDBUtils.findPortForwardingSourceCidrs(loadBalancer.getId()); + List cidrs = ApiDBUtils.findFirewallSourceCidrs(loadBalancer.getId()); lbResponse.setCidrList(StringUtils.join(cidrs, ",")); IPAddressVO publicIp = ApiDBUtils.findIpAddressById(loadBalancer.getSourceIpAddressId()); @@ -989,7 +990,7 @@ public class ApiResponseHelper implements ResponseGenerator { response.setProtocol(fwRule.getProtocol()); response.setPublicStartPort(Integer.toString(fwRule.getSourcePortStart())); response.setPublicEndPort(Integer.toString(fwRule.getSourcePortEnd())); - List cidrs = ApiDBUtils.findPortForwardingSourceCidrs(fwRule.getId()); + List cidrs = ApiDBUtils.findFirewallSourceCidrs(fwRule.getId()); response.setCidrList(StringUtils.join(cidrs, ",")); IpAddress ip = ApiDBUtils.findIpAddressById(fwRule.getSourceIpAddressId()); @@ -2147,4 +2148,37 @@ public class ApiResponseHelper implements ResponseGenerator { response.setObjectName("project"); return response; } + public FirewallResponse createFirewallResponse(FirewallRule fwRule) { + FirewallResponse response = new FirewallResponse(); + + response.setId(fwRule.getId()); + response.setProtocol(fwRule.getProtocol()); + if (fwRule.getSourcePortStart() != null) { + response.setStartPort(Integer.toString(fwRule.getSourcePortStart())); + } + + if (fwRule.getSourcePortEnd() != null) { + response.setEndPort(Integer.toString(fwRule.getSourcePortEnd())); + } + + List cidrs = ApiDBUtils.findFirewallSourceCidrs(fwRule.getId()); + response.setCidrList(StringUtils.join(cidrs, ",")); + + IpAddress ip = ApiDBUtils.findIpAddressById(fwRule.getSourceIpAddressId()); + response.setPublicIpAddressId(ip.getId()); + response.setPublicIpAddress(ip.getAddress().addr()); + + FirewallRule.State state = fwRule.getState(); + String stateToSet = state.toString(); + if (state.equals(FirewallRule.State.Revoke)) { + stateToSet = "Deleting"; + } + + response.setIcmpCode(fwRule.getIcmpCode()); + response.setIcmpType(fwRule.getIcmpType()); + + response.setState(stateToSet); + response.setObjectName("firewallrule"); + return response; + } } diff --git a/server/src/com/cloud/configuration/DefaultComponentLibrary.java b/server/src/com/cloud/configuration/DefaultComponentLibrary.java index 87a830999c5..92e71d8ed9f 100755 --- a/server/src/com/cloud/configuration/DefaultComponentLibrary.java +++ b/server/src/com/cloud/configuration/DefaultComponentLibrary.java @@ -82,6 +82,7 @@ import com.cloud.network.dao.NetworkDomainDaoImpl; import com.cloud.network.dao.NetworkRuleConfigDaoImpl; import com.cloud.network.dao.RemoteAccessVpnDaoImpl; import com.cloud.network.dao.VpnUserDaoImpl; +import com.cloud.network.firewall.FirewallManagerImpl; import com.cloud.network.lb.LoadBalancingRulesManagerImpl; import com.cloud.network.ovs.OvsNetworkManagerImpl; import com.cloud.network.ovs.OvsTunnelManagerImpl; @@ -316,6 +317,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com addManager("ClusterFenceManager", ClusterFenceManagerImpl.class); addManager("ResourceManager", ResourceManagerImpl.class); addManager("OCFS2Manager", OCFS2ManagerImpl.class); + addManager("FirewallManager", FirewallManagerImpl.class); ComponentInfo info = addManager("ConsoleProxyManager", ConsoleProxyManagerImpl.class); info.addParameter("consoleproxy.sslEnabled", "true"); addManager("ClusteredAgentManager", ClusteredAgentManagerImpl.class); diff --git a/server/src/com/cloud/network/FirewallRulesCidrsVO.java b/server/src/com/cloud/network/FirewallRulesCidrsVO.java index 1bc86b182a3..1c8845e9c70 100644 --- a/server/src/com/cloud/network/FirewallRulesCidrsVO.java +++ b/server/src/com/cloud/network/FirewallRulesCidrsVO.java @@ -53,13 +53,13 @@ public class FirewallRulesCidrsVO { public long getFirewallRuleId() { return firewallRuleId; } - - public void setFirewallRuleId(long firewallRuleId){ - this.firewallRuleId = firewallRuleId; - } public String getCidr() { return sourceCidrList; } + + public String getSourceCidrList() { + return sourceCidrList; + } } diff --git a/server/src/com/cloud/network/LoadBalancerVO.java b/server/src/com/cloud/network/LoadBalancerVO.java index 193c8e1beca..7664b129e27 100644 --- a/server/src/com/cloud/network/LoadBalancerVO.java +++ b/server/src/com/cloud/network/LoadBalancerVO.java @@ -18,7 +18,6 @@ package com.cloud.network; -import java.util.ArrayList; import java.util.List; import javax.persistence.Column; @@ -26,7 +25,6 @@ import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; -import javax.persistence.Transient; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.LoadBalancer; @@ -52,21 +50,17 @@ public class LoadBalancerVO extends FirewallRuleVO implements LoadBalancer { @Column(name="default_port_end") private int defaultPortEnd; - - @Transient - List sourceCidrs; public LoadBalancerVO() { } public LoadBalancerVO(String xId, String name, String description, long srcIpId, int srcPort, int dstPort, List sourceCidrs, String algorithm, long networkId, long accountId, long domainId) { - super(xId, srcIpId, srcPort, NetUtils.TCP_PROTO, networkId, accountId, domainId, Purpose.LoadBalancing); + super(xId, srcIpId, srcPort, NetUtils.TCP_PROTO, networkId, accountId, domainId, Purpose.LoadBalancing, sourceCidrs, null, null); this.name = name; this.description = description; this.algorithm = algorithm; this.defaultPortStart = dstPort; this.defaultPortEnd = dstPort; - this.sourceCidrs = sourceCidrs; } @Override @@ -77,14 +71,6 @@ public class LoadBalancerVO extends FirewallRuleVO implements LoadBalancer { @Override public String getDescription() { return description; - } - - public void setSourceCidrList(List sourceCidrs) { - this.sourceCidrs=sourceCidrs; - } - @Override - public List getSourceCidrList() { - return sourceCidrs; } @Override diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 0c9e445683e..afda95deb47 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -94,13 +94,17 @@ import com.cloud.network.Networks.AddressFormat; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.TrafficType; import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkDomainDao; import com.cloud.network.element.NetworkElement; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.lb.LoadBalancingRulesManager; +import com.cloud.network.rules.FirewallManager; import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.RulesManager; import com.cloud.network.vpn.PasswordResetElement; import com.cloud.network.vpn.RemoteAccessVpnElement; @@ -214,6 +218,10 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag NetworkDomainDao _networkDomainDao; @Inject VMInstanceDao _vmDao; + @Inject + FirewallManager _firewallMgr; + @Inject + FirewallRulesDao _firewallDao; @Inject DomainRouterDao _routerDao; @@ -2207,6 +2215,20 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag success = false; s_logger.warn("Failed to cleanup LB rules as a part of network id=" + networkId + " cleanup"); } + + //revoke all firewall rules for the network + try { + if (_firewallMgr.revokeAllFirewallRulesForNetwork(networkId, callerUserId, caller)) { + s_logger.debug("Successfully cleaned up firewallRules rules for network id=" + networkId); + } else { + success = false; + s_logger.warn("Failed to cleanup Firewall rules as a part of network id=" + networkId + " cleanup"); + } + } catch (ResourceUnavailableException ex) { + success = false; + // shouldn't even come here as network is being cleaned up after all network elements are shutdown + s_logger.warn("Failed to cleanup Firewall rules as a part of network id=" + networkId + " cleanup due to resourceUnavailable ", ex); + } // release all ip addresses List ipsToRelease = _ipAddressDao.listByAssociatedNetwork(networkId, null); @@ -2399,6 +2421,13 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag s_logger.warn("Failed to apply ip addresses as a part of network id" + networkId + " restart"); success = false; } + + // apply firewall rules + List firewallRulesToApply = _firewallDao.listByNetworkAndPurpose(networkId, Purpose.Firewall); + if (!_firewallMgr.applyFirewallRules(firewallRulesToApply, false, caller)) { + s_logger.warn("Failed to reapply firewall rule(s) as a part of network id=" + networkId + " restart"); + success = false; + } // apply port forwarding rules if (!_rulesMgr.applyPortForwardingRulesForNetwork(networkId, false, caller)) { @@ -2423,7 +2452,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag if (vpnsToReapply != null) { for (RemoteAccessVpn vpn : vpnsToReapply) { // Start remote access vpn per ip - if (_vpnMgr.startRemoteAccessVpn(vpn.getServerAddressId()) == null) { + if (_vpnMgr.startRemoteAccessVpn(vpn.getServerAddressId(), false) == null) { s_logger.warn("Failed to reapply vpn rules as a part of network id=" + networkId + " restart"); success = false; } @@ -2767,9 +2796,11 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag private boolean cleanupIpResources(long ipId, long userId, Account caller) { boolean success = true; + + //Revoke all PF/Static nat rules for the ip try { - s_logger.debug("Revoking all PF/StaticNat rules as a part of public IP id=" + ipId + " release..."); - if (!_rulesMgr.revokeAllRulesForIp(ipId, userId, caller)) { + s_logger.debug("Revoking all " + Purpose.PortForwarding + "/" + Purpose.StaticNat + " rules as a part of public IP id=" + ipId + " release..."); + if (!_rulesMgr.revokeAllPFAndStaticNatRulesForIp(ipId, userId, caller)) { s_logger.warn("Unable to revoke all the port forwarding rules for ip id=" + ipId + " as a part of ip release"); success = false; } @@ -2778,7 +2809,7 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag success = false; } - s_logger.debug("Revoking all LB rules as a part of public IP id=" + ipId + " release..."); + s_logger.debug("Revoking all " + Purpose.LoadBalancing + " rules as a part of public IP id=" + ipId + " release..."); if (!_lbMgr.removeAllLoadBalanacersForIp(ipId, caller, userId)) { s_logger.warn("Unable to revoke all the load balancer rules for ip id=" + ipId + " as a part of ip release"); success = false; @@ -2795,6 +2826,18 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag s_logger.warn("Unable to destroy remote access vpn for ip id=" + ipId + " as a part of ip release", e); success = false; } + + //Revoke all firewall rules for the ip + try { + s_logger.debug("Revoking all " + Purpose.Firewall + "rules as a part of public IP id=" + ipId + " release..."); + if (!_firewallMgr.revokeFirewallRulesForIp(ipId, userId, caller)) { + s_logger.warn("Unable to revoke all the firewall rules for ip id=" + ipId + " as a part of ip release"); + success = false; + } + } catch (ResourceUnavailableException e) { + s_logger.warn("Unable to revoke all firewall rules for ip id=" + ipId + " as a part of ip release", e); + success = false; + } return success; } diff --git a/server/src/com/cloud/network/dao/FirewallRulesDao.java b/server/src/com/cloud/network/dao/FirewallRulesDao.java index d68fd907a19..a80fe8be2b4 100644 --- a/server/src/com/cloud/network/dao/FirewallRulesDao.java +++ b/server/src/com/cloud/network/dao/FirewallRulesDao.java @@ -39,10 +39,12 @@ public interface FirewallRulesDao extends GenericDao { boolean releasePorts(long ipAddressId, String protocol, FirewallRule.Purpose purpose, int[] ports); - List listByIpAndPurpose(long ipAddressId, FirewallRule.Purpose purpose); + List listByIpAndPurpose(long ipAddressId, FirewallRule.Purpose purpose); List listByNetworkAndPurpose(long networkId, FirewallRule.Purpose purpose); List listStaticNatByVmId(long vmId); + + List listByIpPurposeAndProtocolAndNotRevoked(long ipAddressId, Integer startPort, Integer endPort, String protocol, FirewallRule.Purpose purpose); } diff --git a/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java b/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java index ce65cd13ab5..36448e18c59 100644 --- a/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java +++ b/server/src/com/cloud/network/dao/FirewallRulesDaoImpl.java @@ -36,6 +36,7 @@ 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; @Local(value=FirewallRulesDao.class) @DB(txn=false) public class FirewallRulesDaoImpl extends GenericDaoBase implements FirewallRulesDao { @@ -46,6 +47,8 @@ public class FirewallRulesDaoImpl extends GenericDaoBase i protected final SearchBuilder ReleaseSearch; protected SearchBuilder VmSearch; + protected final FirewallRulesCidrsDaoImpl _firewallRulesCidrsDao = ComponentLocator.inject(FirewallRulesCidrsDaoImpl.class); + protected FirewallRulesDaoImpl() { super(); @@ -64,6 +67,9 @@ public class FirewallRulesDaoImpl extends GenericDaoBase i NotRevokedSearch.and("ipId", NotRevokedSearch.entity().getSourceIpAddressId(), Op.EQ); NotRevokedSearch.and("state", NotRevokedSearch.entity().getState(), Op.NEQ); NotRevokedSearch.and("purpose", NotRevokedSearch.entity().getPurpose(), Op.EQ); + NotRevokedSearch.and("protocol", NotRevokedSearch.entity().getProtocol(), Op.EQ); + NotRevokedSearch.and("sourcePortStart", NotRevokedSearch.entity().getSourcePortStart(), Op.EQ); + NotRevokedSearch.and("sourcePortEnd", NotRevokedSearch.entity().getSourcePortEnd(), Op.EQ); NotRevokedSearch.and("networkId", NotRevokedSearch.entity().getNetworkId(), Op.EQ); NotRevokedSearch.done(); @@ -167,6 +173,49 @@ public class FirewallRulesDaoImpl extends GenericDaoBase i sc.setParameters("purpose", Purpose.StaticNat); sc.setJoinParameters("ipSearch", "associatedWithVmId", vmId); + return listBy(sc); + } + + @Override @DB + public FirewallRuleVO persist(FirewallRuleVO firewallRule) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + + FirewallRuleVO dbfirewallRule = super.persist(firewallRule); + saveSourceCidrs(firewallRule); + + txn.commit(); + return dbfirewallRule; + } + + + public void saveSourceCidrs(FirewallRuleVO firewallRule) { + List cidrlist = firewallRule.getSourceCidrList(); + if (cidrlist == null) { + return; + } + _firewallRulesCidrsDao.persist(firewallRule.getId(), cidrlist); + } + + @Override + public List listByIpPurposeAndProtocolAndNotRevoked(long ipAddressId, Integer startPort, Integer endPort, String protocol, FirewallRule.Purpose purpose) { + SearchCriteria sc = NotRevokedSearch.create(); + sc.setParameters("ipId", ipAddressId); + sc.setParameters("state", State.Revoke); + + if (purpose != null) { + sc.setParameters("purpose", purpose); + } + + if (protocol != null) { + sc.setParameters("protocol", protocol); + } + + sc.setParameters("sourcePortStart", startPort); + + sc.setParameters("sourcePortEnd", endPort); + + return listBy(sc); } diff --git a/server/src/com/cloud/network/dao/LoadBalancerDaoImpl.java b/server/src/com/cloud/network/dao/LoadBalancerDaoImpl.java index 38ef6faeeaf..7086c548706 100644 --- a/server/src/com/cloud/network/dao/LoadBalancerDaoImpl.java +++ b/server/src/com/cloud/network/dao/LoadBalancerDaoImpl.java @@ -28,9 +28,7 @@ import javax.ejb.Local; import org.apache.log4j.Logger; import com.cloud.network.LoadBalancerVO; -import com.cloud.network.rules.PortForwardingRuleVO; import com.cloud.utils.component.ComponentLocator; -import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; @@ -120,48 +118,5 @@ public class LoadBalancerDaoImpl extends GenericDaoBase im sc.setParameters("name", name); return findOneBy(sc); } - - public void saveSourceCidrs(LoadBalancerVO loadBalancerRule) { - List cidrlist = loadBalancerRule.getSourceCidrList(); - if (cidrlist == null) { - return; - } - _portForwardingRulesCidrsDao.persist(loadBalancerRule.getId(), cidrlist); - } - - - public void loadSourceCidrs(LoadBalancerVO loadBalancerRule){ - List sourceCidrs = _portForwardingRulesCidrsDao.getSourceCidrs(loadBalancerRule.getId()); - loadBalancerRule.setSourceCidrList(sourceCidrs); - } - - - @Override @DB - public LoadBalancerVO persist(LoadBalancerVO loadBalancerRule) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - - LoadBalancerVO dbfirewallRule = super.persist(loadBalancerRule); - saveSourceCidrs(loadBalancerRule); - - txn.commit(); - return dbfirewallRule; - } - - - @Override @DB - public boolean update(Long loadBalancerRuleId, LoadBalancerVO loadBalancerRule) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - - boolean persisted = super.update(loadBalancerRuleId, loadBalancerRule); - if (!persisted) { - return persisted; - } - saveSourceCidrs(loadBalancerRule); - - txn.commit(); - return persisted; - } } diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index 0a16bf36cfb..11faafb97d0 100644 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -267,7 +267,7 @@ public class VirtualRouterElement extends DhcpElement implements NetworkElement, firewallCapabilities.put(Capability.PortForwarding, "true"); firewallCapabilities.put(Capability.TrafficStatistics, "per public ip"); firewallCapabilities.put(Capability.StaticNat, "true"); - firewallCapabilities.put(Capability.SupportedProtocols, "tcp,udp"); + firewallCapabilities.put(Capability.SupportedProtocols, "tcp,udp,icmp"); firewallCapabilities.put(Capability.MultipleIps, "true"); firewallCapabilities.put(Capability.SupportedSourceNatTypes, "per account"); diff --git a/server/src/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java new file mode 100644 index 00000000000..f02a29c73ca --- /dev/null +++ b/server/src/com/cloud/network/firewall/FirewallManagerImpl.java @@ -0,0 +1,499 @@ +package com.cloud.network.firewall; + +import java.util.ArrayList; +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.ListFirewallRulesCmd; +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.Capability; +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.FirewallManager; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.FirewallRule.Purpose; +import com.cloud.network.rules.FirewallRule.State; +import com.cloud.network.rules.FirewallRuleVO; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.UserContext; +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.NetUtils; + +@Local(value = { FirewallService.class, FirewallManager.class }) +public class FirewallManagerImpl implements FirewallService, FirewallManager, Manager{ + private static final Logger s_logger = Logger.getLogger(FirewallManagerImpl.class); + String _name; + + @Inject + FirewallRulesDao _firewallDao; + @Inject + IPAddressDao _ipAddressDao; + @Inject + EventDao _eventDao; + @Inject + DomainDao _domainDao; + @Inject + FirewallRulesCidrsDao _firewallCidrsDao; + @Inject + AccountManager _accountMgr; + @Inject + NetworkManager _networkMgr; + @Inject + UsageEventDao _usageEventDao; + + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return _name; + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + _name = name; + return true; + } + + @Override + public FirewallRule createFirewallRule(FirewallRule rule) throws NetworkRuleConflictException { + Account caller = UserContext.current().getCaller(); + + return createFirewallRule(rule.getSourceIpAddressId(), caller, rule.getXid(), rule.getSourcePortStart() ,rule.getSourcePortEnd(), rule.getProtocol(), rule.getSourceCidrList(), rule.getIcmpCode(), rule.getIcmpType()); + } + + @DB + @Override + @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_OPEN, eventDescription = "creating firewll rule", create = true) + public FirewallRule createFirewallRule(long ipAddrId, Account caller, String xId, Integer portStart,Integer portEnd, String protocol, List sourceCidrList, Integer icmpCode, Integer icmpType) throws NetworkRuleConflictException{ + 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"); + } + + validateFirewallRule(caller, ipAddress, portStart, portEnd, protocol); + + if (!protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (icmpCode != null || icmpType != null)) { + throw new InvalidParameterValueException("Can specify icmpCode and icmpType for ICMP protocol only"); + } + + Long networkId = ipAddress.getAssociatedWithNetworkId(); + Long accountId = ipAddress.getAccountId(); + Long domainId = ipAddress.getDomainId(); + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + FirewallRuleVO newRule = new FirewallRuleVO (xId, ipAddrId, portStart, portEnd, protocol.toLowerCase(), networkId, accountId, domainId, Purpose.Firewall, sourceCidrList, icmpCode, icmpType); + newRule = _firewallDao.persist(newRule); + + 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()); + + txn.commit(); + + return newRule; + } + + @Override + public List listFirewallRules(ListFirewallRulesCmd cmd) { + Account caller = UserContext.current().getCaller(); + Long ipId = cmd.getIpAddressId(); + Long id = cmd.getId(); + String path = null; + + Pair 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 firewall rules yet"); + } + _accountMgr.checkAccess(caller, ipAddressVO); + } + + if (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) { + Domain domain = _accountMgr.getDomain(caller.getDomainId()); + path = domain.getPath(); + } + + Filter filter = new Filter(FirewallRuleVO.class, "id", false, cmd.getStartIndex(), cmd.getPageSizeVal()); + SearchBuilder sb = _firewallDao.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 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 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.getActiveAccount(accountName, domainId); + sc.setParameters("accountId", account.getId()); + } + } + + sc.setParameters("purpose", Purpose.Firewall); + + if (path != null) { + sc.setJoinParameters("domainSearch", "path", path + "%"); + } + + return _firewallDao.search(sc, filter); + } + + @Override + public void detectRulesConflict(FirewallRule newRule, IpAddress ipAddress) throws NetworkRuleConflictException { + assert newRule.getSourceIpAddressId() == ipAddress.getId() : "You passed in an ip address that doesn't match the address in the new rule"; + + List rules = _firewallDao.listByIpAndPurposeAndNotRevoked(newRule.getSourceIpAddressId(), null); + 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."; + + + + for (FirewallRuleVO rule : rules) { + if (rule.getId() == newRule.getId()) { + continue; // Skips my own rule. + } + + if (rule.getPurpose() == Purpose.StaticNat && newRule.getPurpose() != Purpose.StaticNat) { + throw new NetworkRuleConflictException("There is 1 to 1 Nat rule specified for the ip address id=" + newRule.getSourceIpAddressId()); + } else if (rule.getPurpose() != Purpose.StaticNat && newRule.getPurpose() == Purpose.StaticNat) { + throw new NetworkRuleConflictException("There is already firewall rule specified for the ip address id=" + newRule.getSourceIpAddressId()); + } + + 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()); + } + + boolean allowFirewall = ((rule.getPurpose() == Purpose.Firewall || newRule.getPurpose() == Purpose.Firewall) && newRule.getPurpose() != rule.getPurpose()); + + boolean notNullPorts = (newRule.getSourcePortStart() != null && newRule.getSourcePortEnd() != null && rule.getSourcePortStart() != null && rule.getSourcePortEnd() != null); + if (!allowFirewall && notNullPorts && ((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()))) { + + // we allow port forwarding rules with the same parameters but different protocols + boolean allowPf = (rule.getPurpose() == Purpose.PortForwarding && newRule.getPurpose() == Purpose.PortForwarding && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())); + boolean allowStaticNat = (rule.getPurpose() == Purpose.StaticNat && newRule.getPurpose() == Purpose.StaticNat && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())); + + if (!(allowPf || allowStaticNat || allowFirewall)) { + throw new NetworkRuleConflictException("The range specified, " + newRule.getSourcePortStart() + "-" + newRule.getSourcePortEnd() + ", conflicts with rule " + rule.getId() + + " which has " + rule.getSourcePortStart() + "-" + rule.getSourcePortEnd()); + } + } + + if (newRule.getProtocol().equalsIgnoreCase(NetUtils.ICMP_PROTO) && newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())) { + if (newRule.getIcmpCode().longValue() == rule.getIcmpCode().longValue() || newRule.getIcmpType().longValue() == rule.getIcmpType().longValue() || newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())) { + throw new InvalidParameterValueException("New rule conflicts with existing rule id=" + rule.getId()); + } + + } + } + + + + if (s_logger.isDebugEnabled()) { + s_logger.debug("No network rule conflicts detected for " + newRule + " against " + (rules.size() - 1) + " existing rules"); + } + } + + + @Override + public void validateFirewallRule(Account caller, IPAddressVO ipAddress, Integer portStart, Integer portEnd, String proto) { + // Validate ip address + _accountMgr.checkAccess(caller, ipAddress); + + Long networkId = ipAddress.getAssociatedWithNetworkId(); + if (networkId == null) { + throw new InvalidParameterValueException("Unable to create port forwarding rule ; ip id=" + ipAddress.getId() + " is not associated with any network"); + + } + + Network network = _networkMgr.getNetwork(networkId); + assert network != null : "Can't create port forwarding rule as network associated with public ip address is null...how is it possible?"; + + if (portStart != null && !NetUtils.isValidPort(portStart)) { + throw new InvalidParameterValueException("publicPort is an invalid value: " + portStart); + } + if (portEnd != null && !NetUtils.isValidPort(portEnd)) { + throw new InvalidParameterValueException("Public port range is an invalid value: " + portEnd); + } + + // start port can't be bigger than end port + if (portStart != null && portEnd != null && portStart > portEnd) { + throw new InvalidParameterValueException("Start port can't be bigger than end port"); + } + + // Verify that the network guru supports the protocol specified + Map firewallCapabilities = _networkMgr.getServiceCapabilities(network.getDataCenterId(), network.getNetworkOfferingId(), Service.Firewall); + String supportedProtocols = firewallCapabilities.get(Capability.SupportedProtocols).toLowerCase(); + if (!supportedProtocols.contains(proto.toLowerCase())) { + throw new InvalidParameterValueException("Protocol " + proto + " is not supported in zone " + network.getDataCenterId()); + } + } + + @Override + public boolean applyRules(List rules, boolean continueOnError) throws ResourceUnavailableException { + if (!_networkMgr.applyRules(rules, continueOnError)) { + s_logger.warn("Rules are not completely applied"); + return false; + } else { + for (FirewallRule rule : rules) { + if (rule.getState() == FirewallRule.State.Revoke) { + _firewallDao.remove(rule.getId()); + } else if (rule.getState() == FirewallRule.State.Add) { + FirewallRuleVO ruleVO = _firewallDao.findById(rule.getId()); + ruleVO.setState(FirewallRule.State.Active); + _firewallDao.update(ruleVO.getId(), ruleVO); + } + } + return true; + } + } + + @Override + public boolean applyFirewallRules(long ipId, Account caller) throws ResourceUnavailableException { + List rules = _firewallDao.listByIpAndPurpose(ipId, Purpose.Firewall); + return applyFirewallRules(rules, false, caller); + } + + + @Override + public boolean applyFirewallRules(List rules, boolean continueOnError, Account caller) { + + if (rules.size() == 0) { + s_logger.debug("There are no firewall rules to apply for ip id=" + rules); + return true; + } + + for (FirewallRuleVO rule: rules){ + // load cidrs if any + rule.setSourceCidrList(_firewallCidrsDao.getSourceCidrs(rule.getId())); + } + + + if (caller != null) { + _accountMgr.checkAccess(caller, rules.toArray(new FirewallRuleVO[rules.size()])); + } + + try { + if (!applyRules(rules, continueOnError)) { + return false; + } + } catch (ResourceUnavailableException ex) { + s_logger.warn("Failed to apply firewall rules due to ", ex); + return false; + } + + return true; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_CLOSE, eventDescription = "revoking firewall rule", async = true) + public boolean revokeFirewallRule(long ruleId, boolean apply, Account caller, long userId) { + + FirewallRuleVO rule = _firewallDao.findById(ruleId); + if (rule == null || rule.getPurpose() != Purpose.Firewall) { + throw new InvalidParameterValueException("Unable to find " + ruleId + " having purpose " + Purpose.Firewall); + } + + _accountMgr.checkAccess(caller, rule); + + + revokeRule(rule, caller, userId, false); + + boolean success = false; + + if (apply) { + List rules = _firewallDao.listByIpAndPurpose(rule.getSourceIpAddressId(), Purpose.Firewall); + return applyFirewallRules(rules, false, caller); + } else { + success = true; + } + + return success; + + } + + @Override + public boolean revokeFirewallRule(long ruleId, boolean apply) { + Account caller = UserContext.current().getCaller(); + long userId = UserContext.current().getCallerUserId(); + return revokeFirewallRule(ruleId, apply, caller, userId); + } + + @Override + @DB + public void revokeRule(FirewallRuleVO rule, Account caller, long userId, boolean needUsageEvent) { + if (caller != null) { + _accountMgr.checkAccess(caller, rule); + } + + Transaction txn = Transaction.currentTxn(); + boolean generateUsageEvent = false; + + txn.start(); + 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()); + generateUsageEvent = true; + } else if (rule.getState() == State.Add || rule.getState() == State.Active) { + rule.setState(State.Revoke); + _firewallDao.update(rule.getId(), rule); + generateUsageEvent = true; + } + + if (generateUsageEvent && needUsageEvent) { + UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_RULE_DELETE, rule.getAccountId(), 0, rule.getId(), null); + _usageEventDao.persist(usageEvent); + } + + txn.commit(); + } + + + @Override + public FirewallRule getFirewallRule(long ruleId) { + return _firewallDao.findById(ruleId); + } + + @Override + public boolean revokeFirewallRulesForIp(long ipId, long userId, Account caller) throws ResourceUnavailableException { + List rules = new ArrayList(); + + List fwRules = _firewallDao.listByIpAndPurposeAndNotRevoked(ipId, Purpose.Firewall); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Releasing " + fwRules.size() + " firewall rules for ip id=" + ipId); + } + + for (FirewallRuleVO rule : fwRules) { + // Mark all Firewall rules as Revoke, but don't revoke them yet - we have to revoke all rules for ip, no need to send them one by one + revokeFirewallRule(rule.getId(), false, caller, Account.ACCOUNT_ID_SYSTEM); + } + + // now send everything to the backend + List rulesToApply = _firewallDao.listByIpAndPurpose(ipId, Purpose.Firewall); + applyFirewallRules(rulesToApply, true, caller); + + // Now we check again in case more rules have been inserted. + rules.addAll(_firewallDao.listByIpAndPurposeAndNotRevoked(ipId, Purpose.Firewall)); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Successfully released firewall rules for ip id=" + ipId + " and # of rules now = " + rules.size()); + } + + return rules.size() == 0; + } + + @Override + public FirewallRule createRuleForAllCidrs(long ipAddrId, Account caller, Integer startPort, Integer endPort, String protocol, Integer icmpCode, Integer icmpType) throws NetworkRuleConflictException{ + + //If firwallRule for this port range already exists, return it + List rules = _firewallDao.listByIpPurposeAndProtocolAndNotRevoked(ipAddrId, startPort, endPort, protocol, Purpose.Firewall); + if (!rules.isEmpty()) { + return rules.get(0); + } + + List oneCidr = new ArrayList(); + oneCidr.add(NetUtils.ALL_CIDRS); + return createFirewallRule(ipAddrId, caller, null, startPort, endPort, protocol, oneCidr, icmpCode, icmpType); + } + + @Override + public boolean revokeAllFirewallRulesForNetwork(long networkId, long userId, Account caller) throws ResourceUnavailableException { + List rules = new ArrayList(); + + List fwRules = _firewallDao.listByNetworkAndPurposeAndNotRevoked(networkId, Purpose.Firewall); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Releasing " + fwRules.size() + " firewall rules for network id=" + networkId); + } + + for (FirewallRuleVO rule : fwRules) { + // Mark all Firewall rules as Revoke, but don't revoke them yet - we have to revoke all rules for ip, no need to send them one by one + revokeFirewallRule(rule.getId(), false, caller, Account.ACCOUNT_ID_SYSTEM); + } + + // now send everything to the backend + List rulesToApply = _firewallDao.listByNetworkAndPurpose(networkId, Purpose.Firewall); + applyFirewallRules(rulesToApply, true, caller); + + // Now we check again in case more rules have been inserted. + rules.addAll(_firewallDao.listByNetworkAndPurposeAndNotRevoked(networkId, Purpose.Firewall)); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Successfully released firewall rules for network id=" + networkId + " and # of rules now = " + rules.size()); + } + + return rules.size() == 0; + } +} diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 17a8f1348e6..1382538d1f2 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -58,11 +58,11 @@ import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.LoadBalancerDao; import com.cloud.network.dao.LoadBalancerVMMapDao; import com.cloud.network.lb.LoadBalancingRule.LbDestination; +import com.cloud.network.rules.FirewallManager; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.LoadBalancer; -import com.cloud.network.rules.PortForwardingRuleVO; import com.cloud.network.rules.RulesManager; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -122,6 +122,8 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager, UsageEventDao _usageEventDao; @Inject FirewallRulesCidrsDao _firewallCidrsDao; + @Inject + FirewallManager _firewallMgr; @Override @DB @@ -346,7 +348,7 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager, @Override @DB @ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_CREATE, eventDescription = "creating load balancer") - public LoadBalancer createLoadBalancerRule(LoadBalancer lb) throws NetworkRuleConflictException { + public LoadBalancer createLoadBalancerRule(LoadBalancer lb, boolean openFirewall) throws NetworkRuleConflictException { UserContext caller = UserContext.current(); long ipId = lb.getSourceIpAddressId(); @@ -362,18 +364,8 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager, int defPortStart = lb.getDefaultPortStart(); int defPortEnd = lb.getDefaultPortEnd(); - if (!NetUtils.isValidPort(srcPortStart)) { - throw new InvalidParameterValueException("publicPort is an invalid value: " + srcPortStart); - } - if (!NetUtils.isValidPort(srcPortEnd)) { - throw new InvalidParameterValueException("Public port range is an invalid value: " + srcPortEnd); - } - if (srcPortStart > srcPortEnd) { - throw new InvalidParameterValueException("Public port range is an invalid value: " + srcPortStart + "-" + srcPortEnd); - } - if (!NetUtils.isValidPort(defPortStart)) { - throw new InvalidParameterValueException("privatePort is an invalid value: " + defPortStart); - } + _firewallMgr.validateFirewallRule(caller.getCaller(), ipAddr, srcPortStart, srcPortEnd, lb.getProtocol()); + if (!NetUtils.isValidPort(defPortEnd)) { throw new InvalidParameterValueException("privatePort is an invalid value: " + defPortEnd); } @@ -384,29 +376,27 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager, throw new InvalidParameterValueException("Invalid algorithm: " + lb.getAlgorithm()); } - Long networkId = ipAddr.getAssociatedWithNetworkId(); - if (networkId == null) { - throw new InvalidParameterValueException("Unable to create load balancer rule ; ip id=" + ipId + " is not associated with any network"); - - } - - _accountMgr.checkAccess(caller.getCaller(), ipAddr); - // verify that lb service is supported by the network - Network network = _networkMgr.getNetwork(networkId); + Network network = _networkMgr.getNetwork(ipAddr.getAssociatedWithNetworkId()); if (!_networkMgr.isServiceSupported(network.getNetworkOfferingId(), Service.Lb)) { - throw new InvalidParameterValueException("LB service is not supported in network id=" + networkId); + throw new InvalidParameterValueException("LB service is not supported in network id=" + network.getId()); } Transaction txn = Transaction.currentTxn(); txn.start(); - + + if (openFirewall) { + _firewallMgr.createRuleForAllCidrs(ipId, caller.getCaller(), lb.getSourcePortStart(), lb.getSourcePortEnd(), lb.getProtocol(), null, null); + } + LoadBalancerVO newRule = new LoadBalancerVO(lb.getXid(), lb.getName(), lb.getDescription(), lb.getSourceIpAddressId(), lb.getSourcePortEnd(), lb.getDefaultPortStart(), - lb.getSourceCidrList(), lb.getAlgorithm(), networkId, ipAddr.getAccountId(), ipAddr.getDomainId()); + lb.getSourceCidrList(), lb.getAlgorithm(), network.getId(), ipAddr.getAccountId(), ipAddr.getDomainId()); + newRule = _lbDao.persist(newRule); + boolean success = true; try { - _rulesMgr.detectRulesConflict(newRule, ipAddr); + _firewallMgr.detectRulesConflict(newRule, ipAddr); if (!_rulesDao.setStateToAdd(newRule)) { throw new CloudRuntimeException("Unable to update the state to add for " + newRule); } @@ -415,14 +405,26 @@ public class LoadBalancingRulesManagerImpl implements LoadBalancingRulesManager, UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_LOAD_BALANCER_CREATE, ipAddr.getAllocatedToAccountId(), ipAddr.getDataCenterId(), newRule.getId(), null); _usageEventDao.persist(usageEvent); txn.commit(); + + // send firewallRule to the backend + if (openFirewall) { + success = success && _firewallMgr.applyFirewallRules(lb.getSourceIpAddressId(), caller.getCaller()); + } + return newRule; } catch (Exception e) { - _lbDao.remove(newRule.getId()); + success = false; if (e instanceof NetworkRuleConflictException) { throw (NetworkRuleConflictException) e; } throw new CloudRuntimeException("Unable to add rule for ip address id=" + newRule.getSourceIpAddressId(), e); + } finally { + if (!success) { + _lbDao.remove(newRule.getId()); + } } + + } @Override diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 16485ef82cd..b67ec6eee02 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -50,10 +50,12 @@ import com.cloud.agent.api.routing.LoadBalancerConfigCommand; import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; import com.cloud.agent.api.routing.SavePasswordCommand; +import com.cloud.agent.api.routing.SetFirewallRulesCommand; import com.cloud.agent.api.routing.SetPortForwardingRulesCommand; import com.cloud.agent.api.routing.SetStaticNatRulesCommand; import com.cloud.agent.api.routing.VmDataCommand; import com.cloud.agent.api.routing.VpnUsersCfgCommand; +import com.cloud.agent.api.to.FirewallRuleTO; import com.cloud.agent.api.to.IpAddressTO; import com.cloud.agent.api.to.LoadBalancerTO; import com.cloud.agent.api.to.PortForwardingRuleTO; @@ -2086,7 +2088,9 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian result = result && applyPortForwardingRules(router, (List) rules); } else if (rules.get(0).getPurpose() == Purpose.StaticNat) { result = result && applyStaticNatRules(router, (List) rules); - } else { + } else if (rules.get(0).getPurpose() == Purpose.Firewall) { + result = result && applyFirewallRules(router, (List) rules); + }else { s_logger.warn("Unable to apply rules of purpose: " + rules.get(0).getPurpose()); result = false; } @@ -2131,4 +2135,32 @@ public class VirtualNetworkApplianceManagerImpl implements VirtualNetworkApplian } return vrs; } + + private void createFirewallRulesCommands(List rules, DomainRouterVO router, Commands cmds) { + List rulesTO = null; + if (rules != null) { + rulesTO = new ArrayList(); + for (FirewallRule rule : rules) { + IpAddress sourceIp = _networkMgr.getIp(rule.getSourceIpAddressId()); + FirewallRuleTO ruleTO = new FirewallRuleTO(rule, sourceIp.getAddress().addr()); + rulesTO.add(ruleTO); + } + } + + SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(rulesTO); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, router.getPrivateIpAddress()); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP, router.getGuestIpAddress()); + cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName()); + DataCenterVO dcVo = _dcDao.findById(router.getDataCenterIdToDeployIn()); + cmd.setAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE, dcVo.getNetworkType().toString()); + cmds.addCommand(cmd); + } + + + protected boolean applyFirewallRules(DomainRouterVO router, List rules) throws ResourceUnavailableException { + Commands cmds = new Commands(OnError.Continue); + createFirewallRulesCommands(rules, router, cmds); + // Send commands to router + return sendCommandsToRouter(router, cmds); + } } diff --git a/server/src/com/cloud/network/rules/FirewallManager.java b/server/src/com/cloud/network/rules/FirewallManager.java new file mode 100644 index 00000000000..c7faf66b6ac --- /dev/null +++ b/server/src/com/cloud/network/rules/FirewallManager.java @@ -0,0 +1,58 @@ +package com.cloud.network.rules; + +import java.util.List; + +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.IPAddressVO; +import com.cloud.network.IpAddress; +import com.cloud.network.firewall.FirewallService; +import com.cloud.user.Account; + +public interface FirewallManager extends FirewallService{ + /** + * detectRulesConflict finds conflicts in networking rules. It checks for + * conflicts between the following types of netowrking rules; + * 1. one to one nat ip forwarding + * 2. port forwarding + * 3. load balancing + * + * It is possible for two conflicting rules to be added at the same time + * and conflicts are detected between those two rules. In this case, it + * is possible for both rules to be rolled back when, technically, we should + * only roll back one of the rules. However, the chances of that is low + * and the user can simply re-add one of the rules themselves. + * + * @param newRule the new rule created. + * @param ipAddress ip address that back up the new rule. + * @throws NetworkRuleConflictException + */ + void detectRulesConflict(FirewallRule newRule, IpAddress ipAddress) throws NetworkRuleConflictException; + + void validateFirewallRule(Account caller, IPAddressVO ipAddress, Integer portStart, Integer portEnd, String proto); + + boolean applyRules(List rules, boolean continueOnError) throws ResourceUnavailableException; + + boolean applyFirewallRules(List rules, boolean continueOnError, Account caller); + + public void revokeRule(FirewallRuleVO rule, Account caller, long userId, boolean needUsageEvent); + + boolean revokeFirewallRulesForIp(long ipId, long userId, Account caller) throws ResourceUnavailableException; + + /** + * Revokes a firewall rule + * @param ruleId the id of the rule to revoke. + * @param caller TODO + * @param userId TODO + * @return + */ + boolean revokeFirewallRule(long ruleId, boolean apply, Account caller, long userId); + + FirewallRule createFirewallRule(long ipAddrId, Account caller, String xId, Integer portStart, Integer portEnd, String protocol, List sourceCidrList, Integer icmpCode, Integer icmpType) + throws NetworkRuleConflictException; + + FirewallRule createRuleForAllCidrs(long ipAddrId, Account caller, Integer startPort, Integer endPort, String protocol, Integer icmpCode, Integer icmpType) throws NetworkRuleConflictException; + + boolean revokeAllFirewallRulesForNetwork(long networkId, long userId, Account caller) throws ResourceUnavailableException; + +} diff --git a/server/src/com/cloud/network/rules/FirewallRuleVO.java b/server/src/com/cloud/network/rules/FirewallRuleVO.java index 7c2a9fb1027..cf73e52d75a 100644 --- a/server/src/com/cloud/network/rules/FirewallRuleVO.java +++ b/server/src/com/cloud/network/rules/FirewallRuleVO.java @@ -18,6 +18,7 @@ package com.cloud.network.rules; import java.util.Date; +import java.util.List; import java.util.UUID; import javax.persistence.Column; @@ -32,6 +33,7 @@ import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.Table; +import javax.persistence.Transient; import com.cloud.utils.db.GenericDao; import com.cloud.utils.net.NetUtils; @@ -60,10 +62,10 @@ public class FirewallRuleVO implements FirewallRule { long sourceIpAddressId; @Column(name="start_port", updatable=false) - int sourcePortStart; + Integer sourcePortStart; @Column(name="end_port", updatable=false) - int sourcePortEnd; + Integer sourcePortEnd; @Column(name="protocol", updatable=false) String protocol = NetUtils.TCP_PROTO; @@ -81,6 +83,28 @@ public class FirewallRuleVO implements FirewallRule { @Column(name="network_id") long networkId; + + @Column(name="icmp_code") + Integer icmpCode; + + @Column(name="icmp_type") + Integer icmpType; + + // This is a delayed load value. If the value is null, + // then this field has not been loaded yet. + // Call firewallrules dao to load it. + @Transient + List sourceCidrs; + + + public void setSourceCidrList(List sourceCidrs) { + this.sourceCidrs=sourceCidrs; + } + + @Override + public List getSourceCidrList() { + return sourceCidrs; + } @Override public long getAccountId() { @@ -108,12 +132,12 @@ public class FirewallRuleVO implements FirewallRule { } @Override - public int getSourcePortStart() { + public Integer getSourcePortStart() { return sourcePortStart; } @Override - public int getSourcePortEnd() { + public Integer getSourcePortEnd() { return sourcePortEnd; } @@ -148,7 +172,7 @@ public class FirewallRuleVO implements FirewallRule { protected FirewallRuleVO() { } - public FirewallRuleVO(String xId, long ipAddressId, int portStart, int portEnd, String protocol, long networkId, long accountId, long domainId, Purpose purpose) { + public FirewallRuleVO(String xId, long ipAddressId, Integer portStart, Integer portEnd, String protocol, long networkId, long accountId, long domainId, Purpose purpose, List sourceCidrs, Integer icmpCode, Integer icmpType) { this.xId = xId; if (xId == null) { this.xId = UUID.randomUUID().toString(); @@ -162,10 +186,13 @@ public class FirewallRuleVO implements FirewallRule { this.purpose = purpose; this.networkId = networkId; this.state = State.Staged; + this.icmpCode = icmpCode; + this.icmpType = icmpType; + this.sourceCidrs = sourceCidrs; } - public FirewallRuleVO(String xId, long ipAddressId, int port, String protocol, long networkId, long accountId, long domainId, Purpose purpose) { - this(xId, ipAddressId, port, port, protocol, networkId, accountId, domainId, purpose); + public FirewallRuleVO(String xId, long ipAddressId, int port, String protocol, long networkId, long accountId, long domainId, Purpose purpose, List sourceCidrs, Integer icmpCode, Integer icmpType) { + this(xId, ipAddressId, port, port, protocol, networkId, accountId, domainId, purpose, sourceCidrs, icmpCode, icmpType); } @Override @@ -173,4 +200,14 @@ public class FirewallRuleVO implements FirewallRule { return new StringBuilder("Rule[").append(id).append("-").append(purpose).append("-").append(state).append("]").toString(); } + @Override + public Integer getIcmpCode() { + return icmpCode; + } + + @Override + public Integer getIcmpType() { + return icmpType; + } + } diff --git a/server/src/com/cloud/network/rules/PortForwardingRuleVO.java b/server/src/com/cloud/network/rules/PortForwardingRuleVO.java index dbb4f339fe6..f38fcc04b80 100644 --- a/server/src/com/cloud/network/rules/PortForwardingRuleVO.java +++ b/server/src/com/cloud/network/rules/PortForwardingRuleVO.java @@ -27,7 +27,6 @@ import javax.persistence.EnumType; import javax.persistence.Enumerated; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; -import javax.persistence.Transient; import com.cloud.utils.net.Ip; @@ -48,35 +47,17 @@ public class PortForwardingRuleVO extends FirewallRuleVO implements PortForwardi private int destinationPortEnd; @Column(name="instance_id") - private long virtualMachineId; - - // This is a delayed load value. If the value is null, - // then this field has not been loaded yet. - // Call firewallrules dao to load it. - @Transient - List sourceCidrs; - - - public void setSourceCidrList(List sourceCidrs) { - this.sourceCidrs=sourceCidrs; - } - - @Override - public List getSourceCidrList() { - return sourceCidrs; - } - + private long virtualMachineId; public PortForwardingRuleVO() { } public PortForwardingRuleVO(String xId, long srcIpId, int srcPortStart, int srcPortEnd, Ip dstIp, int dstPortStart, int dstPortEnd, String protocol, List sourceCidrs, long networkId, long accountId, long domainId, long instanceId) { - super(xId, srcIpId, srcPortStart, srcPortEnd, protocol, networkId, accountId, domainId, Purpose.PortForwarding); + super(xId, srcIpId, srcPortStart, srcPortEnd, protocol, networkId, accountId, domainId, Purpose.PortForwarding, sourceCidrs, null, null); this.destinationIpAddress = dstIp; this.virtualMachineId = instanceId; this.destinationPortStart = dstPortStart; - this.destinationPortEnd = dstPortEnd; - this.sourceCidrs = sourceCidrs; + this.destinationPortEnd = dstPortEnd; } public PortForwardingRuleVO(String xId, long srcIpId, int srcPort, Ip dstIp, int dstPort, String protocol, List sourceCidrs, long networkId, long accountId, long domainId, long instanceId) { diff --git a/server/src/com/cloud/network/rules/RulesManager.java b/server/src/com/cloud/network/rules/RulesManager.java index eaba1bc1e0b..8872d2c1b95 100644 --- a/server/src/com/cloud/network/rules/RulesManager.java +++ b/server/src/com/cloud/network/rules/RulesManager.java @@ -39,29 +39,10 @@ public interface RulesManager extends RulesService { boolean applyStaticNatRulesForNetwork(long networkId, boolean continueOnError, Account caller); - /** - * detectRulesConflict finds conflicts in networking rules. It checks for - * conflicts between the following types of netowrking rules; - * 1. one to one nat ip forwarding - * 2. port forwarding - * 3. load balancing - * - * It is possible for two conflicting rules to be added at the same time - * and conflicts are detected between those two rules. In this case, it - * is possible for both rules to be rolled back when, technically, we should - * only roll back one of the rules. However, the chances of that is low - * and the user can simply re-add one of the rules themselves. - * - * @param newRule the new rule created. - * @param ipAddress ip address that back up the new rule. - * @throws NetworkRuleConflictException - */ - void detectRulesConflict(FirewallRule newRule, IpAddress ipAddress) throws NetworkRuleConflictException; - void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller); void checkRuleAndUserVm(FirewallRule rule, UserVm userVm, Account caller); - boolean revokeAllRulesForIp(long ipId, long userId, Account caller) throws ResourceUnavailableException; + boolean revokeAllPFAndStaticNatRulesForIp(long ipId, long userId, Account caller) throws ResourceUnavailableException; boolean revokeAllRulesForNetwork(long networkId, long userId, Account caller) throws ResourceUnavailableException; @@ -81,7 +62,7 @@ public interface RulesManager extends RulesService { boolean revokeStaticNatRulesForVm(long vmId); - FirewallRule[] reservePorts(IpAddress ip, String protocol, FirewallRule.Purpose purpose, int... ports) throws NetworkRuleConflictException; + FirewallRule[] reservePorts(IpAddress ip, String protocol, FirewallRule.Purpose purpose, boolean openFirewall, Account caller, int... ports) throws NetworkRuleConflictException; boolean releasePorts(long ipId, String protocol, FirewallRule.Purpose purpose, int... ports); List listByNetworkId(long networkId); diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 698894298fa..c11dd7d8380 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -43,14 +43,12 @@ 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.Capability; 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.FirewallRule.State; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -98,48 +96,10 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { UsageEventDao _usageEventDao; @Inject DomainDao _domainDao; + @Inject + FirewallManager _firewallMgr; - @Override - public void detectRulesConflict(FirewallRule newRule, IpAddress ipAddress) throws NetworkRuleConflictException { - assert newRule.getSourceIpAddressId() == ipAddress.getId() : "You passed in an ip address that doesn't match the address in the new rule"; - List rules = _firewallDao.listByIpAndPurposeAndNotRevoked(newRule.getSourceIpAddressId(), null); - 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."; - - for (FirewallRuleVO rule : rules) { - if (rule.getId() == newRule.getId()) { - continue; // Skips my own rule. - } - - if (rule.getPurpose() == Purpose.StaticNat && newRule.getPurpose() != Purpose.StaticNat) { - throw new NetworkRuleConflictException("There is 1 to 1 Nat rule specified for the ip address id=" + newRule.getSourceIpAddressId()); - } else if (rule.getPurpose() != Purpose.StaticNat && newRule.getPurpose() == Purpose.StaticNat) { - throw new NetworkRuleConflictException("There is already firewall rule specified for the ip address id=" + newRule.getSourceIpAddressId()); - } - - 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.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())) { - - // we allow port forwarding rules with the same parameters but different protocols - boolean allowPf = (rule.getPurpose() == Purpose.PortForwarding && newRule.getPurpose() == Purpose.PortForwarding && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())); - boolean allowStaticNat = (rule.getPurpose() == Purpose.StaticNat && newRule.getPurpose() == Purpose.StaticNat && !newRule.getProtocol().equalsIgnoreCase(rule.getProtocol())); - if (!(allowPf || allowStaticNat)) { - 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) { @@ -190,38 +150,29 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { @Override @DB @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_ADD, eventDescription = "creating forwarding rule", create = true) - public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId) throws NetworkRuleConflictException { + public PortForwardingRule createPortForwardingRule(PortForwardingRule rule, Long vmId, boolean openFirewall) throws NetworkRuleConflictException { UserContext ctx = UserContext.current(); Account caller = ctx.getCaller(); - Long networkId = null; - Long accountId = null; - Long domainId = null; 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"); - } else { - _accountMgr.checkAccess(caller, ipAddress); - - networkId = ipAddress.getAssociatedWithNetworkId(); - if (networkId == null) { - throw new InvalidParameterValueException("Unable to create port forwarding rule ; ip id=" + ipAddrId + " is not associated with any network"); - - } - // get account/domain info from the ip address (can't get it from the network as the network can be shared between - // accounts) - accountId = ipAddress.getAccountId(); - domainId = ipAddress.getDomainId(); - } - + } + + _firewallMgr.validateFirewallRule(caller, ipAddress, rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol()); + + 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() || rule.getSourcePortStart() > rule.getSourcePortEnd()) { + if (rule.getDestinationPortStart() > rule.getDestinationPortEnd()) { throw new InvalidParameterValueException("Start port can't be bigger than end port"); } @@ -229,17 +180,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { if ((rule.getDestinationPortEnd() - rule.getDestinationPortStart()) != (rule.getSourcePortEnd() - rule.getSourcePortStart())) { throw new InvalidParameterValueException("Source port and destination port ranges should be of equal sizes."); } - - Network network = _networkMgr.getNetwork(networkId); - assert network != null : "Can't create port forwarding rule as network associated with public ip address is null...how is it possible?"; - - // Verify that the network guru supports the protocol specified - Map firewallCapabilities = _networkMgr.getServiceCapabilities(network.getDataCenterId(), network.getNetworkOfferingId(), Service.Firewall); - String supportedProtocols = firewallCapabilities.get(Capability.SupportedProtocols).toLowerCase(); - if (!supportedProtocols.contains(rule.getProtocol().toLowerCase())) { - throw new InvalidParameterValueException("Protocol " + rule.getProtocol() + " is not supported in zone " + network.getDataCenterId()); - } - + // validate user VM exists UserVm vm = _vmDao.findById(vmId); if (vm == null) { @@ -260,12 +201,17 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { Transaction txn = Transaction.currentTxn(); txn.start(); + //create firewallRule for 0.0.0.0/0 cidr + if (openFirewall) { + _firewallMgr.createRuleForAllCidrs(ipAddrId, caller, rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), null, null); + } + PortForwardingRuleVO newRule = new PortForwardingRuleVO(rule.getXid(), rule.getSourceIpAddressId(), rule.getSourcePortStart(), rule.getSourcePortEnd(), dstIp, rule.getDestinationPortStart(), rule.getDestinationPortEnd(), rule.getProtocol().toLowerCase(), rule.getSourceCidrList(), networkId, accountId, domainId, vmId); newRule = _forwardingDao.persist(newRule); try { - detectRulesConflict(newRule, ipAddress); + _firewallMgr.detectRulesConflict(newRule, ipAddress); if (!_firewallDao.setStateToAdd(newRule)) { throw new CloudRuntimeException("Unable to update the state to add for " + newRule); } @@ -285,64 +231,45 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { @Override @DB @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_ADD, eventDescription = "creating static nat rule", create = true) - public StaticNatRule createStaticNatRule(StaticNatRule rule) throws NetworkRuleConflictException { + public StaticNatRule createStaticNatRule(StaticNatRule rule, boolean openFirewall) throws NetworkRuleConflictException { Account caller = UserContext.current().getCaller(); - Long networkId = null; - Long accountId = null; - Long domainId = null; Long ipAddrId = rule.getSourceIpAddressId(); IPAddressVO ipAddress = _ipAddressDao.findById(ipAddrId); - - // Verify ip address existst and if 1-1 nat is enabled for it + + // 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()); - } else { - _accountMgr.checkAccess(caller, ipAddress); - - networkId = ipAddress.getAssociatedWithNetworkId(); - if (networkId == null) { - throw new InvalidParameterValueException("Unable to create static nat rule ; ip id=" + ipAddrId + " is not associated with any network"); - - } - // get account/domain info from the ip address (can't get it from the network as the network can be shared between - // accounts) - accountId = ipAddress.getAccountId(); - domainId = ipAddress.getDomainId(); - } - - Network network = _networkMgr.getNetwork(networkId); - assert network != null : "Can't create static nat rule as network associated with public ip address is null...how is it possible?"; + } + + _firewallMgr.validateFirewallRule(caller, ipAddress, rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol()); + + Long networkId = ipAddress.getAssociatedWithNetworkId(); + Long accountId = ipAddress.getAccountId(); + Long domainId = ipAddress.getDomainId(); // Get nic IP4 address Nic guestNic = _networkMgr.getNicInNetwork(ipAddress.getAssociatedWithVmId(), networkId); assert (guestNic != null && guestNic.getIp4Address() != null) : "Vm doesn't belong to network associated with ipAddress or ip4 address is null...how is it possible?"; String dstIp = guestNic.getIp4Address(); - // Verify that the network guru supports the protocol specified - Map firewallCapability = _networkMgr.getServiceCapabilities(network.getDataCenterId(), network.getNetworkOfferingId(), Service.Firewall); - String supportedProtocols = firewallCapability.get(Capability.SupportedProtocols).toLowerCase(); - if (!supportedProtocols.contains(rule.getProtocol().toLowerCase())) { - throw new InvalidParameterValueException("Protocol " + rule.getProtocol() + " is not supported in zone " + network.getDataCenterId()); - } - - // start port can't be bigger than end port - if (rule.getSourcePortStart() > rule.getSourcePortEnd()) { - throw new InvalidParameterValueException("Start port can't be bigger than end port"); - } - Transaction txn = Transaction.currentTxn(); txn.start(); + //create firewallRule for 0.0.0.0/0 cidr + if (openFirewall) { + _firewallMgr.createRuleForAllCidrs(ipAddrId, caller, rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), null, null); + } + FirewallRuleVO newRule = new FirewallRuleVO(rule.getXid(), rule.getSourceIpAddressId(), rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol().toLowerCase(), - networkId, accountId, domainId, rule.getPurpose()); + networkId, accountId, domainId, rule.getPurpose(), null, null, null); newRule = _firewallDao.persist(newRule); try { - detectRulesConflict(newRule, ipAddress); + _firewallMgr.detectRulesConflict(newRule, ipAddress); if (!_firewallDao.setStateToAdd(newRule)) { throw new CloudRuntimeException("Unable to update the state to add for " + newRule); } @@ -424,68 +351,9 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { ipAddress.setOneToOneNat(true); ipAddress.setAssociatedWithVmId(vmId); - if ( _ipAddressDao.update(ipAddress.getId(), ipAddress)) - { - List staticNatRules = new ArrayList(); - - FirewallRuleVO ruleVO = new FirewallRuleVO(null, ipAddress.getId(), 0, 0, "icmp", - networkId,vm.getAccountId(), vm.getDomainId(), Purpose.StaticNat); - - staticNatRules.add(new StaticNatRuleImpl(ruleVO, guestNic.getIp4Address())); - - try { - if (!applyRules(staticNatRules, true)) { - return false; - } - - } catch (ResourceUnavailableException ex) { - s_logger.warn("Failed to apply icmp firewall rules due to ", ex); - return false; - } - return true; - - } - return false; + return _ipAddressDao.update(ipAddress.getId(), ipAddress); } - @DB - protected void revokeRule(FirewallRuleVO rule, Account caller, long userId) { - if (caller != null) { - _accountMgr.checkAccess(caller, rule); - } - - Transaction txn = Transaction.currentTxn(); - boolean generateUsageEvent = false; - - txn.start(); - 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()); - generateUsageEvent = true; - } else if (rule.getState() == State.Add || rule.getState() == State.Active) { - rule.setState(State.Revoke); - _firewallDao.update(rule.getId(), rule); - generateUsageEvent = true; - } - - if (generateUsageEvent) { - UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_NET_RULE_DELETE, rule.getAccountId(), 0, rule.getId(), null); - _usageEventDao.persist(usageEvent); - } - - // Save and create the event - String ruleName = rule.getPurpose() == Purpose.Firewall ? "Firewall" : (rule.getPurpose() == FirewallRule.Purpose.StaticNat ? "ip forwarding" : "port forwarding"); - StringBuilder description = new StringBuilder("deleted ").append(ruleName).append(" rule [ipAddressId=").append(rule.getSourceIpAddressId()).append(":").append(rule.getSourcePortStart()) - .append("-").append(rule.getSourcePortEnd()).append("]"); - if (rule.getPurpose() == Purpose.PortForwarding) { - PortForwardingRuleVO pfRule = (PortForwardingRuleVO) rule; - description.append("->[").append(pfRule.getDestinationIpAddress()).append(":").append(pfRule.getDestinationPortStart()).append("-").append(pfRule.getDestinationPortEnd()).append("]"); - } - description.append(" ").append(rule.getProtocol()); - txn.commit(); - } @Override @ActionEvent(eventType = EventTypes.EVENT_NET_RULE_DELETE, eventDescription = "revoking forwarding rule", async = true) @@ -506,7 +374,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { private boolean revokePortForwardingRuleInternal(long ruleId, Account caller, long userId, boolean apply) { PortForwardingRuleVO rule = _forwardingDao.findById(ruleId); - revokeRule(rule, caller, userId); + _firewallMgr.revokeRule(rule, caller, userId, true); boolean success = false; @@ -538,7 +406,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { private boolean revokeStaticNatRuleInternal(long ruleId, Account caller, long userId, boolean apply) { FirewallRuleVO rule = _firewallDao.findById(ruleId); - revokeRule(rule, caller, userId); + _firewallMgr.revokeRule(rule, caller, userId, true); boolean success = false; @@ -716,7 +584,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } try { - if (!applyRules(rules, continueOnError)) { + if (!_firewallMgr.applyRules(rules, continueOnError)) { return false; } } catch (ResourceUnavailableException ex) { @@ -764,7 +632,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } try { - if (!applyRules(staticNatRules, continueOnError)) { + if (!_firewallMgr.applyRules(staticNatRules, continueOnError)) { return false; } } catch (ResourceUnavailableException ex) { @@ -788,7 +656,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } try { - if (!applyRules(rules, continueOnError)) { + if (!_firewallMgr.applyRules(rules, continueOnError)) { return false; } } catch (ResourceUnavailableException ex) { @@ -818,7 +686,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } try { - if (!applyRules(staticNatRules, continueOnError)) { + if (!_firewallMgr.applyRules(staticNatRules, continueOnError)) { return false; } } catch (ResourceUnavailableException ex) { @@ -829,24 +697,6 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { return true; } - private boolean applyRules(List rules, boolean continueOnError) throws ResourceUnavailableException { - if (!_networkMgr.applyRules(rules, continueOnError)) { - s_logger.warn("Rules are not completely applied"); - return false; - } else { - for (FirewallRule rule : rules) { - if (rule.getState() == FirewallRule.State.Revoke) { - _firewallDao.remove(rule.getId()); - } else if (rule.getState() == FirewallRule.State.Add) { - FirewallRuleVO ruleVO = _firewallDao.findById(rule.getId()); - ruleVO.setState(FirewallRule.State.Active); - _firewallDao.update(ruleVO.getId(), ruleVO); - } - } - return true; - } - } - @Override public List searchStaticNatRules(Long ipId, Long id, Long vmId, Long start, Long size, String accountName, Long domainId) { Account caller = UserContext.current().getCaller(); @@ -934,7 +784,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } @Override - public boolean revokeAllRulesForIp(long ipId, long userId, Account caller) throws ResourceUnavailableException { + public boolean revokeAllPFAndStaticNatRulesForIp(long ipId, long userId, Account caller) throws ResourceUnavailableException { List rules = new ArrayList(); List pfRules = _forwardingDao.listByIpAndNotRevoked(ipId); @@ -1048,13 +898,18 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { @Override @DB - public FirewallRuleVO[] reservePorts(IpAddress ip, String protocol, FirewallRule.Purpose purpose, int... ports) throws NetworkRuleConflictException { + 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); + + if (openFirewall) { + _firewallMgr.createRuleForAllCidrs(ip.getId(), caller, ports[i], ports[i], protocol, null, null); + } + + rules[i] = new FirewallRuleVO(null, ip.getId(), ports[i], protocol, ip.getAssociatedWithNetworkId(), ip.getAllocatedToAccountId(), ip.getAllocatedInDomainId(), purpose, null, null, null); rules[i] = _firewallDao.persist(rules[i]); } txn.commit(); @@ -1062,7 +917,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { boolean success = false; try { for (FirewallRuleVO newRule : rules) { - detectRulesConflict(newRule, ip); + _firewallMgr.detectRulesConflict(newRule, ip); } success = true; return rules; @@ -1117,33 +972,10 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { throw new InvalidParameterValueException("One to one nat is not enabled for the ip id=" + ipId); } - if (!revokeAllRulesForIp(ipId, UserContext.current().getCallerUserId(), caller)) { + if (!revokeAllPFAndStaticNatRulesForIp(ipId, UserContext.current().getCallerUserId(), caller)) { s_logger.warn("Unable to revoke all static nat rules for ip " + ipAddress); success = false; } - if (success) - { - long vmId = ipAddress.getAssociatedWithVmId(); - Nic guestNic = _networkMgr.getNicInNetwork(vmId, ipAddress.getAssociatedWithNetworkId()); - if (guestNic == null) { - throw new InvalidParameterValueException("Vm doesn't belong to the network " + ipAddress.getAssociatedWithNetworkId()); - } - List staticNatRules = new ArrayList(); - FirewallRuleVO ruleVO = new FirewallRuleVO(null, ipAddress.getId(), 0, 0, "icmp", - ipAddress.getAssociatedWithNetworkId(),ipAddress.getAccountId(), ipAddress.getDomainId(), Purpose.StaticNat); - - ruleVO.setState(State.Revoke); - staticNatRules.add(new StaticNatRuleImpl(ruleVO, guestNic.getIp4Address())); - - try { - if (!applyRules(staticNatRules, true)) { - return false; - } - } catch (ResourceUnavailableException ex) { - s_logger.warn("Failed to apply icmp firewall rules due to ", ex); - return false; - } - } if (success) { ipAddress.setOneToOneNat(false); ipAddress.setAssociatedWithVmId(null); @@ -1178,5 +1010,5 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { return new StaticNatRuleImpl(ruleVO, guestNic.getIp4Address()); } - + } diff --git a/server/src/com/cloud/network/rules/StaticNatRuleImpl.java b/server/src/com/cloud/network/rules/StaticNatRuleImpl.java index ebc3366ce51..4c480666d4e 100644 --- a/server/src/com/cloud/network/rules/StaticNatRuleImpl.java +++ b/server/src/com/cloud/network/rules/StaticNatRuleImpl.java @@ -18,6 +18,8 @@ package com.cloud.network.rules; +import java.util.List; + public class StaticNatRuleImpl implements StaticNatRule{ long id; @@ -52,7 +54,7 @@ public class StaticNatRuleImpl implements StaticNatRule{ } @Override - public int getSourcePortEnd() { + public Integer getSourcePortEnd() { return portEnd; } @@ -87,7 +89,7 @@ public class StaticNatRuleImpl implements StaticNatRule{ } @Override - public int getSourcePortStart() { + public Integer getSourcePortStart() { return portStart; } @@ -105,4 +107,19 @@ public class StaticNatRuleImpl implements StaticNatRule{ public String getXid() { return xid; } + + @Override + public Integer getIcmpCode() { + return null; + } + + @Override + public Integer getIcmpType() { + return null; + } + + @Override + public List getSourceCidrList() { + return null; + } } diff --git a/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java b/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java index 1846aaa3010..07952f9d5ac 100644 --- a/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java +++ b/server/src/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java @@ -24,17 +24,13 @@ import javax.ejb.Local; import org.apache.log4j.Logger; import com.cloud.network.dao.FirewallRulesCidrsDaoImpl; -import com.cloud.network.dao.FirewallRulesDaoImpl; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.State; -import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.PortForwardingRuleVO; import com.cloud.utils.component.ComponentLocator; -import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.Transaction; import com.cloud.utils.db.SearchCriteria.Op; @Local(value=PortForwardingRulesDao.class) @@ -153,50 +149,5 @@ public class PortForwardingRulesDaoImpl extends GenericDaoBase cidrlist = portForwardingRule.getSourceCidrList(); - if (cidrlist == null) { - return; - } - _portForwardingRulesCidrsDao.persist(portForwardingRule.getId(), cidrlist); - } - - - public void loadSourceCidrs(PortForwardingRuleVO portForwardingRule){ - List sourceCidrs = _portForwardingRulesCidrsDao.getSourceCidrs(portForwardingRule.getId()); - portForwardingRule.setSourceCidrList(sourceCidrs); - } - - - - @Override @DB - public PortForwardingRuleVO persist(PortForwardingRuleVO portForwardingRule) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - - PortForwardingRuleVO dbfirewallRule = super.persist(portForwardingRule); - saveSourceCidrs(portForwardingRule); - - txn.commit(); - return dbfirewallRule; - } - - - @Override @DB - public boolean update(Long portForwardingRuleId, PortForwardingRuleVO portForwardingRule) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - - boolean persisted = super.update(portForwardingRuleId, portForwardingRule); - if (!persisted) { - return persisted; - } - saveSourceCidrs(portForwardingRule); - - txn.commit(); - return persisted; - } - + } diff --git a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java index c0c5add1ca3..f4c3bd5332b 100755 --- a/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java +++ b/server/src/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java @@ -50,6 +50,7 @@ import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.RemoteAccessVpnDao; import com.cloud.network.dao.VpnUserDao; import com.cloud.network.router.VirtualNetworkApplianceManager; +import com.cloud.network.rules.FirewallManager; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.RulesManager; @@ -87,6 +88,7 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag @Inject RulesManager _rulesMgr; @Inject DomainDao _domainDao; @Inject FirewallRulesDao _rulesDao; + @Inject FirewallManager _firewallMgr; int _userLimit; int _pskLength; @@ -94,7 +96,7 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag SearchBuilder VpnSearch; @Override - public RemoteAccessVpn createRemoteAccessVpn(long publicIpId, String ipRange) throws NetworkRuleConflictException { + public RemoteAccessVpn createRemoteAccessVpn(long publicIpId, String ipRange, boolean openFirewall) throws NetworkRuleConflictException { UserContext ctx = UserContext.current(); Account caller = ctx.getCaller(); @@ -165,7 +167,7 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag long startIp = NetUtils.ip2Long(range[0]); String newIpRange = NetUtils.long2Ip(++startIp) + "-" + range[1]; String sharedSecret = PasswordGenerator.generatePresharedKey(_pskLength); - _rulesMgr.reservePorts(ipAddr, NetUtils.UDP_PROTO, Purpose.Vpn, NetUtils.VPN_PORT, NetUtils.VPN_L2TP_PORT, NetUtils.VPN_NATT_PORT); + _rulesMgr.reservePorts(ipAddr, NetUtils.UDP_PROTO, Purpose.Vpn, openFirewall, caller, NetUtils.VPN_PORT, NetUtils.VPN_L2TP_PORT, NetUtils.VPN_NATT_PORT); vpnVO = new RemoteAccessVpnVO(ipAddr.getAllocatedToAccountId(), ipAddr.getAllocatedInDomainId(), ipAddr.getAssociatedWithNetworkId(), publicIpId, range[0], newIpRange, sharedSecret); return _remoteAccessVpnDao.persist(vpnVO); @@ -302,7 +304,7 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag } @Override - public RemoteAccessVpnVO startRemoteAccessVpn(long vpnId) throws ResourceUnavailableException { + public RemoteAccessVpnVO startRemoteAccessVpn(long vpnId, boolean openFirewall) throws ResourceUnavailableException { Account caller = UserContext.current().getCaller(); RemoteAccessVpnVO vpn = _remoteAccessVpnDao.findById(vpnId); @@ -311,18 +313,28 @@ public class RemoteAccessVpnManagerImpl implements RemoteAccessVpnService, Manag } _accountMgr.checkAccess(caller, vpn); + + Network network = _networkMgr.getNetwork(vpn.getNetworkId()); List elements = _networkMgr.getRemoteAccessVpnElements(); boolean started = false; try { - for (RemoteAccessVpnElement element : elements) { - if (element.startVpn(network, vpn)) { - started = true; - break; + boolean firewallOpened = true; + if (openFirewall) { + firewallOpened = _firewallMgr.applyFirewallRules(vpn.getServerAddressId(), caller); + } + + if (firewallOpened) { + for (RemoteAccessVpnElement element : elements) { + if (element.startVpn(network, vpn)) { + started = true; + break; + } } } + return vpn; } finally { if (started) { diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java index 2c102b46ea8..d2c022f1abe 100644 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java @@ -333,7 +333,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V String publicCidr = NetUtils.ipAndNetMaskToCidr(secStorageVm.getPublicIpAddress(), secStorageVm.getPublicNetmask()); if (NetUtils.isNetworkAWithinNetworkB(privateCidr, publicCidr) || NetUtils.isNetworkAWithinNetworkB(publicCidr, privateCidr)) { s_logger.info("private and public interface overlaps, add a default route through private interface. privateCidr: " + privateCidr + ", publicCidr: " + publicCidr); - allowedCidrs.add("0.0.0.0/0"); + allowedCidrs.add(NetUtils.ALL_CIDRS); } setupCmd.setAllowedInternalSites(allowedCidrs.toArray(new String[allowedCidrs.size()])); } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 0f1404759ca..90195382a4f 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -578,8 +578,8 @@ CREATE TABLE `cloud`.`op_dc_vnet_alloc` ( CREATE TABLE `cloud`.`firewall_rules` ( `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', `ip_address_id` bigint unsigned NOT NULL COMMENT 'id of the corresponding ip address', - `start_port` int(10) NOT NULL COMMENT 'starting port of a port range', - `end_port` int(10) NOT NULL COMMENT 'end port of a port range', + `start_port` int(10) COMMENT 'starting port of a port range', + `end_port` int(10) COMMENT 'end port of a port range', `state` char(32) NOT NULL COMMENT 'current state of this rule', `protocol` char(16) NOT NULL default 'TCP' COMMENT 'protocol to open these ports for', `purpose` char(32) NOT NULL COMMENT 'why are these ports opened?', @@ -588,6 +588,8 @@ CREATE TABLE `cloud`.`firewall_rules` ( `network_id` bigint unsigned NOT NULL COMMENT 'network id', `xid` char(40) NOT NULL COMMENT 'external id', `created` datetime COMMENT 'Date created', + `icmp_code` int(10) COMMENT 'The ICMP code (if protocol=ICMP). A value of -1 means all codes for the given ICMP type.', + `icmp_type` int(10) COMMENT 'The ICMP type (if protocol=ICMP). A value of -1 means all types.', PRIMARY KEY (`id`), CONSTRAINT `fk_firewall_rules__ip_address_id` FOREIGN KEY(`ip_address_id`) REFERENCES `user_ip_address`(`id`), CONSTRAINT `fk_firewall_rules__network_id` FOREIGN KEY(`network_id`) REFERENCES `networks`(`id`) ON DELETE CASCADE, diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index 55a145c2879..ed0f8e39fa4 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -54,6 +54,8 @@ public class NetUtils { public final static String ANY_PROTO = "any"; public final static String ICMP_PROTO = "icmp"; public final static String ALL_PROTO = "all"; + + public final static String ALL_CIDRS = "0.0.0.0/0"; private final static Random _rand = new Random(System.currentTimeMillis());