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 ...@@ -89,6 +89,10 @@ func NewIPSet(handle utilipset.Interface, name string, setType utilipset.Type, i
return set return set
} }
func (set *IPSet) validateEntry(entry *utilipset.Entry) bool {
return entry.Validate(&set.IPSet)
}
func (set *IPSet) isEmpty() bool { func (set *IPSet) isEmpty() bool {
return len(set.activeEntries.UnsortedList()) == 0 return len(set.activeEntries.UnsortedList()) == 0
} }
...@@ -123,7 +127,7 @@ func (set *IPSet) syncIPSetEntries() { ...@@ -123,7 +127,7 @@ func (set *IPSet) syncIPSetEntries() {
} }
// Create active entries // Create active entries
for _, entry := range set.activeEntries.Difference(currentIPSetEntries).List() { 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) glog.Errorf("Failed to add entry: %v to ip set: %s, error: %v", entry, set.Name, err)
} else { } else {
glog.V(3).Infof("Successfully add entry: %v to ip set: %s", entry, set.Name) glog.V(3).Infof("Successfully add entry: %v to ip set: %s", entry, set.Name)
......
...@@ -55,7 +55,7 @@ const testIPSetVersion = "v6.19" ...@@ -55,7 +55,7 @@ const testIPSetVersion = "v6.19"
func TestSyncIPSetEntries(t *testing.T) { func TestSyncIPSetEntries(t *testing.T) {
testCases := []struct { testCases := []struct {
setName string set *utilipset.IPSet
setType utilipset.Type setType utilipset.Type
ipv6 bool ipv6 bool
activeEntries []string activeEntries []string
...@@ -63,7 +63,9 @@ func TestSyncIPSetEntries(t *testing.T) { ...@@ -63,7 +63,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries []string expectedEntries []string
}{ }{
{ // case 0 { // case 0
setName: "foo", set: &utilipset.IPSet{
Name: "foo",
},
setType: utilipset.HashIPPort, setType: utilipset.HashIPPort,
ipv6: false, ipv6: false,
activeEntries: []string{"172.17.0.4,tcp:80"}, activeEntries: []string{"172.17.0.4,tcp:80"},
...@@ -71,7 +73,9 @@ func TestSyncIPSetEntries(t *testing.T) { ...@@ -71,7 +73,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"172.17.0.4,tcp:80"}, expectedEntries: []string{"172.17.0.4,tcp:80"},
}, },
{ // case 1 { // case 1
setName: "abz", set: &utilipset.IPSet{
Name: "abz",
},
setType: utilipset.HashIPPort, setType: utilipset.HashIPPort,
ipv6: true, ipv6: true,
activeEntries: []string{"FE80::0202:B3FF:FE1E:8329,tcp:80"}, activeEntries: []string{"FE80::0202:B3FF:FE1E:8329,tcp:80"},
...@@ -79,7 +83,9 @@ func TestSyncIPSetEntries(t *testing.T) { ...@@ -79,7 +83,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"FE80::0202:B3FF:FE1E:8329,tcp:80"}, expectedEntries: []string{"FE80::0202:B3FF:FE1E:8329,tcp:80"},
}, },
{ // case 2 { // case 2
setName: "bca", set: &utilipset.IPSet{
Name: "bca",
},
setType: utilipset.HashIPPort, setType: utilipset.HashIPPort,
ipv6: false, ipv6: false,
activeEntries: []string{"172.17.0.4,tcp:80", "172.17.0.5,tcp:80"}, activeEntries: []string{"172.17.0.4,tcp:80", "172.17.0.5,tcp:80"},
...@@ -87,7 +93,9 @@ func TestSyncIPSetEntries(t *testing.T) { ...@@ -87,7 +93,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"172.17.0.4,tcp:80", "172.17.0.5,tcp:80"}, expectedEntries: []string{"172.17.0.4,tcp:80", "172.17.0.5,tcp:80"},
}, },
{ // case 3 { // case 3
setName: "bar", set: &utilipset.IPSet{
Name: "bar",
},
setType: utilipset.HashIPPortIP, setType: utilipset.HashIPPortIP,
ipv6: false, ipv6: false,
activeEntries: []string{"172.17.0.4,tcp:80:172.17.0.4"}, activeEntries: []string{"172.17.0.4,tcp:80:172.17.0.4"},
...@@ -95,7 +103,9 @@ func TestSyncIPSetEntries(t *testing.T) { ...@@ -95,7 +103,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"172.17.0.4,tcp:80:172.17.0.4"}, expectedEntries: []string{"172.17.0.4,tcp:80:172.17.0.4"},
}, },
{ // case 4 { // case 4
setName: "baz", set: &utilipset.IPSet{
Name: "baz",
},
setType: utilipset.HashIPPortIP, setType: utilipset.HashIPPortIP,
ipv6: true, ipv6: true,
activeEntries: []string{"FE80:0000:0000:0000:0202:B3FF:FE1E:8329,tcp:8080:FE80:0000:0000:0000:0202:B3FF:FE1E:8329"}, 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) { ...@@ -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"}, expectedEntries: []string{"FE80:0000:0000:0000:0202:B3FF:FE1E:8329,tcp:8080:FE80:0000:0000:0000:0202:B3FF:FE1E:8329"},
}, },
{ // case 5 { // case 5
setName: "NOPE", set: &utilipset.IPSet{
Name: "NOPE",
},
setType: utilipset.HashIPPortIP, setType: utilipset.HashIPPortIP,
ipv6: false, ipv6: false,
activeEntries: []string{"172.17.0.4,tcp:80,172.17.0.9", "172.17.0.5,tcp:80,172.17.0.10"}, 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) { ...@@ -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"}, expectedEntries: []string{"172.17.0.4,tcp:80,172.17.0.9", "172.17.0.5,tcp:80,172.17.0.10"},
}, },
{ // case 6 { // case 6
setName: "ABC-DEF", set: &utilipset.IPSet{
Name: "ABC-DEF",
},
setType: utilipset.HashIPPortNet, setType: utilipset.HashIPPortNet,
ipv6: false, 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"}, 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) { ...@@ -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"}, 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 { // case 7
setName: "zar", set: &utilipset.IPSet{
Name: "zar",
},
setType: utilipset.HashIPPortNet, setType: utilipset.HashIPPortNet,
ipv6: true, ipv6: true,
activeEntries: []string{"FE80::8329,tcp:8800,2001:db8::/32"}, activeEntries: []string{"FE80::8329,tcp:8800,2001:db8::/32"},
...@@ -127,7 +143,9 @@ func TestSyncIPSetEntries(t *testing.T) { ...@@ -127,7 +143,9 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: []string{"FE80::8329,tcp:8800,2001:db8::/32"}, expectedEntries: []string{"FE80::8329,tcp:8800,2001:db8::/32"},
}, },
{ // case 8 { // case 8
setName: "bbb", set: &utilipset.IPSet{
Name: "bbb",
},
setType: utilipset.HashIPPortNet, setType: utilipset.HashIPPortNet,
ipv6: true, ipv6: true,
activeEntries: nil, activeEntries: nil,
...@@ -135,21 +153,27 @@ func TestSyncIPSetEntries(t *testing.T) { ...@@ -135,21 +153,27 @@ func TestSyncIPSetEntries(t *testing.T) {
expectedEntries: nil, expectedEntries: nil,
}, },
{ // case 9 { // case 9
setName: "AAA", set: &utilipset.IPSet{
Name: "AAA",
},
setType: utilipset.BitmapPort, setType: utilipset.BitmapPort,
activeEntries: nil, activeEntries: nil,
currentEntries: []string{"80"}, currentEntries: []string{"80"},
expectedEntries: nil, expectedEntries: nil,
}, },
{ // case 10 { // case 10
setName: "c-c-c", set: &utilipset.IPSet{
Name: "c-c-c",
},
setType: utilipset.BitmapPort, setType: utilipset.BitmapPort,
activeEntries: []string{"8080", "9090"}, activeEntries: []string{"8080", "9090"},
currentEntries: []string{"80"}, currentEntries: []string{"80"},
expectedEntries: []string{"8080", "9090"}, expectedEntries: []string{"8080", "9090"},
}, },
{ // case 11 { // case 11
setName: "NODE-PORT", set: &utilipset.IPSet{
Name: "NODE-PORT",
},
setType: utilipset.BitmapPort, setType: utilipset.BitmapPort,
activeEntries: []string{"8080"}, activeEntries: []string{"8080"},
currentEntries: []string{"80", "9090", "8081", "8082"}, currentEntries: []string{"80", "9090", "8081", "8082"},
...@@ -158,19 +182,19 @@ func TestSyncIPSetEntries(t *testing.T) { ...@@ -158,19 +182,19 @@ func TestSyncIPSetEntries(t *testing.T) {
} }
for i := range testCases { 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 { if err := set.handle.CreateSet(&set.IPSet, true); err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
for _, entry := range testCases[i].expectedEntries { 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.activeEntries.Insert(testCases[i].activeEntries...)
set.syncIPSetEntries() set.syncIPSetEntries()
for _, entry := range testCases[i].expectedEntries { 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 { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
......
...@@ -957,6 +957,9 @@ func (proxier *Proxier) OnEndpointsSynced() { ...@@ -957,6 +957,9 @@ func (proxier *Proxier) OnEndpointsSynced() {
proxier.syncProxyRules() 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. // This is where all of the ipvs calls happen.
// assumes proxier.mu is held // assumes proxier.mu is held
func (proxier *Proxier) syncProxyRules() { func (proxier *Proxier) syncProxyRules() {
...@@ -1111,6 +1114,10 @@ func (proxier *Proxier) syncProxyRules() { ...@@ -1111,6 +1114,10 @@ func (proxier *Proxier) syncProxyRules() {
IP2: epIP, IP2: epIP,
SetType: utilipset.HashIPPortIP, 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()) proxier.loopbackSet.activeEntries.Insert(entry.String())
} }
...@@ -1125,9 +1132,11 @@ func (proxier *Proxier) syncProxyRules() { ...@@ -1125,9 +1132,11 @@ func (proxier *Proxier) syncProxyRules() {
// add service Cluster IP:Port to kubeServiceAccess ip set for the purpose of solving hairpin. // add service Cluster IP:Port to kubeServiceAccess ip set for the purpose of solving hairpin.
// proxier.kubeServiceAccessSet.activeEntries.Insert(entry.String()) // proxier.kubeServiceAccessSet.activeEntries.Insert(entry.String())
// Install masquerade rules if 'masqueradeAll' or 'clusterCIDR' is specified. // Install masquerade rules if 'masqueradeAll' or 'clusterCIDR' is specified.
if proxier.masqueradeAll { if proxier.masqueradeAll || len(proxier.clusterCIDR) > 0 {
proxier.clusterIPSet.activeEntries.Insert(entry.String()) if valid := proxier.clusterIPSet.validateEntry(entry); !valid {
} else if len(proxier.clusterCIDR) > 0 { glog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.clusterIPSet.Name))
continue
}
proxier.clusterIPSet.activeEntries.Insert(entry.String()) proxier.clusterIPSet.activeEntries.Insert(entry.String())
} }
// ipvs call // ipvs call
...@@ -1195,6 +1204,10 @@ func (proxier *Proxier) syncProxyRules() { ...@@ -1195,6 +1204,10 @@ func (proxier *Proxier) syncProxyRules() {
SetType: utilipset.HashIPPort, SetType: utilipset.HashIPPort,
} }
// We have to SNAT packets to external IPs. // 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()) proxier.externalIPSet.activeEntries.Insert(entry.String())
// ipvs call // ipvs call
...@@ -1234,12 +1247,20 @@ func (proxier *Proxier) syncProxyRules() { ...@@ -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 globally, we need to masquerade in case we cross nodes.
// If we are proxying only locally, we can retain the source IP. // If we are proxying only locally, we can retain the source IP.
if !svcInfo.onlyNodeLocalEndpoints { 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()) proxier.lbMasqSet.activeEntries.Insert(entry.String())
} }
if len(svcInfo.loadBalancerSourceRanges) != 0 { if len(svcInfo.loadBalancerSourceRanges) != 0 {
// The service firewall rules are created based on ServiceSpec.loadBalancerSourceRanges field. // The service firewall rules are created based on ServiceSpec.loadBalancerSourceRanges field.
// This currently works for loadbalancers that preserves source ips. // This currently works for loadbalancers that preserves source ips.
// For loadbalancers which direct traffic to service NodePort, the firewall rules will not apply. // 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()) proxier.lbIngressSet.activeEntries.Insert(entry.String())
allowFromNode := false allowFromNode := false
...@@ -1253,6 +1274,10 @@ func (proxier *Proxier) syncProxyRules() { ...@@ -1253,6 +1274,10 @@ func (proxier *Proxier) syncProxyRules() {
SetType: utilipset.HashIPPortNet, SetType: utilipset.HashIPPortNet,
} }
// enumerate all white list source cidr // 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()) proxier.lbWhiteListCIDRSet.activeEntries.Insert(entry.String())
// ignore error because it has been validated // ignore error because it has been validated
...@@ -1273,6 +1298,10 @@ func (proxier *Proxier) syncProxyRules() { ...@@ -1273,6 +1298,10 @@ func (proxier *Proxier) syncProxyRules() {
SetType: utilipset.HashIPPortIP, SetType: utilipset.HashIPPortIP,
} }
// enumerate all white list source ip // 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()) proxier.lbWhiteListIPSet.activeEntries.Insert(entry.String())
} }
} }
...@@ -1332,15 +1361,23 @@ func (proxier *Proxier) syncProxyRules() { ...@@ -1332,15 +1361,23 @@ func (proxier *Proxier) syncProxyRules() {
Protocol: protocol, Protocol: protocol,
SetType: utilipset.BitmapPort, SetType: utilipset.BitmapPort,
} }
var nodePortSet *IPSet
switch protocol { switch protocol {
case "tcp": case "tcp":
proxier.nodePortSetTCP.activeEntries.Insert(entry.String()) nodePortSet = proxier.nodePortSetTCP
case "udp": case "udp":
proxier.nodePortSetUDP.activeEntries.Insert(entry.String()) nodePortSet = proxier.nodePortSetUDP
default: default:
// It should never hit // It should never hit
glog.Errorf("Unsupported protocol type: %s", protocol) 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 // Build ipvs kernel routes for each node ip address
......
...@@ -8,7 +8,10 @@ go_library( ...@@ -8,7 +8,10 @@ go_library(
], ],
importpath = "k8s.io/kubernetes/pkg/util/ipset", importpath = "k8s.io/kubernetes/pkg/util/ipset",
visibility = ["//visibility:public"], 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( go_test(
......
...@@ -93,15 +93,15 @@ func (f *FakeIPSet) CreateSet(set *ipset.IPSet, ignoreExistErr bool) error { ...@@ -93,15 +93,15 @@ func (f *FakeIPSet) CreateSet(set *ipset.IPSet, ignoreExistErr bool) error {
} }
// AddEntry is part of interface. // AddEntry is part of interface.
func (f *FakeIPSet) AddEntry(entry string, set string, ignoreExistErr bool) error { func (f *FakeIPSet) AddEntry(entry string, set *ipset.IPSet, ignoreExistErr bool) error {
if f.Entries[set].Has(entry) { if f.Entries[set.Name].Has(entry) {
if !ignoreExistErr { if !ignoreExistErr {
// already exists // already exists
return fmt.Errorf("Element cannot be added to the set: it's already added") return fmt.Errorf("Element cannot be added to the set: it's already added")
} }
return nil return nil
} }
f.Entries[set].Insert(entry) f.Entries[set.Name].Insert(entry)
return nil return nil
} }
......
...@@ -45,8 +45,8 @@ func TestSetEntry(t *testing.T) { ...@@ -45,8 +45,8 @@ func TestSetEntry(t *testing.T) {
} }
// add two entries // add two entries
fake.AddEntry("192.168.1.1,tcp:8080", set.Name, true) fake.AddEntry("192.168.1.1,tcp:8080", set, true)
fake.AddEntry("192.168.1.2,tcp:8081", set.Name, true) fake.AddEntry("192.168.1.2,tcp:8081", set, true)
entries, err := fake.ListEntries(set.Name) entries, err := fake.ListEntries(set.Name)
if err != nil { if err != nil {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
......
...@@ -58,13 +58,3 @@ var ValidIPSetTypes = []Type{ ...@@ -58,13 +58,3 @@ var ValidIPSetTypes = []Type{
BitmapPort, BitmapPort,
HashIPPortNet, 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