Skip to content

Commit

Permalink
Create a early first working version
Browse files Browse the repository at this point in the history
  • Loading branch information
Themimitoof committed Aug 16, 2022
0 parents commit 574b989
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 0 deletions.
15 changes: 15 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module github.com/themimitoof/ipg

go 1.18

require (
github.com/alecthomas/kong v0.6.1
github.com/c-robinson/iplib v1.0.3
github.com/fatih/color v1.13.0
)

require (
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
)
28 changes: 28 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
github.com/alecthomas/kong v0.6.1 h1:1kNhcFepkR+HmasQpbiKDLylIL8yh5B5y1zPp5bJimA=
github.com/alecthomas/kong v0.6.1/go.mod h1:JfHWDzLmbh/puW6I3V7uWenoh56YNVONW+w8eKeUr9I=
github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142 h1:8Uy0oSf5co/NZXje7U1z8Mpep++QJOldL2hs/sBQf48=
github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/c-robinson/iplib v1.0.3 h1:NG0UF0GoEsrC1/vyfX1Lx2Ss7CySWl3KqqXh3q4DdPU=
github.com/c-robinson/iplib v1.0.3/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
176 changes: 176 additions & 0 deletions ipg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package main

import (
"fmt"
"math/rand"
"net"
"os"
"strings"
"time"

"github.com/alecthomas/kong"
"github.com/c-robinson/iplib"
"github.com/fatih/color"
)

var cli struct {
Subnet string `arg:"" help:"IPv6 Subnet"`
Random bool `short:"r" xor:"Name,Random" required:"" help:"Generate a random IPv6 address on the given subnet."`
Name string `short:"n" xor:"Name,Random" required:"" help:"Specify the hostname of a machine, an IPv6 address will be generated based on it."`
Silent bool `short:"s" help:"Only display values without their labels."`
Reverse bool `short:"R" help:"Display the ARPA version of the IP address."`
DNSRecord bool `name:"dns" short:"d" help:"Returns a DNS record ready to paste to a DNS zone."`
ReverseRecord bool `name:"rrecord" short:"x" help:"Returns a rDNS record ready to paste to a DNS zone."`
DNSTTL int `name:"ttl" short:"t" default:"86400" help:"TTL value for DNS returned DNS records."`
}

// Function stollen from c-robinson/iplib, method non-exposed by the lib ¯\_(ツ)_/¯
func Net6wildcard(n iplib.Net6) net.IPMask {
wc := make([]byte, len(n.Mask()))
for i, b := range n.Mask() {
wc[i] = 0xff - b
}
return wc
}

func RandomNumber(min int, max int) int {
rand.Seed(time.Now().UnixNano())
return rand.Intn(max-min) + min
}

// Generate a random IP address based on the given IP subnet.
func GenerateRandomIP(net iplib.Net6) net.IP {
finalIP := net.FirstAddress()

for idx, b := range net.Mask() {
if b == 0xff {
continue
} else if b != 0x0 {
randByte := byte(RandomNumber(0, 255))
wildCardByte := Net6wildcard(net)[idx]

finalIP[idx] = net.IP()[idx] + wildCardByte&randByte
} else {
finalIP[idx] = byte(RandomNumber(0, 255))
}
}

return finalIP
}

// Generate an IP address based on the hostname.
// The algorithm first tries with the complete hostname, if it does not work,
// it tries by removing vowels and iterate by removing character by character.
func GenerateIPFromHostname(net iplib.Net6, hostname string) net.IP {
finalIP := []byte(net.FirstAddress())
cidr, _ := net.Mask().Size()
availableBits := 128 - cidr
hostname = strings.Split(hostname, ".")[0]

if len(hostname)*8 > availableBits {
// Remove vowels
shrinkedHostname := []byte{}
for _, c := range hostname {
asVowel := false

for _, v := range "aiueo" {
if c == v {
asVowel = true
}
}

if !asVowel {
shrinkedHostname = append(shrinkedHostname, byte(c))
}
}

// In case it's not enough, shrink last character until it fits
for len(shrinkedHostname)*8 > availableBits {
shrinkedHostname = shrinkedHostname[0 : len(shrinkedHostname)-1]
}

hostname = string(shrinkedHostname)
}

for i, c := range hostname {
pos := len(finalIP) - len(hostname) + i
finalIP[pos] = byte(c)
}

return finalIP
}

// Generate a DNS record ready to be paste on a Bind compatible zone
func GenerateDNSRecord(ip string, ttl int, hostname string) string {
return fmt.Sprintf("%s\t%d\tIN\tAAAA\t%s", hostname, ttl, ip)
}

// Generate a ARPA record ready to be paste on a Bind compatible zone
func GenerateReverseDNSRecord(ip string, ttl int, hostname string) string {
return fmt.Sprintf("%s.\t%d\tIN\tPTR\t%s", ip, ttl, hostname)
}

func main() {
kong.Parse(
&cli,
kong.Description("A simple IPv6 generator for lazy netadmins."),
)

var ipNetwork iplib.Net6 = iplib.Net6FromStr(cli.Subnet)

// Check if the Subnet is valid or not.
if len(ipNetwork.IP()) == 0 {
fmt.Println("The given subnet is not valid.")
os.Exit(1)
}

// Check if the subnet is not too small to be used
var cidr, _ = ipNetwork.Mask().Size()

if cidr > 126 {
fmt.Printf("The given subnet is too small (/%d) to be used with ipg.\n", cidr)
os.Exit(1)
}

// Generate the new IP address using the given generation method
var generatedIp net.IP

if cli.Random {
generatedIp = GenerateRandomIP(ipNetwork)
} else {
generatedIp = GenerateIPFromHostname(ipNetwork, cli.Name)
}

var reverseIpAddr string = iplib.IPToARPA(generatedIp)
var ipAddr string = generatedIp.String()

// Always display the generated IP address
if !cli.Silent {
fmt.Printf("IP address: ")
}
color.Yellow(ipAddr)

// Display the ARPA version of the IP address if the flag is set
if cli.Reverse {
if !cli.Silent {
fmt.Printf("Reverse IP address: ")
}
color.Yellow(reverseIpAddr)
}

// Display the BIND DNS record if the flag is set
if cli.DNSRecord {
if !cli.Silent {
fmt.Println("DNS record:")
}
color.Yellow(GenerateDNSRecord(ipAddr, cli.DNSTTL, cli.Name))
}

// Display the ARPA DNS record if the flag is set
if cli.ReverseRecord {
if !cli.Silent {
fmt.Println("ARPA DNS record:")
}
color.Yellow(GenerateReverseDNSRecord(reverseIpAddr, cli.DNSTTL, cli.Name))
}
}

0 comments on commit 574b989

Please sign in to comment.