Unverified Commit ebffd76a authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #57268 from m1093782566/validate-ipset

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. validate ipset set and entry - ipvs proxier validate entry before adding it and validate set before creating it **What this PR does / why we need it**: validate ipset util. **Which issue(s) this PR fixes**: Fixes #57269 **Special notes for your reviewer**: I splitted this PR into some small pieces for the sake of code review. **Release note**: ```release-note NONE ```
parents 8201e4ba 10a899f3
......@@ -89,6 +89,10 @@ func NewIPSet(handle utilipset.Interface, name string, setType utilipset.Type, i
return set
}
func (set *IPSet) validateEntry(entry *utilipset.Entry) bool {
return entry.Validate(&set.IPSet)
}
func (set *IPSet) isEmpty() bool {
return len(set.activeEntries.UnsortedList()) == 0
}
......@@ -123,7 +127,7 @@ func (set *IPSet) syncIPSetEntries() {
}
// Create active entries
for _, entry := range set.activeEntries.Difference(currentIPSetEntries).List() {
if err := set.handle.AddEntry(entry, set.Name, true); err != nil {
if err := set.handle.AddEntry(entry, &set.IPSet, true); err != nil {
glog.Errorf("Failed to add entry: %v to ip set: %s, error: %v", entry, set.Name, err)
} else {
glog.V(3).Infof("Successfully add entry: %v to ip set: %s", entry, set.Name)
......
......@@ -55,7 +55,7 @@ const testIPSetVersion = "v6.19"
func TestSyncIPSetEntries(t *testing.T) {
testCases := []struct {
setName string
set *utilipset.IPSet
setType utilipset.Type
ipv6 bool
activeEntries []string
......@@ -63,7 +63,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries []string
}{
{ // case 0
setName: "foo",
set: &utilipset.IPSet{
Name: "foo",
},
setType: utilipset.HashIPPort,
ipv6: false,
activeEntries: []string{"172.17.0.4,tcp:80"},
......@@ -71,7 +73,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"172.17.0.4,tcp:80"},
},
{ // case 1
setName: "abz",
set: &utilipset.IPSet{
Name: "abz",
},
setType: utilipset.HashIPPort,
ipv6: true,
activeEntries: []string{"FE80::0202:B3FF:FE1E:8329,tcp:80"},
......@@ -79,7 +83,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"FE80::0202:B3FF:FE1E:8329,tcp:80"},
},
{ // case 2
setName: "bca",
set: &utilipset.IPSet{
Name: "bca",
},
setType: utilipset.HashIPPort,
ipv6: false,
activeEntries: []string{"172.17.0.4,tcp:80", "172.17.0.5,tcp:80"},
......@@ -87,7 +93,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"172.17.0.4,tcp:80", "172.17.0.5,tcp:80"},
},
{ // case 3
setName: "bar",
set: &utilipset.IPSet{
Name: "bar",
},
setType: utilipset.HashIPPortIP,
ipv6: false,
activeEntries: []string{"172.17.0.4,tcp:80:172.17.0.4"},
......@@ -95,7 +103,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"172.17.0.4,tcp:80:172.17.0.4"},
},
{ // case 4
setName: "baz",
set: &utilipset.IPSet{
Name: "baz",
},
setType: utilipset.HashIPPortIP,
ipv6: true,
activeEntries: []string{"FE80:0000:0000:0000:0202:B3FF:FE1E:8329,tcp:8080:FE80:0000:0000:0000:0202:B3FF:FE1E:8329"},
......@@ -103,7 +113,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"FE80:0000:0000:0000:0202:B3FF:FE1E:8329,tcp:8080:FE80:0000:0000:0000:0202:B3FF:FE1E:8329"},
},
{ // case 5
setName: "NOPE",
set: &utilipset.IPSet{
Name: "NOPE",
},
setType: utilipset.HashIPPortIP,
ipv6: false,
activeEntries: []string{"172.17.0.4,tcp:80,172.17.0.9", "172.17.0.5,tcp:80,172.17.0.10"},
......@@ -111,7 +123,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"172.17.0.4,tcp:80,172.17.0.9", "172.17.0.5,tcp:80,172.17.0.10"},
},
{ // case 6
setName: "ABC-DEF",
set: &utilipset.IPSet{
Name: "ABC-DEF",
},
setType: utilipset.HashIPPortNet,
ipv6: false,
activeEntries: []string{"172.17.0.4,tcp:80,172.17.0.0/16", "172.17.0.5,tcp:80,172.17.0.0/16"},
......@@ -119,7 +133,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"172.17.0.4,tcp:80,172.17.0.0/16", "172.17.0.5,tcp:80,172.17.0.0/16"},
},
{ // case 7
setName: "zar",
set: &utilipset.IPSet{
Name: "zar",
},
setType: utilipset.HashIPPortNet,
ipv6: true,
activeEntries: []string{"FE80::8329,tcp:8800,2001:db8::/32"},
......@@ -127,7 +143,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"FE80::8329,tcp:8800,2001:db8::/32"},
},
{ // case 8
setName: "bbb",
set: &utilipset.IPSet{
Name: "bbb",
},
setType: utilipset.HashIPPortNet,
ipv6: true,
activeEntries: nil,
......@@ -135,21 +153,27 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: nil,
},
{ // case 9
setName: "AAA",
set: &utilipset.IPSet{
Name: "AAA",
},
setType: utilipset.BitmapPort,
activeEntries: nil,
currentEntries: []string{"80"},
expectedEntries: nil,
},
{ // case 10
setName: "c-c-c",
set: &utilipset.IPSet{
Name: "c-c-c",
},
setType: utilipset.BitmapPort,
activeEntries: []string{"8080", "9090"},
currentEntries: []string{"80"},
expectedEntries: []string{"8080", "9090"},
},
{ // case 11
setName: "NODE-PORT",
set: &utilipset.IPSet{
Name: "NODE-PORT",
},
setType: utilipset.BitmapPort,
activeEntries: []string{"8080"},
currentEntries: []string{"80", "9090", "8081", "8082"},
......@@ -158,19 +182,19 @@ func TestSyncIPSetEntries(t *testing.T) {
}
for i := range testCases {
set := NewIPSet(fakeipset.NewFake(testIPSetVersion), testCases[i].setName, testCases[i].setType, testCases[i].ipv6)
set := NewIPSet(fakeipset.NewFake(testIPSetVersion), testCases[i].set.Name, testCases[i].setType, testCases[i].ipv6)
if err := set.handle.CreateSet(&set.IPSet, true); err != nil {
t.Errorf("Unexpected error: %v", err)
}
for _, entry := range testCases[i].expectedEntries {
set.handle.AddEntry(entry, testCases[i].setName, true)
set.handle.AddEntry(entry, testCases[i].set, true)
}
set.activeEntries.Insert(testCases[i].activeEntries...)
set.syncIPSetEntries()
for _, entry := range testCases[i].expectedEntries {
found, err := set.handle.TestEntry(entry, testCases[i].setName)
found, err := set.handle.TestEntry(entry, testCases[i].set.Name)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
......
......@@ -957,6 +957,9 @@ func (proxier *Proxier) OnEndpointsSynced() {
proxier.syncProxyRules()
}
// EntryInvalidErr indicates if an ipset entry is invalid or not
const EntryInvalidErr = "error adding entry %s to ipset %s"
// This is where all of the ipvs calls happen.
// assumes proxier.mu is held
func (proxier *Proxier) syncProxyRules() {
......@@ -1111,6 +1114,10 @@ func (proxier *Proxier) syncProxyRules() {
IP2: epIP,
SetType: utilipset.HashIPPortIP,
}
if valid := proxier.loopbackSet.validateEntry(entry); !valid {
glog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.loopbackSet.Name))
continue
}
proxier.loopbackSet.activeEntries.Insert(entry.String())
}
......@@ -1125,9 +1132,11 @@ func (proxier *Proxier) syncProxyRules() {
// add service Cluster IP:Port to kubeServiceAccess ip set for the purpose of solving hairpin.
// proxier.kubeServiceAccessSet.activeEntries.Insert(entry.String())
// Install masquerade rules if 'masqueradeAll' or 'clusterCIDR' is specified.
if proxier.masqueradeAll {
proxier.clusterIPSet.activeEntries.Insert(entry.String())
} else if len(proxier.clusterCIDR) > 0 {
if proxier.masqueradeAll || len(proxier.clusterCIDR) > 0 {
if valid := proxier.clusterIPSet.validateEntry(entry); !valid {
glog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.clusterIPSet.Name))
continue
}
proxier.clusterIPSet.activeEntries.Insert(entry.String())
}
// ipvs call
......@@ -1195,6 +1204,10 @@ func (proxier *Proxier) syncProxyRules() {
SetType: utilipset.HashIPPort,
}
// We have to SNAT packets to external IPs.
if valid := proxier.externalIPSet.validateEntry(entry); !valid {
glog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.externalIPSet.Name))
continue
}
proxier.externalIPSet.activeEntries.Insert(entry.String())
// ipvs call
......@@ -1234,12 +1247,20 @@ func (proxier *Proxier) syncProxyRules() {
// If we are proxying globally, we need to masquerade in case we cross nodes.
// If we are proxying only locally, we can retain the source IP.
if !svcInfo.onlyNodeLocalEndpoints {
if valid := proxier.lbMasqSet.validateEntry(entry); !valid {
glog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.lbMasqSet.Name))
continue
}
proxier.lbMasqSet.activeEntries.Insert(entry.String())
}
if len(svcInfo.loadBalancerSourceRanges) != 0 {
// The service firewall rules are created based on ServiceSpec.loadBalancerSourceRanges field.
// This currently works for loadbalancers that preserves source ips.
// For loadbalancers which direct traffic to service NodePort, the firewall rules will not apply.
if valid := proxier.lbIngressSet.validateEntry(entry); !valid {
glog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.lbIngressSet.Name))
continue
}
proxier.lbIngressSet.activeEntries.Insert(entry.String())
allowFromNode := false
......@@ -1253,6 +1274,10 @@ func (proxier *Proxier) syncProxyRules() {
SetType: utilipset.HashIPPortNet,
}
// enumerate all white list source cidr
if valid := proxier.lbWhiteListCIDRSet.validateEntry(entry); !valid {
glog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.lbWhiteListCIDRSet.Name))
continue
}
proxier.lbWhiteListCIDRSet.activeEntries.Insert(entry.String())
// ignore error because it has been validated
......@@ -1273,6 +1298,10 @@ func (proxier *Proxier) syncProxyRules() {
SetType: utilipset.HashIPPortIP,
}
// enumerate all white list source ip
if valid := proxier.lbWhiteListIPSet.validateEntry(entry); !valid {
glog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.lbWhiteListIPSet.Name))
continue
}
proxier.lbWhiteListIPSet.activeEntries.Insert(entry.String())
}
}
......@@ -1332,15 +1361,23 @@ func (proxier *Proxier) syncProxyRules() {
Protocol: protocol,
SetType: utilipset.BitmapPort,
}
var nodePortSet *IPSet
switch protocol {
case "tcp":
proxier.nodePortSetTCP.activeEntries.Insert(entry.String())
nodePortSet = proxier.nodePortSetTCP
case "udp":
proxier.nodePortSetUDP.activeEntries.Insert(entry.String())
nodePortSet = proxier.nodePortSetUDP
default:
// It should never hit
glog.Errorf("Unsupported protocol type: %s", protocol)
}
if nodePortSet != nil {
if valid := nodePortSet.validateEntry(entry); !valid {
glog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, nodePortSet.Name))
continue
}
nodePortSet.activeEntries.Insert(entry.String())
}
}
// Build ipvs kernel routes for each node ip address
......
......@@ -8,7 +8,10 @@ go_library(
],
importpath = "k8s.io/kubernetes/pkg/util/ipset",
visibility = ["//visibility:public"],
deps = ["//vendor/k8s.io/utils/exec:go_default_library"],
deps = [
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",
],
)
go_test(
......
......@@ -93,15 +93,15 @@ func (f *FakeIPSet) CreateSet(set *ipset.IPSet, ignoreExistErr bool) error {
}
// AddEntry is part of interface.
func (f *FakeIPSet) AddEntry(entry string, set string, ignoreExistErr bool) error {
if f.Entries[set].Has(entry) {
func (f *FakeIPSet) AddEntry(entry string, set *ipset.IPSet, ignoreExistErr bool) error {
if f.Entries[set.Name].Has(entry) {
if !ignoreExistErr {
// already exists
return fmt.Errorf("Element cannot be added to the set: it's already added")
}
return nil
}
f.Entries[set].Insert(entry)
f.Entries[set.Name].Insert(entry)
return nil
}
......
......@@ -45,8 +45,8 @@ func TestSetEntry(t *testing.T) {
}
// add two entries
fake.AddEntry("192.168.1.1,tcp:8080", set.Name, true)
fake.AddEntry("192.168.1.2,tcp:8081", set.Name, true)
fake.AddEntry("192.168.1.1,tcp:8080", set, true)
fake.AddEntry("192.168.1.2,tcp:8081", set, true)
entries, err := fake.ListEntries(set.Name)
if err != nil {
t.Errorf("Unexpected error: %v", err)
......
......@@ -58,13 +58,3 @@ var ValidIPSetTypes = []Type{
BitmapPort,
HashIPPortNet,
}
// IsValidIPSetType checks if the given ipset type is valid.
func IsValidIPSetType(set Type) bool {
for _, valid := range ValidIPSetTypes {
if set == valid {
return true
}
}
return false
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment