-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparam.go
160 lines (152 loc) · 4.2 KB
/
param.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package gojail
import (
"errors"
"fmt"
"net"
"reflect"
"strings"
"syscall"
"unsafe"
)
//JailParseParametersToIovec parses a map[string]interface{} parameter set to []syscall.Iovec
//for use in Jail syscalls requiring []syscall.Iovec
//Byte slices & pointers are considered in/out variables and will be filled with JailGet.
//for setting handing use strings or ints instead.
//gojail uses errmsg, and will error out if it's passed as a key
//No validation is done w.r.t. the type required by the jail parameter
func JailParseParametersToIovec(parameters map[string]interface{}) ([]syscall.Iovec, error) {
iovecs := make([]syscall.Iovec, 0)
for key, value := range parameters {
if key == "errmsg" {
return nil, errors.New("Usage of errmsg is reserved by gojail")
}
parIovec, err := paramToIOVec(key, value)
if err != nil {
return nil, err
}
//we allow vnet=false to return nil, nil continue in that case
if parIovec == nil {
continue
}
iovecs = append(iovecs, parIovec...)
}
return iovecs, nil
}
func splitParamInPrefixAndParam(p string) (prefix string, param string) {
s := strings.Split(p, ".")
param = s[len(s)-1]
s = s[:len(s)-1]
prefix = strings.Join(s, ".") + "."
return prefix, param
}
func paramToIOVec(key string, value interface{}) ([]syscall.Iovec, error) {
var val *byte
name, err := syscall.ByteSliceFromString(key)
if err != nil {
return nil, err
}
valsize := int(4)
switch v := value.(type) {
case int32:
val = (*byte)(unsafe.Pointer(&v))
case uint32:
val = (*byte)(unsafe.Pointer(&v))
case JailID:
val = (*byte)(unsafe.Pointer(&v))
case *int32:
val = (*byte)(unsafe.Pointer(v))
case *uint32:
val = (*byte)(unsafe.Pointer(v))
case *JailID:
val = (*byte)(unsafe.Pointer(&v))
case string:
//Special case: some parameters take strings "disabled", "new" or "inherit"
//in normal config, but actually map to 0, 1 ,2
switch v {
case "disabled":
return paramToIOVec(key, int32(0))
case "new":
return paramToIOVec(key, int32(1))
case "inherit":
return paramToIOVec(key, int32(2))
default:
val, err = syscall.BytePtrFromString(v)
if err != nil {
return nil, err
}
valsize = len(v) + 1
}
case []byte:
val = &v[0]
valsize = len(v)
case []net.IP:
//This bit is untested still, use at your own risk
ipBytes := make([]byte, 0)
if strings.Contains(key, "ipv4") {
for _, ip := range v {
ipv4 := ip.To4()
if ipv4 != nil {
ipBytes = append(ipBytes, []byte(ipv4)...)
} else {
return nil, fmt.Errorf("could not parse %s to ipv4 address", ip.String())
}
}
} else if strings.Contains(key, "ipv6") {
for _, ip := range v {
if ipv4 := ip.To4(); ipv4 == nil {
ipBytes = append(ipBytes, []byte(ip)...)
} else {
return nil, fmt.Errorf("expected ipv6 address got %s", ip.String())
}
}
} else {
return nil, fmt.Errorf("parsing of net.IP not implemented for key: %s", key)
}
val = &ipBytes[0]
valsize = len(ipBytes)
case bool:
//work around for vnet, which is used like a bool, but from testing seems to need
//an int32 value of 1 when enabling
if key == "vnet" || key == "novnet" {
if v {
return paramToIOVec("vnet", int32(1))
}
//change to error if deemed necesarry to have this be consumed by something external
return nil, nil
}
var prefix, param string
param = key
//node are deliminated with a "." character, "no" is actually prefixed to the last bit
//not the entire node
if strings.Contains(key, ".") {
prefix, param = splitParamInPrefixAndParam(param)
}
if v {
if strings.HasPrefix(param, "no") {
param = strings.TrimPrefix(param, "no")
}
} else {
if !strings.HasPrefix(param, "no") {
param = "no" + param
}
}
var err error
name, err = syscall.ByteSliceFromString(prefix + param)
if err != nil {
return nil, err
}
val = nil
valsize = 0
default:
return nil, fmt.Errorf("paramToIOVec: type: %s not implemented", reflect.TypeOf(v))
}
return makeJailIovec(name, val, valsize), nil
}
func makeJailIovec(name []byte, value *byte, valuesize int) []syscall.Iovec {
iovecs := make([]syscall.Iovec, 2)
iovecs[0].Base = &name[0]
iovecs[0].SetLen(len(name))
iovecs[1].Base = value
iovecs[1].SetLen(valuesize)
return iovecs
}