mirror of
https://github.com/h44z/wg-portal
synced 2025-02-26 05:49:14 +00:00
209 lines
4.3 KiB
Go
209 lines
4.3 KiB
Go
package domain
|
|
|
|
import (
|
|
"github.com/vishvananda/netlink"
|
|
"net"
|
|
"net/netip"
|
|
"strings"
|
|
)
|
|
|
|
type Cidr struct {
|
|
Cidr string `gorm:"primaryKey;column:cidr"` // Sqlite/GORM does not support composite primary keys...
|
|
Addr string `gorm:"column:addr"`
|
|
NetLength int `gorm:"column:net_len"`
|
|
}
|
|
|
|
func (c Cidr) Prefix() netip.Prefix {
|
|
return netip.PrefixFrom(netip.MustParseAddr(c.Addr), c.NetLength)
|
|
}
|
|
|
|
func (c Cidr) String() string {
|
|
return c.Prefix().String()
|
|
}
|
|
|
|
func (c Cidr) IsValid() bool {
|
|
return c.Prefix().IsValid()
|
|
}
|
|
|
|
func CidrFromString(str string) (Cidr, error) {
|
|
prefix, err := netip.ParsePrefix(strings.TrimSpace(str))
|
|
if err != nil {
|
|
return Cidr{}, err
|
|
}
|
|
return CidrFromPrefix(prefix), nil
|
|
}
|
|
|
|
func CidrsFromString(str string) ([]Cidr, error) {
|
|
strParts := strings.Split(str, ",")
|
|
cidrs := make([]Cidr, len(strParts))
|
|
|
|
for i, cidrStr := range strParts {
|
|
cidr, err := CidrFromString(cidrStr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cidrs[i] = cidr
|
|
}
|
|
|
|
return cidrs, nil
|
|
}
|
|
|
|
func CidrsMust(cidrs []Cidr, err error) []Cidr {
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return cidrs
|
|
}
|
|
|
|
func CidrsFromArray(strs []string) ([]Cidr, error) {
|
|
cidrs := make([]Cidr, len(strs))
|
|
|
|
for i, cidrStr := range strs {
|
|
cidr, err := CidrFromString(cidrStr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cidrs[i] = cidr
|
|
}
|
|
|
|
return cidrs, nil
|
|
}
|
|
|
|
func CidrFromPrefix(prefix netip.Prefix) Cidr {
|
|
return Cidr{
|
|
Cidr: prefix.String(),
|
|
Addr: prefix.Addr().String(),
|
|
NetLength: prefix.Bits(),
|
|
}
|
|
}
|
|
|
|
func CidrFromIpNet(ipNet net.IPNet) Cidr {
|
|
prefix, _ := CidrFromString(ipNet.String())
|
|
return prefix
|
|
}
|
|
|
|
func CidrFromNetlinkAddr(addr netlink.Addr) Cidr {
|
|
prefix, _ := CidrFromString(addr.IPNet.String())
|
|
return prefix
|
|
}
|
|
|
|
func (c Cidr) IpNet() *net.IPNet {
|
|
ip, cidr, _ := net.ParseCIDR(c.String())
|
|
cidr.IP = ip
|
|
return cidr
|
|
}
|
|
|
|
func (c Cidr) NetlinkAddr() *netlink.Addr {
|
|
return &netlink.Addr{
|
|
IPNet: c.IpNet(),
|
|
}
|
|
}
|
|
|
|
func (c Cidr) IsV4() bool {
|
|
return c.Prefix().Addr().Is4()
|
|
}
|
|
|
|
// BroadcastAddr returns the last address in the given network (for IPv6), or the broadcast address.
|
|
func (c Cidr) BroadcastAddr() Cidr {
|
|
prefix := c.Prefix()
|
|
if !prefix.IsValid() {
|
|
return Cidr{}
|
|
}
|
|
a16 := prefix.Addr().As16()
|
|
var off uint8
|
|
var bits uint8 = 128
|
|
if prefix.Addr().Is4() {
|
|
off = 12
|
|
bits = 32
|
|
}
|
|
for b := uint8(prefix.Bits()); b < bits; b++ {
|
|
byteNum, bitInByte := b/8, 7-(b%8)
|
|
a16[off+byteNum] |= 1 << uint(bitInByte)
|
|
}
|
|
if prefix.Addr().Is4() {
|
|
addr := netip.AddrFrom16(a16).Unmap()
|
|
return Cidr{
|
|
Cidr: netip.PrefixFrom(addr, prefix.Bits()).String(),
|
|
Addr: addr.String(),
|
|
NetLength: prefix.Bits(),
|
|
}
|
|
} else {
|
|
addr := netip.AddrFrom16(a16) // doesn't unmap
|
|
return Cidr{
|
|
Cidr: netip.PrefixFrom(addr, prefix.Bits()).String(),
|
|
Addr: addr.String(), // doesn't unmap
|
|
NetLength: prefix.Bits(),
|
|
}
|
|
}
|
|
}
|
|
|
|
// NetworkAddr returns the network address in the given prefix.
|
|
func (c Cidr) NetworkAddr() Cidr {
|
|
prefix := c.Prefix()
|
|
if !prefix.IsValid() {
|
|
return Cidr{}
|
|
}
|
|
|
|
return CidrFromPrefix(prefix.Masked())
|
|
}
|
|
|
|
func (c Cidr) FirstAddr() Cidr {
|
|
prefix := c.Prefix()
|
|
firstAddr := prefix.Masked().Addr().Next()
|
|
return Cidr{
|
|
Cidr: netip.PrefixFrom(firstAddr, c.NetLength).String(),
|
|
Addr: firstAddr.String(),
|
|
NetLength: prefix.Bits(),
|
|
}
|
|
}
|
|
|
|
func (c Cidr) NextAddr() Cidr {
|
|
prefix := c.Prefix()
|
|
nextAddr := prefix.Addr().Next()
|
|
return Cidr{
|
|
Cidr: netip.PrefixFrom(nextAddr, c.NetLength).String(),
|
|
Addr: nextAddr.String(),
|
|
NetLength: prefix.Bits(),
|
|
}
|
|
}
|
|
|
|
func (c Cidr) HostAddr() Cidr {
|
|
return Cidr{
|
|
Cidr: netip.PrefixFrom(c.Prefix().Addr(), c.Prefix().Addr().BitLen()).String(),
|
|
Addr: c.Addr,
|
|
NetLength: c.Prefix().Addr().BitLen(),
|
|
}
|
|
}
|
|
|
|
func (c Cidr) NextSubnet() Cidr {
|
|
prefix := c.Prefix()
|
|
nextAddr := c.BroadcastAddr().Prefix().Addr().Next()
|
|
return Cidr{
|
|
Cidr: netip.PrefixFrom(nextAddr, c.NetLength).String(),
|
|
Addr: nextAddr.String(),
|
|
NetLength: prefix.Bits(),
|
|
}
|
|
}
|
|
|
|
func CidrsToString(slice []Cidr) string {
|
|
return strings.Join(CidrsToStringSlice(slice), ",")
|
|
}
|
|
|
|
func CidrsToStringSlice(slice []Cidr) []string {
|
|
cidrs := make([]string, len(slice))
|
|
|
|
for i, cidr := range slice {
|
|
cidrs[i] = cidr.String()
|
|
}
|
|
|
|
return cidrs
|
|
}
|
|
|
|
func (c Cidr) Contains(other Cidr) bool {
|
|
_, subnet, _ := net.ParseCIDR(c.String())
|
|
otherIP, _, _ := net.ParseCIDR(other.String())
|
|
|
|
return subnet.Contains(otherIP)
|
|
}
|