interface.go 15 KB

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