blob: 58894d71d9f7fef366cdb34db2c4cd499399ab97 [file] [log] [blame] [edit]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package internal
import (
"fmt"
"net"
"os"
"strings"
"v.io/v23/verror"
"v.io/x/lib/vlog"
"v.io/x/lib/netstate"
"v.io/x/ref/lib/exec"
"v.io/x/ref/lib/flags"
)
// ParseFlags parses all registered flags taking into account overrides from other
// configuration and environment variables. It must be called by the profile and
// flags.RuntimeFlags() must be passed to the runtime initialization function. The
// profile can use or modify the flags as it pleases.
func ParseFlags(f *flags.Flags) error {
handle, err := exec.GetChildHandle()
if err == nil {
// The process has been started through the vanadium exec
// library.
} else if verror.ErrorID(err) == exec.ErrNoVersion.ID {
// The process has not been started through the vanadium exec
// library. No further action is needed.
} else {
return err
}
// Parse runtime flags.
var config map[string]string
if handle != nil {
config = handle.Config.Dump()
}
return f.Parse(os.Args[1:], config)
}
// IPAddressChooser returns the preferred IP address, which is,
// a public IPv4 address, then any non-loopback IPv4, then a public
// IPv6 address and finally any non-loopback/link-local IPv6
func IPAddressChooser(network string, addrs []net.Addr) ([]net.Addr, error) {
if !netstate.IsIPProtocol(network) {
return nil, fmt.Errorf("can't support network protocol %q", network)
}
accessible := netstate.ConvertToAddresses(addrs)
// Try and find an address on a interface with a default route.
// We give preference to IPv4 over IPv6 for compatibility for now.
var predicates []netstate.AddressPredicate
if !strings.HasSuffix(network, "6") {
predicates = append(predicates, netstate.IsPublicUnicastIPv4, netstate.IsUnicastIPv4)
}
if !strings.HasSuffix(network, "4") {
predicates = append(predicates, netstate.IsPublicUnicastIPv6, netstate.IsUnicastIPv6)
}
for _, predicate := range predicates {
if addrs := accessible.Filter(predicate); len(addrs) > 0 {
onDefaultRoutes := addrs.Filter(netstate.IsOnDefaultRoute)
if len(onDefaultRoutes) > 0 {
return onDefaultRoutes.AsNetAddrs(), nil
}
}
}
// We failed to find any addresses with default routes, try again
// but without the default route requirement.
for _, predicate := range predicates {
if addrs := accessible.Filter(predicate); len(addrs) > 0 {
return addrs.AsNetAddrs(), nil
}
}
return []net.Addr{}, nil
}
// HasPublicIP returns true if the host has at least one public IP address.
func HasPublicIP(log vlog.Logger) bool {
state, err := netstate.GetAccessibleIPs()
if err != nil {
log.Infof("failed to determine network state: %s", err)
return false
}
any := state.Filter(netstate.IsUnicastIP)
if len(any) == 0 {
log.Infof("failed to find any usable IP addresses at startup")
return false
}
for _, a := range any {
if netstate.IsPublicUnicastIPv4(a) {
return true
}
}
return false
}