Skip to content

Instantly share code, notes, and snippets.

@kkirsche
Last active October 25, 2022 15:18
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kkirsche/ed0dd0fc7c044705fd1a56a7e1b1fa24 to your computer and use it in GitHub Desktop.
Save kkirsche/ed0dd0fc7c044705fd1a56a7e1b1fa24 to your computer and use it in GitHub Desktop.
inet_aton and inet6_aton in Golang
package nessusProcessor
import (
"encoding/hex"
"math/big"
"net"
)
// Inet_Aton converts an IPv4 net.IP object to a 64 bit integer.
func Inet_Aton(ip net.IP) int64 {
ipv4Int := big.NewInt(0)
ipv4Int.SetBytes(ip.To4())
return ipv4Int.Int64()
}
// Inet6_Aton converts an IP Address (IPv4 or IPv6) net.IP object to a hexadecimal
// representaiton. This function is the equivalent of
// inet6_aton({{ ip address }}) in MySQL.
func Inet6_Aton(ip net.IP) string {
ipv4 := false
if ip.To4() != nil {
ipv4 = true
}
ipInt := big.NewInt(0)
if ipv4 {
ipInt.SetBytes(ip.To4())
ipHex := hex.EncodeToString(ipInt.Bytes())
return ipHex
}
ipInt.SetBytes(ip.To16())
ipHex := hex.EncodeToString(ipInt.Bytes())
return ipHex
}
@sundarv85
Copy link

Is there a way to reverse it, ie. for IPv4 from int64 back to net.IP, and for IPv6 from string back to IPv6.

@michaellindman
Copy link

michaellindman commented Feb 2, 2021

Is there a way to reverse it, ie. for IPv4 from int64 back to net.IP, and for IPv6 from string back to IPv6.

I know this is super old but this should do the trick, all you have todo is decode the hex and return it as a net.IP.

func Inet6_Aton_Decode(ipHex string) (ip net.IP, err error) {
	hex, err := hex.DecodeString(ipHex)
	if err != nil {
		return nil, err
	}
	return net.IP(hex), nil
}

@jrwren
Copy link

jrwren commented Jun 29, 2021

These are my drive by comments:

These functions are named backwards.

https://linux.die.net/man/3/inet_aton takes a string and returns an address. "a to n" as in "address(ascii) to network".

What is implemented here would be better named IPToInt and IPToN respectively. inet_ntoa is also documented in the linked man page.

@isaacwein
Copy link

I played around with your examples it it works great, but

mysql SELECT INET6_ATON('11:22:33:44:55:66:77:88'); returns 0x00110022003300440055006600770088 length 32
go Inet6_Aton("11:22:33:44:55:66:77:88")returns 110022003300440055006600770088 length 30

@isaacwein
Copy link

I made a full example and I update it to go1.18 netip (go doc says this package's Addr type takes less memory)

import (
	"encoding/hex"
	"fmt"
	"math/big"
	"net/netip"
	"strings"
)

// INET_ATON converts an IPv4 netip.Addr object to a 64 bit integer.
func INET_ATON(ip netip.Addr) (int64, error) {
	if !ip.Is4() {
		return 0, fmt.Errorf("ip is not ipv4")
	}
	ipv4Int := big.NewInt(0)
	ipv4 := ip.As4()
	ipv4Int.SetBytes(ipv4[:])
	return ipv4Int.Int64(), nil
}

// INET6_ATON converts an IP Address (IPv4 or IPv6) netip.Addr object to a hexadecimal
// representaiton. This function is the equivalent of
// inet6_aton({{ ip address }}) in MySQL.
func INET6_ATON(ip netip.Addr) (string, error) {
	ipInt := big.NewInt(0)
	switch {
	case ip.Is4():
		ipv4 := ip.As4()
		ipInt.SetBytes(ipv4[:])
		return hex.EncodeToString(ipInt.Bytes()), nil
	case ip.Is6():
		ipv6 := ip.As16()
		ipInt.SetBytes(ipv6[:])
		return hex.EncodeToString(ipInt.Bytes()), nil
	default:
		return "", fmt.Errorf("invalid ip address")
	}
}

// INET_NTOA came from https://go.dev/play/p/JlYJXZnUxl
func INET_NTOA(ipInt64 uint32) (ip netip.Addr) {
	ipArray := [4]byte{byte(ipInt64 >> 24), byte(ipInt64 >> 16), byte(ipInt64 >> 8), byte(ipInt64)}
	ip = netip.AddrFrom4(ipArray)
	return
}

func INET6_NTOA(ipHex string) (ip netip.Addr, err error) {
	ipHex = strings.TrimPrefix(ipHex, "0x")

	HEX, err := hex.DecodeString(ipHex)
	if err != nil {
		err = fmt.Errorf("error decoding hex %w", err)
		return
	}
	if len(HEX) > 16 {
		//adding all caraters that mising of the begening
		HEX = append(make([]byte, 16-len(HEX)), HEX...)
	}

	ip, ok := netip.AddrFromSlice(HEX)
	if !ok {
		err = fmt.Errorf("invalid ip hax")
	}
	return
}

test.go

import (
	"net/netip"
	"testing"
)

func TestINET_ATON(t *testing.T) {
	ipv4, _ := netip.ParseAddr("192.168.1.1")
	aton, err := INET_ATON(ipv4)
	if err != nil {
		t.Errorf("err: %s", err.Error())
		return
	}

	t.Logf("number: %d", aton)
}

func TestINET6_ATON(t *testing.T) {
	ipv4, _ := netip.ParseAddr("11:22:33:44:55:66:77:88")
	aton, err := INET6_ATON(ipv4)
	if err != nil {
		t.Errorf("err: %s", err.Error())
		return
	}

	t.Logf("hex: 0x%s", aton)
}

func TestINET_NTOA(t *testing.T) {
	ntoa := INET_NTOA(3232235777)
	t.Logf("ipv4: %s",ntoa.String())
}

func TestINET6_NTOA(t *testing.T) {
	ntoa, err := INET6_NTOA("0x110022003300440055006600770088")
	if err != nil {
		t.Errorf("err: %s", err.Error())
		return
	}

	t.Logf("ipv6: %s",ntoa.String())
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment