windows encrypted rdp passwords in golang - winapi

like http://play.golang.org/p/fD7mx2k4Yc
window rdp password encrypted http://www.remkoweijnen.nl/blog/2007/10/18/how-rdp-passwords-are-encrypted/
package main
import (
"fmt"
"log"
"syscall"
"unsafe"
)
const (
CRYPTPROTECT_UI_FORBIDDEN = 0x1
)
var (
dllcrypt32 = syscall.NewLazyDLL("Crypt32.dll")
dllkernel32 = syscall.NewLazyDLL("Kernel32.dll")
procEncryptData = dllcrypt32.NewProc("CryptProtectData")
procDecryptData = dllcrypt32.NewProc("CryptUnprotectData")
procLocalFree = dllkernel32.NewProc("LocalFree")
)
type DATA_BLOB struct {
cbData uint32
pbData *byte
}
func NewBlob(d []byte) *DATA_BLOB {
if len(d) == 0 {
return &DATA_BLOB{}
}
return &DATA_BLOB{
pbData: &d[0],
cbData: uint32(len(d)),
}
}
func (b *DATA_BLOB) ToByteArray() []byte {
d := make([]byte, b.cbData)
copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
return d
}
func Encrypt(data []byte) ([]byte, error) {
var outblob DATA_BLOB
r, _, err := procEncryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outblob)))
if r == 0 {
return nil, err
}
defer procLocalFree.Call(uintptr(unsafe.Pointer(outblob.pbData)))
return outblob.ToByteArray(), nil
}
func Decrypt(data []byte) ([]byte, error) {
var outblob DATA_BLOB
r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outblob)))
if r == 0 {
return nil, err
}
defer procLocalFree.Call(uintptr(unsafe.Pointer(outblob.pbData)))
return outblob.ToByteArray(), nil
}
func main() {
const secret = "MYpasswd"
enc, err := Encrypt([]byte(secret))
if err != nil {
log.Fatalf("Encrypt failed: %v", err)
}
dec, err := Decrypt(enc)
if err != nil {
log.Fatalf("Decrypt failed: %v", err)
}
if string(dec) != secret {
log.Fatalf("decrypted secret \"%s\" does not match to \"%s\".", dec, secret)
}
fmt.Println(fmt.Sprintf("%x", enc))
fmt.Println(string(dec))
}
out: 01000000d08c9ddf0115d1118c7a00c04fc297eb01000000de7c90fbe3c9854381f0a0ffe1d496f3000000000200000000001066000000010000200000000790b641e1a9d4bfe54d81966c4d7aaeabf19b63c36dff42668e3b256edbeed8000000000e8000000002000020000000d6385d3352d5a4b011e171ab25b30271e73a4ddc0b9f9bfb8ecd13f230362a0110000000da71663217c163d7ab77231282e7d8d64000000025fbcbb72efcdc711f3a74c38bddbf0b71538f0ffe27d133c0c5cd2434f88d55d924f598ac2f94758d66a448682ed841fb56ce8c9de38601dcce6bd42aa41fbb
MYpasswd
create tmp.rdp
screen mode id:i:1
....
winposstr:s:0,1,153,64,953,664
username:s:{{username}}
domain:s:
password 51:b:01000000d08c9ddf0115d1118c7a00c04fc297eb0100000............
disable wallpaper:i:1
disable full window drag:i:1
final:
mstsc.exe tmp.rdp
But Login failed
python "win32crypt.CryptProtectData" is work.
pwdHash = win32crypt.CryptProtectData(u"MYpasswd", u'pws', None, None, None, 0)
enc_password = binascii.hexlify(pwdHash)

make an addition for the not-detailed answer above. According #Fuqiang's answer, just transfer the encoding of the plain string to UTF-16LE before encrypting, and it finally works. So it looks like this:
....
func convertToUTF16LittleEndianBytes(s string) []byte {
u := utf16.Encode([]rune(s))
b := make([]byte, 2*len(u))
for index, value := range u {
binary.LittleEndian.PutUint16(b[index*2:], value)
}
return b
}
func main() {
const secret = "MYpasswd"
s := convertToUTF16LittleEndianBytes(secret)
enc, err := Encrypt(s)
if err != nil {
log.Fatalf("Encrypt failed: %v", err)
}
...
}
And after decrypting, you have to decode the decrypted string from utf-16le before you comparing or using it, don't directly transfer the utf-16le char to string by string(dec).

The issue has been solved.
secret = "MYpasswd"
string must use UTF-16LE encode.

Related

Golang Gorilla Websocket stops receiving information at 120 seconds

I'm currently trying to connect to the CEX.IO bitcoin exchange's websocket, but have been having issues not only with CEX.IO but with others too. All of my connections drop around the 120-second mark which makes me think there is some TTL problem going on. The Process() goroutine in the main package ends up just hanging and waiting for data from the readLoop which just stops receiving data. I've included some read-only API keys in the code so you can test if you'd like.
package main
import (
"fmt"
"bitbucket.org/tradedefender/cryptocurrency/exchange-connector/cexio"
"github.com/shopspring/decimal"
"encoding/json"
"time"
)
type OrderBook struct {
Asks []Ask
Bids []Bid
}
type Ask struct {
Rate decimal.Decimal
Amount decimal.Decimal
}
type Bid struct {
Rate decimal.Decimal
Amount decimal.Decimal
}
func main() {
cexioConn := new(cexio.Connection)
err := cexioConn.Connect()
if err != nil {
fmt.Errorf("error: %s", err.Error())
}
err = cexioConn.Authenticate("TLwYkktLf7Im6nqSKt6UO1IrU", "9ImOJcR7Qj3LMIyPCzky0D7WE")
if err != nil {
fmt.Errorf("error: %s", err.Error())
}
readChannel := make(chan cexio.IntraAppMessage, 25)
go cexioConn.ReadLoop(readChannel)
processor := Processor{
WatchPairs: [][2]string{
[2]string{
"BTC", "USD",
},
},
conn: cexioConn,
}
go processor.Process(readChannel)
// LOL
for {
continue
}
}
type Processor struct {
WatchPairs [][2]string
conn *cexio.Connection
}
func (p *Processor) Process(ch <-chan cexio.IntraAppMessage) {
p.conn.SubscribeToOrderBook(p.WatchPairs[0])
pingTimer := time.Now().Unix()
for {
fmt.Printf("(%v)\n", time.Now().Unix())
if (time.Now().Unix() - pingTimer) >= 10 {
fmt.Println("sending ping")
p.conn.SendPing()
pingTimer = time.Now().Unix()
}
readMsg := <- ch
output, _ := json.Marshal(readMsg.SocketMessage)
fmt.Println(string(output))
if readMsg.SocketMessage.Event == "ping" {
fmt.Println("sending pong")
p.conn.SendPong()
pingTimer = time.Now().Unix()
}
}
}
Below is the connector to the cexio websocket. Here is a link to their API: https://cex.io/websocket-api
package cexio
import (
"github.com/gorilla/websocket"
//"github.com/shopspring/decimal"
"github.com/satori/go.uuid"
"encoding/hex"
"encoding/json"
"crypto/hmac"
"crypto/sha256"
"bytes"
"strconv"
"time"
"fmt"
)
const Url = "wss://ws.cex.io/ws/"
type Connection struct {
conn *websocket.Conn
}
type IntraAppMessage struct {
SocketMessage GenericMessage
ProgramMessage ProgramMessage
}
type GenericMessage struct {
Event string `json:"e"`
Data interface{} `json:"data"`
Auth AuthData `json:"auth,omitempty"`
Ok string `json:"ok,omitempty"`
Oid string `json:"oid,omitempty"`
Time int64 `json:"time,omitempty"`
}
type ProgramMessage struct {
Error string
}
type AuthData struct {
Key string `json:"key"`
Signature string `json:"signature"`
Timestamp int64 `json:"timestamp"`
}
type OrderBookSubscribeData struct {
Pair [2]string `json:"pair"`
Subscribe bool `json:"subscribe"`
Depth int `json:"depth"`
}
func (c *Connection) SendPong() error {
pongMsg := GenericMessage{
Event: "pong",
}
err := c.conn.WriteJSON(pongMsg)
if err != nil {
return nil
}
deadline := time.Now().Add(15*time.Second)
err = c.conn.WriteControl(websocket.PongMessage, nil, deadline)
if err != nil {
return err
}
return nil
}
func (c *Connection) SendPing() error {
pingMsg := GenericMessage{
Event: "get-balance",
Oid: uuid.NewV4().String(),
}
err := c.conn.WriteJSON(pingMsg)
if err != nil {
return err
}
deadline := time.Now().Add(15*time.Second)
err = c.conn.WriteControl(websocket.PingMessage, nil, deadline)
if err != nil {
return err
}
return nil
}
func (c *Connection) Connect() error {
dialer := *websocket.DefaultDialer
wsConn, _, err := dialer.Dial(Url, nil)
if err != nil {
return err
}
c.conn = wsConn
//c.conn.SetPingHandler(c.HandlePing)
for {
_, msgBytes, err := c.conn.ReadMessage()
if err != nil {
c.Disconnect()
return err
}
fmt.Println(string(msgBytes))
var m GenericMessage
err = json.Unmarshal(msgBytes, &m)
if err != nil {
c.Disconnect()
return err
}
if m.Event != "connected" {
c.Disconnect()
return err
} else {
break
}
}
return nil
}
func (c *Connection) Disconnect() error {
return c.conn.Close()
}
func (c *Connection) ReadLoop(ch chan<- IntraAppMessage) {
for {
fmt.Println("starting new read")
_, msgBytes, err := c.conn.ReadMessage()
if err != nil {
ch <- IntraAppMessage{
ProgramMessage: ProgramMessage{
Error: err.Error(),
},
}
continue
}
var m GenericMessage
err = json.Unmarshal(msgBytes, &m)
if err != nil {
ch <- IntraAppMessage{
ProgramMessage: ProgramMessage{
Error: err.Error(),
},
}
continue
}
ch <- IntraAppMessage{
SocketMessage: m,
}
}
}
func CreateSignature(timestamp int64, key, secret string) string {
secretBytes := []byte(secret)
h := hmac.New(sha256.New, secretBytes)
var buffer bytes.Buffer
buffer.WriteString(strconv.FormatInt(timestamp, 10))
buffer.WriteString(key)
h.Write(buffer.Bytes())
return hex.EncodeToString(h.Sum(nil))
}
func (c *Connection) Authenticate(key, secret string) error {
timestamp := time.Now().Unix()
signature := CreateSignature(timestamp, key, secret)
var authMsg GenericMessage
authMsg.Event = "auth"
authMsg.Auth = AuthData{
Key: key,
Signature: signature,
Timestamp: timestamp,
}
err := c.conn.WriteJSON(authMsg)
if err != nil {
return err
}
for {
_, msgBytes, err := c.conn.ReadMessage()
if err != nil {
c.Disconnect()
return err
}
fmt.Println(string(msgBytes))
var m GenericMessage
err = json.Unmarshal(msgBytes, &m)
if err != nil {
c.Disconnect()
return err
}
if m.Event != "auth" && m.Ok != "ok" {
c.Disconnect()
return err
} else {
break
}
}
return nil
}
func (c *Connection) SubscribeToOrderBook(pair [2]string) error {
sendMsg := GenericMessage{
Event: "order-book-subscribe",
Data: OrderBookSubscribeData{
Pair: pair,
Subscribe: true,
Depth: 0,
},
Oid: uuid.NewV4().String(),
}
err := c.conn.WriteJSON(sendMsg)
if err != nil {
return err
}
return nil
}
func (c *Connection) GetBalance() error {
sendMsg := GenericMessage{
Event: "get-balance",
Oid: uuid.NewV4().String(),
}
err := c.conn.WriteJSON(sendMsg)
if err != nil {
return err
}
return nil
}
Solution was to remove the
for {
continue
}
at the end of the main function

how to generate multiple uuid and md5 files in golang

Hi I've generated Md5 and uuid in golang but now I want generate it for multiple files using command line arguments, so what exactly I've to do. This is how I've generated my md5 and uuid:
package main
import (
"crypto/rand"
"crypto/md5"
"fmt"
"io"
"os"
"log"
"text/template"
)
type Data struct {
Uuid string
Md5 string
}
func main() {
uuid, err := newUUID()
if err != nil {
fmt.Printf("error: %v\n", err)
}
fmt.Printf("UUID: %s\n", uuid)
md5 := Getmd5(uuid)
fmt.Printf("Checksum: %s\n",md5)
fillData := Data{uuid, md5}
file, err := os.Create("text.txt")
if err != nil {
return
}
defer file.Close()
templ, err := template.ParseFiles("template.html")
if err !=nil{
log.Fatalln(err)
}
err = templ.Execute(file,fillData)
if err != nil{
log.Fatalln(err)
}
}
// newUUID generates a random UUID according to RFC 4122
func newUUID() (string, error) {
uuid := make([]byte, 16)
n, err := io.ReadFull(rand.Reader, uuid)
if n != len(uuid) || err != nil {
return "", err
}
// variant bits
uuid[8] = uuid[8]&^0xc0 | 0x80
// version 4 (pseudo-random)
uuid[6] = uuid[6]&^0xf0 | 0x40
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
}
func Getmd5(uuid string) (string) {
data := []byte(uuid)
//md5_buffer := fmt.Sprintf("%x", md5.Sum(data))
md5_buffer := md5.Sum(data)
return fmt.Sprintf("{0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x};\n",md5_buffer[0:1],
md5_buffer[1:2],md5_buffer[2:3],md5_buffer[3:4],md5_buffer[4:5],md5_buffer[5:6],md5_buffer[6:7],md5_buffer[7:8],
md5_buffer[8:9],md5_buffer[9:10],md5_buffer[10:11],md5_buffer[11:12],md5_buffer[12:13],md5_buffer[13:14],md5_buffer[14:15],
md5_buffer[15:16])
}
Can anyone help me out?
You can use os.Args to accept command line arguements
os.Args provides access to raw command-line arguments. Note that the first value in this slice is the path to the program, and os.Args[1:] holds the arguments to the program.
Your program will look like this, have a look at createFile and getNumberOfFiles functions and the main
package main
import (
"crypto/md5"
"crypto/rand"
"errors"
"fmt"
"io"
"log"
"os"
"strconv"
"text/template"
)
type Data struct {
Uuid string
Md5 string
}
func createFile(uuid string) {
md5 := Getmd5(uuid)
fmt.Printf("Checksum: %s\n", md5)
fillData := Data{uuid, md5}
file, err := os.Create(uuid + ".txt")
if err != nil {
return
}
defer file.Close()
templ, err := template.ParseFiles("template.html")
if err != nil {
log.Fatalln(err)
}
err = templ.Execute(file, fillData)
if err != nil {
log.Fatalln(err)
}
}
func getNumberOfFiles() (num int, err error) {
if len(os.Args) == 1 {
return 0, errors.New("Not enough arguements")
}
if num, err = strconv.Atoi(os.Args[1]); err != nil {
return
}
return num, nil
}
func main() {
numberOfFiles, err := getNumberOfFiles()
if err != nil {
fmt.Println(err.Error())
}
fmt.Printf("Creating %d files", numberOfFiles)
for i := 0; i < numberOfFiles; i++ {
uuid, err := newUUID()
if err != nil {
fmt.Printf("error: %v\n", err)
}
createFile(uuid)
}
}
// newUUID generates a random UUID according to RFC 4122
func newUUID() (string, error) {
uuid := make([]byte, 16)
n, err := io.ReadFull(rand.Reader, uuid)
if n != len(uuid) || err != nil {
return "", err
}
// variant bits
uuid[8] = uuid[8]&^0xc0 | 0x80
// version 4 (pseudo-random)
uuid[6] = uuid[6]&^0xf0 | 0x40
return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
}
func Getmd5(uuid string) string {
data := []byte(uuid)
//md5_buffer := fmt.Sprintf("%x", md5.Sum(data))
md5_buffer := md5.Sum(data)
return fmt.Sprintf("{0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x};\n", md5_buffer[0:1],
md5_buffer[1:2], md5_buffer[2:3], md5_buffer[3:4], md5_buffer[4:5], md5_buffer[5:6], md5_buffer[6:7], md5_buffer[7:8],
md5_buffer[8:9], md5_buffer[9:10], md5_buffer[10:11], md5_buffer[11:12], md5_buffer[12:13], md5_buffer[13:14], md5_buffer[14:15],
md5_buffer[15:16])
}

How to get process id by process name in windows environment?

I want to get the process id by the process name in windows environment?
I find golang only has the api os.FindProcess(id),but no by name.
I had to struggle with this too, and found the way to the solution not very straightforward, because… WinApi :)
In the end you have to create a snapshot of the current windows process list using CreateToolhelp32Snapshot. Then you get the first process in the snapshot with Process32First. After that keep iterating over the list with Process32Next, until you get the ERROR_NO_MORE_FILES error. Only then you have the whole process list.
See how2readwindowsprocesses for a working example.
Here is the gist:
const TH32CS_SNAPPROCESS = 0x00000002
type WindowsProcess struct {
ProcessID int
ParentProcessID int
Exe string
}
func processes() ([]WindowsProcess, error) {
handle, err := windows.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
if err != nil {
return nil, err
}
defer windows.CloseHandle(handle)
var entry windows.ProcessEntry32
entry.Size = uint32(unsafe.Sizeof(entry))
// get the first process
err = windows.Process32First(handle, &entry)
if err != nil {
return nil, err
}
results := make([]WindowsProcess, 0, 50)
for {
results = append(results, newWindowsProcess(&entry))
err = windows.Process32Next(handle, &entry)
if err != nil {
// windows sends ERROR_NO_MORE_FILES on last process
if err == syscall.ERROR_NO_MORE_FILES {
return results, nil
}
return nil, err
}
}
}
func findProcessByName(processes []WindowsProcess, name string) *WindowsProcess {
for _, p := range processes {
if strings.ToLower(p.Exe) == strings.ToLower(name) {
return &p
}
}
return nil
}
func newWindowsProcess(e *windows.ProcessEntry32) WindowsProcess {
// Find when the string ends for decoding
end := 0
for {
if e.ExeFile[end] == 0 {
break
}
end++
}
return WindowsProcess{
ProcessID: int(e.ProcessID),
ParentProcessID: int(e.ParentProcessID),
Exe: syscall.UTF16ToString(e.ExeFile[:end]),
}
}
You can list all the processes and match them with the name you want to find, by using the updated sys call package, https://godoc.org/golang.org/x/sys,
it has most of the windows api.
func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error)
func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error)
also see the msdn docs:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms684834(v=vs.85).aspx
const TH32CS_SNAPPROCESS = 0x00000002
type WindowsProcess struct {
ProcessID int
ParentProcessID int
Exe string
}
func newWindowsProcess(e *syscall.ProcessEntry32) WindowsProcess {
// Find when the string ends for decoding
end := 0
for {
if e.ExeFile[end] == 0 {
break
}
end++
}
return WindowsProcess{
ProcessID: int(e.ProcessID),
ParentProcessID: int(e.ParentProcessID),
Exe: syscall.UTF16ToString(e.ExeFile[:end]),
}
}
func processes() ([]WindowsProcess, error) {
handle, err := syscall.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
if err != nil {
return nil, err
}
defer syscall.CloseHandle(handle)
var entry syscall.ProcessEntry32
entry.Size = uint32(unsafe.Sizeof(entry))
// get the first process
err = syscall.Process32First(handle, &entry)
if err != nil {
return nil, err
}
results := make([]WindowsProcess, 0, 50)
for {
results = append(results, newWindowsProcess(&entry))
err = syscall.Process32Next(handle, &entry)
if err != nil {
// windows sends ERROR_NO_MORE_FILES on last process
if err == syscall.ERROR_NO_MORE_FILES {
return results, nil
}
return nil, err
}
}
}
func findProcessByName(processes []WindowsProcess, name string) *WindowsProcess {
for _, p := range processes {
if bytes.Contains([]byte(strings.ToUpper(p.Exe)), []byte(strings.ToUpper(name))) {
return &p
}
}
return nil
}
This seems to do it:
package main
import (
"fmt"
"golang.org/x/sys/windows"
)
// unsafe.Sizeof(windows.ProcessEntry32{})
const processEntrySize = 568
func processID(name string) (uint32, error) {
h, e := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0)
if e != nil { return 0, e }
p := windows.ProcessEntry32{Size: processEntrySize}
for {
e := windows.Process32Next(h, &p)
if e != nil { return 0, e }
if windows.UTF16ToString(p.ExeFile[:]) == name {
return p.ProcessID, nil
}
}
return 0, fmt.Errorf("%q not found", name)
}
func main() {
n, e := processID("WindowsTerminal.exe")
if e != nil {
panic(e)
}
println(n)
}
https://pkg.go.dev/golang.org/x/sys/windows#CreateToolhelp32Snapshot

How to monitor ip address change using RTNETLINK socket in go language

I have following code, which should monitor network changes using RTNETLINK socket. However when I am setting new IP address for interface "New Addr" or "Del Addr" does not showing. What can be possible problem.
package main
import (
"fmt"
"syscall"
)
func main() {
l, _ := ListenNetlink()
for {
msgs, err := l.ReadMsgs()
if err != nil {
fmt.Println("Could not read netlink: %s", err)
}
for _, m := range msgs {
if IsNewAddr(&m) {
fmt.Println("New Addr")
}
if IsDelAddr(&m) {
fmt.Println("Del Addr")
}
}
}
}
type NetlinkListener struct {
fd int
sa *syscall.SockaddrNetlink
}
func ListenNetlink() (*NetlinkListener, error) {
groups := syscall.RTNLGRP_LINK |
syscall.RTNLGRP_IPV4_IFADDR |
syscall.RTNLGRP_IPV6_IFADDR
s, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM,
syscall.NETLINK_ROUTE)
if err != nil {
return nil, fmt.Errorf("socket: %s", err)
}
saddr := &syscall.SockaddrNetlink{
Family: syscall.AF_NETLINK,
Pid: uint32(0),
Groups: uint32(groups),
}
err = syscall.Bind(s, saddr)
if err != nil {
return nil, fmt.Errorf("bind: %s", err)
}
return &NetlinkListener{fd: s, sa: saddr}, nil
}
func (l *NetlinkListener) ReadMsgs() ([]syscall.NetlinkMessage, error) {
defer func() {
recover()
}()
pkt := make([]byte, 2048)
n, err := syscall.Read(l.fd, pkt)
if err != nil {
return nil, fmt.Errorf("read: %s", err)
}
msgs, err := syscall.ParseNetlinkMessage(pkt[:n])
if err != nil {
return nil, fmt.Errorf("parse: %s", err)
}
return msgs, nil
}
func IsNewAddr(msg *syscall.NetlinkMessage) bool {
if msg.Header.Type == syscall.RTM_NEWADDR {
return true
}
return false
}
func IsDelAddr(msg *syscall.NetlinkMessage) bool {
if msg.Header.Type == syscall.RTM_DELADDR {
return true
}
return false
}
func IsRelevant(msg *syscall.IfAddrmsg) bool {
if msg.Scope == syscall.RT_SCOPE_UNIVERSE ||
msg.Scope == syscall.RT_SCOPE_SITE {
return true
}
return false
}
I found bag in syscall.go file. Constant variable syscall.RTNLGRP_IPV4_IFADDR=0x5. However analog RTMGRP_IPV4_IFADDR constant in C language which is defined in rtnetlink.h source has different value as following:
#define RTMGRP_IPV4_IFADDR 0x10
I submitted issue through github.com and I hope it will fixed in upcoming releases.
For now you can use 0x10 in your code insted of 0x5. It will work perfectly.
Turns out that it is not bug at all. They did not re declare RTMGRP_* constant variables group from rtnetlink.h source and do not want to add this in feature as well since syscall.go is frozen. However they suggest using RTNLGRP_* which is also declared in rtnetlink.h source. However this two groups of constant variables is different in following way. RTMGRP_* group represents bit value (i.e.: RTMGRP_IPV4_IFADDR = 0x10) and declared for userspace backward capabilities. RTLNGRP_* group represents bit position rather than bit value (i.e.: RTNLGRP_IPV4_IFADDR=0x5) which can be translated to bit value by following way 1 << (RTNLGRP_* - 1)
As per the accepted answer, the fix it to change the groups to the following:
groups := (1 << (syscall.RTNLGRP_LINK - 1)) |
(1 << (syscall.RTNLGRP_IPV4_IFADDR - 1)) |
(1 << (syscall.RTNLGRP_IPV6_IFADDR - 1))
Here's the equivalent code for *BSD:
package main
import (
"fmt"
"log"
"syscall"
)
func main() {
netlink, err := ListenNetlink()
if err != nil {
log.Printf("[ERR] Could not create netlink listener: %v", err)
return
}
for {
msgs, err := netlink.ReadMsgs()
if err != nil {
log.Printf("[ERR] Could not read netlink: %v", err)
}
for _, msg := range msgs {
if _, ok := msg.(*syscall.InterfaceAddrMessage); ok {
log.Printf("address change!")
}
}
}
}
type NetlinkListener struct {
fd int
}
func ListenNetlink() (*NetlinkListener, error) {
s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
if err != nil {
return nil, fmt.Errorf("socket: %s", err)
}
return &NetlinkListener{fd: s}, nil
}
func (l *NetlinkListener) ReadMsgs() ([]syscall.RoutingMessage, error) {
defer func() {
recover()
}()
pkt := make([]byte, 2048)
n, err := syscall.Read(l.fd, pkt)
if err != nil {
return nil, fmt.Errorf("read: %s", err)
}
msgs, err := syscall.ParseRoutingMessage(pkt[:n])
if err != nil {
return nil, fmt.Errorf("parse: %s", err)
}
return msgs, nil
}
the update Example should be
package main
import (
"fmt"
"syscall"
)
func main() {
l, _ := ListenNetlink()
for {
msgs, err := l.ReadMsgs()
if err != nil {
fmt.Println("Could not read netlink: %s", err)
}
for _, m := range msgs {
if IsNewAddr(&m) {
fmt.Println("New Addr")
}
if IsDelAddr(&m) {
fmt.Println("Del Addr")
}
}
}
}
type NetlinkListener struct {
fd int
sa *syscall.SockaddrNetlink
}
func ListenNetlink() (*NetlinkListener, error) {
groups := (1 << (syscall.RTNLGRP_LINK - 1)) |
(1 << (syscall.RTNLGRP_IPV4_IFADDR - 1)) |
(1 << (syscall.RTNLGRP_IPV6_IFADDR - 1))
s, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM,
syscall.NETLINK_ROUTE)
if err != nil {
return nil, fmt.Errorf("socket: %s", err)
}
saddr := &syscall.SockaddrNetlink{
Family: syscall.AF_NETLINK,
Pid: uint32(0),
Groups: uint32(groups),
}
err = syscall.Bind(s, saddr)
if err != nil {
return nil, fmt.Errorf("bind: %s", err)
}
return &NetlinkListener{fd: s, sa: saddr}, nil
}
func (l *NetlinkListener) ReadMsgs() ([]syscall.NetlinkMessage, error) {
defer func() {
recover()
}()
pkt := make([]byte, 2048)
n, err := syscall.Read(l.fd, pkt)
if err != nil {
return nil, fmt.Errorf("read: %s", err)
}
msgs, err := syscall.ParseNetlinkMessage(pkt[:n])
if err != nil {
return nil, fmt.Errorf("parse: %s", err)
}
return msgs, nil
}
func IsNewAddr(msg *syscall.NetlinkMessage) bool {
if msg.Header.Type == syscall.RTM_NEWADDR {
return true
}
return false
}
func IsDelAddr(msg *syscall.NetlinkMessage) bool {
if msg.Header.Type == syscall.RTM_DELADDR {
return true
}
return false
}
// rtm_scope is the distance to the destination:
//
// RT_SCOPE_UNIVERSE global route
// RT_SCOPE_SITE interior route in the
// local autonomous system
// RT_SCOPE_LINK route on this link
// RT_SCOPE_HOST route on the local host
// RT_SCOPE_NOWHERE destination doesn't exist
//
// The values between RT_SCOPE_UNIVERSE and RT_SCOPE_SITE are
// available to the user.
func IsRelevant(msg *syscall.IfAddrmsg) bool {
if msg.Scope == syscall.RT_SCOPE_UNIVERSE ||
msg.Scope == syscall.RT_SCOPE_SITE {
return true
}
return false
}

How could i use flags to select which func i want to call

Hello this is my first actually stab at writing an actual Go command line program so please forgive the appearance I also pulled some of this code off the Internet. What I am actually trying to do is have the ability to choose when i want to encrypt or decrypt while still being able to choose the src file and dest file. Thanks in advance for any help. I couldn't find anything solid explaining this or at least nothing i could make out.
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"errors"
"io"
"io/ioutil"
"log"
"os"
)
func decrypt(key, ciphertext []byte) (plaintext []byte, err error) {
var block cipher.Block
if block, err = aes.NewCipher(key); err != nil {
return
}
if len(ciphertext) < aes.BlockSize {
err = errors.New("ciphertext too short")
return
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
cfb := cipher.NewCFBDecrypter(block, iv)
cfb.XORKeyStream(ciphertext, ciphertext)
plaintext = ciphertext
return
}
func encrypt(key, text []byte) (ciphertext []byte, err error) {
var block cipher.Block
if block, err = aes.NewCipher(key); err != nil {
return nil, err
}
ciphertext = make([]byte, aes.BlockSize+len(string(text)))
iv := ciphertext[:aes.BlockSize]
if _, err = io.ReadFull(rand.Reader, iv); err != nil {
return
}
cfb := cipher.NewCFBEncrypter(block, iv)
cfb.XORKeyStream(ciphertext[aes.BlockSize:], text)
return
}
func encryptFileData(srcFile, destFile string) {
if len(os.Args) > 1 {
srcFile = os.Args[1]
}
if len(os.Args) > 2 {
destFile = os.Args[2]
}
var cipherText, plainText []byte
var err error
key := []byte("abcdefg123456789")
plainText, _ = ioutil.ReadFile(srcFile)
if cipherText, err = encrypt(key, plainText); err != nil {
log.Fatal(err)
}
ioutil.WriteFile(destFile, cipherText, 0755)
return
}
func decryptFileData(srcFile, destFile string) {
if len(os.Args) > 1 {
srcFile = os.Args[1]
}
if len(os.Args) > 2 {
destFile = os.Args[2]
}
var cipherText, plainText []byte
var err error
key := []byte("abcdefg123456789")
cipherText, _ = ioutil.ReadFile(srcFile)
if plainText, err = decrypt(key, cipherText); err != nil {
log.Fatal(err)
}
ioutil.WriteFile(destFile, plainText, 0755)
return
}
func main() {
encryptFileData(os.Args[1], os.Args[2])
decryptFileData(os.Args[1], os.Args[2])
}
Use the flag package. For example:
func main() {
encrypt := flag.Bool("encrypt", false, "encrypt file")
decrypt := flag.Bool("decrypt", false, "decrypt file")
flag.Parse()
srcFile, destFile := flag.Arg(0), flag.Arg(1)
if *encrypt {
encryptFileData(srcFile, destFile)
}
if *decrypt {
decryptFileData(srcFile, destFile)
}
}

Resources