How can I get the address of a pointer? - go

package main
import "fmt"
func main() {
var a int= 20
var ip *int
ip = &a
fmt.Printf("a address: %x\n", &a )
fmt.Printf(" the adrress that ip stored: %x\n", ip )
/*I try to get the address of variable ip */
fmt.Printf(" the address of ip: %d\n", &ip )
}
go run a.go
result:
a address: c420016078
the adrress that ip stored: c420016078
the address of ip: 842350510120
my question is : is 842350510120 correct address of ip?

If you print addresses in a consistent base (hexadecimal), you will see the expected result. In the current versions of the Go gc compiler, the variables i and pi are allocated on the heap.
For example,
package main
import "fmt"
func main() {
var i int = 20
var pi *int = &i
fmt.Printf("%x the address of i\n", &i)
fmt.Printf("%x the address of pi\n", &pi)
fmt.Printf("%x the address that pi stored\n", pi)
}
Output:
c00008e010 the address of i
c000090018 the address of pi
c00008e010 the address that pi stored

my question is : is 842350510120 correct address of ip?
Nobody can answer this. It depends on your computer and might even change on every run of the program.
If you are asking whether fmt.Printf("%d", &ip) prints the address of ip: Yes.

No, you need to print the address like %x like you did in the previous print statements. I guess, thats what confused you as the address was being read as an int.
Working code here, https://play.golang.org/p/v0UXMQ3fCkd

Related

How to get the IP range of a CIDR

How can I get the start and end for v4 and v6 ip addresses of a CIDR? I don't care about addresses which are between.
I have checked the net library and parseCIDR does not return this information. Is there an idiomatic way to calculate the ip range of a CIDR which will work for v6 and v4 addresses alike?
For example, given the CIDR 2001:db8:a0b:12f0::1/32 I would expect
2001:0db8:0000:0000:0000:0000:0000:0000 and 2001:0db8:ffff:ffff:ffff:ffff:ffff:ffff returned as the start and end addresses respectively.
Using the IPAddress Go library, this code will do it for either IPv4 or IPv6. Disclaimer: I am the project manager.
import (
"fmt"
"github.com/seancfoley/ipaddress-go/ipaddr"
)
func main() {
ipRange("2001:db8:a0b:12f0::1/32")
ipRange("1.2.3.1/16")
}
func ipRange(cidr string) {
block := ipaddr.NewIPAddressString(cidr).GetAddress().ToPrefixBlock()
addr := block.WithoutPrefixLen()
fmt.Printf("addr %s block %s lower %s upper %s\n",
cidr, block, addr.GetLower(), addr.GetUpper())
}
Output:
addr 2001:db8:a0b:12f0::1/32 block 2001:db8::/32 lower 2001:db8:: upper 2001:db8:ffff:ffff:ffff:ffff:ffff:ffff
addr 1.2.3.1/16 block 1.2.0.0/16 lower 1.2.0.0 upper 1.2.255.255

Remaining IPs in a range/CIDR

I would like to find the remaining IPs in a range (CIDR).
For example:
prefixLen, bits := n.Mask.Size()
return 1 << (uint64(bits) - uint64(prefixLen)), nil
This return the # of IPs in the range where n is *net.IPNet.
But say if I have few addresses that are already given out and want to know how many are left 'starting' from some IP addresses, how can I do it?
Here's something you could do
package main
import (
"fmt"
"net"
)
func inet_aton(ip string) uint32 {
var rv uint32
b := net.ParseIP(ip).To4()
rv=uint32(b[0]) << 24
rv=rv+uint32(b[1]) << 16
rv=rv+uint32(b[2]) << 8
rv=rv+uint32(b[3])
return rv
}
func main() {
start := inet_aton("192.168.0.1") //192.168.2.0/20 start
fin := inet_aton("192.168.15.255") //ditto end
here := inet_aton("192.168.15.248") //current allocation
fmt.Printf("you have %d remaining\n",(fin-start) - (here-start))
}
Here is a way to do it that works for both IPv4 and IPv6 using the IPAddress Go library. Disclaimer: I am the project manager.
func remaining(cidr string) (used, remaining, total *big.Int) {
cidrStr := ipaddr.NewIPAddressString(cidr)
cidrBlock := cidrStr.GetAddress().ToPrefixBlock()
host := cidrStr.GetHostAddress()
used = new(big.Int).Sub(host.GetValue(), cidrBlock.GetValue())
remaining = new(big.Int).Sub(cidrBlock.GetUpperValue(), host.GetValue())
total = cidrBlock.GetCount()
fmt.Printf("\nHost %s is address number %d of %d addresses in block %s.\n"+
"There remains %d addresses.\n", host, used, total, cidrBlock,
remaining)
return
}
If you want to stick with IPv4, then you can replace big.Int with unsigned int types.
func remainingIPv4(cidr string) (used, remaining uint32, total uint64) {
cidrStr := ipaddr.NewIPAddressString(cidr)
cidrBlock := cidrStr.GetAddress().ToPrefixBlock().ToIPv4()
host := cidrStr.GetHostAddress().ToIPv4()
used = host.Uint32Value() - cidrBlock.Uint32Value()
remaining = cidrBlock.UpperUint32Value() - host.Uint32Value()
total = cidrBlock.GetIPv4Count()
fmt.Printf("\nHost %s is address number %d of %d addresses in block %s.\n"+
"There remains %d addresses.\n", host, used, total, cidrBlock,
remaining)
return
}
Example:
package main
import (
"fmt"
"github.com/seancfoley/ipaddress-go/ipaddr"
"math/big"
)
func main() {
remaining("192.168.2.0/20")
remaining("2001:0db8:85a3::8a2e:0370:7334/64")
remainingIPv4("192.168.2.0/20")
}
Example output:
Host 192.168.2.0 is address number 512 of 4096 addresses in block 192.168.0.0/20.
There remains 3583 addresses.
Host 2001:db8:85a3::8a2e:370:7334 is address number 151930230829876 of 18446744073709551616 addresses in block 2001:db8:85a3::/64.
There remains 18446592143478721739 addresses.
Host 192.168.2.0 is address number 512 of 4096 addresses in block 192.168.0.0/20.
There remains 3583 addresses.

How to find range (prefix?) of ipv6 addresses that a machine can use, and how to transform a subnet of ipv6 into a slice of ip addresses?

There are many things I don't understand about ipv6 and networking in general, which is why I need some further clarification on some the answers already posted to other questions. I'll list my questions, what I grasped from other answers, and what I'm still confused about.
Say I have a VPS with a /56 ipv6 subnet (256 * residential /64 subnets) allotted to it. How can I programmatically find the range (prefix?) of the ip's I "own".
How to get IPv4 and IPv6 address of local machine?. This is the answer I saw for this question: and what I think I understand is that I get the DNS hostname for the machine, then look up that same hostname to find the range. I'm wondering two things: How do I do this in Go, and
How do I transfer this range ^ into a slice (array) of ipv6 addresses. For this specific use case: the ideal solution would be to only get one ipv6 address per \64 subnet, resulting in 256 seperate ips
DNS is not very helpful in determining the local IP addresses, because a DNS entry is not required to make an IP address work, nor is it required to point to (only) the machine that you happen to run your program on.
Instead, inspect the network interfaces and their configuration:
package main
import (
"fmt"
"log"
"net"
"os"
"text/tabwriter"
)
func main() {
tw := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
ifaces, err := net.Interfaces()
if err != nil {
log.Fatal(err)
}
for _, iface := range ifaces {
addrs, err := iface.Addrs()
if err != nil {
log.Fatal(err)
}
for _, addr := range addrs {
addr, ok := addr.(*net.IPNet)
if !ok {
// Not an IP interface
continue
}
if addr.IP.To4() != nil {
// Skip IPv4 addresses
continue
}
fmt.Fprintf(tw, "%s\t%s\t%s\t%s\n",
iface.Name, addr.String(), addr.IP, addr.Mask)
}
}
tw.Flush()
}
For my local machine the output is:
lo ::1/128 ::1 ffffffffffffffffffffffffffffffff
enp2s0 fe80::52e5:49ff:fe3b:107a/64 fe80::52e5:49ff:fe3b:107a ffffffffffffffff0000000000000000
docker0 fe80::42:afff:fedb:7389/64 fe80::42:afff:fedb:7389 ffffffffffffffff0000000000000000
tun0 fe80::f22c:2d3b:a5a0:1b61/64 fe80::f22c:2d3b:a5a0:1b61 ffffffffffffffff0000000000000000
vethd176f0c fe80::1cc1:65ff:fe39:feff/64 fe80::1cc1:65ff:fe39:feff ffffffffffffffff0000000000000000
Note that these addresses are not necessarily reachable from the Internet. This all depends on how the routing of the hoster works. In any kind of cloud setup, you are almost always better off querying the providers APIs.
To list all /64 subnets in a particular /56 subnet, you have to leave the 56 upper bits of the subnet address as they are and permute the following 64-56 = 8 bits (which happens to be the eigth byte):
package main
import (
"fmt"
"net"
)
func main() {
_, subnet, _ := net.ParseCIDR("2001:db8::/56")
fmt.Println(subnet)
subnet.Mask = net.CIDRMask(64, 128) // change mask to /64
for i := 0; i <= 0xff; i++ {
subnet.IP[7] = byte(i) // permute the 8th byte
fmt.Println("\t", subnet)
}
// Output:
// 2001:db8::/56
// 2001:db8::/64
// 2001:db8:0:1::/64
// 2001:db8:0:2::/64
// 2001:db8:0:3::/64
// 2001:db8:0:4::/64
// 2001:db8:0:5::/64
// 2001:db8:0:6::/64
// 2001:db8:0:7::/64
// 2001:db8:0:8::/64
// [...]
}
Regarding the second part of your question, "How do I transfer this range ^ into a slice (array) of ipv6 addresses"
The IPAddress Go library can do this with polymorphic code that works with both IPv4 and IPv6 addresses and all prefix lengths. Repository here. Disclaimer: I am the project manager.
addrStr := "2001:db8::/56"
addr := ipaddr.NewIPAddressString(addrStr).GetAddress()
addrAdjusted := addr.SetPrefixLen(64) // adjust prefix
iterator := addrAdjusted.PrefixIterator()
var blocks []*ipaddr.IPAddress
for iterator.HasNext() {
blocks = append(blocks, iterator.Next())
}
// print the details
fmt.Println("first and last blocks are",
addrAdjusted.GetLower().ToPrefixBlock(), "and",
addrAdjusted.GetUpper().ToPrefixBlock())
fmt.Print("list: ")
for i, addr := range blocks {
if i < 3 || len(blocks)-i <= 3 {
if i > 0 {
fmt.Print(", ")
}
fmt.Print(addr)
} else if i == 3 {
fmt.Print(", ...")
}
}
Output:
first and last blocks are 2001:db8::/64 and 2001:db8:0:ff::/64
list: 2001:db8::/64, 2001:db8:0:1::/64, 2001:db8:0:2::/64, ..., 2001:db8:0:fd::/64, 2001:db8:0:fe::/64, 2001:db8:0:ff::/64

Why the & operator on struct doesn't return a digital address?

I just started to learn the golang.
I found the & operator behaves differently for simple type and struct.
For simple type, & returns an address.
For struct, it returns something else.
Code:
package main
import "fmt"
type person struct {
name string
age int
}
func main() {
s1 := "abc"
fmt.Println("s1 address =", &s1)
s2 := person{"Sam", 55}
fmt.Println("s2 address = ", &s2)
}
Output:
[ `hello` | done: 79.0079ms ]
s1 address = 0xc04203c1e0
s2 address = &{Sam 55} <======== What's this? And why not some address like above?
Again, is this design a have-to or a happen-to?
The unitary operator & behaves the same for builtin types and structs, it's used to get the memory address of a var. In this case we'll see &{Sam 55} because Go always checks by default if the parameter in fmt.Println() is a struct or a pointer to struct and in that case will try to print each field of the struct for debugging purposes, but if you want to see a pointer you can use fmt.Printf() with %p, like this:
func main() {
s1 := "abc"
fmt.Println("s1 address =", &s1)
s2 := person{"Sam", 55}
fmt.Println("s2 as pointer =", &s2)
fmt.Printf("s2 address = %p value with fields %+v", &s2, s2)
}
Bonus: you can use %+v to print field names and values
https://play.golang.org/p/p7OVRu8YWB

Memory address for struct not visible

In Go, I was confused about why the memory address for variables like int can be obtained but not for structs. As an example:
package main
import "fmt"
func main() {
stud1 := stud{"name1", "school1"}
a:=10
fmt.Println("&a is:", &a)
fmt.Println("&stud1 is:",&stud1)
}
output is:
&a is: 0x20818a220
&stud1 is: &{name1 school1}
Why is &a giving the memory address, however &stud1 not giving the exact memory location. I don't have any intention of using the memory address but just was curious about the different behavior.
the fmt package uses reflection to print out values, and there is a specific case to print a pointer to a struct as &{Field Value}.
If you want to see the memory address, use the pointer formatting verb %p.
fmt.Printf("&stud is: %p\n", &stud)

Resources