Files
gluetun/internal/routing/local.go
Quentin McGaw (desktop) d6659552df Maint: refactor internal/routing
- Split Go files better
- Reduce public API for exported errors
2021-08-25 17:52:05 +00:00

122 lines
2.9 KiB
Go

package routing
import (
"errors"
"fmt"
"net"
"github.com/qdm12/gluetun/internal/netlink"
)
var (
ErrLinkList = errors.New("cannot list links")
ErrLinkLocalNotFound = errors.New("local link not found")
ErrSubnetDefaultNotFound = errors.New("default subnet not found")
ErrSubnetLocalNotFound = errors.New("local subnet not found")
)
type LocalNetwork struct {
IPNet *net.IPNet
InterfaceName string
IP net.IP
}
type LocalSubnetGetter interface {
LocalSubnet() (defaultSubnet net.IPNet, err error)
}
func (r *Routing) LocalSubnet() (defaultSubnet net.IPNet, err error) {
routes, err := r.netLinker.RouteList(nil, netlink.FAMILY_ALL)
if err != nil {
return defaultSubnet, fmt.Errorf("%w: %s", ErrRoutesList, err)
}
defaultLinkIndex := -1
for _, route := range routes {
if route.Dst == nil {
defaultLinkIndex = route.LinkIndex
break
}
}
if defaultLinkIndex == -1 {
return defaultSubnet, fmt.Errorf("%w: in %d route(s)", ErrLinkDefaultNotFound, len(routes))
}
for _, route := range routes {
if route.Gw != nil || route.LinkIndex != defaultLinkIndex {
continue
}
defaultSubnet = *route.Dst
r.logger.Info("local subnet found: " + defaultSubnet.String())
return defaultSubnet, nil
}
return defaultSubnet, fmt.Errorf("%w: in %d routes", ErrSubnetDefaultNotFound, len(routes))
}
type LocalNetworksGetter interface {
LocalNetworks() (localNetworks []LocalNetwork, err error)
}
func (r *Routing) LocalNetworks() (localNetworks []LocalNetwork, err error) {
links, err := r.netLinker.LinkList()
if err != nil {
return localNetworks, fmt.Errorf("%w: %s", ErrLinkList, err)
}
localLinks := make(map[int]struct{})
for _, link := range links {
if link.Attrs().EncapType != "ether" {
continue
}
localLinks[link.Attrs().Index] = struct{}{}
r.logger.Info("local ethernet link found: " + link.Attrs().Name)
}
if len(localLinks) == 0 {
return localNetworks, fmt.Errorf("%w: in %d links", ErrLinkLocalNotFound, len(links))
}
routes, err := r.netLinker.RouteList(nil, netlink.FAMILY_V4)
if err != nil {
return localNetworks, fmt.Errorf("%w: %s", ErrRoutesList, err)
}
for _, route := range routes {
if route.Gw != nil || route.Dst == nil {
continue
} else if _, ok := localLinks[route.LinkIndex]; !ok {
continue
}
var localNet LocalNetwork
localNet.IPNet = route.Dst
r.logger.Info("local ipnet found: " + localNet.IPNet.String())
link, err := r.netLinker.LinkByIndex(route.LinkIndex)
if err != nil {
return localNetworks, fmt.Errorf("%w: at index %d: %s", ErrLinkByIndex, route.LinkIndex, err)
}
localNet.InterfaceName = link.Attrs().Name
ip, err := r.assignedIP(localNet.InterfaceName)
if err != nil {
return localNetworks, err
}
localNet.IP = ip
localNetworks = append(localNetworks, localNet)
}
if len(localNetworks) == 0 {
return localNetworks, fmt.Errorf("%w: in %d routes", ErrSubnetLocalNotFound, len(routes))
}
return localNetworks, nil
}