utils.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package util
  14. import (
  15. "context"
  16. "errors"
  17. "fmt"
  18. "net"
  19. "strconv"
  20. v1 "k8s.io/api/core/v1"
  21. "k8s.io/apimachinery/pkg/types"
  22. utilrand "k8s.io/apimachinery/pkg/util/rand"
  23. "k8s.io/apimachinery/pkg/util/sets"
  24. "k8s.io/client-go/tools/record"
  25. helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
  26. utilnet "k8s.io/utils/net"
  27. "k8s.io/klog"
  28. )
  29. const (
  30. // IPv4ZeroCIDR is the CIDR block for the whole IPv4 address space
  31. IPv4ZeroCIDR = "0.0.0.0/0"
  32. // IPv6ZeroCIDR is the CIDR block for the whole IPv6 address space
  33. IPv6ZeroCIDR = "::/0"
  34. )
  35. var (
  36. // ErrAddressNotAllowed indicates the address is not allowed
  37. ErrAddressNotAllowed = errors.New("address not allowed")
  38. // ErrNoAddresses indicates there are no addresses for the hostname
  39. ErrNoAddresses = errors.New("No addresses for hostname")
  40. )
  41. // isValidEndpoint checks that the given host / port pair are valid endpoint
  42. func isValidEndpoint(host string, port int) bool {
  43. return host != "" && port > 0
  44. }
  45. // BuildPortsToEndpointsMap builds a map of portname -> all ip:ports for that
  46. // portname. Explode Endpoints.Subsets[*] into this structure.
  47. func BuildPortsToEndpointsMap(endpoints *v1.Endpoints) map[string][]string {
  48. portsToEndpoints := map[string][]string{}
  49. for i := range endpoints.Subsets {
  50. ss := &endpoints.Subsets[i]
  51. for i := range ss.Ports {
  52. port := &ss.Ports[i]
  53. for i := range ss.Addresses {
  54. addr := &ss.Addresses[i]
  55. if isValidEndpoint(addr.IP, int(port.Port)) {
  56. portsToEndpoints[port.Name] = append(portsToEndpoints[port.Name], net.JoinHostPort(addr.IP, strconv.Itoa(int(port.Port))))
  57. }
  58. }
  59. }
  60. }
  61. return portsToEndpoints
  62. }
  63. // IsZeroCIDR checks whether the input CIDR string is either
  64. // the IPv4 or IPv6 zero CIDR
  65. func IsZeroCIDR(cidr string) bool {
  66. if cidr == IPv4ZeroCIDR || cidr == IPv6ZeroCIDR {
  67. return true
  68. }
  69. return false
  70. }
  71. // IsProxyableIP checks if a given IP address is permitted to be proxied
  72. func IsProxyableIP(ip string) error {
  73. netIP := net.ParseIP(ip)
  74. if netIP == nil {
  75. return ErrAddressNotAllowed
  76. }
  77. return isProxyableIP(netIP)
  78. }
  79. func isProxyableIP(ip net.IP) error {
  80. if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsInterfaceLocalMulticast() {
  81. return ErrAddressNotAllowed
  82. }
  83. return nil
  84. }
  85. // Resolver is an interface for net.Resolver
  86. type Resolver interface {
  87. LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)
  88. }
  89. // IsProxyableHostname checks if the IP addresses for a given hostname are permitted to be proxied
  90. func IsProxyableHostname(ctx context.Context, resolv Resolver, hostname string) error {
  91. resp, err := resolv.LookupIPAddr(ctx, hostname)
  92. if err != nil {
  93. return err
  94. }
  95. if len(resp) == 0 {
  96. return ErrNoAddresses
  97. }
  98. for _, host := range resp {
  99. if err := isProxyableIP(host.IP); err != nil {
  100. return err
  101. }
  102. }
  103. return nil
  104. }
  105. // GetLocalAddrs returns a list of all network addresses on the local system
  106. func GetLocalAddrs() ([]net.IP, error) {
  107. var localAddrs []net.IP
  108. addrs, err := net.InterfaceAddrs()
  109. if err != nil {
  110. return nil, err
  111. }
  112. for _, addr := range addrs {
  113. ip, _, err := net.ParseCIDR(addr.String())
  114. if err != nil {
  115. return nil, err
  116. }
  117. localAddrs = append(localAddrs, ip)
  118. }
  119. return localAddrs, nil
  120. }
  121. // ShouldSkipService checks if a given service should skip proxying
  122. func ShouldSkipService(svcName types.NamespacedName, service *v1.Service) bool {
  123. // if ClusterIP is "None" or empty, skip proxying
  124. if !helper.IsServiceIPSet(service) {
  125. klog.V(3).Infof("Skipping service %s due to clusterIP = %q", svcName, service.Spec.ClusterIP)
  126. return true
  127. }
  128. // Even if ClusterIP is set, ServiceTypeExternalName services don't get proxied
  129. if service.Spec.Type == v1.ServiceTypeExternalName {
  130. klog.V(3).Infof("Skipping service %s due to Type=ExternalName", svcName)
  131. return true
  132. }
  133. return false
  134. }
  135. // GetNodeAddresses return all matched node IP addresses based on given cidr slice.
  136. // Some callers, e.g. IPVS proxier, need concrete IPs, not ranges, which is why this exists.
  137. // NetworkInterfacer is injected for test purpose.
  138. // We expect the cidrs passed in is already validated.
  139. // Given an empty input `[]`, it will return `0.0.0.0/0` and `::/0` directly.
  140. // If multiple cidrs is given, it will return the minimal IP sets, e.g. given input `[1.2.0.0/16, 0.0.0.0/0]`, it will
  141. // only return `0.0.0.0/0`.
  142. // NOTE: GetNodeAddresses only accepts CIDRs, if you want concrete IPs, e.g. 1.2.3.4, then the input should be 1.2.3.4/32.
  143. func GetNodeAddresses(cidrs []string, nw NetworkInterfacer) (sets.String, error) {
  144. uniqueAddressList := sets.NewString()
  145. if len(cidrs) == 0 {
  146. uniqueAddressList.Insert(IPv4ZeroCIDR)
  147. uniqueAddressList.Insert(IPv6ZeroCIDR)
  148. return uniqueAddressList, nil
  149. }
  150. // First round of iteration to pick out `0.0.0.0/0` or `::/0` for the sake of excluding non-zero IPs.
  151. for _, cidr := range cidrs {
  152. if IsZeroCIDR(cidr) {
  153. uniqueAddressList.Insert(cidr)
  154. }
  155. }
  156. // Second round of iteration to parse IPs based on cidr.
  157. for _, cidr := range cidrs {
  158. if IsZeroCIDR(cidr) {
  159. continue
  160. }
  161. _, ipNet, _ := net.ParseCIDR(cidr)
  162. itfs, err := nw.Interfaces()
  163. if err != nil {
  164. return nil, fmt.Errorf("error listing all interfaces from host, error: %v", err)
  165. }
  166. for _, itf := range itfs {
  167. addrs, err := nw.Addrs(&itf)
  168. if err != nil {
  169. return nil, fmt.Errorf("error getting address from interface %s, error: %v", itf.Name, err)
  170. }
  171. for _, addr := range addrs {
  172. if addr == nil {
  173. continue
  174. }
  175. ip, _, err := net.ParseCIDR(addr.String())
  176. if err != nil {
  177. return nil, fmt.Errorf("error parsing CIDR for interface %s, error: %v", itf.Name, err)
  178. }
  179. if ipNet.Contains(ip) {
  180. if utilnet.IsIPv6(ip) && !uniqueAddressList.Has(IPv6ZeroCIDR) {
  181. uniqueAddressList.Insert(ip.String())
  182. }
  183. if !utilnet.IsIPv6(ip) && !uniqueAddressList.Has(IPv4ZeroCIDR) {
  184. uniqueAddressList.Insert(ip.String())
  185. }
  186. }
  187. }
  188. }
  189. }
  190. return uniqueAddressList, nil
  191. }
  192. // LogAndEmitIncorrectIPVersionEvent logs and emits incorrect IP version event.
  193. func LogAndEmitIncorrectIPVersionEvent(recorder record.EventRecorder, fieldName, fieldValue, svcNamespace, svcName string, svcUID types.UID) {
  194. errMsg := fmt.Sprintf("%s in %s has incorrect IP version", fieldValue, fieldName)
  195. klog.Errorf("%s (service %s/%s).", errMsg, svcNamespace, svcName)
  196. if recorder != nil {
  197. recorder.Eventf(
  198. &v1.ObjectReference{
  199. Kind: "Service",
  200. Name: svcName,
  201. Namespace: svcNamespace,
  202. UID: svcUID,
  203. }, v1.EventTypeWarning, "KubeProxyIncorrectIPVersion", errMsg)
  204. }
  205. }
  206. // FilterIncorrectIPVersion filters out the incorrect IP version case from a slice of IP strings.
  207. func FilterIncorrectIPVersion(ipStrings []string, isIPv6Mode bool) ([]string, []string) {
  208. return filterWithCondition(ipStrings, isIPv6Mode, utilnet.IsIPv6String)
  209. }
  210. // FilterIncorrectCIDRVersion filters out the incorrect IP version case from a slice of CIDR strings.
  211. func FilterIncorrectCIDRVersion(ipStrings []string, isIPv6Mode bool) ([]string, []string) {
  212. return filterWithCondition(ipStrings, isIPv6Mode, utilnet.IsIPv6CIDRString)
  213. }
  214. func filterWithCondition(strs []string, expectedCondition bool, conditionFunc func(string) bool) ([]string, []string) {
  215. var corrects, incorrects []string
  216. for _, str := range strs {
  217. if conditionFunc(str) != expectedCondition {
  218. incorrects = append(incorrects, str)
  219. } else {
  220. corrects = append(corrects, str)
  221. }
  222. }
  223. return corrects, incorrects
  224. }
  225. // AppendPortIfNeeded appends the given port to IP address unless it is already in
  226. // "ipv4:port" or "[ipv6]:port" format.
  227. func AppendPortIfNeeded(addr string, port int32) string {
  228. // Return if address is already in "ipv4:port" or "[ipv6]:port" format.
  229. if _, _, err := net.SplitHostPort(addr); err == nil {
  230. return addr
  231. }
  232. // Simply return for invalid case. This should be caught by validation instead.
  233. ip := net.ParseIP(addr)
  234. if ip == nil {
  235. return addr
  236. }
  237. // Append port to address.
  238. if ip.To4() != nil {
  239. return fmt.Sprintf("%s:%d", addr, port)
  240. }
  241. return fmt.Sprintf("[%s]:%d", addr, port)
  242. }
  243. // ShuffleStrings copies strings from the specified slice into a copy in random
  244. // order. It returns a new slice.
  245. func ShuffleStrings(s []string) []string {
  246. if s == nil {
  247. return nil
  248. }
  249. shuffled := make([]string, len(s))
  250. perm := utilrand.Perm(len(s))
  251. for i, j := range perm {
  252. shuffled[j] = s[i]
  253. }
  254. return shuffled
  255. }