This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch 4.19
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.19 by this push:
new 4189bac8e0d enable to create VPC portfowarding rules with source cidr
(#7081)
4189bac8e0d is described below
commit 4189bac8e0d755a65c10ab07868686bba0128bac
Author: Rodrigo D. Lopez <[email protected]>
AuthorDate: Thu Nov 28 13:53:07 2024 -0300
enable to create VPC portfowarding rules with source cidr (#7081)
Co-authored-by: Lopez <[email protected]>
Co-authored-by: Fabricio Duarte <[email protected]>
---
.../cloud/agent/api/to/PortForwardingRuleTO.java | 13 +++
.../java/com/cloud/network/rules/RulesService.java | 5 +-
.../org/apache/cloudstack/api/ApiConstants.java | 1 +
.../user/firewall/CreatePortForwardingRuleCmd.java | 22 ++---
.../user/firewall/UpdatePortForwardingRuleCmd.java | 15 +++-
.../loadbalancer/CreateLoadBalancerRuleCmd.java | 2 +-
.../facade/SetPortForwardingRulesConfigItem.java | 2 +-
.../virtualnetwork/model/ForwardingRule.java | 9 +-
.../cloud/network/dao/FirewallRulesCidrsDao.java | 2 +
.../network/dao/FirewallRulesCidrsDaoImpl.java | 19 ++++
.../cloud/network/dao/FirewallRulesDaoImpl.java | 3 -
.../cloud/network/rules/PortForwardingRuleVO.java | 23 +++--
.../rules/dao/PortForwardingRulesDaoImpl.java | 45 +++++++++-
...ernetesClusterResourceModifierActionWorker.java | 2 +-
.../network/firewall/FirewallManagerImpl.java | 75 ++++++++++++----
.../cloud/network/router/CommandSetupHelper.java | 2 +
.../com/cloud/network/rules/RulesManagerImpl.java | 52 +++++++++--
.../network/firewall/FirewallManagerTest.java | 100 ++++++++++++++++++++-
systemvm/debian/opt/cloud/bin/configure.py | 10 ++-
systemvm/debian/opt/cloud/bin/cs/CsNetfilter.py | 2 +-
.../debian/opt/cloud/bin/cs_forwardingrules.py | 22 ++++-
ui/public/locales/en.json | 1 +
ui/public/locales/pt_BR.json | 3 +-
ui/src/views/network/LoadBalancing.vue | 6 +-
ui/src/views/network/PortForwarding.vue | 27 +++++-
25 files changed, 396 insertions(+), 67 deletions(-)
diff --git a/api/src/main/java/com/cloud/agent/api/to/PortForwardingRuleTO.java
b/api/src/main/java/com/cloud/agent/api/to/PortForwardingRuleTO.java
index 76d6d952814..d43625c09a9 100644
--- a/api/src/main/java/com/cloud/agent/api/to/PortForwardingRuleTO.java
+++ b/api/src/main/java/com/cloud/agent/api/to/PortForwardingRuleTO.java
@@ -19,6 +19,9 @@ package com.cloud.agent.api.to;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.PortForwardingRule;
import com.cloud.utils.net.NetUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
/**
* PortForwardingRuleTO specifies one port forwarding rule.
@@ -29,6 +32,8 @@ public class PortForwardingRuleTO extends FirewallRuleTO {
String dstIp;
int[] dstPortRange;
+ List<String> sourceCidrList;
+
protected PortForwardingRuleTO() {
super();
}
@@ -37,6 +42,7 @@ public class PortForwardingRuleTO extends FirewallRuleTO {
super(rule, srcVlanTag, srcIp);
this.dstIp = rule.getDestinationIpAddress().addr();
this.dstPortRange = new int[] {rule.getDestinationPortStart(),
rule.getDestinationPortEnd()};
+ this.sourceCidrList = rule.getSourceCidrList();
}
public PortForwardingRuleTO(long id, String srcIp, int srcPortStart, int
srcPortEnd, String dstIp, int dstPortStart, int dstPortEnd, String protocol,
@@ -58,4 +64,11 @@ public class PortForwardingRuleTO extends FirewallRuleTO {
return NetUtils.portRangeToString(dstPortRange);
}
+ public String getSourceCidrListAsString() {
+ if (sourceCidrList != null) {
+ return StringUtils.join(sourceCidrList, ",");
+ }
+ return null;
+ }
+
}
diff --git a/api/src/main/java/com/cloud/network/rules/RulesService.java
b/api/src/main/java/com/cloud/network/rules/RulesService.java
index 0b4afeef945..547d4ab51e0 100644
--- a/api/src/main/java/com/cloud/network/rules/RulesService.java
+++ b/api/src/main/java/com/cloud/network/rules/RulesService.java
@@ -26,6 +26,7 @@ import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
import com.cloud.utils.net.Ip;
+import
org.apache.cloudstack.api.command.user.firewall.UpdatePortForwardingRuleCmd;
public interface RulesService {
Pair<List<? extends FirewallRule>, Integer> searchStaticNatRules(Long
ipId, Long id, Long vmId, Long start, Long size, String accountName, Long
domainId,
@@ -81,6 +82,8 @@ public interface RulesService {
boolean disableStaticNat(long ipId) throws ResourceUnavailableException,
NetworkRuleConflictException, InsufficientAddressCapacityException;
- PortForwardingRule updatePortForwardingRule(long id, Integer privatePort,
Integer privateEndPort, Long virtualMachineId, Ip vmGuestIp, String customId,
Boolean forDisplay);
+ PortForwardingRule updatePortForwardingRule(UpdatePortForwardingRuleCmd
cmd);
+
+ void validatePortForwardingSourceCidrList(List<String> sourceCidrList);
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
index b9a4938b5b2..b2042c116a7 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
@@ -427,6 +427,7 @@ public class ApiConstants {
public static final String SNAPSHOT_TYPE = "snapshottype";
public static final String SNAPSHOT_QUIESCEVM = "quiescevm";
public static final String SUPPORTS_STORAGE_SNAPSHOT =
"supportsstoragesnapshot";
+ public static final String SOURCE_CIDR_LIST = "sourcecidrlist";
public static final String SOURCE_ZONE_ID = "sourcezoneid";
public static final String START_DATE = "startdate";
public static final String START_ID = "startid";
diff --git
a/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java
b/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java
index 5e136210150..05d627fe577 100644
---
a/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java
+++
b/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/CreatePortForwardingRuleCmd.java
@@ -107,8 +107,12 @@ public class CreatePortForwardingRuleCmd extends
BaseAsyncCreateCmd implements P
description = "the ID of the virtual machine for the port
forwarding rule")
private Long virtualMachineId;
- @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST,
collectionType = CommandType.STRING, description = "the cidr list to forward
traffic from. Multiple entries must be separated by a single comma character
(,). This parameter is deprecated. Do not use.")
- private List<String> cidrlist;
+ @Parameter(name = ApiConstants.CIDR_LIST,
+ type = CommandType.LIST,
+ collectionType = CommandType.STRING,
+ description = " the source CIDR list to allow traffic from; all
other CIDRs will be blocked. " +
+ "Multiple entries must be separated by a single comma
character (,). This param will be used only for VPC tiers. By default, all
CIDRs are allowed.")
+ private List<String> sourceCidrList;
@Parameter(name = ApiConstants.OPEN_FIREWALL, type = CommandType.BOOLEAN,
description = "if true, firewall rule for source/end public port is
automatically created; "
+ "if false - firewall rule has to be created explicitly. If not
specified 1) defaulted to false when PF"
@@ -157,11 +161,7 @@ public class CreatePortForwardingRuleCmd extends
BaseAsyncCreateCmd implements P
@Override
public List<String> getSourceCidrList() {
- if (cidrlist != null) {
- throw new InvalidParameterValueException("Parameter cidrList is
deprecated; if you need to open firewall "
- + "rule for the specific cidr, please refer to
createFirewallRule command");
- }
- return null;
+ return sourceCidrList;
}
public Boolean getOpenFirewall() {
@@ -334,12 +334,6 @@ public class CreatePortForwardingRuleCmd extends
BaseAsyncCreateCmd implements P
@Override
public void create() {
- // cidr list parameter is deprecated
- if (cidrlist != null) {
- throw new InvalidParameterValueException(
- "Parameter cidrList is deprecated; if you need to open
firewall rule for the specific cidr, please refer to createFirewallRule
command");
- }
-
Ip privateIp = getVmSecondaryIp();
if (privateIp != null) {
if (!NetUtils.isValidIp4(privateIp.toString())) {
@@ -347,6 +341,8 @@ public class CreatePortForwardingRuleCmd extends
BaseAsyncCreateCmd implements P
}
}
+ _rulesService.validatePortForwardingSourceCidrList(sourceCidrList);
+
try {
PortForwardingRule result =
_rulesService.createPortForwardingRule(this, virtualMachineId, privateIp,
getOpenFirewall(), isDisplay());
setEntityId(result.getId());
diff --git
a/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/UpdatePortForwardingRuleCmd.java
b/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/UpdatePortForwardingRuleCmd.java
index 2afc0bb66ad..da02aa4b174 100644
---
a/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/UpdatePortForwardingRuleCmd.java
+++
b/api/src/main/java/org/apache/cloudstack/api/command/user/firewall/UpdatePortForwardingRuleCmd.java
@@ -33,6 +33,8 @@ import com.cloud.network.rules.PortForwardingRule;
import com.cloud.user.Account;
import com.cloud.utils.net.Ip;
+import java.util.List;
+
@APICommand(name = "updatePortForwardingRule",
responseObject = FirewallRuleResponse.class,
description = "Updates a port forwarding rule. Only the private port
and the virtual machine can be updated.", entityType =
{PortForwardingRule.class},
@@ -65,6 +67,13 @@ public class UpdatePortForwardingRuleCmd extends
BaseAsyncCustomIdCmd {
@Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN,
description = "an optional field, whether to the display the rule to the end
user or not", since = "4.4", authorized = {RoleType.Admin})
private Boolean display;
+ @Parameter(name = ApiConstants.CIDR_LIST,
+ type = CommandType.LIST,
+ collectionType = CommandType.STRING,
+ description = " the source CIDR list to allow traffic from; all
other CIDRs will be blocked. " +
+ "Multiple entries must be separated by a single comma
character (,). This param will be used only for VPC tiers. By default, all
CIDRs are allowed.")
+ private List<String> sourceCidrList;
+
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@@ -96,6 +105,10 @@ public class UpdatePortForwardingRuleCmd extends
BaseAsyncCustomIdCmd {
return display;
}
+ public List<String> getSourceCidrList() {
+ return sourceCidrList;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@@ -132,7 +145,7 @@ public class UpdatePortForwardingRuleCmd extends
BaseAsyncCustomIdCmd {
@Override
public void execute() {
- PortForwardingRule rule =
_rulesService.updatePortForwardingRule(getId(), getPrivatePort(),
getPrivateEndPort(), getVirtualMachineId(), getVmGuestIp(), getCustomId(),
getDisplay());
+ PortForwardingRule rule = _rulesService.updatePortForwardingRule(this);
FirewallRuleResponse fwResponse = new FirewallRuleResponse();
if (rule != null) {
fwResponse =
_responseGenerator.createPortForwardingRuleResponse(rule);
diff --git
a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java
b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java
index ef9e46f3a76..b741310cb16 100644
---
a/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java
+++
b/api/src/main/java/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java
@@ -106,7 +106,7 @@ public class CreateLoadBalancerRuleCmd extends
BaseAsyncCreateCmd /*implements L
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID,
entityType = DomainResponse.class, description = "the domain ID associated with
the load balancer")
private Long domainId;
- @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST,
collectionType = CommandType.STRING, since = "4.18.0.0", description = "the
CIDR list to allow traffic, "
+ @Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST,
collectionType = CommandType.STRING, since = "4.18.0.0", description = "the
source CIDR list to allow traffic from; "
+ "all other CIDRs will be blocked. Multiple entries must be
separated by a single comma character (,). By default, all CIDRs are allowed.")
private List<String> cidrlist;
diff --git
a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetPortForwardingRulesConfigItem.java
b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetPortForwardingRulesConfigItem.java
index c9d0e74e2e4..4daef64ed8a 100644
---
a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetPortForwardingRulesConfigItem.java
+++
b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetPortForwardingRulesConfigItem.java
@@ -41,7 +41,7 @@ public class SetPortForwardingRulesConfigItem extends
AbstractConfigItemFacade {
for (final PortForwardingRuleTO rule : command.getRules()) {
final ForwardingRule fwdRule = new ForwardingRule(rule.revoked(),
rule.getProtocol().toLowerCase(), rule.getSrcIp(),
rule.getStringSrcPortRange(), rule.getDstIp(),
- rule.getStringDstPortRange());
+ rule.getStringDstPortRange(),
rule.getSourceCidrListAsString());
rules.add(fwdRule);
}
diff --git
a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/ForwardingRule.java
b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/ForwardingRule.java
index cf3e43d1c01..1dc1cc855c4 100644
---
a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/ForwardingRule.java
+++
b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/ForwardingRule.java
@@ -26,18 +26,21 @@ public class ForwardingRule {
private String sourcePortRange;
private String destinationIpAddress;
private String destinationPortRange;
+ private String sourceCidrList;
public ForwardingRule() {
// Empty constructor for (de)serialization
}
- public ForwardingRule(boolean revoke, String protocol, String
sourceIpAddress, String sourcePortRange, String destinationIpAddress, String
destinationPortRange) {
+ public ForwardingRule(boolean revoke, String protocol, String
sourceIpAddress, String sourcePortRange, String destinationIpAddress, String
destinationPortRange,
+ String sourceCidrList) {
this.revoke = revoke;
this.protocol = protocol;
this.sourceIpAddress = sourceIpAddress;
this.sourcePortRange = sourcePortRange;
this.destinationIpAddress = destinationIpAddress;
this.destinationPortRange = destinationPortRange;
+ this.sourceCidrList = sourceCidrList;
}
public boolean isRevoke() {
@@ -88,4 +91,8 @@ public class ForwardingRule {
this.destinationPortRange = destinationPortRange;
}
+ public String getSourceCidrList() {
+ return sourceCidrList;
+ }
+
}
diff --git
a/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesCidrsDao.java
b/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesCidrsDao.java
index 55c454860ef..df5b6b5d647 100644
---
a/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesCidrsDao.java
+++
b/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesCidrsDao.java
@@ -29,4 +29,6 @@ public interface FirewallRulesCidrsDao extends
GenericDao<FirewallRulesCidrsVO,
@DB
List<FirewallRulesCidrsVO> listByFirewallRuleId(long firewallRuleId);
+
+ void updateSourceCidrsForRule(Long firewallRuleId, List<String>
sourceCidrList);
}
diff --git
a/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java
b/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java
index f6185309972..4630925ddee 100644
---
a/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java
+++
b/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesCidrsDaoImpl.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@@ -65,9 +66,27 @@ public class FirewallRulesCidrsDaoImpl extends
GenericDaoBase<FirewallRulesCidrs
return results;
}
+ @Override
+ public void updateSourceCidrsForRule(Long firewallRuleId, List<String>
sourceCidrList) {
+ TransactionLegacy txn = TransactionLegacy.currentTxn();
+ txn.start();
+
+ SearchCriteria<FirewallRulesCidrsVO> sc = CidrsSearch.create();
+ sc.setParameters("firewallRuleId", firewallRuleId);
+ remove(sc);
+
+ persist(firewallRuleId, sourceCidrList);
+
+ txn.commit();
+ }
+
@Override
@DB
public void persist(long firewallRuleId, List<String> sourceCidrs) {
+ if (CollectionUtils.isEmpty(sourceCidrs)) {
+ return;
+ }
+
TransactionLegacy txn = TransactionLegacy.currentTxn();
txn.start();
diff --git
a/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesDaoImpl.java
b/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesDaoImpl.java
index 3ac860b08c5..f18fb98f3de 100644
---
a/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesDaoImpl.java
+++
b/engine/schema/src/main/java/com/cloud/network/dao/FirewallRulesDaoImpl.java
@@ -243,9 +243,6 @@ public class FirewallRulesDaoImpl extends
GenericDaoBase<FirewallRuleVO, Long> i
}
public void saveSourceCidrs(FirewallRuleVO firewallRule, List<String>
cidrList) {
- if (cidrList == null) {
- return;
- }
_firewallRulesCidrsDao.persist(firewallRule.getId(), cidrList);
}
diff --git
a/engine/schema/src/main/java/com/cloud/network/rules/PortForwardingRuleVO.java
b/engine/schema/src/main/java/com/cloud/network/rules/PortForwardingRuleVO.java
index e1a698881f3..28d12fb24b4 100644
---
a/engine/schema/src/main/java/com/cloud/network/rules/PortForwardingRuleVO.java
+++
b/engine/schema/src/main/java/com/cloud/network/rules/PortForwardingRuleVO.java
@@ -25,6 +25,7 @@ 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;
@@ -47,21 +48,20 @@ public class PortForwardingRuleVO extends FirewallRuleVO
implements PortForwardi
@Column(name = "instance_id")
private long virtualMachineId;
+ @Transient
+ List<String> sourceCidrs;
+
public PortForwardingRuleVO() {
}
public PortForwardingRuleVO(String xId, long srcIpId, int srcPortStart,
int srcPortEnd, Ip dstIp, int dstPortStart, int dstPortEnd, String protocol,
long networkId,
- long accountId, long domainId, long instanceId) {
- super(xId, srcIpId, srcPortStart, srcPortEnd, protocol, networkId,
accountId, domainId, Purpose.PortForwarding, null, null, null, null, null);
+ long accountId, long domainId, long
instanceId, List<String> sourceCidrs) {
+ super(xId, srcIpId, srcPortStart, srcPortEnd, protocol, networkId,
accountId, domainId, Purpose.PortForwarding, sourceCidrs, null, null, null,
null);
this.destinationIpAddress = dstIp;
this.virtualMachineId = instanceId;
this.destinationPortStart = dstPortStart;
this.destinationPortEnd = dstPortEnd;
- }
-
- public PortForwardingRuleVO(String xId, long srcIpId, int srcPort, Ip
dstIp, int dstPort, String protocol, List<String> sourceCidrs, long networkId,
long accountId,
- long domainId, long instanceId) {
- this(xId, srcIpId, srcPort, srcPort, dstIp, dstPort, dstPort,
protocol.toLowerCase(), networkId, accountId, domainId, instanceId);
+ this.sourceCidrs = sourceCidrs;
}
@Override
@@ -106,4 +106,13 @@ public class PortForwardingRuleVO extends FirewallRuleVO
implements PortForwardi
return null;
}
+ public void setSourceCidrList(List<String> sourceCidrs) {
+ this.sourceCidrs = sourceCidrs;
+ }
+
+ @Override
+ public List<String> getSourceCidrList() {
+ return sourceCidrs;
+ }
+
}
diff --git
a/engine/schema/src/main/java/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java
b/engine/schema/src/main/java/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java
index 29cba516d72..1ddecaa8a17 100644
---
a/engine/schema/src/main/java/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java
+++
b/engine/schema/src/main/java/com/cloud/network/rules/dao/PortForwardingRulesDaoImpl.java
@@ -20,6 +20,9 @@ import java.util.List;
import javax.inject.Inject;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallback;
+import com.cloud.utils.db.TransactionLegacy;
import org.springframework.stereotype.Component;
import com.cloud.network.dao.FirewallRulesCidrsDao;
@@ -41,7 +44,7 @@ public class PortForwardingRulesDaoImpl extends
GenericDaoBase<PortForwardingRul
protected final SearchBuilder<PortForwardingRuleVO>
ActiveRulesSearchByAccount;
@Inject
- protected FirewallRulesCidrsDao _portForwardingRulesCidrsDao;
+ protected FirewallRulesCidrsDao portForwardingRulesCidrsDao;
protected PortForwardingRulesDaoImpl() {
super();
@@ -170,4 +173,44 @@ public class PortForwardingRulesDaoImpl extends
GenericDaoBase<PortForwardingRul
sc.setParameters("dstIp", secondaryIp);
return findOneBy(sc);
}
+
+ @Override
+ public PortForwardingRuleVO persist(PortForwardingRuleVO
portForwardingRule) {
+ return Transaction.execute((TransactionCallback<PortForwardingRuleVO>)
transactionStatus -> {
+ PortForwardingRuleVO dbPfRule = super.persist(portForwardingRule);
+
+ portForwardingRulesCidrsDao.persist(portForwardingRule.getId(),
portForwardingRule.getSourceCidrList());
+ List<String> cidrList =
portForwardingRulesCidrsDao.getSourceCidrs(portForwardingRule.getId());
+ portForwardingRule.setSourceCidrList(cidrList);
+
+ return dbPfRule;
+ });
+
+ }
+
+ @Override
+ public boolean update(Long id, PortForwardingRuleVO entity) {
+ TransactionLegacy txn = TransactionLegacy.currentTxn();
+ txn.start();
+
+ boolean success = super.update(id, entity);
+ if (!success) {
+ return false;
+ }
+
+ portForwardingRulesCidrsDao.updateSourceCidrsForRule(entity.getId(),
entity.getSourceCidrList());
+ txn.commit();
+
+ return true;
+ }
+
+ @Override
+ public PortForwardingRuleVO findById(Long id) {
+ PortForwardingRuleVO rule = super.findById(id);
+
+ List<String> sourceCidrList =
portForwardingRulesCidrsDao.getSourceCidrs(id);
+ rule.setSourceCidrList(sourceCidrList);
+
+ return rule;
+ }
}
diff --git
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
index d721db4b6b4..60cd9a2dff4 100644
---
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
+++
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
@@ -472,7 +472,7 @@ public class KubernetesClusterResourceModifierActionWorker
extends KubernetesClu
sourcePort, sourcePort,
vmIp,
destPort, destPort,
- "tcp", networkId, accountId, domainId, vmId);
+ "tcp", networkId, accountId, domainId, vmId, null);
newRule.setDisplay(true);
newRule.setState(FirewallRule.State.Add);
newRule = portForwardingRulesDao.persist(newRule);
diff --git
a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java
b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java
index 4ed480ea68b..4d4a8b30a56 100644
--- a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java
@@ -33,6 +33,7 @@ import
org.apache.cloudstack.api.command.user.ipv6.ListIpv6FirewallRulesCmd;
import org.apache.cloudstack.context.CallContext;
import
org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import org.apache.commons.lang3.ObjectUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@@ -391,20 +392,34 @@ public class FirewallManagerImpl extends ManagerBase
implements FirewallService,
((rule.getPurpose() == Purpose.Firewall ||
newRule.getPurpose() == Purpose.Firewall) && ((newRule.getPurpose() !=
rule.getPurpose()) || (!newRule.getProtocol()
.equalsIgnoreCase(rule.getProtocol()))));
- // if both rules are firewall and their cidrs are different, we
can skip port ranges verification
- boolean bothRulesFirewall = (rule.getPurpose() ==
newRule.getPurpose() && rule.getPurpose() == Purpose.Firewall);
+ // if both rules are firewall/port forwarding and their cidrs are
different, we can skip port ranges verification
boolean duplicatedCidrs = false;
+
+ boolean bothRulesFirewall = (rule.getPurpose() ==
newRule.getPurpose() && rule.getPurpose() == Purpose.Firewall);
if (bothRulesFirewall) {
_firewallDao.loadSourceCidrs(rule);
_firewallDao.loadSourceCidrs((FirewallRuleVO)newRule);
+ if (ObjectUtils.anyNull(rule.getSourceCidrList(),
newRule.getSourceCidrList())) {
+ continue;
+ }
+
_firewallDao.loadDestinationCidrs(rule);
_firewallDao.loadDestinationCidrs((FirewallRuleVO) newRule);
- if (rule.getSourceCidrList() == null ||
newRule.getSourceCidrList() == null) {
+ duplicatedCidrs =
detectConflictingCidrs(rule.getSourceCidrList(), newRule.getSourceCidrList())
&& detectConflictingCidrs(rule.getDestinationCidrList(),
newRule.getDestinationCidrList());
+ }
+
+ boolean bothRulesPortForwarding = rule.getPurpose() ==
newRule.getPurpose() && rule.getPurpose() == Purpose.PortForwarding;
+ if (bothRulesPortForwarding) {
+ _firewallDao.loadSourceCidrs(rule);
+ _firewallDao.loadSourceCidrs((FirewallRuleVO) newRule);
+
+ if (ObjectUtils.anyNull(rule.getSourceCidrList(),
newRule.getSourceCidrList())) {
continue;
}
- duplicatedCidrs =
(detectConflictingCidrs(rule.getSourceCidrList(), newRule.getSourceCidrList())
&& detectConflictingCidrs(rule.getDestinationCidrList(),
newRule.getDestinationCidrList()));
+
+ duplicatedCidrs =
detectConflictingCidrs(rule.getSourceCidrList(), newRule.getSourceCidrList());
}
if (!oneOfRulesIsFirewall) {
@@ -440,18 +455,7 @@ public class FirewallManagerImpl extends ManagerBase
implements FirewallService,
if (!notNullPorts) {
continue;
- } else if (!oneOfRulesIsFirewall &&
- !(bothRulesFirewall && !duplicatedCidrs) &&
- ((rule.getSourcePortStart().intValue() <=
newRule.getSourcePortStart().intValue() &&
- rule.getSourcePortEnd().intValue() >=
newRule.getSourcePortStart().intValue()) ||
- (rule.getSourcePortStart().intValue() <=
newRule.getSourcePortEnd().intValue() &&
- rule.getSourcePortEnd().intValue() >=
newRule.getSourcePortEnd().intValue()) ||
- (newRule.getSourcePortStart().intValue() <=
rule.getSourcePortStart().intValue() &&
- newRule.getSourcePortEnd().intValue() >=
rule.getSourcePortStart().intValue()) ||
- (newRule.getSourcePortStart().intValue() <=
rule.getSourcePortEnd().intValue() &&
- newRule.getSourcePortEnd().intValue() >=
rule.getSourcePortEnd().intValue()))) {
- //Above else if conditions checks for the conflicting port
ranges.
-
+ } else if (checkIfRulesHaveConflictingPortRanges(newRule, rule,
oneOfRulesIsFirewall, bothRulesFirewall, bothRulesPortForwarding,
duplicatedCidrs)) {
// 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(
@@ -478,6 +482,45 @@ public class FirewallManagerImpl extends ManagerBase
implements FirewallService,
}
}
+ protected boolean checkIfRulesHaveConflictingPortRanges(FirewallRule
newRule, FirewallRule rule, boolean oneOfRulesIsFirewall, boolean
bothRulesFirewall, boolean bothRulesPortForwarding, boolean duplicatedCidrs) {
+ String rulesAsString = String.format("[%s] and [%s]", rule, newRule);
+
+ if (oneOfRulesIsFirewall) {
+ s_logger.debug(String.format("Only one of the rules (%s) is
firewall; therefore, their port ranges will not conflict.",
+ rulesAsString));
+ return false;
+ }
+
+ if ((bothRulesFirewall || bothRulesPortForwarding) &&
!duplicatedCidrs) {
+ s_logger.debug(String.format("Both rules (%s) are firewall/port
forwarding, but they do not have duplicated CIDRs; therefore, their port ranges
will not conflict.",
+ rulesAsString));
+ return false;
+ }
+
+ if (rule.getSourcePortStart() <= newRule.getSourcePortStart() &&
rule.getSourcePortEnd() >= newRule.getSourcePortStart()) {
+ s_logger.debug(String.format("Rules (%s) have conflicting port
ranges.", rulesAsString));
+ return true;
+ }
+
+ if (rule.getSourcePortStart() <= newRule.getSourcePortEnd() &&
rule.getSourcePortEnd() >= newRule.getSourcePortEnd()) {
+ s_logger.debug(String.format("Rules (%s) have conflicting port
ranges.", rulesAsString));
+ return true;
+ }
+
+ if (newRule.getSourcePortStart() <= rule.getSourcePortStart() &&
newRule.getSourcePortEnd() >= rule.getSourcePortStart()) {
+ s_logger.debug(String.format("Rules (%s) have conflicting port
ranges.", rulesAsString));
+ return true;
+ }
+
+ if (newRule.getSourcePortStart() <= rule.getSourcePortEnd() &&
newRule.getSourcePortEnd() >= rule.getSourcePortEnd()) {
+ s_logger.debug(String.format("Rules (%s) have conflicting port
ranges.", rulesAsString));
+ return true;
+ }
+
+ s_logger.debug(String.format("Rules (%s) do not have conflicting port
ranges.", rulesAsString));
+ return false;
+ }
+
@Override
public void validateFirewallRule(Account caller, IPAddressVO ipAddress,
Integer portStart, Integer portEnd, String proto, Purpose purpose,
FirewallRuleType type,
Long networkId, FirewallRule.TrafficType trafficType) {
diff --git
a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java
b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java
index a7ed6478efa..0e3acb953c7 100644
--- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java
+++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java
@@ -27,6 +27,7 @@ import java.util.Set;
import javax.inject.Inject;
+import com.cloud.network.rules.PortForwardingRuleVO;
import org.apache.cloudstack.api.ApiConstants;
import
org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
@@ -396,6 +397,7 @@ public class CommandSetupHelper {
final List<PortForwardingRuleTO> rulesTO = new
ArrayList<PortForwardingRuleTO>();
if (rules != null) {
for (final PortForwardingRule rule : rules) {
+ _rulesDao.loadSourceCidrs((PortForwardingRuleVO) rule);
final IpAddress sourceIp =
_networkModel.getIp(rule.getSourceIpAddressId());
final PortForwardingRuleTO ruleTO = new
PortForwardingRuleTO(rule, null, sourceIp.getAddress().addr());
rulesTO.add(ruleTO);
diff --git a/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java
b/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java
index 7686a8d7887..1b7177ec416 100644
--- a/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java
@@ -33,6 +33,7 @@ import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.VirtualMachineProfileImpl;
import org.apache.cloudstack.acl.SecurityChecker;
import
org.apache.cloudstack.api.command.user.firewall.ListPortForwardingRulesCmd;
+import
org.apache.cloudstack.api.command.user.firewall.UpdatePortForwardingRuleCmd;
import org.apache.cloudstack.context.CallContext;
import
org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.log4j.Logger;
@@ -103,6 +104,7 @@ import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.NicSecondaryIpVO;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
+import org.apache.commons.collections.CollectionUtils;
public class RulesManagerImpl extends ManagerBase implements RulesManager,
RulesService {
private static final Logger s_logger =
Logger.getLogger(RulesManagerImpl.class);
@@ -114,7 +116,7 @@ public class RulesManagerImpl extends ManagerBase
implements RulesManager, Rules
@Inject
PortForwardingRulesDao _portForwardingDao;
@Inject
- FirewallRulesCidrsDao _firewallCidrsDao;
+ FirewallRulesCidrsDao firewallCidrsDao;
@Inject
FirewallRulesDao _firewallDao;
@Inject
@@ -249,6 +251,7 @@ public class RulesManagerImpl extends ManagerBase
implements RulesManager, Rules
final Long accountId = ipAddress.getAllocatedToAccountId();
final Long domainId = ipAddress.getAllocatedInDomainId();
+ List<String> sourceCidrList = rule.getSourceCidrList();
// start port can't be bigger than end port
if (rule.getDestinationPortStart() >
rule.getDestinationPortEnd()) {
@@ -312,9 +315,8 @@ public class RulesManagerImpl extends ManagerBase
implements RulesManager, Rules
final IPAddressVO ipAddressFinal = ipAddress;
return
Transaction.execute((TransactionCallbackWithException<PortForwardingRuleVO,
NetworkRuleConflictException>) status -> {
PortForwardingRuleVO newRule =
- new PortForwardingRuleVO(rule.getXid(),
rule.getSourceIpAddressId(), rule.getSourcePortStart(),
rule.getSourcePortEnd(), dstIpFinal,
- rule.getDestinationPortStart(),
rule.getDestinationPortEnd(), rule.getProtocol().toLowerCase(), networkId,
accountId, domainId, vmId);
-
+ new PortForwardingRuleVO(rule.getXid(),
rule.getSourceIpAddressId(), rule.getSourcePortStart(),
rule.getSourcePortEnd(), dstIpFinal,
+ rule.getDestinationPortStart(),
rule.getDestinationPortEnd(), rule.getProtocol().toLowerCase(), networkId,
accountId, domainId, vmId, sourceCidrList);
if (forDisplay != null) {
newRule.setDisplay(forDisplay);
}
@@ -898,6 +900,10 @@ public class RulesManagerImpl extends ManagerBase
implements RulesManager, Rules
_accountMgr.checkAccess(caller, null, true, rules.toArray(new
PortForwardingRuleVO[rules.size()]));
}
+ for (PortForwardingRuleVO rule : rules) {
+
rule.setSourceCidrList(firewallCidrsDao.getSourceCidrs(rule.getId()));
+ }
+
try {
if (!_firewallMgr.applyRules(rules, continueOnError, true)) {
return false;
@@ -951,6 +957,10 @@ public class RulesManagerImpl extends ManagerBase
implements RulesManager, Rules
_accountMgr.checkAccess(caller, null, true, rules.toArray(new
PortForwardingRuleVO[rules.size()]));
}
+ for (PortForwardingRuleVO rule: rules) {
+
rule.setSourceCidrList(firewallCidrsDao.getSourceCidrs(rule.getId()));
+ }
+
try {
if (!_firewallMgr.applyRules(rules, continueOnError, true)) {
return false;
@@ -1570,12 +1580,22 @@ public class RulesManagerImpl extends ManagerBase
implements RulesManager, Rules
@Override
@ActionEvent(eventType = EventTypes.EVENT_NET_RULE_MODIFY,
eventDescription = "updating forwarding rule", async = true)
- public PortForwardingRule updatePortForwardingRule(long id, Integer
privatePort, Integer privateEndPort, Long virtualMachineId, Ip vmGuestIp,
String customId, Boolean forDisplay) {
- Account caller = CallContext.current().getCallingAccount();
+ public PortForwardingRule
updatePortForwardingRule(UpdatePortForwardingRuleCmd cmd) {
+ long id = cmd.getId();
+ Integer privatePort = cmd.getPrivatePort();
+ Integer privateEndPort = cmd.getPrivateEndPort();
+ Long virtualMachineId = cmd.getVirtualMachineId();
+ Ip vmGuestIp = cmd.getVmGuestIp();
+ String customId = cmd.getCustomId();
+ Boolean forDisplay = cmd.getDisplay();
+ List<String> sourceCidrList = cmd.getSourceCidrList();
+
PortForwardingRuleVO rule = _portForwardingDao.findById(id);
if (rule == null) {
throw new InvalidParameterValueException("Unable to find " + id);
}
+
+ Account caller = CallContext.current().getCallingAccount();
_accountMgr.checkAccess(caller, null, true, rule);
if (customId != null) {
@@ -1636,6 +1656,8 @@ public class RulesManagerImpl extends ManagerBase
implements RulesManager, Rules
}
}
+ validatePortForwardingSourceCidrList(sourceCidrList);
+
// revoke old rules at first
List<PortForwardingRuleVO> rules = new
ArrayList<PortForwardingRuleVO>();
rule.setState(State.Revoke);
@@ -1663,6 +1685,11 @@ public class RulesManagerImpl extends ManagerBase
implements RulesManager, Rules
rule.setVirtualMachineId(virtualMachineId);
rule.setDestinationIpAddress(dstIp);
}
+
+ if (sourceCidrList != null) {
+ rule.setSourceCidrList(sourceCidrList);
+ }
+
_portForwardingDao.update(id, rule);
//apply new rules
@@ -1672,4 +1699,17 @@ public class RulesManagerImpl extends ManagerBase
implements RulesManager, Rules
return _portForwardingDao.findById(id);
}
+
+ @Override
+ public void validatePortForwardingSourceCidrList(List<String>
sourceCidrList) {
+ if (CollectionUtils.isEmpty(sourceCidrList)) {
+ return;
+ }
+
+ for (String cidr : sourceCidrList) {
+ if (!NetUtils.isValidCidrList(cidr) &&
!NetUtils.isValidIp6Cidr(cidr)) {
+ throw new InvalidParameterValueException(String.format("The
given source CIDR [%s] is invalid.", cidr));
+ }
+ }
+ }
}
diff --git
a/server/src/test/java/com/cloud/network/firewall/FirewallManagerTest.java
b/server/src/test/java/com/cloud/network/firewall/FirewallManagerTest.java
index 2200d6b125b..e8f01576e4c 100644
--- a/server/src/test/java/com/cloud/network/firewall/FirewallManagerTest.java
+++ b/server/src/test/java/com/cloud/network/firewall/FirewallManagerTest.java
@@ -27,7 +27,6 @@ import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.element.FirewallServiceProvider;
import com.cloud.network.element.VirtualRouterElement;
import com.cloud.network.element.VpcVirtualRouterElement;
-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;
@@ -35,9 +34,9 @@ import com.cloud.network.vpc.VpcManager;
import com.cloud.user.AccountManager;
import com.cloud.user.DomainManager;
import com.cloud.utils.component.ComponentContext;
-import junit.framework.Assert;
import
org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.log4j.Logger;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -45,7 +44,8 @@ import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Arrays;
@@ -108,12 +108,35 @@ public class FirewallManagerTest {
@Mock
FirewallRulesDao _firewallDao;
+ @Spy
@InjectMocks
- FirewallManager _firewallMgr = new FirewallManagerImpl();
+ FirewallManagerImpl _firewallMgr;
+
+ FirewallRule fwRule50to150;
+ FirewallRule fwRule100to200;
+ FirewallRule fwRule151to200;
+
+ FirewallRule pfRule50to150;
+ FirewallRule pfRule100to200;
+ FirewallRule pfRule151to200;
+
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
+
+ fwRule50to150 = createFirewallRule(50, 150, Purpose.Firewall);
+ fwRule100to200 = createFirewallRule(100, 150, Purpose.Firewall);
+ fwRule151to200 = createFirewallRule(151, 200, Purpose.Firewall);
+
+ pfRule50to150 = createFirewallRule(50, 150, Purpose.PortForwarding);
+ pfRule100to200 = createFirewallRule(100, 150, Purpose.PortForwarding);
+ pfRule151to200 = createFirewallRule(151, 200, Purpose.PortForwarding);
+ }
+
+ private FirewallRule createFirewallRule(int startPort, int endPort,
Purpose purpose) {
+ return new FirewallRuleVO("xid", 1L, startPort, endPort, "TCP", 2, 3,
4, purpose, new ArrayList<>(),
+ new ArrayList<>(), 5, 6, null,
FirewallRule.TrafficType.Ingress);
}
@Ignore("Requires database to be set up")
@@ -210,6 +233,75 @@ public class FirewallManagerTest {
}
}
+ @Test
+ public void
checkIfRulesHaveConflictingPortRangesTestOnlyOneRuleIsFirewallReturnsFalse()
+ {
+ boolean result =
_firewallMgr.checkIfRulesHaveConflictingPortRanges(fwRule50to150,
pfRule50to150, true, false, false, true);
+
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void
checkIfRulesHaveConflictingPortRangesTestBothRulesAreFirewallButNoDuplicateCidrsReturnsFalse()
+ {
+ boolean result =
_firewallMgr.checkIfRulesHaveConflictingPortRanges(fwRule50to150,
fwRule50to150, false, true, false, false);
+
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void
checkIfRulesHaveConflictingPortRangesTestBothRulesArePortForwardingButNoDuplicateCidrsReturnsFalse()
+ {
+ boolean result =
_firewallMgr.checkIfRulesHaveConflictingPortRanges(pfRule50to150,
pfRule50to150, false, false, true, false);
+
+ Assert.assertFalse(result);
+ }
+
+ @Test
+ public void
checkIfRulesHaveConflictingPortRangesTestBothRulesAreFirewallAndDuplicatedCidrsAndNewRuleSourceStartPortIsInsideExistingRangeReturnsTrue()
+ {
+ boolean result =
_firewallMgr.checkIfRulesHaveConflictingPortRanges(fwRule100to200,
fwRule50to150, false, true, false, true);
+
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void
checkIfRulesHaveConflictingPortRangesTestBothRulesAreFirewallAndDuplicatedCidrsAndNewRuleSourceEndPortIsInsideExistingRangeReturnsTrue()
+ {
+ boolean result =
_firewallMgr.checkIfRulesHaveConflictingPortRanges(fwRule50to150,
fwRule100to200, false, true, false, true);
+
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void
checkIfRulesHaveConflictingPortRangesTestBothRulesArePortForwardingAndDuplicatedCidrsAndNewRuleSourceStartPortIsInsideExistingRangeReturnsTrue()
+ {
+ boolean result =
_firewallMgr.checkIfRulesHaveConflictingPortRanges(pfRule50to150,
pfRule100to200, false, false, true, true);
+
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void
checkIfRulesHaveConflictingPortRangesTestBothRulesArePortForwardingAndDuplicatedCidrsAndNewRuleSourceEndPortIsInsideExistingRangeReturnsTrue()
+ {
+ boolean result =
_firewallMgr.checkIfRulesHaveConflictingPortRanges(pfRule50to150,
pfRule100to200, false, false, true, true);
+
+ Assert.assertTrue(result);
+ }
+
+ @Test
+ public void
checkIfRulesHaveConflictingPortRangesTestBothRulesAreFirewallAndDuplicatedCidrsAndNoRangeConflictReturnsFalse()
+ {
+ boolean result =
_firewallMgr.checkIfRulesHaveConflictingPortRanges(fwRule50to150,
fwRule151to200, false, true, false, true);
+ Assert.assertFalse(result);
+ }
+ @Test
+ public void
checkIfRulesHaveConflictingPortRangesTestBothRulesArePortForwardingAndDuplicatedCidrsAndNoRangeConflictReturnsFalse()
+ {
+ boolean result =
_firewallMgr.checkIfRulesHaveConflictingPortRanges(pfRule50to150,
pfRule151to200, false, false, true, true);
+
+ Assert.assertFalse(result);
+ }
}
diff --git a/systemvm/debian/opt/cloud/bin/configure.py
b/systemvm/debian/opt/cloud/bin/configure.py
index c261293af0f..fd421fc268f 100755
--- a/systemvm/debian/opt/cloud/bin/configure.py
+++ b/systemvm/debian/opt/cloud/bin/configure.py
@@ -1217,7 +1217,10 @@ class CsForwardingRules(CsDataBag):
self.fw.append(["filter", "", fw7])
def forward_vpc(self, rule):
- fw_prerout_rule = "-A PREROUTING -d %s/32 " % (rule["public_ip"])
+ fw_prerout_rule = "-A PREROUTING"
+ if "source_cidr_list" in rule and rule["source_cidr_list"]:
+ fw_prerout_rule += " -s %s" % rule["source_cidr_list"]
+ fw_prerout_rule += " -d %s/32" % rule["public_ip"]
if not rule["protocol"] == "any":
fw_prerout_rule += " -m %s -p %s" % (rule["protocol"],
rule["protocol"])
if not rule["public_ports"] == "any":
@@ -1226,7 +1229,10 @@ class CsForwardingRules(CsDataBag):
if not rule["internal_ports"] == "any":
fw_prerout_rule += ":" +
self.portsToString(rule["internal_ports"], "-")
- fw_output_rule = "-A OUTPUT -d %s/32" % rule["public_ip"]
+ fw_output_rule = "-A OUTPUT"
+ if "source_cidr_list" in rule and rule["source_cidr_list"]:
+ fw_output_rule += " -s %s" % rule["source_cidr_list"]
+ fw_output_rule += " -d %s/32" % rule["public_ip"]
if not rule["protocol"] == "any":
fw_output_rule += " -m %s -p %s" % (rule["protocol"],
rule["protocol"])
if not rule["public_ports"] == "any":
diff --git a/systemvm/debian/opt/cloud/bin/cs/CsNetfilter.py
b/systemvm/debian/opt/cloud/bin/cs/CsNetfilter.py
index a034034dc8b..14a49feda76 100755
--- a/systemvm/debian/opt/cloud/bin/cs/CsNetfilter.py
+++ b/systemvm/debian/opt/cloud/bin/cs/CsNetfilter.py
@@ -327,7 +327,7 @@ class CsNetfilter(object):
return self.rule
def to_str(self, delete=False):
- """ Convert the rule back into aynactically correct iptables command
"""
+ """ Convert the rule back into syntactically correct iptables command
"""
# Order is important
order = ['-A', '-s', '-d', '!_-d', '-i', '!_-i', '-p', '-m', '-m2',
'--icmp-type', '--state',
'--dport', '--destination-port', '-o', '!_-o', '-j',
'--set-xmark', '--checksum',
diff --git a/systemvm/debian/opt/cloud/bin/cs_forwardingrules.py
b/systemvm/debian/opt/cloud/bin/cs_forwardingrules.py
index 974c468e8dc..c8b4c91ad75 100755
--- a/systemvm/debian/opt/cloud/bin/cs_forwardingrules.py
+++ b/systemvm/debian/opt/cloud/bin/cs_forwardingrules.py
@@ -16,6 +16,8 @@
# under the License.
+import logging
+
def merge(dbag, rules):
for rule in rules["rules"]:
source_ip = rule["source_ip_address"]
@@ -33,6 +35,8 @@ def merge(dbag, rules):
newrule["public_ports"] = rule["source_port_range"]
newrule["internal_ports"] = rule["destination_port_range"]
newrule["protocol"] = rule["protocol"]
+ if "source_cidr_list" in rule:
+ newrule["source_cidr_list"] = rule["source_cidr_list"]
if not revoke:
if rules["type"] == "staticnatrules":
@@ -59,7 +63,7 @@ def merge(dbag, rules):
for forward in dbag[source_ip]:
if ruleCompare(forward, newrule):
index = dbag[source_ip].index(forward)
- print "removing index %s" % str(index)
+ logging.info("Removing forwarding rule [%s] at
index [%s].", forward, index)
if not index == -1:
del dbag[source_ip][index]
@@ -74,4 +78,18 @@ def ruleCompare(ruleA, ruleB):
return ruleA["public_ip"] == ruleB["public_ip"]
elif ruleA["type"] == "forward":
return ruleA["public_ip"] == ruleB["public_ip"] and
ruleA["public_ports"] == ruleB["public_ports"] \
- and ruleA["protocol"] == ruleB["protocol"]
+ and ruleA["protocol"] == ruleB["protocol"] and
cidrsConflict(ruleA.get("source_cidr_list"), ruleB.get("source_cidr_list"))
+
+# Same validation as in
com.cloud.network.firewall.FirewallManagerImpl.detectConflictingCidrs
+def cidrsConflict(cidrListA, cidrListB):
+ if not cidrListA and not cidrListB:
+ return True
+ if not cidrListA:
+ return False
+ if not cidrListB:
+ return False
+
+ cidrListA = set(cidrListA.split(","))
+ cidrListB = set(cidrListB.split(","))
+
+ return len(cidrListA.intersection(cidrListB)) > 0
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 48f78f598eb..8cc17bbb128 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -1946,6 +1946,7 @@
"label.source": "Select Import-Export Source Hypervisor",
"label.source.based": "SourceBased",
"label.sourcecidr": "Source CIDR",
+"label.sourcecidrlist": "Source CIDR list",
"label.sourcehost": "Source host",
"label.sourceipaddress": "Source IP address",
"label.sourceipaddressnetworkid": "Network ID of source IP address",
diff --git a/ui/public/locales/pt_BR.json b/ui/public/locales/pt_BR.json
index c36a5c762a7..937caa69a59 100644
--- a/ui/public/locales/pt_BR.json
+++ b/ui/public/locales/pt_BR.json
@@ -349,7 +349,7 @@
"label.choose.saml.identity": "Escolha um provedor de identidade SAML",
"label.cidr": "CIDR",
"label.cidr.destination.network": "CIDR da rede de destino",
-"label.cidrlist": "Lista de CIDR ",
+"label.cidrlist": "Lista de CIDRs",
"label.cisco.nexus1000v.ip.address": "Endere\u00e7o IP do Nexus 1000v",
"label.cisco.nexus1000v.password": "Senha do Nexus 1000v",
"label.cisco.nexus1000v.username": "Usu\u00e1rio do Nexus 1000v",
@@ -1494,6 +1494,7 @@
"label.sockettimeout": "Tempo limite no socket",
"label.source.based": "SourceBased",
"label.sourcecidr": "CIDR de origem",
+"label.sourcecidrlist": "Lista de CIDRs de origem",
"label.sourceipaddress": "Endere\u00e7o IP de origem",
"label.sourcenat": "Source NAT",
"label.sourcenatsupported": "Suporte \u00e0 source NAT",
diff --git a/ui/src/views/network/LoadBalancing.vue
b/ui/src/views/network/LoadBalancing.vue
index eeec232cee5..09f9a39c4cf 100644
--- a/ui/src/views/network/LoadBalancing.vue
+++ b/ui/src/views/network/LoadBalancing.vue
@@ -37,7 +37,7 @@
</div>
<div class="form">
<div class="form__item" ref="newCidrList">
- <tooltip-label :title="$t('label.cidrlist')" bold
:tooltip="createLoadBalancerRuleParams.cidrlist.description"
:tooltip-placement="'right'"/>
+ <tooltip-label :title="$t('label.sourcecidrlist')" bold
:tooltip="createLoadBalancerRuleParams.cidrlist.description"
:tooltip-placement="'right'"/>
<a-input v-model:value="newRule.cidrlist"></a-input>
</div>
<div class="form__item">
@@ -126,7 +126,7 @@
:rowKey="record => record.id">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'cidrlist'">
- <span style="white-space: pre-line"> {{
record.cidrlist?.replaceAll(" ", "\n") }}</span>
+ <span style="white-space: pre-line"> {{
record.cidrlist?.replaceAll(",", "\n") }}</span>
</template>
<template v-if="column.key === 'algorithm'">
{{ returnAlgorithmName(record.algorithm) }}
@@ -808,7 +808,7 @@ export default {
},
{
key: 'cidrlist',
- title: this.$t('label.cidrlist')
+ title: this.$t('label.sourcecidrlist')
},
{
key: 'protocol',
diff --git a/ui/src/views/network/PortForwarding.vue
b/ui/src/views/network/PortForwarding.vue
index 81843a1a0b0..2c10b4bcc75 100644
--- a/ui/src/views/network/PortForwarding.vue
+++ b/ui/src/views/network/PortForwarding.vue
@@ -72,6 +72,12 @@
<a-select-option value="udp" :label="$t('label.udp')">{{
$t('label.udp') }}</a-select-option>
</a-select>
</div>
+ <div v-if="isVPC()">
+ <div class="form__item" ref="newCidrList">
+ <tooltip-label :title="$t('label.sourcecidrlist')" bold
:tooltip="apiParams.cidrlist.description" :tooltip-placement="'right'"/>
+ <a-input v-model:value="newRule.cidrlist"></a-input>
+ </div>
+ </div>
<div class="form__item" style="margin-left: auto;">
<div class="form__label">{{ $t('label.add.vm') }}</div>
<a-button :disabled="!('createPortForwardingRule' in
$store.getters.apis)" type="primary" @click="openAddVMModal">{{ $t('label.add')
}}</a-button>
@@ -108,6 +114,9 @@
<template v-if="column.key === 'protocol'">
{{ getCapitalise(record.protocol) }}
</template>
+ <template v-if="column.key === 'cidrlist'">
+ <span style="white-space: pre-line"> {{
record.cidrlist?.replaceAll(",", "\n") }}</span>
+ </template>
<template v-if="column.key === 'vm'">
<div><desktop-outlined/>
<router-link
@@ -334,9 +343,11 @@ import Status from '@/components/widgets/Status'
import TooltipButton from '@/components/widgets/TooltipButton'
import BulkActionView from '@/components/view/BulkActionView'
import eventBus from '@/config/eventBus'
+import TooltipLabel from '@/components/widgets/TooltipLabel.vue'
export default {
components: {
+ TooltipLabel,
Status,
TooltipButton,
BulkActionView
@@ -399,6 +410,11 @@ export default {
key: 'protocol',
title: this.$t('label.protocol')
},
+ {
+ key: 'cidrlist',
+ title: this.$t('label.sourcecidrlist'),
+ hidden: !this.isVPC()
+ },
{
title: this.$t('label.state'),
dataIndex: 'state'
@@ -411,7 +427,7 @@ export default {
key: 'actions',
title: this.$t('label.actions')
}
- ],
+ ].filter(item => !item.hidden),
tiers: {
loading: false,
data: []
@@ -450,7 +466,8 @@ export default {
vmPage: 1,
vmPageSize: 10,
vmCount: 0,
- searchQuery: null
+ searchQuery: null,
+ cidrlist: ''
}
},
computed: {
@@ -458,6 +475,9 @@ export default {
return this.selectedRowKeys.length > 0
}
},
+ beforeCreate () {
+ this.apiParams = this.$getApiParams('createPortForwardingRule')
+ },
created () {
console.log(this.resource)
this.initForm()
@@ -830,6 +850,9 @@ export default {
onSearch (value) {
this.searchQuery = value
this.fetchVirtualMachines()
+ },
+ isVPC () {
+ return 'vpcid' in this.resource
}
}
}