diff options
author | Franck Cuny <franck@fcuny.net> | 2022-06-18 14:10:23 -0700 |
---|---|---|
committer | Franck Cuny <franck@fcuny.net> | 2022-06-18 14:18:02 -0700 |
commit | 300eb227b160f05d7aa429e9c779f2c74e095f81 (patch) | |
tree | 8b0ea3e46f6d259969aef51eec2e20d385fecfa7 | |
parent | ref(scripts): remove the module for scripts (diff) | |
download | world-300eb227b160f05d7aa429e9c779f2c74e095f81.tar.gz |
feat(ipconverter): add a tool to convert IPv4 to int and vice-versa
It's sometimes useful to store IPv4 addresses as an integer. This tool helps with the conversion, and also does the reverse conversion. ``` % go run . int2ip 3232235521 3232235521 192.168.0.1 % go run . ip2int 192.168.0.1 192.168.0.1 3232235521 ``` Change-Id: Ic1e44057bca3539b4c183d387c635f69f5bf3f36 Reviewed-on: https://cl.fcuny.net/c/world/+/441 Tested-by: CI Reviewed-by: Franck Cuny <franck@fcuny.net>
-rw-r--r-- | tools/ipconverter/default.nix | 15 | ||||
-rw-r--r-- | tools/ipconverter/go.mod | 3 | ||||
-rw-r--r-- | tools/ipconverter/main.go | 58 | ||||
-rw-r--r-- | tools/ipconverter/main_test.go | 44 |
4 files changed, 120 insertions, 0 deletions
diff --git a/tools/ipconverter/default.nix b/tools/ipconverter/default.nix new file mode 100644 index 0000000..3be25fc --- /dev/null +++ b/tools/ipconverter/default.nix @@ -0,0 +1,15 @@ +{ pkgs, ... }: + +pkgs.buildGoModule rec { + name = "ipconverter"; + src = ./.; + vendorSha256 = "sha256-pQpattmS9VmO3ZIQUFn66az8GSmB4IvYhTTCFn6SUmo="; + nativeBuildInputs = with pkgs; [ go ]; + + meta = with pkgs.lib; { + description = "CLI to convert IP addresses to integer and vice versa"; + license = licenses.mit; + platforms = platforms.linux; + maintainers = [ ]; + }; +} diff --git a/tools/ipconverter/go.mod b/tools/ipconverter/go.mod new file mode 100644 index 0000000..49b8653 --- /dev/null +++ b/tools/ipconverter/go.mod @@ -0,0 +1,3 @@ +module golang.fcuny.net/ipconverter + +go 1.17 diff --git a/tools/ipconverter/main.go b/tools/ipconverter/main.go new file mode 100644 index 0000000..1211970 --- /dev/null +++ b/tools/ipconverter/main.go @@ -0,0 +1,58 @@ +package main + +import ( + "encoding/binary" + "fmt" + "math/big" + "net" + "os" + "path" + "strconv" +) + +func main() { + cmd := path.Base(os.Args[1]) + + switch cmd { + case "ip2int": + for _, ip := range os.Args[2:] { + r, err := IPtoInt(ip) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to parse %s to an int: %s", ip, err) + continue + } + fmt.Printf("%s\t%d\n", ip, r) + } + case "int2ip": + for _, ip := range os.Args[2:] { + r, err := IPtoN(ip) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to parse %s to an addresse IP: %s", ip, err) + continue + } + fmt.Printf("%s\t%s", ip, r) + } + default: + fmt.Printf("`%s' is not a supported command", cmd) + os.Exit(1) + } +} + +func IPtoInt(ip string) (*big.Int, error) { + i := net.ParseIP(ip) + if len(i.To4()) == 4 { + return big.NewInt(0).SetBytes(i.To4()), nil + } else { + return nil, fmt.Errorf("%s is not an IPv4 address", ip) + } +} + +func IPtoN(ip string) (string, error) { + r, err := strconv.Atoi(ip) + if err != nil { + return "", fmt.Errorf("failed to parse %s to an int: %s", ip, err) + } + newIP := make(net.IP, 4) + binary.BigEndian.PutUint32(newIP, uint32(r)) + return newIP.To4().String(), nil +} diff --git a/tools/ipconverter/main_test.go b/tools/ipconverter/main_test.go new file mode 100644 index 0000000..394dc28 --- /dev/null +++ b/tools/ipconverter/main_test.go @@ -0,0 +1,44 @@ +package main + +import ( + "math/big" + "testing" +) + +func TestIPtoInt(t *testing.T) { + + tests := map[string]*big.Int{ + "192.168.0.1": big.NewInt(3232235521), + "10.0.0.1": big.NewInt(167772161), + } + for test := range tests { + r, err := IPtoInt(test) + if err != nil { + t.Errorf("failed to convert %s to an int: %s", test, err) + } + if r.Cmp(tests[test]) != 0 { + t.Errorf("convert %s to int, got %d expected %d", test, r, tests[test]) + } + } + + if _, err := IPtoInt("10"); err == nil { + t.Error("calling IPtoInt with invalid IP did not result in error") + } +} + + +func TestIPtoN(t *testing.T) { + tests := map[string]string{ + "3232235521": "192.168.0.1", + "167772161": "10.0.0.1", + } + for test := range tests { + r, err := IPtoN(test) + if err != nil { + t.Errorf("failed to convert %s to an address: %s", test, err) + } + if r != tests[test] { + t.Errorf("convert %s to address, got %s expected %s", test, r, tests[test]) + } + } +} |