-
Notifications
You must be signed in to change notification settings - Fork 0
/
cmd.go
94 lines (79 loc) · 2.02 KB
/
cmd.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package smcroute
import (
"bytes"
"encoding/binary"
"fmt"
"strings"
"unsafe"
)
type header struct {
length int64
cmd CmdKind
argsCount uint16
}
type Cmd struct {
header
args []byte
argsOrig []string
}
func (cmd *Cmd) StringBash() string {
return fmt.Sprintf(
"sudo smcroute -%c %s",
cmd.cmd,
strings.Join(cmd.argsOrig, " "),
)
}
// -j eth0.33 239.255.11.101
//
// +----+-----+---+-------------------------------+
// | 40 | 'j' | 2 | "eth0.33\0239.255.11.101\0\0" |
// +----+-----+---+-------------------------------+
// ^ ^
// | |
// | |
// +-----cmd------+
//
// sizeof(struct cmd) = 16
// strlen(args) = 21
// sizeof(3 NULL_CHARACTERS) = 3
// 2 => after each string arument
// 1 => at the end of arfs bye array
//
// length = 16 + 21 + 3 = 40 bytes
//
// strace: write(3, "(\0\0\0\0\0\0\0j\0\2\0\0\0\0\0eth0.33\000239.255.11.101\0\0", 40) = 40
func (cmd *Cmd) Encode() (*bytes.Buffer, error) {
b := make([]byte, cmd.length)
buf := bytes.NewBuffer(b)
buf.Reset()
if err := binary.Write(buf, binary.LittleEndian, cmd.header); err != nil {
return nil, err
}
// add 0 padding
// e.g. 1. sizeof(struct{size_t, uint16, uint16}) in C is 16 bytes
// 2. sizeof(size_t) + sizeof(uint16) + sizeof(uint16) = 8 + 2 + 2 = 12 bytes
// 3. 16 - 12 = 4 bytes of padding should be added
structPaddedSize := int(unsafe.Sizeof(cmd.header))
for structPaddedSize-buf.Len() > 0 {
if err := buf.WriteByte(nullCharacter); err != nil {
return nil, err
}
}
if _, err := buf.Write(cmd.args); err != nil {
return nil, err
}
return buf, nil
}
func NewCmd(cmdKind CmdKind, args ...string) *Cmd {
cmd := new(Cmd)
cmd.header.cmd = cmdKind
cmd.header.argsCount = uint16(len(args))
for _, arg := range args {
cmd.args = append(cmd.args, []byte(arg)...)
cmd.args = append(cmd.args, nullCharacter)
}
cmd.args = append(cmd.args, nullCharacter)
cmd.argsOrig = args
cmd.header.length = int64(unsafe.Sizeof(cmd.header)) + int64(len(cmd.args))
return cmd
}