New functions for net.IP and net.IPNet

1,745 views
Skip to first unread message

bill...@gmail.com

unread,
Jun 30, 2013, 8:44:37 PM6/30/13
to golan...@googlegroups.com
Hello all,

I wrote a very small library which contains three functions I needed in my program relating to IP addresses: https://github.com/llimllib/ipaddress

Two of the functions are for converting an IP to a uint32 and back, and the other returns the broadcast address of an IPNet.

Would there be any interest in me writing up a patch to contribute any of these to the standard library? I think they're quite general, and many ip address libraries contain functions like these.

Thanks
Bill Mill

References:

Nigel Tao

unread,
Jul 1, 2013, 2:40:52 AM7/1/13
to bill...@gmail.com, golang-nuts
On Mon, Jul 1, 2013 at 10:44 AM, <bill...@gmail.com> wrote:
> I wrote a very small library which contains three functions I needed in my
> program relating to IP addresses: https://github.com/llimllib/ipaddress

A couple of points on the first two:

Using a bytes.Buffer is overkill. Just use BigEndian directly:
return binary.BigEndian.Uint32([]byte(ip))

The 0xFFs in
return net.IPv4(byte(ip>>24), byte(ip>>16&0xFF), byte(ip>>8&0xFF),
byte(ip&0xFF))
are unnecessary; they are implied by the byte conversion. It can just be:
return net.IPv4(byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip))


> Would there be any interest in me writing up a patch to contribute any of
> these to the standard library? I think they're quite general, and many ip
> address libraries contain functions like these.

I am not really a network guy, but these little helper functions seem
trivial, once they're written properly. What's the need? Why do you
need to convert a net.IP to a uint32? Can't you pass a net.IP around
instead?

bill...@gmail.com

unread,
Jul 1, 2013, 9:24:13 AM7/1/13
to golan...@googlegroups.com
On Monday, July 1, 2013 2:40:52 AM UTC-4, Nigel Tao wrote:
On Mon, Jul 1, 2013 at 10:44 AM,  <bill...@gmail.com> wrote:
> I wrote a very small library which contains three functions I needed in my
> program relating to IP addresses: https://github.com/llimllib/ipaddress

A couple of points on the first two:

Using a bytes.Buffer is overkill. Just use BigEndian directly:
return binary.BigEndian.Uint32([]byte(ip))

The 0xFFs in
return net.IPv4(byte(ip>>24), byte(ip>>16&0xFF), byte(ip>>8&0xFF),
byte(ip&0xFF))
are unnecessary; they are implied by the byte conversion. It can just be:
return net.IPv4(byte(ip>>24), byte(ip>>16), byte(ip>>8), byte(ip))

Both fixed, thank you very much for the review. I'm new to Go.
 
> Would there be any interest in me writing up a patch to contribute any of
> these to the standard library? I think they're quite general, and many ip
> address libraries contain functions like these.

I am not really a network guy, but these little helper functions seem
trivial, once they're written properly. What's the need? Why do you
need to convert a net.IP to a uint32? Can't you pass a net.IP around
instead?

Inside the program it's quite easy to pass around a net.IP. However, IPv4s are generally passed to databases and in wire protocols as integers.

My argument that they ought to be considered for the stdlib rests not on the difficulty of writing the functions (though you proved that it's possible for a person to do poorly!), but on the frequency of such operations.

Converting to/from an integer is the most common way to serialize an IPv4, and the current standard library has no way to get the *end* of an IPNet range, hence the BroadcastAddress function.

Thanks,
Bill Mill

DisposaBoy

unread,
Jul 1, 2013, 2:46:02 PM7/1/13
to golan...@googlegroups.com
I'm not in a position to search but I believe some database have support for storing up addresses so maybe you don't need to mess around with serialization

Mikio Hara

unread,
Jul 13, 2013, 3:44:32 AM7/13/13
to bill...@gmail.com, golang-nuts
On Mon, Jul 1, 2013 at 10:24 PM, <bill...@gmail.com> wrote:

> Converting to/from an integer is the most common way to serialize an IPv4,
> and the current standard library has no way to get the *end* of an IPNet
> range, hence the BroadcastAddress function.

You can write something like:

func ipv4DirectedBroadcast(n *net.IPNet) net.IP {
ip4 := n.IP.To4()
if ip4 == nil {
return nil
}
last := make(net.IP, len(ip4))
copy(last, ip4)
for i := range ip4 {
last[i] |= ^n.Mask[i]
}
return last
}

PS. http://godoc.org/github.com/mikioh/ipaddr

bill...@gmail.com

unread,
Jul 15, 2013, 12:01:04 AM7/15/13
to golan...@googlegroups.com, bill...@gmail.com
Why do you like that better than my BroadcastAddress function? I ask honestly, I'm not sure, and it seems like it doesn't work for IPv6.
 

PS. http://godoc.org/github.com/mikioh/ipaddr

Awesome! I didn't see this when I was looking for libraries. I've added it to the packages wiki[1], where I had been searching for packages.

I suppose that godoc is much more complete than the package wiki? Perhaps the link at the bottom of http://golang.org/pkg/ should be changed from pointing to the package wiki to pointing to godoc.org?

Anyway, I'm going to keep my library around because I want to return uint32 for IPv4, not big.Int. (Unless you would consider accepting a pull request for an IPv4 -> uint32 function for ipaddress? In that case I'd happily remove my library).

Thanks
Bill Mill

Mikio Hara

unread,
Jul 15, 2013, 7:56:47 PM7/15/13
to Bill Mill, golang-nuts
On Mon, Jul 15, 2013 at 1:01 PM, <bill...@gmail.com> wrote:

> Why do you like that better than my BroadcastAddress function? I ask
> honestly, I'm not sure,

IPv6 addressing architecture has no broadcast stuff, use multicasting instead.
So your proposed signature net.BroadcastAddress(*net.IPNet) (uint32, error)
looks a bit confusing me.

> and it seems like it doesn't work for IPv6.

You can test address families by using net.IP.TO4() and net.IP.To16().

> Awesome! I didn't see this when I was looking for libraries. I've added it
> to the packages wiki[1], where I had been searching for packages.

Thanks. Actually you reminded me that having ipaddr.py-like package is
not so bad. So I gathered code fragments from old exercise folders and
wrapped them in that package last friday night.

> I suppose that godoc is much more complete than the package wiki? Perhaps
> the link at the bottom of http://golang.org/pkg/ should be changed from
> pointing to the package wiki to pointing to godoc.org?

Well, not sure.

> Anyway, I'm going to keep my library around because I want to return uint32
> for IPv4, not big.Int. (Unless you would consider accepting a pull request
> for an IPv4 -> uint32 function for ipaddress? In that case I'd happily
> remove my library).

Having your own package is really nice.
Please keep trying to improve it and happy hacking!

PS: You can use Bits method of ipaddr.Prefix; e.g., p.Bits(0, 32) will return
a 32-bit sequence.

Mikio Hara

unread,
Jul 15, 2013, 9:38:31 PM7/15/13
to Bill Mill, golang-nuts
On Tue, Jul 16, 2013 at 8:56 AM, Mikio Hara <mikioh...@gmail.com> wrote:

> So your proposed signature net.BroadcastAddress(*net.IPNet) (uint32, error)

s/uint32/net.IP/, sorry.

bill...@gmail.com

unread,
Jul 15, 2013, 11:44:20 PM7/15/13
to golan...@googlegroups.com, Bill Mill
On Monday, July 15, 2013 7:56:47 PM UTC-4, Mikio Hara wrote:
On Mon, Jul 15, 2013 at 1:01 PM,  <bill...@gmail.com> wrote:

> Why do you like that better than my BroadcastAddress function? I ask
> honestly, I'm not sure,

IPv6 addressing architecture has no broadcast stuff, use multicasting instead.
So your proposed signature net.BroadcastAddress(*net.IPNet) (uint32, error)
looks a bit confusing me.

Fair enough! I only intended to create a function to return the last address of a range, and I don't know much at all about IPv6. I'll rename the function to LastAddress to be clearer.

> You can test address families by using net.IP.TO4() and net.IP.To16(). 

Yup, I do that in my code.

Anyway, I'd still like to see the three functions I provide in the stdlib! They're very simple but a bit tricky (as we see in this thread!) to write, and super handy. I have to use them all the time working with network addresses.

Right now it's possible to create an IP range with the standard library's net.IPNet but not to get the range of addresses without writing your own annoying bit-twiddling function, which seems like a poor API to me.

-Bill

Mikio Hara

unread,
Jul 16, 2013, 11:13:08 PM7/16/13
to Bill Mill, golang-nuts
On Tue, Jul 16, 2013 at 12:44 PM, <bill...@gmail.com> wrote:

> They're very simple but a bit tricky (as we see in this thread!) to write,
> and super handy. I have to use them all the time working with network
> addresses.

I believe you can use encoding/binary package instead.

ip := net.ParseIP("192.168.0.1")
i := binary.BigEndian.Uint32(ip.To4())
i++
nip := make(net.IP, len(ip.To4()))
binary.BigEndian.PutUint32(nip, i)

And wrt BroadcastAddr, how could we deal with a multiply ambiguous net.IPNet?
http://play.golang.org/p/Igo6Ct3gx

So I don't think adding net.BroadcastAddr is a good idea.

Mikio Hara

unread,
Jul 16, 2013, 11:19:20 PM7/16/13
to Bill Mill, golang-nuts
Reply all
Reply to author
Forward
0 new messages