Disable proxy to loopback and linklocal

This commit is contained in:
Micah Hausler
2018-09-22 19:24:49 -07:00
parent c49896f924
commit 9740b6a6e1
6 changed files with 128 additions and 0 deletions

View File

@@ -17,6 +17,8 @@ limitations under the License.
package util
import (
"context"
"errors"
"fmt"
"net"
@@ -35,6 +37,11 @@ const (
IPv6ZeroCIDR = "::/0"
)
var (
ErrAddressNotAllowed = errors.New("address not allowed")
ErrNoAddresses = errors.New("No addresses for hostname")
)
func IsZeroCIDR(cidr string) bool {
if cidr == IPv4ZeroCIDR || cidr == IPv6ZeroCIDR {
return true
@@ -42,6 +49,46 @@ func IsZeroCIDR(cidr string) bool {
return false
}
// IsProxyableIP checks if a given IP address is permitted to be proxied
func IsProxyableIP(ip string) error {
netIP := net.ParseIP(ip)
if netIP == nil {
return ErrAddressNotAllowed
}
return isProxyableIP(netIP)
}
func isProxyableIP(ip net.IP) error {
if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsInterfaceLocalMulticast() {
return ErrAddressNotAllowed
}
return nil
}
// Resolver is an interface for net.Resolver
type Resolver interface {
LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)
}
// IsProxyableHostname checks if the IP addresses for a given hostname are permitted to be proxied
func IsProxyableHostname(ctx context.Context, resolv Resolver, hostname string) error {
resp, err := resolv.LookupIPAddr(ctx, hostname)
if err != nil {
return err
}
if len(resp) == 0 {
return ErrNoAddresses
}
for _, host := range resp {
if err := isProxyableIP(host.IP); err != nil {
return err
}
}
return nil
}
func IsLocalIP(ip string) (bool, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {

View File

@@ -17,6 +17,7 @@ limitations under the License.
package util
import (
"context"
"net"
"testing"
@@ -27,6 +28,74 @@ import (
fake "k8s.io/kubernetes/pkg/proxy/util/testing"
)
func TestIsProxyableIP(t *testing.T) {
testCases := []struct {
ip string
want error
}{
{"127.0.0.1", ErrAddressNotAllowed},
{"127.0.0.2", ErrAddressNotAllowed},
{"169.254.169.254", ErrAddressNotAllowed},
{"169.254.1.1", ErrAddressNotAllowed},
{"224.0.0.0", ErrAddressNotAllowed},
{"10.0.0.1", nil},
{"192.168.0.1", nil},
{"172.16.0.1", nil},
{"8.8.8.8", nil},
{"::1", ErrAddressNotAllowed},
{"fe80::", ErrAddressNotAllowed},
{"ff02::", ErrAddressNotAllowed},
{"ff01::", ErrAddressNotAllowed},
{"2600::", nil},
{"1", ErrAddressNotAllowed},
{"", ErrAddressNotAllowed},
}
for i := range testCases {
got := IsProxyableIP(testCases[i].ip)
if testCases[i].want != got {
t.Errorf("case %d: expected %v, got %v", i, testCases[i].want, got)
}
}
}
type dummyResolver struct {
ips []string
err error
}
func (r *dummyResolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error) {
if r.err != nil {
return nil, r.err
}
resp := []net.IPAddr{}
for _, ipString := range r.ips {
resp = append(resp, net.IPAddr{IP: net.ParseIP(ipString)})
}
return resp, nil
}
func TestIsProxyableHostname(t *testing.T) {
testCases := []struct {
hostname string
ips []string
want error
}{
{"k8s.io", []string{}, ErrNoAddresses},
{"k8s.io", []string{"8.8.8.8"}, nil},
{"k8s.io", []string{"169.254.169.254"}, ErrAddressNotAllowed},
{"k8s.io", []string{"127.0.0.1", "8.8.8.8"}, ErrAddressNotAllowed},
}
for i := range testCases {
resolv := dummyResolver{ips: testCases[i].ips}
got := IsProxyableHostname(context.Background(), &resolv, testCases[i].hostname)
if testCases[i].want != got {
t.Errorf("case %d: expected %v, got %v", i, testCases[i].want, got)
}
}
}
func TestShouldSkipService(t *testing.T) {
testCases := []struct {
service *v1.Service