Project

General

Profile

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

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

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

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

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

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

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

    
215
			$dyndnslck = lock("DDNS".$dnsID, LOCK_EX);
216

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

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

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

    
334
			$this->_debugID = rand(1000000, 9999999);
335

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

    
420
			unlock($dyndnslck);
421
		}
422

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

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

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

    
440
			$ch = curl_init();
441

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

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

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

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

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

    
800
					curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
801

    
802
					if(strpos($this->_dnsUser, '@') !== false){
803
						curl_setopt($ch, CURLOPT_HTTPHEADER, array(
804
							'X-Auth-Email: '.$this->_dnsUser.'',
805
							'X-Auth-Key: '.$this->_dnsPass.'',
806
							'Content-Type: application/json'
807
						));
808

    
809
						// Get zone ID
810
						$getZoneId = "https://{$dnsServer}/client/v4/zones/?name={$this->_dnsDomain}";
811
						curl_setopt($ch, CURLOPT_URL, $getZoneId);
812
						$output = json_decode(curl_exec($ch));
813
						$zone = $output->result[0]->id;
814
					} else {
815
						curl_setopt($ch, CURLOPT_HTTPHEADER, array(
816
							'Authorization: Bearer '.$this->_dnsPass.'',
817
							'Content-Type: application/json'
818
						));
819

    
820
						$zone = $this->_dnsUser;
821
					}
822

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

    
962
					//step 1: login to API
963
					$post_data['username'] = $this->_dnsUser;
964
					$post_data['password'] = $this->_dnsPass;
965
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
966
					curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/login");
967
					curl_setopt($ch, CURLOPT_HEADER, 1); //return the full headers to extract the cookies
968
					$output = curl_exec($ch);
969

    
970
					//extract the cookies
971
					preg_match_all("/^Set-cookie: (.*?);/ism", $output, $cookies);
972
					if( count($cookies[1]) > 0 ){
973
						$cookie_data = implode("; ",$cookies[1]);
974
					}
975

    
976
					//step 2: find the id of the A record
977
					$post_data = null;
978
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
979
					curl_setopt($ch, CURLOPT_COOKIE, $cookie_data);
980
					curl_setopt($ch, CURLOPT_HEADER, 0);
981
					curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/dns");
982
					curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
983

    
984
					$output = curl_exec($ch);
985
					$pregHost = preg_quote($this->_dnsHost);
986
					$pregDomain = preg_quote($this->_dnsDomain);
987
					preg_match("/^{\"succeeded\":true.*?domain_name\":\"{$pregDomain}.*?entries.*?{\"id\":\"([^\"]*?)\",\"name\":\"{$pregHost}\",\"type\":\"A\".*?\$/", $output, $hostID);
988
					$hostID = $hostID[1];
989
					preg_match("/^{\"succeeded\":true.*?domain_name\":\"{$pregDomain}.*?entries.*?{[^\}]*?\"name\":\"{$pregHost}\",\"type\":\"A\".*?content\":\"([^\"]*?)\".*?\$/", $output, $hostIP);
990
					$hostIP = $hostIP[1];
991
					unset($pregHost);
992
					unset($pregDomain);
993

    
994
					//step 3: update the IP
995
					if ($hostID) {
996
						curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
997
						curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
998
						curl_setopt($ch, CURLOPT_COOKIE, $cookie_data);
999
						$post_data['content'] = $this->_dnsIP;
1000
						curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1001
						curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
1002
						curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/dns/{$hostID}");
1003
						log_error("HostID:{$hostID}, OldIP:{$hostIP}");
1004
					}
1005
					break;
1006
				case 'dreamhost':
1007
				case 'dreamhost-v6':
1008
					$needsIP = TRUE;
1009
					$isv6 = ($this->_dnsService === 'dreamhost-v6');
1010
					$server = 'https://api.dreamhost.com/';
1011
					$post_data['key'] = $this->_dnsPass;
1012
					$post_data['unique_id'] = uniqid($this->_dnsHost);
1013
					$post_data['cmd'] = 'dns-add_record';
1014
					$post_data['format'] = 'json';
1015
					$post_data['value'] = $this->_dnsIP;
1016
					$post_data['record'] = $this->_dnsHost;
1017
					$post_data['type'] = $isv6 ? 'AAAA' : 'A';
1018
					$post_data['comment'] = "Updated by pfSense:$this->_dnsUser on ".date('c');
1019
					$port = "";
1020
					if ($this->_dnsServer) {
1021
						$server = $this->_dnsServer;
1022
					}
1023
					if ($this->_dnsPort) {
1024
						$port = ":" . $this->_dnsPort;
1025
					}
1026
					curl_setopt($ch, CURLOPT_URL, $server . $port);
1027
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1028
					break;
1029
				case 'digitalocean':
1030
				case 'digitalocean-v6':
1031
					// Get record ID
1032
					$server = 'https://api.digitalocean.com/v2/domains/';
1033
					$isv6 = ($this->_dnsService === 'digitalocean-v6');
1034
					$url = $server . $this->_dnsDomain . '/records';
1035
					curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer {$this->_dnsPass}"));
1036
					curl_setopt($ch, CURLOPT_URL, $url);
1037
					$output = json_decode(curl_exec($ch));
1038
					if (!is_array($output->domain_records)) {
1039
						$output->domain_records = array();
1040
					}
1041
					foreach($output->domain_records as $dnsRecord) {
1042
						// NS records are named @ in DO's API, so check type as well 
1043
						// https://redmine.pfsense.org/issues/9171
1044
						if ($this->_dnsHost == $dnsRecord->name && $dnsRecord->type == 'A') {
1045
							$recordID = $dnsRecord->id;
1046
							break;
1047
						}
1048
					}
1049

    
1050
					// Create/update record
1051
					if ($recordID == null) {
1052
						$url = $server . $this->_dnsDomain . '/records';
1053
					} else {
1054
						$url = $server . $this->_dnsDomain . '/records/' . $recordID;
1055
						curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
1056
					}
1057
					$post_data['type'] = $isv6 ? 'AAAA' : 'A';
1058
					$post_data['ttl'] = $this->_dnsTTL;
1059
					$post_data['name'] = $this->_dnsHost;
1060
					$post_data['data'] = $this->_dnsIP;
1061
					curl_setopt($ch, CURLOPT_URL, $url);
1062
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1063
					break;
1064
				case 'cloudns':
1065
					/* Uses ClouDNS REST API
1066
					   Requires auth-id or sub-auth-id or sub-auth-user */
1067
					// Step 1: Find the Record ID
1068
					$url = 'https://api.cloudns.net/dns/records.json';
1069
					$post_data['auth-id'] = $this->_dnsUser;
1070
					$post_data['auth-password'] = $this->_dnsPass;
1071
					$post_data['domain-name'] = $this->_dnsDomain;
1072
					$post_data['host'] = $this->_dnsHost;
1073
					$post_data['type'] = 'a';
1074
					curl_setopt($ch, CURLOPT_URL, $url);
1075
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1076
					$output = json_decode(curl_exec($ch));
1077
					$recordID = key(get_object_vars($output));
1078

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

    
1174
					// get domain id
1175
					curl_setopt($ch, CURLOPT_URL, "{$linode_api}/domains");
1176
					$domains_output = curl_exec($ch);
1177
					$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1178
					if ( $http_code == 401 && preg_match('/invalid oauth token/i', $domains_output) ) {
1179
						log_error("$err_prefix " . gettext("querying domains") . ": " . gettext("User Authentication Failed"));
1180
						return false;
1181
					} else if ( $http_code == 401 ) {
1182
						log_error("$err_prefix " . gettext("querying domains") . ": " . gettext("User Authorization Failed"));
1183
						return false;
1184
					} else if ( $http_code != 200 ) {
1185
						log_error("$err_prefix " . gettext("querying domains") . ": " .
1186
							( isset($domains_result["errors"][0]["reason"]) ? $domains_result["errors"][0]["reason"] : "HTTP {$http_code}" ) );
1187
						return false;
1188
					}
1189

    
1190
					$domains_result = json_decode($domains_output, TRUE);
1191
					foreach($domains_result["data"] as $domains_entry) {
1192
						if ($domains_entry["domain"] == $this->_dnsDomain) {
1193
							$domain_id = $domains_entry["id"];
1194
						}
1195
					}
1196
					if ( ! $domain_id ) {
1197
						log_error("{$err_prefix} " . gettext("no domain ID for domain") . ": '{$this->_dnsDomain}'");
1198
						return false;
1199
					}
1200
					if ($this->_dnsVerboseLog) {
1201
						log_error("_update(): " . sprintf(gettext("found domain id: %s"), $domain_id));
1202
					}
1203

    
1204
					// get existing record if present
1205
					curl_setopt($ch, CURLOPT_URL, "{$linode_api}/domains/{$domain_id}/records");
1206
					$records_output = curl_exec($ch);
1207
					$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1208
					if ( $http_code != 200 )
1209
					{
1210
						log_error("$err_prefix " . gettext("querying domains") . ": " .
1211
							( isset($domains_result["errors"][0]["reason"]) ? $domains_result["errors"][0]["reason"] : "HTTP {$http_code}" ) );
1212
						return false;
1213
					}
1214

    
1215
					$records_result = json_decode($records_output, TRUE);
1216
					foreach($records_result["data"] as $records_entry) {
1217
						if ( $records_entry["type"] == $record_type && $records_entry["name"] == $record_name ) {
1218
							// not adding support for pagination at this time, hope you have < 100 records!
1219
							$record = $records_entry;
1220
						}
1221
					}
1222
					if ($this->_dnsVerboseLog) {
1223
						log_error("_update(): " . ( $record ? sprintf(gettext("found existing record id: %s"), $record["id"]) : gettext("no matching record found") ));
1224
					}
1225

    
1226
					if (is_array($record)) {
1227
						// update existing record
1228
						$record["target"] = $this->_dnsIP;
1229
						$record["ttl_sec"] = (int) $this->_dnsTTL; // linode may round this up, 0 = zone default
1230
						curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($record));
1231
						curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
1232
						curl_setopt($ch, CURLOPT_URL, "{$linode_api}/domains/{$domain_id}/records/" . $record["id"]);
1233
					} else {
1234
						// create a new record
1235
						$record = array(
1236
							"type"    => $record_type,
1237
							"name"    => $record_name,
1238
							"target"  => $this->_dnsIP,
1239
							"ttl_sec" => (int) $this->_dnsTTL, // linode may round this up, 0 = zone default
1240
						);
1241
						curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($record));
1242
						curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
1243
						curl_setopt($ch, CURLOPT_URL, "{$linode_api}/domains/{$domain_id}/records");
1244
					}
1245

    
1246
				break;
1247
			case 'gandi-livedns':
1248
				// NOTE: quite similar to digitalocean case but with json content like azure case
1249
				// Get record href
1250
				$server = 'https://dns.api.gandi.net/api/v5/domains/';
1251
				$url = $server . $this->_dnsDomain . '/records';
1252
				curl_setopt($ch, CURLOPT_HTTPHEADER, array("X-Api-Key: {$this->_dnsPass}"));
1253
				curl_setopt($ch, CURLOPT_URL, $url);
1254
				$output = json_decode(curl_exec($ch));
1255
				if (!is_array($output)) {
1256
					$output = array();
1257
				}
1258
				foreach($output as $dnsRecord) {
1259
					// NS records are named @ in DO's API, so check type as well
1260
					if ($this->_dnsHost == $dnsRecord->rrset_name && $dnsRecord->rrset_type == 'A') {
1261
						$recordHref = $dnsRecord->rrset_href;
1262
						break;
1263
					}
1264
				}
1265
				$request_headers = array();
1266
				//$request_headers[] = 'Accept: application/json';
1267
				$request_headers[] = 'X-Api-Key: ' .$this->_dnsPass;
1268
				$request_headers[] = 'Content-Type: application/json';
1269
				//create or update record
1270
				if ($recordHref == null) {
1271
					//create record
1272
					$url = $server . $this->_dnsDomain . '/records';
1273
					$body = '{"rrset_type": "A", "rrset_ttl": ' . $this->_dnsTTL . ', "rrset_name": "' . $this->_dnsHost . '", "rrset_values": ["' . $this->_dnsIP . '"]}';
1274
				} else {
1275
					//update record
1276
					$url = $recordHref;
1277
					$body = '{"rrset_ttl": ' . $this->_dnsTTL . ', "rrset_values": ["' . $this->_dnsIP . '"]}';
1278
					curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
1279
				}
1280
				curl_setopt($ch, CURLOPT_URL, $url);
1281
				curl_setopt($ch, CURLOPT_HTTPHEADER, $request_headers);
1282
				curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
1283
					break;
1284
				default:
1285
					break;
1286
			}
1287
			if ($this->_dnsService != 'ods') {
1288
				curl_setopt($ch, CURLOPT_HEADER, 1);
1289
				$response = curl_exec($ch);
1290
				$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1291
				$header = substr($response, 0, $header_size);
1292
				$data = substr($response, $header_size);
1293
				$this->_checkStatus($ch, $data, $header);
1294
				@curl_close($ch);
1295
			}
1296
		}
1297

    
1298
		/**
1299
		 * Private Function (added 23 Feb 17)
1300
		 *   Send Removal To Selected Service.
1301
		 *
1302
		 *   Some services do not perform an inplace upgrade.  If they do not then the solution
1303
		 *   is to remove the existing record and add a new record.
1304
		 *
1305
		 * @param unknown $existing_ip If required, an existing IP address for the record.
1306
		 */
1307
		function _remove($existing_ip = NULL) {
1308
			$remove_allowed = false;
1309
			if ($this->_dnsVerboseLog) {
1310
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _remove() starting.'), $this->_dnsService, $this->_FQDN));
1311
			}
1312

    
1313
			if (strstr($this->_dnsRequestIf, "_vip")) {
1314
				$parentif = get_configured_vip_interface($this->_dnsRequestIf);
1315
				$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
1316
			} else {
1317
				$realparentif = $this->_dnsRequestIf;
1318
			}
1319

    
1320
			$ch = curl_init();
1321

    
1322
			if ($this->_useIPv6 == false) {
1323
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1324
			}
1325

    
1326
			curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
1327
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
1328
			curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
1329
			curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
1330

    
1331
			switch ($this->_dnsService) {
1332
			case 'dreamhost':
1333
			case 'dreamhost-v6':
1334
				$server = 'https://api.dreamhost.com/';
1335
				$post_data['key'] = $this->_dnsPass;
1336
				$post_data['unique_id'] = uniqid($this->_dnsHost);
1337
				$post_data['cmd'] = 'dns-remove_record';
1338
				$post_data['format'] = 'json';
1339
				$post_data['value'] = $existing_ip;
1340
				$post_data['record'] = $this->_dnsHost;
1341
				$isv6 = ($this->_dnsService === 'dreamhost-v6');
1342
				$post_data['type'] = $isv6 ? 'AAAA' : 'A';
1343
				$port = "";
1344
				if ($this->_dnsServer) {
1345
					$server = $this->_dnsServer;
1346
				}
1347
				if ($this->_dnsPort) {
1348
					$port = ":" . $this->_dnsPort;
1349
				}
1350
				curl_setopt($ch, CURLOPT_URL, $server . $port);
1351
				curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1352
				$remove_allowed = true;
1353
				break;
1354
			default:
1355
				break;
1356
			}
1357
			if ($remove_allowed) {
1358
				curl_setopt($ch, CURLOPT_HEADER, 1);
1359
				$response = curl_exec($ch);
1360
				$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1361
				$header = substr($response, 0, $header_size);
1362
				$data = substr($response, $header_size);
1363
				$this->_checkStatus($ch, $data, $header);
1364
				@curl_close($ch);
1365
			}
1366
		}
1367

    
1368
		/**
1369
		 * Private Function (added 23 Feb 17)
1370
		 * Retrieves current DNS records from an external API source.
1371
		 *
1372
		 * Some services cannot perform new operations without the caller
1373
		 * providing existing record information.
1374
		 */
1375
		function _lookup_current() {
1376
			$lookup_allowed = false;
1377
			if ($this->_dnsVerboseLog) {
1378
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _listCurrent() starting.'), $this->_dnsService, $this->_FQDN));
1379
			}
1380

    
1381
			if (strstr($this->_dnsRequestIf, "_vip")) {
1382
				$parentif = get_configured_vip_interface($this->_dnsRequestIf);
1383
				$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
1384
			} else {
1385
				$realparentif = $this->_dnsRequestIf;
1386
			}
1387

    
1388
			$ch = curl_init();
1389

    
1390
			if ($this->_useIPv6 == false) {
1391
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1392
			}
1393

    
1394
			curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
1395
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
1396
			curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
1397
			curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
1398

    
1399
			switch ($this->_dnsService) {
1400
			case 'dreamhost':
1401
			case 'dreamhost-v6':
1402
				$server = 'https://api.dreamhost.com/';
1403
				$post_data['key'] = $this->_dnsPass;
1404
				$post_data['unique_id'] = uniqid($this->_dnsHost);
1405
				$post_data['cmd'] = 'dns-list_records';
1406
				$post_data['format'] = 'json';
1407
				$port = "";
1408
				if ($this->_dnsServer) {
1409
					$server = $this->_dnsServer;
1410
				}
1411
				if ($this->_dnsPort) {
1412
					$port = ":" . $this->_dnsPort;
1413
				}
1414
				curl_setopt($ch, CURLOPT_URL, $server . $port);
1415
				curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1416
				$lookup_allowed = true;
1417
				break;
1418
			default:
1419
				break;
1420
			}
1421
			if ($lookup_allowed) {
1422
				curl_setopt($ch, CURLOPT_HEADER, 1);
1423
				$response = curl_exec($ch);
1424
				$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1425
				$header = substr($response, 0, $header_size);
1426
				$data = substr($response, $header_size);
1427
				$this->_checkLookupStatus($ch, $data, $header);
1428
				@curl_close($ch);
1429
			}
1430
		}
1431

    
1432
		/*
1433
		 * Private Function (added 23 Feb 17)
1434
		 *   Retrieve Lookup Status from the provided data and/or header
1435
		 */
1436
		function _checkLookupStatus($ch, $data, $header) {
1437
			if ($this->_dnsVerboseLog) {
1438
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkLookupStatus() starting.'), $this->_dnsService, $this->_FQDN));
1439
			}
1440
			$success_str = "(" . gettext("Success") . ") ";
1441
			$error_str = "(" . gettext("Error") . ") ";
1442
			$status_intro = "phpDynDNS ({$this->_dnsHost}): ";
1443

    
1444
			if ($this->_dnsService != 'ods' && @curl_error($ch)) {
1445
				$status = gettext("Curl error occurred:") . " " . curl_error($ch);
1446
				log_error($status);
1447
				$this->status = $status;
1448
				return;
1449
			}
1450
			switch ($this->_dnsService) {
1451
			case 'dreamhost':
1452
			case 'dreamhost-v6':
1453
				$result = json_decode($data,true);
1454
				if($result["result"] != "success") {
1455
					log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1456
					$this->_debug($data);
1457
					return;
1458
				} else {
1459
					foreach($result["data"] as $key => $row) {
1460
						if($row["record"] == $this->_dnsHost &&
1461
								(($row["type"] == "A" && !$this->_useIPv6)
1462
										|| ($row["type"] == "AAAA" && $this->_useIPv6)
1463
								)) {
1464
							if($row["editable"] == 0) {
1465
								log_error($status_intro . "host " . $this->_dnsHost . " is not editable.");
1466
								continue;
1467
							}
1468
							$this->_existingRecords[]=array("record"=>$row["type"], "type"=>$row["type"], "existing_val"=>$row["value"]);
1469
						}
1470
					}
1471
				}
1472
				if (!is_array($this->_existingRecords)){
1473
					if ($this->_dnsVerboseLog) {
1474
						log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkLookupStatus() ending.  No matching records found.'), $this->_dnsService, $this->_FQDN));
1475
					}
1476
				}
1477
				break;
1478
			default:
1479
				break;
1480
			}
1481
		}
1482

    
1483
		/*
1484
		 * Private Function (added 12 July 2005) [beta]
1485
		 *   Retrieve Update Status
1486
		 */
1487
		function _checkStatus($ch, $data, $header) {
1488
			if ($this->_dnsVerboseLog) {
1489
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkStatus() starting.'), $this->_dnsService, $this->_FQDN));
1490
			}
1491
			$successful_update = false;
1492
			$success_str = "(" . gettext("Success") . ") ";
1493
			$error_str = "(" . gettext("Error") . ") ";
1494
			$status_intro = "phpDynDNS ({$this->_dnsHost}): ";
1495

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

    
2312
			if ($successful_update == true) {
2313
				/* Write WAN IP to cache file */
2314
				$wan_ip = $this->_checkIP();
2315
				if ($this->_useIPv6 == false && $wan_ip > 0) {
2316
					$currentTime = time();
2317
					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));
2318
					log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $this->_cacheFile, $wan_ip));
2319
					@file_put_contents($this->_cacheFile, "{$wan_ip}|{$currentTime}");
2320
				} else {
2321
					@unlink($this->_cacheFile);
2322
				}
2323
				if ($this->_useIPv6 == true && $wan_ip > 0) {
2324
					$currentTime = time();
2325
					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));
2326
					log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $this->_cacheFile_v6, $wan_ip));
2327
					@file_put_contents($this->_cacheFile_v6, "{$wan_ip}|{$currentTime}");
2328
				} else {
2329
					@unlink($this->_cacheFile_v6);
2330
				}
2331
			}
2332
			$this->status = $status;
2333
			log_error($status);
2334
		}
2335

    
2336
		/*
2337
		 * Private Function (added 12 July 05) [beta]
2338
		 *   Return Error, Set Last Error, and Die.
2339
		 */
2340
		function _error($errorNumber = '1') {
2341
			$err_str = 'phpDynDNS: (' . gettext('ERROR!') . ') ';
2342
			$err_str_r53 = 'Route 53: (' . gettext('Error') . ') ';
2343
			switch ($errorNumber) {
2344
				case 0:
2345
					break;
2346
				case 2:
2347
					$error = $err_str . gettext('No Dynamic DNS Service provider was selected.');
2348
					break;
2349
				case 3:
2350
					$error = $err_str . gettext('No Username Provided.');
2351
					break;
2352
				case 4:
2353
					$error = $err_str . gettext('No Password Provided.');
2354
					break;
2355
				case 5:
2356
					$error = $err_str . gettext('No Hostname Provided.');
2357
					break;
2358
				case 6:
2359
					$error = $err_str . gettext('The Dynamic DNS Service provided is not yet supported.');
2360
					break;
2361
				case 7:
2362
					$error = $err_str . gettext('No Update URL Provided.');
2363
					break;
2364
				case 8:
2365
					$status = $err_str_r53 . gettext("Invalid ZoneID");
2366
					break;
2367
				case 9:
2368
					$status = $err_str_r53 . gettext("Invalid TTL");
2369
					break;
2370
				case 10:
2371
					$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);
2372
					break;
2373
				default:
2374
					$error = $err_str . gettext('Unknown Response.');
2375
					/* FIXME: $data isn't in scope here */
2376
					/* $this->_debug($data); */
2377
					break;
2378
			}
2379
			$this->lastError = $error;
2380
			log_error($error);
2381
		}
2382

    
2383
		/*
2384
		 * Private Function (added 12 July 05) [beta]
2385
		 *   - Detect whether or not IP needs to be updated.
2386
		 *      | Written Specifically for pfSense (https://www.pfsense.org) may
2387
		 *      | work with other systems. pfSense base is FreeBSD.
2388
		 */
2389
		function _detectChange() {
2390
			global $debug;
2391

    
2392
			if ($debug) {
2393
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _detectChange() starting.'), $this->_dnsService, $this->_FQDN));
2394
			}
2395

    
2396
			$currentTime = time();
2397

    
2398
			$wan_ip = $this->_checkIP();
2399
			if ($wan_ip == 0) {
2400
				log_error(sprintf(gettext("Dynamic Dns (%s): Current WAN IP could not be determined, skipping update process."), $this->_FQDN));
2401
				return false;
2402
			}
2403
			$log_error = sprintf(gettext('Dynamic Dns (%1$s): Current WAN IP: %2$s'), $this->_FQDN, $wan_ip) . " ";
2404

    
2405
			if ($this->_useIPv6 == true) {
2406
				if (file_exists($this->_cacheFile_v6)) {
2407
					$contents = file_get_contents($this->_cacheFile_v6);
2408
					list($cacheIP, $cacheTime) = explode('|', $contents);
2409
					$this->_debug($cacheIP.'/'.$cacheTime);
2410
					$initial = false;
2411
					$log_error .= sprintf(gettext("Cached IPv6: %s"), $cacheIP);
2412
				} else {
2413
					$cacheIP = '::';
2414
					@file_put_contents($this->_cacheFile, "::|{$currentTime}");
2415
					$cacheTime = $currentTime;
2416
					$initial = true;
2417
					$log_error .= gettext("No Cached IPv6 found.");
2418
				}
2419
			} else {
2420
				if (file_exists($this->_cacheFile)) {
2421
					$contents = file_get_contents($this->_cacheFile);
2422
					list($cacheIP, $cacheTime) = explode('|', $contents);
2423
					$this->_debug($cacheIP.'/'.$cacheTime);
2424
					$initial = false;
2425
					$log_error .= sprintf(gettext("Cached IP: %s"), $cacheIP);
2426
				} else {
2427
					$cacheIP = '0.0.0.0';
2428
					@file_put_contents($this->_cacheFile, "0.0.0.0|{$currentTime}");
2429
					$cacheTime = $currentTime;
2430
					$initial = true;
2431
					$log_error .= gettext("No Cached IP found.");
2432
				}
2433
			}
2434
			if ($this->_dnsVerboseLog) {
2435
				log_error($log_error);
2436
			}
2437

    
2438
			// Convert seconds = days * hr/day * min/hr * sec/min
2439
			$maxCacheAgeSecs = $this->_dnsMaxCacheAgeDays * 24 * 60 * 60;
2440

    
2441
			$needs_updating = FALSE;
2442
			/* lets determine if the item needs updating */
2443
			if ($cacheIP != $wan_ip) {
2444
				$needs_updating = true;
2445
				$update_reason = gettext("Dynamic Dns: cacheIP != wan_ip. Updating.") . " ";
2446
				$update_reason .= sprintf(gettext('Cached IP: %1$s WAN IP: %2$s'), $cacheIP, $wan_ip) . " ";
2447
			}
2448
			if (($currentTime - $cacheTime) > $maxCacheAgeSecs) {
2449
				$needs_updating = true;
2450
				$this->_forceUpdateNeeded = true;
2451
				$update_reason = sprintf(gettext("Dynamic Dns: More than %s days. Updating."), $this->_dnsMaxCacheAgeDays);
2452
				$update_reason .= " {$currentTime} - {$cacheTime} > {$maxCacheAgeSecs} ";
2453
			}
2454
			if ($initial == true) {
2455
				$needs_updating = true;
2456
				$update_reason .= gettext("Initial update.");
2457
			}
2458

    
2459
			/*   finally if we need updating then store the
2460
			 *   new cache value and return true
2461
			 */
2462
			if ($needs_updating == true) {
2463
				if ($this->_dnsVerboseLog) {
2464
					log_error("DynDns ({$this->_FQDN}): {$update_reason}");
2465
				}
2466
				return true;
2467
			}
2468

    
2469
			return false;
2470
		}
2471

    
2472
		/*
2473
		 * Private Function (added 16 July 05) [beta]
2474
		 *   - Writes debug information to a file.
2475
		 *   - This function is only called when a unknown response
2476
		 *   - status is returned from a DynDNS service provider.
2477
		 */
2478
		function _debug($data) {
2479
			global $g;
2480

    
2481
			if (!$g['debug']) {
2482
				return;
2483
			}
2484
			$string = date('m-d-y h:i:s').' - ('.$this->_debugID.') - ['.$this->_dnsService.'] - '.$data."\n";
2485
			$file = fopen($this->_debugFile, 'a');
2486
			fwrite($file, $string);
2487
			fclose($file);
2488
		}
2489
		function _checkIP() {
2490
			global $debug;
2491

    
2492
			if ($debug) {
2493
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkIP() starting.'), $this->_dnsService, $this->_FQDN));
2494
			}
2495

    
2496
			if ($this->_useIPv6 == true) {
2497
				$ip_address = get_interface_ipv6($this->_if);
2498
				if (!is_ipaddrv6($ip_address)) {
2499
					return 0;
2500
				}
2501
			} else {
2502
				$ip_address = dyndnsCheckIP($this->_if);
2503
				if (!is_ipaddr($ip_address)) {
2504
					return 0;
2505
				}
2506
			}
2507
			if ($this->_useIPv6 == false && is_private_ip(get_interface_ip($this->_if))) {
2508
				if (is_ipaddr($ip_address)) {
2509
					if ($this->_dnsVerboseLog) {
2510
						log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): %3$s extracted from Check IP Service'), $this->_dnsService, $this->_FQDN, $ip_address));
2511
					}
2512
				} else {
2513
					log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): IP address could not be extracted from Check IP Service'), $this->_dnsService, $this->_FQDN));
2514
					return 0;
2515
				}
2516
			} else {
2517
				if ($this->_dnsVerboseLog) {
2518
					log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): %3$s extracted from local system.'), $this->_dnsService, $this->_FQDN, $ip_address));
2519
				}
2520
			}
2521
			$this->_dnsIP = $ip_address;
2522

    
2523
			return $ip_address;
2524
		}
2525

    
2526
	}
2527

    
2528
?>
(15-15/60)