github.com/haraldrudell/parl@v0.4.176/pnet/destination.go (about)

     1  /*
     2  © 2020–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package pnet
     7  
     8  import (
     9  	"net/netip"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/haraldrudell/parl/perrors"
    14  )
    15  
    16  // Destination represents a selector for routing, ie. an IPv4 or IPv6 address with zone
    17  // and prefix.
    18  // go1.18 introduced [netip.Prefix] for this purpose
    19  // see Linux: ip route add.
    20  // [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ] [ table TABLE_ID ] [ vrf NAME ]
    21  // [ proto RTPROTO ] [ type TYPE ] [ scope SCOPE ]
    22  // contains IP, Zone and Mask
    23  type Destination struct {
    24  	netip.Prefix
    25  }
    26  
    27  // NewDestination instantiates Destination.
    28  // addr is IPv4 address or IPv6 address with Zone.
    29  // prefix is number of bits actually used 0…32 for IPv4, 0…128 for IPv6
    30  func NewDestination(prefix netip.Prefix) (d *Destination) {
    31  	return &Destination{Prefix: prefix}
    32  }
    33  
    34  func (d Destination) IsValid() (err error) {
    35  	if !d.Prefix.IsValid() {
    36  		err = perrors.ErrorfPF("invalid prefix: %#v", d.Prefix)
    37  		return
    38  	}
    39  	return
    40  }
    41  
    42  // Key is a string suitable as a key in a map
    43  func (d Destination) Key() (key netip.Prefix) {
    44  	return d.Prefix
    45  }
    46  
    47  // IsDefaultRoute returns whether Destination is a default route:
    48  //   - IPv4: 0/0 or 0.0.0.0/0
    49  //   - IPv6: ::
    50  func (d Destination) IsDefaultRoute() (isDefault bool) {
    51  	var addr = d.Addr()
    52  	if !addr.IsValid() || d.Bits() != 0 {
    53  		return // address not valid or not /0
    54  	}
    55  	isDefault = addr.IsUnspecified()
    56  
    57  	return
    58  }
    59  
    60  // "1.2.3.4/24" or "2000::/3"
    61  // - abbreviate IPv4: "127.0.0.0/8" → "127/8"
    62  // - IPv4 default route: "0.0.0.0/0" → "0/0"
    63  //   - IPv6 default route stays "::/0"
    64  func (d Destination) String() (s string) {
    65  
    66  	// abbreviate IPv4: 0.0.0.0/0 → 0/0 127.0.0.0/8 → 127/8
    67  	if d.Prefix.Addr().Is4() {
    68  		ipv4 := d.Prefix.Addr().String()
    69  		for strings.HasSuffix(ipv4, ".0") {
    70  			ipv4 = strings.TrimSuffix(ipv4, ".0")
    71  		}
    72  		return ipv4 + "/" + strconv.Itoa(d.Bits())
    73  	}
    74  	return d.Prefix.String()
    75  }