server: Adding VPN options for IKE version and IKE split connections (#4953)

IKE version allows selecting ike (autoselect), ikev1, or ikev2.
Split connections gives an option of separating the first right subnet from the rest, and kicking out individual statements for each right subnet for better cross-compatibility.

Backported from PR: #4137
update per PR suggestion

Fixes #3138

Co-authored-by: Greg Goodrich <ggoodrich@ippathways.com>
Co-authored-by: Daan Hoogland <dahn@onecht.net>
Co-authored-by: Pearl Dsilva <pearl.dsilva@shapeblue.com>
This commit is contained in:
Pearl Dsilva 2021-05-05 12:54:23 +05:30 committed by GitHub
parent 7a7fd27350
commit bc80815cf5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 334 additions and 35 deletions

View File

@ -43,5 +43,9 @@ public interface Site2SiteCustomerGateway extends ControlledEntity, Identity, In
public Date getRemoved();
public Boolean getSplitConnections();
public String getIkeVersion();
String getName();
}

View File

@ -629,12 +629,14 @@ public class ApiConstants {
public static final String GUEST_IP = "guestip";
public static final String REMOVED = "removed";
public static final String COMPLETED = "completed";
public static final String IKE_VERSION = "ikeversion";
public static final String IKE_POLICY = "ikepolicy";
public static final String ESP_POLICY = "esppolicy";
public static final String IKE_LIFETIME = "ikelifetime";
public static final String ESP_LIFETIME = "esplifetime";
public static final String DPD = "dpd";
public static final String FORCE_ENCAP = "forceencap";
public static final String SPLIT_CONNECTIONS = "splitconnections";
public static final String FOR_VPC = "forvpc";
public static final String SHRINK_OK = "shrinkok";
public static final String NICIRA_NVP_DEVICE_ID = "nvpdeviceid";

View File

@ -92,6 +92,13 @@ public class CreateVpnCustomerGatewayCmd extends BaseAsyncCmd {
description = "create site-to-site VPN customer gateway for the project", since = "4.6")
private Long projectId;
@Parameter(name = ApiConstants.SPLIT_CONNECTIONS, type = CommandType.BOOLEAN, required = false, description = "For IKEv2, whether to split multiple right subnet cidrs into multiple connection statements.")
private Boolean splitConnections;
@Parameter(name = ApiConstants.IKE_VERSION, type = CommandType.STRING, required = false, description = "Which IKE Version to use, one of ike (autoselect), ikev1, or ikev2. " +
"Connections marked with 'ike' will use 'ikev2' when initiating, but accept any protocol version when responding. Defaults to ike")
private String ikeVersion;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -146,6 +153,14 @@ public class CreateVpnCustomerGatewayCmd extends BaseAsyncCmd {
return projectId;
}
public Boolean getSplitConnections() {
return splitConnections;
}
public String getIkeVersion() {
return ikeVersion;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -94,6 +94,13 @@ public class UpdateVpnCustomerGatewayCmd extends BaseAsyncCmd {
+ "gateway associated with the account for the specified domain.")
private Long domainId;
@Parameter(name = ApiConstants.SPLIT_CONNECTIONS, type = CommandType.BOOLEAN, required = false, description = "For IKEv2, whether to split multiple right subnet cidrs into multiple connection statements.")
private Boolean splitConnections;
@Parameter(name = ApiConstants.IKE_VERSION, type = CommandType.STRING, required = false, description = "Which IKE Version to use, one of ike (autoselect), ikev1, or ikev2." +
"Connections marked with 'ike' will use 'ikev2' when initiating, but accept any protocol version when responding. Defaults to ike")
private String ikeVersion;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -140,6 +147,14 @@ public class UpdateVpnCustomerGatewayCmd extends BaseAsyncCmd {
public Boolean getEncap() { return encap; }
public boolean getSplitConnections() {
return null == splitConnections ? false : splitConnections;
}
public String getIkeVersion() {
return ikeVersion;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -102,6 +102,14 @@ public class Site2SiteCustomerGatewayResponse extends BaseResponse implements Co
@Param(description = "the date and time the host was removed")
private Date removed;
@SerializedName(ApiConstants.SPLIT_CONNECTIONS)
@Param(description = "For IKEv2, whether to split multiple right subnet cidrs into multiple connection statements.")
private Boolean splitConnections;
@SerializedName(ApiConstants.IKE_VERSION)
@Param(description = "Which IKE Version to use, one of ike (autoselect), ikev1, or ikev2. Defaults to ike")
private String ikeVersion;
public void setId(String id) {
this.id = id;
}
@ -148,6 +156,14 @@ public class Site2SiteCustomerGatewayResponse extends BaseResponse implements Co
public void setEncap(Boolean encap) { this.encap = encap; }
public void setSplitConnections(Boolean splitConnections) {
this.splitConnections = splitConnections;
}
public void setIkeVersion(String ikeVersion) {
this.ikeVersion = ikeVersion;
}
public void setRemoved(Date removed) {
this.removed = removed;
}

View File

@ -132,6 +132,14 @@ public class Site2SiteVpnConnectionResponse extends BaseResponse implements Cont
@Param(description = "is connection for display to the regular user", since = "4.4", authorized = {RoleType.Admin})
private Boolean forDisplay;
@SerializedName(ApiConstants.SPLIT_CONNECTIONS)
@Param(description = "Split multiple remote networks into multiple phase 2 SAs. Often used with Cisco some products.")
private Boolean splitConnections;
@SerializedName(ApiConstants.IKE_VERSION)
@Param(description = "Which IKE Version to use, one of ike (autoselect), ikev1, or ikev2. Defaults to ike")
private String ikeVersion;
public void setId(String id) {
this.id = id;
}
@ -200,6 +208,14 @@ public class Site2SiteVpnConnectionResponse extends BaseResponse implements Cont
this.removed = removed;
}
public void setSplitConnections(Boolean splitConnections) {
this.splitConnections = splitConnections;
}
public void setIkeVersion(String ikeVersion) {
this.ikeVersion = ikeVersion;
}
@Override
public void setAccountName(String accountName) {
this.accountName = accountName;

View File

@ -35,6 +35,8 @@ public class Site2SiteVpnCfgCommand extends NetworkElementCommand {
private boolean dpd;
private boolean passive;
private boolean encap;
private boolean splitConnections;
private String ikeVersion;
@Override
public boolean executeInSequence() {
@ -46,7 +48,8 @@ public class Site2SiteVpnCfgCommand extends NetworkElementCommand {
}
public Site2SiteVpnCfgCommand(boolean create, String localPublicIp, String localPublicGateway, String localGuestCidr, String peerGatewayIp, String peerGuestCidrList,
String ikePolicy, String espPolicy, String ipsecPsk, Long ikeLifetime, Long espLifetime, Boolean dpd, boolean passive, boolean encap) {
String ikePolicy, String espPolicy, String ipsecPsk, Long ikeLifetime, Long espLifetime, Boolean dpd, boolean passive, boolean encap,
boolean splitConnections, String ikeVersion) {
this.create = create;
this.setLocalPublicIp(localPublicIp);
this.setLocalPublicGateway(localPublicGateway);
@ -61,6 +64,8 @@ public class Site2SiteVpnCfgCommand extends NetworkElementCommand {
this.dpd = dpd;
this.passive = passive;
this.encap = encap;
this.splitConnections = splitConnections;
this.ikeVersion = ikeVersion;
}
public boolean isCreate() {
@ -174,4 +179,20 @@ public class Site2SiteVpnCfgCommand extends NetworkElementCommand {
public void setPassive(boolean passive) {
this.passive = passive;
}
public boolean getSplitConnections() {
return splitConnections;
}
public void setSplitConnections(boolean splitConnections) {
this.splitConnections = splitConnections;
}
public String getIkeVersion() {
return ikeVersion;
}
public void setIkeVersion(String ikeVersion) {
this.ikeVersion = ikeVersion;
}
}

View File

@ -36,7 +36,7 @@ public class Site2SiteVpnConfigItem extends AbstractConfigItemFacade {
final Site2SiteVpn site2siteVpn = new Site2SiteVpn(command.getLocalPublicIp(), command.getLocalGuestCidr(), command.getLocalPublicGateway(), command.getPeerGatewayIp(),
command.getPeerGuestCidrList(), command.getEspPolicy(), command.getIkePolicy(), command.getIpsecPsk(), command.getIkeLifetime(), command.getEspLifetime(), command.isCreate(), command.getDpd(),
command.isPassive(), command.getEncap());
command.isPassive(), command.getEncap(), command.getSplitConnections(), command.getIkeVersion());
return generateConfigItems(site2siteVpn);
}

View File

@ -21,9 +21,9 @@ package com.cloud.agent.resource.virtualnetwork.model;
public class Site2SiteVpn extends ConfigBase {
private String localPublicIp, localGuestCidr, localPublicGateway, peerGatewayIp, peerGuestCidrList, espPolicy, ikePolicy, ipsecPsk;
private String localPublicIp, localGuestCidr, localPublicGateway, peerGatewayIp, peerGuestCidrList, espPolicy, ikePolicy, ipsecPsk, ikeVersion;
private Long ikeLifetime, espLifetime;
private boolean create, dpd, passive, encap;
private boolean create, dpd, passive, encap, splitConnections;
public Site2SiteVpn() {
super(ConfigBase.SITE2SITEVPN);
@ -31,7 +31,7 @@ public class Site2SiteVpn extends ConfigBase {
public Site2SiteVpn(String localPublicIp, String localGuestCidr, String localPublicGateway, String peerGatewayIp, String peerGuestCidrList, String espPolicy,
String ikePolicy,
String ipsecPsk, Long ikeLifetime, Long espLifetime, boolean create, Boolean dpd, boolean passive, boolean encap) {
String ipsecPsk, Long ikeLifetime, Long espLifetime, boolean create, Boolean dpd, boolean passive, boolean encap, boolean splitConnections, String ikeVersion) {
super(ConfigBase.SITE2SITEVPN);
this.localPublicIp = localPublicIp;
this.localGuestCidr = localGuestCidr;
@ -47,6 +47,8 @@ public class Site2SiteVpn extends ConfigBase {
this.dpd = dpd;
this.passive = passive;
this.encap = encap;
this.splitConnections = splitConnections;
this.ikeVersion = ikeVersion;
}
public String getLocalPublicIp() {
@ -161,4 +163,20 @@ public class Site2SiteVpn extends ConfigBase {
this.encap = encap;
}
public boolean getSplitConnections() {
return splitConnections;
}
public void setSplitConnections(boolean splitConnections) {
this.splitConnections = splitConnections;
}
public String getIkeVersion() {
return ikeVersion;
}
public void setIkeVersion(String ikeVersion) {
this.ikeVersion = ikeVersion;
}
}

View File

@ -495,17 +495,17 @@ public class VirtualRoutingResourceTest implements VirtualRouterDeployer {
public void testSite2SiteVpnCfgCommand() {
_count = 0;
Site2SiteVpnCfgCommand cmd = new Site2SiteVpnCfgCommand(true, "64.10.1.10", "64.10.1.1", "192.168.1.1/16", "124.10.1.10", "192.168.100.1/24", "3des-sha1,aes128-sha1;modp1536", "3des-sha1,aes128-md5", "psk", Long.valueOf(1800), Long.valueOf(1800), true, false, false);
Site2SiteVpnCfgCommand cmd = new Site2SiteVpnCfgCommand(true, "64.10.1.10", "64.10.1.1", "192.168.1.1/16", "124.10.1.10", "192.168.100.1/24", "3des-sha1,aes128-sha1;modp1536", "3des-sha1,aes128-md5", "psk", Long.valueOf(1800), Long.valueOf(1800), true, false, false, false, "ike");
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, ROUTERNAME);
Answer answer = _resource.executeRequest(cmd);
assertTrue(answer.getResult());
cmd = new Site2SiteVpnCfgCommand(true, "64.10.1.10", "64.10.1.1", "192.168.1.1/16", "124.10.1.10", "192.168.100.1/24", "3des-sha1,aes128-sha1;modp1536", "3des-sha1,aes128-md5", "psk", Long.valueOf(1800), Long.valueOf(1800), false, true, false);
cmd = new Site2SiteVpnCfgCommand(true, "64.10.1.10", "64.10.1.1", "192.168.1.1/16", "124.10.1.10", "192.168.100.1/24", "3des-sha1,aes128-sha1;modp1536", "3des-sha1,aes128-md5", "psk", Long.valueOf(1800), Long.valueOf(1800), false, true, false, false, "ike");
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, ROUTERNAME);
answer = _resource.executeRequest(cmd);
assertTrue(answer.getResult());
cmd = new Site2SiteVpnCfgCommand(false, "64.10.1.10", "64.10.1.1", "192.168.1.1/16", "124.10.1.10", "192.168.100.1/24", "3des-sha1,aes128-sha1;modp1536", "3des-sha1,aes128-md5", "psk", Long.valueOf(1800), Long.valueOf(1800), false, true, false);
cmd = new Site2SiteVpnCfgCommand(false, "64.10.1.10", "64.10.1.1", "192.168.1.1/16", "124.10.1.10", "192.168.100.1/24", "3des-sha1,aes128-sha1;modp1536", "3des-sha1,aes128-md5", "psk", Long.valueOf(1800), Long.valueOf(1800), false, true, false, false, "ike");
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, ROUTERNAME);
answer = _resource.executeRequest(cmd);
assertTrue(answer.getResult());

View File

@ -79,6 +79,12 @@ public class Site2SiteCustomerGatewayVO implements Site2SiteCustomerGateway {
@Column(name = "account_id")
private Long accountId;
@Column(name = "split_connections")
private boolean splitConnections;
@Column(name = "ike_version")
private String ikeVersion;
@Column(name = GenericDao.REMOVED_COLUMN)
private Date removed;
@ -86,7 +92,7 @@ public class Site2SiteCustomerGatewayVO implements Site2SiteCustomerGateway {
}
public Site2SiteCustomerGatewayVO(String name, long accountId, long domainId, String gatewayIp, String guestCidrList, String ipsecPsk, String ikePolicy,
String espPolicy, long ikeLifetime, long espLifetime, boolean dpd, boolean encap) {
String espPolicy, long ikeLifetime, long espLifetime, boolean dpd, boolean encap, boolean splitConnections, String ikeVersion) {
this.name = name;
this.gatewayIp = gatewayIp;
this.guestCidrList = guestCidrList;
@ -100,6 +106,8 @@ public class Site2SiteCustomerGatewayVO implements Site2SiteCustomerGateway {
uuid = UUID.randomUUID().toString();
this.accountId = accountId;
this.domainId = domainId;
this.splitConnections = splitConnections;
this.ikeVersion = ikeVersion;
}
@Override
@ -221,6 +229,24 @@ public class Site2SiteCustomerGatewayVO implements Site2SiteCustomerGateway {
return accountId;
}
@Override
public Boolean getSplitConnections() {
return splitConnections;
}
public void setSplitConnections(Boolean splitConnections) {
this.splitConnections = splitConnections;
}
@Override
public String getIkeVersion() {
return ikeVersion;
}
public void setIkeVersion(String ikeVersion) {
this.ikeVersion = ikeVersion;
}
@Override
public Class<?> getEntityType() {
return Site2SiteCustomerGateway.class;

View File

@ -56,7 +56,8 @@ INSERT IGNORE INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervis
INSERT INTO `cloud`.`guest_os` (id, uuid, category_id, display_name, created) VALUES (335, UUID(), 10, 'Ubuntu 20.04 LTS', now());
INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'Xenserver', '8.2.0', 'Ubuntu Focal Fossa 20.04', 330, now(), 0);
-------------------------------------------------------------------------------------------------------------
ALTER TABLE `cloud`.`s2s_customer_gateway` ADD COLUMN `ike_version` varchar(5) NOT NULL DEFAULT 'ike' COMMENT 'one of ike, ikev1, ikev2';
ALTER TABLE `cloud`.`s2s_customer_gateway` ADD COLUMN `split_connections` int(1) NOT NULL DEFAULT 0;
-- Add support for VMware 7.0
INSERT IGNORE INTO `cloud`.`hypervisor_capabilities` (uuid, hypervisor_type, hypervisor_version, max_guests_limit, security_group_enabled, max_data_volumes_limit, max_hosts_per_cluster, storage_motion_supported, vm_snapshot_enabled) values (UUID(), 'VMware', '7.0', 1024, 0, 59, 64, 1, 1);
@ -131,4 +132,3 @@ INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_vers
-- Add support for windows2019srvNext_64Guest from VMware 7.0.1.0
INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) VALUES (UUID(),'VMware', '7.0.1.0', 'windows2019srvNext_64Guest', 276, now(), 0);

View File

@ -3251,6 +3251,8 @@ public class ApiResponseHelper implements ResponseGenerator {
response.setDpd(result.getDpd());
response.setEncap(result.getEncap());
response.setRemoved(result.getRemoved());
response.setIkeVersion(result.getIkeVersion());
response.setSplitConnections(result.getSplitConnections());
response.setObjectName("vpncustomergateway");
populateAccount(response, result.getAccountId());
@ -3290,6 +3292,8 @@ public class ApiResponseHelper implements ResponseGenerator {
response.setEspLifetime(customerGateway.getEspLifetime());
response.setDpd(customerGateway.getDpd());
response.setEncap(customerGateway.getEncap());
response.setIkeVersion(customerGateway.getIkeVersion());
response.setSplitConnections(customerGateway.getSplitConnections());
}
}

View File

@ -944,9 +944,11 @@ public class CommandSetupHelper {
final Long espLifetime = gw.getEspLifetime();
final Boolean dpd = gw.getDpd();
final Boolean encap = gw.getEncap();
final Boolean splitConnections = gw.getSplitConnections();
final String ikeVersion = gw.getIkeVersion();
final Site2SiteVpnCfgCommand cmd = new Site2SiteVpnCfgCommand(isCreate, localPublicIp, localPublicGateway, localGuestCidr, peerGatewayIp, peerGuestCidrList, ikePolicy,
espPolicy, ipsecPsk, ikeLifetime, espLifetime, dpd, conn.isPassive(), encap);
espPolicy, ipsecPsk, ikeLifetime, espLifetime, dpd, conn.isPassive(), encap, splitConnections, ikeVersion);
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId()));
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId()));
cmd.setAccessDetail(NetworkElementCommand.ROUTER_NAME, router.getInstanceName());

View File

@ -45,6 +45,7 @@ import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.Site2SiteCustomerGateway;
import com.cloud.network.Site2SiteVpnConnection;
@ -229,10 +230,20 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
throw new InvalidParameterValueException("The customer gateway with name " + name + " already existed!");
}
Boolean splitConnections = cmd.getSplitConnections();
if (splitConnections == null) {
splitConnections = false;
}
String ikeVersion = cmd.getIkeVersion();
if (ikeVersion == null) {
ikeVersion = "ike";
}
checkCustomerGatewayCidrList(peerCidrList);
Site2SiteCustomerGatewayVO gw =
new Site2SiteCustomerGatewayVO(name, accountId, owner.getDomainId(), gatewayIp, peerCidrList, ipsecPsk, ikePolicy, espPolicy, ikeLifetime, espLifetime, dpd, encap);
new Site2SiteCustomerGatewayVO(name, accountId, owner.getDomainId(), gatewayIp, peerCidrList, ipsecPsk, ikePolicy, espPolicy, ikeLifetime, espLifetime, dpd, encap, splitConnections, ikeVersion);
_customerGatewayDao.persist(gw);
return gw;
}
@ -419,14 +430,6 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
}
_accountMgr.checkAccess(caller, null, false, gw);
List<Site2SiteVpnConnectionVO> conns = _vpnConnectionDao.listByCustomerGatewayId(id);
if (conns != null) {
for (Site2SiteVpnConnection conn : conns) {
if (conn.getState() != State.Error) {
throw new InvalidParameterValueException("Unable to update customer gateway with connections in non-Error state!");
}
}
}
String name = cmd.getName();
String gatewayIp = cmd.getGatewayIp();
@ -476,6 +479,10 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
encap = false;
}
Boolean splitConnections = cmd.getSplitConnections();
String ikeVersion = cmd.getIkeVersion();
checkCustomerGatewayCidrList(guestCidrList);
long accountId = gw.getAccountId();
@ -494,10 +501,47 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn
gw.setEspLifetime(espLifetime);
gw.setDpd(dpd);
gw.setEncap(encap);
gw.setSplitConnections(splitConnections);
if (ikeVersion != null) {
gw.setIkeVersion(ikeVersion);
}
_customerGatewayDao.persist(gw);
setupVpnConnection(caller, id);
return gw;
}
private void setupVpnConnection(Account caller, Long vpnCustomerGwIp) {
List<Site2SiteVpnConnectionVO> conns = _vpnConnectionDao.listByCustomerGatewayId(vpnCustomerGwIp);
if (conns != null) {
for (Site2SiteVpnConnection conn : conns) {
try {
_accountMgr.checkAccess(caller, null, false, conn);
} catch (PermissionDeniedException e) {
// Just don't restart this connection, as the user has no rights to it
// Maybe should issue a notification to the system?
s_logger.info("Site2SiteVpnManager:updateCustomerGateway() Not resetting VPN connection " + conn.getId() + " as user lacks permission");
continue;
}
if (conn.getState() == State.Pending) {
// Vpn connection cannot be reset when the state is Pending
continue;
}
try {
if (conn.getState() == State.Connected || conn.getState() == State.Error) {
stopVpnConnection(conn.getId());
}
startVpnConnection(conn.getId());
} catch (ResourceUnavailableException e) {
// Should never get here, as we are looping on the actual connections, but we must handle it regardless
s_logger.warn("Failed to update VPN connection");
}
}
}
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_S2S_VPN_CONNECTION_DELETE, eventDescription = "deleting s2s vpn connection", create = true)
public boolean deleteVpnConnection(DeleteVpnConnectionCmd cmd) throws ResourceUnavailableException {

View File

@ -278,7 +278,7 @@ public class VirtualNetworkApplianceManagerImplTest {
conns.add(conn);
conns.add(conn1);
Site2SiteCustomerGatewayVO gw = new Site2SiteCustomerGatewayVO("Testing gateway", 1L, 1L, "192.168.50.15", "Guest List", "ipsecPsk", "ikePolicy", "espPolicy", 1L, 1L, true, true);
Site2SiteCustomerGatewayVO gw = new Site2SiteCustomerGatewayVO("Testing gateway", 1L, 1L, "192.168.50.15", "Guest List", "ipsecPsk", "ikePolicy", "espPolicy", 1L, 1L, true, true, false, "ike");
HostVO hostVo = new HostVO(1L, "Testing host", Host.Type.Routing, "192.168.50.15", "privateNetmask", "privateMacAddress", "publicIpAddress", "publicNetmask", "publicMacAddress", "storageIpAddress", "storageNetmask", "storageMacAddress", "deuxStorageIpAddress", "duxStorageNetmask", "deuxStorageMacAddress", "guid", Status.Up, "version", "iqn", new Date() , 1L, 1L, 1L, 1L, "parent", 20L, Storage.StoragePoolType.Gluster);
hostVo.setManagementServerId(ManagementServerNode.getManagementServerId());

View File

@ -556,10 +556,18 @@ class CsSite2SiteVpn(CsDataBag):
vpnsecretsfile = "%s/ipsec.vpn-%s.secrets" % (self.VPNCONFDIR, rightpeer)
ikepolicy = obj['ike_policy'].replace(';', '-')
esppolicy = obj['esp_policy'].replace(';', '-')
splitconnections = obj['split_connections'] if 'split_connections' in obj else False
ikeversion = obj['ike_version'] if 'ike_version' in obj and obj['ike_version'].lower() in ('ike', 'ikev1', 'ikev2') else 'ike'
peerlistarr = peerlist.split(',')
if splitconnections:
logging.debug('Splitting rightsubnets %s' % peerlistarr)
peerlist = peerlistarr[0]
if rightpeer in self.confips:
self.confips.remove(rightpeer)
file = CsFile(vpnconffile)
file.repopulate() # This avoids issues when switching off split_connections or removing subnets with split_connections == true
file.add("#conn for vpn-%s" % rightpeer, 0)
file.search("conn ", "conn vpn-%s" % rightpeer)
file.addeq(" left=%s" % leftpeer)
@ -568,7 +576,7 @@ class CsSite2SiteVpn(CsDataBag):
file.addeq(" rightsubnet=%s" % peerlist)
file.addeq(" type=tunnel")
file.addeq(" authby=secret")
file.addeq(" keyexchange=ike")
file.addeq(" keyexchange=%s" % ikeversion)
file.addeq(" ike=%s" % ikepolicy)
file.addeq(" ikelifetime=%s" % self.convert_sec_to_h(obj['ike_lifetime']))
file.addeq(" esp=%s" % esppolicy)
@ -582,6 +590,14 @@ class CsSite2SiteVpn(CsDataBag):
file.addeq(" dpddelay=30")
file.addeq(" dpdtimeout=120")
file.addeq(" dpdaction=restart")
if splitconnections and peerlistarr.count > 1:
logging.debug('Splitting connections for rightsubnets %s' % peerlistarr)
for peeridx in range(1, len(peerlistarr)):
logging.debug('Adding split connection -%d for subnet %s' % (peeridx + 1, peerlistarr[peeridx]))
file.append('')
file.search('conn vpn-.*-%d' % (peeridx + 1), "conn vpn-%s-%d" % (rightpeer, peeridx + 1))
file.append(' also=vpn-%s' % rightpeer)
file.append(' rightsubnet=%s' % peerlistarr[peeridx])
secret = CsFile(vpnsecretsfile)
secret.search("%s " % leftpeer, "%s %s : PSK \"%s\"" % (leftpeer, rightpeer, obj['ipsec_psk']))
if secret.is_changed() or file.is_changed():
@ -595,14 +611,25 @@ class CsSite2SiteVpn(CsDataBag):
os.chmod(vpnsecretsfile, 0400)
for i in xrange(3):
result = CsHelper.execute('ipsec status vpn-%s | grep "%s"' % (rightpeer, peerlist.split(",", 1)[0]))
if len(result) > 0:
done = True
for peeridx in range(0, len(peerlistarr)):
# Check for the proper connection and subnet
conn = rightpeer if not splitconnections else rightpeer if peeridx == 0 else '%s-%d' % (rightpeer, peeridx + 1)
result = CsHelper.execute('ipsec status vpn-%s | grep "%s"' % (conn, peerlistarr[peeridx]))
# If any of the peers hasn't yet finished, continue the outer loop
if len(result) == 0:
done = False
if done:
break
time.sleep(1)
# With 'auto=route', connections are established on an attempt to
# communicate over the S2S VPN. This uses ping to initialize the connection.
CsHelper.execute("timeout 5 ping -c 3 %s" % (peerlist.split("/", 1)[0].replace(".0", ".1")))
for peer in peerlistarr:
octets = peer.split('/', 1)[0].split('.')
octets[3] = str((int(octets[3]) + 1))
ipinsubnet = '.'.join(octets)
CsHelper.execute("timeout 5 ping -c 3 %s" % ipinsubnet)
def convert_sec_to_h(self, val):
hrs = int(val) / 3600

View File

@ -23,7 +23,7 @@ vpnoutmark="0x525"
vpninmark="0x524"
usage() {
printf "Usage: %s: (-A|-D) -l <left-side vpn peer> -n <left-side guest cidr> -g <left-side next hop> -r <right-side vpn peer> -N <right-side private subnets> -e <esp policy> -i <ike policy> -t <ike lifetime> -T <esp lifetime> -s <pre-shared secret> -d <dpd 0 or 1> [ -p <passive or not> -c <check if up on creation> -S <disable vpn ports iptables> ]\n" $(basename $0) >&2
printf "Usage: %s: (-A|-D) -l <left-side vpn peer> -n <left-side guest cidr> -g <left-side next hop> -r <right-side vpn peer> -N <right-side private subnets> -e <esp policy> -i <ike policy> -t <ike lifetime> -T <esp lifetime> -s <pre-shared secret> -d <dpd 0 or 1> [ -p <passive or not> -c <check if up on creation> -S <disable vpn ports iptables> -C <ike split connections or not, default not> -v <ike version, default:'ike'> ]\n" $(basename $0) >&2
}
#set -x
@ -139,14 +139,21 @@ ipsec_tunnel_add() {
check_and_enable_iptables
rsubnets=" rightsubnets={$rightnets}"
if [ $splitconnections -eq 1 ]
then
rsubnetarr=(${rightnets})
rsubnets=" rightsubnet=${rsubnetarr[0]}"
fi
sudo echo "conn vpn-$rightpeer" > $vpnconffile &&
sudo echo " left=$leftpeer" >> $vpnconffile &&
sudo echo " leftsubnet=$leftnet" >> $vpnconffile &&
sudo echo " right=$rightpeer" >> $vpnconffile &&
sudo echo " rightsubnets={$rightnets}" >> $vpnconffile &&
sudo echo $rsubnets >> $vpnconffile &&
sudo echo " type=tunnel" >> $vpnconffile &&
sudo echo " authby=secret" >> $vpnconffile &&
sudo echo " keyexchange=ike" >> $vpnconffile &&
sudo echo " keyexchange=${ikeversion:-ike}" >> $vpnconffile &&
sudo echo " ike=$ikepolicy" >> $vpnconffile &&
sudo echo " ikelifetime=${ikelifetime}s" >> $vpnconffile &&
sudo echo " esp=$esppolicy" >> $vpnconffile &&
@ -163,6 +170,20 @@ ipsec_tunnel_add() {
sudo echo " dpdaction=restart" >> $vpnconffile
fi
if [ $splitconnections -eq 1 ]
then
# Split out all but the first right subnet into their own statements
subnetidx=2
for rsubnet in ${rsubnetarr[@]:1}; do
sudo echo "" >> $vpnconffile &&
sudo echo "conn vpn-$rightpeer-$subnetidx" >> $vpnconffile &&
sudo echo " also=vpn-$rightpeer" >> $vpnconffile &&
sudo echo " auto=route" >> $vpnconffile &&
sudo echo " rightsubnet=$rsubnet" >> $vpnconffile
((++subnetidx))
done
fi
enable_iptables_subnets
sudo ipsec auto --rereadall
@ -215,8 +236,10 @@ passive=0
op=""
checkup=0
secure=1
ikeversion="ike"
splitconnections=0
while getopts 'ADSpcl:n:g:r:N:e:i:t:T:s:d:' OPTION
while getopts 'ACDSpcl:n:g:r:N:e:i:t:T:s:d:v:' OPTION
do
case $OPTION in
A) opflag=1
@ -243,6 +266,8 @@ do
e) eflag=1
esppolicy="$OPTARG"
;;
v) ikeversion="$OPTARG"
;;
i) iflag=1
ikepolicy="$OPTARG"
;;
@ -264,6 +289,8 @@ do
;;
S) secure=0
;;
C) splitconnections=1
;;
?) usage
exit 2
;;

View File

@ -828,6 +828,7 @@
"label.icmpcode": "ICMP Code",
"label.icmptype": "ICMP Type",
"label.id": "ID",
"label.ike.version": "IKE Version",
"label.ikedh": "IKE DH",
"label.ikeencryption": "IKE Encryption",
"label.ikehash": "IKE Hash",
@ -897,6 +898,7 @@
"label.ipaddress2": "IP Address",
"label.iplimit": "Public IP Limits",
"label.ips": "IPs",
"label.ipsec.splitconnections": "Split Connections",
"label.ipsecpsk": "IPsec Preshared-Key",
"label.iptotal": "Total of IP Addresses",
"label.ipv4.cidr": "IPv4 CIDR",

View File

@ -1026,11 +1026,13 @@
"label.icmptype.start.port": "ICMP Type / Start Port",
"label.id": "ID",
"label.identity.and.access": "Identity and Access",
"label.ike.version": "IKE Version",
"label.ikedh": "IKE DH",
"label.ikeencryption": "IKE Encryption",
"label.ikehash": "IKE Hash",
"label.ikelifetime": "IKE lifetime (second)",
"label.ikepolicy": "IKE policy",
"label.ikeversion": "IKE Version",
"label.images": "Images",
"label.import.backup.offering": "Import Backup Offering",
"label.import.offering": "Import Offering",
@ -1106,6 +1108,7 @@
"label.ipaddress2": "IP Address",
"label.iplimit": "Public IP Limits",
"label.ips": "IPs",
"label.ipsec.splitconnections": "Split Connections",
"label.ipsecpsk": "IPsec Preshared-Key",
"label.iptotal": "Total of IP Addresses",
"label.ipv4.cidr": "IPv4 CIDR",
@ -1973,6 +1976,7 @@
"label.specify.vxlan": "Specify VXLAN",
"label.specifyipranges": "Specify IP ranges",
"label.specifyvlan": "Specify VLAN",
"label.splitconnections": "Split Connections",
"label.sr.name": "SR Name-Label",
"label.srx": "SRX",
"label.srx.details": "SRX details",

View File

@ -828,6 +828,7 @@
"label.icmpcode": "Codice ICMP",
"label.icmptype": "Tipo ICMP",
"label.id": "ID",
"label.ike.version": "Versione di IKE",
"label.ikedh": "DH di IKE",
"label.ikeencryption": "Encryption di IKE",
"label.ikehash": "Hash di IKE",
@ -897,6 +898,7 @@
"label.ipaddress2": "Indirizzo IP",
"label.iplimit": "Public IP Limits",
"label.ips": "Indirizzi IP",
"label.ipsec.splitconnections": "Connessioni Divise",
"label.ipsecpsk": "Preshared-Key di IPsec",
"label.iptotal": "Total of IP Addresses",
"label.ipv4.cidr": "IPv4 CIDR",

View File

@ -828,6 +828,7 @@
"label.icmpcode": "ICMP-kode",
"label.icmptype": "ICMP-type",
"label.id": "ID",
"label.ike.version": "IKE versjon",
"label.ikedh": "IKE DH",
"label.ikeencryption": "IKE kryptering",
"label.ikehash": "IKE Hash",
@ -897,6 +898,7 @@
"label.ipaddress2": "IP-adresse",
"label.iplimit": "Offentlig IP-addresse Grenser",
"label.ips": "IPer",
"label.ipsec.splitconnections": "delte forbindelser",
"label.ipsecpsk": "IPSec Delt N\u00f8kkel",
"label.iptotal": "Totalt IP-adresser",
"label.ipv4.cidr": "IPv4 CIDR",

View File

@ -828,6 +828,7 @@
"label.icmpcode": "ICMP Code",
"label.icmptype": "ICMP Type",
"label.id": "ID",
"label.ike.version": "IKE Versie",
"label.ikedh": "IKE DH",
"label.ikeencryption": "IKE Encryptie",
"label.ikehash": "IKE Hash",
@ -897,6 +898,7 @@
"label.ipaddress2": "IP Adres",
"label.iplimit": "Publieke IP Limieten",
"label.ips": "IPs",
"label.ipsec.splitconnections": "Gesplitste Verbindingen",
"label.ipsecpsk": "IPsec Preshared-Key",
"label.iptotal": "totaal aantal IP adressen",
"label.ipv4.cidr": "IPv4 CIDR",

View File

@ -828,6 +828,7 @@
"label.icmpcode": "ICMP Code",
"label.icmptype": "ICMP Type",
"label.id": "ID",
"label.ike.version": "IKE Version",
"label.ikedh": "IKE DH",
"label.ikeencryption": "IKE Encryption",
"label.ikehash": "IKE Hash",
@ -897,6 +898,7 @@
"label.ipaddress2": "IP Address",
"label.iplimit": "Public IP Limits",
"label.ips": "IP",
"label.ipsec.splitconnections": "Split Connections",
"label.ipsecpsk": "IPsec Preshared-Key",
"label.iptotal": "Total of IP Addresses",
"label.ipv4.cidr": "IPv4 CIDR",

View File

@ -407,7 +407,7 @@ export default {
hidden: true,
permission: ['listVpnConnections'],
columns: ['publicip', 'state', 'gateway', 'ipsecpsk', 'ikepolicy', 'esppolicy'],
details: ['publicip', 'gateway', 'passive', 'cidrlist', 'ipsecpsk', 'ikepolicy', 'esppolicy', 'ikelifetime', 'esplifetime', 'dpd', 'forceencap', 'created'],
details: ['publicip', 'gateway', 'passive', 'cidrlist', 'ipsecpsk', 'ikepolicy', 'esppolicy', 'ikelifetime', 'ikeversion', 'esplifetime', 'dpd', 'splitconnections', 'forceencap', 'created'],
actions: [
{
api: 'createVpnConnection',
@ -593,7 +593,7 @@ export default {
icon: 'lock',
permission: ['listVpnCustomerGateways'],
columns: ['name', 'gateway', 'cidrlist', 'ipsecpsk', 'account'],
details: ['name', 'id', 'gateway', 'cidrlist', 'ipsecpsk', 'ikepolicy', 'ikelifetime', 'esppolicy', 'esplifetime', 'dpd', 'forceencap', 'account', 'domain'],
details: ['name', 'id', 'gateway', 'cidrlist', 'ipsecpsk', 'ikepolicy', 'ikelifetime', 'ikeversion', 'esppolicy', 'esplifetime', 'dpd', 'splitconnections', 'forceencap', 'account', 'domain'],
searchFilters: ['keyword', 'domainid', 'account'],
actions: [
{
@ -611,7 +611,12 @@ export default {
label: 'label.edit',
docHelp: 'adminguide/networking_and_traffic.html#updating-and-removing-a-vpn-customer-gateway',
dataView: true,
args: ['name', 'gateway', 'cidrlist', 'ipsecpsk', 'ikepolicy', 'ikelifetime', 'esppolicy', 'esplifetime', 'dpd', 'forceencap']
args: ['name', 'gateway', 'cidrlist', 'ipsecpsk', 'ikepolicy', 'ikelifetime', 'ikeversion', 'esppolicy', 'esplifetime', 'dpd', 'splitconnections', 'forceencap'],
mapping: {
ikeversion: {
options: ['ike', 'ikev1', 'ikev2']
}
}
},
{
api: 'deleteVpnCustomerGateway',

View File

@ -108,6 +108,26 @@
</a-select-option>
</a-select>
</a-form-item>
<a-form-item>
<span slot="label">
{{ $t('label.ikeversion') }}
<a-tooltip :title="apiParams.ikeversion.description">
<a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
</a-tooltip>
</span>
<a-select
v-decorator="[
'ikeversion',
{
initialValue: 'ike',
},
]"
@change="val => { ikeversion = val }">
<a-select-option :value="vers" v-for="(vers, idx) in ikeVersions" :key="idx">
{{ vers }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item
:label="$t('label.ikedh')">
<a-select
@ -218,6 +238,21 @@
},
]"/>
</a-form-item>
<a-form-item v-if="ikeversion !== 'ikev1'">
<span slot="label">
{{ $t('label.splitconnections') }}
<a-tooltip :title="apiParams.splitconnections.description">
<a-icon type="info-circle" style="color: rgba(0,0,0,.45)" />
</a-tooltip>
</span>
<a-switch
v-decorator="[
'splitconnections',
{
initialValue: 'false',
},
]"/>
</a-form-item>
<a-form-item>
<span slot="label">
{{ $t('label.forceencap') }}
@ -270,6 +305,11 @@ export default {
'sha512',
'md5'
],
ikeVersions: [
'ike',
'ikev1',
'ikev2'
],
DHGroups: {
'': 'None',
'Group 2': 'modp1024',
@ -280,7 +320,8 @@ export default {
'Group 17': 'modp6144',
'Group 18': 'modp8192'
},
ikeDhGroupInitialValue: 'Group 5(modp1536)'
ikeDhGroupInitialValue: 'Group 5(modp1536)',
ikeversion: 'ike'
}
},
beforeCreate () {
@ -317,7 +358,9 @@ export default {
dpd: values.dpd,
forceencap: values.forceencap,
ikepolicy: ikepolicy,
esppolicy: esppolicy
esppolicy: esppolicy,
splitconnections: values.splitconnections,
ikeversion: values.ikeversion
}).then(response => {
this.$store.dispatch('AddAsyncJob', {
title: this.$t('message.add.vpn.customer.gateway'),