mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-30 17:13:08 +08:00
fix: allow security group cidr have multiple prefixes (#25122)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
@@ -16,6 +16,7 @@ package compute
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
@@ -136,6 +137,24 @@ type SSecgroupRuleUpdateInput struct {
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func IsValidSecgroupRuleCIDR(cidr string) bool {
|
||||
isInvalidCidr := func(cidr string) bool {
|
||||
return !regutils.MatchCIDR(cidr) && !regutils.MatchIP4Addr(cidr) && !regutils.MatchCIDR6(cidr) && !regutils.MatchIP6Addr(cidr)
|
||||
}
|
||||
|
||||
if strings.Contains(cidr, ",") {
|
||||
cidrs := strings.Split(cidr, ",")
|
||||
for i := range cidrs {
|
||||
if isInvalidCidr(cidrs[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else if isInvalidCidr(cidr) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (input *SSecgroupRuleResource) Check() error {
|
||||
priority := 1
|
||||
if input.Priority != nil {
|
||||
@@ -159,8 +178,8 @@ func (input *SSecgroupRuleResource) Check() error {
|
||||
}
|
||||
|
||||
if len(input.CIDR) > 0 {
|
||||
if !regutils.MatchCIDR(input.CIDR) && !regutils.MatchIP4Addr(input.CIDR) && !regutils.MatchCIDR6(input.CIDR) && !regutils.MatchIP6Addr(input.CIDR) {
|
||||
return fmt.Errorf("invalid ip address: %s", input.CIDR)
|
||||
if !IsValidSecgroupRuleCIDR(input.CIDR) {
|
||||
return fmt.Errorf("invalid cidr: %s", input.CIDR)
|
||||
}
|
||||
} else {
|
||||
// empty CIDR means both IPv4 and IPv6
|
||||
|
||||
@@ -3500,7 +3500,7 @@ func (self *SGuest) getSecurityGroupsRules() string {
|
||||
}
|
||||
rules := []string{}
|
||||
for _, rule := range secrules {
|
||||
rules = append(rules, rule.String())
|
||||
rules = append(rules, rule.Strings()...)
|
||||
}
|
||||
return strings.Join(rules, SECURITY_GROUP_SEPARATOR)
|
||||
}
|
||||
@@ -3520,7 +3520,7 @@ func (self *SGuest) getNetworkSecurityGroupsRules(networkIndex int) string {
|
||||
}
|
||||
rules := []string{}
|
||||
for _, rule := range secrules {
|
||||
rules = append(rules, rule.String())
|
||||
rules = append(rules, rule.Strings()...)
|
||||
}
|
||||
return strings.Join(rules, SECURITY_GROUP_SEPARATOR)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
||||
@@ -25,7 +24,6 @@ import (
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/compare"
|
||||
"yunion.io/x/pkg/util/rbacscope"
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
"yunion.io/x/pkg/util/secrules"
|
||||
"yunion.io/x/pkg/util/stringutils"
|
||||
"yunion.io/x/sqlchemy"
|
||||
@@ -39,6 +37,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
"yunion.io/x/onecloud/pkg/util/netutils2"
|
||||
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
||||
)
|
||||
|
||||
@@ -319,10 +318,6 @@ func (self *SSecurityGroupRule) ValidateUpdateData(ctx context.Context, userCred
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if input.CIDR == nil {
|
||||
// input.CIDR = &self.CIDR
|
||||
}
|
||||
|
||||
driver, err := secgrp.GetRegionDriver()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -341,15 +336,19 @@ func (self *SSecurityGroupRule) ValidateUpdateData(ctx context.Context, userCred
|
||||
return input, nil
|
||||
}
|
||||
|
||||
func (self *SSecurityGroupRule) String() string {
|
||||
rule, err := self.toRule()
|
||||
func (self *SSecurityGroupRule) Strings() []string {
|
||||
rules, err := self.toRules()
|
||||
if err != nil {
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
return rule.String()
|
||||
ruleStrs := make([]string, len(rules))
|
||||
for i := range rules {
|
||||
ruleStrs[i] = rules[i].String()
|
||||
}
|
||||
return ruleStrs
|
||||
}
|
||||
|
||||
func (self *SSecurityGroupRule) toRule() (*secrules.SecurityRule, error) {
|
||||
func (self *SSecurityGroupRule) toRules() ([]*secrules.SecurityRule, error) {
|
||||
rule := secrules.SecurityRule{
|
||||
Priority: int(self.Priority),
|
||||
Direction: secrules.TSecurityRuleDirection(self.Direction),
|
||||
@@ -357,33 +356,31 @@ func (self *SSecurityGroupRule) toRule() (*secrules.SecurityRule, error) {
|
||||
Protocol: self.Protocol,
|
||||
Description: self.Description,
|
||||
}
|
||||
if regutils.MatchCIDR(self.CIDR) || regutils.MatchCIDR6(self.CIDR) {
|
||||
_, rule.IPNet, _ = net.ParseCIDR(self.CIDR)
|
||||
} else if regutils.MatchIP4Addr(self.CIDR) {
|
||||
rule.IPNet = &net.IPNet{
|
||||
IP: net.ParseIP(self.CIDR),
|
||||
Mask: net.CIDRMask(32, 32),
|
||||
{
|
||||
err := rule.ParsePorts(self.Ports)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ParsePorts")
|
||||
}
|
||||
} else if regutils.MatchIP6Addr(self.CIDR) {
|
||||
rule.IPNet = &net.IPNet{
|
||||
IP: net.ParseIP(self.CIDR),
|
||||
Mask: net.CIDRMask(128, 128),
|
||||
}
|
||||
{
|
||||
err := rule.ValidateRule()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ValidateRule")
|
||||
}
|
||||
} else {
|
||||
// any
|
||||
}
|
||||
|
||||
ipnets := netutils2.Str2IPNets(self.CIDR)
|
||||
if len(ipnets) == 0 {
|
||||
rule.IPNet = nil
|
||||
/* &net.IPNet{
|
||||
IP: net.IPv4zero,
|
||||
Mask: net.CIDRMask(0, 32),
|
||||
} */
|
||||
return []*secrules.SecurityRule{&rule}, nil
|
||||
}
|
||||
|
||||
err := rule.ParsePorts(self.Ports)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
rules := make([]*secrules.SecurityRule, len(ipnets))
|
||||
for i := range ipnets {
|
||||
ruleClone := rule
|
||||
ruleClone.IPNet = ipnets[i]
|
||||
rules[i] = &ruleClone
|
||||
}
|
||||
|
||||
return &rule, rule.ValidateRule()
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func (self *SSecurityGroupRule) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
||||
@@ -448,15 +445,6 @@ func (self *SSecurityGroup) StartSecurityGroupRuleUpdateTask(ctx context.Context
|
||||
return task.ScheduleRun(nil)
|
||||
}
|
||||
|
||||
func (manager *SSecurityGroupRuleManager) getRulesBySecurityGroup(secgroup *SSecurityGroup) ([]SSecurityGroupRule, error) {
|
||||
rules := make([]SSecurityGroupRule, 0)
|
||||
q := manager.Query().Equals("secgroup_id", secgroup.Id)
|
||||
if err := db.FetchModelObjects(manager, q, &rules); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func (self *SSecurityGroupRule) GetOwnerId() mcclient.IIdentityProvider {
|
||||
secgrp, _ := self.GetSecGroup()
|
||||
if secgrp != nil {
|
||||
|
||||
@@ -592,7 +592,7 @@ func (self *SSecurityGroup) getSecurityRuleString() (string, error) {
|
||||
}
|
||||
var rules []string
|
||||
for _, rule := range secgrouprules {
|
||||
rules = append(rules, rule.String())
|
||||
rules = append(rules, rule.Strings()...)
|
||||
}
|
||||
return strings.Join(rules, SECURITY_GROUP_SEPARATOR), nil
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/httputils"
|
||||
randutil "yunion.io/x/pkg/util/rand"
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
"yunion.io/x/pkg/util/secrules"
|
||||
"yunion.io/x/pkg/util/sets"
|
||||
"yunion.io/x/pkg/utils"
|
||||
@@ -1602,7 +1601,7 @@ func (self *SKVMRegionDriver) ValidateUpdateSecurityGroupRuleInput(ctx context.C
|
||||
}
|
||||
}
|
||||
|
||||
if input.CIDR != nil && len(*input.CIDR) > 0 && !regutils.MatchCIDR(*input.CIDR) && !regutils.MatchIP4Addr(*input.CIDR) && !regutils.MatchCIDR6(*input.CIDR) && !regutils.MatchIP6Addr(*input.CIDR) {
|
||||
if input.CIDR != nil && len(*input.CIDR) > 0 && !api.IsValidSecgroupRuleCIDR(*input.CIDR) {
|
||||
return nil, httperrors.NewInputParameterError("invalid cidr %s", *input.CIDR)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed 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 netutils2
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
"yunion.io/x/pkg/util/regutils"
|
||||
)
|
||||
|
||||
func str2ipRange(cidr string) (*netutils.IPV4AddrRange, *netutils.IPV6AddrRange) {
|
||||
if regutils.MatchCIDR(cidr) {
|
||||
v4prefix, err := netutils.NewIPV4Prefix(cidr)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
v4range := v4prefix.ToIPRange()
|
||||
return &v4range, nil
|
||||
} else if regutils.MatchCIDR6(cidr) {
|
||||
v6prefix, err := netutils.NewIPV6Prefix(cidr)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
v6range := v6prefix.ToIPRange()
|
||||
return nil, &v6range
|
||||
} else if regutils.MatchIP4Addr(cidr) {
|
||||
v4addr, err := netutils.NewIPV4Addr(cidr)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
v4range := netutils.NewIPV4AddrRange(v4addr, v4addr)
|
||||
return &v4range, nil
|
||||
} else if regutils.MatchIP6Addr(cidr) {
|
||||
v6addr, err := netutils.NewIPV6Addr(cidr)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
v6range := netutils.NewIPV6AddrRange(v6addr, v6addr)
|
||||
return nil, &v6range
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func str2ipRangeList(cidr string) ([]netutils.IPV4AddrRange, []netutils.IPV6AddrRange) {
|
||||
v4ranges := []netutils.IPV4AddrRange{}
|
||||
v6ranges := []netutils.IPV6AddrRange{}
|
||||
if strings.Contains(cidr, ",") {
|
||||
cidrStrs := strings.Split(cidr, ",")
|
||||
for _, cidrStr := range cidrStrs {
|
||||
cidrStr = strings.TrimSpace(cidrStr)
|
||||
v4range, v6range := str2ipRange(cidrStr)
|
||||
if v4range != nil {
|
||||
v4ranges = append(v4ranges, *v4range)
|
||||
}
|
||||
if v6range != nil {
|
||||
v6ranges = append(v6ranges, *v6range)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
v4range, v6range := str2ipRange(cidr)
|
||||
if v4range != nil {
|
||||
v4ranges = append(v4ranges, *v4range)
|
||||
}
|
||||
if v6range != nil {
|
||||
v6ranges = append(v6ranges, *v6range)
|
||||
}
|
||||
}
|
||||
if len(v4ranges) > 0 {
|
||||
v4ranges = netutils.IPV4AddrRangeList(v4ranges).Merge()
|
||||
}
|
||||
if len(v6ranges) > 0 {
|
||||
v6ranges = netutils.IPV6AddrRangeList(v6ranges).Merge()
|
||||
}
|
||||
return v4ranges, v6ranges
|
||||
}
|
||||
|
||||
func Str2IPNets(cidr string) []*net.IPNet {
|
||||
v4ranges, v6ranges := str2ipRangeList(cidr)
|
||||
ipnets := []*net.IPNet{}
|
||||
for i := range v4ranges {
|
||||
v4nets := v4ranges[i].ToIPNets()
|
||||
ipnets = append(ipnets, v4nets...)
|
||||
}
|
||||
for i := range v6ranges {
|
||||
v6nets := v6ranges[i].ToIPNets()
|
||||
ipnets = append(ipnets, v6nets...)
|
||||
}
|
||||
return ipnets
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// Licensed 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 netutils2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStr2IPNets(t *testing.T) {
|
||||
tests := []struct {
|
||||
cidr string
|
||||
want []*net.IPNet
|
||||
}{
|
||||
{
|
||||
cidr: "192.168.1.0/24",
|
||||
want: []*net.IPNet{
|
||||
{IP: net.IPv4(192, 168, 1, 0), Mask: net.CIDRMask(24, 32)},
|
||||
},
|
||||
},
|
||||
{
|
||||
cidr: "192.168.1.0/24,192.168.2.0/24",
|
||||
want: []*net.IPNet{
|
||||
{IP: net.IPv4(192, 168, 1, 0), Mask: net.CIDRMask(24, 32)},
|
||||
{IP: net.IPv4(192, 168, 2, 0), Mask: net.CIDRMask(24, 32)},
|
||||
},
|
||||
},
|
||||
{
|
||||
cidr: "192.168.1.0/24,192.168.2.0/24,192.168.3.0/24",
|
||||
want: []*net.IPNet{
|
||||
{IP: net.IPv4(192, 168, 1, 0), Mask: net.CIDRMask(24, 32)},
|
||||
{IP: net.IPv4(192, 168, 2, 0), Mask: net.CIDRMask(23, 32)},
|
||||
},
|
||||
},
|
||||
{
|
||||
cidr: "192.168.2.0/24,192.168.2.0/24,192.168.3.0/24",
|
||||
want: []*net.IPNet{
|
||||
{IP: net.IPv4(192, 168, 2, 0), Mask: net.CIDRMask(23, 32)},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
got := Str2IPNets(test.cidr)
|
||||
gotStr := fmt.Sprintf("%v", got)
|
||||
wantStr := fmt.Sprintf("%v", test.want)
|
||||
if gotStr != wantStr {
|
||||
t.Errorf("Str2IPNets(%s) = %s, want %s", test.cidr, gotStr, wantStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user