How can I get all addresses and masks from local interfaces in golang?
I need the actual network mask configured along with every IP address.
This code does not show the network masks in Windows 7:
package main
import (
"fmt"
"log"
"net"
)
func localAddresses() {
ifaces, err := net.Interfaces()
if err != nil {
log.Print(fmt.Errorf("localAddresses: %v\n", err.Error()))
return
}
for _, i := range ifaces {
addrs, err := i.Addrs()
if err != nil {
log.Print(fmt.Errorf("localAddresses: %v\n", err.Error()))
continue
}
for _, a := range addrs {
log.Printf("%v %v\n", i.Name, a)
}
}
}
func main() {
localAddresses()
}
UPDATE: This issue has been fixed in Go: https://github.com/golang/go/issues/5395
There are multiply types of addresses that a net.Interface might have. The Addr is just an interface which may contain a net.IPAddr. But with a type assertion or type switch you can access the actual address type:
package main
import (
"fmt"
"net"
)
func localAddresses() {
ifaces, err := net.Interfaces()
if err != nil {
fmt.Print(fmt.Errorf("localAddresses: %+v\n", err.Error()))
return
}
for _, i := range ifaces {
addrs, err := i.Addrs()
if err != nil {
fmt.Print(fmt.Errorf("localAddresses: %+v\n", err.Error()))
continue
}
for _, a := range addrs {
switch v := a.(type) {
case *net.IPAddr:
fmt.Printf("%v : %s (%s)\n", i.Name, v, v.IP.DefaultMask())
}
}
}
}
func main() {
localAddresses()
}
Edit
Unfortunately the net package doesn't return the Mask of the address. So, you will have to do the low level syscalls that the net package does. The code below is an example, but parsing of the ip and the mask still needs to be done:
package main
import (
"fmt"
"net"
"os"
"syscall"
"unsafe"
)
func getAdapterList() (*syscall.IpAdapterInfo, error) {
b := make([]byte, 1000)
l := uint32(len(b))
a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
// TODO(mikio): GetAdaptersInfo returns IP_ADAPTER_INFO that
// contains IPv4 address list only. We should use another API
// for fetching IPv6 stuff from the kernel.
err := syscall.GetAdaptersInfo(a, &l)
if err == syscall.ERROR_BUFFER_OVERFLOW {
b = make([]byte, l)
a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
err = syscall.GetAdaptersInfo(a, &l)
}
if err != nil {
return nil, os.NewSyscallError("GetAdaptersInfo", err)
}
return a, nil
}
func localAddresses() error {
ifaces, err := net.Interfaces()
if err != nil {
return err
}
aList, err := getAdapterList()
if err != nil {
return err
}
for _, ifi := range ifaces {
for ai := aList; ai != nil; ai = ai.Next {
index := ai.Index
if ifi.Index == int(index) {
ipl := &ai.IpAddressList
for ; ipl != nil; ipl = ipl.Next {
fmt.Printf("%s: %s (%s)\n", ifi.Name, ipl.IpAddress, ipl.IpMask)
}
}
}
}
return err
}
func main() {
err := localAddresses()
if err != nil {
panic(err)
}
}
Some code shamelessly borrowed from interface_windows.go. Even comments are left intact
I'm modifying #ANisus answer and get all interfaces & masks (tested on Windows 10 & WSL in it (Microsoft Ubuntu 16.04.5 LTS):
package main
import (
"fmt"
"net"
)
func localAddresses() {
ifaces, err := net.Interfaces()
if err != nil {
fmt.Print(fmt.Errorf("localAddresses: %+v\n", err.Error()))
return
}
for _, i := range ifaces {
addrs, err := i.Addrs()
if err != nil {
fmt.Print(fmt.Errorf("localAddresses: %+v\n", err.Error()))
continue
}
for _, a := range addrs {
switch v := a.(type) {
case *net.IPAddr:
fmt.Printf("%v : %s (%s)\n", i.Name, v, v.IP.DefaultMask())
case *net.IPNet:
fmt.Printf("%v : %s [%v/%v]\n", i.Name, v, v.IP, v.Mask)
}
}
}
}
func main() {
localAddresses()
}
This should give you the ipnet you're looking for.
ip, ipnet, err := net.ParseCIDR(a.String())
I know this post for Windows 7, but if you use Mac OS X hope this could help you.
Just Call GetNetMask("en0")
func GetNetMask(deviceName string) string {
switch runtime.GOOS {
case "darwin":
cmd := exec.Command("ipconfig", "getoption", deviceName, "subnet_mask")
out, err := cmd.CombinedOutput()
if err != nil {
return ""
}
nm := strings.Replace(string(out), "\n", "", -1)
log.Println("netmask=", nm, " OS=", runtime.GOOS)
return nm
default:
return ""
}
return ""
}
Related
I have a function which should get the page name and print it, for example, if the URL is http://localhost:8080/login.html the function should print login.html
If you only need to parse the URL you can use below:
package main
import (
"fmt"
"net/url"
)
func main() {
URL := "http://localhost:8080/login.html"
name, err := getPageName(URL)
if err != nil {
panic(err)
}
fmt.Println(name)
}
func getPageName(URL string) (string, error) {
u, err := url.Parse(URL)
if err != nil {
return "", err
}
return u.Path[1:], nil // To remove initial /
}
If you need to get page's HTML and parse the title from <head> you can use go-query
package main
import (
"fmt"
"log"
"net/http"
"github.com/PuerkitoBio/goquery"
)
func main() {
URL := "https://stackoverflow.com"
res, err := http.Get(URL)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
}
// Load the HTML document
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
log.Fatal(err)
}
title := doc.Find("title").Text()
fmt.Println(title)
}
You can do this to get the page name:
func GetPageName(address string) (string, error) {
u, err := url.Parse(address)
if err != nil {
return "", err
}
params := strings.Split(u.Path, "/")
// Index page
if len(params) == 0 || (len(params) == 1 && params[0] == "") {
return "", nil
} else {
pageName := params[len(params)-1]
// Has trailing slash
if pageName == "" {
return params[len(params)-2], nil
}
// Doesn't have trailing slash
return pageName, nil
}
}
If the url address is the index page address, for example host.com or host.com/ it returns an empty string.
Otherwise returns the page name for the given url. For example test for host.com/test and host.com/test/ and host.com/path/test.
The hope is to quickly parse a very large number of similar URLs (only one 'id' element differs from one to the next) and dump the response body into a channel that will later be queried by the main function and used to build a text file.
Inside the getpageCanal() function, the body seems to be ok, but after that, I don't understand why the channel doesn't properly load the body string.
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
)
func main() {
initial := "https://www1.medion.de/downloads/index.pl?op=detail&id="
ending := "&type=treiber&lang=uk"
links := []string{}
os.Remove("dump.txt")
dumpFile, _ := os.Create("dump.txt")
c := make(chan string)
for i := 16000; i < 16004; i++ {
links = append(links, initial+fmt.Sprint(i)+ending)
}
fmt.Println(links[0])
for _, link := range links {
//the hope is to make this a go routine, but first I need to just make it work
getpageCanal(c, link)
}
for el := range c {
fmt.Println(el)
n, err := dumpFile.WriteString(el)
if err != nil {
fmt.Println(err)
}
if n == 0 {
fmt.Println(" nothing written in main")
}
}
}
func getpageCanal(canal chan string, url string) {
defer close(canal)
page, err := http.Get(url)
if err != nil {
fmt.Println("you done fucked up, boy")
}
content, er2 := ioutil.ReadAll(page.Body)
//fmt.Println(content)
if er2 != nil {
fmt.Println(er2)
}
canal <- string(content)
}
After modifying the code as instructed by the first comments (not closing the channel after each call and making the call to the worker function a go routine) I will now provide you with a working version:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
)
func main() {
initial := "https://www1.medion.de/downloads/index.pl?op=detail&id="
ending := "&type=treiber&lang=uk"
links := []string{}
os.Remove("dump.txt")
dumpFile, _ := os.Create("dump.txt")
c := make(chan string)
for i := 16000; i < 16004; i++ {
links = append(links, initial+fmt.Sprint(i)+ending)
}
fmt.Println(links[0])
for _, link := range links {
go getpageCanal(c, link)
}
for el := range c {
fmt.Println(el)
n, err := dumpFile.WriteString(el)
if err != nil {
fmt.Println(err)
}
if n == 0 {
fmt.Println(" nothing written in main")
}
}
}
func getpageCanal(canal chan string, url string) {
//defer close(canal)
page, err := http.Get(url)
if err != nil {
fmt.Println("you done fucked up, boy")
}
content, er2 := ioutil.ReadAll(page.Body)
//fmt.Println(content)
if er2 != nil {
fmt.Println(er2)
}
canal <- string(content)
}
I try to convert a make(map[string]string) into a yaml like that:
Yaml Output desire:
items:
keys1:value1
keys2:value2
keys3:value3
keys4:value4
The keys,values are this listKey map of string. J = string = {"key1":"value1","key2":"value2" }
type Items struct {
items string
ItemsValues map[string][]string
}
func ConvertToYelm(j string){
y := Items{}
var dataJson map[string]string
err := json.Unmarshal([]byte(j), &dataJson)
if err != nil {
fmt.Println(err)
return
}
listKey := make(map[string]string)
for k := range dataJson{
listKey[k] = k
}
yelm, err := yaml.Marshal(listKey)
if err != nil {
fmt.Println(err)
return
}
err = yaml.Unmarshal(yelm, Items)
if err != nil {
fmt.Println(err)
return
}
yeml2, err := yaml.Marshal(&yelm)
fmt.Printf ("%s", string(yeml2))
To be honest, I'm a little bit lost here, thank you for the help
To get the exact YAML from your post:
items:
keys1:value1
keys2:value2
keys3:value3
keys4:value4
You can do this (Go Playground):
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
type ItemsStruct struct {
Items map[string]string `yaml:"items"`
}
func main() {
itms := &ItemsStruct{Items: map[string]string{
"keys1": "value1",
"keys2": "value2",
"keys3": "value3",
"keys4": "value4"}}
yamlBytes, err := yaml.Marshal(itms)
if err != nil {
//handle error
}
fmt.Println(string(yamlBytes))
}
And just to add, I see your code is decoding this JSON {"key1":"value1", "key2":"value2", ... } and then encoding it as YAML in your specified format. Here is the Go Playground for that.
Im using a class to encrypt/decrypt strings in PHP.
How could I encrypt/decrypt the strings in Go?
The PHP class:
class Crypto {
private $encryptKey = 'xxxxxxxxxxxxxxxx';
private $iv = 'xxxxxxxxxxxxxxxx';
private $blocksize = 16;
public function decrypt($data)
{
return $this->unpad(mcrypt_decrypt(MCRYPT_RIJNDAEL_128,
$this->encryptKey,
hex2bin($data),
MCRYPT_MODE_CBC, $this->iv), $this->blocksize);
}
public function encrypt($data)
{
//don't use default php padding which is '\0'
$pad = $this->blocksize - (strlen($data) % $this->blocksize);
$data = $data . str_repeat(chr($pad), $pad);
return bin2hex(mcrypt_encrypt(MCRYPT_RIJNDAEL_128,
$this->encryptKey,
$data, MCRYPT_MODE_CBC, $this->iv));
}
private function unpad($str, $blocksize)
{
$len = strlen($str);
$pad = ord($str[$len - 1]);
if ($pad && $pad <= $blocksize) {
if (substr($str, -$pad) === str_repeat(chr($pad), $pad)) {
return substr($str, 0, $len - $pad);
}
}
return $str;
}
}
What to be able to encrypt/decrypt same string in both PHP and Go.
Here is an example:
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/base64"
"errors"
"fmt"
"io"
"log"
)
func main() {
key := []byte("xxxxxxxxxxxxxxxx") // 32 bytes
plaintext := []byte("TEST")
fmt.Printf("%s\n", plaintext)
ciphertext, err := encrypt(key, plaintext)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%0x\n", ciphertext)
result, err := decrypt(key, ciphertext)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", result)
}
func encrypt(key, text []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
b := base64.StdEncoding.EncodeToString(text)
ciphertext := make([]byte, aes.BlockSize+len(b))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
cfb := cipher.NewCFBEncrypter(block, iv)
cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
return ciphertext, nil
}
func decrypt(key, text []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(text) < aes.BlockSize {
return nil, errors.New("ciphertext too short")
}
iv := text[:aes.BlockSize]
text = text[aes.BlockSize:]
cfb := cipher.NewCFBDecrypter(block, iv)
cfb.XORKeyStream(text, text)
data, err := base64.StdEncoding.DecodeString(string(text))
if err != nil {
return nil, err
}
return data, nil
}
Mostly borrowed and adapted from: https://golang.org/src/crypto/cipher/example_test.go
// Input => TEST
// Output => 13360adba03733e11dd2702de441ff8bbb90676ad762fc83
UPDATE
To use a string as a parameter for decode function, you need to convert the string to byte using hex.Decodestring
data, _ := hex.DecodeString("1d6f12d3aa2353b23c6012dbc85816632129363d58a76063")
result, err := decrypt(key, data)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", result)
Do not forget to include "encoding/hex" into package list.
i'm trying to track the upload progress in GOLANG, that's what i got at the moment
func Upload(w http.ResponseWriter, req *http.Request) {
mr, err := req.MultipartReader()
if err != nil {
return
}
for {
// var part *multipart.Part
part, err := mr.NextPart()
mr.partsRead
if err == io.EOF {
break
}
println(part)
}
}
This will work, a stream to calc the bytes read and the total progress you need to point the stream somewhere, in this code example I pointed it to a file.
func Upload(w http.ResponseWriter, req *http.Request) {
mr, err := req.MultipartReader()
if err != nil {
return
}
length := req.ContentLength
for {
part, err := mr.NextPart()
if err == io.EOF {
break
}
var read int64
var p float32
dst, err := os.OpenFile("dstfile", os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return
}
for {
buffer := make([]byte, 100000)
cBytes, err := part.Read(buffer)
if err == io.EOF {
break
}
read = read + int64(cBytes)
//fmt.Printf("read: %v \n",read )
p = float32(read) / float32(length) *100
fmt.Printf("progress: %v \n",p )
dst.Write(buffer[0:cBytes])
}
}
}