interface.go 11 KB

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