CLOUDSTACK-763: Added acl_id param to createNetwork API. Backend changes for acl_deny. Support for all protocol and protocol number

This commit is contained in:
Kishan Kavala 2013-05-02 17:53:56 +05:30
parent 5d711be0d7
commit 0de6a80f50
17 changed files with 125 additions and 38 deletions

View File

@ -325,4 +325,6 @@ public interface Network extends ControlledEntity, StateObject<Network.State>, I
Long getVpcId();
Long getNetworkACLId();
void setNetworkACLId(Long networkACLId);
}

View File

@ -243,6 +243,11 @@ public class NetworkProfile implements Network {
return networkAclId;
}
@Override
public void setNetworkACLId(Long networkACLId) {
this.networkAclId = networkACLId;
}
@Override
public void setTrafficType(TrafficType type) {
this.trafficType = type;

View File

@ -21,6 +21,9 @@ import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.api.InternalIdentity;
public interface NetworkACL extends InternalIdentity, ControlledEntity{
public static final long DEFAULT_DENY = 1;
public static final long DEFAULT_ALLOW = 2;
String getDescription();
String getUuid();

View File

@ -56,7 +56,7 @@ public class CreateNetworkACLCmd extends BaseAsyncCreateCmd {
// ///////////////////////////////////////////////////
@Parameter(name = ApiConstants.PROTOCOL, type = CommandType.STRING, required = true, description =
"the protocol for the ACL rule. Valid values are TCP/UDP/ICMP.")
"the protocol for the ACL rule. Valid values are TCP/UDP/ICMP/ALL or valid protocol number")
private String protocol;
@Parameter(name = ApiConstants.START_PORT, type = CommandType.INTEGER, description = "the starting port of ACL")

View File

@ -22,13 +22,7 @@ import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.NetworkOfferingResponse;
import org.apache.cloudstack.api.response.NetworkResponse;
import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.VpcResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.api.response.*;
import org.apache.log4j.Logger;
import com.cloud.exception.ConcurrentOperationException;
@ -126,6 +120,9 @@ public class CreateNetworkCmd extends BaseCmd {
@Parameter(name=ApiConstants.IP6_CIDR, type=CommandType.STRING, description="the CIDR of IPv6 network, must be at least /64")
private String ip6Cidr;
@Parameter(name=ApiConstants.ACL_ID, type=CommandType.UUID, entityType = NetworkACLResponse.class,
description="Network ACL Id associated for the network")
private Long aclId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -247,6 +244,10 @@ public class CreateNetworkCmd extends BaseCmd {
return ip6Cidr.toLowerCase();
}
public Long getAclId() {
return aclId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -544,6 +544,7 @@ public class NetworkVO implements Network {
this.ip6Gateway = ip6Gateway;
}
@Override
public void setNetworkACLId(Long networkACLId) {
this.networkACLId = networkACLId;
}

View File

@ -102,6 +102,7 @@ acl_entry_for_guest_network() {
local sport=$(echo $rule | cut -d: -f3)
local eport=$(echo $rule | cut -d: -f4)
local cidrs=$(echo $rule | cut -d: -f5 | sed 's/-/ /g')
local action=$(echo $rule | cut -d: -f6)
if [ "$sport" == "0" -a "$eport" == "0" ]
then
DPORT=""
@ -123,21 +124,21 @@ acl_entry_for_guest_network() {
if [ "$ttype" == "Ingress" ]
then
sudo iptables -I ACL_INBOUND_$dev -p $prot -s $lcidr \
--icmp-type $typecode -j ACCEPT
--icmp-type $typecode -j $action
else
let egress++
sudo iptables -t mangle -I ACL_OUTBOUND_$dev -p $prot -d $lcidr \
--icmp-type $typecode -j ACCEPT
--icmp-type $typecode -j $action
fi
else
if [ "$ttype" == "Ingress" ]
then
sudo iptables -I ACL_INBOUND_$dev -p $prot -s $lcidr \
$DPORT -j ACCEPT
$DPORT -j $action
else
let egress++
sudo iptables -t mangle -I ACL_OUTBOUND_$dev -p $prot -d $lcidr \
$DPORT -j ACCEPT
$DPORT -j $action
fi
fi
result=$?
@ -195,7 +196,7 @@ fi
# protocal:sport:eport:cidr
#-a tcp:80:80:0.0.0.0/0::tcp:220:220:0.0.0.0/0:,172.16.92.44:tcp:222:222:192.168.10.0/24-75.57.23.0/22-88.100.33.1/32
# if any entry is reverted , entry will be in the format <ip>:reverted:0:0:0
# example : 172.16.92.44:tcp:80:80:0.0.0.0/0:,172.16.92.44:tcp:220:220:0.0.0.0/0:,200.1.1.2:reverted:0:0:0
# example : 172.16.92.44:tcp:80:80:0.0.0.0/0:ACCEPT:,172.16.92.44:tcp:220:220:0.0.0.0/0:DROP,200.1.1.2:reverted:0:0:0
success=0

View File

@ -18,6 +18,8 @@ package com.cloud.network;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetAddress;
import java.net.Inet6Address;
import java.net.UnknownHostException;
import java.security.InvalidParameterException;
import java.sql.PreparedStatement;
@ -42,6 +44,10 @@ import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd;
import org.apache.cloudstack.api.command.admin.network.ListDedicatedGuestVlanRangesCmd;
import com.cloud.network.vpc.NetworkACL;
import com.cloud.network.vpc.dao.NetworkACLDao;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd;
import org.apache.cloudstack.api.command.user.network.CreateNetworkCmd;
import org.apache.cloudstack.api.command.user.network.ListNetworksCmd;
@ -49,6 +55,10 @@ import org.apache.cloudstack.api.command.user.network.RestartNetworkCmd;
import org.apache.cloudstack.api.command.user.vm.ListNicsCmd;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.apache.cloudstack.api.command.user.vm.ListNicsCmd;
import org.bouncycastle.util.IPAddress;
import com.cloud.configuration.Config;
import com.cloud.configuration.ConfigurationManager;
@ -271,6 +281,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
DataCenterVnetDao _datacneter_vnet;
@Inject
AccountGuestVlanMapDao _accountGuestVlanMapDao;
@Inject
NetworkACLDao _networkACLDao;
int _cidrLimit;
boolean _allowSubdomainNetworkAccess;
@ -900,6 +912,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
String endIPv6 = cmd.getEndIpv6();
String ip6Gateway = cmd.getIp6Gateway();
String ip6Cidr = cmd.getIp6Cidr();
Long aclId = cmd.getAclId();
// Validate network offering
NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
@ -1177,8 +1190,21 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
if (!_configMgr.isOfferingForVpc(ntwkOff)){
throw new InvalidParameterValueException("Network offering can't be used for VPC networks");
}
network = _vpcMgr.createVpcGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId,
networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, caller);
if(aclId == null){
//Use default deny all ACL, when aclId is not specified
aclId = NetworkACL.DEFAULT_DENY;
} else {
NetworkACL acl = _networkACLDao.findById(aclId);
if(acl == null){
throw new InvalidParameterValueException("Unable to find specified NetworkACL");
}
if(vpcId != acl.getVpcId()){
throw new InvalidParameterValueException("ACL: "+aclId+" do not belong to the VPC");
}
}
network = _vpcMgr.createVpcGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId,
networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, aclId, caller);
} else {
if (_configMgr.isOfferingForVpc(ntwkOff)){
throw new InvalidParameterValueException("Network offering can be used for VPC networks only");

View File

@ -33,4 +33,5 @@ public interface NetworkACLItemDao extends GenericDao<NetworkACLItemVO, Long> {
int getMaxNumberByACL(long aclId);
NetworkACLItemVO findByAclAndNumber(long aclId, int number);
}

View File

@ -77,13 +77,15 @@ public class NetworkACLManagerImpl extends ManagerBase implements NetworkACLMana
@Override
public boolean applyNetworkACL(long aclId) throws ResourceUnavailableException {
boolean handled = false;
boolean handled = true;
List<NetworkACLItemVO> rules = _networkACLItemDao.listByACL(aclId);
//Find all networks using this ACL
List<NetworkVO> networks = _networkDao.listByAclId(aclId);
for(NetworkVO network : networks){
//Failure case??
handled = applyACLItemsToNetwork(network.getId(), rules);
if(!applyACLItemsToNetwork(network.getId(), rules)) {
handled = false;
break;
}
}
if(handled){
for (NetworkACLItem rule : rules) {
@ -115,9 +117,6 @@ public class NetworkACLManagerImpl extends ManagerBase implements NetworkACLMana
@Override
public boolean replaceNetworkACL(NetworkACL acl, NetworkVO network) throws ResourceUnavailableException {
if(network.getVpcId() != acl.getVpcId()){
throw new InvalidParameterValueException("Network: "+network.getUuid()+" and ACL: "+acl.getUuid()+" do not belong to the same VPC");
}
network.setNetworkACLId(acl.getId());
if(_networkDao.update(network.getId(), network)){
return applyACLToNetwork(network.getId());
@ -146,9 +145,6 @@ public class NetworkACLManagerImpl extends ManagerBase implements NetworkACLMana
NetworkACLItemVO newRule = new NetworkACLItemVO(portStart, portEnd, protocol.toLowerCase(), aclId, sourceCidrList, icmpCode, icmpType, trafficType, ruleAction, number);
newRule = _networkACLItemDao.persist(newRule);
//ToDo: Is this required now with number??
//detectNetworkACLConflict(newRule);
if (!_networkACLItemDao.setStateToAdd(newRule)) {
throw new CloudRuntimeException("Unable to update the state to add for " + newRule);
}

View File

@ -20,6 +20,7 @@ import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.Network;
import com.cloud.network.NetworkModel;
import com.cloud.network.Networks;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.network.element.NetworkACLServiceProvider;
@ -46,6 +47,7 @@ import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd;
import org.apache.cloudstack.api.command.user.network.ListNetworkACLsCmd;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -166,14 +168,24 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ
throw new InvalidParameterValueException("Network is not part of a VPC: "+ network.getUuid());
}
Vpc vpc = _vpcMgr.getVpc(acl.getVpcId());
if(vpc == null){
throw new InvalidParameterValueException("Unable to find Vpc associated with the NetworkACL");
if (network.getTrafficType() != Networks.TrafficType.Guest) {
throw new InvalidParameterValueException("Network ACL can be created just for networks of type " + Networks.TrafficType.Guest);
}
_accountMgr.checkAccess(caller, null, true, vpc);
if(network.getVpcId() != acl.getVpcId()){
throw new InvalidParameterValueException("Network: "+networkId+" and ACL: "+aclId+" do not belong to the same VPC");
if(aclId != NetworkACL.DEFAULT_DENY) {
//ACL is not default DENY
// ACL should be associated with a VPC
Vpc vpc = _vpcMgr.getVpc(acl.getVpcId());
if(vpc == null){
throw new InvalidParameterValueException("Unable to find Vpc associated with the NetworkACL");
}
_accountMgr.checkAccess(caller, null, true, vpc);
if(network.getVpcId() != acl.getVpcId()){
throw new InvalidParameterValueException("Network: "+networkId+" and ACL: "+aclId+" do not belong to the same VPC");
}
}
return _networkAclMgr.replaceNetworkACL(acl, network);
}
@ -207,6 +219,12 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ
Account aclOwner = _accountMgr.getAccount(vpc.getAccountId());
_accountMgr.checkAccess(aclOwner, SecurityChecker.AccessType.ModifyEntry, false, acl);
if(aclItemCmd.getNumber() != null){
if(_networkACLItemDao.findByAclAndNumber(aclId, aclItemCmd.getNumber()) != null){
throw new InvalidParameterValueException("ACL item with number "+aclItemCmd.getNumber()+" already exists in ACL: "+acl.getUuid());
}
}
validateNetworkACLItem(aclItemCmd.getSourcePortStart(), aclItemCmd.getSourcePortEnd(), aclItemCmd.getSourceCidrList(),
aclItemCmd.getProtocol(), aclItemCmd.getIcmpCode(), aclItemCmd.getIcmpType(), aclItemCmd.getAction());
@ -238,6 +256,22 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ
}
}
//Validate Protocol
//Check if protocol is a number
if(StringUtils.isNumeric(protocol)){
int protoNumber = Integer.parseInt(protocol);
if(protoNumber < 0 || protoNumber > 255){
throw new InvalidParameterValueException("Invalid protocol number: " + protoNumber);
}
} else {
//Protocol is not number
//Check for valid protocol strings
String supportedProtocols = "tcp,udp,icmp,all";
if(!supportedProtocols.contains(protocol.toLowerCase())){
throw new InvalidParameterValueException("Invalid protocol: " + protocol);
}
}
// icmp code and icmp type can't be passed in for any other protocol rather than icmp
if (!protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (icmpCode != null || icmpType != null)) {
throw new InvalidParameterValueException("Can specify icmpCode and icmpType for ICMP protocol only");

View File

@ -104,7 +104,7 @@ public interface VpcManager extends VpcService{
*/
Network createVpcGuestNetwork(long ntwkOffId, String name, String displayText, String gateway, String cidr,
String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork pNtwk, long zoneId,
ACLType aclType, Boolean subdomainAccess, long vpcId, Account caller)
ACLType aclType, Boolean subdomainAccess, long vpcId, long aclId, Account caller)
throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException;

View File

@ -1940,7 +1940,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
@Override
public Network createVpcGuestNetwork(long ntwkOffId, String name, String displayText, String gateway,
String cidr, String vlanId, String networkDomain, Account owner, Long domainId,
PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, long vpcId, Account caller)
PhysicalNetwork pNtwk, long zoneId, ACLType aclType, Boolean subdomainAccess, long vpcId, long aclId, Account caller)
throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
Vpc vpc = getActiveVpc(vpcId);
@ -1966,7 +1966,10 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
//2) Create network
Network guestNetwork = _ntwkMgr.createGuestNetwork(ntwkOffId, name, displayText, gateway, cidr, vlanId,
networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, null, null);
if(guestNetwork != null){
guestNetwork.setNetworkACLId(aclId);
_ntwkDao.update(guestNetwork.getId(), (NetworkVO)guestNetwork);
}
return guestNetwork;
}

View File

@ -45,6 +45,8 @@ public class NetworkACLItemDaoImpl extends GenericDaoBase<NetworkACLItemVO, Long
AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), Op.EQ);
AllFieldsSearch.and("aclId", AllFieldsSearch.entity().getAclId(), Op.EQ);
AllFieldsSearch.and("trafficType", AllFieldsSearch.entity().getTrafficType(), Op.EQ);
AllFieldsSearch.and("number", AllFieldsSearch.entity().getNumber(), Op.EQ);
AllFieldsSearch.and("action", AllFieldsSearch.entity().getAction(), Op.EQ);
AllFieldsSearch.done();
NotRevokedSearch = createSearchBuilder();
@ -101,4 +103,11 @@ public class NetworkACLItemDaoImpl extends GenericDaoBase<NetworkACLItemVO, Long
return (max == null) ? 0 : max;
}
@Override
public NetworkACLItemVO findByAclAndNumber(long aclId, int number) {
SearchCriteria<NetworkACLItemVO> sc = AllFieldsSearch.create();
sc.setParameters("aclId", aclId);
sc.setParameters("number", number);
return findOneBy(sc);
}
}

View File

@ -303,7 +303,7 @@ public class MockVpcManagerImpl extends ManagerBase implements VpcManager {
*/
@Override
public Network createVpcGuestNetwork(long ntwkOffId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork pNtwk,
long zoneId, ACLType aclType, Boolean subdomainAccess, long vpcId, Account caller) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
long zoneId, ACLType aclType, Boolean subdomainAccess, long vpcId, long aclId, Account caller) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
// TODO Auto-generated method stub
return null;
}

View File

@ -268,7 +268,6 @@ CREATE TABLE `cloud`.`networks` (
`removed` datetime COMMENT 'date removed if not null',
`specify_ip_ranges` int(1) unsigned NOT NULL DEFAULT 0 COMMENT 'true if the network provides an ability to define ip ranges',
`vpc_id` bigint unsigned COMMENT 'vpc this network belongs to',
`network_acl_id` bigint unsigned COMMENT 'network acl id',
PRIMARY KEY (`id`),
CONSTRAINT `fk_networks__network_offering_id` FOREIGN KEY (`network_offering_id`) REFERENCES `network_offerings`(`id`),
CONSTRAINT `fk_networks__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE,

View File

@ -1169,11 +1169,17 @@ CREATE TABLE `cloud`.`network_acl_item` (
`number` int(10) NOT NULL COMMENT 'priority number of the acl item',
`action` varchar(10) NOT NULL COMMENT 'rule action, allow or deny',
PRIMARY KEY (`id`),
UNIQUE KEY (`acl_id`, `number`),
CONSTRAINT `fk_network_acl_item__acl_id` FOREIGN KEY(`acl_id`) REFERENCES `network_acl`(`id`) ON DELETE CASCADE,
CONSTRAINT `uc_network_acl_item__uuid` UNIQUE (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `cloud`.`networks` add column `network_acl_id` bigint unsigned COMMENT 'network acl id';
INSERT INTO `cloud`.`network_acl` values (1, UUID(), 0, "Default Network ACL", "default");
INSERT INTO `cloud`.`network_acl_item` (id, uuid, acl_id, state, protocol, created, traffic_type, cidr, number, action) values (1, UUID(), 1, "Active", "tcp", now(), "Ingress", "0.0.0.0/0", 1, "Deny");
INSERT INTO `cloud`.`network_acl_item` (id, uuid, acl_id, state, protocol, created, traffic_type, cidr, number, action) values (2, UUID(), 1, "Active", "tcp", now(), "Egress", "0.0.0.0/0", 2, "Deny");
INSERT INTO `cloud`.`network_acl` (id, uuid, vpc_id, description, name) values (1, UUID(), 0, "Default Network ACL Deny All", "default_deny");
INSERT INTO `cloud`.`network_acl_item` (id, uuid, acl_id, state, protocol, created, traffic_type, cidr, number, action) values (1, UUID(), 1, "Active", "all", now(), "Ingress", "0.0.0.0/0", 1, "Deny");
INSERT INTO `cloud`.`network_acl_item` (id, uuid, acl_id, state, protocol, created, traffic_type, cidr, number, action) values (2, UUID(), 1, "Active", "all", now(), "Egress", "0.0.0.0/0", 2, "Deny");
INSERT INTO `cloud`.`network_acl` (id, uuid, vpc_id, description, name) values (2, UUID(), 0, "Default Network ACL Allow All", "default_allow");
INSERT INTO `cloud`.`network_acl_item` (id, uuid, acl_id, state, protocol, created, traffic_type, cidr, number, action) values (3, UUID(), 2, "Active", "all", now(), "Ingress", "0.0.0.0/0", 1, "Allow");
INSERT INTO `cloud`.`network_acl_item` (id, uuid, acl_id, state, protocol, created, traffic_type, cidr, number, action) values (4, UUID(), 2, "Active", "all", now(), "Egress", "0.0.0.0/0", 2, "Allow");