nettools/net/ip.go

153 lines
3.5 KiB
Go

package net_utils
import (
"encoding/binary"
"errors"
"io"
"net"
"net/http"
common_utils "git.mic.pp.ua/anderson/nettools/common"
)
var (
ErrInitializingRequest = errors.New("error while initializing the request")
ErrReadingBody = errors.New("err while reading the body")
ErrDialingServ = errors.New("err while dealing the server")
ErrInterfaceNotFound = errors.New("provided network interface name wasn't found")
)
const (
DEFAULT_HTTP_PORT = 80
DEFAULT_WS_PORT = 80
DEFAULT_WSS_PORT = 443
DEFAULT_HTTPS_PORT = 443
DEFAULT_GRPC_PORT = 9090
)
const (
// network masks
MASK8 uint32 = 0b11111111_00000000_00000000_00000000
MASK12 uint32 = 0b11111111_11110000_00000000_00000000
MASK16 uint32 = 0b11111111_11111111_00000000_00000000
MASK24 uint32 = 0b11111111_11111111_11111111_00000000
MASK32 uint32 = 0b11111111_11111111_11111111_11111111
// reserved IP adresses
IP_192_168_0_0 uint32 = 0b11000000_10101000_00000000_00000000
IP_172_16_0_0 uint32 = 0b10101100_00010000_00000000_00000000
IP_10_0_0_0 uint32 = 0b00001010_00000000_00000000_00000000
// reserved for Local Network IP addresses
PRESERVED_IP_RANGE_192 uint32 = IP_192_168_0_0 & MASK16
PRESERVED_IP_RANGE_172 uint32 = IP_172_16_0_0 & MASK12
PRESERVED_IP_RANGE_10 uint32 = IP_10_0_0_0 & MASK8
)
func MaskToBytes[T common_utils.Int](mask T) [4]uint8 {
if mask > 32 {
panic("mask is invalid: value out of range")
}
var out [4]uint8
for i := 0; i < 4; i++ {
if mask >= 8 {
out[i] = 0b11111111
mask -= 8
} else {
out[i] = 1<<mask - 1
out[i] = out[i] << (8 - mask)
break
}
}
return out
}
func BytesToUint32(in []uint8) (uint32, error) {
bytes := make([]uint8, 4)
if len(bytes) > 4 {
return 0, errors.New("bad input value length, expected up to 4 bytes")
}
copy(in, bytes)
return uint32(
bytes[0])<<24 |
uint32(bytes[1])<<16 |
uint32(bytes[2])<<8 |
uint32(bytes[3]), nil
}
type NetInterfaceNamesT = map[string]struct{}
// Those are ones I have on my machine, so they are default, lol
var DefaultNetInterfaceNames = NetInterfaceNamesT{
"eth0": {},
"wlan0": {},
}
// Converts IP which is a byte array to an integer
// So it can be used with the bitmasks or be compared fast
func IpToInt(ip net.IP) uint32 {
if len(ip) == 16 {
return binary.BigEndian.Uint32(ip[12:16])
}
return binary.BigEndian.Uint32(ip)
}
func GetWanIP(ipv4 bool) (net.IP, error) {
url := "http://4.ident.me"
if !ipv4 {
url = "http://6.ident.me"
}
req, err := http.Get(url)
if err != nil {
return nil, errors.Join(ErrInitializingRequest, err)
}
defer req.Body.Close()
body, err := io.ReadAll(req.Body)
if err != nil {
return nil, errors.Join(ErrReadingBody, err)
}
return net.ParseIP(string(body)), err
}
func GetLanIP(interfaceNames NetInterfaceNamesT) (net.IP, error) {
if interfaceNames == nil {
interfaceNames = DefaultNetInterfaceNames
}
ifaces, err := net.Interfaces()
if err != nil {
return nil, err
}
for _, i := range ifaces {
if i.Name != "" {
_, whitelisted := interfaceNames[i.Name]
if !whitelisted {
continue
}
}
addrs, err := i.Addrs()
if err != nil {
return nil, err
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
intIP := IpToInt(ip)
if intIP&MASK16 == PRESERVED_IP_RANGE_192 ||
intIP&MASK12 == PRESERVED_IP_RANGE_172 ||
intIP&MASK8 == PRESERVED_IP_RANGE_10 {
return ip, nil
}
}
}
return nil, ErrInterfaceNotFound
}