func getLocalIP() ([]string, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return nil, err
}
IPs := make([]string, 0)
for _, a := range addrs {
if ipNet, ok := a.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
IPs = append(IPs, ipNet.IP.To4().String())
}
}
}
return IPs, nil
}
func TestGetLocalIP() {
addrs, _ := getLocalIP()
for _, a := range addrs {
fmt.Println(a)
}
}
I used this,but it give me a list of ip address.
I just want to get my wifi local address,how to do that?
You need to know at least one of two pieces of information going in:
the name of the correct interface (typically en0 on a Mac, e.g., but YMMV)
the address for your wireless network, including the length of the mask - something like 192.168.0.0/16 or 192.168.0.0/24 is pretty common, but you'll have to figure this out ahead of time.
If you only know the interface name:
ifs, _ := net.Interfaces()
for _, ifi := range ifs {
if ifi.Name == "en0" { // Or whatever other filter you want
addrs, _ := ifi.Addresses()
for _, a := range addrs {
// Filter to get the one you want, typically unicast IP4
}
}
}
Still simpler:
if, _ := net.InterfaceByName("en0")
addrs, _ := if.Addresses()
for _, a := range addrs {
// As before, filter for the address you want
}
If you know the network address for your wireless network
// Loop over interfaces, get addrs, then loop over addresses and get IPs for those that have them
if ip.Mask(net.CIDRMask(16, 32)) == myNetworkAddress {
// The interface you got this IP from is probably your wifi interface
}
Which method to choose
Depending on the interface having a specific name is generally not going to be portable. So while my assumption was that you were just trying to get this working on your own workstation, if this is for something which needs to run across multiple hosts, you may need to start off at least with matching against the correct network address. There are other tricks as well - if you know e.g. that you are going to be running in a server farm in which every host has a NIC from manufacturer XXX, you can look up the MAC address and see if it comes from that manufacturer - you can try this out here. You can use other filters as well, but those are going to be pretty specific to your individual use case.
Related
i have a file. it has some ip
1.1.1.0/24
1.1.2.0/24
2.2.1.0/24
2.2.2.0/24
i read this file to slice, and used *(*string)(unsafe.Pointer(&b)) to parse []byte to string, but is doesn't work
func TestInitIpRangeFromFile(t *testing.T) {
filepath := "/tmp/test"
file, err := os.Open(filepath)
if err != nil {
t.Errorf("failed to open ip range file:%s, err:%s", filepath, err)
}
reader := bufio.NewReader(file)
ranges := make([]string, 0)
for {
ip, _, err := reader.ReadLine()
if err != nil {
if err == io.EOF {
break
}
logger.Fatalf("failed to read ip range file, err:%s", err)
}
t.Logf("ip:%s", *(*string)(unsafe.Pointer(&ip)))
ranges = append(ranges, *(*string)(unsafe.Pointer(&ip)))
}
t.Logf("%v", ranges)
}
result:
task_test.go:71: ip:1.1.1.0/24
task_test.go:71: ip:1.1.2.0/24
task_test.go:71: ip:2.2.1.0/24
task_test.go:71: ip:2.2.2.0/24
task_test.go:75: [2.2.2.0/24 1.1.2.0/24 2.2.1.0/24 2.2.2.0/24]
why 1.1.1.0/24 changed to 2.2.2.0/24 ?
change
*(*string)(unsafe.Pointer(&ip))
to string(ip) it works
So, while reinterpreting a slice-header as a string-header the way you did is absolutely bonkers and has no guarantee whatsoever of working correctly, it's only indirectly the cause of your problem.
The real problem is that you're retaining a pointer to the return value of bufio/Reader.ReadLine(), but the docs for that method say "The returned buffer is only valid until the next call to ReadLine." Which means that the reader is free to reuse that memory later on, and that's what's happening.
When you do the cast in the proper way, string(ip), Go copies the contents of the buffer into the newly-created string, which remains valid in the future. But when you type-pun the slice into a string, you keep the exact same pointer, which stops working as soon as the reader refills its buffer.
If you decided to do the pointer trickery as a performance hack to avoid copying and allocation... too bad. The reader interface is going to force you to copy the data out anyway, and since it does, you should just use string().
I'm looking for a way to convert a netmask string into CIDR notation in Go.
For instance, "255.255.255.0" -> "/24"
I'm currently obtaining an IP address and the net mask string with the below logic, which may just be complicating things.
I've been perusing the net library trying to see if there is a different function to use to accomplish what I'd like, which is really just a IP address in CIDR notation:
192.168.1.2/24
var mgmtInterface *net.Interface
var err error
mgmtInterface, err = net.InterfaceByName("eth0")
if err != nil {
log.Println("Unable to find interface eth0, trying en0")
mgmtInterface, err = net.InterfaceByName("en0")
}
addrs, err := mgmtInterface.Addrs()
if err != nil {
log.Println("interface has no address")
}
for _, addr := range addrs {
var ip net.IP
var mask net.IPMask
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
mask = v.Mask
case *net.IPAddr:
ip = v.IP
mask = ip.DefaultMask()
}
if ip == nil {
continue
}
ip = ip.To4()
if ip == nil {
continue
}
// create the netmask
cleanMask := fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3])
}
This isn't very obvious at first, but:
addr := ip.To4()
sz, _ := net.IPV4Mask(addr[0], addr[1], addr[2], addr[3]).Size()
I'm not aware about existense of such function but it's easy to create one.
CIDR notation is just a count of set bits in netmask.
So, crude solution could be:
func cidr(netmask string) int {
var mask uint32
for idx, dotpart := range strings.Split(netmask, ".") {
part, _ := strconv.Atoi(dotpart)
mask = mask | uint32(part) << uint32(24-idx*8)
}
return len(fmt.Sprintf("%b", mask))
}
This is straightforward using the IPAddress Go library. Note that this code works equally well with both IPv4 and IPv6. Disclaimer: I am the project manager.
import (
"fmt"
"github.com/seancfoley/ipaddress-go/ipaddr"
)
func main() {
maskStr := "255.255.255.0"
pref := ipaddr.NewIPAddressString(maskStr).GetAddress().
GetBlockMaskPrefixLen(true)
fmt.Printf("prefix length for %s is %d", maskStr, pref.Len())
}
Output:
prefix length for 255.255.255.0 is 24
I'm very new to golang, I have some experience with python but not on this level per say. I am creating an application that's called "digall", making it easy for a user to see active dns-records when checking a domain name.
In the application I am using LookupSRV, which I seem to have some issues with:
func srvRecord(query string) {
service := "sipfederationtls"
protocol:= "tcp"
fmt.Printf("\n[+] SRV Record(s)\n")
//srvMap := ["sipfederationtls", "autodiscover", "VLMCS"]
cname, addresses, err := net.LookupSRV(service, protocol, query)
if err != nil {
fmt.Printf("[!] This feature is currently under development, thus not ready yet.\n")
}
fmt.Printf("cname : %s \n", cname)
for i := 0; i < len(addresses); i++ {
fmt.Printf("addrs[%d].Target : %s \n", i, addresses[i].Target)
fmt.Printf("addrs[%d].Port : %d \n", i, addresses[i].Port)
fmt.Printf("addrs[%d].Priority : %d \n", i, addresses[i].Priority)
fmt.Printf("addrs[%d].Weight : %d \n", i, addresses[i].Weight)
}
}
As you can see the variable "service" serves as the prefix of the SRV record. My only problem is that i want to check multiple prefixes of this record, namely "sipfederationtls", "autodiscover" and "VLMCS".
What I am asking is; How to i make this function swift through these prefixes and return the ones that work? (the ones that error out will be handled by err by my fantastic error message)
I am aware that this is a noob question, and like I said I am very new to golang. I would appreciate any tips you guys could give me.
Here is the full source of the application: http://dpaste.com/3X24ZYR
Thank you.
You can't query multiple services at once using LookupSRV method, as you can't use dig for querying several services at once.
You better create a slice of the services' names:
services := [...]string{"service1", "service2", "service3")
And then iterate over it and call LookupSRV for each service:
for _, service := range services {
cname , addrs, err := net.LookupSRV(service, "tcp", "your.domain.name")
// error handlling
}
Also when iterating over the lookup result, it is better to use the range keyword:
for _, record := range addrs {
fmt.Printf("Target: %s:%d\n", record.Target, record.Port)
}
Newbie question:
I want to print various variables of a library (is that the correct name? reflect.TypeOf(servers) gives []lib.Server)
I want to do something like this, but this obviously does not work:
servers, err := GetClient().GetServers() //call to external API
serverVariables := []string{}
serverVariables = append(serverVariables, "Name")
serverVariables = append(serverVariables, "IPAddress")
for _, server := range servers {
for _,element := range serverVariables {
fmt.Println(server.element)
}
}
What I already can do is the following (but I want to do it using the above approach):
servers, err := GetClient().GetServers() //call to external API
for _, server := range servers {
fmt.Println(server.Name)
fmt.Println(server.IPAddress)
}
giving the following output:
ServerNameOne
192.168.0.1
ServerNameTwo
192.168.0.2
Reflection is what you probably want to use:
for _, server := range servers {
v := reflect.ValueOf(server)
for _, element := range serverVariables {
fmt.Println(v.FieldByName(element))
}
}
You should also change serverVariables initialization to be serverVariables := []string{}
Playground example: https://play.golang.org/p/s_kzIJ7-B7
It seems to me that you have experience in some dynamic language like Python or JavaScript. Go is compiled and strongly typed. Besides reflection being slower, when using it compiler can't help you with finding basic errors in your code and what is most important you lose type of the accessed variable.
More info on http://blog.golang.org/laws-of-reflection
So I strongly recommend you to keep your current approach:
for _, server := range servers {
fmt.Println(server.Name)
fmt.Println(server.IPAddress)
}
I've bound several vpn on the server which is ppp0 ~ ppp4.
Now comes the problem.I want to start 5 progresses each one use the difference network interface.
proc0 -> ppp0
proc1 -> ppp1
proc2 -> ppp2
proc3 -> ppp3
proc4 -> ppp4
I now how to do this with c language.Just use setsockopt with parameter SO_BINDTODEVICE.
But how to do this with net package in golang?
You probably want net.Interfaces() to get a slice of net.Interface() representing the network interfaces on your system, or, as you know the interface names, you can use net.InterfaceByName() to get a particular net.Interface.
ppp0, err := net.InterfaceByName("ppp0")
You can then call Interface.Addrs() on the returned net.Interface and get the interface's IP address(es).
addrs, err := ppp0.Addrs()
You can then use the desired address in the rest of your code (probably using net.ListenIP or net.DialIP.
addr, err := net.ResolveIPAddr("ip4", addrs[0])
// check err
conn, err := net.ListenIP("ip4:pptp", addr)
// check err, then do stuff with conn
Regarding doing this for more than one interface concurrently, you can launch a goroutine for each listener / interface, and move the traffic over channels, but this really depends on what you want to do. (are you just logging the data, sending the data, modifying the data etc.)
The dialer's LocalAddr doesn't work for ppp interfaces, we should set the SOL_SOCKET flag to socket using setsockopt, for go 1.11+ you can create a dialer like this
dialer := net.Dialer{
Control: func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
err := syscall.SetsockoptString(int(fd), syscall.SOL_SOCKET, 25, "ppp0")
if err != nil {
log.Printf("control: %s", err)
return
}
})
},
}
// use the dialer