interface.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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 Route struct {
  25. Interface string
  26. Destination net.IP
  27. Gateway net.IP
  28. // TODO: add more fields here if needed
  29. }
  30. func getRoutes(input io.Reader) ([]Route, error) {
  31. routes := []Route{}
  32. if input == nil {
  33. return nil, fmt.Errorf("input is nil")
  34. }
  35. scanner := bufio.NewReader(input)
  36. for {
  37. line, err := scanner.ReadString('\n')
  38. if err == io.EOF {
  39. break
  40. }
  41. //ignore the headers in the route info
  42. if strings.HasPrefix(line, "Iface") {
  43. continue
  44. }
  45. fields := strings.Fields(line)
  46. routes = append(routes, Route{})
  47. route := &routes[len(routes)-1]
  48. route.Interface = fields[0]
  49. ip, err := parseIP(fields[1])
  50. if err != nil {
  51. return nil, err
  52. }
  53. route.Destination = ip
  54. ip, err = parseIP(fields[2])
  55. if err != nil {
  56. return nil, err
  57. }
  58. route.Gateway = ip
  59. }
  60. return routes, nil
  61. }
  62. func parseIP(str string) (net.IP, error) {
  63. if str == "" {
  64. return nil, fmt.Errorf("input is nil")
  65. }
  66. bytes, err := hex.DecodeString(str)
  67. if err != nil {
  68. return nil, err
  69. }
  70. //TODO add ipv6 support
  71. if len(bytes) != net.IPv4len {
  72. return nil, fmt.Errorf("only IPv4 is supported")
  73. }
  74. bytes[0], bytes[1], bytes[2], bytes[3] = bytes[3], bytes[2], bytes[1], bytes[0]
  75. return net.IP(bytes), nil
  76. }
  77. func isInterfaceUp(intf *net.Interface) bool {
  78. if intf == nil {
  79. return false
  80. }
  81. if intf.Flags&net.FlagUp != 0 {
  82. glog.V(4).Infof("Interface %v is up", intf.Name)
  83. return true
  84. }
  85. return false
  86. }
  87. //getFinalIP method receives all the IP addrs of a Interface
  88. //and returns a nil if the address is Loopback, Ipv6, link-local or nil.
  89. //It returns a valid IPv4 if an Ipv4 address is found in the array.
  90. func getFinalIP(addrs []net.Addr) (net.IP, error) {
  91. if len(addrs) > 0 {
  92. for i := range addrs {
  93. glog.V(4).Infof("Checking addr %s.", addrs[i].String())
  94. ip, _, err := net.ParseCIDR(addrs[i].String())
  95. if err != nil {
  96. return nil, err
  97. }
  98. //Only IPv4
  99. //TODO : add IPv6 support
  100. if ip.To4() != nil {
  101. if !ip.IsLoopback() && !ip.IsLinkLocalMulticast() && !ip.IsLinkLocalUnicast() {
  102. glog.V(4).Infof("IP found %v", ip)
  103. return ip, nil
  104. } else {
  105. glog.V(4).Infof("Loopback/link-local found %v", ip)
  106. }
  107. } else {
  108. glog.V(4).Infof("%v is not a valid IPv4 address", ip)
  109. }
  110. }
  111. }
  112. return nil, nil
  113. }
  114. func getIPFromInterface(intfName string, nw networkInterfacer) (net.IP, error) {
  115. intf, err := nw.InterfaceByName(intfName)
  116. if err != nil {
  117. return nil, err
  118. }
  119. if isInterfaceUp(intf) {
  120. addrs, err := nw.Addrs(intf)
  121. if err != nil {
  122. return nil, err
  123. }
  124. glog.V(4).Infof("Interface %q has %d addresses :%v.", intfName, len(addrs), addrs)
  125. finalIP, err := getFinalIP(addrs)
  126. if err != nil {
  127. return nil, err
  128. }
  129. if finalIP != nil {
  130. glog.V(4).Infof("valid IPv4 address for interface %q found as %v.", intfName, finalIP)
  131. return finalIP, nil
  132. }
  133. }
  134. return nil, nil
  135. }
  136. func flagsSet(flags net.Flags, test net.Flags) bool {
  137. return flags&test != 0
  138. }
  139. func flagsClear(flags net.Flags, test net.Flags) bool {
  140. return flags&test == 0
  141. }
  142. func chooseHostInterfaceNativeGo() (net.IP, error) {
  143. intfs, err := net.Interfaces()
  144. if err != nil {
  145. return nil, err
  146. }
  147. i := 0
  148. var ip net.IP
  149. for i = range intfs {
  150. if flagsSet(intfs[i].Flags, net.FlagUp) && flagsClear(intfs[i].Flags, net.FlagLoopback|net.FlagPointToPoint) {
  151. addrs, err := intfs[i].Addrs()
  152. if err != nil {
  153. return nil, err
  154. }
  155. if len(addrs) > 0 {
  156. for _, addr := range addrs {
  157. if addrIP, _, err := net.ParseCIDR(addr.String()); err == nil {
  158. if addrIP.To4() != nil {
  159. ip = addrIP.To4()
  160. if !ip.IsLinkLocalMulticast() && !ip.IsLinkLocalUnicast() {
  161. break
  162. }
  163. }
  164. }
  165. }
  166. if ip != nil {
  167. // This interface should suffice.
  168. break
  169. }
  170. }
  171. }
  172. }
  173. if ip == nil {
  174. return nil, fmt.Errorf("no acceptable interface from host")
  175. }
  176. glog.V(4).Infof("Choosing interface %s (IP %v) as default", intfs[i].Name, ip)
  177. return ip, nil
  178. }
  179. //ChooseHostInterface is a method used fetch an IP for a daemon.
  180. //It uses data from /proc/net/route file.
  181. //For a node with no internet connection ,it returns error
  182. //For a multi n/w interface node it returns the IP of the interface with gateway on it.
  183. func ChooseHostInterface() (net.IP, error) {
  184. inFile, err := os.Open("/proc/net/route")
  185. if err != nil {
  186. if os.IsNotExist(err) {
  187. return chooseHostInterfaceNativeGo()
  188. }
  189. return nil, err
  190. }
  191. defer inFile.Close()
  192. var nw networkInterfacer = networkInterface{}
  193. return chooseHostInterfaceFromRoute(inFile, nw)
  194. }
  195. type networkInterfacer interface {
  196. InterfaceByName(intfName string) (*net.Interface, error)
  197. Addrs(intf *net.Interface) ([]net.Addr, error)
  198. }
  199. type networkInterface struct{}
  200. func (_ networkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
  201. intf, err := net.InterfaceByName(intfName)
  202. if err != nil {
  203. return nil, err
  204. }
  205. return intf, nil
  206. }
  207. func (_ networkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
  208. addrs, err := intf.Addrs()
  209. if err != nil {
  210. return nil, err
  211. }
  212. return addrs, nil
  213. }
  214. func chooseHostInterfaceFromRoute(inFile io.Reader, nw networkInterfacer) (net.IP, error) {
  215. routes, err := getRoutes(inFile)
  216. if err != nil {
  217. return nil, err
  218. }
  219. zero := net.IP{0, 0, 0, 0}
  220. var finalIP net.IP
  221. for i := range routes {
  222. //find interface with gateway
  223. if routes[i].Destination.Equal(zero) {
  224. glog.V(4).Infof("Default route transits interface %q", routes[i].Interface)
  225. finalIP, err := getIPFromInterface(routes[i].Interface, nw)
  226. if err != nil {
  227. return nil, err
  228. }
  229. if finalIP != nil {
  230. glog.V(4).Infof("Choosing IP %v ", finalIP)
  231. return finalIP, nil
  232. }
  233. }
  234. }
  235. glog.V(4).Infof("No valid IP found")
  236. if finalIP == nil {
  237. return nil, fmt.Errorf("Unable to select an IP.")
  238. }
  239. return nil, nil
  240. }
  241. // If bind-address is usable, return it directly
  242. // If bind-address is not usable (unset, 0.0.0.0, or loopback), we will use the host's default
  243. // interface.
  244. func ChooseBindAddress(bindAddress net.IP) (net.IP, error) {
  245. if bindAddress == nil || bindAddress.IsUnspecified() || bindAddress.IsLoopback() {
  246. hostIP, err := ChooseHostInterface()
  247. if err != nil {
  248. return nil, err
  249. }
  250. bindAddress = hostIP
  251. }
  252. return bindAddress, nil
  253. }