Project

General

Profile

Download (100 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
	 *    - Gandi LiveDNS (www.gandi.net)
53
	 *    - GratisDNS (gratisdns.dk)
54
	 *    - City Network (citynetwork.se)
55
	 *    - GleSYS (glesys.com)
56
	 *    - DNSimple (dnsimple.com)
57
	 *    - Google Domains (domains.google.com)
58
	 *    - DNS Made Easy (www.dnsmadeeasy.com)
59
	 *    - SPDYN (spdyn.de)
60
	 *    - SPDYN IPv6 (spdyn.de)
61
	 *    - All-Inkl (all-inkl.com)
62
	 *    - DuiaDNS (www.duiadns.net)
63
	 *    - DuiaDNS IPv6 (www.duiadns.net)
64
	 *    - Hover (www.hover.com)
65
	 *    - DreamHost DNS (www.dreamhost.com)
66
	 *    - ClouDNS (www.cloudns.net)
67
	 *    - GoDaddy (www.godaddy.com)
68
	 *    - Azure DNS (azure.microsoft.com)
69
	 * +----------------------------------------------------+
70
	 *  Requirements:
71
	 *    - PHP version 4.0.2 or higher with the CURL Library and the PCRE Library
72
	 * +----------------------------------------------------+
73
	 *  Public Functions
74
	 *    - updatedns()
75
	 *
76
	 *  Private Functions
77
	 *    - _update()
78
	 *    - _checkStatus()
79
	 *    - _error()
80
	 *    - _detectChange()
81
	 *    - _debug()
82
	 *    - _checkIP()
83
	 * +----------------------------------------------------+
84
	 *  DynDNS Dynamic  - Last Tested: 12 July 2005
85
	 *  DynDNS Static   - Last Tested: NEVER
86
	 *  DynDNS Custom   - Last Tested: NEVER
87
	 *  No-IP           - Last Tested: 20 July 2008
88
	 *  HN.org          - Last Tested: 12 July 2005
89
	 *  EasyDNS         - Last Tested: 20 July 2008
90
	 *  DHS             - Last Tested: 12 July 2005
91
	 *  ZoneEdit        - Last Tested: NEVER
92
	 *  Dyns            - Last Tested: NEVER
93
	 *  ODS             - Last Tested: 02 August 2005
94
	 *  FreeDNS         - Last Tested: 01 May 2016
95
	 *  FreeDNS IPv6    - Last Tested: 01 May 2016
96
	 *  Loopia          - Last Tested: NEVER
97
	 *  StaticCling     - Last Tested: 27 April 2006
98
	 *  DNSexit         - Last Tested: 20 July 2008
99
	 *  OpenDNS         - Last Tested: 4 August 2008
100
	 *  Namecheap       - Last Tested: 31 August 2010
101
	 *  HE.net          - Last Tested: 7 July 2013
102
	 *  HE.net IPv6     - Last Tested: 7 July 2013
103
	 *  HE.net Tunnel   - Last Tested: 28 June 2011
104
	 *  SelfHost        - Last Tested: 26 December 2011
105
	 *  Amazon Route 53 - Last Tested: 04 February 2017
106
	 *  DNS-O-Matic     - Last Tested: 9 September 2010
107
	 *  Cloudflare      - Last Tested: 05 September 2016
108
	 *  Cloudflare IPv6 - Last Tested: 17 July 2016
109
	 *  Eurodns         - Last Tested: 27 June 2013
110
	 *  GratisDNS       - Last Tested: 15 August 2012
111
	 *  OVH DynHOST     - Last Tested: NEVER
112
	 *  City Network    - Last Tested: 13 November 2013
113
	 *  GleSYS          - Last Tested: 3 February 2015
114
	 *  DNSimple        - Last Tested: 09 February 2015
115
	 *  Google Domains  - Last Tested: 27 April 2015
116
	 *  DNS Made Easy   - Last Tested: 27 April 2015
117
	 *  SPDYN           - Last Tested: 02 July 2016
118
	 *  SPDYN IPv6      - Last Tested: 02 July 2016
119
	 *  All-Inkl        - Last Tested: 12 November 2016
120
	 *  DuiaDNS         - Last Tested: 25 November 2016
121
	 *  DuiaDNS IPv6    - Last Tested: 25 November 2016
122
	 *  Hover           - Last Tested: 15 February 2017
123
	 *  DreamHost       - Last Tested: 30 April 2017
124
	 *  DreamHost IPv6  - Not Yet Tested
125
	 *  ClouDNS         - Last Tested: 22 August 2017
126
	 *  GoDaddy         - Last Tested: 22 November 2017
127
	 *  GoDaddy IPv6    - Last Tested: 22 November 2017
128
	 *  DigitalOcean    - Not Yet Tested
129
	 *  Azure DNS       - Last Tested: 08 March 2018
130
	 *  Gandi LiveDNS   - Not Yet Tested
131
	 * +====================================================+
132
	 *
133
	 * @author 	E.Kristensen
134
	 * @link    	http://www.idylldesigns.com/projects/phpdns/
135
	 * @version 	0.8
136
	 * @updated	13 October 05 at 21:02:42 GMT
137
	 *
138
	 * DNSexit/OpenDNS support and multiwan extension for pfSense by Ermal Luçi
139
	 * Custom DNS support by Matt Corallo
140
	 *
141
	 */
142

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

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

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

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

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

    
213
			$dyndnslck = lock("DDNS".$dnsID, LOCK_EX);
214

    
215
			if (!$dnsService) $this->_error(2);
216
			switch ($dnsService) {
217
			case 'freedns':
218
			case 'freedns-v6':
219
				if (!$dnsHost) $this->_error(5);
220
				break;
221
			case "namecheap":
222
				if (!$dnsPass) $this->_error(4);
223
				if (!$dnsHost) $this->_error(5);
224
				if (!$dnsDomain) $this->_error(5);
225
				break;
226
			case "cloudflare-v6":
227
			case "cloudflare":
228
			case "gratisdns":
229
			case "hover":
230
				if (!$dnsUser) $this->_error(3);
231
				if (!$dnsPass) $this->_error(4);
232
				if (!$dnsHost) $this->_error(5);
233
				if (!$dnsDomain) $this->_error(5);
234
				break;
235
			case 'route53-v6':
236
			case 'route53':
237
				if (!$dnsZoneID) $this->_error(8);
238
				if (!$dnsTTL) $this->_error(9);
239
				break;
240
			case 'cloudns':
241
			case "godaddy":
242
			case "godaddy-v6":
243
				if (!$dnsUser) $this->_error(3);
244
				if (!$dnsPass) $this->_error(4);
245
				if (!$dnsHost) $this->_error(5);
246
				if (!$dnsDomain) $this->_error(5);
247
				if (!$dnsTTL) $this->_error(9);
248
				break;
249
			case 'digitalocean':
250
			case 'digitalocean-v6':
251
			case 'linode':
252
			case 'linode-v6':
253
				if (!$dnsPass) $this->_error(4);
254
				if (!$dnsHost) $this->_error(5);
255
				if (!$dnsDomain) $this->_error(5);
256
				if (!$dnsTTL) $this->_error(9);
257
				break;
258
			case 'azure':
259
			case 'azurev6':
260
				if (!$dnsUser) $this->_error(3);
261
				if (!$dnsPass) $this->_error(4);
262
				if (!$dnsHost) $this->_error(5);
263
				if (!$dnsZoneID) $this->_error(8);
264
				if (!$dnsTTL) $this->_error(9);
265
				break;
266
			case 'gandi-livedns': // NOTE: same as digitalocean
267
				if (!$dnsPass) $this->_error(4);//API key
268
				if (!$dnsHost) $this->_error(5); //DNS Record to update
269
				if (!$dnsDomain) $this->_error(5);//domain
270
				if (!$dnsTTL) $this->_error(9);//ttl
271
				break;
272
			case 'custom':
273
			case 'custom-v6':
274
				if (!$dnsUpdateURL) $this->_error(7);
275
				break;
276
			default:
277
				if (!$dnsUser) $this->_error(3);
278
				if (!$dnsPass) $this->_error(4);
279
				if (!$dnsHost) $this->_error(5);
280
			}
281

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

    
325
			// Ensure that we were able to lookup the IP
326
			if (!is_ipaddr($this->_dnsIP)) {
327
				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));
328
				unlock($dyndnslck);
329
				return;
330
			}
331

    
332
			$this->_debugID = rand(1000000, 9999999);
333

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

    
418
			unlock($dyndnslck);
419
		}
420

    
421
		/*
422
		 * Private Function (added 12 July 05) [beta]
423
		 *   Send Update To Selected Service.
424
		 */
425
		function _update() {
426

    
427
			if ($this->_dnsVerboseLog) {
428
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _update() starting.'), $this->_dnsService, $this->_FQDN));
429
			}
430

    
431
			if (strstr($this->_dnsRequestIf, "_vip")) {
432
				$parentif = get_configured_vip_interface($this->_dnsRequestIf);
433
				$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
434
			} else {
435
				$realparentif = $this->_dnsRequestIf;
436
			}
437

    
438
			$ch = curl_init();
439

    
440
			if ($this->_useIPv6 == false) {
441
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
442
			}
443

    
444
			if ($this->_dnsService != 'ods') {
445
				curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
446
				curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
447
				curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
448
				curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
449
			}
450

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

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

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

    
794
					curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
795
					curl_setopt($ch, CURLOPT_HTTPHEADER, array(
796
						'X-Auth-Email: '.$this->_dnsUser.'',
797
						'X-Auth-Key: '.$this->_dnsPass.'',
798
						'Content-Type: application/json'
799
					));
800

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

    
944
					//step 1: login to API
945
					$post_data['username'] = $this->_dnsUser;
946
					$post_data['password'] = $this->_dnsPass;
947
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
948
					curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/login");
949
					curl_setopt($ch, CURLOPT_HEADER, 1); //return the full headers to extract the cookies
950
					$output = curl_exec($ch);
951

    
952
					//extract the cookies
953
					preg_match_all("/^Set-cookie: (.*?);/ism", $output, $cookies);
954
					if( count($cookies[1]) > 0 ){
955
						$cookie_data = implode("; ",$cookies[1]);
956
					}
957

    
958
					//step 2: find the id of the A record
959
					$post_data = null;
960
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
961
					curl_setopt($ch, CURLOPT_COOKIE, $cookie_data);
962
					curl_setopt($ch, CURLOPT_HEADER, 0);
963
					curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/dns");
964
					curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
965

    
966
					$output = curl_exec($ch);
967
					preg_match("/^{\"succeeded\":true.*?domain_name\":\"{$this->_dnsDomain}.*?entries.*?{\"id\":\"([^\"]*?)\",\"name\":\"{$this->_dnsHost}\".*?\$/", $output, $hostID);
968
					$hostID = $hostID[1];
969
					preg_match("/^{\"succeeded\":true.*?domain_name\":\"{$this->_dnsDomain}.*?entries.*?{[^\}]*?\"name\":\"{$this->_dnsHost}\".*?content\":\"([^\"]*?)\".*?\$/", $output, $hostIP);
970
					$hostIP = $hostIP[1];
971

    
972
					//step 3: update the IP
973
					if ($hostID) {
974
						curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
975
						curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
976
						curl_setopt($ch, CURLOPT_COOKIE, $cookie_data);
977
						$post_data['content'] = $this->_dnsIP;
978
						curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
979
						curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
980
						curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/dns/{$hostID}");
981
						log_error("HostID:{$hostID}, OldIP:{$hostIP}");
982
					}
983
					break;
984
				case 'dreamhost':
985
				case 'dreamhost-v6':
986
					$needsIP = TRUE;
987
					$isv6 = ($this->_dnsService === 'dreamhost-v6');
988
					$server = 'https://api.dreamhost.com/';
989
					$post_data['key'] = $this->_dnsPass;
990
					$post_data['unique_id'] = uniqid($this->_dnsHost);
991
					$post_data['cmd'] = 'dns-add_record';
992
					$post_data['format'] = 'json';
993
					$post_data['value'] = $this->_dnsIP;
994
					$post_data['record'] = $this->_dnsHost;
995
					$post_data['type'] = $isv6 ? 'AAAA' : 'A';
996
					$post_data['comment'] = "Updated by pfSense:$this->_dnsUser on ".date('c');
997
					$port = "";
998
					if ($this->_dnsServer) {
999
						$server = $this->_dnsServer;
1000
					}
1001
					if ($this->_dnsPort) {
1002
						$port = ":" . $this->_dnsPort;
1003
					}
1004
					curl_setopt($ch, CURLOPT_URL, $server . $port);
1005
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1006
					break;
1007
				case 'digitalocean':
1008
				case 'digitalocean-v6':
1009
					// Get record ID
1010
					$server = 'https://api.digitalocean.com/v2/domains/';
1011
					$isv6 = ($this->_dnsService === 'digitalocean-v6');
1012
					$url = $server . $this->_dnsDomain . '/records';
1013
					curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer {$this->_dnsPass}"));
1014
					curl_setopt($ch, CURLOPT_URL, $url);
1015
					$output = json_decode(curl_exec($ch));
1016
					if (!is_array($output->domain_records)) {
1017
						$output->domain_records = array();
1018
					}
1019
					foreach($output->domain_records as $dnsRecord) {
1020
						// NS records are named @ in DO's API, so check type as well 
1021
						// https://redmine.pfsense.org/issues/9171
1022
						if ($this->_dnsHost == $dnsRecord->name && $dnsRecord->type == 'A') {
1023
							$recordID = $dnsRecord->id;
1024
							break;
1025
						}
1026
					}
1027

    
1028
					// Create/update record
1029
					if ($recordID == null) {
1030
						$url = $server . $this->_dnsDomain . '/records';
1031
					} else {
1032
						$url = $server . $this->_dnsDomain . '/records/' . $recordID;
1033
						curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
1034
					}
1035
					$post_data['type'] = $isv6 ? 'AAAA' : 'A';
1036
					$post_data['ttl'] = $this->_dnsTTL;
1037
					$post_data['name'] = $this->_dnsHost;
1038
					$post_data['data'] = $this->_dnsIP;
1039
					curl_setopt($ch, CURLOPT_URL, $url);
1040
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1041
					break;
1042
				case 'cloudns':
1043
					/* Uses ClouDNS REST API
1044
					   Requires auth-id or sub-auth-id or sub-auth-user */
1045
					// Step 1: Find the Record ID
1046
					$url = 'https://api.cloudns.net/dns/records.json';
1047
					$post_data['auth-id'] = $this->_dnsUser;
1048
					$post_data['auth-password'] = $this->_dnsPass;
1049
					$post_data['domain-name'] = $this->_dnsDomain;
1050
					$post_data['host'] = $this->_dnsHost;
1051
					$post_data['type'] = 'a';
1052
					curl_setopt($ch, CURLOPT_URL, $url);
1053
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1054
					$output = json_decode(curl_exec($ch));
1055
					$recordID = key(get_object_vars($output));
1056

    
1057
					// Step 2: Set the record
1058
					$needsIP = TRUE;
1059
					$url = 'https://api.cloudns.net/dns/mod-record.json';
1060
					$post_data = array();
1061
					$post_data['auth-id'] = $this->_dnsUser;
1062
					$post_data['auth-password'] = $this->_dnsPass;
1063
					$post_data['domain-name'] = $this->_dnsDomain;
1064
					$post_data['record-id'] = $recordID;
1065
					$post_data['host'] = $this->_dnsHost;
1066
					$post_data['record'] = $this->_dnsIP;
1067
					$post_data['ttl'] = $this->_dnsTTL;
1068
					curl_setopt($ch, CURLOPT_URL, $url);
1069
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1070
					break;
1071
				case 'azurev6':
1072
				case 'azure':
1073
					$hostname = "{$this->_dnsHost}";
1074
					$resourceid = trim($this->_dnsZoneID);
1075
					$app_id = $this->_dnsUser;
1076
					$client_secret = $this->_dnsPass;
1077
					$newip = $this->_dnsIP;
1078
					$newttl = $this->_dnsTTL;
1079
						// ensure resourceid starts with / and has no trailing /
1080
					$resourceid = '/' . trim($resourceid, '/');
1081
						// extract subscription id from resource id
1082
					preg_match('/\\/subscriptions\\/(?<sid>[^\\/]*)/', $resourceid, $result);
1083
					$subscriptionid = isset($result['sid']) ? $result['sid'] : '';
1084
					if (isset($result['sid'])) {
1085
						$subscriptionid = $result['sid'];
1086
					} else {
1087
						log_error("Azure subscription id not found in resource id");
1088
						return false;
1089
					}
1090
						// find tenant id from subscription id
1091
					curl_setopt($ch, CURLOPT_URL, "https://management.azure.com/subscriptions/" . $subscriptionid . "?api-version=2016-09-01");
1092
					curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1093
					curl_setopt($ch, CURLOPT_HEADER, 1);
1094
					curl_setopt($ch, CURLOPT_NOBODY, 1);
1095
					$output = curl_exec($ch);
1096
					$pattern = '/Bearer authorization_uri="https:\\/\\/login.windows.net\\/(?<tid>[^"]*)/i';
1097
					preg_match($pattern, $output, $result);
1098
					if (isset($result['tid'])) {
1099
						$tenantid = $result['tid'];
1100
					} else {
1101
						log_error("Tenant ID not found");
1102
						return false;
1103
					}
1104
						// get an bearer token
1105
					curl_setopt($ch, CURLOPT_URL, "https://login.microsoftonline.com/" . $tenantid . "/oauth2/token");
1106
					curl_setopt($ch, CURLOPT_POST, 1);
1107
					$body = "resource=" . urlencode("https://management.core.windows.net/") . "&grant_type=client_credentials&client_id=" . $app_id . "&client_secret=" . urlencode($client_secret);
1108
					curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
1109
					curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1110
					$server_output = curl_exec($ch);
1111
					$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1112
					preg_match("/\"access_token\":\"(?<tok>[^\"]*)\"/", $server_output, $result);
1113
					if (isset($result['tok'])) {
1114
						$bearertoken = $result['tok'];
1115
					} else {
1116
						log_error("no valid bearer token");
1117
						return false;
1118
					}
1119
						// Update the DNS record
1120
					if ($this->_useIPv6) {
1121
						$url = "https://management.azure.com" . $resourceid . "/AAAA/" . $hostname . "?api-version=2017-09-01";
1122
						$body = '{"properties":{"TTL":"' . $newttl . '", "AAAARecords":[{"ipv6Address":"' . $newip . '"}]}}';
1123
					} else {
1124
						$url = "https://management.azure.com" . $resourceid . "/A/" . $hostname . "?api-version=2017-09-01";
1125
						$body = '{"properties":{"TTL":"' . $newttl . '", "ARecords":[{"ipv4Address":"' . $newip . '"}]}}';
1126
					}
1127
					$request_headers = array();
1128
					$request_headers[] = 'Accept: application/json';
1129
					$request_headers[] = 'Authorization: Bearer ' . $bearertoken;
1130
					$request_headers[] = 'Content-Type: application/json';
1131
					curl_setopt($ch, CURLOPT_URL, $url);
1132
					curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
1133
					curl_setopt($ch, CURLOPT_HTTPHEADER, $request_headers);
1134
					curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
1135
					curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1136
					curl_setopt($ch, CURLOPT_HEADER, 1);
1137
					curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
1138
					break;
1139
				case 'linode':
1140
				case 'linode-v6':
1141
					$linode_api = "https://api.linode.com/v4";
1142
					$record_type = $this->_useIPv6 ? "AAAA" : "A";
1143
					$record_name = $this->_dnsHost == "@" ? "" : $this->_dnsHost;
1144
					$err_prefix = gettext("Dynamic DNS") . " {$this->_dnsService} ({$this->_FQDN}): (" . gettext("Error") . ")";
1145
					curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1146
					curl_setopt($ch, CURLOPT_HTTPHEADER, array(
1147
						'Accept: application/json',
1148
						'Content-Type: application/json',
1149
						'Authorization: Bearer ' . $this->_dnsPass
1150
					));
1151

    
1152
					// get domain id
1153
					curl_setopt($ch, CURLOPT_URL, "{$linode_api}/domains");
1154
					$domains_output = curl_exec($ch);
1155
					$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1156
					if ( $http_code == 401 && preg_match('/invalid oauth token/i', $domains_output) ) {
1157
						log_error("$err_prefix " . gettext("querying domains") . ": " . gettext("User Authentication Failed"));
1158
						return false;
1159
					} else if ( $http_code == 401 ) {
1160
						log_error("$err_prefix " . gettext("querying domains") . ": " . gettext("User Authorization Failed"));
1161
						return false;
1162
					} else if ( $http_code != 200 ) {
1163
						log_error("$err_prefix " . gettext("querying domains") . ": " .
1164
							( isset($domains_result["errors"][0]["reason"]) ? $domains_result["errors"][0]["reason"] : "HTTP {$http_code}" ) );
1165
						return false;
1166
					}
1167

    
1168
					$domains_result = json_decode($domains_output, TRUE);
1169
					foreach($domains_result["data"] as $domains_entry) {
1170
						if ($domains_entry["domain"] == $this->_dnsDomain) {
1171
							$domain_id = $domains_entry["id"];
1172
						}
1173
					}
1174
					if ( ! $domain_id ) {
1175
						log_error("{$err_prefix} " . gettext("no domain ID for domain") . ": '{$this->_dnsDomain}'");
1176
						return false;
1177
					}
1178
					if ($this->_dnsVerboseLog) {
1179
						log_error("_update(): " . sprintf(gettext("found domain id: %s"), $domain_id));
1180
					}
1181

    
1182
					// get existing record if present
1183
					curl_setopt($ch, CURLOPT_URL, "{$linode_api}/domains/{$domain_id}/records");
1184
					$records_output = curl_exec($ch);
1185
					$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1186
					if ( $http_code != 200 )
1187
					{
1188
						log_error("$err_prefix " . gettext("querying domains") . ": " .
1189
							( isset($domains_result["errors"][0]["reason"]) ? $domains_result["errors"][0]["reason"] : "HTTP {$http_code}" ) );
1190
						return false;
1191
					}
1192

    
1193
					$records_result = json_decode($records_output, TRUE);
1194
					foreach($records_result["data"] as $records_entry) {
1195
						if ( $records_entry["type"] == $record_type && $records_entry["name"] == $record_name ) {
1196
							// not adding support for pagination at this time, hope you have < 100 records!
1197
							$record = $records_entry;
1198
						}
1199
					}
1200
					if ($this->_dnsVerboseLog) {
1201
						log_error("_update(): " . ( $record ? sprintf(gettext("found existing record id: %s"), $record["id"]) : gettext("no matching record found") ));
1202
					}
1203

    
1204
					if (is_array($record)) {
1205
						// update existing record
1206
						$record["target"] = $this->_dnsIP;
1207
						$record["ttl_sec"] = (int) $this->_dnsTTL; // linode may round this up, 0 = zone default
1208
						curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($record));
1209
						curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
1210
						curl_setopt($ch, CURLOPT_URL, "{$linode_api}/domains/{$domain_id}/records/" . $record["id"]);
1211
					} else {
1212
						// create a new record
1213
						$record = array(
1214
							"type"    => $record_type,
1215
							"name"    => $record_name,
1216
							"target"  => $this->_dnsIP,
1217
							"ttl_sec" => (int) $this->_dnsTTL, // linode may round this up, 0 = zone default
1218
						);
1219
						curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($record));
1220
						curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
1221
						curl_setopt($ch, CURLOPT_URL, "{$linode_api}/domains/{$domain_id}/records");
1222
					}
1223

    
1224
				break;
1225
			case 'gandi-livedns':
1226
				// NOTE: quite similar to digitalocean case but with json content like azure case
1227
				// Get record href
1228
				$server = 'https://dns.api.gandi.net/api/v5/domains/';
1229
				$url = $server . $this->_dnsDomain . '/records';
1230
				curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Api-Key: {$this->_dnsPass}"));
1231
				curl_setopt($ch, CURLOPT_URL, $url);
1232
				$output = json_decode(curl_exec($ch));
1233
				if (!is_array($output)) {
1234
					$output = array();
1235
				}
1236
				foreach($output as $dnsRecord) {
1237
					// NS records are named @ in DO's API, so check type as well
1238
					if ($this->_dnsHost == $dnsRecord->rrset_name && $dnsRecord->rrset_type == 'A') {
1239
						$recordHref = $dnsRecord->rrset_href;
1240
						break;
1241
					}
1242
				}
1243
				$request_headers = array();
1244
				//$request_headers[] = 'Accept: application/json';
1245
				$request_headers[] = 'X-Api-Key: ' .$this->_dnsPass;
1246
				$request_headers[] = 'Content-Type: application/json';
1247
				//create or update record
1248
				if ($recordHref == null) {
1249
					//create record
1250
					$url = $server . $this->_dnsDomain . '/records';
1251
					$body = '{"rrset_type": "A", "rrset_ttl": ' . $this->_dnsTTL . ', "rrset_name": "' . $this->_dnsHost . '", "rrset_values": ["' . $this->_dnsIP . '"]}';
1252
				} else {
1253
					//update record
1254
					$url = $recordHref;
1255
					$body = '{"rrset_ttl": ' . $this->_dnsTTL . ', "rrset_values": ["' . $this->_dnsIP . '"]}';
1256
					curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
1257
				}
1258
				curl_setopt($ch, CURLOPT_URL, $url);
1259
				curl_setopt($ch, CURLOPT_HTTPHEADER, $request_headers);
1260
				curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
1261
					break;
1262
				default:
1263
					break;
1264
			}
1265
			if ($this->_dnsService != 'ods') {
1266
				curl_setopt($ch, CURLOPT_HEADER, 1);
1267
				$response = curl_exec($ch);
1268
				$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1269
				$header = substr($response, 0, $header_size);
1270
				$data = substr($response, $header_size);
1271
				$this->_checkStatus($ch, $data, $header);
1272
				@curl_close($ch);
1273
			}
1274
		}
1275

    
1276
		/**
1277
		 * Private Function (added 23 Feb 17)
1278
		 *   Send Removal To Selected Service.
1279
		 *
1280
		 *   Some services do not perform an inplace upgrade.  If they do not then the solution
1281
		 *   is to remove the existing record and add a new record.
1282
		 *
1283
		 * @param unknown $existing_ip If required, an existing IP address for the record.
1284
		 */
1285
		function _remove($existing_ip = NULL) {
1286
			$remove_allowed = false;
1287
			if ($this->_dnsVerboseLog) {
1288
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _remove() starting.'), $this->_dnsService, $this->_FQDN));
1289
			}
1290

    
1291
			if (strstr($this->_dnsRequestIf, "_vip")) {
1292
				$parentif = get_configured_vip_interface($this->_dnsRequestIf);
1293
				$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
1294
			} else {
1295
				$realparentif = $this->_dnsRequestIf;
1296
			}
1297

    
1298
			$ch = curl_init();
1299

    
1300
			if ($this->_useIPv6 == false) {
1301
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1302
			}
1303

    
1304
			curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
1305
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
1306
			curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
1307
			curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
1308

    
1309
			switch ($this->_dnsService) {
1310
			case 'dreamhost':
1311
			case 'dreamhost-v6':
1312
				$server = 'https://api.dreamhost.com/';
1313
				$post_data['key'] = $this->_dnsPass;
1314
				$post_data['unique_id'] = uniqid($this->_dnsHost);
1315
				$post_data['cmd'] = 'dns-remove_record';
1316
				$post_data['format'] = 'json';
1317
				$post_data['value'] = $existing_ip;
1318
				$post_data['record'] = $this->_dnsHost;
1319
				$isv6 = ($this->_dnsService === 'dreamhost-v6');
1320
				$post_data['type'] = $isv6 ? 'AAAA' : 'A';
1321
				$port = "";
1322
				if ($this->_dnsServer) {
1323
					$server = $this->_dnsServer;
1324
				}
1325
				if ($this->_dnsPort) {
1326
					$port = ":" . $this->_dnsPort;
1327
				}
1328
				curl_setopt($ch, CURLOPT_URL, $server . $port);
1329
				curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1330
				$remove_allowed = true;
1331
				break;
1332
			default:
1333
				break;
1334
			}
1335
			if ($remove_allowed) {
1336
				curl_setopt($ch, CURLOPT_HEADER, 1);
1337
				$response = curl_exec($ch);
1338
				$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1339
				$header = substr($response, 0, $header_size);
1340
				$data = substr($response, $header_size);
1341
				$this->_checkStatus($ch, $data, $header);
1342
				@curl_close($ch);
1343
			}
1344
		}
1345

    
1346
		/**
1347
		 * Private Function (added 23 Feb 17)
1348
		 * Retrieves current DNS records from an external API source.
1349
		 *
1350
		 * Some services cannot perform new operations without the caller
1351
		 * providing existing record information.
1352
		 */
1353
		function _lookup_current() {
1354
			$lookup_allowed = false;
1355
			if ($this->_dnsVerboseLog) {
1356
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _listCurrent() starting.'), $this->_dnsService, $this->_FQDN));
1357
			}
1358

    
1359
			if (strstr($this->_dnsRequestIf, "_vip")) {
1360
				$parentif = get_configured_vip_interface($this->_dnsRequestIf);
1361
				$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
1362
			} else {
1363
				$realparentif = $this->_dnsRequestIf;
1364
			}
1365

    
1366
			$ch = curl_init();
1367

    
1368
			if ($this->_useIPv6 == false) {
1369
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1370
			}
1371

    
1372
			curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
1373
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
1374
			curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
1375
			curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
1376

    
1377
			switch ($this->_dnsService) {
1378
			case 'dreamhost':
1379
			case 'dreamhost-v6':
1380
				$server = 'https://api.dreamhost.com/';
1381
				$post_data['key'] = $this->_dnsPass;
1382
				$post_data['unique_id'] = uniqid($this->_dnsHost);
1383
				$post_data['cmd'] = 'dns-list_records';
1384
				$post_data['format'] = 'json';
1385
				$port = "";
1386
				if ($this->_dnsServer) {
1387
					$server = $this->_dnsServer;
1388
				}
1389
				if ($this->_dnsPort) {
1390
					$port = ":" . $this->_dnsPort;
1391
				}
1392
				curl_setopt($ch, CURLOPT_URL, $server . $port);
1393
				curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1394
				$lookup_allowed = true;
1395
				break;
1396
			default:
1397
				break;
1398
			}
1399
			if ($lookup_allowed) {
1400
				curl_setopt($ch, CURLOPT_HEADER, 1);
1401
				$response = curl_exec($ch);
1402
				$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1403
				$header = substr($response, 0, $header_size);
1404
				$data = substr($response, $header_size);
1405
				$this->_checkLookupStatus($ch, $data, $header);
1406
				@curl_close($ch);
1407
			}
1408
		}
1409

    
1410
		/*
1411
		 * Private Function (added 23 Feb 17)
1412
		 *   Retrieve Lookup Status from the provided data and/or header
1413
		 */
1414
		function _checkLookupStatus($ch, $data, $header) {
1415
			if ($this->_dnsVerboseLog) {
1416
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkLookupStatus() starting.'), $this->_dnsService, $this->_FQDN));
1417
			}
1418
			$success_str = "(" . gettext("Success") . ") ";
1419
			$error_str = "(" . gettext("Error") . ") ";
1420
			$status_intro = "phpDynDNS ({$this->_dnsHost}): ";
1421

    
1422
			if ($this->_dnsService != 'ods' && @curl_error($ch)) {
1423
				$status = gettext("Curl error occurred:") . " " . curl_error($ch);
1424
				log_error($status);
1425
				$this->status = $status;
1426
				return;
1427
			}
1428
			switch ($this->_dnsService) {
1429
			case 'dreamhost':
1430
			case 'dreamhost-v6':
1431
				$result = json_decode($data,true);
1432
				if($result["result"] != "success") {
1433
					log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1434
					$this->_debug($data);
1435
					return;
1436
				} else {
1437
					foreach($result["data"] as $key => $row) {
1438
						if($row["record"] == $this->_dnsHost &&
1439
								(($row["type"] == "A" && !$this->_useIPv6)
1440
										|| ($row["type"] == "AAAA" && $this->_useIPv6)
1441
								)) {
1442
							if($row["editable"] == 0) {
1443
								log_error($status_intro . "host " . $this->_dnsHost . " is not editable.");
1444
								continue;
1445
							}
1446
							$this->_existingRecords[]=array("record"=>$row["type"], "type"=>$row["type"], "existing_val"=>$row["value"]);
1447
						}
1448
					}
1449
				}
1450
				if (!is_array($this->_existingRecords)){
1451
					if ($this->_dnsVerboseLog) {
1452
						log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkLookupStatus() ending.  No matching records found.'), $this->_dnsService, $this->_FQDN));
1453
					}
1454
				}
1455
				break;
1456
			default:
1457
				break;
1458
			}
1459
		}
1460

    
1461
		/*
1462
		 * Private Function (added 12 July 2005) [beta]
1463
		 *   Retrieve Update Status
1464
		 */
1465
		function _checkStatus($ch, $data, $header) {
1466
			if ($this->_dnsVerboseLog) {
1467
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkStatus() starting.'), $this->_dnsService, $this->_FQDN));
1468
			}
1469
			$successful_update = false;
1470
			$success_str = "(" . gettext("Success") . ") ";
1471
			$error_str = "(" . gettext("Error") . ") ";
1472
			$status_intro = "phpDynDNS ({$this->_dnsHost}): ";
1473

    
1474
			if ($this->_dnsService != 'ods' && @curl_error($ch)) {
1475
				$status = gettext("Curl error occurred:") . " " . curl_error($ch);
1476
				log_error($status);
1477
				$this->status = $status;
1478
				return;
1479
			}
1480
			switch ($this->_dnsService) {
1481
				case 'glesys':
1482
					$status_intro = "GleSYS ({$this->_dnsHost}): ";
1483
					if (preg_match('/Record updated/i', $data)) {
1484
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1485
						$successful_update = true;
1486
					} else {
1487
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1488
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1489
						$this->_debug($data);
1490
					}
1491
					break;
1492
				case 'dnsomatic':
1493
					$status_intro = "DNS-O-Matic ({$this->_dnsHost}): ";
1494
					if (preg_match('/badauth/i', $data)) {
1495
						$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.");
1496
					} else if (preg_match('/notfqdn /i', $data)) {
1497
						$status = $status_intro . gettext("The hostname specified is not a fully-qualified domain name. If no hostnames included, notfqdn will be returned once.");
1498
					} else if (preg_match('/nohost/i', $data)) {
1499
						$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.");
1500
					} else if (preg_match('/numhost/i', $data)) {
1501
						$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.");
1502
					} else if (preg_match('/abuse/i', $data)) {
1503
						$status = $status_intro . gettext("The hostname is blocked for update abuse.");
1504
					} else if (preg_match('/good/i', $data)) {
1505
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1506
						$successful_update = true;
1507
					} else if (preg_match('/dnserr/i', $data)) {
1508
						$status = $status_intro . gettext("DNS error encountered. Stop updating for 30 minutes.");
1509
					} else {
1510
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1511
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1512
						$this->_debug($data);
1513
					}
1514
					break;
1515
				case 'citynetwork':
1516
					if (preg_match('/notfqdn/i', $data)) {
1517
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1518
					} else if (preg_match('/nohost/i', $data)) {
1519
						$status = $status_intro . $error_str . gettext("No such host");
1520
					} else if (preg_match('/nochg/i', $data)) {
1521
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1522
						$successful_update = true;
1523
					} else if (preg_match('/good/i', $data)) {
1524
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1525
						$successful_update = true;
1526
					} else if (preg_match('/badauth/i', $data)) {
1527
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1528
					} else {
1529
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1530
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1531
						$this->_debug($data);
1532
					}
1533
					break;
1534
				case 'ovh-dynhost':
1535
				case 'dyndns':
1536
					if (preg_match('/notfqdn/i', $data)) {
1537
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1538
					} else if (preg_match('/nochg/i', $data)) {
1539
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1540
						$successful_update = true;
1541
					} else if (preg_match('/good/i', $data)) {
1542
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1543
						$successful_update = true;
1544
					} else if (preg_match('/noauth/i', $data)) {
1545
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1546
					} else {
1547
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1548
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1549
						$this->_debug($data);
1550
					}
1551
					break;
1552
				case 'dyndns-static':
1553
					if (preg_match('/notfqdn/i', $data)) {
1554
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1555
					} else if (preg_match('/nochg/i', $data)) {
1556
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1557
						$successful_update = true;
1558
					} else if (preg_match('/good/i', $data)) {
1559
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1560
						$successful_update = true;
1561
					} else if (preg_match('/noauth/i', $data)) {
1562
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1563
					} else {
1564
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1565
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1566
						$this->_debug($data);
1567
					}
1568
					break;
1569
				case 'dyndns-custom':
1570
					if (preg_match('/notfqdn/i', $data)) {
1571
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1572
					} else if (preg_match('/nochg/i', $data)) {
1573
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1574
						$successful_update = true;
1575
					} else if (preg_match('/good/i', $data)) {
1576
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1577
						$successful_update = true;
1578
					} else if (preg_match('/noauth/i', $data)) {
1579
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1580
					} else {
1581
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1582
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1583
						$this->_debug($data);
1584
					}
1585
					break;
1586
				case 'dhs':
1587
					break;
1588
				case 'noip':
1589
				case 'noip-free':
1590
					list($ip, $code) = explode(":", $data);
1591
					switch ($code) {
1592
						case 0:
1593
							$status = $status_intro . $success_str . gettext("IP address is current, no update performed.");
1594
							$successful_update = true;
1595
							break;
1596
						case 1:
1597
							$status = $status_intro . $success_str . gettext("DNS hostname update successful.");
1598
							$successful_update = true;
1599
							break;
1600
						case 2:
1601
							$status = $status_intro . $error_str . gettext("Hostname supplied does not exist.");
1602
							break;
1603
						case 3:
1604
							$status = $status_intro . $error_str . gettext("Invalid Username.");
1605
							break;
1606
						case 4:
1607
							$status = $status_intro . $error_str . gettext("Invalid Password.");
1608
							break;
1609
						case 5:
1610
							$status = $status_intro . $error_str . gettext("Too many updates sent.");
1611
							break;
1612
						case 6:
1613
							$status = $status_intro . $error_str . gettext("Account disabled due to violation of No-IP terms of service.");
1614
							break;
1615
						case 7:
1616
							$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.");
1617
							break;
1618
						case 8:
1619
							$status = $status_intro . $error_str . gettext("Disabled / Locked Hostname.");
1620
							break;
1621
						case 9:
1622
							$status = $status_intro . $error_str . gettext("Host updated is configured as a web redirect and no update was performed.");
1623
							break;
1624
						case 10:
1625
							$status = $status_intro . $error_str . gettext("Group supplied does not exist.");
1626
							break;
1627
						case 11:
1628
							$status = $status_intro . $success_str . gettext("DNS group update is successful.");
1629
							$successful_update = true;
1630
							break;
1631
						case 12:
1632
							$status = $status_intro . $success_str . gettext("DNS group is current, no update performed.");
1633
							$successful_update = true;
1634
							break;
1635
						case 13:
1636
							$status = $status_intro . $error_str . gettext("Update client support not available for supplied hostname or group.");
1637
							break;
1638
						case 14:
1639
							$status = $status_intro . $error_str . gettext("Hostname supplied does not have offline settings configured.");
1640
							break;
1641
						case 99:
1642
							$status = $status_intro . $error_str . gettext("Client disabled. Client should exit and not perform any more updates without user intervention.");
1643
							break;
1644
						case 100:
1645
							$status = $status_intro . $error_str . gettext("Client disabled. Client should exit and not perform any more updates without user intervention.");
1646
							break;
1647
						default:
1648
							$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1649
							$this->_debug(gettext("Unknown Response:") . " " . $data);
1650
							break;
1651
					}
1652
					break;
1653
				case 'easydns':
1654
					if (preg_match('/NOACCESS/i', $data)) {
1655
						$status = $status_intro . $error_str . gettext("Authentication Failed: Username and/or Password was Incorrect.");
1656
					} else if (preg_match('/NOSERVICE/i', $data)) {
1657
						$status = $status_intro . $error_str . gettext("No Service: Dynamic DNS Service has been disabled for this domain.");
1658
					} else if (preg_match('/ILLEGAL INPUT/i', $data)) {
1659
						$status = $status_intro . $error_str . gettext("Illegal Input: Self-Explanatory");
1660
					} else if (preg_match('/TOOSOON/i', $data)) {
1661
						$status = $status_intro . $error_str . gettext("Too Soon: Not Enough Time Has Elapsed Since Last Update");
1662
					} else if (preg_match('/NOERROR/i', $data)) {
1663
						$status = $status_intro . $success_str . gettext("IP Updated Successfully!");
1664
						$successful_update = true;
1665
					} else {
1666
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1667
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1668
						$this->_debug($data);
1669
					}
1670
					break;
1671
				case 'hn':
1672
					/* FIXME: add checks */
1673
					break;
1674
				case 'zoneedit':
1675
					if (preg_match('/799/i', $data)) {
1676
						$status = $status_intro . "(" . gettext("Error 799") . ") " . gettext("Update Failed!");
1677
					} else if (preg_match('/700/i', $data)) {
1678
						$status = $status_intro . "(" . gettext("Error 700") . ") " . gettext("Update Failed!");
1679
					} else if (preg_match('/200/i', $data)) {
1680
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1681
						$successful_update = true;
1682
					} else if (preg_match('/201/i', $data)) {
1683
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1684
						$successful_update = true;
1685
					} else {
1686
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1687
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1688
						$this->_debug($data);
1689
					}
1690
					break;
1691
				case 'dyns':
1692
					if (preg_match("/400/i", $data)) {
1693
						$status = $status_intro . $error_str . gettext("Bad Request - The URL was malformed. Required parameters were not provided.");
1694
					} else if (preg_match('/402/i', $data)) {
1695
						$status = $status_intro . $error_str . gettext("Update Too Soon - Attempted to update too quickly since last change.");
1696
					} else if (preg_match('/403/i', $data)) {
1697
						$status = $status_intro . $error_str . gettext("Database Error - There was a server-sided database error.");
1698
					} else if (preg_match('/405/i', $data)) {
1699
						$status = $status_intro . $error_str . sprintf(gettext('Hostname Error - The hostname (%1$s) doesn\'t belong to user (%2$s).'), $this->_dnsHost, $this->_dnsUser);
1700
					} else if (preg_match('/200/i', $data)) {
1701
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1702
						$successful_update = true;
1703
					} else {
1704
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1705
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1706
						$this->_debug($data);
1707
					}
1708
					break;
1709
				case 'ods':
1710
					if (preg_match("/299/i", $data)) {
1711
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
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 'freedns':
1720
				case 'freedns-v6':
1721
					if (preg_match("/has not changed./i", $data)) {
1722
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1723
						$successful_update = true;
1724
					} else if (preg_match("/Updated/i", $data)) {
1725
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1726
						$successful_update = true;
1727
					} else {
1728
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1729
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1730
						$this->_debug($data);
1731
					}
1732
					break;
1733
				case 'dnsexit':
1734
					if (preg_match("/is the same/i", $data)) {
1735
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1736
						$successful_update = true;
1737
					} else if (preg_match("/Success/i", $data)) {
1738
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
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 'loopia':
1747
					if (preg_match("/nochg/i", $data)) {
1748
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1749
						$successful_update = true;
1750
					} else if (preg_match("/good/i", $data)) {
1751
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1752
						$successful_update = true;
1753
					} else if (preg_match('/badauth/i', $data)) {
1754
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1755
					} else {
1756
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1757
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1758
						$this->_debug($data);
1759
					}
1760
					break;
1761
				case 'opendns':
1762
					if (preg_match('/badauth/i', $data)) {
1763
						$status = $status_intro . $error_str . gettext("Not a valid username or password!");
1764
					} else if (preg_match('/nohost/i', $data)) {
1765
						$status = $status_intro . $error_str . gettext("Hostname specified does not exist.");
1766
						$successful_update = true;
1767
					} else if (preg_match('/good/i', $data)) {
1768
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1769
						$successful_update = true;
1770
					} else if (preg_match('/yours/i', $data)) {
1771
						$status = $status_intro . $error_str . gettext("Hostname specified exists, but not under the username specified.");
1772
					} else if (preg_match('/abuse/i', $data)) {
1773
						$status = $status_intro . $error_str . gettext("Updating too frequently, considered abuse.");
1774
					} else {
1775
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1776
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1777
						$this->_debug($data);
1778
					}
1779
					break;
1780
				case 'staticcling':
1781
					if (preg_match("/invalid ip/i", $data)) {
1782
						$status = $status_intro . $error_str . gettext("Bad Request - The IP provided was invalid.");
1783
					} else if (preg_match('/required info missing/i', $data)) {
1784
						$status = $status_intro . $error_str . gettext("Bad Request - Required parameters were not provided.");
1785
					} else if (preg_match('/invalid characters/i', $data)) {
1786
						$status = $status_intro . $error_str . gettext("Bad Request - Illegal characters in either the username or the password.");
1787
					} else if (preg_match('/bad password/i', $data)) {
1788
						$status = $status_intro . $error_str . gettext("Invalid password.");
1789
					} else if (preg_match('/account locked/i', $data)) {
1790
						$status = $status_intro . $error_str . gettext("This account has been administratively locked.");
1791
					} else if (preg_match('/update too frequent/i', $data)) {
1792
						$status = $status_intro . $error_str . gettext("Updating too frequently.");
1793
					} else if (preg_match('/DB error/i', $data)) {
1794
						$status = $status_intro . $error_str . gettext("Server side error.");
1795
					} else if (preg_match('/success/i', $data)) {
1796
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1797
						$successful_update = true;
1798
					} else {
1799
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1800
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1801
						$this->_debug($data);
1802
					}
1803
					break;
1804
				case 'namecheap':
1805
					$tmp = str_replace("^M", "", $data);
1806
					$ncresponse = @xml2array($tmp);
1807
					if (preg_match("/internal server error/i", $data)) {
1808
						$status = $status_intro . $error_str . gettext("Server side error.");
1809
					} else if (preg_match("/request is badly formed/i", $data)) {
1810
						$status = $status_intro . $error_str . gettext("Badly Formed Request (check the settings).");
1811
					} else if ($ncresponse['interface-response']['ErrCount'] === "0") {
1812
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1813
						$successful_update = true;
1814
					} else if (is_numeric($ncresponse['interface-response']['ErrCount']) && ($ncresponse['interface-response']['ErrCount'] > 0)) {
1815
						$status = $status_intro . $error_str . implode(", ", $ncresponse["interface-response"]["errors"]);
1816
						$successful_update = true;
1817
					} else {
1818
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1819
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1820
						$this->_debug($data);
1821
					}
1822
					break;
1823
				case 'duiadns':
1824
				case 'duiadns-v6':
1825
					if (preg_match("/error/i", $data)) {
1826
						$status = $status_intro . $error_str . gettext("Server side error.");
1827
					} else if (preg_match('/nohost/i', $data)) {
1828
						$status = $status_intro . $error_str . gettext("Bad Request - A hostname was not provided.");
1829
					} else if (preg_match('/badauth/i', $data)) {
1830
						$status = $status_intro . $error_str . gettext("Invalid username or password.");
1831
					} else if (preg_match('/good/i', $data)) {
1832
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1833
						$successful_update = true;
1834
					} else if (preg_match('/nochg/i', $data)) {
1835
						$status = $status_intro . $success_str . gettext("No Change In IP Address.");
1836
						$successful_update = true;
1837
					} else {
1838
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1839
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1840
						$this->_debug($data);
1841
					}
1842
					break;
1843
				case 'he-net':
1844
				case 'he-net-v6':
1845
					if (preg_match("/badip/i", $data)) {
1846
						$status = $status_intro . $error_str . gettext("Bad Request - The IP provided was invalid.");
1847
					} else if (preg_match('/nohost/i', $data)) {
1848
						$status = $status_intro . $error_str . gettext("Bad Request - A hostname was not provided.");
1849
					} else if (preg_match('/badauth/i', $data)) {
1850
						$status = $status_intro . $error_str . gettext("Invalid username or password.");
1851
					} else if (preg_match('/good/i', $data)) {
1852
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1853
						$successful_update = true;
1854
					} else if (preg_match('/nochg/i', $data)) {
1855
						$status = $status_intro . $success_str . gettext("No Change In IP Address.");
1856
						$successful_update = true;
1857
					} else {
1858
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1859
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1860
						$this->_debug($data);
1861
					}
1862
					break;
1863
				case 'he-net-tunnelbroker':
1864
					/*
1865
					-ERROR: Missing parameter(s).
1866
					-ERROR: Invalid API key or password
1867
					-ERROR: Tunnel not found
1868
					-ERROR: Another tunnel exists for this IP.
1869
					-ERROR: This tunnel is already associated with this IP address
1870
					+OK: Tunnel endpoint updated to: x.x.x.x
1871
					*/
1872
					if (preg_match("/Missing parameter/i", $data)) {
1873
						$status = $status_intro . $error_str . gettext("Bad Request - Missing/Invalid Parameters.");
1874
					} else if (preg_match('/Tunnel not found/i', $data)) {
1875
						$status = $status_intro . $error_str . gettext("Bad Request - Invalid Tunnel ID.");
1876
					} else if (preg_match('/Invalid API key or password/i', $data)) {
1877
						$status = $status_intro . $error_str . gettext("Invalid username or password.");
1878
					} else if (preg_match('/OK:/i', $data)) {
1879
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1880
						$successful_update = true;
1881
					} else if (preg_match('/This tunnel is already associated with this IP address/i', $data)) {
1882
						$status = $status_intro . $success_str . gettext("No Change In IP Address.");
1883
						$successful_update = true;
1884
					} else {
1885
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1886
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1887
						$this->_debug($data);
1888
					}
1889
					break;
1890
				case 'selfhost':
1891
					if (preg_match('/notfqdn/i', $data)) {
1892
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1893
					} else if (preg_match('/nochg/i', $data)) {
1894
						$status = $status_intro . $success_str . gettext("No Change In IP Address.");
1895
						$successful_update = true;
1896
					} else if (preg_match('/good/i', $data)) {
1897
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1898
						$successful_update = true;
1899
					} else if (preg_match('/noauth/i', $data)) {
1900
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1901
					} else {
1902
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1903
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1904
						$this->_debug($data);
1905
					}
1906
					break;
1907
				case 'route53':
1908
				case 'route53-v6':
1909
					if(preg_match('/ErrorResponse/', $data)){
1910
						$status = $status_intro . $error_str . gettext("Route53 API call failed");
1911
						log_error(sprintf("error message: %s", $data));
1912
						$status_update = false;
1913
					} else {
1914
						$status = $status_intro . $success_str . gettext("IP address changed successfully");
1915
						$successful_update = true;
1916
					}
1917
					break;
1918
				case 'custom':
1919
				case 'custom-v6':
1920
					$successful_update = false;
1921
					if ($this->_dnsResultMatch == "") {
1922
						$successful_update = true;
1923
					} else {
1924
						$this->_dnsResultMatch = str_replace("%IP%", $this->_dnsIP, $this->_dnsResultMatch);
1925
						$matches = preg_split("/(?<!\\\\)\\|/", $this->_dnsResultMatch);
1926
						foreach ($matches as $match) {
1927
							$match= str_replace("\\|", "|", $match);
1928
							if (strcmp($match, trim($data, "\t\n\r")) == 0) {
1929
								$successful_update = true;
1930
							}
1931
						}
1932
						unset ($matches);
1933
					}
1934
					if ($successful_update == true) {
1935
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1936
					} else {
1937
						$status = $status_intro . $error_str . gettext("Result did not match.") . " [" . $data . "]";
1938
					}
1939
					break;
1940
				case 'cloudflare-v6':
1941
				case 'cloudflare':
1942
					$output = json_decode($data);
1943
					if ($output->result->content === $this->_dnsIP) {
1944
						$status = $status_intro . $success_str . sprintf(gettext('%1$s updated to %2$s'), $this->_dnsHost, $this->_dnsIP);
1945
						$successful_update = true;
1946
					} elseif ($output->errors[0]->code === 9103) {
1947
						$status = $status_intro . $error_str . gettext("Invalid Credentials! Don't forget to use API Key for password field with Cloudflare.");
1948
					} elseif (($output->success) && (!$output->result[0]->id)) {
1949
						$status = $status_intro . $error_str . gettext("Zone or Host ID was not found, check the hostname.");
1950
					} else {
1951
						$status = $status_intro . gettext("UNKNOWN ERROR") . " - " . $output->errors[0]->message;
1952
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1953
					}
1954
					break;
1955
				case 'eurodns':
1956
					if (preg_match('/notfqdn/i', $data)) {
1957
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1958
					} else if (preg_match('/nochg/i', $data)) {
1959
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1960
						$successful_update = true;
1961
					} else if (preg_match('/good/i', $data)) {
1962
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1963
						$successful_update = true;
1964
					} else if (preg_match('/badauth/i', $data)) {
1965
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1966
					} else {
1967
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1968
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1969
						$this->_debug($data);
1970
					}
1971
					break;
1972
				case 'gratisdns':
1973
					if (preg_match('/Forkerte værdier/i', $data)) {
1974
						$status = $status_intro . $error_str . gettext("Wrong values - Update could not be completed.");
1975
					} else if (preg_match('/Bruger login: Bruger eksistere ikke/i', $data)) {
1976
						$status = $status_intro . $error_str . gettext("Unknown username - User does not exist.");
1977
					} else if (preg_match('/Bruger login: 1Fejl i kodeord/i', $data)) {
1978
						$status = $status_intro . $error_str . gettext("Wrong password - Remember password is case sensitive.");
1979
					} else if (preg_match('/Domæne kan IKKE administreres af bruger/i', $data)) {
1980
						$status = $status_intro . $error_str . gettext("User unable to administer the selected domain.");
1981
					} else if (preg_match('/OK/i', $data)) {
1982
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1983
						$successful_update = true;
1984
					} else {
1985
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1986
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1987
						$this->_debug($data);
1988
					}
1989
					break;
1990
				case 'digitalocean':
1991
				case 'digitalocean-v6':
1992
					// Creating new records returns an HTTP 201, updating existing records get 200
1993
					// https://redmine.pfsense.org/issues/9171
1994
					if (preg_match("/HTTP\/2\s20[0,1]/i", $header)) {
1995
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1996
						$successful_update = true;
1997
					} else {
1998
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1999
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
2000
						$this->_debug($data);
2001
					}
2002
					break;
2003
				case 'dnsimple':
2004
					/* Responds with HTTP 200 on success.
2005
					   Responds with HTTP 4xx on error.
2006
					   Returns JSON data as body */
2007
;
2008
					if (preg_match("/\s200\sOK/i", $header)) {
2009
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
2010
						$successful_update = true;
2011
					} else if (preg_match("/\s4\d\d\s/i", $header)) {
2012
						$arrbody = json_decode($data, true);
2013
						$message = $arrbody['message'] . ".";
2014
						if (isset($arrbody['errors']['content'])) {
2015
							foreach ($arrbody['errors']['content'] as $key => $content) {
2016
								$message .= " " . $content . ".";
2017
							}
2018
						}
2019
						$status = $status_intro . $error_str . $message;
2020
					} else {
2021
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
2022
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
2023
						$this->_debug($data);
2024
					}
2025
					break;
2026
				case 'godaddy':
2027
				case 'godaddy-v6':
2028
					/* Responds with HTTP 200 on success.
2029
					   Responds with HTTP 4xx or  on error.
2030
					   Returns JSON data as body */
2031
;
2032
					if (preg_match("/\s200\sOK/i", $header)) {
2033
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
2034
						$successful_update = true;
2035
					} else if (preg_match("/\s4\d\d\s/i", $header)) {
2036
						$arrbody = json_decode($data, true);
2037
						$message = $arrbody['message'] . ".";
2038
						if (isset($arrbody['fields'])) {
2039
							foreach ($arrbody['fields'] as $error) {
2040
								$message .= " " . $error['path'] . ": " . $error['message'] . ".";
2041
							}
2042
						}
2043
						$status = $status_intro . $error_str . $message;
2044
					} else {
2045
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
2046
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
2047
						$this->_debug($data);
2048
					}
2049
					break;
2050
				case 'googledomains':
2051
					if (preg_match('/notfqdn/i', $data)) {
2052
						$status = $status_intro . $error_str . gettext("Not A FQDN");
2053
					} else if (preg_match('/nochg/i', $data)) {
2054
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
2055
						$successful_update = true;
2056
					} else if (preg_match('/good/i', $data)) {
2057
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
2058
						$successful_update = true;
2059
					} else if (preg_match('/badauth/i', $data)) {
2060
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
2061
					} else if (preg_match('/nohost/i', $data)) {
2062
						$status = $status_intro . $error_str . gettext("Hostname does not exist or DynDNS not enabled");
2063
					} else if (preg_match('/badagent/i', $data)) {
2064
						$status = $status_intro . $error_str . gettext("Bad request");
2065
					} else if (preg_match('/abuse/i', $data)) {
2066
						$status = $status_intro . $error_str . gettext("Dynamic DNS access has been blocked!");
2067
					} else if (preg_match('/911/i', $data)) {
2068
						$status = $status_intro . $error_str . gettext("Error on Google's end, retry in 5 minutes");
2069
					} else {
2070
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
2071
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
2072
						$this->_debug($data);
2073
					}
2074
					break;
2075
				case 'dnsmadeeasy':
2076
					switch ($data) {
2077
						case 'success':
2078
							$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
2079
							$successful_update = true;
2080
							break;
2081
						case 'error-auth':
2082
							$status = $status_intro . $error_str . gettext("Invalid username or password");
2083
							break;
2084
						case 'error-auth-suspend':
2085
							$status = $status_intro . $error_str . gettext("Account suspended");
2086
							break;
2087
						case 'error-auth-voided':
2088
							$status = $status_intro . $error_str . gettext("Account revoked");
2089
							break;
2090
						case 'error-record-invalid':
2091
							$status = $status_intro . $error_str . gettext("Record does not exist in the system. Unable to update record");
2092
							break;
2093
						case 'error-record-auth':
2094
							$status = $status_intro . $error_str . gettext("User does not have access to this record");
2095
							break;
2096
						case 'error-record-ip-same':
2097
							$status = $status_intro . $success_str . gettext("No Change In IP Address");
2098
							$successful_update = true;
2099
							break;
2100
						case 'error-system':
2101
							$status = $status_intro . $error_str . gettext("General system error recognized by the system");
2102
							break;
2103
						case 'error':
2104
							$status = $status_intro . $error_str . gettext("General system error unrecognized by the system");
2105
							break;
2106
						default:
2107
							$status = $status_intro . "(" . gettext("Unknown Response") . ")";
2108
							log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
2109
							$this->_debug($data);
2110
							break;
2111
					}
2112
					break;
2113
				case 'spdyn':
2114
				case 'spdyn-v6':
2115
					if (preg_match('/notfqdn/i', $data)) {
2116
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
2117
					} else if (preg_match('/nohost/i', $data)) {
2118
						$status = $status_intro . $error_str . gettext("No such host");
2119
					} else if (preg_match('/nochg/i', $data)) {
2120
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
2121
						$successful_update = true;
2122
					} else if (preg_match('/good/i', $data)) {
2123
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
2124
						$successful_update = true;
2125
					} else if (preg_match('/badauth/i', $data)) {
2126
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
2127
					} else {
2128
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
2129
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
2130
						$this->_debug($data);
2131
					}
2132
					break;
2133
				case 'all-inkl':
2134
 					if (preg_match('/good\s'.$this->_dnsIP.'/i', $data)) {
2135
							$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
2136
 							$successful_update = true;
2137
 					} else if (preg_match('/good/i', $data)) {
2138
						$status = $status_intro . $error_str . gettext("Result did not match.");
2139
					} else if (preg_match("/\s401\sUnauthorized/i", $header)) {
2140
						$status = $status_intro . $error_str . gettext("Invalid username or password");
2141
					}
2142
					else {
2143
							$status = $status_intro . "(" . gettext("Unknown Response") . ")";
2144
							log_error($status_intro . gettext("PAYLOAD:") . " " . $header.$data);
2145
 							$this->_debug($data);
2146
 							$this->_debug($header);
2147
 					}
2148
 					break;
2149
				case 'hover':
2150
					if (preg_match('/succeeded":true/i', $data)) {
2151
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
2152
						$successful_update = true;
2153
					} else {
2154
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
2155
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
2156
						$this->_debug($data);
2157
					}
2158
					break;
2159
				case 'cloudns':
2160
					$result = json_decode($data, true);
2161
					if ($result['status'] == 'Success') {
2162
						$successful_update = true;
2163
					} else {
2164
						log_error($result['status'] . "(" . $result['statusDescription'] . ")");
2165
					}
2166
					break;
2167
				case 'dreamhost':
2168
				case 'dreamhost-v6':
2169
					$result = json_decode($data,true);
2170
					if ($this->_dnsVerboseLog) {
2171
						log_error(sprintf(gettext('_checkStatus() results: %1$s'), $data));
2172
					}
2173
					switch ($result['data']) {
2174
					case 'success':
2175
					case 'record_added':
2176
					case 'record_removed':
2177
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
2178
						$successful_update = true;
2179
						break;
2180
					case 'no_record':
2181
					case 'no_such_record ':
2182
						$status = $status_intro . $error_str . gettext("No record exists.");
2183
						break;
2184
					case 'no_type':
2185
					case 'no_such_type ':
2186
						$status = $status_intro . $error_str . gettext("No type exists.");
2187
						break;
2188
					case 'no_value':
2189
					case 'no_such_value ':
2190
						$status = $status_intro . $error_str . gettext("No value exists.");
2191
						break;
2192
					case 'no_such_zone':
2193
						$status = $status_intro . $error_str . gettext("No such zone exists.");
2194
						break;
2195
					case 'invalid_record':
2196
						$status = $status_intro . $error_str . gettext("The specified record is invalid.");
2197
						break;
2198
					case 'invalid_type':
2199
						$status = $status_intro . $error_str . gettext("The specified type is invalid.");
2200
						break;
2201
					case 'invalid_value':
2202
						$status = $status_intro . $error_str . gettext("The specified value is invalid.");
2203
						break;
2204
					case 'not_editable ':
2205
						$status = $status_intro . $error_str . gettext("Record is not editable.");
2206
						break;
2207
					case 'record_already_exists_not_editable':
2208
						$status = $status_intro . $error_str . gettext("Record exists but is not editable.");
2209
						break;
2210
					case 'record_already_exists_remove_first':
2211
						$status = $status_intro . $error_str . gettext("Record exists and must be removed before adding.");
2212
						break;
2213
					case 'internal_error_updating_zone':
2214
						$status = $status_intro . $error_str . gettext("A remote server error occurred updating the zone.");
2215
						break;
2216
					case 'internal_error_could_not_load_zone':
2217
						$status = $status_intro . $error_str . gettext("A remote server error occurred loading the zone.");
2218
						break;
2219
					case 'internal_error_could_not_update_zone':
2220
						$status = $status_intro . $error_str . gettext("A remote server error occurred updating the zone.");
2221
						break;
2222
					case 'internal_error_could_not_add_record':
2223
						$status = $status_intro . $error_str . gettext("A remote server error occurred adding a new record.");
2224
						break;
2225
					case 'internal_error_could_not_destroy_record ':
2226
						$status = $status_intro . $error_str . gettext("A remote server error occurred removing an existing record.");
2227
						break;
2228
					default:
2229
						break;
2230
					}
2231
				case 'azure':
2232
				case 'azurev6':
2233
					$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2234
					if ($http_code == 401) {
2235
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
2236
					} else if ($http_code == 201) {
2237
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
2238
						$successful_update = true;
2239
					} else if ($http_code == 200) {
2240
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
2241
						$successful_update = true;
2242
					} else {
2243
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
2244
						log_error($status_intro . gettext("PAYLOAD:") . " " . $http_code);
2245
						$this->_debug($data);
2246
					}
2247
					break;
2248
				case 'linode':
2249
				case 'linode-v6':
2250
					$status_intro = gettext("Dynamic DNS") . " {$this->_dnsService} ({$this->_FQDN}): ";
2251
					$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2252
					$result = json_decode($data,true);
2253
					if ($this->_dnsVerboseLog) {
2254
						log_error(sprintf(gettext('_checkStatus() results: %1$s'), $data));
2255
					}
2256
					if ($http_code == 200 && isset($result["id"]) && ! isset($result["errors"])) {
2257
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
2258
						$successful_update = true;
2259
					} else if ( $http_code == 401 && preg_match('/not authorized to use/i', $data) ) {
2260
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
2261
					} else {
2262
						$status = $status_intro . $error_str .
2263
							( isset($domains_result["errors"][0]["reason"]) ? $domains_result["errors"][0]["reason"] : "HTTP {$http_code}" );
2264
					}
2265
					break;
2266
				case 'gandi-livedns':
2267
					// NOTE: same as azure
2268
					// Creating new records returns an HTTP 201, updating existing records get 200
2269
					$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2270
					if ($http_code == 401) {
2271
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
2272
					} else if ($http_code == 201) {
2273
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
2274
						$successful_update = true;
2275
					} else if ($http_code == 200) {
2276
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
2277
						$successful_update = true;
2278
					} else {
2279
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
2280
						log_error($status_intro . gettext("PAYLOAD:") . " " . $http_code);
2281
						$this->_debug($data);
2282
					}
2283
					break;
2284
				default:
2285
					break;
2286
			}
2287

    
2288
			if ($successful_update == true) {
2289
				/* Write WAN IP to cache file */
2290
				$wan_ip = $this->_checkIP();
2291
				if ($this->_useIPv6 == false && $wan_ip > 0) {
2292
					$currentTime = time();
2293
					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));
2294
					log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $this->_cacheFile, $wan_ip));
2295
					@file_put_contents($this->_cacheFile, "{$wan_ip}|{$currentTime}");
2296
				} else {
2297
					@unlink($this->_cacheFile);
2298
				}
2299
				if ($this->_useIPv6 == true && $wan_ip > 0) {
2300
					$currentTime = time();
2301
					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));
2302
					log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $this->_cacheFile_v6, $wan_ip));
2303
					@file_put_contents($this->_cacheFile_v6, "{$wan_ip}|{$currentTime}");
2304
				} else {
2305
					@unlink($this->_cacheFile_v6);
2306
				}
2307
			}
2308
			$this->status = $status;
2309
			log_error($status);
2310
		}
2311

    
2312
		/*
2313
		 * Private Function (added 12 July 05) [beta]
2314
		 *   Return Error, Set Last Error, and Die.
2315
		 */
2316
		function _error($errorNumber = '1') {
2317
			$err_str = 'phpDynDNS: (' . gettext('ERROR!') . ') ';
2318
			$err_str_r53 = 'Route 53: (' . gettext('Error') . ') ';
2319
			switch ($errorNumber) {
2320
				case 0:
2321
					break;
2322
				case 2:
2323
					$error = $err_str . gettext('No Dynamic DNS Service provider was selected.');
2324
					break;
2325
				case 3:
2326
					$error = $err_str . gettext('No Username Provided.');
2327
					break;
2328
				case 4:
2329
					$error = $err_str . gettext('No Password Provided.');
2330
					break;
2331
				case 5:
2332
					$error = $err_str . gettext('No Hostname Provided.');
2333
					break;
2334
				case 6:
2335
					$error = $err_str . gettext('The Dynamic DNS Service provided is not yet supported.');
2336
					break;
2337
				case 7:
2338
					$error = $err_str . gettext('No Update URL Provided.');
2339
					break;
2340
				case 8:
2341
					$status = $err_str_r53 . gettext("Invalid ZoneID");
2342
					break;
2343
				case 9:
2344
					$status = $err_str_r53 . gettext("Invalid TTL");
2345
					break;
2346
				case 10:
2347
					$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);
2348
					break;
2349
				default:
2350
					$error = $err_str . gettext('Unknown Response.');
2351
					/* FIXME: $data isn't in scope here */
2352
					/* $this->_debug($data); */
2353
					break;
2354
			}
2355
			$this->lastError = $error;
2356
			log_error($error);
2357
		}
2358

    
2359
		/*
2360
		 * Private Function (added 12 July 05) [beta]
2361
		 *   - Detect whether or not IP needs to be updated.
2362
		 *      | Written Specifically for pfSense (https://www.pfsense.org) may
2363
		 *      | work with other systems. pfSense base is FreeBSD.
2364
		 */
2365
		function _detectChange() {
2366
			global $debug;
2367

    
2368
			if ($debug) {
2369
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _detectChange() starting.'), $this->_dnsService, $this->_FQDN));
2370
			}
2371

    
2372
			$currentTime = time();
2373

    
2374
			$wan_ip = $this->_checkIP();
2375
			if ($wan_ip == 0) {
2376
				log_error(sprintf(gettext("Dynamic Dns (%s): Current WAN IP could not be determined, skipping update process."), $this->_FQDN));
2377
				return false;
2378
			}
2379
			$log_error = sprintf(gettext('Dynamic Dns (%1$s): Current WAN IP: %2$s'), $this->_FQDN, $wan_ip) . " ";
2380

    
2381
			if ($this->_useIPv6 == true) {
2382
				if (file_exists($this->_cacheFile_v6)) {
2383
					$contents = file_get_contents($this->_cacheFile_v6);
2384
					list($cacheIP, $cacheTime) = explode('|', $contents);
2385
					$this->_debug($cacheIP.'/'.$cacheTime);
2386
					$initial = false;
2387
					$log_error .= sprintf(gettext("Cached IPv6: %s"), $cacheIP);
2388
				} else {
2389
					$cacheIP = '::';
2390
					@file_put_contents($this->_cacheFile, "::|{$currentTime}");
2391
					$cacheTime = $currentTime;
2392
					$initial = true;
2393
					$log_error .= gettext("No Cached IPv6 found.");
2394
				}
2395
			} else {
2396
				if (file_exists($this->_cacheFile)) {
2397
					$contents = file_get_contents($this->_cacheFile);
2398
					list($cacheIP, $cacheTime) = explode('|', $contents);
2399
					$this->_debug($cacheIP.'/'.$cacheTime);
2400
					$initial = false;
2401
					$log_error .= sprintf(gettext("Cached IP: %s"), $cacheIP);
2402
				} else {
2403
					$cacheIP = '0.0.0.0';
2404
					@file_put_contents($this->_cacheFile, "0.0.0.0|{$currentTime}");
2405
					$cacheTime = $currentTime;
2406
					$initial = true;
2407
					$log_error .= gettext("No Cached IP found.");
2408
				}
2409
			}
2410
			if ($this->_dnsVerboseLog) {
2411
				log_error($log_error);
2412
			}
2413

    
2414
			// Convert seconds = days * hr/day * min/hr * sec/min
2415
			$maxCacheAgeSecs = $this->_dnsMaxCacheAgeDays * 24 * 60 * 60;
2416

    
2417
			$needs_updating = FALSE;
2418
			/* lets determine if the item needs updating */
2419
			if ($cacheIP != $wan_ip) {
2420
				$needs_updating = true;
2421
				$update_reason = gettext("Dynamic Dns: cacheIP != wan_ip. Updating.") . " ";
2422
				$update_reason .= sprintf(gettext('Cached IP: %1$s WAN IP: %2$s'), $cacheIP, $wan_ip) . " ";
2423
			}
2424
			if (($currentTime - $cacheTime) > $maxCacheAgeSecs) {
2425
				$needs_updating = true;
2426
				$this->_forceUpdateNeeded = true;
2427
				$update_reason = sprintf(gettext("Dynamic Dns: More than %s days. Updating."), $this->_dnsMaxCacheAgeDays);
2428
				$update_reason .= " {$currentTime} - {$cacheTime} > {$maxCacheAgeSecs} ";
2429
			}
2430
			if ($initial == true) {
2431
				$needs_updating = true;
2432
				$update_reason .= gettext("Initial update.");
2433
			}
2434

    
2435
			/*   finally if we need updating then store the
2436
			 *   new cache value and return true
2437
			 */
2438
			if ($needs_updating == true) {
2439
				if ($this->_dnsVerboseLog) {
2440
					log_error("DynDns ({$this->_FQDN}): {$update_reason}");
2441
				}
2442
				return true;
2443
			}
2444

    
2445
			return false;
2446
		}
2447

    
2448
		/*
2449
		 * Private Function (added 16 July 05) [beta]
2450
		 *   - Writes debug information to a file.
2451
		 *   - This function is only called when a unknown response
2452
		 *   - status is returned from a DynDNS service provider.
2453
		 */
2454
		function _debug($data) {
2455
			global $g;
2456

    
2457
			if (!$g['debug']) {
2458
				return;
2459
			}
2460
			$string = date('m-d-y h:i:s').' - ('.$this->_debugID.') - ['.$this->_dnsService.'] - '.$data."\n";
2461
			$file = fopen($this->_debugFile, 'a');
2462
			fwrite($file, $string);
2463
			fclose($file);
2464
		}
2465
		function _checkIP() {
2466
			global $debug;
2467

    
2468
			if ($debug) {
2469
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkIP() starting.'), $this->_dnsService, $this->_FQDN));
2470
			}
2471

    
2472
			if ($this->_useIPv6 == true) {
2473
				$ip_address = get_interface_ipv6($this->_if);
2474
				if (!is_ipaddrv6($ip_address)) {
2475
					return 0;
2476
				}
2477
			} else {
2478
				$ip_address = dyndnsCheckIP($this->_if);
2479
				if (!is_ipaddr($ip_address)) {
2480
					return 0;
2481
				}
2482
			}
2483
			if ($this->_useIPv6 == false && is_private_ip(get_interface_ip($this->_if))) {
2484
				if (is_ipaddr($ip_address)) {
2485
					if ($this->_dnsVerboseLog) {
2486
						log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): %3$s extracted from Check IP Service'), $this->_dnsService, $this->_FQDN, $ip_address));
2487
					}
2488
				} else {
2489
					log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): IP address could not be extracted from Check IP Service'), $this->_dnsService, $this->_FQDN));
2490
					return 0;
2491
				}
2492
			} else {
2493
				if ($this->_dnsVerboseLog) {
2494
					log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): %3$s extracted from local system.'), $this->_dnsService, $this->_FQDN, $ip_address));
2495
				}
2496
			}
2497
			$this->_dnsIP = $ip_address;
2498

    
2499
			return $ip_address;
2500
		}
2501

    
2502
	}
2503

    
2504
?>
(15-15/59)