interface.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*
  2. Copyright 2016 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 net
  14. import (
  15. "bufio"
  16. "encoding/hex"
  17. "fmt"
  18. "io"
  19. "net"
  20. "os"
  21. "strings"
  22. "k8s.io/klog/v2"
  23. netutils "k8s.io/utils/net"
  24. )
  25. type AddressFamily uint
  26. const (
  27. familyIPv4 AddressFamily = 4
  28. familyIPv6 AddressFamily = 6
  29. )
  30. type AddressFamilyPreference []AddressFamily
  31. var (
  32. preferIPv4 = AddressFamilyPreference{familyIPv4, familyIPv6}
  33. preferIPv6 = AddressFamilyPreference{familyIPv6, familyIPv4}
  34. )
  35. const (
  36. // LoopbackInterfaceName is the default name of the loopback interface
  37. LoopbackInterfaceName = "lo"
  38. )
  39. const (
  40. ipv4RouteFile = "/proc/net/route"
  41. ipv6RouteFile = "/proc/net/ipv6_route"
  42. )
  43. type Route struct {
  44. Interface string
  45. Destination net.IP
  46. Gateway net.IP
  47. Family AddressFamily
  48. }
  49. type RouteFile struct {
  50. name string
  51. parse func(input io.Reader) ([]Route, error)
  52. }
  53. // noRoutesError can be returned in case of no routes
  54. type noRoutesError struct {
  55. message string
  56. }
  57. func (e noRoutesError) Error() string {
  58. return e.message
  59. }
  60. // IsNoRoutesError checks if an error is of type noRoutesError
  61. func IsNoRoutesError(err error) bool {
  62. if err == nil {
  63. return false
  64. }
  65. switch err.(type) {
  66. case noRoutesError:
  67. return true
  68. default:
  69. return false
  70. }
  71. }
  72. var (
  73. v4File = RouteFile{name: ipv4RouteFile, parse: getIPv4DefaultRoutes}
  74. v6File = RouteFile{name: ipv6RouteFile, parse: getIPv6DefaultRoutes}
  75. )
  76. func (rf RouteFile) extract() ([]Route, error) {
  77. file, err := os.Open(rf.name)
  78. if err != nil {
  79. return nil, err
  80. }
  81. defer file.Close()
  82. return rf.parse(file)
  83. }
  84. // getIPv4DefaultRoutes obtains the IPv4 routes, and filters out non-default routes.
  85. func getIPv4DefaultRoutes(input io.Reader) ([]Route, error) {
  86. routes := []Route{}
  87. scanner := bufio.NewReader(input)
  88. for {
  89. line, err := scanner.ReadString('\n')
  90. if err == io.EOF {
  91. break
  92. }
  93. //ignore the headers in the route info
  94. if strings.HasPrefix(line, "Iface") {
  95. continue
  96. }
  97. fields := strings.Fields(line)
  98. // Interested in fields:
  99. // 0 - interface name
  100. // 1 - destination address
  101. // 2 - gateway
  102. dest, err := parseIP(fields[1], familyIPv4)
  103. if err != nil {
  104. return nil, err
  105. }
  106. gw, err := parseIP(fields[2], familyIPv4)
  107. if err != nil {
  108. return nil, err
  109. }
  110. if !dest.Equal(net.IPv4zero) {
  111. continue
  112. }
  113. routes = append(routes, Route{
  114. Interface: fields[0],
  115. Destination: dest,
  116. Gateway: gw,
  117. Family: familyIPv4,
  118. })
  119. }
  120. return routes, nil
  121. }
  122. func getIPv6DefaultRoutes(input io.Reader) ([]Route, error) {
  123. routes := []Route{}
  124. scanner := bufio.NewReader(input)
  125. for {
  126. line, err := scanner.ReadString('\n')
  127. if err == io.EOF {
  128. break
  129. }
  130. fields := strings.Fields(line)
  131. // Interested in fields:
  132. // 0 - destination address
  133. // 4 - gateway
  134. // 9 - interface name
  135. dest, err := parseIP(fields[0], familyIPv6)
  136. if err != nil {
  137. return nil, err
  138. }
  139. gw, err := parseIP(fields[4], familyIPv6)
  140. if err != nil {
  141. return nil, err
  142. }
  143. if !dest.Equal(net.IPv6zero) {
  144. continue
  145. }
  146. if gw.Equal(net.IPv6zero) {
  147. continue // loopback
  148. }
  149. routes = append(routes, Route{
  150. Interface: fields[9],
  151. Destination: dest,
  152. Gateway: gw,
  153. Family: familyIPv6,
  154. })
  155. }
  156. return routes, nil
  157. }
  158. // parseIP takes the hex IP address string from route file and converts it
  159. // to a net.IP address. For IPv4, the value must be converted to big endian.
  160. func parseIP(str string, family AddressFamily) (net.IP, error) {
  161. if str == "" {
  162. return nil, fmt.Errorf("input is nil")
  163. }
  164. bytes, err := hex.DecodeString(str)
  165. if err != nil {
  166. return nil, err
  167. }
  168. if family == familyIPv4 {
  169. if len(bytes) != net.IPv4len {
  170. return nil, fmt.Errorf("invalid IPv4 address in route")
  171. }
  172. return net.IP([]byte{bytes[3], bytes[2], bytes[1], bytes[0]}), nil
  173. }
  174. // Must be IPv6
  175. if len(bytes) != net.IPv6len {
  176. return nil, fmt.Errorf("invalid IPv6 address in route")
  177. }
  178. return net.IP(bytes), nil
  179. }
  180. func isInterfaceUp(intf *net.Interface) bool {
  181. if intf == nil {
  182. return false
  183. }
  184. if intf.Flags&net.FlagUp != 0 {
  185. klog.V(4).Infof("Interface %v is up", intf.Name)
  186. return true
  187. }
  188. return false
  189. }
  190. func isLoopbackOrPointToPoint(intf *net.Interface) bool {
  191. return intf.Flags&(net.FlagLoopback|net.FlagPointToPoint) != 0
  192. }
  193. // getMatchingGlobalIP returns the first valid global unicast address of the given
  194. // 'family' from the list of 'addrs'.
  195. func getMatchingGlobalIP(addrs []net.Addr, family AddressFamily) (net.IP, error) {
  196. if len(addrs) > 0 {
  197. for i := range addrs {
  198. klog.V(4).Infof("Checking addr %s.", addrs[i].String())
  199. ip, _, err := netutils.ParseCIDRSloppy(addrs[i].String())
  200. if err != nil {
  201. return nil, err
  202. }
  203. if memberOf(ip, family) {
  204. if ip.IsGlobalUnicast() {
  205. klog.V(4).Infof("IP found %v", ip)
  206. return ip, nil
  207. } else {
  208. klog.V(4).Infof("Non-global unicast address found %v", ip)
  209. }
  210. } else {
  211. klog.V(4).Infof("%v is not an IPv%d address", ip, int(family))
  212. }
  213. }
  214. }
  215. return nil, nil
  216. }
  217. // getIPFromInterface gets the IPs on an interface and returns a global unicast address, if any. The
  218. // interface must be up, the IP must in the family requested, and the IP must be a global unicast address.
  219. func getIPFromInterface(intfName string, forFamily AddressFamily, nw networkInterfacer) (net.IP, error) {
  220. intf, err := nw.InterfaceByName(intfName)
  221. if err != nil {
  222. return nil, err
  223. }
  224. if isInterfaceUp(intf) {
  225. addrs, err := nw.Addrs(intf)
  226. if err != nil {
  227. return nil, err
  228. }
  229. klog.V(4).Infof("Interface %q has %d addresses :%v.", intfName, len(addrs), addrs)
  230. matchingIP, err := getMatchingGlobalIP(addrs, forFamily)
  231. if err != nil {
  232. return nil, err
  233. }
  234. if matchingIP != nil {
  235. klog.V(4).Infof("Found valid IPv%d address %v for interface %q.", int(forFamily), matchingIP, intfName)
  236. return matchingIP, nil
  237. }
  238. }
  239. return nil, nil
  240. }
  241. // getIPFromLoopbackInterface gets the IPs on a loopback interface and returns a global unicast address, if any.
  242. // The loopback interface must be up, the IP must in the family requested, and the IP must be a global unicast address.
  243. func getIPFromLoopbackInterface(forFamily AddressFamily, nw networkInterfacer) (net.IP, error) {
  244. intfs, err := nw.Interfaces()
  245. if err != nil {
  246. return nil, err
  247. }
  248. for _, intf := range intfs {
  249. if !isInterfaceUp(&intf) {
  250. continue
  251. }
  252. if intf.Flags&(net.FlagLoopback) != 0 {
  253. addrs, err := nw.Addrs(&intf)
  254. if err != nil {
  255. return nil, err
  256. }
  257. klog.V(4).Infof("Interface %q has %d addresses :%v.", intf.Name, len(addrs), addrs)
  258. matchingIP, err := getMatchingGlobalIP(addrs, forFamily)
  259. if err != nil {
  260. return nil, err
  261. }
  262. if matchingIP != nil {
  263. klog.V(4).Infof("Found valid IPv%d address %v for interface %q.", int(forFamily), matchingIP, intf.Name)
  264. return matchingIP, nil
  265. }
  266. }
  267. }
  268. return nil, nil
  269. }
  270. // memberOf tells if the IP is of the desired family. Used for checking interface addresses.
  271. func memberOf(ip net.IP, family AddressFamily) bool {
  272. if ip.To4() != nil {
  273. return family == familyIPv4
  274. } else {
  275. return family == familyIPv6
  276. }
  277. }
  278. // chooseIPFromHostInterfaces looks at all system interfaces, trying to find one that is up that
  279. // has a global unicast address (non-loopback, non-link local, non-point2point), and returns the IP.
  280. // addressFamilies determines whether it prefers IPv4 or IPv6
  281. func chooseIPFromHostInterfaces(nw networkInterfacer, addressFamilies AddressFamilyPreference) (net.IP, error) {
  282. intfs, err := nw.Interfaces()
  283. if err != nil {
  284. return nil, err
  285. }
  286. if len(intfs) == 0 {
  287. return nil, fmt.Errorf("no interfaces found on host.")
  288. }
  289. for _, family := range addressFamilies {
  290. klog.V(4).Infof("Looking for system interface with a global IPv%d address", uint(family))
  291. for _, intf := range intfs {
  292. if !isInterfaceUp(&intf) {
  293. klog.V(4).Infof("Skipping: down interface %q", intf.Name)
  294. continue
  295. }
  296. if isLoopbackOrPointToPoint(&intf) {
  297. klog.V(4).Infof("Skipping: LB or P2P interface %q", intf.Name)
  298. continue
  299. }
  300. addrs, err := nw.Addrs(&intf)
  301. if err != nil {
  302. return nil, err
  303. }
  304. if len(addrs) == 0 {
  305. klog.V(4).Infof("Skipping: no addresses on interface %q", intf.Name)
  306. continue
  307. }
  308. for _, addr := range addrs {
  309. ip, _, err := netutils.ParseCIDRSloppy(addr.String())
  310. if err != nil {
  311. return nil, fmt.Errorf("unable to parse CIDR for interface %q: %s", intf.Name, err)
  312. }
  313. if !memberOf(ip, family) {
  314. klog.V(4).Infof("Skipping: no address family match for %q on interface %q.", ip, intf.Name)
  315. continue
  316. }
  317. // TODO: Decide if should open up to allow IPv6 LLAs in future.
  318. if !ip.IsGlobalUnicast() {
  319. klog.V(4).Infof("Skipping: non-global address %q on interface %q.", ip, intf.Name)
  320. continue
  321. }
  322. klog.V(4).Infof("Found global unicast address %q on interface %q.", ip, intf.Name)
  323. return ip, nil
  324. }
  325. }
  326. }
  327. return nil, fmt.Errorf("no acceptable interface with global unicast address found on host")
  328. }
  329. // ChooseHostInterface is a method used fetch an IP for a daemon.
  330. // If there is no routing info file, it will choose a global IP from the system
  331. // interfaces. Otherwise, it will use IPv4 and IPv6 route information to return the
  332. // IP of the interface with a gateway on it (with priority given to IPv4). For a node
  333. // with no internet connection, it returns error.
  334. func ChooseHostInterface() (net.IP, error) {
  335. return chooseHostInterface(preferIPv4)
  336. }
  337. func chooseHostInterface(addressFamilies AddressFamilyPreference) (net.IP, error) {
  338. var nw networkInterfacer = networkInterface{}
  339. if _, err := os.Stat(ipv4RouteFile); os.IsNotExist(err) {
  340. return chooseIPFromHostInterfaces(nw, addressFamilies)
  341. }
  342. routes, err := getAllDefaultRoutes()
  343. if err != nil {
  344. return nil, err
  345. }
  346. return chooseHostInterfaceFromRoute(routes, nw, addressFamilies)
  347. }
  348. // networkInterfacer defines an interface for several net library functions. Production
  349. // code will forward to net library functions, and unit tests will override the methods
  350. // for testing purposes.
  351. type networkInterfacer interface {
  352. InterfaceByName(intfName string) (*net.Interface, error)
  353. Addrs(intf *net.Interface) ([]net.Addr, error)
  354. Interfaces() ([]net.Interface, error)
  355. }
  356. // networkInterface implements the networkInterfacer interface for production code, just
  357. // wrapping the underlying net library function calls.
  358. type networkInterface struct{}
  359. func (_ networkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
  360. return net.InterfaceByName(intfName)
  361. }
  362. func (_ networkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
  363. return intf.Addrs()
  364. }
  365. func (_ networkInterface) Interfaces() ([]net.Interface, error) {
  366. return net.Interfaces()
  367. }
  368. // getAllDefaultRoutes obtains IPv4 and IPv6 default routes on the node. If unable
  369. // to read the IPv4 routing info file, we return an error. If unable to read the IPv6
  370. // routing info file (which is optional), we'll just use the IPv4 route information.
  371. // Using all the routing info, if no default routes are found, an error is returned.
  372. func getAllDefaultRoutes() ([]Route, error) {
  373. routes, err := v4File.extract()
  374. if err != nil {
  375. return nil, err
  376. }
  377. v6Routes, _ := v6File.extract()
  378. routes = append(routes, v6Routes...)
  379. if len(routes) == 0 {
  380. return nil, noRoutesError{
  381. message: fmt.Sprintf("no default routes found in %q or %q", v4File.name, v6File.name),
  382. }
  383. }
  384. return routes, nil
  385. }
  386. // chooseHostInterfaceFromRoute cycles through each default route provided, looking for a
  387. // global IP address from the interface for the route. If there are routes but no global
  388. // address is obtained from the interfaces, it checks if the loopback interface has a global address.
  389. // addressFamilies determines whether it prefers IPv4 or IPv6
  390. func chooseHostInterfaceFromRoute(routes []Route, nw networkInterfacer, addressFamilies AddressFamilyPreference) (net.IP, error) {
  391. for _, family := range addressFamilies {
  392. klog.V(4).Infof("Looking for default routes with IPv%d addresses", uint(family))
  393. for _, route := range routes {
  394. if route.Family != family {
  395. continue
  396. }
  397. klog.V(4).Infof("Default route transits interface %q", route.Interface)
  398. finalIP, err := getIPFromInterface(route.Interface, family, nw)
  399. if err != nil {
  400. return nil, err
  401. }
  402. if finalIP != nil {
  403. klog.V(4).Infof("Found active IP %v ", finalIP)
  404. return finalIP, nil
  405. }
  406. // In case of network setups where default routes are present, but network
  407. // interfaces use only link-local addresses (e.g. as described in RFC5549).
  408. // the global IP is assigned to the loopback interface, and we should use it
  409. loopbackIP, err := getIPFromLoopbackInterface(family, nw)
  410. if err != nil {
  411. return nil, err
  412. }
  413. if loopbackIP != nil {
  414. klog.V(4).Infof("Found active IP %v on Loopback interface", loopbackIP)
  415. return loopbackIP, nil
  416. }
  417. }
  418. }
  419. klog.V(4).Infof("No active IP found by looking at default routes")
  420. return nil, fmt.Errorf("unable to select an IP from default routes.")
  421. }
  422. // ResolveBindAddress returns the IP address of a daemon, based on the given bindAddress:
  423. // If bindAddress is unset, it returns the host's default IP, as with ChooseHostInterface().
  424. // If bindAddress is unspecified or loopback, it returns the default IP of the same
  425. // address family as bindAddress.
  426. // Otherwise, it just returns bindAddress.
  427. func ResolveBindAddress(bindAddress net.IP) (net.IP, error) {
  428. addressFamilies := preferIPv4
  429. if bindAddress != nil && memberOf(bindAddress, familyIPv6) {
  430. addressFamilies = preferIPv6
  431. }
  432. if bindAddress == nil || bindAddress.IsUnspecified() || bindAddress.IsLoopback() {
  433. hostIP, err := chooseHostInterface(addressFamilies)
  434. if err != nil {
  435. return nil, err
  436. }
  437. bindAddress = hostIP
  438. }
  439. return bindAddress, nil
  440. }
  441. // ChooseBindAddressForInterface choose a global IP for a specific interface, with priority given to IPv4.
  442. // This is required in case of network setups where default routes are present, but network
  443. // interfaces use only link-local addresses (e.g. as described in RFC5549).
  444. // e.g when using BGP to announce a host IP over link-local ip addresses and this ip address is attached to the lo interface.
  445. func ChooseBindAddressForInterface(intfName string) (net.IP, error) {
  446. var nw networkInterfacer = networkInterface{}
  447. for _, family := range preferIPv4 {
  448. ip, err := getIPFromInterface(intfName, family, nw)
  449. if err != nil {
  450. return nil, err
  451. }
  452. if ip != nil {
  453. return ip, nil
  454. }
  455. }
  456. return nil, fmt.Errorf("unable to select an IP from %s network interface", intfName)
  457. }