interface.go 12 KB

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