package netUtils import ( "encoding/binary" "errors" "io" "net" "net/http" common "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.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< 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{} // DefaultNetInterfaceNames are interface names that I have on my machine var DefaultNetInterfaceNames = NetInterfaceNamesT{ "eth0": {}, "wlan0": {}, } // IpToInt 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 }