looking to send an ipv4 address across in 4 bytes, and ipv6 address in 16 bytes - What's similar to inet_pton() in go?
struct sockaddr_in sa;
char str[INET_ADDRSTRLEN];
inet_pton(AF_INET, "192.0.2.33", &(sa.sin_addr));
struct sockaddr_in6 sa;
char str[INET6_ADDRSTRLEN];
inet_pton(AF_INET6, "2001:db8:8714:3a90::12", &(sa.sin6_addr));
I know of https://play.golang.org/p/jn8t7zJzT5v - that is looking complicated for IPV6 addresses though.
Thanks!
net.ParseIP() will take an IPv4 or IPv6 formatted string and return a net.IP containing the IP address.
The net.IP is what you'll need to feed to most other Go functions, such as to make a connection to the host.
Note that unlike most Go functions which return an error, net.ParseIP() simply returns nil if the string could not be parsed into an IP address.
https://play.golang.org/p/Cgsrgth7JKY
Either you can use the net package:
`
a := net.ParseIP("127.0.0.1")
fmt.Printf("%b %s", net.IP.To4(a))
`
https://play.golang.org/p/KzqYpk9OBh8
Or, you can split the IP and convert each value into an integer using strconv.Atoi(), and thereafter convert each integer into byte()
`
ipString := "127.0.0.1"
octets := strings.Split(ipString, ".")
octet0, _ := strconv.Atoi(octets[0])
octet1, _ := strconv.Atoi(octets[1])
octet2, _ := strconv.Atoi(octets[2])
octet3, _ := strconv.Atoi(octets[3])
b := [4]byte{byte(octet0),byte(octet1),byte(octet2),byte(octet3)}
fmt.Printf("%s has 4-byte representation of %b\n", ipString, b)
`
https://play.golang.org/p/2F3bC0df9wB
Related
SSRF vul should forbidden local ip request.
How did go net.LookupIP work with Base 8 (octal )?
#go code
net.LookupIP("0177.0.0.01") // NOT_OK 0177.0.0.01
net.LookupIP("0266.075.0310.07") // OK 182.61.200.7
#shell
ping 0177.0.0.01 //OK 127.0.0.1
ping 0266.075.0310.07 // OK 182.61.200.7
input http:address to chrome is the same as ping ,but go not stablize
debug-snapshot-img net.LookupIP("0177.0.0.01") Has Not Decode Base8
debug-snapshot-img ping 0177.0.0.01 in shell Has Decode Base8
debug-snapshot-img net.LookupIP("0266.075.0310.07") Has Decode Base8
The problem
I think you cannot for a simple reason: that A.B.C.D format of IPv4 addresses is called "dot-decimal" (or "dotted-decimal") for a reason: the numbers representing the octets of an address are in the decimal format, and no "special modifiers"—such as 0x, 0, 0o etc—to make it "not decimal" are allowed.
I'm inclined to think that the fact ping is OK to parse the address with some octets in octal is some weird artefact of its implementation; for instance, it also parses hexadecimal:
$ ping 0xAB.0.0.0x01
PING 0xAB.0.0.0x01 (171.0.0.1) 56(84) bytes of data.
^C
Also note that there's no such thing as "the standard ping tool": any OS can have any implementation of it; for instance, ping available on Windows definitely shares no source code with ping available on a typical GNU/Linux-based OS, and that one is probably different from ping implementations available on systems tracing their heritage to *BSD.
To further illustrate my point, consider host:
$ host -t PTR 0177.0.0.01
Host 0177.0.0.01 not found: 3(NXDOMAIN)
This tool, as you can see, failed to cope with the leading 0s.
So, I think it's sensible to assume that the fact net.LookupIP (and net.ParseIP for that matter) definitely cannot be blamed for not supporting "octals" when they parse the dotted-decimal representation of an IPv4 address.
Possible solutions
Possible solutions depend on what really you're after.
If you have to accept IP addresses as strings in such a "dotted-not-so-decimal" format, I'd propose to write a simplistic custom parser which would "preprocess" the strings before calling net.LookupIP on them.
Such a preprocessor would split the string and try to parse each octet, then assemble the address back.
Go has strconv.ParseInt in its standard library, which accepts the "base" argument telling it which base the digits forming the string representation to parse are, and if you pass 0 as the base, the function uses the usual heuristics to guess the base; in particular, the leading 0 signalizes the base 8—just as you'd want it to.
So, we could roll something like this:
package main
import (
"errors"
"fmt"
"net"
"strconv"
"strings"
)
func normalizeIPv4Addr(s string) (string, error) {
parts := strings.SplitN(s, ".", 4)
if len(parts) != 4 || strings.IndexByte(parts[3], '.') != -1 {
return "", errors.New("invalid IPv4 address: invalid number of octets")
}
var dst [4]byte
for i, p := range parts {
n, err := strconv.ParseInt(p, 0, 8)
if err != nil {
return "", fmt.Errorf("invalid IPv4 address: invalid octet %d: %s", i+1, err)
}
if n < 0 || 255 < n {
return "", fmt.Errorf("invalid IPv4 address: invalid octet %d: out of range", i+1)
}
dst[i] = byte(n)
}
return net.IP(dst[:]).String(), nil
}
func main() {
fmt.Println(normalizeIPv4Addr("0177.0.0.01"))
}
Playground.
I have this string representing hex:
00000000ff00ff00000900000600020a
I'm trying to convert it to IPv6 with net package
the result I'm expecting is(big endian):
20a:600::9:ff00:ff00::
I tried this:
ip := "00000000ff00ff00000900000600020a"
res := make(net.IP, net.IPv6len)
var err error
res,err = hex.DecodeString(ip)
if err != nil {
fmt.Println("error")
}
for i := 0; i < 16/2; i++ {
res[i], res[16-1-i] = res[16-1-i], res[i]
}
fmt.Println(res.String())
but I'm getting this:
a02:6:0:900:ff:ff::
Thanks!
Your question is not clear what is being reversed, when you compare. Typically, when switching endianness, you reverse the bytes, but that is not what you seem to want here.
In any case, here is code to reverse in many different ways, using the IPAddress Go library. Disclaimer: I am the project manager.
str := "00000000ff00ff00000900000600020a"
ipAddr := ipaddr.NewIPAddressString(str).GetAddress()
reversedAddr, _ := ipAddr.ReverseBytes()
reverseEachSegment := ipAddr.ReverseSegments()
reverseBitsEachByte, _ := ipAddr.ReverseBits(true)
reverseBits, _ := ipAddr.ReverseBits(false)
fmt.Println("original", ipAddr)
fmt.Println("bytes reversed", reversedAddr)
fmt.Println("bytes reversed in each segment", reverseEachSegment)
fmt.Println("bits reversed in each byte", reverseBitsEachByte)
fmt.Println("bits reversed", reverseBits)
Output:
original ::ff00:ff00:9:0:600:20a
bytes reversed a02:6:0:900:ff:ff::
bytes reversed in each segment 20a:600:0:9:ff00:ff00::
bits reversed in each byte ::ff00:ff00:90:0:6000:4050
bits reversed 5040:60:0:9000:ff:ff::
For some reason it is reversing the bytes in each segment that gets you what you expect, although that is not switching endianness.
Try this:
for i := 0; i < 16/2; i += 2 {
res[i], res[16-2-i] = res[16-2-i], res[i]
res[i+1], res[16-1-i] = res[16-1-i], res[i+1]
}
bytes goes in pair, so you need to flip both at time
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
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
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