github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/network/gateway.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package network 5 6 import ( 7 "net" 8 "os/exec" 9 "runtime" 10 "strconv" 11 "strings" 12 ) 13 14 var simulatedOS = "" 15 16 // GetDefaultRoute returns the IP address and device name of default gateway on the machine. 17 // If we don't support OS, or we don't have a default route, we return nothing (not an error!). 18 func GetDefaultRoute() (net.IP, string, error) { 19 os := simulatedOS 20 if os == "" { 21 os = runtime.GOOS 22 } 23 // TODO(wpk) 2017-11-20 Add Windows support here, hence the switch. 24 switch os { 25 case "linux": 26 return getDefaultRouteLinux() 27 default: 28 return nil, "", nil 29 } 30 } 31 32 func parseIpRouteShowLine(line string) (string, map[string]string) { 33 values := make(map[string]string) 34 fields := strings.Fields(line) 35 if len(fields) < 2 { 36 return "", values 37 } 38 to, fields := fields[0], fields[1:] 39 for ; len(fields) >= 2; fields = fields[2:] { 40 values[fields[0]] = fields[1] 41 } 42 return to, values 43 } 44 45 func launchIpRouteShowReal() (string, error) { 46 output, err := exec.Command("ip", "route", "show").CombinedOutput() 47 if err != nil { 48 return "", err 49 } 50 return string(output), nil 51 } 52 53 var launchIpRouteShow = launchIpRouteShowReal 54 55 func getDefaultRouteLinux() (net.IP, string, error) { 56 output, err := launchIpRouteShow() 57 if err != nil { 58 return nil, "", err 59 } 60 logger.Tracef("ip route show output:\n%s", output) 61 var defaultRouteMetric = ^uint64(0) 62 var defaultRoute string 63 var defaultRouteDevice string 64 for _, line := range strings.Split(output, "\n") { 65 to, values := parseIpRouteShowLine(line) 66 logger.Tracef("parsing ip r s line to %q, values %+v ", to, values) 67 if to == "default" { 68 var metric = uint64(0) 69 if v, ok := values["metric"]; ok { 70 if i, err := strconv.ParseUint(v, 10, 64); err == nil { 71 metric = i 72 } else { 73 return nil, "", err 74 } 75 } 76 if metric < defaultRouteMetric { 77 // We want to replace our current default route if it's valid. 78 via, hasVia := values["via"] 79 dev, hasDev := values["dev"] 80 if hasVia || hasDev { 81 defaultRouteMetric = metric 82 if hasVia { 83 defaultRoute = via 84 } else { 85 defaultRoute = "" 86 } 87 if hasDev { 88 defaultRouteDevice = dev 89 } else { 90 defaultRouteDevice = "" 91 } 92 } 93 } 94 } 95 } 96 return net.ParseIP(defaultRoute), defaultRouteDevice, nil 97 }