diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/AuthorizeSecurityGroupIngressCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/AuthorizeSecurityGroupIngressCmd.java index a8073862933..fb66e31622f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/AuthorizeSecurityGroupIngressCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/securitygroup/AuthorizeSecurityGroupIngressCmd.java @@ -58,7 +58,7 @@ public class AuthorizeSecurityGroupIngressCmd extends BaseAsyncCmd { // ////////////// API parameters ///////////////////// // /////////////////////////////////////////////////// - @Parameter(name = ApiConstants.PROTOCOL, type = CommandType.STRING, description = "TCP is default. UDP is the other supported protocol") + @Parameter(name = ApiConstants.PROTOCOL, type = CommandType.STRING, description = "the protocol for the ACL rule. Valid values are TCP/UDP/ICMP/ALL or valid protocol number (see /etc/protocols). ALL is default.") private String protocol; @Parameter(name = ApiConstants.START_PORT, type = CommandType.INTEGER, description = "start port for this ingress rule") diff --git a/scripts/vm/network/security_group.py b/scripts/vm/network/security_group.py index 82f5bc7e3d9..2ca7ba82a4e 100755 --- a/scripts/vm/network/security_group.py +++ b/scripts/vm/network/security_group.py @@ -1032,7 +1032,18 @@ def add_network_rules(vm_name, vm_id, vm_ip, vm_ip6, signature, seqno, vmMac, ru action = "ACCEPT" direction = "-s" - range = str(start) + ':' + str(end) + if start == 0 and end == 0: + dport = "" + else: + dport = " --dport " + str(start) + ":" + str(end) + + if protocol != 'all' and protocol != 'icmp' and protocol != 'tcp' and protocol != 'udp': + protocol_all = " -p " + protocol + protocol_state = " " + else: + protocol_all = " -p " + protocol + " -m " + protocol + protocol_state = " -m state --state NEW " + if 'icmp' == protocol: range = str(start) + '/' + str(end) if start == -1: @@ -1041,16 +1052,16 @@ def add_network_rules(vm_name, vm_id, vm_ip, vm_ip6, signature, seqno, vmMac, ru for ip in rule['ipv4']: if protocol == 'all': execute('iptables -I ' + vmchain + ' -m state --state NEW ' + direction + ' ' + ip + ' -j ' + action) - elif protocol != 'icmp': - execute('iptables -I ' + vmchain + ' -p ' + protocol + ' -m ' + protocol + ' --dport ' + range + ' -m state --state NEW ' + direction + ' ' + ip + ' -j ' + action) + elif protocol == 'icmp': + execute("iptables -I " + vmchain + " -p icmp --icmp-type " + range + " " + direction + " " + ip + " -j " + action) else: - execute('iptables -I ' + vmchain + ' -p icmp --icmp-type ' + range + ' ' + direction + ' ' + ip + ' -j ' + action) + execute("iptables -I " + vmchain + protocol_all + dport + protocol_state + direction + " " + ip + " -j "+ action) for ip in rule['ipv6']: if protocol == 'all': execute('ip6tables -I ' + vmchain + ' -m state --state NEW ' + direction + ' ' + ip + ' -j ' + action) elif 'icmp' != protocol: - execute('ip6tables -I ' + vmchain + ' -p ' + protocol + ' -m ' + protocol + ' --dport ' + range + ' -m state --state NEW ' + direction + ' ' + ip + ' -j ' + action) + execute("ip6tables -I " + vmchain + protocol_all + dport + protocol_state + direction + " " + ip + " -j "+ action) else: # ip6tables does not allow '--icmpv6-type any', allowing all ICMPv6 is done by not allowing a specific type if range == 'any': 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 07d7e4d1b8f..a0c828588c0 100644 --- a/server/src/main/java/com/cloud/network/security/SecurityGroupManagerImpl.java +++ b/server/src/main/java/com/cloud/network/security/SecurityGroupManagerImpl.java @@ -50,6 +50,7 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.utils.identity.ManagementServerNode; import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; @@ -617,10 +618,27 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro } } - if (!NetUtils.isValidSecurityGroupProto(protocol)) { - throw new InvalidParameterValueException("Invalid protocol " + protocol); + //Validate Protocol + protocol = protocol.trim().toLowerCase(); + //Check if protocol is a number + 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; + } else if(protoNumber < 0 || protoNumber > 255){ + throw new InvalidParameterValueException("Invalid protocol number: " + protoNumber); + } + } else { + //Protocol is not number + //Check for valid protocol strings + if (!NetUtils.isValidSecurityGroupProto(protocol)) { + throw new InvalidParameterValueException("Invalid protocol " + protocol); + } } - if ("icmp".equalsIgnoreCase(protocol)) { + if (protocol.equals(NetUtils.ICMP_PROTO)) { if ((icmpType == null) || (icmpCode == null)) { throw new InvalidParameterValueException("Invalid ICMP type/code specified, icmpType = " + icmpType + ", icmpCode = " + icmpCode); } @@ -641,7 +659,7 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro } startPortOrType = 0; endPortOrCode = 0; - } else { + } else if (protocol.equals(NetUtils.TCP_PROTO) || protocol.equals(NetUtils.UDP_PROTO)) { if ((startPort == null) || (endPort == null)) { throw new InvalidParameterValueException("Invalid port range specified, startPort = " + startPort + ", endPort = " + endPort); } @@ -660,10 +678,13 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro } startPortOrType = startPort; endPortOrCode = endPort; + } else { + // in 4.6, the start port and end port are ignored in definition of ProtocolAclRule + // see core/src/com/cloud/agent/resource/virtualnetwork/facade/SetNetworkAclConfigItem.java + startPortOrType = 0; + endPortOrCode = 0; } - protocol = protocol.toLowerCase(); - List authorizedGroups = new ArrayList(); if (groupList != null) { Collection userGroupCollection = groupList.values(); diff --git a/test/integration/component/test_protocol_number_security_group.py b/test/integration/component/test_protocol_number_security_group.py new file mode 100644 index 00000000000..60296753845 --- /dev/null +++ b/test/integration/component/test_protocol_number_security_group.py @@ -0,0 +1,460 @@ +# 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. + +""" +Tests protocol number support for security groups +""" + +# Import Local Modules +from nose.plugins.attrib import attr +from marvin.cloudstackTestCase import cloudstackTestCase, unittest +from marvin.cloudstackAPI import authorizeSecurityGroupIngress, revokeSecurityGroupIngress, authorizeSecurityGroupEgress, revokeSecurityGroupEgress +from marvin.sshClient import SshClient +from marvin.lib.utils import (validateList, + cleanup_resources, + get_host_credentials) +from marvin.lib.base import (Account, + Host, + Domain, + VirtualMachine, + ServiceOffering, + Zone, + SecurityGroup) +from marvin.lib.common import (get_domain, + get_zone, + get_template, + list_hosts) +import logging + +class TestProtocolNumberSecurityGroup(cloudstackTestCase): + @classmethod + def setUpClass(cls): + cls.testClient = super( + TestProtocolNumberSecurityGroup, + cls).getClsTestClient() + cls.apiclient = cls.testClient.getApiClient() + cls.testdata = cls.testClient.getParsedTestDataConfig() + cls.services = cls.testClient.getParsedTestDataConfig() + + zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests()) + cls.zone = Zone(zone.__dict__) + cls.template = get_template(cls.apiclient, cls.zone.id) + cls._cleanup = [] + + if str(cls.zone.securitygroupsenabled) != "True": + sys.exit(1) + + cls.logger = logging.getLogger("TestProtocolNumberSecurityGroup") + cls.stream_handler = logging.StreamHandler() + cls.logger.setLevel(logging.DEBUG) + cls.logger.addHandler(cls.stream_handler) + + # Get Zone, Domain and templates + cls.domain = get_domain(cls.apiclient) + testClient = super(TestProtocolNumberSecurityGroup, cls).getClsTestClient() + cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests()) + cls.services['mode'] = cls.zone.networktype + + # Create new domain, account, network and VM + cls.user_domain = Domain.create( + cls.apiclient, + services=cls.testdata["acl"]["domain2"], + parentdomainid=cls.domain.id) + + # Create account + cls.account = Account.create( + cls.apiclient, + cls.testdata["acl"]["accountD2"], + admin=True, + domainid=cls.user_domain.id + ) + + cls.service_offering = ServiceOffering.create( + cls.apiclient, + cls.testdata["service_offering"] + ) + + cls.testdata["domainid"] = cls.domain.id + cls.testdata["virtual_machine_userdata"]["zoneid"] = cls.zone.id + cls.testdata["virtual_machine_userdata"]["template"] = cls.template.id + + cls._cleanup.append(cls.service_offering) + cls._cleanup.append(cls.account) + cls._cleanup.append(cls.user_domain) + + @classmethod + def tearDownClass(self): + try: + cleanup_resources(self.apiclient, self._cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + def setUp(self): + self.apiclient = self.testClient.getApiClient() + self.cleanup = [] + return + + def tearDown(self): + try: + cleanup_resources(self.apiclient, self.cleanup) + except Exception as e: + raise Exception("Warning: Exception during cleanup : %s" % e) + return + + @attr(tags=["advancedsg"], required_hardware="false") + def test_01_add_valid_protocol_number(self): + # Validate the following + # + # 1. Create a security group + # 2. Try to add a new ingress rule by specifying a protocol number + # 3. New rule should be added successfully + # 4. Try to add a new egress rule by specifying a protocol number + # 5. New rule should be added successfully + + self.security_group = SecurityGroup.create( + self.apiclient, + self.testdata["security_group"], + account=self.account.name, + domainid=self.account.domainid + ) + self.debug("Created security group with ID: %s" % self.security_group.id) + + # Add ingress rule + self.createIngressRule("111") + + # Add egress rule + self.createEgressRule("111") + + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 1, 1) + + @attr(tags=["advancedsg"], required_hardware="false") + def test_02_add_invalid_protocol_number(self): + # Validate the following + # + # 1. Create a security group + # 2. Try to add a new ingress rule by specifying an invalid (> 255) protocol number + # 3. Exception should be thrown successfully + # 4. Try to add a new egreess rule by specifying an invalid (> 255) protocol number + # 5. Exception should be thrown successfully + + self.security_group = SecurityGroup.create( + self.apiclient, + self.testdata["security_group"], + account=self.account.name, + domainid=self.account.domainid + ) + self.debug("Created security group with ID: %s" % self.security_group.id) + + # Create ingress rule with invalid protocol number. Exception should be thrown + with self.assertRaises(Exception): + self.createIngressRule("555") + + # Create egress rule with invalid protocol number. Exception should be thrown + with self.assertRaises(Exception): + self.createEgressRule("555") + + @attr(tags=["advancedsg"], required_hardware="false") + def test_03_add_duplicate_protocol_number(self): + # Validate the following + # + # 1. Create a security group + # 2. Try to add a new ingress rule by specifying a protocol number + # 3. Try to add one more ingress rule by specifying the same protocol number + # 4. Exception should be thrown successfully + # 5. Try to add a new egress rule by specifying a protocol number + # 6. Try to add one more egress rule by specifying the same protocol number + # 7. Exception should be thrown successfully + + self.security_group = SecurityGroup.create( + self.apiclient, + self.testdata["security_group"], + account=self.account.name, + domainid=self.account.domainid + ) + self.debug("Created security group with ID: %s" % self.security_group.id) + + # Add ingress rule + self.createIngressRule("111") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 1, 0) + + # Try to add another ingress with same protocol number. Exception is thrown + with self.assertRaises(Exception): + self.createIngressRule("111") + + # Add egress rule + self.createEgressRule("111") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 1, 1) + + # Try to add another ingress with same protocol number. Exception is thrown + with self.assertRaises(Exception): + self.createEgressRule("111") + + @attr(tags=["advancedsg"], required_hardware="false") + def test_04_add_duplicate_protocol_number(self): + # Validate the following + # + # 1. Create a security group + # 2. Try to add a new ingress rule by using "all" as the protocol string + # 3. Try to add one more ingress rule by specifying the same protocol + # 4. Exception should be thrown successfully + # 5. Try to add a new egress rule by using "all" as the protocol string + # 6. Try to add one more egress rule by specifying the same protocol + # 7. Exception should be thrown successfully + + self.security_group = SecurityGroup.create( + self.apiclient, + self.testdata["security_group"], + account=self.account.name, + domainid=self.account.domainid + ) + self.debug("Created security group with ID: %s" % self.security_group.id) + + # Add ingress rule + self.createIngressRule("111") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 1, 0) + + # Try to add another ingress with same protocol number. Exception is thrown + with self.assertRaises(Exception): + self.createIngressRule("111") + + # Add egress rule + self.createEgressRule("111") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 1, 1) + + # Try to add another ingress with same protocol number. Exception is thrown + with self.assertRaises(Exception): + self.createEgressRule("111") + + @attr(tags=["advancedsg"], required_hardware="false") + def test_05_invalid_protocol_string(self): + # Validate the following + # + # 1. Create a security group + # 2. Try to add ingress rule with invalid protocol name + # 3. Exception should be thrown + # 4. Try to add egressrule with invalid protocol name + # 5. Exception should be thrown + + security_group = SecurityGroup.create( + self.apiclient, + self.testdata["security_group"], + account=self.account.name, + domainid=self.account.domainid + ) + self.debug("Created security group with ID: %s" % security_group.id) + + with self.assertRaises(Exception): + self.createIngressRule("randomprotocol") + + with self.assertRaises(Exception): + self.createEgressRule("randomprotocol") + + @attr(tags=["advancedsg"]) + def test_06_create_virtual_machine(self): + # Validate the following + # + # 1. Create a security group + # 2. Create a virtual machine + # 3. Try to add a new ingress rule + # 4. Check if ingress rule is applied successfully on host + # 5. Throw exception if it's not applied + # 6. Try to add a new egress rule + # 7. Check if egress rule is applied successfully on host + # 8. Throw exception if it's not applied + + self.security_group = SecurityGroup.create( + self.apiclient, + self.testdata["security_group"], + account=self.account.name, + domainid=self.account.domainid + ) + + self.virtual_machine = VirtualMachine.create( + self.apiclient, + self.testdata["virtual_machine_userdata"], + accountid=self.account.name, + domainid=self.account.domainid, + serviceofferingid=self.service_offering.id, + securitygroupids=[self.security_group.id] + ) + + # Get the virtual machine + virtial_machine = VirtualMachine.list( + self.apiclient, + id=self.virtual_machine.id + ) + + vm = virtial_machine[0] + + # get the host on which the vm is running + hosts = list_hosts( + self.apiclient, + id=vm.hostid + ) + + host = hosts[0] + if host.hypervisor.lower() not in "kvm": + return + + host.user, host.passwd = get_host_credentials(self.config, host.ipaddress) + + # Add ingress rule + self.createIngressRule("tcp", "1.1.1.1/32") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 1, 0) + # Check if the ingress rule if applied successfully on host + rule = "-A %s -s 1.1.1.1/32 -p tcp -m tcp --dport 1:65535 -m state --state NEW -j ACCEPT" % vm.instancename + self.verify_rule_on_host(host.ipaddress, host.user, host.passwd, rule) + + # Add ingress rule + self.createIngressRule("udp", "2.2.2.2/32") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 2, 0) + # Check if the ingress rule if applied successfully on host + rule = "-A %s -s 2.2.2.2/32 -p udp -m udp --dport 1:65535 -m state --state NEW -j ACCEPT" % vm.instancename + self.verify_rule_on_host(host.ipaddress, host.user, host.passwd, rule) + + # Add ingress rule + self.createIngressRule("icmp", "3.3.3.3/32") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 3, 0) + # Check if the ingress rule if applied successfully on host + rule = "-A %s -s 3.3.3.3/32 -p icmp -m icmp --icmp-type any -j ACCEPT" % vm.instancename + self.verify_rule_on_host(host.ipaddress, host.user, host.passwd, rule) + + # Add ingress rule + self.createIngressRule("all", "4.4.4.4/32") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 4, 0) + # Check if the ingress rule if applied successfully on host + rule = "-A %s -s 4.4.4.4/32 -m state --state NEW -j ACCEPT" % vm.instancename + self.verify_rule_on_host(host.ipaddress, host.user, host.passwd, rule) + + # Add ingress rule + self.createIngressRule("47", "5.5.5.5/32") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 5, 0) + # Check if the ingress rule if applied successfully on host + rule = "-A %s -s 5.5.5.5/32 -p gre -j ACCEPT" % vm.instancename + self.verify_rule_on_host(host.ipaddress, host.user, host.passwd, rule) + + # Add egress rule + self.createEgressRule("tcp", "11.11.11.11/32") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 5, 1) + # Check if the egress rule if applied successfully on host + rule = "-A %s-eg -d 11.11.11.11/32 -p tcp -m tcp --dport 1:65535 -m state --state NEW -j RETURN" % vm.instancename + self.verify_rule_on_host(host.ipaddress, host.user, host.passwd, rule) + + # Add egress rule + self.createEgressRule("udp", "12.12.12.12/32") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 5, 2) + # Check if the egress rule if applied successfully on host + rule = "-A %s-eg -d 12.12.12.12/32 -p udp -m udp --dport 1:65535 -m state --state NEW -j RETURN" % vm.instancename + self.verify_rule_on_host(host.ipaddress, host.user, host.passwd, rule) + + # Add egress rule + self.createEgressRule("icmp", "13.13.13.13/32") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 5, 3) + # Check if the egress rule if applied successfully on host + rule = "-A %s-eg -d 13.13.13.13/32 -p icmp -m icmp --icmp-type any -j RETURN" % vm.instancename + self.verify_rule_on_host(host.ipaddress, host.user, host.passwd, rule) + + # Add egress rule + self.createEgressRule("all", "14.14.14.14/32") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 5, 4) + # Check if the egress rule if applied successfully on host + rule = "-A %s-eg -d 14.14.14.14/32 -m state --state NEW -j RETURN" % vm.instancename + self.verify_rule_on_host(host.ipaddress, host.user, host.passwd, rule) + + # Add egress rule + self.createEgressRule("47", "15.15.15.15/32") + # verify number of ingress rules and egress rules + self.verify_security_group_rules(self.security_group.id, 5, 5) + # Check if the egress rule if applied successfully on host + rule = "-A %s-eg -d 15.15.15.15/32 -p gre -j RETURN" % vm.instancename + self.verify_rule_on_host(host.ipaddress, host.user, host.passwd, rule) + + def createIngressRule(self, protocol, cidrlist=None): + cmd = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressCmd() + cmd.account=self.account.name + cmd.domainid=self.account.domainid + cmd.securitygroupid=self.security_group.id + cmd.cidrlist="99.99.99.99/32" + if cidrlist: + cmd.cidrlist=cidrlist + cmd.protocol=protocol + if protocol == "tcp" or protocol == "udp": + cmd.startport = 1 + cmd.endport = 65535 + elif protocol == "icmp": + cmd.icmptype = -1 + cmd.icmpcode = -1 + self.apiclient.authorizeSecurityGroupIngress(cmd) + cmd = None + + def createEgressRule(self, protocol, cidrlist=None): + cmd = authorizeSecurityGroupEgress.authorizeSecurityGroupEgressCmd() + cmd.account=self.account.name + cmd.domainid=self.account.domainid + cmd.securitygroupid=self.security_group.id + cmd.cidrlist="88.88.88.88/32" + if cidrlist: + cmd.cidrlist=cidrlist + cmd.protocol=protocol + if protocol == "tcp" or protocol == "udp": + cmd.startport = 1 + cmd.endport = 65535 + elif protocol == "icmp": + cmd.icmptype = -1 + cmd.icmpcode = -1 + self.apiclient.authorizeSecurityGroupEgress(cmd) + cmd = None + + def verify_security_group_rules(self, securitygroupid, numIngress, numEgress): + security_groups = SecurityGroup.list( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + id=securitygroupid + ) + ingressrule = security_groups[0].ingressrule + if len(ingressrule) != numIngress: + raise Exception("Failed to verify ingress rule for security group %s" % security_groups[0].name) + egressrule = security_groups[0].egressrule + if len(egressrule) != numEgress: + raise Exception("Failed to verify egress rule for security group %s" % security_groups[0].name) + + def verify_rule_on_host(self, ipaddress, user, password, rule): + self.logger.debug("Verifying rule '%s' in host %s" % (rule, ipaddress)) + try: + ssh = SshClient(ipaddress, 22, user, password) + result = ssh.execute("iptables-save |grep \"\\%s\"" % rule) + if len(result) == 0 or result[0] != rule: + raise Exception("Unable to apply security group rule") + except KeyError: + self.skipTest( + "Provide a marvin config file with host credentials to run %s" % self._testMethodName) diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 353572c22ee..f93fc5578a4 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -41,6 +41,10 @@ elemData.endport = icmpcode; } + if (elemData.protocol != 'tcp' && elemData.protocol != 'udp' && elemData.protocol != 'icmp') { + elemData.startport = 'all'; + elemData.endport = 'all'; + } return elemData; }; @@ -4581,7 +4585,8 @@ var $otherFields = $inputs.filter(function() { var name = $(this).attr('rel'); - return name != 'icmptype' && + return name != 'protocolnumber' && + name != 'icmptype' && name != 'icmpcode' && name != 'protocol' && name != 'add-rule' && @@ -4590,12 +4595,35 @@ name != 'securitygroup'; }); - if ($(this).val() == 'icmp') { - $icmpFields.show(); - $otherFields.hide(); - } else { + $portFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + return $.inArray(name, [ + 'startport', + 'endport' + ]) > -1; + }); + $protocolFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + + return $.inArray(name, ['protocolnumber']) > -1; + }); + + if ($(this).val() == 'protocolnumber') { $icmpFields.hide(); + $portFields.hide(); + $protocolFields.show(); + } else if ($(this).val() == 'icmp') { + $icmpFields.show(); + $protocolFields.hide(); + $portFields.hide(); + } else if ($(this).val() == 'all') { + $portFields.hide(); + $icmpFields.hide(); + $protocolFields.hide(); + } else { $otherFields.show(); + $icmpFields.hide(); + $protocolFields.hide(); } }); @@ -4609,10 +4637,22 @@ }, { name: 'icmp', description: 'ICMP' + }, { + name: 'all', + description: 'ALL' + }, { + name: 'protocolnumber', + description: 'Protocol Number' }] }); } }, + 'protocolnumber': { + label: 'label.protocol.number', + edit: true, + isHidden: true, + isEditable: true + }, 'startport': { edit: true, label: 'label.start.port', @@ -4663,11 +4703,20 @@ action: function(args) { var data = { securitygroupid: args.context.securityGroups[0].id, - protocol: args.data.protocol, domainid: args.context.securityGroups[0].domainid, account: args.context.securityGroups[0].account }; + if (args.data.protocol == 'protocolnumber') { + $.extend(data, { + protocol: args.data.protocolnumber + }); + } else { + $.extend(data, { + protocol: args.data.protocol + }); + } + if (args.data.icmptype && args.data.icmpcode) { // ICMP $.extend(data, { icmptype: args.data.icmptype, @@ -4791,7 +4840,8 @@ var $otherFields = $inputs.filter(function() { var name = $(this).attr('rel'); - return name != 'icmptype' && + return name != 'protocolnumber' && + name != 'icmptype' && name != 'icmpcode' && name != 'protocol' && name != 'add-rule' && @@ -4800,12 +4850,35 @@ name != 'securitygroup'; }); - if ($(this).val() == 'icmp') { - $icmpFields.show(); - $otherFields.hide(); - } else { + $portFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + return $.inArray(name, [ + 'startport', + 'endport' + ]) > -1; + }); + $protocolFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + + return $.inArray(name, ['protocolnumber']) > -1; + }); + + if ($(this).val() == 'protocolnumber') { $icmpFields.hide(); + $portFields.hide(); + $protocolFields.show(); + } else if ($(this).val() == 'icmp') { + $icmpFields.show(); + $protocolFields.hide(); + $portFields.hide(); + } else if ($(this).val() == 'all') { + $portFields.hide(); + $icmpFields.hide(); + $protocolFields.hide(); + } else { $otherFields.show(); + $icmpFields.hide(); + $protocolFields.hide(); } }); @@ -4819,10 +4892,22 @@ }, { name: 'icmp', description: 'ICMP' + }, { + name: 'all', + description: 'ALL' + }, { + name: 'protocolnumber', + description: 'Protocol Number' }] }); } }, + 'protocolnumber': { + label: 'label.protocol.number', + edit: true, + isHidden: true, + isEditable: true + }, 'startport': { edit: true, label: 'label.start.port', @@ -4873,11 +4958,20 @@ action: function(args) { var data = { securitygroupid: args.context.securityGroups[0].id, - protocol: args.data.protocol, domainid: args.context.securityGroups[0].domainid, account: args.context.securityGroups[0].account }; + if (args.data.protocol == 'protocolnumber') { + $.extend(data, { + protocol: args.data.protocolnumber + }); + } else { + $.extend(data, { + protocol: args.data.protocol + }); + } + if (args.data.icmptype && args.data.icmpcode) { // ICMP $.extend(data, { icmptype: args.data.icmptype,