Project

General

Profile

Download (92.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * dyndns.class
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2018 Rubicon Communications, LLC (Netgate)
7
 * All rights reserved.
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 * http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21

    
22
	/*
23
	 * PHP.updateDNS (pfSense version)
24
	 *
25
	 * +====================================================+
26
	 *  Services Supported:
27
	 *    - DynDns (dyndns.org) [dynamic, static, custom]
28
	 *    - No-IP (no-ip.com)
29
	 *    - EasyDNS (easydns.com)
30
	 *    - DHS (www.dhs.org)
31
	 *    - HN (hn.org) -- incomplete checking!
32
	 *    - DynS (dyns.org)
33
	 *    - ZoneEdit (zoneedit.com)
34
	 *    - FreeDNS (freedns.afraid.org)
35
	 *    - FreeDNS IPv6 (freedns.afraid.org)
36
	 *    - Loopia (loopia.se)
37
	 *    - StaticCling (staticcling.org)
38
	 *    - DNSexit (dnsexit.com)
39
	 *    - OpenDNS (opendns.com)
40
	 *    - Namecheap (namecheap.com)
41
	 *    - HE.net (dns.he.net)
42
	 *    - HE.net IPv6 (dns.he.net)
43
	 *    - HE.net Tunnelbroker IP update (ipv4.tunnelbroker.net)
44
	 *    - SelfHost (selfhost.de)
45
	 *    - Amazon Route 53 (aws.amazon.com)
46
	 *    - DNS-O-Matic (dnsomatic.com)
47
	 *    - Custom DDNS (any URL)
48
	 *    - Custom DDNS IPv6 (any URL)
49
	 *    - Cloudflare (www.cloudflare.com)
50
	 *    - Cloudflare IPv6 (www.cloudflare.com)
51
	 *    - Eurodns (eurodns.com)
52
	 *    - GratisDNS (gratisdns.dk)
53
	 *    - City Network (citynetwork.se)
54
	 *    - GleSYS (glesys.com)
55
	 *    - DNSimple (dnsimple.com)
56
	 *    - Google Domains (domains.google.com)
57
	 *    - DNS Made Easy (www.dnsmadeeasy.com)
58
	 *    - SPDYN (spdyn.de)
59
	 *    - SPDYN IPv6 (spdyn.de)
60
	 *    - All-Inkl (all-inkl.com)
61
	 *    - DuiaDNS (www.duiadns.net)
62
	 *    - DuiaDNS IPv6 (www.duiadns.net)
63
	 *    - Hover (www.hover.com)
64
	 *    - DreamHost DNS (www.dreamhost.com)
65
	 *    - ClouDNS (www.cloudns.net)
66
	 *    - GoDaddy (www.godaddy.com)
67
	 *    - Azure DNS (azure.microsoft.com)
68
	 * +----------------------------------------------------+
69
	 *  Requirements:
70
	 *    - PHP version 4.0.2 or higher with the CURL Library and the PCRE Library
71
	 * +----------------------------------------------------+
72
	 *  Public Functions
73
	 *    - updatedns()
74
	 *
75
	 *  Private Functions
76
	 *    - _update()
77
	 *    - _checkStatus()
78
	 *    - _error()
79
	 *    - _detectChange()
80
	 *    - _debug()
81
	 *    - _checkIP()
82
	 * +----------------------------------------------------+
83
	 *  DynDNS Dynamic  - Last Tested: 12 July 2005
84
	 *  DynDNS Static   - Last Tested: NEVER
85
	 *  DynDNS Custom   - Last Tested: NEVER
86
	 *  No-IP           - Last Tested: 20 July 2008
87
	 *  HN.org          - Last Tested: 12 July 2005
88
	 *  EasyDNS         - Last Tested: 20 July 2008
89
	 *  DHS             - Last Tested: 12 July 2005
90
	 *  ZoneEdit        - Last Tested: NEVER
91
	 *  Dyns            - Last Tested: NEVER
92
	 *  ODS             - Last Tested: 02 August 2005
93
	 *  FreeDNS         - Last Tested: 01 May 2016
94
	 *  FreeDNS IPv6    - Last Tested: 01 May 2016
95
	 *  Loopia          - Last Tested: NEVER
96
	 *  StaticCling     - Last Tested: 27 April 2006
97
	 *  DNSexit         - Last Tested: 20 July 2008
98
	 *  OpenDNS         - Last Tested: 4 August 2008
99
	 *  Namecheap       - Last Tested: 31 August 2010
100
	 *  HE.net          - Last Tested: 7 July 2013
101
	 *  HE.net IPv6     - Last Tested: 7 July 2013
102
	 *  HE.net Tunnel   - Last Tested: 28 June 2011
103
	 *  SelfHost        - Last Tested: 26 December 2011
104
	 *  Amazon Route 53 - Last Tested: 04 February 2017
105
	 *  DNS-O-Matic     - Last Tested: 9 September 2010
106
	 *  Cloudflare      - Last Tested: 05 September 2016
107
	 *  Cloudflare IPv6 - Last Tested: 17 July 2016
108
	 *  Eurodns         - Last Tested: 27 June 2013
109
	 *  GratisDNS       - Last Tested: 15 August 2012
110
	 *  OVH DynHOST     - Last Tested: NEVER
111
	 *  City Network    - Last Tested: 13 November 2013
112
	 *  GleSYS          - Last Tested: 3 February 2015
113
	 *  DNSimple        - Last Tested: 09 February 2015
114
	 *  Google Domains  - Last Tested: 27 April 2015
115
	 *  DNS Made Easy   - Last Tested: 27 April 2015
116
	 *  SPDYN           - Last Tested: 02 July 2016
117
	 *  SPDYN IPv6      - Last Tested: 02 July 2016
118
	 *  All-Inkl        - Last Tested: 12 November 2016
119
	 *  DuiaDNS         - Last Tested: 25 November 2016
120
	 *  DuiaDNS IPv6    - Last Tested: 25 November 2016
121
	 *  Hover           - Last Tested: 15 February 2017
122
	 *  DreamHost       - Last Tested: 30 April 2017
123
	 *  DreamHost IPv6  - Not Yet Tested
124
	 *  ClouDNS         - Last Tested: 22 August 2017
125
	 *  GoDaddy         - Last Tested: 22 November 2017
126
	 *  GoDaddy IPv6    - Last Tested: 22 November 2017
127
	 *  DigitalOcean    - Not Yet Tested
128
	 *  Azure DNS       - Last Tested: 08 March 2018
129
	 * +====================================================+
130
	 *
131
	 * @author 	E.Kristensen
132
	 * @link    	http://www.idylldesigns.com/projects/phpdns/
133
	 * @version 	0.8
134
	 * @updated	13 October 05 at 21:02:42 GMT
135
	 *
136
	 * DNSexit/OpenDNS support and multiwan extension for pfSense by Ermal Luçi
137
	 * Custom DNS support by Matt Corallo
138
	 *
139
	 */
140

    
141
	class updatedns {
142
		var $_cacheFile;
143
		var $_cacheFile_v6;
144
		var $_debugFile;
145
		var $_UserAgent = 'phpDynDNS/0.7';
146
		var $_errorVerbosity = 0;
147
		var $_dnsService;
148
		var $_dnsUser;
149
		var $_dnsPass;
150
		var $_dnsHost;
151
		var $_dnsDomain;
152
		var $_FQDN;
153
		var $_dnsIP;
154
		var $_dnsWildcard;
155
		var $_dnsProxied;
156
		var $_dnsMX;
157
		var $_dnsBackMX;
158
		var $_dnsServer;
159
		var $_dnsPort;
160
		var $_dnsUpdateURL;
161
		var $_dnsZoneID;
162
		var $_dnsTTL;
163
		var $status;
164
		var $_debugID;
165
		var $_if;
166
		var $_dnsResultMatch;
167
		var $_dnsRequestIf;
168
		var $_dnsRequestIfIP;
169
		var $_dnsVerboseLog;
170
		var $_curlIpresolveV4;
171
		var $_curlSslVerifypeer;
172
		var $_dnsMaxCacheAgeDays;
173
		var $_dnsDummyUpdateDone;
174
		var $_forceUpdateNeeded;
175
		var $_useIPv6;
176
		var $_existingRecords;
177

    
178
		/*
179
		 * Public Constructor Function (added 12 July 05) [beta]
180
		 *   - Gets the dice rolling for the update.
181
		 *   - $dnsResultMatch should only be used with $dnsService = 'custom'
182
		 *   -  $dnsResultMatch is parsed for '%IP%', which is the IP the provider was updated to,
183
		 *   -  it is otherwise expected to be exactly identical to what is returned by the Provider.
184
		 *   - $dnsUser, and $dnsPass indicate HTTP Auth for custom DNS, if they are needed in the URL (GET Variables), include them in $dnsUpdateURL.
185
		 *   - $For custom requests, $dnsUpdateURL is parsed for '%IP%', which is replaced with the new IP.
186
		 */
187
		function updatedns ($dnsService = '', $dnsHost = '', $dnsDomain = '', $dnsUser = '', $dnsPass = '',
188
					$dnsWildcard = 'OFF', $dnsProxied = false, $dnsMX = '', $dnsIf = '', $dnsBackMX = '',
189
					$dnsServer = '', $dnsPort = '', $dnsUpdateURL = '', $forceUpdate = false,
190
					$dnsZoneID ='', $dnsTTL='', $dnsResultMatch = '', $dnsRequestIf = '',
191
					$dnsID = '', $dnsVerboseLog = false, $curlIpresolveV4 = false, $curlSslVerifypeer = true) {
192

    
193
			global $config, $g, $dyndns_split_domain_types;
194
			if (in_array($dnsService, $dyndns_split_domain_types)) {
195
				$this->_FQDN = $dnsHost . "." . $dnsDomain;
196
			} else {
197
				$this->_FQDN = $dnsHost;
198
			}
199

    
200
			$this->_cacheFile = "{$g['conf_path']}/dyndns_{$dnsIf}{$dnsService}" . escapeshellarg($this->_FQDN) . "{$dnsID}.cache";
201
			$this->_cacheFile_v6 = "{$g['conf_path']}/dyndns_{$dnsIf}{$dnsService}" . escapeshellarg($this->_FQDN) . "{$dnsID}_v6.cache";
202
			$this->_debugFile = "{$g['varetc_path']}/dyndns_{$dnsIf}{$dnsService}" . escapeshellarg($this->_FQDN) . "{$dnsID}.debug";
203

    
204
			$this->_curlIpresolveV4 = $curlIpresolveV4;
205
			$this->_curlSslVerifypeer = $curlSslVerifypeer;
206
			$this->_dnsVerboseLog = $dnsVerboseLog;
207
			if ($this->_dnsVerboseLog) {
208
				log_error(gettext("Dynamic DNS: updatedns() starting"));
209
			}
210

    
211
			$dyndnslck = lock("DDNS".$dnsID, LOCK_EX);
212

    
213
			if (!$dnsService) $this->_error(2);
214
			switch ($dnsService) {
215
			case 'freedns':
216
			case 'freedns-v6':
217
				if (!$dnsHost) $this->_error(5);
218
				break;
219
			case "namecheap":
220
				if (!$dnsPass) $this->_error(4);
221
				if (!$dnsHost) $this->_error(5);
222
				if (!$dnsDomain) $this->_error(5);
223
				break;
224
			case "cloudflare-v6":
225
			case "cloudflare":
226
			case "gratisdns":
227
			case "hover":
228
				if (!$dnsUser) $this->_error(3);
229
				if (!$dnsPass) $this->_error(4);
230
				if (!$dnsHost) $this->_error(5);
231
				if (!$dnsDomain) $this->_error(5);
232
				break;
233
			case 'route53-v6':
234
			case 'route53':
235
				if (!$dnsZoneID) $this->_error(8);
236
				if (!$dnsTTL) $this->_error(9);
237
				break;
238
			case 'cloudns':
239
			case "godaddy":
240
			case "godaddy-v6":
241
				if (!$dnsUser) $this->_error(3);
242
				if (!$dnsPass) $this->_error(4);
243
				if (!$dnsHost) $this->_error(5);
244
				if (!$dnsDomain) $this->_error(5);
245
				if (!$dnsTTL) $this->_error(9);
246
				break;
247
			case 'digitalocean':
248
				if (!$dnsPass) $this->_error(4);
249
				if (!$dnsHost) $this->_error(5);
250
				if (!$dnsDomain) $this->_error(5);
251
				if (!$dnsTTL) $this->_error(9);
252
				break;
253
			case 'azure':
254
			case 'azurev6':
255
				if (!$dnsUser) $this->_error(3);
256
				if (!$dnsPass) $this->_error(4);
257
				if (!$dnsHost) $this->_error(5);
258
				if (!$dnsZoneID) $this->_error(8);
259
				if (!$dnsTTL) $this->_error(9);
260
				break;
261
			case 'custom':
262
				if (!$dnsUpdateURL) $this->_error(7);
263
				break;
264
			default:
265
				if (!$dnsUser) $this->_error(3);
266
				if (!$dnsPass) $this->_error(4);
267
				if (!$dnsHost) $this->_error(5);
268
			}
269

    
270
			switch ($dnsService) {
271
				case 'he-net-v6':
272
				case 'custom-v6':
273
				case 'spdyn-v6':
274
				case 'route53-v6':
275
				case 'duiadns-v6':
276
				case 'freedns-v6':
277
				case 'cloudflare-v6':
278
				case 'dreamhost-v6':
279
				case 'godaddy-v6':
280
				case 'azurev6':
281
					$this->_useIPv6 = true;
282
					break;
283
				default:
284
					$this->_useIPv6 = false;
285
			}
286
			$this->_dnsService = strtolower($dnsService);
287
			$this->_dnsUser = $dnsUser;
288
			$this->_dnsPass = base64_decode($dnsPass);
289
			$this->_dnsHost = $dnsHost;
290
			$this->_dnsDomain = $dnsDomain;
291
			$this->_dnsServer = $dnsServer;
292
			$this->_dnsPort = $dnsPort;
293
			$this->_dnsWildcard = $dnsWildcard;
294
			$this->_dnsProxied = $dnsProxied;
295
			$this->_dnsMX = $dnsMX;
296
			$this->_dnsZoneID = $dnsZoneID;
297
			$this->_dnsTTL = $dnsTTL;
298
			$this->_if = get_failover_interface($dnsIf);
299
			$this->_checkIP();
300
			$this->_dnsUpdateURL = $dnsUpdateURL;
301
			$this->_dnsResultMatch = $dnsResultMatch;
302
			$this->_dnsRequestIf = get_failover_interface($dnsRequestIf);
303
			if ($this->_dnsVerboseLog) {
304
				log_error(sprintf(gettext('Dynamic DNS (%1$s): running get_failover_interface for %2$s. found %3$s'), $this->_FQDN, $dnsRequestIf, $this->_dnsRequestIf));
305
			}
306
			$this->_dnsRequestIfIP = get_interface_ip($dnsRequestIf);
307
			$this->_dnsMaxCacheAgeDays = 25;
308
			$this->_dnsDummyUpdateDone = false;
309
			$this->_forceUpdateNeeded = $forceUpdate;
310

    
311
			// Ensure that we were able to lookup the IP
312
			if (!is_ipaddr($this->_dnsIP)) {
313
				log_error(sprintf(gettext('Dynamic DNS (%1$s) There was an error trying to determine the public IP for interface - %2$s (%3$s %4$s).'), $this->_FQDN, $dnsIf, $this->_if, $this->_dnsIP));
314
				unlock($dyndnslck);
315
				return;
316
			}
317

    
318
			$this->_debugID = rand(1000000, 9999999);
319

    
320
			if ($forceUpdate == false && $this->_detectChange() == false) {
321
				$this->_error(10);
322
			} else {
323
				switch ($this->_dnsService) {
324
					case 'glesys':
325
					case 'dnsomatic':
326
					case 'dyndns':
327
					case 'dyndns-static':
328
					case 'dyndns-custom':
329
					case 'dhs':
330
					case 'noip':
331
					case 'noip-free':
332
					case 'easydns':
333
					case 'hn':
334
					case 'zoneedit':
335
					case 'dyns':
336
					case 'ods':
337
					case 'freedns':
338
					case 'freedns-v6':
339
					case 'loopia':
340
					case 'staticcling':
341
					case 'dnsexit':
342
					case 'custom':
343
					case 'custom-v6':
344
					case 'opendns':
345
					case 'namecheap':
346
					case 'he-net':
347
					case 'he-net-v6':
348
					case 'duiadns':
349
					case 'duiadns-v6':
350
					case 'selfhost':
351
					case 'he-net-tunnelbroker':
352
					case 'route53':
353
					case 'route53-v6':
354
					case 'cloudflare':
355
					case 'cloudflare-v6':
356
					case 'eurodns':
357
					case 'gratisdns':
358
					case 'ovh-dynhost':
359
					case 'citynetwork':
360
					case 'dnsimple':
361
					case 'googledomains':
362
					case 'dnsmadeeasy':
363
					case 'spdyn':
364
					case 'spdyn-v6':
365
					case 'all-inkl':
366
					case 'cloudns':
367
					case 'hover':
368
					case 'digitalocean':
369
					case 'godaddy':
370
					case 'godaddy-v6':
371
					case  'azure':
372
					case  'azurev6':
373
						$this->_update();
374
						if ($this->_dnsDummyUpdateDone == true) {
375
							// If a dummy update was needed, then sleep a while and do the update again to put the proper address back.
376
							// Some providers (e.g. No-IP free accounts) need to have at least 1 address change every month.
377
							// If the address has not changed recently, or the user did "Force Update", then the code does
378
							// a dummy address change for providers like this.
379
							sleep(10);
380
							$this->_update();
381
						}
382
						break;
383
					case 'dreamhost':
384
					case 'dreamhost-v6':
385
						$this->_lookup_current();
386
						if (isset($this->status)) {
387
							return;
388
						}
389
						foreach ($this->_existingRecords as $record) {
390
							$this->_remove($record['existing_val']);
391
							$this->_update();
392
						}
393
						break;
394
					default:
395
						$this->_error(6);
396
						break;
397
				}
398
			}
399

    
400
			unlock($dyndnslck);
401
		}
402

    
403
		/*
404
		 * Private Function (added 12 July 05) [beta]
405
		 *   Send Update To Selected Service.
406
		 */
407
		function _update() {
408

    
409
			if ($this->_dnsVerboseLog) {
410
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _update() starting.'), $this->_dnsService, $this->_FQDN));
411
			}
412

    
413
			if (strstr($this->_dnsRequestIf, "_vip")) {
414
				$parentif = get_configured_vip_interface($this->_dnsRequestIf);
415
				$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
416
			} else {
417
				$realparentif = $this->_dnsRequestIf;
418
			}
419

    
420
			$ch = curl_init();
421

    
422
			if ($this->_useIPv6 == false) {
423
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
424
			}
425

    
426
			if ($this->_dnsService != 'ods') {
427
				curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
428
				curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
429
				curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
430
				curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
431
			}
432

    
433
			switch ($this->_dnsService) {
434
				case 'glesys':
435
					$needsIP = TRUE;
436
					$server = 'https://api.glesys.com/domain/updaterecord/format/json';
437
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
438
					$post_data['recordid'] = $this->_FQDN;
439
					$post_data['data'] = $this->_dnsIP;
440
					curl_setopt($ch, CURLOPT_URL, $server);
441
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
442
					break;
443
				case 'dyndns':
444
				case 'dyndns-static':
445
				case 'dyndns-custom':
446
					$needsIP = FALSE;
447
					if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") {
448
						$this->_dnsWildcard = "ON";
449
					}
450
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
451
					$server = "https://members.dyndns.org/nic/update";
452
					$port = "";
453
					if ($this->_dnsServer) {
454
						$server = $this->_dnsServer;
455
					}
456
					if ($this->_dnsPort) {
457
						$port = ":" . $this->_dnsPort;
458
					}
459
					curl_setopt($ch, CURLOPT_URL, $server .$port . '?system=dyndns&hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NO');
460
					break;
461
				case 'dhs':
462
					// DHS is disabled in the GUI because the following doesn't work.
463
					$needsIP = TRUE;
464
					$post_data['hostscmd'] = 'edit';
465
					$post_data['hostscmdstage'] = '2';
466
					$post_data['type'] = '4';
467
					$post_data['updatetype'] = 'Online';
468
					$post_data['mx'] = $this->_dnsMX;
469
					$post_data['mx2'] = '';
470
					$post_data['txt'] = '';
471
					$post_data['offline_url'] = '';
472
					$post_data['cloak'] = 'Y';
473
					$post_data['cloak_title'] = '';
474
					$post_data['ip'] = $this->_dnsIP;
475
					$post_data['domain'] = 'dyn.dhs.org';
476
					$post_data['hostname'] = $this->_dnsHost;
477
					$post_data['submit'] = 'Update';
478
					$server = "https://members.dhs.org/nic/hosts";
479
					$port = "";
480
					if ($this->_dnsServer) {
481
						$server = $this->_dnsServer;
482
					}
483
					if ($this->_dnsPort) {
484
						$port = ":" . $this->_dnsPort;
485
					}
486
					curl_setopt($ch, CURLOPT_URL, $server . $port);
487
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
488
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
489
					break;
490
				case 'noip':
491
				case 'noip-free':
492
					$needsIP = TRUE;
493
					$server = "https://dynupdate.no-ip.com/ducupdate.php";
494
					$port = "";
495
					if ($this->_dnsServer) {
496
						$server = $this->_dnsServer;
497
					}
498
					if ($this->_dnsPort) {
499
						$port = ":" . $this->_dnsPort;
500
					}
501
					if (($this->_dnsService == "noip-free") &&
502
					    ($this->_forceUpdateNeeded == true) &&
503
					    ($this->_dnsDummyUpdateDone == false)) {
504
						// Update the IP to a dummy value to force No-IP free accounts to see a change.
505
						$iptoset = "192.168.1.1";
506
						$this->_dnsDummyUpdateDone = true;
507
						log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): Processing dummy update on No-IP free account. IP temporarily set to %3$s'), $this->_dnsService, $this->_dnsHost, $iptoset));
508
					} else {
509
						$iptoset = $this->_dnsIP;
510
					}
511
					curl_setopt($ch, CURLOPT_URL, $server . $port . '?username=' . urlencode($this->_dnsUser) . '&pass=' . urlencode($this->_dnsPass) . '&h[]=' . $this->_dnsHost.'&ip=' . $iptoset);
512
					break;
513
				case 'easydns':
514
					$needsIP = TRUE;
515
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
516
					$server = "https://members.easydns.com/dyn/dyndns.php";
517
					$port = "";
518
					if ($this->_dnsServer) {
519
						$server = $this->_dnsServer;
520
					}
521
					if ($this->_dnsPort) {
522
						$port = ":" . $this->_dnsPort;
523
					}
524
					curl_setopt($ch, CURLOPT_URL, $server . $port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard=' . $this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=' . $this->_dnsBackMX);
525
					break;
526
				case 'hn':
527
					$needsIP = TRUE;
528
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
529
					$server = "http://dup.hn.org/vanity/update";
530
					$port = "";
531
					if ($this->_dnsServer) {
532
						$server = $this->_dnsServer;
533
					}
534
					if ($this->_dnsPort) {
535
						$port = ":" . $this->_dnsPort;
536
					}
537
					curl_setopt($ch, CURLOPT_URL, $server . $port . '?ver=1&IP=' . $this->_dnsIP);
538
					break;
539
				case 'zoneedit':
540
					$needsIP = FALSE;
541
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
542

    
543
					$server = "https://dynamic.zoneedit.com/auth/dynamic.html";
544
					$port = "";
545
					if ($this->_dnsServer) {
546
						$server = $this->_dnsServer;
547
					}
548
					if ($this->_dnsPort) {
549
						$port = ":" . $this->_dnsPort;
550
					}
551
					curl_setopt($ch, CURLOPT_URL, "{$server}{$port}?host=" . $this->_dnsHost . '&dnsto=' . $this->_dnsIP);
552
					break;
553
				case 'dyns':
554
					$needsIP = FALSE;
555
					$server = "http://www.dyns.net/postscript011.php";
556
					$port = "";
557
					if ($this->_dnsServer) {
558
						$server = $this->_dnsServer;
559
					}
560
					if ($this->_dnsPort) {
561
						$port = ":" . $this->_dnsPort;
562
					}
563
					curl_setopt($ch, CURLOPT_URL, $server . $port . '?username=' . urlencode($this->_dnsUser) . '&password=' . $this->_dnsPass . '&host=' . $this->_dnsHost);
564
					break;
565
				case 'ods':
566
					$needsIP = FALSE;
567
					$misc_errno = 0;
568
					$misc_error = "";
569
					$server = "ods.org";
570
					$port = "";
571
					if ($this->_dnsServer) {
572
						$server = $this->_dnsServer;
573
					}
574
					if ($this->_dnsPort) {
575
						$port = ":" . $this->_dnsPort;
576
					}
577
					$this->con['socket'] = fsockopen("{$server}{$port}", "7070", $misc_errno, $misc_error, 30);
578
					/* Check that we have connected */
579
					if (!$this->con['socket']) {
580
						print "error! could not connect.";
581
						break;
582
					}
583
					/* Here is the loop. Read the incoming data (from the socket connection) */
584
					while (!feof($this->con['socket'])) {
585
						$this->con['buffer']['all'] = trim(fgets($this->con['socket'], 4096));
586
						$code = substr($this->con['buffer']['all'], 0, 3);
587
						sleep(1);
588
						switch ($code) {
589
							case 100:
590
								fputs($this->con['socket'], "LOGIN ".$this->_dnsUser." ".$this->_dnsPass."\n");
591
								break;
592
							case 225:
593
								fputs($this->con['socket'], "DELRR ".$this->_dnsHost." A\n");
594
								break;
595
							case 901:
596
								fputs($this->con['socket'], "ADDRR ".$this->_dnsHost." A ".$this->_dnsIP."\n");
597
								break;
598
							case 795:
599
								fputs($this->con['socket'], "QUIT\n");
600
								break;
601
						}
602
					}
603
					$this->_checkStatus(0, $code);
604
					break;
605
				case 'freedns':
606
				case 'freedns-v6':
607
					$needIP = TRUE;
608
					curl_setopt($ch, CURLOPT_URL, 'https://freedns.afraid.org/dynamic/update.php?' . $this->_dnsPass . '&address=' . $this->_dnsIP);
609
					break;
610
				case 'dnsexit':
611
					$needsIP = TRUE;
612
					curl_setopt($ch, CURLOPT_URL, 'https://www.dnsexit.com/RemoteUpdate.sv?login='.$this->_dnsUser. '&password='.$this->_dnsPass.'&host='.$this->_dnsHost.'&myip='.$this->_dnsIP);
613
					break;
614
				case 'loopia':
615
					$needsIP = TRUE;
616
					if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") $this->_dnsWildcard = "ON";
617
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
618
					curl_setopt($ch, CURLOPT_URL, 'https://dns.loopia.se/XDynDNSServer/XDynDNS.php?hostname='.$this->_dnsHost.'&myip='.$this->_dnsIP.'&wildcard='.$this->_dnsWildcard);
619
					break;
620
				case 'opendns':
621
					$needsIP = FALSE;
622
					if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") $this->_dnsWildcard = "ON";
623
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
624
					$server = "https://updates.opendns.com/nic/update?hostname=". $this->_dnsHost;
625
					$port = "";
626
					if ($this->_dnsServer) {
627
						$server = $this->_dnsServer;
628
					}
629
					if ($this->_dnsPort) {
630
						$port = ":" . $this->_dnsPort;
631
					}
632
					curl_setopt($ch, CURLOPT_URL, $server .$port);
633
					break;
634

    
635
				case 'staticcling':
636
					$needsIP = FALSE;
637
					curl_setopt($ch, CURLOPT_URL, 'https://www.staticcling.org/update.html?login='.$this->_dnsUser.'&pass='.$this->_dnsPass);
638
					break;
639
				case 'dnsomatic':
640
					/* Example syntax
641
						https://username:password@updates.dnsomatic.com/nic/update?hostname=yourhostname&myip=ipaddress&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG
642
					*/
643
					$needsIP = FALSE;
644
					if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") {
645
						$this->_dnsWildcard = "ON";
646
					}
647
					/*
648
					Reference: https://www.dnsomatic.com/wiki/api
649
						DNS-O-Matic usernames are 3-25 characters.
650
						DNS-O-Matic passwords are 6-20 characters.
651
						All ASCII letters and numbers accepted.
652
						Dots, dashes, and underscores allowed, but not at the beginning or end of the string.
653
					Required: "rawurlencode" http://www.php.net/manual/en/function.rawurlencode.php
654
						Encodes the given string according to RFC 3986.
655
					*/
656
					$server = "https://" . rawurlencode($this->_dnsUser) . ":" . rawurlencode($this->_dnsPass) . "@updates.dnsomatic.com/nic/update?hostname=";
657
					if ($this->_dnsServer) {
658
						$server = $this->_dnsServer;
659
					}
660
					if ($this->_dnsPort) {
661
						$port = ":" . $this->_dnsPort;
662
					}
663
					curl_setopt($ch, CURLOPT_URL, $server . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NOCHG');
664
					break;
665
				case 'namecheap':
666
					/* Example:
667
						https://dynamicdns.park-your-domain.com/update?host=[host_name]&domain=[domain.com]&password=[domain_password]&ip=[your_ip]
668
					*/
669
					$needsIP = FALSE;
670
					$dnspass = trim($this->_dnsPass);
671
					$server = "https://dynamicdns.park-your-domain.com/update?host={$this->_dnsHost}&domain={$this->_dnsDomain}&password={$dnspass}&ip={$this->_dnsIP}";
672
					curl_setopt($ch, CURLOPT_URL, $server);
673
					break;
674
				case 'duiadns':
675
				case 'duiadns-v6':
676
					$needsIP = FALSE;
677
					$server = "https://ipv4.duiadns.net/dyndns.duia?";
678
					curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
679
					curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
680
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser . ':' . $this->_dnsPass);
681
					curl_setopt($ch, CURLOPT_URL, $server . 'hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
682
					break;
683
				case 'he-net':
684
				case 'he-net-v6':
685
					$needsIP = FALSE;
686
					$server = "https://dyn.dns.he.net/nic/update?";
687
					curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
688
					curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
689
					curl_setopt($ch, CURLOPT_URL, $server . 'hostname=' . $this->_dnsHost . '&password=' . $this->_dnsPass . '&myip=' . $this->_dnsIP);
690
					break;
691
				case 'he-net-tunnelbroker':
692
					$needsIP = FALSE;
693
					$server = "https://ipv4.tunnelbroker.net/ipv4_end.php?";
694
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser . ':' . $this->_dnsPass);
695
					curl_setopt($ch, CURLOPT_URL, $server . 'tid=' . $this->_dnsHost);
696
					break;
697
				case 'selfhost':
698
					$needsIP = FALSE;
699
					if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") {
700
						$this->_dnsWildcard = "ON";
701
					}
702
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
703
					$server = "https://carol.selfhost.de/nic/update";
704
					$port = "";
705
					if ($this->_dnsServer) {
706
						$server = $this->_dnsServer;
707
					}
708
					if ($this->_dnsPort) {
709
						$port = ":" . $this->_dnsPort;
710
					}
711
					curl_setopt($ch, CURLOPT_URL, $server .$port . '?system=dyndns&hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NO');
712
					break;
713
				case 'route53':
714
					require_once("r53.class");
715
					$r53 = new Route53($this->_dnsUser, $this->_dnsPass);
716
					$apiurl = $r53->getApiUrl($this->_dnsZoneID);
717
					$xmlreq = $r53->getRequestBody($this->_dnsHost, $this->_dnsIP, $this->_dnsTTL);
718
					$httphead = $r53->getHttpPostHeaders($this->_dnsZoneID, "us-east-1", hash("sha256",$xmlreq));
719
					curl_setopt($ch, CURLOPT_HTTPHEADER, $httphead);
720
					if($this->_dnsVerboseLog){
721
						log_error(sprintf("Sending request to: %s", $apiurl));
722
						foreach($httphead as $hv){
723
							log_error(sprintf("Header: %s", $hv));
724
						}
725
						log_error(sprintf("XMLPOST: %s", $xmlreq));
726
					}
727
					curl_setopt($ch, CURLOPT_URL, $apiurl);
728
					curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlreq);
729
					break;
730
				case 'route53-v6':
731
					require_once("r53.class");
732
					$r53 = new Route53($this->_dnsUser, $this->_dnsPass);
733
					$apiurl = $r53->getApiUrl($this->_dnsZoneID);
734
					$xmlreq = $r53->getRequestBodyV6($this->_dnsHost, $this->_dnsIP, $this->_dnsTTL);
735
					$httphead = $r53->getHttpPostHeaders($this->_dnsZoneID, "us-east-1", hash("sha256",$xmlreq));
736
					curl_setopt($ch, CURLOPT_HTTPHEADER, $httphead);
737
					if($this->_dnsVerboseLog){
738
						log_error(sprintf("Sending request to: %s", $apiurl));
739
						foreach($httphead as $hv){
740
							log_error(sprintf("Header: %s", $hv));
741
						}
742
						log_error(sprintf("XMLPOST: %s", $xmlreq));
743
					}
744
					curl_setopt($ch, CURLOPT_URL, $apiurl);
745
					curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlreq);
746
					break;
747
				case 'custom':
748
				case 'custom-v6':
749
					if (strstr($this->dnsUpdateURL, "%IP%")) {$needsIP = TRUE;} else {$needsIP = FALSE;}
750
					if ($this->_dnsUser != '') {
751
						if ($this->_curlIpresolveV4) {
752
							curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
753
						}
754
						if ($this->_curlSslVerifypeer) {
755
							curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
756
						} else {
757
							curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
758
						}
759
						curl_setopt($ch, CURLOPT_USERPWD, "{$this->_dnsUser}:{$this->_dnsPass}");
760
					}
761
					$server = str_replace("%IP%", $this->_dnsIP, $this->_dnsUpdateURL);
762
					if ($this->_dnsVerboseLog) {
763
						log_error(sprintf(gettext("Sending request to: %s"), $server));
764
					}
765
					curl_setopt($ch, CURLOPT_URL, $server);
766
					break;
767
				case 'cloudflare-v6':
768
				case 'cloudflare':
769
					$this->_FQDN = ltrim($this->_FQDN, '@.');
770
					$isv6 = ($this->_dnsService === 'cloudflare-v6');
771
					$recordType = $isv6 ? "AAAA" : "A";
772
					$needsIP = TRUE;
773
					$dnsServer ='api.cloudflare.com';
774
					$dnsHost = str_replace(' ', '', $this->_dnsHost);
775

    
776
					curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
777
					curl_setopt($ch, CURLOPT_HTTPHEADER, array(
778
						'X-Auth-Email: '.$this->_dnsUser.'',
779
						'X-Auth-Key: '.$this->_dnsPass.'',
780
						'Content-Type: application/json'
781
					));
782

    
783
					// Get zone ID
784
					$getZoneId = "https://{$dnsServer}/client/v4/zones/?name={$this->_dnsDomain}";
785
					curl_setopt($ch, CURLOPT_URL, $getZoneId);
786
					$output = json_decode(curl_exec($ch));
787
					$zone = $output->result[0]->id;
788
					if ($zone) { // If zone ID was found get host ID
789
						$getHostId = "https://{$dnsServer}/client/v4/zones/{$zone}/dns_records?name={$this->_FQDN}&type={$recordType}";
790
						curl_setopt($ch, CURLOPT_URL, $getHostId);
791
						$output = json_decode(curl_exec($ch));
792
						$host = $output->result[0]->id;
793
						if ($host) { // If host ID was found update host
794
							$hostData = array(
795
								"content" => "{$this->_dnsIP}",
796
								"type" => "{$recordType}",
797
								"proxied" => $this->_dnsProxied,
798
								"name" => "{$this->_dnsHost}"
799
							);
800
							$data_json = json_encode($hostData);
801
							$updateHostId = "https://{$dnsServer}/client/v4/zones/{$zone}/dns_records/{$host}";
802
							curl_setopt($ch, CURLOPT_URL, $updateHostId);
803
							curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
804
							curl_setopt($ch, CURLOPT_POSTFIELDS, $data_json);
805
						}
806
					}
807
					break;
808
				case 'eurodns':
809
					$needsIP = TRUE;
810
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
811
					$server = "https://update.eurodyndns.org/update/";
812
					$port = "";
813
					if ($this->_dnsPort) {
814
						$port = ":" . $this->_dnsPort;
815
					}
816
					curl_setopt($ch, CURLOPT_URL, $server .$port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
817
					break;
818
				case 'gratisdns':
819
					$needsIP = TRUE;
820
					$server = "https://ssl.gratisdns.dk/ddns.phtml";
821
					curl_setopt($ch, CURLOPT_URL, $server . '?u=' . $this->_dnsUser . '&p=' . $this->_dnsPass . '&h=' . $this->_dnsHost . '&d=' . $this->_dnsDomain . '&i=' . $this->_dnsIP);
822
					break;
823
				case 'ovh-dynhost':
824
					$needsIP = FALSE;
825
					if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") $this->_dnsWildcard = "ON";
826
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
827
					$server = "https://www.ovh.com/nic/update";
828
					$port = "";
829
					if ($this->_dnsServer) {
830
						$server = $this->_dnsServer;
831
					}
832
					if ($this->_dnsPort) {
833
						$port = ":" . $this->_dnsPort;
834
					}
835
					curl_setopt($ch, CURLOPT_URL, $server .$port . '?system=dyndns&hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NO');
836
					break;
837
				case 'citynetwork':
838
					$needsIP = TRUE;
839
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
840
					$server = 'https://dyndns.citynetwork.se/nic/update';
841
					$port = "";
842
					if ($this->_dnsServer) {
843
						$server = $this->_dnsServer;
844
					}
845
					if ($this->_dnsPort) {
846
						$port = ":" . $this->_dnsPort;
847
					}
848
					curl_setopt($ch, CURLOPT_URL, $server .$port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
849
					break;
850
				case 'dnsimple':
851
					/* Uses DNSimple's v2 REST API
852
					   Requires the Account ID as the username (found in the URL when pull up the domain)
853
					   And an API Token for the password (generated in the User Settings -> API tokens area of the website)
854
					   Piggybacks on Route 53's ZoneID field for the DNSimple record ID to update
855
					   The DNS record MUST exist before it can update since it performs a PATCH operation
856
					   Data sent as JSON over HTTPS */
857
					$needsIP = TRUE;
858
					$server = 'https://api.dnsimple.com/v2/';
859
					curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
860
					curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/json', 'Authorization: Bearer ' . $this->_dnsPass));
861
					curl_setopt($ch, CURLOPT_URL, $server . $this->_dnsUser . '/zones/' . $this->_dnsHost . '/records/' . $this->_dnsZoneID);
862
					curl_setopt($ch, CURLOPT_POSTFIELDS, '{"content":"' . $this->_dnsIP . '","ttl":"' . $this->_dnsTTL . '"}');
863
					break;
864
				case 'godaddy':
865
				case 'godaddy-v6':
866
					/* Uses GoDaddy's REST API
867
					   Requires username and Account API sso-key passed in header
868
					   Data sent as JSON */
869
					$needsIP = TRUE;
870
					$server = 'https://api.godaddy.com/v1/domains/';
871
					$recordType = $this->_useIPv6 ? "AAAA" : "A";
872
					$url = $server  . $this->_dnsDomain . '/records/' . $recordType . '/' . $this->_dnsHost;
873
					$jsondata = '[{"data":"' . $this->_dnsIP . '","ttl":' . $this->_dnsTTL . '}]';
874
					curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
875
					curl_setopt($ch, CURLOPT_HTTPHEADER, array(
876
						'Accept: application/json',
877
						'Content-Type: application/json',
878
						'Authorization: sso-key ' . $this->_dnsUser . ':' . $this->_dnsPass
879
					));
880
					curl_setopt($ch, CURLOPT_URL, $url);
881
					curl_setopt($ch, CURLOPT_POSTFIELDS, $jsondata);
882
					break;
883
				case 'googledomains':
884
					$needsIP = FALSE;
885
					$post_data['username:password'] = $this->_dnsUser . ':' . $this->_dnsPass;
886
					$post_data['hostname'] = $this->_dnsHost;
887
					$post_data['myip'] = $this->_dnsIP;
888
					$post_data['offline'] = 'no';
889
					$server = "https://domains.google.com/nic/update";
890
					$port = "";
891
					curl_setopt($ch, CURLOPT_URL, 'https://domains.google.com/nic/update');
892
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
893
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
894
					break;
895
				case 'dnsmadeeasy':
896
					$needsIP = TRUE;
897
					$server = "https://cp.dnsmadeeasy.com/servlet/updateip";
898
					curl_setopt($ch, CURLOPT_URL, $server . '?username=' . $this->_dnsUser . '&password=' . $this->_dnsPass . '&id=' . $this->_dnsHost . '&ip=' . $this->_dnsIP);
899
					break;
900
				case 'spdyn':
901
				case 'spdyn-v6':
902
					$needsIP = FALSE;
903
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
904
					$server = "https://update.spdyn.de/nic/update";
905
					$port = "";
906
					if ($this->_dnsServer) {
907
						$server = $this->_dnsServer;
908
					}
909
					if ($this->_dnsPort) {
910
						$port = ":" . $this->_dnsPort;
911
					}
912
					curl_setopt($ch, CURLOPT_URL, $server .$port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
913
					break;
914
				case 'all-inkl':
915
					$needsIP = FALSE;
916
					$server = 'https://dyndns.kasserver.com/';
917
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
918
					curl_setopt($ch, CURLOPT_URL, $server . 'myip=' . $this->_dnsIP);
919
					break;
920
				case 'hover':
921
					$needsIP = FALSE;
922
					$port = "";
923
					curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
924
					curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
925

    
926
					//step 1: login to API
927
					$post_data['username'] = $this->_dnsUser;
928
					$post_data['password'] = $this->_dnsPass;
929
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
930
					curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/login");
931
					curl_setopt($ch, CURLOPT_HEADER, 1); //return the full headers to extract the cookies
932
					$output = curl_exec($ch);
933

    
934
					//extract the cookies
935
					preg_match_all("/^Set-cookie: (.*?);/ism", $output, $cookies);
936
					if( count($cookies[1]) > 0 ){
937
						$cookie_data = implode("; ",$cookies[1]);
938
					}
939

    
940
					//step 2: find the id of the A record
941
					$post_data = null;
942
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
943
					curl_setopt($ch, CURLOPT_COOKIE, $cookie_data);
944
					curl_setopt($ch, CURLOPT_HEADER, 0);
945
					curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/dns");
946
					curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
947

    
948
					$output = curl_exec($ch);
949
					preg_match("/^{\"succeeded\":true.*?domain_name\":\"{$this->_dnsDomain}.*?entries.*?{\"id\":\"([^\"]*?)\",\"name\":\"{$this->_dnsHost}\".*?\$/", $output, $hostID);
950
					$hostID = $hostID[1];
951
					preg_match("/^{\"succeeded\":true.*?domain_name\":\"{$this->_dnsDomain}.*?entries.*?{[^\}]*?\"name\":\"{$this->_dnsHost}\".*?content\":\"([^\"]*?)\".*?\$/", $output, $hostIP);
952
					$hostIP = $hostIP[1];
953

    
954
					//step 3: update the IP
955
					if ($hostID) {
956
						curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
957
						curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
958
						curl_setopt($ch, CURLOPT_COOKIE, $cookie_data);
959
						$post_data['content'] = $this->_dnsIP;
960
						curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
961
						curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
962
						curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/dns/{$hostID}");
963
						log_error("HostID:{$hostID}, OldIP:{$hostIP}");
964
					}
965
					break;
966
				case 'dreamhost':
967
				case 'dreamhost-v6':
968
					$needsIP = TRUE;
969
					$isv6 = ($this->_dnsService === 'dreamhost-v6');
970
					$server = 'https://api.dreamhost.com/';
971
					$post_data['key'] = $this->_dnsPass;
972
					$post_data['unique_id'] = uniqid($this->_dnsHost);
973
					$post_data['cmd'] = 'dns-add_record';
974
					$post_data['format'] = 'json';
975
					$post_data['value'] = $this->_dnsIP;
976
					$post_data['record'] = $this->_dnsHost;
977
					$post_data['type'] = $isv6 ? 'AAAA' : 'A';
978
					$post_data['comment'] = "Updated by pfSense:$this->_dnsUser on ".date('c');
979
					$port = "";
980
					if ($this->_dnsServer) {
981
						$server = $this->_dnsServer;
982
					}
983
					if ($this->_dnsPort) {
984
						$port = ":" . $this->_dnsPort;
985
					}
986
					curl_setopt($ch, CURLOPT_URL, $server . $port);
987
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
988
					break;
989
				case 'digitalocean':
990
					// Get record ID
991
					$server = 'https://api.digitalocean.com/v2/domains/';
992
					$url = $server . $this->_dnsDomain . '/records';
993
					curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer {$this->_dnsPass}"));
994
					curl_setopt($ch, CURLOPT_URL, $url);
995
					$output = json_decode(curl_exec($ch));
996
					if (!is_array($output->domain_records)) {
997
						$output->domain_records = array();
998
					}
999
					foreach($output->domain_records as $dnsRecord) {
1000
						if ($this->_dnsHost == $dnsRecord->name) {
1001
							$recordID = $dnsRecord->id;
1002
							break;
1003
						}
1004
					}
1005

    
1006
					// Create/update record
1007
					if ($recordID == null) {
1008
						$url = $server . $this->_dnsDomain . '/records';
1009
					} else {
1010
						$url = $server . $this->_dnsDomain . '/records/' . $recordID;
1011
						curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
1012
					}
1013
					$post_data['type'] = 'A';
1014
					$post_data['ttl'] = $this->_dnsTTL;
1015
					$post_data['name'] = $this->_dnsHost;
1016
					$post_data['data'] = $this->_dnsIP;
1017
					curl_setopt($ch, CURLOPT_URL, $url);
1018
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1019
					break;
1020
				case 'cloudns':
1021
					/* Uses ClouDNS REST API
1022
					   Requires auth-id or sub-auth-id or sub-auth-user */
1023
					// Step 1: Find the Record ID
1024
					$url = 'https://api.cloudns.net/dns/records.json';
1025
					$post_data['auth-id'] = $this->_dnsUser;
1026
					$post_data['auth-password'] = $this->_dnsPass;
1027
					$post_data['domain-name'] = $this->_dnsDomain;
1028
					$post_data['host'] = $this->_dnsHost;
1029
					$post_data['type'] = 'a';
1030
					curl_setopt($ch, CURLOPT_URL, $url);
1031
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1032
					$output = json_decode(curl_exec($ch));
1033
					$recordID = key(get_object_vars($output));
1034

    
1035
					// Step 2: Set the record
1036
					$needsIP = TRUE;
1037
					$url = 'https://api.cloudns.net/dns/mod-record.json';
1038
					$post_data = array();
1039
					$post_data['auth-id'] = $this->_dnsUser;
1040
					$post_data['auth-password'] = $this->_dnsPass;
1041
					$post_data['domain-name'] = $this->_dnsDomain;
1042
					$post_data['record-id'] = $recordID;
1043
					$post_data['host'] = $this->_dnsHost;
1044
					$post_data['record'] = $this->_dnsIP;
1045
					$post_data['ttl'] = $this->_dnsTTL;
1046
					curl_setopt($ch, CURLOPT_URL, $url);
1047
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1048
					break;
1049
			case 'azurev6':
1050
			case 'azure':
1051
				$hostname = "{$this->_dnsHost}";
1052
				$resourceid = trim($this->_dnsZoneID);
1053
				$app_id = $this->_dnsUser;
1054
				$client_secret = $this->_dnsPass;
1055
				$newip = $this->_dnsIP;
1056
				$newttl = $this->_dnsTTL;
1057
					// ensure resourceid starts with / and has no trailing /
1058
				$resourceid = '/' . trim($resourceid, '/');
1059
					// extract subscription id from resource id
1060
				preg_match('/\\/subscriptions\\/(?<sid>[^\\/]*)/', $resourceid, $result);
1061
				$subscriptionid = isset($result['sid']) ? $result['sid'] : '';
1062
				if (isset($result['sid'])) {
1063
					$subscriptionid = $result['sid'];
1064
				} else {
1065
					log_error("Azure subscription id not found in resource id");
1066
					return false;
1067
				}
1068
					// find tenant id from subscription id
1069
				curl_setopt($ch, CURLOPT_URL, "https://management.azure.com/subscriptions/" . $subscriptionid . "?api-version=2016-09-01");
1070
				curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1071
				curl_setopt($ch, CURLOPT_HEADER, 1);
1072
				curl_setopt($ch, CURLOPT_NOBODY, 1);
1073
				$output = curl_exec($ch);
1074
				$pattern = '/Bearer authorization_uri="https:\\/\\/login.windows.net\\/(?<tid>[^"]*)/i';
1075
				preg_match($pattern, $output, $result);
1076
				if (isset($result['tid'])) {
1077
					$tenantid = $result['tid'];
1078
				} else {
1079
					log_error("Tenant ID not found");
1080
					return false;
1081
				}
1082
					// get an bearer token
1083
				curl_setopt($ch, CURLOPT_URL, "https://login.microsoftonline.com/" . $tenantid . "/oauth2/token");
1084
				curl_setopt($ch, CURLOPT_POST, 1);
1085
				$body = "resource=" . urlencode("https://management.core.windows.net/") . "&grant_type=client_credentials&client_id=" . $app_id . "&client_secret=" . urlencode($client_secret);
1086
				curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
1087
				curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1088
				$server_output = curl_exec($ch);
1089
				$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1090
				preg_match("/\"access_token\":\"(?<tok>[^\"]*)\"/", $server_output, $result);
1091
				if (isset($result['tok'])) {
1092
					$bearertoken = $result['tok'];
1093
				} else {
1094
					log_error("no valid bearer token");
1095
					return false;
1096
				}
1097
					// Update the DNS record
1098
				if ($this->_useIPv6) {
1099
					$url = "https://management.azure.com" . $resourceid . "/AAAA/" . $hostname . "?api-version=2017-09-01";
1100
					$body = '{"properties":{"TTL":"' . $newttl . '", "AaaaRecords":[{"ipv6Address":"' . $newip . '"}]}}';
1101
				} else {
1102
					$url = "https://management.azure.com" . $resourceid . "/A/" . $hostname . "?api-version=2017-09-01";
1103
					$body = '{"properties":{"TTL":"' . $newttl . '", "ARecords":[{"ipv4Address":"' . $newip . '"}]}}';
1104
				}
1105
				$request_headers = array();
1106
				$request_headers[] = 'Accept: application/json';
1107
				$request_headers[] = 'Authorization: Bearer ' . $bearertoken;
1108
				$request_headers[] = 'Content-Type: application/json';
1109
				curl_setopt($ch, CURLOPT_URL, $url);
1110
				curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
1111
				curl_setopt($ch, CURLOPT_HTTPHEADER, $request_headers);
1112
				curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
1113
				curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1114
				curl_setopt($ch, CURLOPT_HEADER, 1);
1115
				curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
1116
				break;
1117

    
1118
			default:
1119
				break;
1120
			}
1121
			if ($this->_dnsService != 'ods') {
1122
				curl_setopt($ch, CURLOPT_HEADER, 1);
1123
				$response = curl_exec($ch);
1124
				$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1125
				$header = substr($response, 0, $header_size);
1126
				$data = substr($response, $header_size);
1127
				$this->_checkStatus($ch, $data, $header);
1128
				@curl_close($ch);
1129
			}
1130
		}
1131

    
1132
		/**
1133
		 * Private Function (added 23 Feb 17)
1134
		 *   Send Removal To Selected Service.
1135
		 *
1136
		 *   Some services do not perform an inplace upgrade.  If they do not then the solution
1137
		 *   is to remove the existing record and add a new record.
1138
		 *
1139
		 * @param unknown $existing_ip If required, an existing IP address for the record.
1140
		 */
1141
		function _remove($existing_ip = NULL) {
1142
			$remove_allowed = false;
1143
			if ($this->_dnsVerboseLog) {
1144
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _remove() starting.'), $this->_dnsService, $this->_FQDN));
1145
			}
1146

    
1147
			if (strstr($this->_dnsRequestIf, "_vip")) {
1148
				$parentif = get_configured_vip_interface($this->_dnsRequestIf);
1149
				$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
1150
			} else {
1151
				$realparentif = $this->_dnsRequestIf;
1152
			}
1153

    
1154
			$ch = curl_init();
1155

    
1156
			if ($this->_useIPv6 == false) {
1157
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1158
			}
1159

    
1160
			curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
1161
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
1162
			curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
1163
			curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
1164

    
1165
			switch ($this->_dnsService) {
1166
			case 'dreamhost':
1167
			case 'dreamhost-v6':
1168
				$server = 'https://api.dreamhost.com/';
1169
				$post_data['key'] = $this->_dnsPass;
1170
				$post_data['unique_id'] = uniqid($this->_dnsHost);
1171
				$post_data['cmd'] = 'dns-remove_record';
1172
				$post_data['format'] = 'json';
1173
				$post_data['value'] = $existing_ip;
1174
				$post_data['record'] = $this->_dnsHost;
1175
				$isv6 = ($this->_dnsService === 'dreamhost-v6');
1176
				$post_data['type'] = $isv6 ? 'AAAA' : 'A';
1177
				$port = "";
1178
				if ($this->_dnsServer) {
1179
					$server = $this->_dnsServer;
1180
				}
1181
				if ($this->_dnsPort) {
1182
					$port = ":" . $this->_dnsPort;
1183
				}
1184
				curl_setopt($ch, CURLOPT_URL, $server . $port);
1185
				curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1186
				$remove_allowed = true;
1187
				break;
1188
			default:
1189
				break;
1190
			}
1191
			if ($remove_allowed) {
1192
				curl_setopt($ch, CURLOPT_HEADER, 1);
1193
				$response = curl_exec($ch);
1194
				$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1195
				$header = substr($response, 0, $header_size);
1196
				$data = substr($response, $header_size);
1197
				$this->_checkStatus($ch, $data, $header);
1198
				@curl_close($ch);
1199
			}
1200
		}
1201

    
1202
		/**
1203
		 * Private Function (added 23 Feb 17)
1204
		 * Retrieves current DNS records from an external API source.
1205
		 *
1206
		 * Some services cannot perform new operations without the caller
1207
		 * providing existing record information.
1208
		 */
1209
		function _lookup_current() {
1210
			$lookup_allowed = false;
1211
			if ($this->_dnsVerboseLog) {
1212
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _listCurrent() starting.'), $this->_dnsService, $this->_FQDN));
1213
			}
1214

    
1215
			if (strstr($this->_dnsRequestIf, "_vip")) {
1216
				$parentif = get_configured_vip_interface($this->_dnsRequestIf);
1217
				$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
1218
			} else {
1219
				$realparentif = $this->_dnsRequestIf;
1220
			}
1221

    
1222
			$ch = curl_init();
1223

    
1224
			if ($this->_useIPv6 == false) {
1225
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1226
			}
1227

    
1228
			curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
1229
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
1230
			curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
1231
			curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
1232

    
1233
			switch ($this->_dnsService) {
1234
			case 'dreamhost':
1235
			case 'dreamhost-v6':
1236
				$server = 'https://api.dreamhost.com/';
1237
				$post_data['key'] = $this->_dnsPass;
1238
				$post_data['unique_id'] = uniqid($this->_dnsHost);
1239
				$post_data['cmd'] = 'dns-list_records';
1240
				$post_data['format'] = 'json';
1241
				$port = "";
1242
				if ($this->_dnsServer) {
1243
					$server = $this->_dnsServer;
1244
				}
1245
				if ($this->_dnsPort) {
1246
					$port = ":" . $this->_dnsPort;
1247
				}
1248
				curl_setopt($ch, CURLOPT_URL, $server . $port);
1249
				curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1250
				$lookup_allowed = true;
1251
				break;
1252
			default:
1253
				break;
1254
			}
1255
			if ($lookup_allowed) {
1256
				curl_setopt($ch, CURLOPT_HEADER, 1);
1257
				$response = curl_exec($ch);
1258
				$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1259
				$header = substr($response, 0, $header_size);
1260
				$data = substr($response, $header_size);
1261
				$this->_checkLookupStatus($ch, $data, $header);
1262
				@curl_close($ch);
1263
			}
1264
		}
1265

    
1266
		/*
1267
		 * Private Function (added 23 Feb 17)
1268
		 *   Retrieve Lookup Status from the provided data and/or header
1269
		 */
1270
		function _checkLookupStatus($ch, $data, $header) {
1271
			if ($this->_dnsVerboseLog) {
1272
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkLookupStatus() starting.'), $this->_dnsService, $this->_FQDN));
1273
			}
1274
			$success_str = "(" . gettext("Success") . ") ";
1275
			$error_str = "(" . gettext("Error") . ") ";
1276
			$status_intro = "phpDynDNS ({$this->_dnsHost}): ";
1277

    
1278
			if ($this->_dnsService != 'ods' && @curl_error($ch)) {
1279
				$status = gettext("Curl error occurred:") . " " . curl_error($ch);
1280
				log_error($status);
1281
				$this->status = $status;
1282
				return;
1283
			}
1284
			switch ($this->_dnsService) {
1285
			case 'dreamhost':
1286
			case 'dreamhost-v6':
1287
				$result = json_decode($data,true);
1288
				if($result["result"] != "success") {
1289
					log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1290
					$this->_debug($data);
1291
					return;
1292
				} else {
1293
					foreach($result["data"] as $key => $row) {
1294
						if($row["record"] == $this->_dnsHost &&
1295
								(($row["type"] == "A" && !$this->_useIPv6)
1296
										|| ($row["type"] == "AAAA" && $this->_useIPv6)
1297
								)) {
1298
							if($row["editable"] == 0) {
1299
								log_error($status_intro . "host " . $this->_dnsHost . " is not editable.");
1300
								continue;
1301
							}
1302
							$this->_existingRecords[]=array("record"=>$row["type"], "type"=>$row["type"], "existing_val"=>$row["value"]);
1303
						}
1304
					}
1305
				}
1306
				if (!is_array($this->_existingRecords)){
1307
					if ($this->_dnsVerboseLog) {
1308
						log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkLookupStatus() ending.  No matching records found.'), $this->_dnsService, $this->_FQDN));
1309
					}
1310
				}
1311
				break;
1312
			default:
1313
				break;
1314
			}
1315
		}
1316

    
1317
		/*
1318
		 * Private Function (added 12 July 2005) [beta]
1319
		 *   Retrieve Update Status
1320
		 */
1321
		function _checkStatus($ch, $data, $header) {
1322
			if ($this->_dnsVerboseLog) {
1323
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkStatus() starting.'), $this->_dnsService, $this->_FQDN));
1324
			}
1325
			$successful_update = false;
1326
			$success_str = "(" . gettext("Success") . ") ";
1327
			$error_str = "(" . gettext("Error") . ") ";
1328
			$status_intro = "phpDynDNS ({$this->_dnsHost}): ";
1329

    
1330
			if ($this->_dnsService != 'ods' && @curl_error($ch)) {
1331
				$status = gettext("Curl error occurred:") . " " . curl_error($ch);
1332
				log_error($status);
1333
				$this->status = $status;
1334
				return;
1335
			}
1336
			switch ($this->_dnsService) {
1337
				case 'glesys':
1338
					$status_intro = "GleSYS ({$this->_dnsHost}): ";
1339
					if (preg_match('/Record updated/i', $data)) {
1340
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1341
						$successful_update = true;
1342
					} else {
1343
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1344
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1345
						$this->_debug($data);
1346
					}
1347
					break;
1348
				case 'dnsomatic':
1349
					$status_intro = "DNS-O-Matic ({$this->_dnsHost}): ";
1350
					if (preg_match('/badauth/i', $data)) {
1351
						$status = $status_intro . gettext("The DNS-O-Matic username or password specified are incorrect. No updates will be distributed to services until this is resolved.");
1352
					} else if (preg_match('/notfqdn /i', $data)) {
1353
						$status = $status_intro . gettext("The hostname specified is not a fully-qualified domain name. If no hostnames included, notfqdn will be returned once.");
1354
					} else if (preg_match('/nohost/i', $data)) {
1355
						$status = $status_intro . gettext("The hostname passed could not be matched to any services configured. The service field will be blank in the return code.");
1356
					} else if (preg_match('/numhost/i', $data)) {
1357
						$status = $status_intro . gettext("Up to 20 hosts my be updated. numhost is returned if attempting to update more than 20 or update a round-robin.");
1358
					} else if (preg_match('/abuse/i', $data)) {
1359
						$status = $status_intro . gettext("The hostname is blocked for update abuse.");
1360
					} else if (preg_match('/good/i', $data)) {
1361
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1362
						$successful_update = true;
1363
					} else if (preg_match('/dnserr/i', $data)) {
1364
						$status = $status_intro . gettext("DNS error encountered. Stop updating for 30 minutes.");
1365
					} else {
1366
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1367
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1368
						$this->_debug($data);
1369
					}
1370
					break;
1371
				case 'citynetwork':
1372
					if (preg_match('/notfqdn/i', $data)) {
1373
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1374
					} else if (preg_match('/nohost/i', $data)) {
1375
						$status = $status_intro . $error_str . gettext("No such host");
1376
					} else if (preg_match('/nochg/i', $data)) {
1377
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1378
						$successful_update = true;
1379
					} else if (preg_match('/good/i', $data)) {
1380
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1381
						$successful_update = true;
1382
					} else if (preg_match('/badauth/i', $data)) {
1383
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1384
					} else {
1385
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1386
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1387
						$this->_debug($data);
1388
					}
1389
					break;
1390
				case 'ovh-dynhost':
1391
				case 'dyndns':
1392
					if (preg_match('/notfqdn/i', $data)) {
1393
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1394
					} else if (preg_match('/nochg/i', $data)) {
1395
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1396
						$successful_update = true;
1397
					} else if (preg_match('/good/i', $data)) {
1398
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1399
						$successful_update = true;
1400
					} else if (preg_match('/noauth/i', $data)) {
1401
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1402
					} else {
1403
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1404
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1405
						$this->_debug($data);
1406
					}
1407
					break;
1408
				case 'dyndns-static':
1409
					if (preg_match('/notfqdn/i', $data)) {
1410
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1411
					} else if (preg_match('/nochg/i', $data)) {
1412
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1413
						$successful_update = true;
1414
					} else if (preg_match('/good/i', $data)) {
1415
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1416
						$successful_update = true;
1417
					} else if (preg_match('/noauth/i', $data)) {
1418
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1419
					} else {
1420
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1421
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1422
						$this->_debug($data);
1423
					}
1424
					break;
1425
				case 'dyndns-custom':
1426
					if (preg_match('/notfqdn/i', $data)) {
1427
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1428
					} else if (preg_match('/nochg/i', $data)) {
1429
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1430
						$successful_update = true;
1431
					} else if (preg_match('/good/i', $data)) {
1432
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1433
						$successful_update = true;
1434
					} else if (preg_match('/noauth/i', $data)) {
1435
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1436
					} else {
1437
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1438
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1439
						$this->_debug($data);
1440
					}
1441
					break;
1442
				case 'dhs':
1443
					break;
1444
				case 'noip':
1445
				case 'noip-free':
1446
					list($ip, $code) = explode(":", $data);
1447
					switch ($code) {
1448
						case 0:
1449
							$status = $status_intro . $success_str . gettext("IP address is current, no update performed.");
1450
							$successful_update = true;
1451
							break;
1452
						case 1:
1453
							$status = $status_intro . $success_str . gettext("DNS hostname update successful.");
1454
							$successful_update = true;
1455
							break;
1456
						case 2:
1457
							$status = $status_intro . $error_str . gettext("Hostname supplied does not exist.");
1458
							break;
1459
						case 3:
1460
							$status = $status_intro . $error_str . gettext("Invalid Username.");
1461
							break;
1462
						case 4:
1463
							$status = $status_intro . $error_str . gettext("Invalid Password.");
1464
							break;
1465
						case 5:
1466
							$status = $status_intro . $error_str . gettext("Too many updates sent.");
1467
							break;
1468
						case 6:
1469
							$status = $status_intro . $error_str . gettext("Account disabled due to violation of No-IP terms of service.");
1470
							break;
1471
						case 7:
1472
							$status = $status_intro . $error_str . gettext("Invalid IP. IP Address submitted is improperly formatted or is a private IP address or is on a blacklist.");
1473
							break;
1474
						case 8:
1475
							$status = $status_intro . $error_str . gettext("Disabled / Locked Hostname.");
1476
							break;
1477
						case 9:
1478
							$status = $status_intro . $error_str . gettext("Host updated is configured as a web redirect and no update was performed.");
1479
							break;
1480
						case 10:
1481
							$status = $status_intro . $error_str . gettext("Group supplied does not exist.");
1482
							break;
1483
						case 11:
1484
							$status = $status_intro . $success_str . gettext("DNS group update is successful.");
1485
							$successful_update = true;
1486
							break;
1487
						case 12:
1488
							$status = $status_intro . $success_str . gettext("DNS group is current, no update performed.");
1489
							$successful_update = true;
1490
							break;
1491
						case 13:
1492
							$status = $status_intro . $error_str . gettext("Update client support not available for supplied hostname or group.");
1493
							break;
1494
						case 14:
1495
							$status = $status_intro . $error_str . gettext("Hostname supplied does not have offline settings configured.");
1496
							break;
1497
						case 99:
1498
							$status = $status_intro . $error_str . gettext("Client disabled. Client should exit and not perform any more updates without user intervention.");
1499
							break;
1500
						case 100:
1501
							$status = $status_intro . $error_str . gettext("Client disabled. Client should exit and not perform any more updates without user intervention.");
1502
							break;
1503
						default:
1504
							$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1505
							$this->_debug(gettext("Unknown Response:") . " " . $data);
1506
							break;
1507
					}
1508
					break;
1509
				case 'easydns':
1510
					if (preg_match('/NOACCESS/i', $data)) {
1511
						$status = $status_intro . $error_str . gettext("Authentication Failed: Username and/or Password was Incorrect.");
1512
					} else if (preg_match('/NOSERVICE/i', $data)) {
1513
						$status = $status_intro . $error_str . gettext("No Service: Dynamic DNS Service has been disabled for this domain.");
1514
					} else if (preg_match('/ILLEGAL INPUT/i', $data)) {
1515
						$status = $status_intro . $error_str . gettext("Illegal Input: Self-Explanatory");
1516
					} else if (preg_match('/TOOSOON/i', $data)) {
1517
						$status = $status_intro . $error_str . gettext("Too Soon: Not Enough Time Has Elapsed Since Last Update");
1518
					} else if (preg_match('/NOERROR/i', $data)) {
1519
						$status = $status_intro . $success_str . gettext("IP Updated Successfully!");
1520
						$successful_update = true;
1521
					} else {
1522
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1523
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1524
						$this->_debug($data);
1525
					}
1526
					break;
1527
				case 'hn':
1528
					/* FIXME: add checks */
1529
					break;
1530
				case 'zoneedit':
1531
					if (preg_match('/799/i', $data)) {
1532
						$status = $status_intro . "(" . gettext("Error 799") . ") " . gettext("Update Failed!");
1533
					} else if (preg_match('/700/i', $data)) {
1534
						$status = $status_intro . "(" . gettext("Error 700") . ") " . gettext("Update Failed!");
1535
					} else if (preg_match('/200/i', $data)) {
1536
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1537
						$successful_update = true;
1538
					} else if (preg_match('/201/i', $data)) {
1539
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1540
						$successful_update = true;
1541
					} else {
1542
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1543
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1544
						$this->_debug($data);
1545
					}
1546
					break;
1547
				case 'dyns':
1548
					if (preg_match("/400/i", $data)) {
1549
						$status = $status_intro . $error_str . gettext("Bad Request - The URL was malformed. Required parameters were not provided.");
1550
					} else if (preg_match('/402/i', $data)) {
1551
						$status = $status_intro . $error_str . gettext("Update Too Soon - Attempted to update too quickly since last change.");
1552
					} else if (preg_match('/403/i', $data)) {
1553
						$status = $status_intro . $error_str . gettext("Database Error - There was a server-sided database error.");
1554
					} else if (preg_match('/405/i', $data)) {
1555
						$status = $status_intro . $error_str . sprintf(gettext('Hostname Error - The hostname (%1$s) doesn\'t belong to user (%2$s).'), $this->_dnsHost, $this->_dnsUser);
1556
					} else if (preg_match('/200/i', $data)) {
1557
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1558
						$successful_update = true;
1559
					} else {
1560
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1561
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1562
						$this->_debug($data);
1563
					}
1564
					break;
1565
				case 'ods':
1566
					if (preg_match("/299/i", $data)) {
1567
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1568
						$successful_update = true;
1569
					} else {
1570
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1571
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1572
						$this->_debug($data);
1573
					}
1574
					break;
1575
				case 'freedns':
1576
				case 'freedns-v6':
1577
					if (preg_match("/has not changed./i", $data)) {
1578
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1579
						$successful_update = true;
1580
					} else if (preg_match("/Updated/i", $data)) {
1581
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1582
						$successful_update = true;
1583
					} else {
1584
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1585
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1586
						$this->_debug($data);
1587
					}
1588
					break;
1589
				case 'dnsexit':
1590
					if (preg_match("/is the same/i", $data)) {
1591
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1592
						$successful_update = true;
1593
					} else if (preg_match("/Success/i", $data)) {
1594
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1595
						$successful_update = true;
1596
					} else {
1597
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1598
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1599
						$this->_debug($data);
1600
					}
1601
					break;
1602
				case 'loopia':
1603
					if (preg_match("/nochg/i", $data)) {
1604
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1605
						$successful_update = true;
1606
					} else if (preg_match("/good/i", $data)) {
1607
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1608
						$successful_update = true;
1609
					} else if (preg_match('/badauth/i', $data)) {
1610
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1611
					} else {
1612
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1613
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1614
						$this->_debug($data);
1615
					}
1616
					break;
1617
				case 'opendns':
1618
					if (preg_match('/badauth/i', $data)) {
1619
						$status = $status_intro . $error_str . gettext("Not a valid username or password!");
1620
					} else if (preg_match('/nohost/i', $data)) {
1621
						$status = $status_intro . $error_str . gettext("Hostname specified does not exist.");
1622
						$successful_update = true;
1623
					} else if (preg_match('/good/i', $data)) {
1624
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1625
						$successful_update = true;
1626
					} else if (preg_match('/yours/i', $data)) {
1627
						$status = $status_intro . $error_str . gettext("Hostname specified exists, but not under the username specified.");
1628
					} else if (preg_match('/abuse/i', $data)) {
1629
						$status = $status_intro . $error_str . gettext("Updating too frequently, considered abuse.");
1630
					} else {
1631
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1632
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1633
						$this->_debug($data);
1634
					}
1635
					break;
1636
				case 'staticcling':
1637
					if (preg_match("/invalid ip/i", $data)) {
1638
						$status = $status_intro . $error_str . gettext("Bad Request - The IP provided was invalid.");
1639
					} else if (preg_match('/required info missing/i', $data)) {
1640
						$status = $status_intro . $error_str . gettext("Bad Request - Required parameters were not provided.");
1641
					} else if (preg_match('/invalid characters/i', $data)) {
1642
						$status = $status_intro . $error_str . gettext("Bad Request - Illegal characters in either the username or the password.");
1643
					} else if (preg_match('/bad password/i', $data)) {
1644
						$status = $status_intro . $error_str . gettext("Invalid password.");
1645
					} else if (preg_match('/account locked/i', $data)) {
1646
						$status = $status_intro . $error_str . gettext("This account has been administratively locked.");
1647
					} else if (preg_match('/update too frequent/i', $data)) {
1648
						$status = $status_intro . $error_str . gettext("Updating too frequently.");
1649
					} else if (preg_match('/DB error/i', $data)) {
1650
						$status = $status_intro . $error_str . gettext("Server side error.");
1651
					} else if (preg_match('/success/i', $data)) {
1652
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1653
						$successful_update = true;
1654
					} else {
1655
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1656
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1657
						$this->_debug($data);
1658
					}
1659
					break;
1660
				case 'namecheap':
1661
					$tmp = str_replace("^M", "", $data);
1662
					$ncresponse = @xml2array($tmp);
1663
					if (preg_match("/internal server error/i", $data)) {
1664
						$status = $status_intro . $error_str . gettext("Server side error.");
1665
					} else if (preg_match("/request is badly formed/i", $data)) {
1666
						$status = $status_intro . $error_str . gettext("Badly Formed Request (check the settings).");
1667
					} else if ($ncresponse['interface-response']['ErrCount'] === "0") {
1668
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1669
						$successful_update = true;
1670
					} else if (is_numeric($ncresponse['interface-response']['ErrCount']) && ($ncresponse['interface-response']['ErrCount'] > 0)) {
1671
						$status = $status_intro . $error_str . implode(", ", $ncresponse["interface-response"]["errors"]);
1672
						$successful_update = true;
1673
					} else {
1674
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1675
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1676
						$this->_debug($data);
1677
					}
1678
					break;
1679
				case 'duiadns':
1680
				case 'duiadns-v6':
1681
					if (preg_match("/error/i", $data)) {
1682
						$status = $status_intro . $error_str . gettext("Server side error.");
1683
					} else if (preg_match('/nohost/i', $data)) {
1684
						$status = $status_intro . $error_str . gettext("Bad Request - A hostname was not provided.");
1685
					} else if (preg_match('/badauth/i', $data)) {
1686
						$status = $status_intro . $error_str . gettext("Invalid username or password.");
1687
					} else if (preg_match('/good/i', $data)) {
1688
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1689
						$successful_update = true;
1690
					} else if (preg_match('/nochg/i', $data)) {
1691
						$status = $status_intro . $success_str . gettext("No Change In IP Address.");
1692
						$successful_update = true;
1693
					} else {
1694
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1695
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1696
						$this->_debug($data);
1697
					}
1698
					break;
1699
				case 'he-net':
1700
				case 'he-net-v6':
1701
					if (preg_match("/badip/i", $data)) {
1702
						$status = $status_intro . $error_str . gettext("Bad Request - The IP provided was invalid.");
1703
					} else if (preg_match('/nohost/i', $data)) {
1704
						$status = $status_intro . $error_str . gettext("Bad Request - A hostname was not provided.");
1705
					} else if (preg_match('/badauth/i', $data)) {
1706
						$status = $status_intro . $error_str . gettext("Invalid username or password.");
1707
					} else if (preg_match('/good/i', $data)) {
1708
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1709
						$successful_update = true;
1710
					} else if (preg_match('/nochg/i', $data)) {
1711
						$status = $status_intro . $success_str . gettext("No Change In IP Address.");
1712
						$successful_update = true;
1713
					} else {
1714
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1715
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1716
						$this->_debug($data);
1717
					}
1718
					break;
1719
				case 'he-net-tunnelbroker':
1720
					/*
1721
					-ERROR: Missing parameter(s).
1722
					-ERROR: Invalid API key or password
1723
					-ERROR: Tunnel not found
1724
					-ERROR: Another tunnel exists for this IP.
1725
					-ERROR: This tunnel is already associated with this IP address
1726
					+OK: Tunnel endpoint updated to: x.x.x.x
1727
					*/
1728
					if (preg_match("/Missing parameter/i", $data)) {
1729
						$status = $status_intro . $error_str . gettext("Bad Request - Missing/Invalid Parameters.");
1730
					} else if (preg_match('/Tunnel not found/i', $data)) {
1731
						$status = $status_intro . $error_str . gettext("Bad Request - Invalid Tunnel ID.");
1732
					} else if (preg_match('/Invalid API key or password/i', $data)) {
1733
						$status = $status_intro . $error_str . gettext("Invalid username or password.");
1734
					} else if (preg_match('/OK:/i', $data)) {
1735
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1736
						$successful_update = true;
1737
					} else if (preg_match('/This tunnel is already associated with this IP address/i', $data)) {
1738
						$status = $status_intro . $success_str . gettext("No Change In IP Address.");
1739
						$successful_update = true;
1740
					} else {
1741
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1742
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1743
						$this->_debug($data);
1744
					}
1745
					break;
1746
				case 'selfhost':
1747
					if (preg_match('/notfqdn/i', $data)) {
1748
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1749
					} else if (preg_match('/nochg/i', $data)) {
1750
						$status = $status_intro . $success_str . gettext("No Change In IP Address.");
1751
						$successful_update = true;
1752
					} else if (preg_match('/good/i', $data)) {
1753
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1754
						$successful_update = true;
1755
					} else if (preg_match('/noauth/i', $data)) {
1756
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1757
					} else {
1758
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1759
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1760
						$this->_debug($data);
1761
					}
1762
					break;
1763
				case 'route53':
1764
				case 'route53-v6':
1765
					if(preg_match('/ErrorResponse/', $data)){
1766
						$status = $status_intro . $error_str . gettext("Route53 API call failed");
1767
						log_error(sprintf("error message: %s", $data));
1768
						$status_update = false;
1769
					} else {
1770
						$status = $status_intro . $success_str . gettext("IP address changed successfully");
1771
						$successful_update = true;
1772
					}
1773
					break;
1774
				case 'custom':
1775
				case 'custom-v6':
1776
					$successful_update = false;
1777
					if ($this->_dnsResultMatch == "") {
1778
						$successful_update = true;
1779
					} else {
1780
						$this->_dnsResultMatch = str_replace("%IP%", $this->_dnsIP, $this->_dnsResultMatch);
1781
						$matches = preg_split("/(?<!\\\\)\\|/", $this->_dnsResultMatch);
1782
						foreach ($matches as $match) {
1783
							$match= str_replace("\\|", "|", $match);
1784
							if (strcmp($match, trim($data, "\t\n\r")) == 0) {
1785
								$successful_update = true;
1786
							}
1787
						}
1788
						unset ($matches);
1789
					}
1790
					if ($successful_update == true) {
1791
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1792
					} else {
1793
						$status = $status_intro . $error_str . gettext("Result did not match.") . " [" . $data . "]";
1794
					}
1795
					break;
1796
				case 'cloudflare-v6':
1797
				case 'cloudflare':
1798
					$output = json_decode($data);
1799
					if ($output->result->content === $this->_dnsIP) {
1800
						$status = $status_intro . $success_str . sprintf(gettext('%1$s updated to %2$s'), $this->_dnsHost, $this->_dnsIP);
1801
						$successful_update = true;
1802
					} elseif ($output->errors[0]->code === 9103) {
1803
						$status = $status_intro . $error_str . gettext("Invalid Credentials! Don't forget to use API Key for password field with Cloudflare.");
1804
					} elseif (($output->success) && (!$output->result[0]->id)) {
1805
						$status = $status_intro . $error_str . gettext("Zone or Host ID was not found, check the hostname.");
1806
					} else {
1807
						$status = $status_intro . gettext("UNKNOWN ERROR") . " - " . $output->errors[0]->message;
1808
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1809
					}
1810
					break;
1811
				case 'eurodns':
1812
					if (preg_match('/notfqdn/i', $data)) {
1813
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1814
					} else if (preg_match('/nochg/i', $data)) {
1815
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1816
						$successful_update = true;
1817
					} else if (preg_match('/good/i', $data)) {
1818
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1819
						$successful_update = true;
1820
					} else if (preg_match('/badauth/i', $data)) {
1821
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1822
					} else {
1823
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1824
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1825
						$this->_debug($data);
1826
					}
1827
					break;
1828
				case 'gratisdns':
1829
					if (preg_match('/Forkerte værdier/i', $data)) {
1830
						$status = $status_intro . $error_str . gettext("Wrong values - Update could not be completed.");
1831
					} else if (preg_match('/Bruger login: Bruger eksistere ikke/i', $data)) {
1832
						$status = $status_intro . $error_str . gettext("Unknown username - User does not exist.");
1833
					} else if (preg_match('/Bruger login: 1Fejl i kodeord/i', $data)) {
1834
						$status = $status_intro . $error_str . gettext("Wrong password - Remember password is case sensitive.");
1835
					} else if (preg_match('/Domæne kan IKKE administreres af bruger/i', $data)) {
1836
						$status = $status_intro . $error_str . gettext("User unable to administer the selected domain.");
1837
					} else if (preg_match('/OK/i', $data)) {
1838
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1839
						$successful_update = true;
1840
					} else {
1841
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1842
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1843
						$this->_debug($data);
1844
					}
1845
					break;
1846
				case 'digitalocean':
1847
					if (preg_match("/\s200\sOK/i", $header)) {
1848
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1849
						$successful_update = true;
1850
					} else {
1851
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1852
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1853
						$this->_debug($data);
1854
					}
1855
					break;
1856
				case 'dnsimple':
1857
					/* Responds with HTTP 200 on success.
1858
					   Responds with HTTP 4xx on error.
1859
					   Returns JSON data as body */
1860
;
1861
					if (preg_match("/\s200\sOK/i", $header)) {
1862
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1863
						$successful_update = true;
1864
					} else if (preg_match("/\s4\d\d\s/i", $header)) {
1865
						$arrbody = json_decode($data, true);
1866
						$message = $arrbody['message'] . ".";
1867
						if (isset($arrbody['errors']['content'])) {
1868
							foreach ($arrbody['errors']['content'] as $key => $content) {
1869
								$message .= " " . $content . ".";
1870
							}
1871
						}
1872
						$status = $status_intro . $error_str . $message;
1873
					} else {
1874
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1875
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1876
						$this->_debug($data);
1877
					}
1878
					break;
1879
				case 'godaddy':
1880
				case 'godaddy-v6':
1881
					/* Responds with HTTP 200 on success.
1882
					   Responds with HTTP 4xx or  on error.
1883
					   Returns JSON data as body */
1884
;
1885
					if (preg_match("/\s200\sOK/i", $header)) {
1886
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1887
						$successful_update = true;
1888
					} else if (preg_match("/\s4\d\d\s/i", $header)) {
1889
						$arrbody = json_decode($data, true);
1890
						$message = $arrbody['message'] . ".";
1891
						if (isset($arrbody['fields'])) {
1892
							foreach ($arrbody['fields'] as $error) {
1893
								$message .= " " . $error['path'] . ": " . $error['message'] . ".";
1894
							}
1895
						}
1896
						$status = $status_intro . $error_str . $message;
1897
					} else {
1898
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1899
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1900
						$this->_debug($data);
1901
					}
1902
					break;
1903
				case 'googledomains':
1904
					if (preg_match('/notfqdn/i', $data)) {
1905
						$status = $status_intro . $error_str . gettext("Not A FQDN");
1906
					} else if (preg_match('/nochg/i', $data)) {
1907
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1908
						$successful_update = true;
1909
					} else if (preg_match('/good/i', $data)) {
1910
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1911
						$successful_update = true;
1912
					} else if (preg_match('/badauth/i', $data)) {
1913
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1914
					} else if (preg_match('/nohost/i', $data)) {
1915
						$status = $status_intro . $error_str . gettext("Hostname does not exist or DynDNS not enabled");
1916
					} else if (preg_match('/badagent/i', $data)) {
1917
						$status = $status_intro . $error_str . gettext("Bad request");
1918
					} else if (preg_match('/abuse/i', $data)) {
1919
						$status = $status_intro . $error_str . gettext("Dynamic DNS access has been blocked!");
1920
					} else if (preg_match('/911/i', $data)) {
1921
						$status = $status_intro . $error_str . gettext("Error on Google's end, retry in 5 minutes");
1922
					} else {
1923
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1924
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1925
						$this->_debug($data);
1926
					}
1927
					break;
1928
				case 'dnsmadeeasy':
1929
					switch ($data) {
1930
						case 'success':
1931
							$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1932
							$successful_update = true;
1933
							break;
1934
						case 'error-auth':
1935
							$status = $status_intro . $error_str . gettext("Invalid username or password");
1936
							break;
1937
						case 'error-auth-suspend':
1938
							$status = $status_intro . $error_str . gettext("Account suspended");
1939
							break;
1940
						case 'error-auth-voided':
1941
							$status = $status_intro . $error_str . gettext("Account revoked");
1942
							break;
1943
						case 'error-record-invalid':
1944
							$status = $status_intro . $error_str . gettext("Record does not exist in the system. Unable to update record");
1945
							break;
1946
						case 'error-record-auth':
1947
							$status = $status_intro . $error_str . gettext("User does not have access to this record");
1948
							break;
1949
						case 'error-record-ip-same':
1950
							$status = $status_intro . $success_str . gettext("No Change In IP Address");
1951
							$successful_update = true;
1952
							break;
1953
						case 'error-system':
1954
							$status = $status_intro . $error_str . gettext("General system error recognized by the system");
1955
							break;
1956
						case 'error':
1957
							$status = $status_intro . $error_str . gettext("General system error unrecognized by the system");
1958
							break;
1959
						default:
1960
							$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1961
							log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1962
							$this->_debug($data);
1963
							break;
1964
					}
1965
					break;
1966
				case 'spdyn':
1967
				case 'spdyn-v6':
1968
					if (preg_match('/notfqdn/i', $data)) {
1969
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1970
					} else if (preg_match('/nohost/i', $data)) {
1971
						$status = $status_intro . $error_str . gettext("No such host");
1972
					} else if (preg_match('/nochg/i', $data)) {
1973
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1974
						$successful_update = true;
1975
					} else if (preg_match('/good/i', $data)) {
1976
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1977
						$successful_update = true;
1978
					} else if (preg_match('/badauth/i', $data)) {
1979
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1980
					} else {
1981
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1982
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1983
						$this->_debug($data);
1984
					}
1985
					break;
1986
				case 'all-inkl':
1987
 					if (preg_match('/good\s'.$this->_dnsIP.'/i', $data)) {
1988
							$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1989
 							$successful_update = true;
1990
 					} else if (preg_match('/good/i', $data)) {
1991
						$status = $status_intro . $error_str . gettext("Result did not match.");
1992
					} else if (preg_match("/\s401\sUnauthorized/i", $header)) {
1993
						$status = $status_intro . $error_str . gettext("Invalid username or password");
1994
					}
1995
					else {
1996
							$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1997
							log_error($status_intro . gettext("PAYLOAD:") . " " . $header.$data);
1998
 							$this->_debug($data);
1999
 							$this->_debug($header);
2000
 					}
2001
 					break;
2002
				case 'hover':
2003
					if (preg_match('/succeeded":true/i', $data)) {
2004
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
2005
						$successful_update = true;
2006
					} else {
2007
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
2008
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
2009
						$this->_debug($data);
2010
					}
2011
					break;
2012
				case 'cloudns':
2013
					$result = json_decode($data, true);
2014
					if ($result['status'] == 'Success') {
2015
						$successful_update = true;
2016
					} else {
2017
						log_error($result['status'] . "(" . $result['statusDescription'] . ")");
2018
					}
2019
					break;
2020
				case 'dreamhost':
2021
				case 'dreamhost-v6':
2022
					$result = json_decode($data,true);
2023
					if ($this->_dnsVerboseLog) {
2024
						log_error(sprintf(gettext('_checkStatus() results: %1$s'), $data));
2025
					}
2026
					switch ($result['data']) {
2027
					case 'success':
2028
					case 'record_added':
2029
					case 'record_removed':
2030
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
2031
						$successful_update = true;
2032
						break;
2033
					case 'no_record':
2034
					case 'no_such_record ':
2035
						$status = $status_intro . $error_str . gettext("No record exists.");
2036
						break;
2037
					case 'no_type':
2038
					case 'no_such_type ':
2039
						$status = $status_intro . $error_str . gettext("No type exists.");
2040
						break;
2041
					case 'no_value':
2042
					case 'no_such_value ':
2043
						$status = $status_intro . $error_str . gettext("No value exists.");
2044
						break;
2045
					case 'no_such_zone':
2046
						$status = $status_intro . $error_str . gettext("No such zone exists.");
2047
						break;
2048
					case 'invalid_record':
2049
						$status = $status_intro . $error_str . gettext("The specified record is invalid.");
2050
						break;
2051
					case 'invalid_type':
2052
						$status = $status_intro . $error_str . gettext("The specified type is invalid.");
2053
						break;
2054
					case 'invalid_value':
2055
						$status = $status_intro . $error_str . gettext("The specified value is invalid.");
2056
						break;
2057
					case 'not_editable ':
2058
						$status = $status_intro . $error_str . gettext("Record is not editable.");
2059
						break;
2060
					case 'record_already_exists_not_editable':
2061
						$status = $status_intro . $error_str . gettext("Record exists but is not editable.");
2062
						break;
2063
					case 'record_already_exists_remove_first':
2064
						$status = $status_intro . $error_str . gettext("Record exists and must be removed before adding.");
2065
						break;
2066
					case 'internal_error_updating_zone':
2067
						$status = $status_intro . $error_str . gettext("A remote server error occurred updating the zone.");
2068
						break;
2069
					case 'internal_error_could_not_load_zone':
2070
						$status = $status_intro . $error_str . gettext("A remote server error occurred loading the zone.");
2071
						break;
2072
					case 'internal_error_could_not_update_zone':
2073
						$status = $status_intro . $error_str . gettext("A remote server error occurred updating the zone.");
2074
						break;
2075
					case 'internal_error_could_not_add_record':
2076
						$status = $status_intro . $error_str . gettext("A remote server error occurred adding a new record.");
2077
						break;
2078
					case 'internal_error_could_not_destroy_record ':
2079
						$status = $status_intro . $error_str . gettext("A remote server error occurred removing an existing record.");
2080
						break;
2081
					default:
2082
						break;
2083
					}
2084
				case 'azure':
2085
				case 'azurev6':
2086
					$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2087
					if ($http_code == 401) {
2088
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
2089
					} else if ($http_code == 201) {
2090
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
2091
						$successful_update = true;
2092
					} else if ($http_code == 200) {
2093
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
2094
						$successful_update = true;
2095
					} else {
2096
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
2097
						log_error($status_intro . gettext("PAYLOAD:") . " " . $http_code);
2098
						$this->_debug($data);
2099
					}
2100
					break;
2101
				default:
2102
					break;
2103
			}
2104

    
2105
			if ($successful_update == true) {
2106
				/* Write WAN IP to cache file */
2107
				$wan_ip = $this->_checkIP();
2108
				if ($this->_useIPv6 == false && $wan_ip > 0) {
2109
					$currentTime = time();
2110
					notify_all_remote(sprintf(gettext('DynDNS updated IP Address on %1$s (%2$s) to %3$s'), convert_real_interface_to_friendly_descr($this->_if), $this->_if, $wan_ip));
2111
					log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $this->_cacheFile, $wan_ip));
2112
					@file_put_contents($this->_cacheFile, "{$wan_ip}|{$currentTime}");
2113
				} else {
2114
					@unlink($this->_cacheFile);
2115
				}
2116
				if ($this->_useIPv6 == true && $wan_ip > 0) {
2117
					$currentTime = time();
2118
					notify_all_remote(sprintf(gettext('DynDNS updated IPv6 Address on %1$s (%2$s) to %3$s'), convert_real_interface_to_friendly_descr($this->_if), $this->_if, $wan_ip));
2119
					log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $this->_cacheFile_v6, $wan_ip));
2120
					@file_put_contents($this->_cacheFile_v6, "{$wan_ip}|{$currentTime}");
2121
				} else {
2122
					@unlink($this->_cacheFile_v6);
2123
				}
2124
			}
2125
			$this->status = $status;
2126
			log_error($status);
2127
		}
2128

    
2129
		/*
2130
		 * Private Function (added 12 July 05) [beta]
2131
		 *   Return Error, Set Last Error, and Die.
2132
		 */
2133
		function _error($errorNumber = '1') {
2134
			$err_str = 'phpDynDNS: (' . gettext('ERROR!') . ') ';
2135
			$err_str_r53 = 'Route 53: (' . gettext('Error') . ') ';
2136
			switch ($errorNumber) {
2137
				case 0:
2138
					break;
2139
				case 2:
2140
					$error = $err_str . gettext('No Dynamic DNS Service provider was selected.');
2141
					break;
2142
				case 3:
2143
					$error = $err_str . gettext('No Username Provided.');
2144
					break;
2145
				case 4:
2146
					$error = $err_str . gettext('No Password Provided.');
2147
					break;
2148
				case 5:
2149
					$error = $err_str . gettext('No Hostname Provided.');
2150
					break;
2151
				case 6:
2152
					$error = $err_str . gettext('The Dynamic DNS Service provided is not yet supported.');
2153
					break;
2154
				case 7:
2155
					$error = $err_str . gettext('No Update URL Provided.');
2156
					break;
2157
				case 8:
2158
					$status = $err_str_r53 . gettext("Invalid ZoneID");
2159
					break;
2160
				case 9:
2161
					$status = $err_str_r53 . gettext("Invalid TTL");
2162
					break;
2163
				case 10:
2164
					$error = "phpDynDNS ({$this->_FQDN}): " . sprintf(gettext("No change in my IP address and/or %s days has not passed. Not updating dynamic DNS entry."), $this->_dnsMaxCacheAgeDays);
2165
					break;
2166
				default:
2167
					$error = $err_str . gettext('Unknown Response.');
2168
					/* FIXME: $data isn't in scope here */
2169
					/* $this->_debug($data); */
2170
					break;
2171
			}
2172
			$this->lastError = $error;
2173
			log_error($error);
2174
		}
2175

    
2176
		/*
2177
		 * Private Function (added 12 July 05) [beta]
2178
		 *   - Detect whether or not IP needs to be updated.
2179
		 *      | Written Specifically for pfSense (https://www.pfsense.org) may
2180
		 *      | work with other systems. pfSense base is FreeBSD.
2181
		 */
2182
		function _detectChange() {
2183
			global $debug;
2184

    
2185
			if ($debug) {
2186
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _detectChange() starting.'), $this->_dnsService, $this->_FQDN));
2187
			}
2188

    
2189
			$currentTime = time();
2190

    
2191
			$wan_ip = $this->_checkIP();
2192
			if ($wan_ip == 0) {
2193
				log_error(sprintf(gettext("Dynamic Dns (%s): Current WAN IP could not be determined, skipping update process."), $this->_FQDN));
2194
				return false;
2195
			}
2196
			$log_error = sprintf(gettext('Dynamic Dns (%1$s): Current WAN IP: %2$s'), $this->_FQDN, $wan_ip) . " ";
2197

    
2198
			if ($this->_useIPv6 == true) {
2199
				if (file_exists($this->_cacheFile_v6)) {
2200
					$contents = file_get_contents($this->_cacheFile_v6);
2201
					list($cacheIP, $cacheTime) = explode('|', $contents);
2202
					$this->_debug($cacheIP.'/'.$cacheTime);
2203
					$initial = false;
2204
					$log_error .= sprintf(gettext("Cached IPv6: %s"), $cacheIP);
2205
				} else {
2206
					$cacheIP = '::';
2207
					@file_put_contents($this->_cacheFile, "::|{$currentTime}");
2208
					$cacheTime = $currentTime;
2209
					$initial = true;
2210
					$log_error .= gettext("No Cached IPv6 found.");
2211
				}
2212
			} else {
2213
				if (file_exists($this->_cacheFile)) {
2214
					$contents = file_get_contents($this->_cacheFile);
2215
					list($cacheIP, $cacheTime) = explode('|', $contents);
2216
					$this->_debug($cacheIP.'/'.$cacheTime);
2217
					$initial = false;
2218
					$log_error .= sprintf(gettext("Cached IP: %s"), $cacheIP);
2219
				} else {
2220
					$cacheIP = '0.0.0.0';
2221
					@file_put_contents($this->_cacheFile, "0.0.0.0|{$currentTime}");
2222
					$cacheTime = $currentTime;
2223
					$initial = true;
2224
					$log_error .= gettext("No Cached IP found.");
2225
				}
2226
			}
2227
			if ($this->_dnsVerboseLog) {
2228
				log_error($log_error);
2229
			}
2230

    
2231
			// Convert seconds = days * hr/day * min/hr * sec/min
2232
			$maxCacheAgeSecs = $this->_dnsMaxCacheAgeDays * 24 * 60 * 60;
2233

    
2234
			$needs_updating = FALSE;
2235
			/* lets determine if the item needs updating */
2236
			if ($cacheIP != $wan_ip) {
2237
				$needs_updating = true;
2238
				$update_reason = gettext("Dynamic Dns: cacheIP != wan_ip. Updating.") . " ";
2239
				$update_reason .= sprintf(gettext('Cached IP: %1$s WAN IP: %2$s'), $cacheIP, $wan_ip) . " ";
2240
			}
2241
			if (($currentTime - $cacheTime) > $maxCacheAgeSecs) {
2242
				$needs_updating = true;
2243
				$this->_forceUpdateNeeded = true;
2244
				$update_reason = sprintf(gettext("Dynamic Dns: More than %s days. Updating."), $this->_dnsMaxCacheAgeDays);
2245
				$update_reason .= " {$currentTime} - {$cacheTime} > {$maxCacheAgeSecs} ";
2246
			}
2247
			if ($initial == true) {
2248
				$needs_updating = true;
2249
				$update_reason .= gettext("Initial update.");
2250
			}
2251

    
2252
			/*   finally if we need updating then store the
2253
			 *   new cache value and return true
2254
			 */
2255
			if ($needs_updating == true) {
2256
				if ($this->_dnsVerboseLog) {
2257
					log_error("DynDns ({$this->_FQDN}): {$update_reason}");
2258
				}
2259
				return true;
2260
			}
2261

    
2262
			return false;
2263
		}
2264

    
2265
		/*
2266
		 * Private Function (added 16 July 05) [beta]
2267
		 *   - Writes debug information to a file.
2268
		 *   - This function is only called when a unknown response
2269
		 *   - status is returned from a DynDNS service provider.
2270
		 */
2271
		function _debug($data) {
2272
			global $g;
2273

    
2274
			if (!$g['debug']) {
2275
				return;
2276
			}
2277
			$string = date('m-d-y h:i:s').' - ('.$this->_debugID.') - ['.$this->_dnsService.'] - '.$data."\n";
2278
			$file = fopen($this->_debugFile, 'a');
2279
			fwrite($file, $string);
2280
			fclose($file);
2281
		}
2282
		function _checkIP() {
2283
			global $debug;
2284

    
2285
			if ($debug) {
2286
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkIP() starting.'), $this->_dnsService, $this->_FQDN));
2287
			}
2288

    
2289
			if ($this->_useIPv6 == true) {
2290
				$ip_address = get_interface_ipv6($this->_if);
2291
				if (!is_ipaddrv6($ip_address)) {
2292
					return 0;
2293
				}
2294
			} else {
2295
				$ip_address = dyndnsCheckIP($this->_if);
2296
				if (!is_ipaddr($ip_address)) {
2297
					return 0;
2298
				}
2299
			}
2300
			if ($this->_useIPv6 == false && is_private_ip(get_interface_ip($this->_if))) {
2301
				if (is_ipaddr($ip_address)) {
2302
					if ($this->_dnsVerboseLog) {
2303
						log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): %3$s extracted from Check IP Service'), $this->_dnsService, $this->_FQDN, $ip_address));
2304
					}
2305
				} else {
2306
					log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): IP address could not be extracted from Check IP Service'), $this->_dnsService, $this->_FQDN));
2307
					return 0;
2308
				}
2309
			} else {
2310
				if ($this->_dnsVerboseLog) {
2311
					log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): %3$s extracted from local system.'), $this->_dnsService, $this->_FQDN, $ip_address));
2312
				}
2313
			}
2314
			$this->_dnsIP = $ip_address;
2315

    
2316
			return $ip_address;
2317
		}
2318

    
2319
	}
2320

    
2321
?>
(15-15/60)