From af8a582055c4194d1e42c8c1abd96969692046ed Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 2 Feb 2024 15:49:04 +0100 Subject: [PATCH] api/utils/ui: List protocol numbers and icmp types (#8293) This PR contains the following changes * adds a new API to list network procotols and details/types/codes, etc * get network protocols on UI and add dropdowns for procotol numbers and icmp types/codes * validate icmp types/codes when add network ACL --- .../apache/cloudstack/api/ApiConstants.java | 1 + .../user/network/ListNetworkProtocolsCmd.java | 109 ++++++ .../api/response/NetworkProtocolResponse.java | 89 +++++ .../network/ListNetworkProtocolsCmdTest.java | 95 +++++ .../security/SecurityGroupManagerImpl.java | 26 +- .../network/vpc/NetworkACLServiceImpl.java | 2 +- .../cloud/server/ManagementServerImpl.java | 2 + .../vpc/NetworkACLServiceImplTest.java | 8 +- ui/src/views/network/AclListRulesTab.vue | 97 ++++- ui/src/views/network/EgressRulesTab.vue | 61 ++- ui/src/views/network/FirewallRules.vue | 63 ++- .../network/IngressEgressRuleConfigure.vue | 83 +++- .../java/com/cloud/utils/net/NetUtils.java | 15 + .../com/cloud/utils/net/NetworkProtocols.java | 362 ++++++++++++++++++ .../com/cloud/utils/net/NetUtilsTest.java | 46 +++ .../cloud/utils/net/NetworkProtocolsTest.java | 47 +++ 16 files changed, 1054 insertions(+), 52 deletions(-) create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworkProtocolsCmd.java create mode 100644 api/src/main/java/org/apache/cloudstack/api/response/NetworkProtocolResponse.java create mode 100644 api/src/test/java/org/apache/cloudstack/api/command/user/network/ListNetworkProtocolsCmdTest.java create mode 100644 utils/src/main/java/com/cloud/utils/net/NetworkProtocols.java create mode 100644 utils/src/test/java/com/cloud/utils/net/NetworkProtocolsTest.java 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 3ae0f319189..db0c5ce494c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -321,6 +321,7 @@ public class ApiConstants { public static final String IS_DEFAULT_USE = "defaultuse"; public static final String OLD_FORMAT = "oldformat"; public static final String OP = "op"; + public static final String OPTION = "option"; public static final String OPTIONS = "options"; public static final String OS_CATEGORY_ID = "oscategoryid"; public static final String OS_CATEGORY_NAME = "oscategoryname"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworkProtocolsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworkProtocolsCmd.java new file mode 100644 index 00000000000..3008d1a8191 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/ListNetworkProtocolsCmd.java @@ -0,0 +1,109 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.network; + +import com.cloud.utils.net.NetworkProtocols; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NetworkProtocolResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; + +import java.util.ArrayList; +import java.util.List; + +@APICommand(name = "listNetworkProtocols", description = "Lists details of network protocols", responseObject = NetworkProtocolResponse.class, + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, + authorized = { RoleType.Admin, RoleType.DomainAdmin, RoleType.ResourceAdmin, RoleType.User}, since = "4.19.0") +public class ListNetworkProtocolsCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(ListNetworkProtocolsCmd.class.getName()); + + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.OPTION, type = CommandType.STRING, required = true, + description = "The option of network protocols. Supported values are: protocolnumber, icmptype.") + private String option; + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + + public String getOption() { + return option; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() { + ListResponse response = new ListResponse<>(); + List networkProtocolResponses = new ArrayList<>(); + + NetworkProtocols.Option option = NetworkProtocols.Option.getOption(getOption()); + switch (option) { + case ProtocolNumber: + updateResponseWithProtocolNumbers(networkProtocolResponses); + break; + case IcmpType: + updateResponseWithIcmpTypes(networkProtocolResponses); + break; + default: + break; + } + + response.setResponses(networkProtocolResponses); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccount().getId(); + } + + private void updateResponseWithProtocolNumbers(List responses) { + for (NetworkProtocols.ProtocolNumber protocolNumber : NetworkProtocols.ProtocolNumbers) { + NetworkProtocolResponse networkProtocolResponse = new NetworkProtocolResponse(protocolNumber.getNumber(), + protocolNumber.getKeyword(), protocolNumber.getProtocol()); + networkProtocolResponse.setObjectName("networkprotocol"); + responses.add(networkProtocolResponse); + } + } + + private void updateResponseWithIcmpTypes(List responses) { + for (NetworkProtocols.IcmpType icmpType : NetworkProtocols.IcmpTypes) { + NetworkProtocolResponse networkProtocolResponse = new NetworkProtocolResponse(icmpType.getType(), + null, icmpType.getDescription()); + for (NetworkProtocols.IcmpCode code : icmpType.getIcmpCodes()) { + networkProtocolResponse.addDetail(String.valueOf(code.getCode()), code.getDescription()); + } + networkProtocolResponse.setObjectName("networkprotocol"); + responses.add(networkProtocolResponse); + } + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkProtocolResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkProtocolResponse.java new file mode 100644 index 00000000000..775333f7192 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkProtocolResponse.java @@ -0,0 +1,89 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class NetworkProtocolResponse extends BaseResponse { + @SerializedName(ApiConstants.INDEX) + @Param(description = "the index (ID, Value, Code, Type, Option, etc) of the protocol parameter") + private Integer index; + + @SerializedName(ApiConstants.NAME) + @Param(description = "the name of the protocol parameter") + private String name; + + @SerializedName(ApiConstants.DESCRIPTION) + @Param(description = "the description of the protocol parameter") + private String description; + + @SerializedName(ApiConstants.DETAILS) + @Param(description = "the details of the protocol parameter") + private Map details; + + public NetworkProtocolResponse(Integer index, String name, String description) { + this.index = index; + this.name = name; + this.description = description; + } + + public Integer getIndex() { + return index; + } + + public void setIndex(Integer index) { + this.index = index; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getDetails() { + return details; + } + + public void setDetails(Map details) { + this.details = details; + } + + public void addDetail(String key, String value) { + if (this.details == null) { + this.details = new LinkedHashMap(); + } + this.details.put(key, value); + } +} diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/network/ListNetworkProtocolsCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/network/ListNetworkProtocolsCmdTest.java new file mode 100644 index 00000000000..7c29de69ade --- /dev/null +++ b/api/src/test/java/org/apache/cloudstack/api/command/user/network/ListNetworkProtocolsCmdTest.java @@ -0,0 +1,95 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.cloudstack.api.command.user.network; + +import com.cloud.utils.net.NetworkProtocols; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NetworkProtocolResponse; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; + +@RunWith(MockitoJUnitRunner.class) +public class ListNetworkProtocolsCmdTest { + + @Test + public void testListNetworkProtocolNumbers() { + ListNetworkProtocolsCmd cmd = new ListNetworkProtocolsCmd(); + String option = NetworkProtocols.Option.ProtocolNumber.toString(); + ReflectionTestUtils.setField(cmd, "option", option); + Assert.assertEquals(cmd.getOption(), option); + + try { + cmd.execute(); + } catch (Exception e) { + e.printStackTrace(); + } + Object response = cmd.getResponseObject(); + Assert.assertTrue(response instanceof ListResponse); + ListResponse listResponse = (ListResponse) response; + Assert.assertEquals(BaseCmd.getResponseNameByClass(cmd.getClass()), listResponse.getResponseName()); + Assert.assertNotNull(listResponse.getResponses()); + Assert.assertNotEquals(0, listResponse.getResponses().size()); + Object firstResponse = listResponse.getResponses().get(0); + Assert.assertTrue(firstResponse instanceof NetworkProtocolResponse); + Assert.assertEquals("networkprotocol", ((NetworkProtocolResponse) firstResponse).getObjectName()); + Assert.assertEquals(Integer.valueOf(0), ((NetworkProtocolResponse) firstResponse).getIndex()); + Assert.assertEquals("HOPOPT", ((NetworkProtocolResponse) firstResponse).getName()); + } + + @Test + public void testListIcmpTypes() { + ListNetworkProtocolsCmd cmd = new ListNetworkProtocolsCmd(); + String option = NetworkProtocols.Option.IcmpType.toString(); + ReflectionTestUtils.setField(cmd, "option", option); + Assert.assertEquals(cmd.getOption(), option); + + try { + cmd.execute(); + } catch (Exception e) { + e.printStackTrace(); + } + Object response = cmd.getResponseObject(); + Assert.assertTrue(response instanceof ListResponse); + ListResponse listResponse = (ListResponse) response; + Assert.assertEquals(BaseCmd.getResponseNameByClass(cmd.getClass()), listResponse.getResponseName()); + Assert.assertNotNull(listResponse.getResponses()); + Assert.assertNotEquals(0, listResponse.getResponses().size()); + Object firstResponse = listResponse.getResponses().get(0); + Assert.assertTrue(firstResponse instanceof NetworkProtocolResponse); + Assert.assertEquals("networkprotocol", ((NetworkProtocolResponse) firstResponse).getObjectName()); + Assert.assertEquals(Integer.valueOf(0), ((NetworkProtocolResponse) firstResponse).getIndex()); + Assert.assertNotNull(((NetworkProtocolResponse) firstResponse).getDetails()); + System.out.println(((NetworkProtocolResponse) firstResponse).getDetails()); + Assert.assertEquals("Echo reply", ((NetworkProtocolResponse) firstResponse).getDetails().get("0")); + } + + @Test(expected = IllegalArgumentException.class) + public void testListInvalidOption() { + ListNetworkProtocolsCmd cmd = new ListNetworkProtocolsCmd(); + String option = "invalid-option"; + ReflectionTestUtils.setField(cmd, "option", option); + Assert.assertEquals(cmd.getOption(), option); + + cmd.execute(); + } +} diff --git a/server/src/main/java/com/cloud/network/security/SecurityGroupManagerImpl.java b/server/src/main/java/com/cloud/network/security/SecurityGroupManagerImpl.java index 5d4b4737cbe..e35503f32de 100644 --- a/server/src/main/java/com/cloud/network/security/SecurityGroupManagerImpl.java +++ b/server/src/main/java/com/cloud/network/security/SecurityGroupManagerImpl.java @@ -658,10 +658,14 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro if(StringUtils.isNumeric(protocol)){ int protoNumber = Integer.parseInt(protocol); // Deal with ICMP(protocol number 1) specially because it need to be paired with icmp type and code - if (protoNumber == 1) { - protocol = "icmp"; - icmpCode = -1; - icmpType = -1; + if (protoNumber == NetUtils.ICMP_PROTO_NUMBER) { + protocol = NetUtils.ICMP_PROTO; + if (icmpCode == null) { + icmpCode = -1; + } + if (icmpType == null) { + icmpType = -1; + } } else if(protoNumber < 0 || protoNumber > 255){ throw new InvalidParameterValueException("Invalid protocol number: " + protoNumber); } @@ -673,18 +677,7 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro } } if (protocol.equals(NetUtils.ICMP_PROTO)) { - if ((icmpType == null) || (icmpCode == null)) { - throw new InvalidParameterValueException("Invalid ICMP type/code specified, icmpType = " + icmpType + ", icmpCode = " + icmpCode); - } - if (icmpType == -1 && icmpCode != -1) { - throw new InvalidParameterValueException("Invalid icmp code"); - } - if (icmpType != -1 && icmpCode == -1) { - throw new InvalidParameterValueException("Invalid icmp code: need non-negative icmp code "); - } - if (icmpCode > 255 || icmpType > 255 || icmpCode < -1 || icmpType < -1) { - throw new InvalidParameterValueException("Invalid icmp type/code "); - } + NetUtils.validateIcmpTypeAndCode(icmpType, icmpCode); startPortOrType = icmpType; endPortOrCode = icmpCode; } else if (protocol.equals(NetUtils.ALL_PROTO)) { @@ -785,6 +778,7 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro SecurityGroupRuleVO securityGroupRule = _securityGroupRuleDao.findByProtoPortsAndAllowedGroupId(securityGroup.getId(), protocolFinal, startPortOrTypeFinal, endPortOrCodeFinal, ngVO.getId()); if ((securityGroupRule != null) && (securityGroupRule.getRuleType() == ruleType)) { + s_logger.warn("The rule already exists. id= " + securityGroupRule.getUuid()); continue; // rule already exists. } securityGroupRule = new SecurityGroupRuleVO(ruleType, securityGroup.getId(), startPortOrTypeFinal, endPortOrCodeFinal, protocolFinal, ngVO.getId()); diff --git a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java index 8139ac1c49e..773d36175c3 100644 --- a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java @@ -583,7 +583,7 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ Integer icmpCode = networkACLItemVO.getIcmpCode(); Integer icmpType = networkACLItemVO.getIcmpType(); // icmp code and icmp type can't be passed in for any other protocol rather than icmp - boolean isIcmpProtocol = protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO); + boolean isIcmpProtocol = protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) || protocol.equalsIgnoreCase(String.valueOf(NetUtils.ICMP_PROTO_NUMBER)); if (!isIcmpProtocol && (icmpCode != null || icmpType != null)) { throw new InvalidParameterValueException("Can specify icmpCode and icmpType for ICMP protocol only"); } diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index f794736a4d5..a73ba9b092c 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -446,6 +446,7 @@ import org.apache.cloudstack.api.command.user.network.ListNetworkACLListsCmd; import org.apache.cloudstack.api.command.user.network.ListNetworkACLsCmd; import org.apache.cloudstack.api.command.user.network.ListNetworkOfferingsCmd; import org.apache.cloudstack.api.command.user.network.ListNetworkPermissionsCmd; +import org.apache.cloudstack.api.command.user.network.ListNetworkProtocolsCmd; import org.apache.cloudstack.api.command.user.network.ListNetworksCmd; import org.apache.cloudstack.api.command.user.network.MoveNetworkAclItemCmd; import org.apache.cloudstack.api.command.user.network.RemoveNetworkPermissionsCmd; @@ -3621,6 +3622,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(DeleteNetworkCmd.class); cmdList.add(ListNetworkACLsCmd.class); cmdList.add(ListNetworkOfferingsCmd.class); + cmdList.add(ListNetworkProtocolsCmd.class); cmdList.add(ListNetworksCmd.class); cmdList.add(RestartNetworkCmd.class); cmdList.add(UpdateNetworkCmd.class); diff --git a/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java b/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java index 18a072172ad..3d63b1db507 100644 --- a/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java +++ b/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java @@ -622,8 +622,8 @@ public class NetworkACLServiceImplTest { @Test(expected = InvalidParameterValueException.class) public void validateProtocolTestProtocolNotIcmpWithIcmpConfigurations() { - Mockito.when(networkAclItemVoMock.getIcmpCode()).thenReturn(1); - Mockito.when(networkAclItemVoMock.getIcmpType()).thenReturn(1); + Mockito.when(networkAclItemVoMock.getIcmpCode()).thenReturn(2); + Mockito.when(networkAclItemVoMock.getIcmpType()).thenReturn(3); Mockito.when(networkAclItemVoMock.getProtocol()).thenReturn("tcp"); networkAclServiceImpl.validateProtocol(networkAclItemVoMock); @@ -647,8 +647,8 @@ public class NetworkACLServiceImplTest { @Test public void validateProtocolTestProtocolIcmpWithIcmpConfigurations() { - Mockito.when(networkAclItemVoMock.getIcmpCode()).thenReturn(1); - Mockito.when(networkAclItemVoMock.getIcmpType()).thenReturn(1); + Mockito.when(networkAclItemVoMock.getIcmpCode()).thenReturn(2); + Mockito.when(networkAclItemVoMock.getIcmpType()).thenReturn(3); Mockito.when(networkAclItemVoMock.getSourcePortStart()).thenReturn(null); Mockito.when(networkAclItemVoMock.getSourcePortEnd()).thenReturn(null); diff --git a/ui/src/views/network/AclListRulesTab.vue b/ui/src/views/network/AclListRulesTab.vue index caf72caf0a5..a0336cb1923 100644 --- a/ui/src/views/network/AclListRulesTab.vue +++ b/ui/src/views/network/AclListRulesTab.vue @@ -64,19 +64,19 @@
{{ $t('label.protocol') }}
{{ element.protocol }}
-
+
{{ $t('label.startport') }}
{{ element.startport }}
-
+
{{ $t('label.endport') }}
{{ element.endport }}
-
+
{{ $t('label.icmpcode') }}
{{ element.icmpcode }}
-
+
{{ $t('label.icmptype') }}
{{ element.icmptype }}
@@ -208,19 +208,50 @@ :label="$t('label.protocolnumber')" ref="protocolnumber" name="protocolnumber"> - + + + {{ opt.index + ' - ' + opt.name }} + + -
+
- + + + {{ opt.index + ' - ' + opt.description }} + + - + + + {{ opt.code + ' - ' + opt.description }} + +
-
+
@@ -285,6 +316,9 @@ export default { return { acls: [], fetchLoading: false, + protocolNumbers: [], + icmpTypes: [], + icmpCodes: [], tags: [], selectedAcl: null, tagsModalVisible: false, @@ -296,6 +330,7 @@ export default { }, created () { this.initForm() + this.fetchNetworkProtocols() this.fetchData() }, watch: { @@ -310,6 +345,8 @@ export default { this.formRef = ref() this.form = reactive({}) this.rules = reactive({}) + this.form.icmptype = -1 + this.form.icmpcode = -1 }, csv ({ data = null, columnDelimiter = ',', lineDelimiter = '\n' }) { let result = null @@ -351,6 +388,35 @@ export default { return result }, + fetchNetworkProtocols () { + api('listNetworkProtocols', { + option: 'protocolnumber' + }).then(json => { + this.protocolNumbers = json.listnetworkprotocolsresponse?.networkprotocol || [] + }) + api('listNetworkProtocols', { + option: 'icmptype' + }).then(json => { + this.icmpTypes.push({ index: -1, description: this.$t('label.all') }) + const results = json.listnetworkprotocolsresponse?.networkprotocol || [] + for (const result of results) { + this.icmpTypes.push(result) + } + }) + this.icmpCodes.push({ code: -1, description: this.$t('label.all') }) + }, + updateIcmpCodes (val) { + this.form.icmpcode = -1 + this.icmpCodes = [] + this.icmpCodes.push({ code: -1, description: this.$t('label.all') }) + const icmpType = this.icmpTypes.find(icmpType => icmpType.index === val) + if (icmpType && icmpType.details) { + const icmpTypeDetails = icmpType.details + for (const k of Object.keys(icmpTypeDetails)) { + this.icmpCodes.push({ code: parseInt(k), description: icmpTypeDetails[k] }) + } + } + }, fetchData () { this.fetchLoading = true api('listNetworkACLs', { aclid: this.resource.id }).then(json => { @@ -476,8 +542,15 @@ export default { self.form.cidrlist = acl.cidrlist self.form.action = acl.action self.form.protocol = acl.protocol + if (!['tcp', 'udp', 'icmp', 'all'].includes(acl.protocol)) { + self.form.protocol = 'protocolnumber' + self.form.protocolnumber = parseInt(acl.protocol) + } self.form.startport = acl.startport self.form.endport = acl.endport + self.form.icmptype = parseInt(acl.icmptype) + this.updateIcmpCodes(self.form.icmptype) + self.form.icmpcode = acl.icmpcode self.form.traffictype = acl.traffictype self.form.reason = acl.reason }, 200) @@ -497,9 +570,9 @@ export default { data.endport = values.endport || '' } - if (values.protocol === 'icmp') { - data.icmptype = values.icmptype || -1 - data.icmpcode = values.icmpcode || -1 + if (values.protocol === 'icmp' || (values.protocol === 'protocolnumber' && values.protocolnumber === 1)) { + data.icmptype = values.icmptype + data.icmpcode = values.icmpcode } if (values.protocol === 'protocolnumber') { diff --git a/ui/src/views/network/EgressRulesTab.vue b/ui/src/views/network/EgressRulesTab.vue index a0fb7085534..9d315416e2a 100644 --- a/ui/src/views/network/EgressRulesTab.vue +++ b/ui/src/views/network/EgressRulesTab.vue @@ -63,11 +63,32 @@
{{ $t('label.icmptype') }}
- + + + {{ opt.index + ' - ' + opt.description }} + +
{{ $t('label.icmpcode') }}
- + + + {{ opt.code + ' - ' + opt.description }} + +
@@ -102,10 +123,10 @@ {{ getCapitalise(record.protocol) }}