forked from K0p1-Git/cloudflare-ddns-updater
-
Notifications
You must be signed in to change notification settings - Fork 1
/
cloudflare-template.sh
268 lines (245 loc) · 12.8 KB
/
cloudflare-template.sh
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
263
264
265
266
267
268
#!/bin/bash
## When the system shell is required, replace the first line of the script with "#!/bin/sh"
auth_email="" # Your account e-mail address; "[email protected]" (https://dash.cloudflare.com)
auth_method="token" # Your account authentication method; Set to "global" for Global API Key or "token" for Scoped API Token
auth_key="" # Your Global API Key or Scoped API Token; Located within the "API Tokens" section of your profile
zone_identifier="" # Your Zone Identifier ID; Located within the "Overview" section of your domain
record_name_A="" # The name of your A record; "www.example.com"
record_name_AAAA="" # The name of your AAAA record; "www.example.com"
ttl="1" # Set the DNS TTL (seconds); "1" for automatic or "3600" for default
proxy="true" # Set the Proxy Status to "true" or "false"; "true" for Proxied or "false" for DNS Only
website_name="" # The title of your website; "Example Website"
slack_channel="" # The name of your Slack channel; "#channel"
slack_uri="" # The URI of your Slack Webhook; "https://hooks.slack.com/services/xxxxx"
discord_uri="" # The URI of your Discord Webhook; "https://discordapp.com/api/webhooks/xxxxx"
#####################################
## Check for a public IPv4 address ##
#####################################
ipv4_regex='((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])'
ipv4=$(curl -s -4 https://cloudflare.com/cdn-cgi/trace | grep -E '^ip'); ret_ipv4=$?
if [[ ! $ret_ipv4 == 0 ]]; then # In the case that Cloudflare failed to return a public IPv4 address.
# Attempt to pull the public IPv4 address from another website.
ipv4=$(curl -s https://api.ipify.org || curl -s https://ipv4.icanhazip.com)
else
# Use regex to extract the public IPv4 address from the "ip=" line of the JSON data provided by Cloudflare.
ipv4=$(echo $ipv4 | sed -E "s/^ip=($ipv4_regex)$/\1/")
ipv4_valid="0"
fi
# Use regex to check whether the returned public IPv4 address is a valid IPv4 address.
if [[ ! $ipv4 =~ ^$ipv4_regex$ ]]; then
logger -s "DDNS Updater: Failed to return a valid public IPv4 address."
ipv4_valid="1"
fi
#####################################
## Check for a public IPv6 address ##
#####################################
ipv6_regex='(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))'
ipv6=$(curl -s -6 https://cloudflare.com/cdn-cgi/trace | grep -E '^ip'); ret_ipv6=$?
if [[ ! $ret_ipv6 == 0 ]]; then # In the case that Cloudflare failed to return a public IPv6 address.
# Attempt to pull the public IPv6 address from another website.
ipv6=$(curl -s https://api64.ipify.org || curl -s https://ipv6.icanhazip.com)
else
# Use regex to extract the public IPv6 address from the "ip=" line of the JSON provided by Cloudflare.
ipv6=$(echo $ipv6 | sed -E "s/^ip=($ipv6_regex)$/\1/")
ipv6_valid="0"
fi
# Use regex to check whether the returned public IPv6 address is a valid IPv6 address.
if [[ ! $ipv6 =~ ^$ipv6_regex$ ]]; then
logger -s "DDNS Updater: Failed to return a valid public IPv6 address."
ipv6_valid="1"
fi
#############################################################
## Check the returned public IPv4 address and IPv6 address ##
#############################################################
if [[ ! $ipv4_valid == 0 && ! $ipv6_valid == 0 ]]; then # In the case that the returned IPv4 address and IPv6 address are both invalid.
# Exit the script with exit code 2: Misuse of shell builtins.
exit 2
fi
###################################
## Set the authentication header ##
###################################
if [[ "${auth_method}" == "global" ]]; then
auth_header="X-Auth-Key:"
else
auth_header="Authorization: Bearer"
fi
######################
## Get the A record ##
######################
logger "DDNS Updater: Check initiated for A record."
record_A=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?type=A&name=$record_name_A" \
-H "X-Auth-Email: $auth_email" \
-H "$auth_header $auth_key" \
-H "Content-Type: application/json")
####################################
## Check for an existing A record ##
####################################
if [[ $record_A == *"\"count\":0"* ]]; then
logger -s "DDNS Updater: A record does not exist. Create one first? (${ipv4} for ${record_name_A})"
record_A_valid="1"
else
record_A_valid="0"
fi
#########################
## Get the AAAA record ##
#########################
logger "DDNS Updater: Check initiated for AAAA record."
record_AAAA=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?type=AAAA&name=$record_name_AAAA" \
-H "X-Auth-Email: $auth_email" \
-H "$auth_header $auth_key" \
-H "Content-Type: application/json")
#######################################
## Check for an existing AAAA record ##
#######################################
if [[ $record_AAAA == *"\"count\":0"* ]]; then
logger -s "DDNS Updater: AAAA record does not exist. Create one first? (${ipv6} for ${record_name_AAAA})"
record_AAAA_valid="1"
else
record_AAAA_valid="0"
fi
#################################################
## Check the returned A record and AAAA record ##
#################################################
if [[ ! $record_A_valid == 0 && ! $record_AAAA_valid == 0 ]]; then # In the case both the returned A record and AAAA record do not exist.
# Exit the script with exit code 1: General errors.
exit 1
fi
#####################################################################
## Check the returned A record for an existing public IPv4 address ##
#####################################################################
old_ipv4=$(echo "$record_A" | sed -E 's/.*"content":"('$ipv4_regex')".*/\1/')
if [[ $ipv4 == $old_ipv4 ]]; then # Use regex to compare whether the returned public IPv4 address and existing public IPv4 address are the same.
logger "DDNS Updater: The IPv4 address ($ipv4) for ${record_name_A} has not changed."
old_ipv4_valid="1"
else
old_ipv4_valid="0"
fi
########################################################################
## Check the returned AAAA record for an existing public IPv6 address ##
########################################################################
old_ipv6=$(echo "$record_AAAA" | sed -E 's/.*"content":"('$ipv6_regex')".*/\1/')
if [[ $ipv6 == $old_ipv6 ]]; then # Use regex to compare whether the returned public IPv6 address and existing public IPv6 address are the same.
logger "DDNS Updater: The IPv6 address ($ipv6) for ${record_name_AAAA} has not changed."
old_ipv6_valid="1"
else
old_ipv6_valid="0"
fi
####################################################################
## Check the existing public IPv4 address and public IPv6 address ##
####################################################################
if [[ ! $record_ipv4_valid == 0 && ! $old_ipv6_valid == 0 ]]; then # In the case both the existing public IPv4 address and public IPv6 address have not changed.
# Exit the script with exit code 0: Success.
exit 0
fi
##################################################
## Set the A record and AAAA record identifiers ##
##################################################
record_identifier_A=$(echo "$record_A" | sed -E 's/.*"id":"(\w+)".*/\1/')
record_identifier_AAAA=$(echo "$record_AAAA" | sed -E 's/.*"id":"(\w+)".*/\1/')
####################################
## Update the public IPv4 address ##
####################################
update_ipv4=$(curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier_A" \
-H "X-Auth-Email: $auth_email" \
-H "$auth_header $auth_key" \
-H "Content-Type: application/json" \
--data "{\"type\":\"A\",\"name\":\"$record_name_A\",\"content\":\"$ipv4\",\"ttl\":\"$ttl\",\"proxied\":${proxy}}")
####################################
## Update the public IPv6 address ##
####################################
update_v6=$(curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier_AAAA" \
-H "X-Auth-Email: $auth_email" \
-H "$auth_header $auth_key" \
-H "Content-Type: application/json" \
--data "{\"type\":\"AAAA\",\"name\":\"$record_name_AAAA\",\"content\":\"$ipv6\",\"ttl\":\"$ttl\",\"proxied\":${proxy}}")
#########################################################
## Report the update status of the public IPv4 address ##
#########################################################
case "$update_ipv4" in
*"\"success\":false"*)
if [[ $slack_uri != "" ]]; then
curl -L -X POST $slack_uri \
--data-raw '{
"channel": "'$slack_channel'",
"text" : "'"$website_name"' DDNS Updater: Failed for '$record_name_A': '$record_identifier_A' ('$ipv4')."
}'
fi
if [[ $discord_uri != "" ]]; then
curl -i -H "Accept: application/json" -H "Content-Type:application/json" -X POST \
--data-raw '{
"content" : "'"$website_name"' DDNS Updater: Failed for '$record_name_A': '$record_identifier_A' ('$ipv4')."
}' $discord_uri
fi
echo -e "DDNS Updater: $ipv4 $record_name_A DDNS failed for $record_identifier_A ($ipv4). Dumping results:\n$update_ipv4" | logger -s
update_ipv4_valid="1"
;;
*)
if [[ $slack_uri != "" ]]; then
curl -L -X POST $slack_uri \
--data-raw '{
"channel": "'$slack_channel'",
"text" : "'"$website_name"' Updated: '$record_name_A''"'"'s'""' new IP Address is '$ipv4'"
}'
fi
if [[ $discord_uri != "" ]]; then
curl -i -H "Accept: application/json" -H "Content-Type:application/json" -X POST \
--data-raw '{
"content" : "'"$website_name"' Updated: '$record_name_A''"'"'s'""' new IP Address is '$ipv4'"
}' $discord_uri
fi
logger "DDNS Updater: $ipv4 $record_name_A DDNS updated successfully."
update_ipv4_valid="0"
;;
esac
#########################################################
## Report the update status of the public IPv6 address ##
#########################################################
case "$update_ipv6" in
*"\"success\":false"*)
if [[ $slack_uri != "" ]]; then
curl -L -X POST $slack_uri \
--data-raw '{
"channel": "'$slack_channel'",
"text" : "'"$website_name"' DDNS Updater: Failed for '$record_name_AAAA': '$record_identifier_AAAA' ('$ipv6')."
}'
fi
if [[ $discord_uri != "" ]]; then
curl -i -H "Accept: application/json" -H "Content-Type:application/json" -X POST \
--data-raw '{
"content" : "'"$website_name"' DDNS Updater: Failed for '$record_name_AAAA': '$record_identifier_AAAA' ('$ipv6')."
}' $discord_uri
fi
echo -e "DDNS Updater: $ipv6 $record_name_AAAA DDNS failed for $record_identifier_AAAA ($ipv6). Dumping results:\n$update_ipv6" | logger -s
update_ipv6_valid="1"
;;
*)
if [[ $slack_uri != "" ]]; then
curl -L -X POST $slack_uri \
--data-raw '{
"channel": "'$slack_channel'",
"text" : "'"$website_name"' Updated: '$record_name_AAAA''"'"'s'""' new IPv6 Address is '$ipv6'"
}'
fi
if [[ $discord_uri != "" ]]; then
curl -i -H "Accept: application/json" -H "Content-Type:application/json" -X POST \
--data-raw '{
"content" : "'"$website_name"' Updated: '$record_name_AAAA''"'"'s'""' new IPv6 Address is '$ipv6'"
}' $discord_uri
fi
logger "DDNS Updater: $ipv6 $record_name_AAAA DDNS updated successfully."
update_ipv6_valid="0"
;;
esac
################################################################################
## Check the update status of the public IPv4 address and public IPv6 address ##
################################################################################
if [[ ! $update_ipv4_valid == 0 || ! $update_ipv6_valid == 0 ]]; then # In the case the update status of either the public IPv4 address or public IPv6 address are invalid.
# Exit the script with exit code 1: General errors.
exit 1
else
# Exit the script with exit code 0: Success.
exit 0
fi
# End of the script
# Exit the script with exit code 0: Success.
exit 0