This is an automated email from the ASF dual-hosted git repository.
weizhou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push:
new af8a582055c api/utils/ui: List protocol numbers and icmp types (#8293)
af8a582055c is described below
commit af8a582055c4194d1e42c8c1abd96969692046ed
Author: Wei Zhou <[email protected]>
AuthorDate: Fri Feb 2 15:49:04 2024 +0100
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
---
.../org/apache/cloudstack/api/ApiConstants.java | 1 +
.../user/network/ListNetworkProtocolsCmd.java | 109 +++++++
.../api/response/NetworkProtocolResponse.java | 89 +++++
.../user/network/ListNetworkProtocolsCmdTest.java | 95 ++++++
.../network/security/SecurityGroupManagerImpl.java | 26 +-
.../cloud/network/vpc/NetworkACLServiceImpl.java | 2 +-
.../com/cloud/server/ManagementServerImpl.java | 2 +
.../network/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 +++-
.../views/network/IngressEgressRuleConfigure.vue | 83 ++++-
.../main/java/com/cloud/utils/net/NetUtils.java | 15 +
.../java/com/cloud/utils/net/NetworkProtocols.java | 362 +++++++++++++++++++++
.../java/com/cloud/utils/net/NetUtilsTest.java | 46 +++
.../com/cloud/utils/net/NetworkProtocolsTest.java | 47 +++
16 files changed, 1054 insertions(+), 52 deletions(-)
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<NetworkProtocolResponse> response = new ListResponse<>();
+ List<NetworkProtocolResponse> 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<NetworkProtocolResponse> 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<NetworkProtocolResponse>
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 @@
<div class="list__label">{{ $t('label.protocol') }}</div>
<div>{{ element.protocol }}</div>
</div>
- <div class="list__col" v-if="element.startport">
+ <div class="list__col" v-if="element.startport !== undefined">
<div class="list__label">{{ $t('label.startport') }}</div>
<div>{{ element.startport }}</div>
</div>
- <div class="list__col" v-if="element.endport">
+ <div class="list__col" v-if="element.endport !== undefined">
<div class="list__label">{{ $t('label.endport') }}</div>
<div>{{ element.endport }}</div>
</div>
- <div class="list__col" v-if="element.icmpcode">
+ <div class="list__col" v-if="element.icmpcode !== undefined">
<div class="list__label">{{ $t('label.icmpcode') }}</div>
<div>{{ element.icmpcode }}</div>
</div>
- <div class="list__col" v-if="element.icmptype">
+ <div class="list__col" v-if="element.icmptype !== undefined">
<div class="list__label">{{ $t('label.icmptype') }}</div>
<div>{{ element.icmptype }}</div>
</div>
@@ -208,19 +208,50 @@
:label="$t('label.protocolnumber')"
ref="protocolnumber"
name="protocolnumber">
- <a-input v-model:value="form.protocolnumber" />
+ <a-select
+ v-model:value="form.protocolnumber"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option v-for="(opt, optIndex) in protocolNumbers"
:key="optIndex" :label="opt.name">
+ {{ opt.index + ' - ' + opt.name }}
+ </a-select-option>
+ </a-select>
</a-form-item>
- <div v-if="form.protocol === 'icmp'">
+ <div v-if="form.protocol === 'icmp' || (form.protocol ===
'protocolnumber' && form.protocolnumber === 1)">
<a-form-item :label="$t('label.icmptype')" ref="icmptype"
name="icmptype">
- <a-input v-model:value="form.icmptype"
:placeholder="$t('icmp.type.desc')" />
+ <a-select
+ v-model:value="form.icmptype"
+ @change="val => { updateIcmpCodes(val) }"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option v-for="(opt) in icmpTypes" :key="opt.index"
:label="opt.description">
+ {{ opt.index + ' - ' + opt.description }}
+ </a-select-option>
+ </a-select>
</a-form-item>
<a-form-item :label="$t('label.icmpcode')" ref="icmpcode"
name="icmpcode">
- <a-input v-model:value="form.icmpcode"
:placeholder="$t('icmp.code.desc')" />
+ <a-select
+ v-model:value="form.icmpcode"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option v-for="(opt) in icmpCodes" :key="opt.code"
:label="opt.description">
+ {{ opt.code + ' - ' + opt.description }}
+ </a-select-option>
+ </a-select>
</a-form-item>
</div>
- <div v-show="['tcp', 'udp', 'protocolnumber'].includes(form.protocol)">
+ <div v-show="['tcp', 'udp', 'protocolnumber'].includes(form.protocol)
&& !(form.protocol === 'protocolnumber' && form.protocolnumber === 1)">
<a-form-item :label="$t('label.startport')" ref="startport"
name="startport">
<a-input-number style="width: 100%" v-model:value="form.startport"
/>
</a-form-item>
@@ -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 @@
</div>
<div v-show="newRule.protocol === 'icmp'" class="form__item">
<div class="form__label">{{ $t('label.icmptype') }}</div>
- <a-input v-model:value="newRule.icmptype"></a-input>
+ <a-select
+ v-model:value="newRule.icmptype"
+ @change="val => { updateIcmpCodes(val) }"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option v-for="(opt) in icmpTypes" :key="opt.index"
:label="opt.description">
+ {{ opt.index + ' - ' + opt.description }}
+ </a-select-option>
+ </a-select>
</div>
<div v-show="newRule.protocol === 'icmp'" class="form__item">
<div class="form__label">{{ $t('label.icmpcode') }}</div>
- <a-input v-model:value="newRule.icmpcode"></a-input>
+ <a-select
+ v-model:value="newRule.icmpcode"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option v-for="(opt) in icmpCodes" :key="opt.code"
:label="opt.description">
+ {{ opt.code + ' - ' + opt.description }}
+ </a-select-option>
+ </a-select>
</div>
<div class="form__item">
<a-button ref="submit" :disabled="!('createEgressFirewallRule' in
$store.getters.apis)" type="primary" @click="addRule">
@@ -102,10 +123,10 @@
{{ getCapitalise(record.protocol) }}
</template>
<template v-if="column.key === 'startport'">
- {{ record.icmptype || record.startport >= 0 ? record.icmptype ||
record.startport : 'All' }}
+ {{ record.icmptype >= 0 ? String(record.icmptype): record.startport
>= 0 ? String(record.startport): 'All' }}
</template>
<template v-if="column.key === 'endport'">
- {{ record.icmpcode || record.endport >= 0 ? record.icmpcode ||
record.endport : 'All' }}
+ {{ record.icmpcode >= 0 ? String(record.icmpcode): record.endport >=
0 ? String(record.endport): 'All' }}
</template>
<template v-if="column.key === 'actions'">
<tooltip-button
@@ -196,6 +217,9 @@ export default {
startport: null,
endport: null
},
+ protocolNumbers: [],
+ icmpTypes: [],
+ icmpCodes: [],
totalCount: 0,
page: 1,
pageSize: 10,
@@ -233,6 +257,7 @@ export default {
}
},
created () {
+ this.fetchNetworkProtocols()
this.fetchData()
},
watch: {
@@ -248,6 +273,34 @@ export default {
},
inject: ['parentFetchData'],
methods: {
+ 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)
+ }
+ })
+ },
+ updateIcmpCodes (val) {
+ this.newRule.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.loading = true
api('listEgressFirewallRules', {
diff --git a/ui/src/views/network/FirewallRules.vue
b/ui/src/views/network/FirewallRules.vue
index 787f5c2d8e2..43ee9536be5 100644
--- a/ui/src/views/network/FirewallRules.vue
+++ b/ui/src/views/network/FirewallRules.vue
@@ -49,11 +49,32 @@
</div>
<div v-show="newRule.protocol === 'icmp'" class="form__item">
<div class="form__label">{{ $t('label.icmptype') }}</div>
- <a-input v-model:value="newRule.icmptype"></a-input>
+ <a-select
+ v-model:value="newRule.icmptype"
+ @change="val => { updateIcmpCodes(val) }"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option v-for="(opt) in icmpTypes" :key="opt.index"
:label="opt.description">
+ {{ opt.index + ' - ' + opt.description }}
+ </a-select-option>
+ </a-select>
</div>
<div v-show="newRule.protocol === 'icmp'" class="form__item">
<div class="form__label">{{ $t('label.icmpcode') }}</div>
- <a-input v-model:value="newRule.icmpcode"></a-input>
+ <a-select
+ v-model:value="newRule.icmpcode"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option v-for="(opt) in icmpCodes" :key="opt.code"
:label="opt.description">
+ {{ opt.code + ' - ' + opt.description }}
+ </a-select-option>
+ </a-select>
</div>
<div class="form__item" style="margin-left: auto;">
<a-button :disabled="!('createFirewallRule' in $store.getters.apis)"
type="primary" ref="submit" @click="addRule">{{ $t('label.add') }}</a-button>
@@ -85,10 +106,10 @@
{{ getCapitalise(record.protocol) }}
</template>
<template v-if="column.key === 'startport'">
- {{ record.icmptype || record.startport >= 0 ? record.icmptype ||
record.startport : $t('label.all') }}
+ {{ record.icmptype >= 0 ? String(record.icmptype): record.startport
>= 0 ? String(record.startport): 'All' }}
</template>
<template v-if="column.key === 'endport'">
- {{ record.icmpcode || record.endport >= 0 ? record.icmpcode ||
record.endport : $t('label.all') }}
+ {{ record.icmpcode >= 0 ? String(record.icmpcode): record.endport >=
0 ? String(record.endport): 'All' }}
</template>
<template v-if="column.key === 'actions'">
<div class="actions">
@@ -238,6 +259,9 @@ export default {
startport: null,
endport: null
},
+ protocolNumbers: [],
+ icmpTypes: [],
+ icmpCodes: [],
tagsModalVisible: false,
selectedRule: null,
tags: [],
@@ -279,6 +303,7 @@ export default {
},
created () {
this.initForm()
+ this.fetchNetworkProtocols()
this.fetchData()
},
watch: {
@@ -301,6 +326,34 @@ export default {
value: [{ required: true, message:
this.$t('message.specify.tag.value') }]
})
},
+ 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)
+ }
+ })
+ },
+ updateIcmpCodes (val) {
+ this.newRule.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.loading = true
api('listFirewallRules', {
@@ -620,7 +673,7 @@ export default {
&__item {
display: flex;
flex-direction: column;
- /*flex: 1;*/
+ flex: 1;
padding-right: 20px;
margin-bottom: 20px;
diff --git a/ui/src/views/network/IngressEgressRuleConfigure.vue
b/ui/src/views/network/IngressEgressRuleConfigure.vue
index adf013cb9aa..92cd2fe50d0 100644
--- a/ui/src/views/network/IngressEgressRuleConfigure.vue
+++ b/ui/src/views/network/IngressEgressRuleConfigure.vue
@@ -47,25 +47,56 @@
<a-select-option value="protocolnumber"
:label="$t('label.protocol.number')">{{ capitalise($t('label.protocol.number'))
}}</a-select-option>
</a-select>
</div>
- <div v-show="newRule.protocol === 'tcp' || newRule.protocol === 'udp'"
class="form__item">
+ <div v-show="newRule.protocol === 'protocolnumber'" class="form__item">
+ <div class="form__label">{{ $t('label.protocol.number') }}</div>
+ <a-select
+ v-model:value="newRule.protocolnumber"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option v-for="(opt, optIndex) in protocolNumbers"
:key="optIndex" :label="opt.name">
+ {{ opt.index + ' - ' + opt.name }}
+ </a-select-option>
+ </a-select>
+ </div>
+ <div v-show="['tcp', 'udp',
'protocolnumber'].includes(newRule.protocol) && !(newRule.protocol ===
'protocolnumber' && newRule.protocolnumber === 1)" class="form__item">
<div class="form__label">{{ $t('label.startport') }}</div>
<a-input v-model:value="newRule.startport"></a-input>
</div>
- <div v-show="newRule.protocol === 'tcp' || newRule.protocol === 'udp'"
class="form__item">
+ <div v-show="['tcp', 'udp',
'protocolnumber'].includes(newRule.protocol) && !(newRule.protocol ===
'protocolnumber' && newRule.protocolnumber === 1)" class="form__item">
<div class="form__label">{{ $t('label.endport') }}</div>
<a-input v-model:value="newRule.endport"></a-input>
</div>
- <div v-show="newRule.protocol === 'protocolnumber'" class="form__item">
- <div class="form__label">{{ $t('label.protocol.number') }}</div>
- <a-input v-model:value="newRule.protocolnumber"></a-input>
- </div>
- <div v-show="newRule.protocol === 'icmp'" class="form__item">
+ <div v-show="newRule.protocol === 'icmp' || (newRule.protocol ===
'protocolnumber' && newRule.protocolnumber === 1)" class="form__item">
<div class="form__label">{{ $t('label.icmptype') }}</div>
- <a-input v-model:value="newRule.icmptype"></a-input>
+ <a-select
+ v-model:value="newRule.icmptype"
+ @change="val => { updateIcmpCodes(val) }"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option v-for="(opt) in icmpTypes" :key="opt.index"
:label="opt.description">
+ {{ opt.index + ' - ' + opt.description }}
+ </a-select-option>
+ </a-select>
</div>
- <div v-show="newRule.protocol === 'icmp'" class="form__item">
+ <div v-show="newRule.protocol === 'icmp' || (newRule.protocol ===
'protocolnumber' && newRule.protocolnumber === 1)" class="form__item">
<div class="form__label">{{ $t('label.icmpcode') }}</div>
- <a-input v-model:value="newRule.icmpcode"></a-input>
+ <a-select
+ v-model:value="newRule.icmpcode"
+ showSearch
+ optionFilterProp="label"
+ :filterOption="(input, option) => {
+ return
option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
+ }" >
+ <a-select-option v-for="(opt) in icmpCodes" :key="opt.code"
:label="opt.description">
+ {{ opt.code + ' - ' + opt.description }}
+ </a-select-option>
+ </a-select>
</div>
<div class="form__item" v-if="addType === 'cidr'">
<div class="form__label">{{ $t('label.cidr') }}</div>
@@ -211,6 +242,9 @@ export default {
group: null
}
},
+ protocolNumbers: [],
+ icmpTypes: [],
+ icmpCodes: [],
tagsModalVisible: false,
tags: [],
newTag: {
@@ -275,6 +309,7 @@ export default {
},
created () {
this.initForm()
+ this.fetchNetworkProtocols()
this.fetchData()
},
methods: {
@@ -286,6 +321,34 @@ export default {
value: [{ required: true, message:
this.$t('message.specify.tag.value') }]
})
},
+ 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)
+ }
+ })
+ },
+ updateIcmpCodes (val) {
+ this.newRule.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.tabType = this.$route.query.tab === 'ingress.rule' ? 'ingress' :
'egress'
this.rules = this.tabType === 'ingress' ? this.resource.ingressrule :
this.resource.egressrule
diff --git a/utils/src/main/java/com/cloud/utils/net/NetUtils.java
b/utils/src/main/java/com/cloud/utils/net/NetUtils.java
index 018912a2140..2a39b12afdf 100644
--- a/utils/src/main/java/com/cloud/utils/net/NetUtils.java
+++ b/utils/src/main/java/com/cloud/utils/net/NetUtils.java
@@ -78,6 +78,7 @@ public class NetUtils {
public final static String ANY_PROTO = "any";
public final static String ICMP_PROTO = "icmp";
public static final String ICMP6_PROTO = "icmp6";
+ public final static int ICMP_PROTO_NUMBER = 1;
public final static String ALL_PROTO = "all";
public final static String HTTP_PROTO = "http";
public final static String HTTPS_PROTO = "https";
@@ -1771,4 +1772,18 @@ public class NetUtils {
}
}
+ public static void validateIcmpTypeAndCode(Integer icmpType, Integer
icmpCode) {
+ if ((icmpType == null) || (icmpCode == null)) {
+ throw new CloudRuntimeException("Invalid ICMP type/code specified,
icmpType = " + icmpType + ", icmpCode = " + icmpCode);
+ }
+ if (icmpType == -1 && icmpCode != -1) {
+ throw new CloudRuntimeException("Invalid icmp code");
+ }
+ if (icmpType != -1 && icmpCode == -1) {
+ throw new CloudRuntimeException("Invalid icmp code: need
non-negative icmp code ");
+ }
+ if (icmpCode > 255 || icmpType > 255 || icmpCode < -1 || icmpType <
-1) {
+ throw new CloudRuntimeException("Invalid icmp type/code ");
+ }
+ }
}
diff --git a/utils/src/main/java/com/cloud/utils/net/NetworkProtocols.java
b/utils/src/main/java/com/cloud/utils/net/NetworkProtocols.java
new file mode 100644
index 00000000000..e3ebe43757f
--- /dev/null
+++ b/utils/src/main/java/com/cloud/utils/net/NetworkProtocols.java
@@ -0,0 +1,362 @@
+// 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 com.cloud.utils.net;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Network protocols and parameters.
+ * see <a href="https://www.iana.org/protocols">Protocol Registries</a>
+ *
+ */
+public class NetworkProtocols {
+
+ public enum Option {
+ ProtocolNumber, IcmpType;
+
+ public static Option getOption(String value) {
+ return Arrays.stream(Option.values())
+ .filter(option -> option.name().equalsIgnoreCase(value))
+ .findFirst()
+ .orElseThrow(() -> new
IllegalArgumentException(String.format("Option " + value + " is not supported.
Supported values are %s", Arrays.toString(Option.values()))));
+ }
+ }
+
+ // Refer to
https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
+ public static List<ProtocolNumber> ProtocolNumbers = new ArrayList<>();
+ static {
+ ProtocolNumbers.add(new ProtocolNumber(0, "HOPOPT", "IPv6 Hop-by-Hop
Option"));
+ ProtocolNumbers.add(new ProtocolNumber(1, "ICMP", "Internet Control
Message"));
+ ProtocolNumbers.add(new ProtocolNumber(2, "IGMP", "Internet Group
Management"));
+ ProtocolNumbers.add(new ProtocolNumber(3, "GGP",
"Gateway-to-Gateway"));
+ ProtocolNumbers.add(new ProtocolNumber(4, "IPv4", "IPv4
encapsulation"));
+ ProtocolNumbers.add(new ProtocolNumber(5, "ST", "Stream"));
+ ProtocolNumbers.add(new ProtocolNumber(6, "TCP", "Transmission
Control"));
+ ProtocolNumbers.add(new ProtocolNumber(7, "CBT", "CBT"));
+ ProtocolNumbers.add(new ProtocolNumber(8, "EGP", "Exterior Gateway
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(9, "IGP", "any private interior
gateway"));
+ ProtocolNumbers.add(new ProtocolNumber(10, "BBN-RCC-MON", "BBN RCC
Monitoring"));
+ ProtocolNumbers.add(new ProtocolNumber(11, "NVP-II", "Network Voice
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(12, "PUP", "PUP"));
+ ProtocolNumbers.add(new ProtocolNumber(13, "ARGUS (deprecated)",
"ARGUS"));
+ ProtocolNumbers.add(new ProtocolNumber(14, "EMCON", "EMCON"));
+ ProtocolNumbers.add(new ProtocolNumber(15, "XNET", "Cross Net
Debugger"));
+ ProtocolNumbers.add(new ProtocolNumber(16, "CHAOS", "Chaos"));
+ ProtocolNumbers.add(new ProtocolNumber(17, "UDP", "User Datagram"));
+ ProtocolNumbers.add(new ProtocolNumber(18, "MUX", "Multiplexing"));
+ ProtocolNumbers.add(new ProtocolNumber(19, "DCN-MEAS", "DCN
Measurement Subsystems"));
+ ProtocolNumbers.add(new ProtocolNumber(20, "HMP", "Host Monitoring"));
+ ProtocolNumbers.add(new ProtocolNumber(21, "PRM", "Packet Radio
Measurement"));
+ ProtocolNumbers.add(new ProtocolNumber(22, "XNS-IDP", "XEROX NS IDP"));
+ ProtocolNumbers.add(new ProtocolNumber(23, "TRUNK-1", "Trunk-1"));
+ ProtocolNumbers.add(new ProtocolNumber(24, "TRUNK-2", "Trunk-2"));
+ ProtocolNumbers.add(new ProtocolNumber(25, "LEAF-1", "Leaf-1"));
+ ProtocolNumbers.add(new ProtocolNumber(26, "LEAF-2", "Leaf-2"));
+ ProtocolNumbers.add(new ProtocolNumber(27, "RDP", "Reliable Data
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(28, "IRTP", "Internet Reliable
Transaction"));
+ ProtocolNumbers.add(new ProtocolNumber(29, "ISO-TP4", "ISO Transport
Protocol Class 4"));
+ ProtocolNumbers.add(new ProtocolNumber(30, "NETBLT", "Bulk Data
Transfer Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(31, "MFE-NSP", "MFE Network
Services Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(32, "MERIT-INP", "MERIT
Internodal Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(33, "DCCP", "Datagram
Congestion Control Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(34, "3PC", "Third Party Connect
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(35, "IDPR", "Inter-Domain
Policy Routing Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(36, "XTP", "XTP"));
+ ProtocolNumbers.add(new ProtocolNumber(37, "DDP", "Datagram Delivery
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(38, "IDPR-CMTP", "IDPR Control
Message Transport Proto"));
+ ProtocolNumbers.add(new ProtocolNumber(39, "TP++", "TP++ Transport
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(40, "IL", "IL Transport
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(41, "IPv6", "IPv6
encapsulation"));
+ ProtocolNumbers.add(new ProtocolNumber(42, "SDRP", "Source Demand
Routing Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(43, "IPv6-Route", "Routing
Header for IPv6"));
+ ProtocolNumbers.add(new ProtocolNumber(44, "IPv6-Frag", "Fragment
Header for IPv6"));
+ ProtocolNumbers.add(new ProtocolNumber(45, "IDRP", "Inter-Domain
Routing Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(46, "RSVP", "Reservation
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(47, "GRE", "Generic Routing
Encapsulation"));
+ ProtocolNumbers.add(new ProtocolNumber(48, "DSR", "Dynamic Source
Routing Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(49, "BNA", "BNA"));
+ ProtocolNumbers.add(new ProtocolNumber(50, "ESP", "Encap Security
Payload"));
+ ProtocolNumbers.add(new ProtocolNumber(51, "AH", "Authentication
Header"));
+ ProtocolNumbers.add(new ProtocolNumber(52, "I-NLSP", "Integrated Net
Layer Security TUBA"));
+ ProtocolNumbers.add(new ProtocolNumber(53, "SWIPE (deprecated)", "IP
with Encryption"));
+ ProtocolNumbers.add(new ProtocolNumber(54, "NARP", "NBMA Address
Resolution Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(55, "MOBILE", "Minimal IPv4
Encapsulation"));
+ ProtocolNumbers.add(new ProtocolNumber(56, "TLSP", "Transport Layer
Security Protocol using Kryptonet key management"));
+ ProtocolNumbers.add(new ProtocolNumber(57, "SKIP", "SKIP"));
+ ProtocolNumbers.add(new ProtocolNumber(58, "IPv6-ICMP", "ICMP for
IPv6"));
+ ProtocolNumbers.add(new ProtocolNumber(59, "IPv6-NoNxt", "No Next
Header for IPv6"));
+ ProtocolNumbers.add(new ProtocolNumber(60, "IPv6-Opts", "Destination
Options for IPv6"));
+ ProtocolNumbers.add(new ProtocolNumber(61, "Any host internal
protocol", "Any host internal protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(62, "CFTP", "CFTP"));
+ ProtocolNumbers.add(new ProtocolNumber(63, "Any local network", "Any
local network"));
+ ProtocolNumbers.add(new ProtocolNumber(64, "SAT-EXPAK", "SATNET and
Backroom EXPAK"));
+ ProtocolNumbers.add(new ProtocolNumber(65, "KRYPTOLAN", "Kryptolan"));
+ ProtocolNumbers.add(new ProtocolNumber(66, "RVD", "MIT Remote Virtual
Disk Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(67, "IPPC", "Internet Pluribus
Packet Core"));
+ ProtocolNumbers.add(new ProtocolNumber(68, "Any distributed file
system", "Any distributed file system"));
+ ProtocolNumbers.add(new ProtocolNumber(69, "SAT-MON", "SATNET
Monitoring"));
+ ProtocolNumbers.add(new ProtocolNumber(70, "VISA", "VISA Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(71, "IPCV", "Internet Packet
Core Utility"));
+ ProtocolNumbers.add(new ProtocolNumber(72, "CPNX", "Computer Protocol
Network Executive"));
+ ProtocolNumbers.add(new ProtocolNumber(73, "CPHB", "Computer Protocol
Heart Beat"));
+ ProtocolNumbers.add(new ProtocolNumber(74, "WSN", "Wang Span
Network"));
+ ProtocolNumbers.add(new ProtocolNumber(75, "PVP", "Packet Video
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(76, "BR-SAT-MON", "Backroom
SATNET Monitoring"));
+ ProtocolNumbers.add(new ProtocolNumber(77, "SUN-ND", "SUN ND
PROTOCOL-Temporary"));
+ ProtocolNumbers.add(new ProtocolNumber(78, "WB-MON", "WIDEBAND
Monitoring"));
+ ProtocolNumbers.add(new ProtocolNumber(79, "WB-EXPAK", "WIDEBAND
EXPAK"));
+ ProtocolNumbers.add(new ProtocolNumber(80, "ISO-IP", "ISO Internet
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(81, "VMTP", "VMTP"));
+ ProtocolNumbers.add(new ProtocolNumber(82, "SECURE-VMTP",
"SECURE-VMTP"));
+ ProtocolNumbers.add(new ProtocolNumber(83, "VINES", "VINES"));
+ ProtocolNumbers.add(new ProtocolNumber(84, "TTP or IPTM", "Internet
Protocol Traffic Manager"));
+ ProtocolNumbers.add(new ProtocolNumber(85, "NSFNET-IGP",
"NSFNET-IGP"));
+ ProtocolNumbers.add(new ProtocolNumber(86, "DGP", "Dissimilar Gateway
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(87, "TCF", "TCF"));
+ ProtocolNumbers.add(new ProtocolNumber(88, "EIGRP", "EIGRP"));
+ ProtocolNumbers.add(new ProtocolNumber(89, "OSPFIGP", "OSPFIGP"));
+ ProtocolNumbers.add(new ProtocolNumber(90, "Sprite-RPC", "Sprite RPC
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(91, "LARP", "Locus Address
Resolution Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(92, "MTP", "Multicast Transport
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(93, "AX.25", "AX.25 Frames"));
+ ProtocolNumbers.add(new ProtocolNumber(94, "IPIP", "IP-within-IP
Encapsulation Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(95, "MICP (deprecated)",
"Mobile Internetworking Control Pro."));
+ ProtocolNumbers.add(new ProtocolNumber(96, "SCC-SP", "Semaphore
Communications Sec. Pro."));
+ ProtocolNumbers.add(new ProtocolNumber(97, "ETHERIP",
"Ethernet-within-IP Encapsulation"));
+ ProtocolNumbers.add(new ProtocolNumber(98, "ENCAP", "Encapsulation
Header"));
+ ProtocolNumbers.add(new ProtocolNumber(99, "Any private encryption
scheme", "Any private encryption scheme"));
+ ProtocolNumbers.add(new ProtocolNumber(100, "GMTP", "GMTP"));
+ ProtocolNumbers.add(new ProtocolNumber(101, "IFMP", "Ipsilon Flow
Management Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(102, "PNNI", "PNNI over IP"));
+ ProtocolNumbers.add(new ProtocolNumber(103, "PIM", "Protocol
Independent Multicast"));
+ ProtocolNumbers.add(new ProtocolNumber(104, "ARIS", "ARIS"));
+ ProtocolNumbers.add(new ProtocolNumber(105, "SCPS", "SCPS"));
+ ProtocolNumbers.add(new ProtocolNumber(106, "QNX", "QNX"));
+ ProtocolNumbers.add(new ProtocolNumber(107, "A/N", "Active Networks"));
+ ProtocolNumbers.add(new ProtocolNumber(108, "IPComp", "IP Payload
Compression Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(109, "SNP", "Sitara Networks
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(110, "Compaq-Peer", "Compaq
Peer Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(111, "IPX-in-IP", "IPX in IP"));
+ ProtocolNumbers.add(new ProtocolNumber(112, "VRRP", "Virtual Router
Redundancy Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(113, "PGM", "PGM Reliable
Transport Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(114, "Any 0-hop protocol", "Any
0-hop protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(115, "L2TP", "Layer Two
Tunneling Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(116, "DDX", "D-II Data Exchange
(DDX)"));
+ ProtocolNumbers.add(new ProtocolNumber(117, "IATP", "Interactive Agent
Transfer Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(118, "STP", "Schedule Transfer
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(119, "SRP", "SpectraLink Radio
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(120, "UTI", "UTI"));
+ ProtocolNumbers.add(new ProtocolNumber(121, "SMP", "Simple Message
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(122, "SM (deprecated)", "Simple
Multicast Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(123, "PTP", "Performance
Transparency Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(124, "ISIS over IPv4", ""));
+ ProtocolNumbers.add(new ProtocolNumber(125, "FIRE", ""));
+ ProtocolNumbers.add(new ProtocolNumber(126, "CRTP", "Combat Radio
Transport Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(127, "CRUDP", "Combat Radio
User Datagram"));
+ ProtocolNumbers.add(new ProtocolNumber(128, "SSCOPMCE", ""));
+ ProtocolNumbers.add(new ProtocolNumber(129, "IPLT", ""));
+ ProtocolNumbers.add(new ProtocolNumber(130, "SPS", "Secure Packet
Shield"));
+ ProtocolNumbers.add(new ProtocolNumber(131, "PIPE", "Private IP
Encapsulation within IP"));
+ ProtocolNumbers.add(new ProtocolNumber(132, "SCTP", "Stream Control
Transmission Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(133, "FC", "Fibre Channel"));
+ ProtocolNumbers.add(new ProtocolNumber(134, "RSVP-E2E-IGNORE", ""));
+ ProtocolNumbers.add(new ProtocolNumber(135, "Mobility Header", ""));
+ ProtocolNumbers.add(new ProtocolNumber(136, "UDPLite", ""));
+ ProtocolNumbers.add(new ProtocolNumber(137, "MPLS-in-IP", ""));
+ ProtocolNumbers.add(new ProtocolNumber(138, "manet", "MANET
Protocols"));
+ ProtocolNumbers.add(new ProtocolNumber(139, "HIP", "Host Identity
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(140, "Shim6", "Shim6
Protocol"));
+ ProtocolNumbers.add(new ProtocolNumber(141, "WESP", "Wrapped
Encapsulating Security Payload"));
+ ProtocolNumbers.add(new ProtocolNumber(142, "ROHC", "Robust Header
Compression"));
+ ProtocolNumbers.add(new ProtocolNumber(143, "Ethernet", "Ethernet"));
+ ProtocolNumbers.add(new ProtocolNumber(144, "AGGFRAG", "AGGFRAG
encapsulation payload for ESP"));
+ ProtocolNumbers.add(new ProtocolNumber(145, "NSH", "Network Service
Header"));
+ }
+ /**
+ * Different Internet Protocol Numbers.
+ */
+ public static class ProtocolNumber {
+
+ private final Integer number;
+
+ private final String keyword;
+
+ private final String protocol;
+
+ public ProtocolNumber(Integer number, String keyword, String protocol)
{
+ this.number = number;
+ this.keyword = keyword;
+ this.protocol = protocol;
+ }
+
+ public Integer getNumber() {
+ return number;
+ }
+
+ public String getKeyword() {
+ return keyword;
+ }
+
+ public String getProtocol() {
+ return protocol;
+ }
+ }
+
+ // Refer to
https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml
+ public static List<IcmpType> IcmpTypes = new ArrayList<>();
+ static {
+ IcmpTypes.add(new IcmpType(0, "Echo Reply"));
+ IcmpTypes.add(new IcmpType(3, "Destination Unreachable"));
+ IcmpTypes.add(new IcmpType(5, "Redirect"));
+ IcmpTypes.add(new IcmpType(8, "Echo"));
+ IcmpTypes.add(new IcmpType(9, "Router Advertisement"));
+ IcmpTypes.add(new IcmpType(10, "Router Solicitation"));
+ IcmpTypes.add(new IcmpType(11, "Time Exceeded"));
+ IcmpTypes.add(new IcmpType(12, "Parameter Problem"));
+ IcmpTypes.add(new IcmpType(13, "Timestamp"));
+ IcmpTypes.add(new IcmpType(14, "Timestamp Reply"));
+ IcmpTypes.add(new IcmpType(40, "Photuris"));
+ IcmpTypes.add(new IcmpType(42, "Extended Echo Request"));
+ IcmpTypes.add(new IcmpType(43, "Extended Echo Reply"));
+ }
+
+ /**
+ * Different types of ICMP (Internet Control Message Protocol).
+ */
+ public static class IcmpType {
+
+ private final Integer type;
+
+ private final String description;
+
+ private final List<IcmpCode> icmpCodes = new ArrayList<>();
+
+ public IcmpType(Integer type, String description) {
+ this.type = type;
+ this.description = description;
+ }
+
+ public Integer getType() {
+ return type;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public List<IcmpCode> getIcmpCodes() {
+ return icmpCodes;
+ }
+
+ public void addIcmpCodes(IcmpCode code) {
+ this.icmpCodes.add(code);
+ }
+ }
+
+ static void addIcmpCode(IcmpCode code) {
+ IcmpType type = IcmpTypes.stream().filter(icmpType ->
icmpType.getType().equals(code.getType())).findFirst().get();
+ type.addIcmpCodes(code);
+ }
+
+ public static boolean validateIcmpTypeAndCode(Integer type, Integer code) {
+ if (type != null && type != -1) {
+ Optional<IcmpType> icmpTypeOptional = IcmpTypes.stream().filter(t
-> t.getType().equals(type)).findFirst();
+ if (icmpTypeOptional == null || icmpTypeOptional.isEmpty()) {
+ return false;
+ }
+ IcmpType icmpType = icmpTypeOptional.get();
+ if (code != null && code != -1) {
+ Optional<IcmpCode> icmpCodeOptional =
icmpType.getIcmpCodes().stream().filter(c ->
c.getCode().equals(code)).findFirst();
+ if (icmpCodeOptional == null || icmpCodeOptional.isEmpty()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ static {
+ addIcmpCode(new IcmpCode(0, 0, "Echo reply"));
+ addIcmpCode(new IcmpCode(3, 0, "Net unreachable"));
+ addIcmpCode(new IcmpCode(3, 1, "Host unreachable"));
+ addIcmpCode(new IcmpCode(3, 2, "Protocol unreachable"));
+ addIcmpCode(new IcmpCode(3, 3, "Port unreachable"));
+ addIcmpCode(new IcmpCode(3, 4, "Fragmentation needed and DF set"));
+ addIcmpCode(new IcmpCode(3, 5, "Source route failed"));
+ addIcmpCode(new IcmpCode(3, 6, "Destination network unknown"));
+ addIcmpCode(new IcmpCode(3, 7, "Destination host unknown"));
+ addIcmpCode(new IcmpCode(3, 9, "Network administratively prohibited"));
+ addIcmpCode(new IcmpCode(3, 10, "Host administratively prohibited"));
+ addIcmpCode(new IcmpCode(3, 11, "Network unreachable for ToS"));
+ addIcmpCode(new IcmpCode(3, 12, "Host unreachable for ToS"));
+ addIcmpCode(new IcmpCode(3, 13, "Communication administratively
prohibited"));
+ addIcmpCode(new IcmpCode(3, 14, "Host Precedence Violation"));
+ addIcmpCode(new IcmpCode(3, 15, "Precedence cutoff in effect"));
+ addIcmpCode(new IcmpCode(5, 0, "Redirect Datagram for the Network"));
+ addIcmpCode(new IcmpCode(5, 1, "Redirect Datagram for the Host"));
+ addIcmpCode(new IcmpCode(5, 2, "Redirect Datagram for the ToS &
network"));
+ addIcmpCode(new IcmpCode(5, 3, "Redirect Datagram for the ToS &
host"));
+ addIcmpCode(new IcmpCode(8, 0, "Echo request"));
+ addIcmpCode(new IcmpCode(9, 0, "Router advertisement"));
+ addIcmpCode(new IcmpCode(9, 16, "Does not route common traffic"));
+ addIcmpCode(new IcmpCode(10, 0, "Router solicitation"));
+ addIcmpCode(new IcmpCode(11, 0, "TTL expired in transit"));
+ addIcmpCode(new IcmpCode(11, 1, "Fragment reassembly time exceeded"));
+ addIcmpCode(new IcmpCode(12, 0, "Parameter problem: Pointer indicates
the error"));
+ addIcmpCode(new IcmpCode(12, 1, "Parameter problem: Missing a required
option"));
+ addIcmpCode(new IcmpCode(12, 2, "Parameter problem: Bad length"));
+ addIcmpCode(new IcmpCode(13, 0, "Timestamp"));
+ addIcmpCode(new IcmpCode(14, 0, "Timestamp reply"));
+ addIcmpCode(new IcmpCode(40, 0, "Photuris: Security failures"));
+ addIcmpCode(new IcmpCode(40, 1, "Photuris: Authentication failed"));
+ addIcmpCode(new IcmpCode(40, 2, "Photuris: Decompression failed"));
+ addIcmpCode(new IcmpCode(40, 3, "Photuris: Decryption failed"));
+ addIcmpCode(new IcmpCode(40, 4, "Photuris: Need authentication"));
+ addIcmpCode(new IcmpCode(40, 5, "Photuris: Need authorization"));
+ }
+
+ /**
+ * Code field of ICMP types.
+ */
+ public static class IcmpCode {
+
+ private final Integer type;
+ private final Integer code;
+ private final String description;
+
+ public IcmpCode(Integer type, Integer code, String description) {
+ this.type = type;
+ this.code = code;
+ this.description = description;
+ }
+
+ public Integer getType() {
+ return type;
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+ }
+}
diff --git a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
index defb440c2a5..5da4ac96d69 100644
--- a/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
+++ b/utils/src/test/java/com/cloud/utils/net/NetUtilsTest.java
@@ -843,4 +843,50 @@ public class NetUtilsTest {
Assert.assertEquals(expected, result);
networkInterfaceMocked.close();
}
+
+ @Test
+ public void validateIcmpTypeAndCodesGood1() {
+ NetUtils.validateIcmpTypeAndCode(-1, -1);
+ }
+ @Test
+ public void validateIcmpTypeAndCodesGood2() {
+ NetUtils.validateIcmpTypeAndCode(3, 2);
+ }
+
+ @Test(expected=CloudRuntimeException.class)
+ public void validateIcmpTypeAndCodesThrowsException1() {
+ NetUtils.validateIcmpTypeAndCode(null, null);
+ }
+ @Test(expected=CloudRuntimeException.class)
+ public void validateIcmpTypeAndCodesThrowsException2() {
+ NetUtils.validateIcmpTypeAndCode(null, -1);
+ }
+ @Test(expected=CloudRuntimeException.class)
+ public void validateIcmpTypeAndCodesThrowsException3() {
+ NetUtils.validateIcmpTypeAndCode(-1, null);
+ }
+ @Test(expected=CloudRuntimeException.class)
+ public void validateIcmpTypeAndCodesThrowsException4() {
+ NetUtils.validateIcmpTypeAndCode(-1, 2);
+ }
+ @Test(expected=CloudRuntimeException.class)
+ public void validateIcmpTypeAndCodesThrowsException5() {
+ NetUtils.validateIcmpTypeAndCode(3, -1);
+ }
+ @Test(expected=CloudRuntimeException.class)
+ public void validateIcmpTypeAndCodesThrowsException6() {
+ NetUtils.validateIcmpTypeAndCode(-2, 2);
+ }
+ @Test(expected=CloudRuntimeException.class)
+ public void validateIcmpTypeAndCodesThrowsException7() {
+ NetUtils.validateIcmpTypeAndCode(257, 2);
+ }
+ @Test(expected=CloudRuntimeException.class)
+ public void validateIcmpTypeAndCodesThrowsException8() {
+ NetUtils.validateIcmpTypeAndCode(3, -2);
+ }
+ @Test(expected=CloudRuntimeException.class)
+ public void validateIcmpTypeAndCodesThrowsException9() {
+ NetUtils.validateIcmpTypeAndCode(3, -257);
+ }
}
diff --git a/utils/src/test/java/com/cloud/utils/net/NetworkProtocolsTest.java
b/utils/src/test/java/com/cloud/utils/net/NetworkProtocolsTest.java
new file mode 100644
index 00000000000..9f1780ba2e7
--- /dev/null
+++ b/utils/src/test/java/com/cloud/utils/net/NetworkProtocolsTest.java
@@ -0,0 +1,47 @@
+//
+// 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 com.cloud.utils.net;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+
+
+@RunWith(MockitoJUnitRunner.class)
+public class NetworkProtocolsTest {
+
+ @Test
+ public void validateIcmpTypeAndCode() {
+ validateIcmpTypeAndCodeInternal(null, null, true);
+ validateIcmpTypeAndCodeInternal(null, -1, true);
+ validateIcmpTypeAndCodeInternal(-1, -1, true);
+ validateIcmpTypeAndCodeInternal(3, -1, true);
+ validateIcmpTypeAndCodeInternal(3, 15, true);
+ validateIcmpTypeAndCodeInternal(4, -1, false);
+ validateIcmpTypeAndCodeInternal(5, 10, false);
+ }
+
+ private void validateIcmpTypeAndCodeInternal(Integer type, Integer code,
boolean expected) {
+ boolean actual = NetworkProtocols.validateIcmpTypeAndCode(type, code);
+ Assert.assertEquals(expected, actual);
+ }
+}