github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/core/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 goos = func() string {
    15  	return runtime.GOOS
    16  }
    17  
    18  var runIPRouteShow = func() (string, error) {
    19  	output, err := exec.Command("ip", "route", "show").CombinedOutput()
    20  	if err != nil {
    21  		return "", err
    22  	}
    23  	return string(output), nil
    24  }
    25  
    26  func GetDefaultRoute() (net.IP, string, error) {
    27  	output, err := runIPRouteShow()
    28  	if err != nil {
    29  		return nil, "", err
    30  	}
    31  	logger.Tracef("ip route show output:\n%s", output)
    32  	var defaultRouteMetric = ^uint64(0)
    33  	var defaultRoute string
    34  	var defaultRouteDevice string
    35  	for _, line := range strings.Split(output, "\n") {
    36  		to, values := parseIpRouteShowLine(line)
    37  		logger.Tracef("parsing ip r s line to %q, values %+v ", to, values)
    38  		if to == "default" {
    39  			var metric = uint64(0)
    40  			if v, ok := values["metric"]; ok {
    41  				if i, err := strconv.ParseUint(v, 10, 64); err == nil {
    42  					metric = i
    43  				} else {
    44  					return nil, "", err
    45  				}
    46  			}
    47  			if metric < defaultRouteMetric {
    48  				// We want to replace our current default route if it's valid.
    49  				via, hasVia := values["via"]
    50  				dev, hasDev := values["dev"]
    51  				if hasVia || hasDev {
    52  					defaultRouteMetric = metric
    53  					if hasVia {
    54  						defaultRoute = via
    55  					} else {
    56  						defaultRoute = ""
    57  					}
    58  					if hasDev {
    59  						defaultRouteDevice = dev
    60  					} else {
    61  						defaultRouteDevice = ""
    62  					}
    63  				}
    64  			}
    65  		}
    66  	}
    67  	return net.ParseIP(defaultRoute), defaultRouteDevice, nil
    68  }
    69  
    70  func parseIpRouteShowLine(line string) (string, map[string]string) {
    71  	values := make(map[string]string)
    72  	fields := strings.Fields(line)
    73  	if len(fields) < 2 {
    74  		return "", values
    75  	}
    76  	to, fields := fields[0], fields[1:]
    77  	for ; len(fields) >= 2; fields = fields[2:] {
    78  		values[fields[0]] = fields[1]
    79  	}
    80  	return to, values
    81  }