-
Notifications
You must be signed in to change notification settings - Fork 1
/
ztrules.bash
262 lines (155 loc) · 6.23 KB
/
ztrules.bash
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
#!/bin/bash
read -p "Please enter the network ID: " the_network
# Check that the network exists.
check_net=$(curl -s -H "X-ZT1-Auth: $(cat /var/lib/zerotier-one/authtoken.secret)" "http://localhost:9993/controller/network/" |egrep -o "\"${the_network}\"")
if [[ ${check_net} == "" ]]; then
echo "Error \"${the_network}\" does not exist"
exit 1
fi
tmp_file="ztconfig.tmp"
config_file="ztconfig.json"
# Get the port from the config file and direction
function get_port() {
port=$(echo "${1}" | cut -d: -f4)
d=$(echo "${1}" | cut -d: -f3)
# Check whether source or destination port
if [[ "${d}" == "dport" ]]; then
echo '{"end": '${port}',"not": false,"or": false,"start": '${port}',"type": "MATCH_IP_DEST_PORT_RANGE"}'
else
echo '{"end": '${port}',"not": false,"or": false,"start": '${port}',"type": "MATCH_IP_SOURCE_PORT_RANGE"}'
fi
}
function get_action() {
# check whether the rule is drop or accept
action=$(echo "${1}"| cut -d: -f1)
if [[ "${action}" == "accept" ]]; then
echo '{"type": "ACTION_ACCEPT"}'
else
echo '{"type": "ACTION_DROP"}'
fi
}
# check whether the protocol is tcp or udp
function get_proto() {
proto=$(echo "${1}" |cut -d: -f 2)
if [[ "${proto}" == "tcp" ]]; then
echo '{"ipProtocol": 6,"not": false,"or": false,"type": "MATCH_IP_PROTOCOL"}'
else
echo '{"ipProtocol": 17,"not": false,"or": false,"type": "MATCH_IP_PROTOCOL"}'
fi
}
# check whether the rule applies to the source or destination IP
# example: accept:udp:dport:53:destip:192.168.69.53/32
function get_ipnet() {
direction=$(echo "${1}" | cut -d: -f 5)
the_ip=$(echo "${1}" | cut -d: -f 6)
if [[ "${direction}" == "destip" ]]; then
echo '{"type": "MATCH_IPV4_DEST","not": false,"or": false,"ip": "'"${the_ip}"'"}'
else
echo '{"type": "MATCH_IPV4_SRC","not": false,"or": false,"ip": "'"${the_ip}"'"}'
fi
}
# This is for a rule where there is src/dst ip that applies to another src/dst ip
# example: accept:udp:sport:53:srcip:192.168.69.53/32:destip:192.168.69.0/24
function get_ipnet2() {
direction=$(echo "${1}" | cut -d: -f 7)
the_ip=$(echo "${1}" | cut -d: -f 8)
if [[ "${direction}" == "destip" ]]; then
echo '{"type": "MATCH_IPV4_DEST","not": false,"or": false,"ip": "'"${the_ip}"'"}'
else
echo '{"type": "MATCH_IPV4_SRC","not": false,"or": false,"ip": "'"${the_ip}"'"}'
fi
}
# Create header for the temporary config file
echo '{"rules": [' > ${tmp_file}
### Processes the rules in the config file: ztrules ###
# Read the flow rules config file one line at a time
while read line; do
# IPv4
if [[ "${line}" =~ ^accept:ipv4 ]]; then
echo '{"etherType": 2048,"not": true,"or": false,"type": "MATCH_ETHERTYPE"},' >> ${tmp_file}
fi
# ARP
if [[ "${line}" =~ ^accept:arp ]]; then
echo '{"etherType": 2054, "not": true,"or": false,"type": "MATCH_ETHERTYPE"},' >> ${tmp_file}
fi
if [[ "${line}" =~ ^accept:ipv6 ]]; then
echo '{"etherType": 34525,"not": true,"or": false,"type": "MATCH_ETHERTYPE"},' >> ${tmp_file}
fi
# IPv6
# TEMPORARY but follows the default rule in zerotier network controllers.
if [[ "${line}" =~ ^end:main:protocols ]]; then
echo '{"type": "ACTION_DROP"},' >> ${tmp_file}
fi
# GET ACTION
theact=$(get_action "${line}")
# Match accept:proto:port
if [[ "${line}" =~ ^(accept|drop):(tcp|udp):(dport|sport):([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$ ]]; then
# Port
port=$(get_port "${line}")
# Get Protocol
proto=$(get_proto "${line}")
act=$(get_action "${line}")
# Write Results
echo ''${proto}','${port}','${act}',' >> ${tmp_file}
fi
#Match accept:udp:dport:53:destip:192.168.69.53/32
if [[ "${line}" =~ ^(accept|drop):(tcp|udp):(dport|sport):([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]):(destip|srcip):[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then
# Port
port=$(get_port "${line}")
# Get Protocol
proto=$(get_proto "${line}")
act=$(get_action "${line}")
ipnet=$(get_ipnet "${line}")
# Write Results
echo ''${proto}','${port}','${ipnet}','${act}',' >> ${tmp_file}
fi
# Match accept:tcp:dport:22:srcip:192.168.69.40/32:destip:192.168.69.217/32
if [[ "${line}" =~ ^(accept|drop):(tcp|udp):(dport|sport):([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]):(destip|srcip):[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}:(destip|srcip):[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then
# Port
port=$(get_port "${line}")
# Get Protocol
proto=$(get_proto "${line}")
act=$(get_action "${line}")
ipnet=$(get_ipnet "${line}")
ipnet2=$(get_ipnet2 "${line}")
# Write Results
echo ''${proto}','${port}','${ipnet}','${ipnet2}','${act}',' >> ${tmp_file}
fi
if [[ "${line}" == "drop:udp" ]]; then
# Write Results
echo '{"ipProtocol": 17, "not": false, "or": false, "type": "MATCH_IP_PROTOCOL" },{"type": "ACTION_DROP"},' >> ${tmp_file}
fi
# Drops all tcp packets that don't have a matching rule above.
# based on suggestion from zerotier manual
# https://www.zerotier.com/manual/#3_4_1
if [[ "${line}" == "drop:tcp" ]]; then
# Write Results
echo ' {"mask": "0000000000000002","not": false,"or": false,"type": "MATCH_CHARACTERISTICS"},{"mask": "0000000000000010","not": true,"or": false,"type": "MATCH_CHARACTERISTICS"},{"type": "ACTION_DROP"},' >> ${tmp_file}
fi
# DEFAULT ACTION for flow rules
if [[ "${line}" == "default:accept" ]]; then
# Write Results
echo '{"type": "ACTION_ACCEPT"}' >> ${tmp_file}
fi
if [[ "${line}" == "default:drop" ]]; then
# Write Results
echo '{"type": "ACTION_DROP"}' >> ${tmp_file}
fi
done < ztrules
# End of the ztrules files for json format
echo '],"capabilities": [],"tags": []}' >> ${tmp_file}
# put all json created rules on one line
tr -d '\n' < ${tmp_file} > ${config_file}
j="$(cat ztconfig.json)"
curl -X POST -H "X-ZT1-Auth: $(cat /var/lib/zerotier-one/authtoken.secret)" -d "${j}" "http://localhost:9993/controller/network/${the_network}"
if [[ $? -eq 0 ]]; then
echo ""
echo "####################"
echo "Network rules added."
echo "####################"
else
echo ""
echo "####################"
echo "Error adding rules."
echo "####################"
fi