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  }