Skip to content

Commit

Permalink
Rewrite README and update code examples
Browse files Browse the repository at this point in the history
  • Loading branch information
Chad Robinson committed May 9, 2019
1 parent 65dac03 commit fc330d3
Showing 1 changed file with 117 additions and 61 deletions.
178 changes: 117 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
# IPLib

A hopefully useful, asperationally full-featured library for working with IP
addresses and networks.

IPLib is an extension of the `net.IP` utilities and is intended to make working
with IP addresses a little bit easier by providing tools to manage blocks of
addresses. Tools include:

# IPLib
[![Documentation](https://godoc.org/github.com/c-robinson/iplib?status.svg)](http://godoc.org/github.com/c-robinson/iplib)
[![CircleCI](https://circleci.com/gh/c-robinson/iplib/tree/master.svg?style=svg)](https://circleci.com/gh/c-robinson/iplib/tree/master)
[![Go Report Card](https://goreportcard.com/badge/github.com/c-robinson/iplib)](https://goreportcard.com/report/github.com/c-robinson/iplib)
[![Coverage Status](https://coveralls.io/repos/github/c-robinson/iplib/badge.svg?branch=master)](https://coveralls.io/github/c-robinson/iplib?branch=master)

I really enjoy Python's [ipaddress](https://docs.python.org/3/library/ipaddress.html)
library and Ruby's [ipaddr](https://ruby-doc.org/stdlib-2.5.1/libdoc/ipaddr/rdoc/IPAddr.html),
I think you can write a lot of neat software if some of the little problems
around manipulating IP addresses and netblocks are taken care of for you, so I
set out to write something like them for my language of choice, Go. This is
what I've come up with.

[IPLib](http://godoc.org/github.com/c-robinson/iplib) is a hopefully useful,
aspirationally full-featured library built around and on top of the address
primitives found in the [net](https://golang.org/pkg/net/) package, it seeks
to make them more accessible and easier to manipulate.

It includes:

##### net.IP tools

Some simple tools for performing common tasks against IP objects:
Expand All @@ -37,31 +43,38 @@ An enhancement of `net.IPNet` providing features such as:
- Find free space between allocated subnets
- Expand subnets if space allows

#### Using IPNet
#### Using IPLib

There are a series of functions for working with v4 or v6 `net.IP` objects:

```Go
import "github.com/c-robinson/iplib"
package main

main() {
ipa := net.IP{192,168,1,1}
ipb := net.IP{192,168,1,5}
import (
"fmt"
"net"
"sort"

"github.com/c-robinson/iplib"
)

c := iplib.CompareIPs(ipa, ipb)
d := iplib.DeltaIP(ipa, ipb)

ipc := iplib.IncrementIPBy(ipb, 20)
fmt.Println(IPToHextString(ipc))

iplist := []net.IP{ ipb, ipc, ipa }
sorted := sort.Sort(iplib.ByAddr(iplist))
func main() {
ipa := net.ParseIP("192.168.1.1")
ipb := iplib.IncrementIPBy(ipa, 15) // ipb is 192.168.1.16
ipc := iplib.NextIP(ipa) // ipc is 192.168.1.2

vers := iplib.Version(ipc)
fmt.Println(iplib.CompareIPs(ipa, ipb)) // -1

fmt.Println(iplib.DeltaIP(ipa, ipb)) // 15

fmt.Println(iplib.IPToHexString(ipc)) // "c0a80102"

asInt := iplib.IP4ToUint32(ipc)
ipd := iplib.Uint32ToIP4(asInt+20)
iplist := []net.IP{ ipb, ipc, ipa }
sort.Sort(iplib.ByIP(iplist)) // []net.IP{ipa, ipc, ipb}

fmt.Println(iplib.IP4ToUint32(ipa)) // 3232235777
ipd := iplib.Uint32ToIP4(iplib.IP4ToUint32(ipa)+20) // ipd is 192.168.1.21
}
```

Expand All @@ -72,55 +85,98 @@ IPv6-specific variants use `big.Int` so they can access the entire v6 space:


```Go
main() {
ip6a := net.IP{32,1,13,184,133,163,0,0,0,0,138,46,3,112,115,52}
package main

import (
"fmt"
"math/big"
"net"
"sort"

"github.com/c-robinson/iplib"
)


func main() {
ipa := net.ParseIP("2001:db8::1")
ipb := iplib.IncrementIPBy(ipa, 15) // ipb is 2001:db8::16
ipc := iplib.NextIP(ipa) // ipc is 2001:db8::2

m := big.NewInt(int64(iplib.MaxUint32)) // MaxUint32 is 4,294,967,296
ip6b := iplib.IncrementIP6By(ip6a, m)
fmt.Println(iplib.CompareIPs(ipa, ipb)) // -1

fmt.Println(iplib.DeltaIP6(ipa, ipb)) // 15

fmt.Println(iplib.ExpandIP6(ipa)) // "2001:0db8:0000:0000:0000:0000:0000:0001"
fmt.Println(iplib.IPToBigint(ipa)) // 42540766411282592856903984951653826561

iplist := []net.IP{ ipb, ipc, ipa }
sort.Sort(iplib.ByIP(iplist)) // []net.IP{ipa, ipc, ipb}

d := iplib.DeltaIP6(ip6a, ip6b)
m := big.NewInt(int64(iplib.MaxIPv4)) // e.g. 4,294,967,295
ipd := iplib.IncrementIP6By(ipa, m) // ipd is 2001:db8::1:0:0

asBigint := iplib.IP6ToBigint(ip6b)
ip6c := iplib.BigintToIP6(asBigint.Add(m))
fmt.Println(iplib.DeltaIP6(ipb, ipd)) // 4294967274
}

```

To work with networks simply create an `iplib.IPNet` object:

```Go
import "path/to/iplib"

main() {
ipa, ipna, erra := iplib.NewNet("192.168.1.0/22")
if erra != nil {
// become sad!
}

ipb, ipnb, errb := iplib.NewNet("192.168.2.0/24")
if errb != nil {
// still sad!
}

fmt.Println(ipna.Count()) // there's a Count6() for IPv6

iplib.CompareNets(ipna, ipnb)

ipnlist := []iplib.Net{ipnb, ipna}
sorted := sort.Sort(ByNet(ipnlist))
package main

import (
"fmt"
"net"
"sort"

"github.com/c-robinson/iplib"
)

func main() {
// this calls net.ParseCIDR() under the hood, but returns an iplib.Net object
_, ipna, err := iplib.ParseCIDR("192.168.1.0/22")
if err != nil {
// this will be an error from the net package
}

// NewNet() wants a net.IP and is waaaaaaaaaaaaaaaaay faster
ipb := net.ParseIP("192.168.2.0")
ipnb := iplib.NewNet(ipb, 22)

v := ipna.ContainsNet(ipnb)

ipc, errc := ipna.NextIP(ipna.NetworkAddress())
if errc != nil {
// be sad
}
// ...works for IPv6 too
ipc := net.ParseIP("2001:db8::1")
ipnc := iplib.NewNet(ipc, 64)

ipd, errd := ipna.PreviousIP(ipna.NetworkAddress())
if errd != nil {
// rejoice, for this will error out (underflowing network boundary)
}
fmt.Println(ipna.Count()) // 1022 -- good enough for ipv4, but...

fmt.Println(ipnc.Count()) // 4294967295 -- ...sigh
fmt.Println(ipnc.Count6()) // 18446744073709551616 -- yay Count6() !

iplist := ipna.Enumerate(0, 0)
fmt.Println(iplib.CompareNets(ipna, ipnb)) // -1

ipnlist := []iplib.Net{ipnb, ipna, ipnc}
sort.Sort(iplib.ByNet(ipnlist)) // []iplib.Net{ ipna, ipnb, ipnc }

elist := ipna.Enumerate(0, 0)
fmt.Println(len(elist)) // 1022

fmt.Println(ipna.ContainsNet(ipnb)) // true

fmt.Println(ipna.NetworkAddress()) // 192.168.1.0
fmt.Println(ipna.FirstAddress()) // 192.168.1.1
fmt.Println(ipna.LastAddress()) // 192.168.3.254
fmt.Println(ipna.BroadcastAddress()) // 192.168.3.255

fmt.Println(ipnc.NetworkAddress()) // 2001:db8::1 -- meaningless in IPv6
fmt.Println(ipnc.FirstAddress()) // 2001:db8::1
fmt.Println(ipnc.LastAddress()) // 2001:db8::ffff:ffff:ffff:ffff
fmt.Println(ipnc.BroadcastAddress()) // 2001:db8::ffff:ffff:ffff:ffff

ipa1 := net.ParseIP("2001:db8::2")
ipa1, err = ipna.PreviousIP(ipa1) // net.IP{2001:db8::1}, nil
ipa1, err = ipna.PreviousIP(ipa1) // net.IP{}, ErrAddressAtEndOfRange
}
```

TODO: add subnetting functions

0 comments on commit fc330d3

Please sign in to comment.