Project

General

Profile

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

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

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

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

    
185
			global $config, $g, $dyndns_split_domain_types;
186
			if (in_array($dnsService, $dyndns_split_domain_types)) {
187
				$this->_FQDN = $dnsHost . "." . $dnsDomain;
188
			} else {
189
				$this->_FQDN = $dnsHost;
190
			}
191

    
192
			$this->_cacheFile = "{$g['conf_path']}/dyndns_{$dnsIf}{$dnsService}" . escapeshellarg($this->_FQDN) . "{$dnsID}.cache";
193
			$this->_cacheFile_v6 = "{$g['conf_path']}/dyndns_{$dnsIf}{$dnsService}" . escapeshellarg($this->_FQDN) . "{$dnsID}_v6.cache";
194
			$this->_debugFile = "{$g['varetc_path']}/dyndns_{$dnsIf}{$dnsService}" . escapeshellarg($this->_FQDN) . "{$dnsID}.debug";
195

    
196
			$this->_curlIpresolveV4 = $curlIpresolveV4;
197
			$this->_curlSslVerifypeer = $curlSslVerifypeer;
198
			$this->_dnsVerboseLog = $dnsVerboseLog;
199
			if ($this->_dnsVerboseLog) {
200
				log_error(gettext("Dynamic DNS: updatedns() starting"));
201
			}
202

    
203
			$dyndnslck = lock("DDNS".$dnsID, LOCK_EX);
204

    
205
			if (!$dnsService) $this->_error(2);
206
			switch ($dnsService) {
207
			case 'freedns':
208
			case 'freedns-v6':
209
				if (!$dnsHost) $this->_error(5);
210
				break;
211
			case "namecheap":
212
				if (!$dnsPass) $this->_error(4);
213
				if (!$dnsHost) $this->_error(5);
214
				if (!$dnsDomain) $this->_error(5);
215
				break;
216
			case "cloudflare-v6":
217
			case "cloudflare":
218
			case "gratisdns":
219
			case "hover":
220
				if (!$dnsUser) $this->_error(3);
221
				if (!$dnsPass) $this->_error(4);
222
				if (!$dnsHost) $this->_error(5);
223
				if (!$dnsDomain) $this->_error(5);
224
				break;
225
			case 'route53':
226
				if (!$dnsZoneID) $this->_error(8);
227
				if (!$dnsTTL) $this->_error(9);
228
				break;
229
			case 'custom':
230
				if (!$dnsUpdateURL) $this->_error(7);
231
				break;
232
			default:
233
				if (!$dnsUser) $this->_error(3);
234
				if (!$dnsPass) $this->_error(4);
235
				if (!$dnsHost) $this->_error(5);
236
			}
237

    
238
			switch ($dnsService) {
239
				case 'he-net-v6':
240
				case 'custom-v6':
241
				case 'spdyn-v6':
242
				case 'duiadns-v6':
243
				case 'freedns-v6':
244
				case 'cloudflare-v6':
245
				case 'dreamhost-v6':
246
					$this->_useIPv6 = true;
247
					break;
248
				default:
249
					$this->_useIPv6 = false;
250
			}
251
			$this->_dnsService = strtolower($dnsService);
252
			$this->_dnsUser = $dnsUser;
253
			$this->_dnsPass = base64_decode($dnsPass);
254
			$this->_dnsHost = $dnsHost;
255
			$this->_dnsDomain = $dnsDomain;
256
			$this->_dnsServer = $dnsServer;
257
			$this->_dnsPort = $dnsPort;
258
			$this->_dnsWildcard = $dnsWildcard;
259
			$this->_dnsProxied = $dnsProxied;
260
			$this->_dnsMX = $dnsMX;
261
			$this->_dnsZoneID = $dnsZoneID;
262
			$this->_dnsTTL = $dnsTTL;
263
			$this->_if = get_failover_interface($dnsIf);
264
			$this->_checkIP();
265
			$this->_dnsUpdateURL = $dnsUpdateURL;
266
			$this->_dnsResultMatch = $dnsResultMatch;
267
			$this->_dnsRequestIf = get_failover_interface($dnsRequestIf);
268
			if ($this->_dnsVerboseLog) {
269
				log_error(sprintf(gettext('Dynamic DNS (%1$s): running get_failover_interface for %2$s. found %3$s'), $this->_FQDN, $dnsRequestIf, $this->_dnsRequestIf));
270
			}
271
			$this->_dnsRequestIfIP = get_interface_ip($dnsRequestIf);
272
			$this->_dnsMaxCacheAgeDays = 25;
273
			$this->_dnsDummyUpdateDone = false;
274
			$this->_forceUpdateNeeded = $forceUpdate;
275

    
276
			// Ensure that we were able to lookup the IP
277
			if (!is_ipaddr($this->_dnsIP)) {
278
				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));
279
				unlock($dyndnslck);
280
				return;
281
			}
282

    
283
			$this->_debugID = rand(1000000, 9999999);
284

    
285
			if ($forceUpdate == false && $this->_detectChange() == false) {
286
				$this->_error(10);
287
			} else {
288
				switch ($this->_dnsService) {
289
					case 'glesys':
290
					case 'dnsomatic':
291
					case 'dyndns':
292
					case 'dyndns-static':
293
					case 'dyndns-custom':
294
					case 'dhs':
295
					case 'noip':
296
					case 'noip-free':
297
					case 'easydns':
298
					case 'hn':
299
					case 'zoneedit':
300
					case 'dyns':
301
					case 'ods':
302
					case 'freedns':
303
					case 'freedns-v6':
304
					case 'loopia':
305
					case 'staticcling':
306
					case 'dnsexit':
307
					case 'custom':
308
					case 'custom-v6':
309
					case 'opendns':
310
					case 'namecheap':
311
					case 'he-net':
312
					case 'he-net-v6':
313
					case 'duiadns':
314
					case 'duiadns-v6':
315
					case 'selfhost':
316
					case 'he-net-tunnelbroker':
317
					case 'route53':
318
					case 'cloudflare':
319
					case 'cloudflare-v6':
320
					case 'eurodns':
321
					case 'gratisdns':
322
					case 'ovh-dynhost':
323
					case 'citynetwork':
324
					case 'dnsimple':
325
					case 'googledomains':
326
					case 'dnsmadeeasy':
327
					case 'spdyn':
328
					case 'spdyn-v6':
329
					case 'all-inkl':
330
					case 'hover':
331
						$this->_update();
332
						if ($this->_dnsDummyUpdateDone == true) {
333
							// If a dummy update was needed, then sleep a while and do the update again to put the proper address back.
334
							// Some providers (e.g. No-IP free accounts) need to have at least 1 address change every month.
335
							// If the address has not changed recently, or the user did "Force Update", then the code does
336
							// a dummy address change for providers like this.
337
							sleep(10);
338
							$this->_update();
339
						}
340
						break;
341
					case 'dreamhost':
342
					case 'dreamhost-v6':
343
						$this->_lookup_current();
344
						if (isset($this->status)) {
345
							return;
346
						}
347
						foreach ($this->_existingRecords as $record) {
348
							$this->_remove($record['existing_val']);
349
							$this->_update();
350
						}
351
						break;
352
					default:
353
						$this->_error(6);
354
						break;
355
				}
356
			}
357

    
358
			unlock($dyndnslck);
359
		}
360

    
361
		/*
362
		 * Private Function (added 12 July 05) [beta]
363
		 *   Send Update To Selected Service.
364
		 */
365
		function _update() {
366

    
367
			if ($this->_dnsVerboseLog) {
368
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _update() starting.'), $this->_dnsService, $this->_FQDN));
369
			}
370

    
371
			if (strstr($this->_dnsRequestIf, "_vip")) {
372
				$parentif = get_configured_vip_interface($this->_dnsRequestIf);
373
				$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
374
			} else {
375
				$realparentif = $this->_dnsRequestIf;
376
			}
377

    
378
			$ch = curl_init();
379

    
380
			if ($this->_useIPv6 == false) {
381
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
382
			}
383

    
384
			if ($this->_dnsService != 'ods') {
385
				curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
386
				curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
387
				curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
388
				curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
389
			}
390

    
391
			switch ($this->_dnsService) {
392
				case 'glesys':
393
					$needsIP = TRUE;
394
					$server = 'https://api.glesys.com/domain/updaterecord/format/json';
395
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
396
					$post_data['recordid'] = $this->_FQDN;
397
					$post_data['data'] = $this->_dnsIP;
398
					curl_setopt($ch, CURLOPT_URL, $server);
399
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
400
					break;
401
				case 'dyndns':
402
				case 'dyndns-static':
403
				case 'dyndns-custom':
404
					$needsIP = FALSE;
405
					if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") {
406
						$this->_dnsWildcard = "ON";
407
					}
408
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
409
					$server = "https://members.dyndns.org/nic/update";
410
					$port = "";
411
					if ($this->_dnsServer) {
412
						$server = $this->_dnsServer;
413
					}
414
					if ($this->_dnsPort) {
415
						$port = ":" . $this->_dnsPort;
416
					}
417
					curl_setopt($ch, CURLOPT_URL, $server .$port . '?system=dyndns&hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NO');
418
					break;
419
				case 'dhs':
420
					// DHS is disabled in the GUI because the following doesn't work.
421
					$needsIP = TRUE;
422
					$post_data['hostscmd'] = 'edit';
423
					$post_data['hostscmdstage'] = '2';
424
					$post_data['type'] = '4';
425
					$post_data['updatetype'] = 'Online';
426
					$post_data['mx'] = $this->_dnsMX;
427
					$post_data['mx2'] = '';
428
					$post_data['txt'] = '';
429
					$post_data['offline_url'] = '';
430
					$post_data['cloak'] = 'Y';
431
					$post_data['cloak_title'] = '';
432
					$post_data['ip'] = $this->_dnsIP;
433
					$post_data['domain'] = 'dyn.dhs.org';
434
					$post_data['hostname'] = $this->_dnsHost;
435
					$post_data['submit'] = 'Update';
436
					$server = "https://members.dhs.org/nic/hosts";
437
					$port = "";
438
					if ($this->_dnsServer) {
439
						$server = $this->_dnsServer;
440
					}
441
					if ($this->_dnsPort) {
442
						$port = ":" . $this->_dnsPort;
443
					}
444
					curl_setopt($ch, CURLOPT_URL, $server . $port);
445
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
446
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
447
					break;
448
				case 'noip':
449
				case 'noip-free':
450
					$needsIP = TRUE;
451
					$server = "https://dynupdate.no-ip.com/ducupdate.php";
452
					$port = "";
453
					if ($this->_dnsServer) {
454
						$server = $this->_dnsServer;
455
					}
456
					if ($this->_dnsPort) {
457
						$port = ":" . $this->_dnsPort;
458
					}
459
					if (($this->_dnsService == "noip-free") &&
460
					    ($this->_forceUpdateNeeded == true) &&
461
					    ($this->_dnsDummyUpdateDone == false)) {
462
						// Update the IP to a dummy value to force No-IP free accounts to see a change.
463
						$iptoset = "192.168.1.1";
464
						$this->_dnsDummyUpdateDone = true;
465
						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));
466
					} else {
467
						$iptoset = $this->_dnsIP;
468
					}
469
					curl_setopt($ch, CURLOPT_URL, $server . $port . '?username=' . urlencode($this->_dnsUser) . '&pass=' . urlencode($this->_dnsPass) . '&h[]=' . $this->_dnsHost.'&ip=' . $iptoset);
470
					break;
471
				case 'easydns':
472
					$needsIP = TRUE;
473
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
474
					$server = "https://members.easydns.com/dyn/dyndns.php";
475
					$port = "";
476
					if ($this->_dnsServer) {
477
						$server = $this->_dnsServer;
478
					}
479
					if ($this->_dnsPort) {
480
						$port = ":" . $this->_dnsPort;
481
					}
482
					curl_setopt($ch, CURLOPT_URL, $server . $port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard=' . $this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=' . $this->_dnsBackMX);
483
					break;
484
				case 'hn':
485
					$needsIP = TRUE;
486
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
487
					$server = "http://dup.hn.org/vanity/update";
488
					$port = "";
489
					if ($this->_dnsServer) {
490
						$server = $this->_dnsServer;
491
					}
492
					if ($this->_dnsPort) {
493
						$port = ":" . $this->_dnsPort;
494
					}
495
					curl_setopt($ch, CURLOPT_URL, $server . $port . '?ver=1&IP=' . $this->_dnsIP);
496
					break;
497
				case 'zoneedit':
498
					$needsIP = FALSE;
499
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
500

    
501
					$server = "https://dynamic.zoneedit.com/auth/dynamic.html";
502
					$port = "";
503
					if ($this->_dnsServer) {
504
						$server = $this->_dnsServer;
505
					}
506
					if ($this->_dnsPort) {
507
						$port = ":" . $this->_dnsPort;
508
					}
509
					curl_setopt($ch, CURLOPT_URL, "{$server}{$port}?host=" . $this->_dnsHost . '&dnsto=' . $this->_dnsIP);
510
					break;
511
				case 'dyns':
512
					$needsIP = FALSE;
513
					$server = "http://www.dyns.net/postscript011.php";
514
					$port = "";
515
					if ($this->_dnsServer) {
516
						$server = $this->_dnsServer;
517
					}
518
					if ($this->_dnsPort) {
519
						$port = ":" . $this->_dnsPort;
520
					}
521
					curl_setopt($ch, CURLOPT_URL, $server . $port . '?username=' . urlencode($this->_dnsUser) . '&password=' . $this->_dnsPass . '&host=' . $this->_dnsHost);
522
					break;
523
				case 'ods':
524
					$needsIP = FALSE;
525
					$misc_errno = 0;
526
					$misc_error = "";
527
					$server = "ods.org";
528
					$port = "";
529
					if ($this->_dnsServer) {
530
						$server = $this->_dnsServer;
531
					}
532
					if ($this->_dnsPort) {
533
						$port = ":" . $this->_dnsPort;
534
					}
535
					$this->con['socket'] = fsockopen("{$server}{$port}", "7070", $misc_errno, $misc_error, 30);
536
					/* Check that we have connected */
537
					if (!$this->con['socket']) {
538
						print "error! could not connect.";
539
						break;
540
					}
541
					/* Here is the loop. Read the incoming data (from the socket connection) */
542
					while (!feof($this->con['socket'])) {
543
						$this->con['buffer']['all'] = trim(fgets($this->con['socket'], 4096));
544
						$code = substr($this->con['buffer']['all'], 0, 3);
545
						sleep(1);
546
						switch ($code) {
547
							case 100:
548
								fputs($this->con['socket'], "LOGIN ".$this->_dnsUser." ".$this->_dnsPass."\n");
549
								break;
550
							case 225:
551
								fputs($this->con['socket'], "DELRR ".$this->_dnsHost." A\n");
552
								break;
553
							case 901:
554
								fputs($this->con['socket'], "ADDRR ".$this->_dnsHost." A ".$this->_dnsIP."\n");
555
								break;
556
							case 795:
557
								fputs($this->con['socket'], "QUIT\n");
558
								break;
559
						}
560
					}
561
					$this->_checkStatus(0, $code);
562
					break;
563
				case 'freedns':
564
				case 'freedns-v6':
565
					$needIP = FALSE;
566
					curl_setopt($ch, CURLOPT_URL, 'https://freedns.afraid.org/dynamic/update.php?' . $this->_dnsPass);
567
					break;
568
				case 'dnsexit':
569
					$needsIP = TRUE;
570
					curl_setopt($ch, CURLOPT_URL, 'https://www.dnsexit.com/RemoteUpdate.sv?login='.$this->_dnsUser. '&password='.$this->_dnsPass.'&host='.$this->_dnsHost.'&myip='.$this->_dnsIP);
571
					break;
572
				case 'loopia':
573
					$needsIP = TRUE;
574
					if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") $this->_dnsWildcard = "ON";
575
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
576
					curl_setopt($ch, CURLOPT_URL, 'https://dns.loopia.se/XDynDNSServer/XDynDNS.php?hostname='.$this->_dnsHost.'&myip='.$this->_dnsIP.'&wildcard='.$this->_dnsWildcard);
577
					break;
578
				case 'opendns':
579
					$needsIP = FALSE;
580
					if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") $this->_dnsWildcard = "ON";
581
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
582
					$server = "https://updates.opendns.com/nic/update?hostname=". $this->_dnsHost;
583
					$port = "";
584
					if ($this->_dnsServer) {
585
						$server = $this->_dnsServer;
586
					}
587
					if ($this->_dnsPort) {
588
						$port = ":" . $this->_dnsPort;
589
					}
590
					curl_setopt($ch, CURLOPT_URL, $server .$port);
591
					break;
592

    
593
				case 'staticcling':
594
					$needsIP = FALSE;
595
					curl_setopt($ch, CURLOPT_URL, 'https://www.staticcling.org/update.html?login='.$this->_dnsUser.'&pass='.$this->_dnsPass);
596
					break;
597
				case 'dnsomatic':
598
					/* Example syntax
599
						https://username:password@updates.dnsomatic.com/nic/update?hostname=yourhostname&myip=ipaddress&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG
600
					*/
601
					$needsIP = FALSE;
602
					if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") {
603
						$this->_dnsWildcard = "ON";
604
					}
605
					/*
606
					Reference: https://www.dnsomatic.com/wiki/api
607
						DNS-O-Matic usernames are 3-25 characters.
608
						DNS-O-Matic passwords are 6-20 characters.
609
						All ASCII letters and numbers accepted.
610
						Dots, dashes, and underscores allowed, but not at the beginning or end of the string.
611
					Required: "rawurlencode" http://www.php.net/manual/en/function.rawurlencode.php
612
						Encodes the given string according to RFC 3986.
613
					*/
614
					$server = "https://" . rawurlencode($this->_dnsUser) . ":" . rawurlencode($this->_dnsPass) . "@updates.dnsomatic.com/nic/update?hostname=";
615
					if ($this->_dnsServer) {
616
						$server = $this->_dnsServer;
617
					}
618
					if ($this->_dnsPort) {
619
						$port = ":" . $this->_dnsPort;
620
					}
621
					curl_setopt($ch, CURLOPT_URL, $server . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NOCHG');
622
					break;
623
				case 'namecheap':
624
					/* Example:
625
						https://dynamicdns.park-your-domain.com/update?host=[host_name]&domain=[domain.com]&password=[domain_password]&ip=[your_ip]
626
					*/
627
					$needsIP = FALSE;
628
					$dnspass = trim($this->_dnsPass);
629
					$server = "https://dynamicdns.park-your-domain.com/update?host={$this->_dnsHost}&domain={$this->_dnsDomain}&password={$dnspass}&ip={$this->_dnsIP}";
630
					curl_setopt($ch, CURLOPT_URL, $server);
631
					break;
632
				case 'duiadns':
633
				case 'duiadns-v6':
634
					$needsIP = FALSE;
635
					$server = "https://ipv4.duiadns.net/dyndns.duia?";
636
					curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
637
					curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
638
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser . ':' . $this->_dnsPass);
639
					curl_setopt($ch, CURLOPT_URL, $server . 'hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
640
					break;
641
				case 'he-net':
642
				case 'he-net-v6':
643
					$needsIP = FALSE;
644
					$server = "https://dyn.dns.he.net/nic/update?";
645
					curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
646
					curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
647
					curl_setopt($ch, CURLOPT_URL, $server . 'hostname=' . $this->_dnsHost . '&password=' . $this->_dnsPass . '&myip=' . $this->_dnsIP);
648
					break;
649
				case 'he-net-tunnelbroker':
650
					$needsIP = FALSE;
651
					$server = "https://ipv4.tunnelbroker.net/ipv4_end.php?";
652
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser . ':' . $this->_dnsPass);
653
					curl_setopt($ch, CURLOPT_URL, $server . 'tid=' . $this->_dnsHost);
654
					break;
655
				case 'selfhost':
656
					$needsIP = FALSE;
657
					if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") {
658
						$this->_dnsWildcard = "ON";
659
					}
660
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
661
					$server = "https://carol.selfhost.de/nic/update";
662
					$port = "";
663
					if ($this->_dnsServer) {
664
						$server = $this->_dnsServer;
665
					}
666
					if ($this->_dnsPort) {
667
						$port = ":" . $this->_dnsPort;
668
					}
669
					curl_setopt($ch, CURLOPT_URL, $server .$port . '?system=dyndns&hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NO');
670
					break;
671
				case 'route53':		
672
					require_once("r53.class");
673
					$r53 = new Route53($this->_dnsUser, $this->_dnsPass);
674
					$apiurl = $r53->getApiUrl($this->_dnsZoneID);
675
					$xmlreq = $r53->getRequestBody($this->_dnsHost, $this->_dnsIP, $this->_dnsTTL);
676
					$httphead = $r53->getHttpPostHeaders($this->_dnsZoneID, "us-east-1", hash("sha256",$xmlreq));
677
					curl_setopt($ch, CURLOPT_HTTPHEADER, $httphead);
678
					if($this->_dnsVerboseLog){
679
						log_error(sprintf("Sending reuquest to: %s", $apiurl));
680
						foreach($httphead as $hv){
681
							log_error(sprintf("Header: %s", $hv));
682
						}
683
						log_error(sprintf("XMLPOST: %s", $xmlreq));
684
					}
685
					curl_setopt($ch, CURLOPT_URL, $apiurl);
686
					curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlreq);
687
					break;
688
				case 'custom':
689
				case 'custom-v6':
690
					if (strstr($this->dnsUpdateURL, "%IP%")) {$needsIP = TRUE;} else {$needsIP = FALSE;}
691
					if ($this->_dnsUser != '') {
692
						if ($this->_curlIpresolveV4) {
693
							curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
694
						}
695
						if ($this->_curlSslVerifypeer) {
696
							curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
697
						} else {
698
							curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
699
						}
700
						curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
701
						curl_setopt($ch, CURLOPT_USERPWD, "{$this->_dnsUser}:{$this->_dnsPass}");
702
					}
703
					$server = str_replace("%IP%", $this->_dnsIP, $this->_dnsUpdateURL);
704
					if ($this->_dnsVerboseLog) {
705
						log_error(sprintf(gettext("Sending request to: %s"), $server));
706
					}
707
					curl_setopt($ch, CURLOPT_URL, $server);
708
					break;
709
				case 'cloudflare-v6':
710
				case 'cloudflare':
711
					$this->_FQDN = ltrim($this->_FQDN, '@.');
712
					$isv6 = ($this->_dnsService === 'cloudflare-v6');
713
					$recordType = $isv6 ? "AAAA" : "A";
714
					$needsIP = TRUE;
715
					$dnsServer ='api.cloudflare.com';
716
					$dnsHost = str_replace(' ', '', $this->_dnsHost);
717

    
718
					curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
719
					curl_setopt($ch, CURLOPT_HTTPHEADER, array(
720
						'X-Auth-Email: '.$this->_dnsUser.'',
721
						'X-Auth-Key: '.$this->_dnsPass.'',
722
						'Content-Type: application/json'
723
					));
724

    
725
					// Get zone ID
726
					$getZoneId = "https://{$dnsServer}/client/v4/zones/?name={$this->_dnsDomain}";
727
					curl_setopt($ch, CURLOPT_URL, $getZoneId);
728
					$output = json_decode(curl_exec($ch));
729
					$zone = $output->result[0]->id;
730
					if ($zone) { // If zone ID was found get host ID
731
						$getHostId = "https://{$dnsServer}/client/v4/zones/{$zone}/dns_records?name={$this->_FQDN}&type={$recordType}";
732
						curl_setopt($ch, CURLOPT_URL, $getHostId);
733
						$output = json_decode(curl_exec($ch));
734
						$host = $output->result[0]->id;
735
						if ($host) { // If host ID was found update host
736
							$hostData = array(
737
								"content" => "{$this->_dnsIP}",
738
								"type" => "{$recordType}",
739
								"proxied" => $this->_dnsProxied,
740
								"name" => "{$this->_dnsHost}"
741
							);
742
							$data_json = json_encode($hostData);
743
							$updateHostId = "https://{$dnsServer}/client/v4/zones/{$zone}/dns_records/{$host}";
744
							curl_setopt($ch, CURLOPT_URL, $updateHostId);
745
							curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
746
							curl_setopt($ch, CURLOPT_POSTFIELDS, $data_json);
747
						}
748
					}
749
					break;
750
				case 'eurodns':
751
					$needsIP = TRUE;
752
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
753
					$server = "https://update.eurodyndns.org/update/";
754
					$port = "";
755
					if ($this->_dnsPort) {
756
						$port = ":" . $this->_dnsPort;
757
					}
758
					curl_setopt($ch, CURLOPT_URL, $server .$port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
759
					break;
760
				case 'gratisdns':
761
					$needsIP = TRUE;
762
					$server = "https://ssl.gratisdns.dk/ddns.phtml";
763
					curl_setopt($ch, CURLOPT_URL, $server . '?u=' . $this->_dnsUser . '&p=' . $this->_dnsPass . '&h=' . $this->_dnsHost . '&d=' . $this->_dnsDomain . '&i=' . $this->_dnsIP);
764
					break;
765
				case 'ovh-dynhost':
766
					$needsIP = FALSE;
767
					if (isset($this->_dnsWildcard) && $this->_dnsWildcard != "OFF") $this->_dnsWildcard = "ON";
768
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
769
					$server = "https://www.ovh.com/nic/update";
770
					$port = "";
771
					if ($this->_dnsServer) {
772
						$server = $this->_dnsServer;
773
					}
774
					if ($this->_dnsPort) {
775
						$port = ":" . $this->_dnsPort;
776
					}
777
					curl_setopt($ch, CURLOPT_URL, $server .$port . '?system=dyndns&hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP . '&wildcard='.$this->_dnsWildcard . '&mx=' . $this->_dnsMX . '&backmx=NO');
778
					break;
779
				case 'citynetwork':
780
					$needsIP = TRUE;
781
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
782
					$server = 'https://dyndns.citynetwork.se/nic/update';
783
					$port = "";
784
					if ($this->_dnsServer) {
785
						$server = $this->_dnsServer;
786
					}
787
					if ($this->_dnsPort) {
788
						$port = ":" . $this->_dnsPort;
789
					}
790
					curl_setopt($ch, CURLOPT_URL, $server .$port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
791
					break;
792
				case 'dnsimple':
793
					/* Uses DNSimple's REST API
794
					   Requires username and Account API token passed in header
795
					   Piggybacks on Route 53's ZoneID field for DNSimple record ID
796
					   Data sent as JSON */
797
					$needsIP = TRUE;
798
					$server = 'https://api.dnsimple.com/v1/domains/';
799
					$token = $this->_dnsUser . ':' . $this->_dnsPass;
800
					$jsondata = '{"record":{"content":"' . $this->_dnsIP . '","ttl":"' . $this->_dnsTTL . '"}}';
801
					curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
802
					curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/json', 'X-DNSimple-Token: ' . $token));
803
					curl_setopt($ch, CURLOPT_URL, $server . $this->_dnsHost . '/records/' . $this->_dnsZoneID);
804
					curl_setopt($ch, CURLOPT_POSTFIELDS, $jsondata);
805
					break;
806
				case 'googledomains':
807
					$needsIP = FALSE;
808
					$post_data['username:password'] = $this->_dnsUser . ':' . $this->_dnsPass;
809
					$post_data['hostname'] = $this->_dnsHost;
810
					$post_data['myip'] = $this->_dnsIP;
811
					$post_data['offline'] = 'no';
812
					$server = "https://domains.google.com/nic/update";
813
					$port = "";
814
					curl_setopt($ch, CURLOPT_URL, 'https://domains.google.com/nic/update');
815
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
816
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
817
					break;
818
				case 'dnsmadeeasy':
819
					$needsIP = TRUE;
820
					$server = "https://cp.dnsmadeeasy.com/servlet/updateip";
821
					curl_setopt($ch, CURLOPT_URL, $server . '?username=' . $this->_dnsUser . '&password=' . $this->_dnsPass . '&id=' . $this->_dnsHost . '&ip=' . $this->_dnsIP);
822
					break;
823
				case 'spdyn':
824
				case 'spdyn-v6':
825
					$needsIP = FALSE;
826
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
827
					$server = "https://update.spdyn.de/nic/update";
828
					$port = "";
829
					if ($this->_dnsServer) {
830
						$server = $this->_dnsServer;
831
					}
832
					if ($this->_dnsPort) {
833
						$port = ":" . $this->_dnsPort;
834
					}
835
					curl_setopt($ch, CURLOPT_URL, $server .$port . '?hostname=' . $this->_dnsHost . '&myip=' . $this->_dnsIP);
836
					break;
837
				case 'all-inkl':
838
					$needsIP = FALSE;
839
					$server = 'https://dyndns.kasserver.com/';
840
					curl_setopt($ch, CURLOPT_USERPWD, $this->_dnsUser.':'.$this->_dnsPass);
841
					curl_setopt($ch, CURLOPT_URL, $server . 'myip=' . $this->_dnsIP);
842
					break;
843
				case 'hover':
844
					$needsIP = FALSE;
845
					$port = "";
846
					curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
847
					curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
848

    
849
					//step 1: login to API
850
					$post_data['username'] = $this->_dnsUser;
851
					$post_data['password'] = $this->_dnsPass;
852
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
853
					curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/login");
854
					curl_setopt($ch, CURLOPT_HEADER, 1); //return the full headers to extract the cookies
855
					$output = curl_exec($ch);
856

    
857
					//extract the cookies
858
					preg_match_all("/^Set-cookie: (.*?);/ism", $output, $cookies);
859
					if( count($cookies[1]) > 0 ){
860
						$cookie_data = implode("; ",$cookies[1]);
861
					}
862

    
863
					//step 2: find the id of the A record
864
					$post_data = null;
865
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
866
					curl_setopt($ch, CURLOPT_COOKIE, $cookie_data);
867
					curl_setopt($ch, CURLOPT_HEADER, 0);
868
					curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/dns");
869
					curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
870

    
871
					$output = curl_exec($ch);
872
					preg_match("/^{\"succeeded\":true.*?domain_name\":\"{$this->_dnsDomain}.*?entries.*?{\"id\":\"([^\"]*?)\",\"name\":\"{$this->_dnsHost}\".*?\$/", $output, $hostID);
873
					$hostID = $hostID[1];
874
					preg_match("/^{\"succeeded\":true.*?domain_name\":\"{$this->_dnsDomain}.*?entries.*?{[^\}]*?\"name\":\"{$this->_dnsHost}\".*?content\":\"([^\"]*?)\".*?\$/", $output, $hostIP);
875
					$hostIP = $hostIP[1];
876

    
877
					//step 3: update the IP
878
					if ($hostID) {
879
						curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
880
						curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
881
						curl_setopt($ch, CURLOPT_COOKIE, $cookie_data);
882
						$post_data['content'] = $this->_dnsIP;
883
						curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
884
						curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
885
						curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/dns/{$hostID}");
886
						log_error("HostID:{$hostID}, OldIP:{$hostIP}");
887
					}
888
					break;
889
				case 'dreamhost':
890
				case 'dreamhost-v6':
891
					$needsIP = TRUE;
892
					$isv6 = ($this->_dnsService === 'dreamhost-v6');
893
					$server = 'https://api.dreamhost.com/';
894
					$post_data['key'] = $this->_dnsPass;
895
					$post_data['unique_id'] = uniqid($this->_dnsHost);
896
					$post_data['cmd'] = 'dns-add_record';
897
					$post_data['format'] = 'json';
898
					$post_data['value'] = $this->_dnsIP;
899
					$post_data['record'] = $this->_dnsHost;
900
					$post_data['type'] = $isv6 ? 'AAAA' : 'A';
901
					$post_data['comment'] = "Updated by pfSense:$this->_dnsUser on ".date('c');
902
					$port = "";
903
					if ($this->_dnsServer) {
904
						$server = $this->_dnsServer;
905
					}
906
					if ($this->_dnsPort) {
907
						$port = ":" . $this->_dnsPort;
908
					}
909
					curl_setopt($ch, CURLOPT_URL, $server . $port);
910
					curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
911
					break;
912
				default:
913
					break;
914
			}
915
			if ($this->_dnsService != 'ods') {
916
				curl_setopt($ch, CURLOPT_HEADER, 1);
917
				$response = curl_exec($ch);
918
				$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
919
				$header = substr($response, 0, $header_size);
920
				$data = substr($response, $header_size);
921
				$this->_checkStatus($ch, $data, $header);
922
				@curl_close($ch);
923
			}
924
		}
925
		
926
		/**
927
		 * Private Function (added 23 Feb 17)
928
		 *   Send Removal To Selected Service.
929
		 *   
930
		 *   Some services do not perform an inplace upgrade.  If they do not then the solution
931
		 *   is to remove the existing record and add a new record.
932
		 *   
933
		 * @param unknown $existing_ip If required, an existing IP address for the record.
934
		 */
935
		function _remove($existing_ip = NULL) {
936
			$remove_allowed = false;
937
			if ($this->_dnsVerboseLog) {
938
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _remove() starting.'), $this->_dnsService, $this->_FQDN));
939
			}
940
			
941
			if (strstr($this->_dnsRequestIf, "_vip")) {
942
				$parentif = get_configured_vip_interface($this->_dnsRequestIf);
943
				$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
944
			} else {
945
				$realparentif = $this->_dnsRequestIf;
946
			}
947
			
948
			$ch = curl_init();
949
			
950
			if ($this->_useIPv6 == false) {
951
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
952
			}
953
			
954
			curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
955
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
956
			curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
957
			curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
958
			
959
			switch ($this->_dnsService) {
960
			case 'dreamhost':
961
			case 'dreamhost-v6':
962
				$server = 'https://api.dreamhost.com/';
963
				$post_data['key'] = $this->_dnsPass;
964
				$post_data['unique_id'] = uniqid($this->_dnsHost);
965
				$post_data['cmd'] = 'dns-remove_record';
966
				$post_data['format'] = 'json';
967
				$post_data['value'] = $existing_ip;
968
				$post_data['record'] = $this->_dnsHost;
969
				$isv6 = ($this->_dnsService === 'dreamhost-v6');
970
				$post_data['type'] = $isv6 ? 'AAAA' : 'A';
971
				$port = "";
972
				if ($this->_dnsServer) {
973
					$server = $this->_dnsServer;
974
				}
975
				if ($this->_dnsPort) {
976
					$port = ":" . $this->_dnsPort;
977
				}
978
				curl_setopt($ch, CURLOPT_URL, $server . $port);
979
				curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
980
				$remove_allowed = true;
981
				break;
982
			default:
983
				break;
984
			}
985
			if ($remove_allowed) {
986
				curl_setopt($ch, CURLOPT_HEADER, 1);
987
				$response = curl_exec($ch);
988
				$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
989
				$header = substr($response, 0, $header_size);
990
				$data = substr($response, $header_size);
991
				$this->_checkStatus($ch, $data, $header);
992
				@curl_close($ch);
993
			}
994
		}
995
		
996
		/**
997
		 * Private Function (added 23 Feb 17)
998
		 * Retrieves current DNS records from an external API source.
999
		 * 
1000
		 * Some services cannot perform new operations without the caller 
1001
		 * providing existing record information. 
1002
		 */
1003
		function _lookup_current() {
1004
			$lookup_allowed = false;
1005
			if ($this->_dnsVerboseLog) {
1006
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _listCurrent() starting.'), $this->_dnsService, $this->_FQDN));
1007
			}
1008
				
1009
			if (strstr($this->_dnsRequestIf, "_vip")) {
1010
				$parentif = get_configured_vip_interface($this->_dnsRequestIf);
1011
				$realparentif = convert_friendly_interface_to_real_interface_name($parentif);
1012
			} else {
1013
				$realparentif = $this->_dnsRequestIf;
1014
			}
1015
				
1016
			$ch = curl_init();
1017
				
1018
			if ($this->_useIPv6 == false) {
1019
				curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
1020
			}
1021
				
1022
			curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
1023
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
1024
			curl_setopt($ch, CURLOPT_INTERFACE, 'if!' . $realparentif);
1025
			curl_setopt($ch, CURLOPT_TIMEOUT, 120); // Completely empirical
1026
				
1027
			switch ($this->_dnsService) {
1028
			case 'dreamhost':
1029
			case 'dreamhost-v6':
1030
				$server = 'https://api.dreamhost.com/';
1031
				$post_data['key'] = $this->_dnsPass;
1032
				$post_data['unique_id'] = uniqid($this->_dnsHost);
1033
				$post_data['cmd'] = 'dns-list_records';
1034
				$post_data['format'] = 'json';
1035
				$port = "";
1036
				if ($this->_dnsServer) {
1037
					$server = $this->_dnsServer;
1038
				}
1039
				if ($this->_dnsPort) {
1040
					$port = ":" . $this->_dnsPort;
1041
				}
1042
				curl_setopt($ch, CURLOPT_URL, $server . $port);
1043
				curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
1044
				$lookup_allowed = true;
1045
				break;
1046
			default:
1047
				break;
1048
			}
1049
			if ($lookup_allowed) {
1050
				curl_setopt($ch, CURLOPT_HEADER, 1);
1051
				$response = curl_exec($ch);
1052
				$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1053
				$header = substr($response, 0, $header_size);
1054
				$data = substr($response, $header_size);
1055
				$this->_checkLookupStatus($ch, $data, $header);
1056
				@curl_close($ch);
1057
			}
1058
		}
1059

    
1060
		/*
1061
		 * Private Function (added 23 Feb 17) 
1062
		 *   Retrieve Lookup Status from the provided data and/or header
1063
		 */
1064
		function _checkLookupStatus($ch, $data, $header) {
1065
			if ($this->_dnsVerboseLog) {
1066
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkLookupStatus() starting.'), $this->_dnsService, $this->_FQDN));
1067
			}
1068
			$success_str = "(" . gettext("Success") . ") ";
1069
			$error_str = "(" . gettext("Error") . ") ";
1070
			$status_intro = "phpDynDNS ({$this->_dnsHost}): ";
1071

    
1072
			if ($this->_dnsService != 'ods' && @curl_error($ch)) {
1073
				$status = gettext("Curl error occurred:") . " " . curl_error($ch);
1074
				log_error($status);
1075
				$this->status = $status;
1076
				return;
1077
			}
1078
			switch ($this->_dnsService) {
1079
			case 'dreamhost':
1080
			case 'dreamhost-v6':
1081
				$result = json_decode($data,true);
1082
				if($result["result"] != "success") {
1083
					log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1084
					$this->_debug($data);
1085
					return;
1086
				} else {
1087
					foreach($result["data"] as $key => $row) {
1088
						if($row["record"] == $this->_dnsHost && 
1089
								(($row["type"] == "A" && !$this->_useIPv6)
1090
										|| ($row["type"] == "AAAA" && $this->_useIPv6)
1091
								)) {
1092
							if($row["editable"] == 0) {
1093
								log_error($status_intro . "host " . $this->_dnsHost . " is not editable.");
1094
								continue;
1095
							}
1096
							$this->_existingRecords[]=array("record"=>$row["type"], "type"=>$row["type"], "existing_val"=>$row["value"]);
1097
						}
1098
					}
1099
				}
1100
				if (!is_array($this->_existingRecords)){
1101
					if ($this->_dnsVerboseLog) {
1102
						log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkLookupStatus() ending.  No matching records found.'), $this->_dnsService, $this->_FQDN));
1103
					}
1104
				}
1105
				break;
1106
			default:
1107
				break;
1108
			}
1109
		}
1110

    
1111
		/*
1112
		 * Private Function (added 12 July 2005) [beta]
1113
		 *   Retrieve Update Status
1114
		 */
1115
		function _checkStatus($ch, $data, $header) {
1116
			if ($this->_dnsVerboseLog) {
1117
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkStatus() starting.'), $this->_dnsService, $this->_FQDN));
1118
			}
1119
			$successful_update = false;
1120
			$success_str = "(" . gettext("Success") . ") ";
1121
			$error_str = "(" . gettext("Error") . ") ";
1122
			$status_intro = "phpDynDNS ({$this->_dnsHost}): ";
1123

    
1124
			if ($this->_dnsService != 'ods' && @curl_error($ch)) {
1125
				$status = gettext("Curl error occurred:") . " " . curl_error($ch);
1126
				log_error($status);
1127
				$this->status = $status;
1128
				return;
1129
			}
1130
			switch ($this->_dnsService) {
1131
				case 'glesys':
1132
					$status_intro = "GleSYS ({$this->_dnsHost}): ";
1133
					if (preg_match('/Record updated/i', $data)) {
1134
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1135
						$successful_update = true;
1136
					} else {
1137
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1138
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1139
						$this->_debug($data);
1140
					}
1141
					break;
1142
				case 'dnsomatic':
1143
					$status_intro = "DNS-O-Matic ({$this->_dnsHost}): ";
1144
					if (preg_match('/badauth/i', $data)) {
1145
						$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.");
1146
					} else if (preg_match('/notfqdn /i', $data)) {
1147
						$status = $status_intro . gettext("The hostname specified is not a fully-qualified domain name. If no hostnames included, notfqdn will be returned once.");
1148
					} else if (preg_match('/nohost/i', $data)) {
1149
						$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.");
1150
					} else if (preg_match('/numhost/i', $data)) {
1151
						$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.");
1152
					} else if (preg_match('/abuse/i', $data)) {
1153
						$status = $status_intro . gettext("The hostname is blocked for update abuse.");
1154
					} else if (preg_match('/good/i', $data)) {
1155
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1156
						$successful_update = true;
1157
					} else if (preg_match('/dnserr/i', $data)) {
1158
						$status = $status_intro . gettext("DNS error encountered. Stop updating for 30 minutes.");
1159
					} else {
1160
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1161
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1162
						$this->_debug($data);
1163
					}
1164
					break;
1165
				case 'citynetwork':
1166
					if (preg_match('/notfqdn/i', $data)) {
1167
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1168
					} else if (preg_match('/nohost/i', $data)) {
1169
						$status = $status_intro . $error_str . gettext("No such host");
1170
					} else if (preg_match('/nochg/i', $data)) {
1171
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1172
						$successful_update = true;
1173
					} else if (preg_match('/good/i', $data)) {
1174
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1175
						$successful_update = true;
1176
					} else if (preg_match('/badauth/i', $data)) {
1177
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1178
					} else {
1179
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1180
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1181
						$this->_debug($data);
1182
					}
1183
					break;
1184
				case 'ovh-dynhost':
1185
				case 'dyndns':
1186
					if (preg_match('/notfqdn/i', $data)) {
1187
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1188
					} else if (preg_match('/nochg/i', $data)) {
1189
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1190
						$successful_update = true;
1191
					} else if (preg_match('/good/i', $data)) {
1192
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1193
						$successful_update = true;
1194
					} else if (preg_match('/noauth/i', $data)) {
1195
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1196
					} else {
1197
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1198
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1199
						$this->_debug($data);
1200
					}
1201
					break;
1202
				case 'dyndns-static':
1203
					if (preg_match('/notfqdn/i', $data)) {
1204
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1205
					} else if (preg_match('/nochg/i', $data)) {
1206
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1207
						$successful_update = true;
1208
					} else if (preg_match('/good/i', $data)) {
1209
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1210
						$successful_update = true;
1211
					} else if (preg_match('/noauth/i', $data)) {
1212
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1213
					} else {
1214
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1215
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1216
						$this->_debug($data);
1217
					}
1218
					break;
1219
				case 'dyndns-custom':
1220
					if (preg_match('/notfqdn/i', $data)) {
1221
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1222
					} else if (preg_match('/nochg/i', $data)) {
1223
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1224
						$successful_update = true;
1225
					} else if (preg_match('/good/i', $data)) {
1226
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1227
						$successful_update = true;
1228
					} else if (preg_match('/noauth/i', $data)) {
1229
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1230
					} else {
1231
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1232
						log_error($status_intro . gettext("PAYLOAD:") . " {$data}");
1233
						$this->_debug($data);
1234
					}
1235
					break;
1236
				case 'dhs':
1237
					break;
1238
				case 'noip':
1239
				case 'noip-free':
1240
					list($ip, $code) = explode(":", $data);
1241
					switch ($code) {
1242
						case 0:
1243
							$status = $status_intro . $success_str . gettext("IP address is current, no update performed.");
1244
							$successful_update = true;
1245
							break;
1246
						case 1:
1247
							$status = $status_intro . $success_str . gettext("DNS hostname update successful.");
1248
							$successful_update = true;
1249
							break;
1250
						case 2:
1251
							$status = $status_intro . $error_str . gettext("Hostname supplied does not exist.");
1252
							break;
1253
						case 3:
1254
							$status = $status_intro . $error_str . gettext("Invalid Username.");
1255
							break;
1256
						case 4:
1257
							$status = $status_intro . $error_str . gettext("Invalid Password.");
1258
							break;
1259
						case 5:
1260
							$status = $status_intro . $error_str . gettext("Too many updates sent.");
1261
							break;
1262
						case 6:
1263
							$status = $status_intro . $error_str . gettext("Account disabled due to violation of No-IP terms of service.");
1264
							break;
1265
						case 7:
1266
							$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.");
1267
							break;
1268
						case 8:
1269
							$status = $status_intro . $error_str . gettext("Disabled / Locked Hostname.");
1270
							break;
1271
						case 9:
1272
							$status = $status_intro . $error_str . gettext("Host updated is configured as a web redirect and no update was performed.");
1273
							break;
1274
						case 10:
1275
							$status = $status_intro . $error_str . gettext("Group supplied does not exist.");
1276
							break;
1277
						case 11:
1278
							$status = $status_intro . $success_str . gettext("DNS group update is successful.");
1279
							$successful_update = true;
1280
							break;
1281
						case 12:
1282
							$status = $status_intro . $success_str . gettext("DNS group is current, no update performed.");
1283
							$successful_update = true;
1284
							break;
1285
						case 13:
1286
							$status = $status_intro . $error_str . gettext("Update client support not available for supplied hostname or group.");
1287
							break;
1288
						case 14:
1289
							$status = $status_intro . $error_str . gettext("Hostname supplied does not have offline settings configured.");
1290
							break;
1291
						case 99:
1292
							$status = $status_intro . $error_str . gettext("Client disabled. Client should exit and not perform any more updates without user intervention.");
1293
							break;
1294
						case 100:
1295
							$status = $status_intro . $error_str . gettext("Client disabled. Client should exit and not perform any more updates without user intervention.");
1296
							break;
1297
						default:
1298
							$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1299
							$this->_debug(gettext("Unknown Response:") . " " . $data);
1300
							break;
1301
					}
1302
					break;
1303
				case 'easydns':
1304
					if (preg_match('/NOACCESS/i', $data)) {
1305
						$status = $status_intro . $error_str . gettext("Authentication Failed: Username and/or Password was Incorrect.");
1306
					} else if (preg_match('/NOSERVICE/i', $data)) {
1307
						$status = $status_intro . $error_str . gettext("No Service: Dynamic DNS Service has been disabled for this domain.");
1308
					} else if (preg_match('/ILLEGAL INPUT/i', $data)) {
1309
						$status = $status_intro . $error_str . gettext("Illegal Input: Self-Explanatory");
1310
					} else if (preg_match('/TOOSOON/i', $data)) {
1311
						$status = $status_intro . $error_str . gettext("Too Soon: Not Enough Time Has Elapsed Since Last Update");
1312
					} else if (preg_match('/NOERROR/i', $data)) {
1313
						$status = $status_intro . $success_str . gettext("IP Updated Successfully!");
1314
						$successful_update = true;
1315
					} else {
1316
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1317
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1318
						$this->_debug($data);
1319
					}
1320
					break;
1321
				case 'hn':
1322
					/* FIXME: add checks */
1323
					break;
1324
				case 'zoneedit':
1325
					if (preg_match('/799/i', $data)) {
1326
						$status = $status_intro . "(" . gettext("Error 799") . ") " . gettext("Update Failed!");
1327
					} else if (preg_match('/700/i', $data)) {
1328
						$status = $status_intro . "(" . gettext("Error 700") . ") " . gettext("Update Failed!");
1329
					} else if (preg_match('/200/i', $data)) {
1330
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1331
						$successful_update = true;
1332
					} else if (preg_match('/201/i', $data)) {
1333
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1334
						$successful_update = true;
1335
					} else {
1336
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1337
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1338
						$this->_debug($data);
1339
					}
1340
					break;
1341
				case 'dyns':
1342
					if (preg_match("/400/i", $data)) {
1343
						$status = $status_intro . $error_str . gettext("Bad Request - The URL was malformed. Required parameters were not provided.");
1344
					} else if (preg_match('/402/i', $data)) {
1345
						$status = $status_intro . $error_str . gettext("Update Too Soon - Attempted to update too quickly since last change.");
1346
					} else if (preg_match('/403/i', $data)) {
1347
						$status = $status_intro . $error_str . gettext("Database Error - There was a server-sided database error.");
1348
					} else if (preg_match('/405/i', $data)) {
1349
						$status = $status_intro . $error_str . sprintf(gettext('Hostname Error - The hostname (%1$s) doesn\'t belong to user (%2$s).'), $this->_dnsHost, $this->_dnsUser);
1350
					} else if (preg_match('/200/i', $data)) {
1351
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1352
						$successful_update = true;
1353
					} else {
1354
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1355
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1356
						$this->_debug($data);
1357
					}
1358
					break;
1359
				case 'ods':
1360
					if (preg_match("/299/i", $data)) {
1361
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1362
						$successful_update = true;
1363
					} else {
1364
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1365
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1366
						$this->_debug($data);
1367
					}
1368
					break;
1369
				case 'freedns':
1370
				case 'freedns-v6':
1371
					if (preg_match("/has not changed./i", $data)) {
1372
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1373
						$successful_update = true;
1374
					} else if (preg_match("/Updated/i", $data)) {
1375
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1376
						$successful_update = true;
1377
					} else {
1378
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1379
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1380
						$this->_debug($data);
1381
					}
1382
					break;
1383
				case 'dnsexit':
1384
					if (preg_match("/is the same/i", $data)) {
1385
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1386
						$successful_update = true;
1387
					} else if (preg_match("/Success/i", $data)) {
1388
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1389
						$successful_update = true;
1390
					} else {
1391
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1392
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1393
						$this->_debug($data);
1394
					}
1395
					break;
1396
				case 'loopia':
1397
					if (preg_match("/nochg/i", $data)) {
1398
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1399
						$successful_update = true;
1400
					} else if (preg_match("/good/i", $data)) {
1401
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!");
1402
						$successful_update = true;
1403
					} else if (preg_match('/badauth/i', $data)) {
1404
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1405
					} else {
1406
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1407
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1408
						$this->_debug($data);
1409
					}
1410
					break;
1411
				case 'opendns':
1412
					if (preg_match('/badauth/i', $data)) {
1413
						$status = $status_intro . $error_str . gettext("Not a valid username or password!");
1414
					} else if (preg_match('/nohost/i', $data)) {
1415
						$status = $status_intro . $error_str . gettext("Hostname specified does not exist.");
1416
						$successful_update = true;
1417
					} else if (preg_match('/good/i', $data)) {
1418
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1419
						$successful_update = true;
1420
					} else if (preg_match('/yours/i', $data)) {
1421
						$status = $status_intro . $error_str . gettext("Hostname specified exists, but not under the username specified.");
1422
					} else if (preg_match('/abuse/i', $data)) {
1423
						$status = $status_intro . $error_str . gettext("Updating too frequently, considered abuse.");
1424
					} else {
1425
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1426
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1427
						$this->_debug($data);
1428
					}
1429
					break;
1430
				case 'staticcling':
1431
					if (preg_match("/invalid ip/i", $data)) {
1432
						$status = $status_intro . $error_str . gettext("Bad Request - The IP provided was invalid.");
1433
					} else if (preg_match('/required info missing/i', $data)) {
1434
						$status = $status_intro . $error_str . gettext("Bad Request - Required parameters were not provided.");
1435
					} else if (preg_match('/invalid characters/i', $data)) {
1436
						$status = $status_intro . $error_str . gettext("Bad Request - Illegal characters in either the username or the password.");
1437
					} else if (preg_match('/bad password/i', $data)) {
1438
						$status = $status_intro . $error_str . gettext("Invalid password.");
1439
					} else if (preg_match('/account locked/i', $data)) {
1440
						$status = $status_intro . $error_str . gettext("This account has been administratively locked.");
1441
					} else if (preg_match('/update too frequent/i', $data)) {
1442
						$status = $status_intro . $error_str . gettext("Updating too frequently.");
1443
					} else if (preg_match('/DB error/i', $data)) {
1444
						$status = $status_intro . $error_str . gettext("Server side error.");
1445
					} else if (preg_match('/success/i', $data)) {
1446
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1447
						$successful_update = true;
1448
					} else {
1449
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1450
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1451
						$this->_debug($data);
1452
					}
1453
					break;
1454
				case 'namecheap':
1455
					$tmp = str_replace("^M", "", $data);
1456
					$ncresponse = @xml2array($tmp);
1457
					if (preg_match("/internal server error/i", $data)) {
1458
						$status = $status_intro . $error_str . gettext("Server side error.");
1459
					} else if (preg_match("/request is badly formed/i", $data)) {
1460
						$status = $status_intro . $error_str . gettext("Badly Formed Request (check the settings).");
1461
					} else if ($ncresponse['interface-response']['ErrCount'] === "0") {
1462
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1463
						$successful_update = true;
1464
					} else if (is_numeric($ncresponse['interface-response']['ErrCount']) && ($ncresponse['interface-response']['ErrCount'] > 0)) {
1465
						$status = $status_intro . $error_str . implode(", ", $ncresponse["interface-response"]["errors"]);
1466
						$successful_update = true;
1467
					} else {
1468
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1469
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1470
						$this->_debug($data);
1471
					}
1472
					break;
1473
				case 'duiadns':
1474
				case 'duiadns-v6':
1475
					if (preg_match("/error/i", $data)) {
1476
						$status = $status_intro . $error_str . gettext("Server side error.");
1477
					} else if (preg_match('/nohost/i', $data)) {
1478
						$status = $status_intro . $error_str . gettext("Bad Request - A hostname was not provided.");
1479
					} else if (preg_match('/badauth/i', $data)) {
1480
						$status = $status_intro . $error_str . gettext("Invalid username or password.");
1481
					} else if (preg_match('/good/i', $data)) {
1482
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1483
						$successful_update = true;
1484
					} else if (preg_match('/nochg/i', $data)) {
1485
						$status = $status_intro . $success_str . gettext("No Change In IP Address.");
1486
						$successful_update = true;
1487
					} else {
1488
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1489
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1490
						$this->_debug($data);
1491
					}
1492
					break;
1493
				case 'he-net':
1494
				case 'he-net-v6':
1495
					if (preg_match("/badip/i", $data)) {
1496
						$status = $status_intro . $error_str . gettext("Bad Request - The IP provided was invalid.");
1497
					} else if (preg_match('/nohost/i', $data)) {
1498
						$status = $status_intro . $error_str . gettext("Bad Request - A hostname was not provided.");
1499
					} else if (preg_match('/badauth/i', $data)) {
1500
						$status = $status_intro . $error_str . gettext("Invalid username or password.");
1501
					} else if (preg_match('/good/i', $data)) {
1502
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1503
						$successful_update = true;
1504
					} else if (preg_match('/nochg/i', $data)) {
1505
						$status = $status_intro . $success_str . gettext("No Change In IP Address.");
1506
						$successful_update = true;
1507
					} else {
1508
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1509
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1510
						$this->_debug($data);
1511
					}
1512
					break;
1513
				case 'he-net-tunnelbroker':
1514
					/*
1515
					-ERROR: Missing parameter(s).
1516
					-ERROR: Invalid API key or password
1517
					-ERROR: Tunnel not found
1518
					-ERROR: Another tunnel exists for this IP.
1519
					-ERROR: This tunnel is already associated with this IP address
1520
					+OK: Tunnel endpoint updated to: x.x.x.x
1521
					*/
1522
					if (preg_match("/Missing parameter/i", $data)) {
1523
						$status = $status_intro . $error_str . gettext("Bad Request - Missing/Invalid Parameters.");
1524
					} else if (preg_match('/Tunnel not found/i', $data)) {
1525
						$status = $status_intro . $error_str . gettext("Bad Request - Invalid Tunnel ID.");
1526
					} else if (preg_match('/Invalid API key or password/i', $data)) {
1527
						$status = $status_intro . $error_str . gettext("Invalid username or password.");
1528
					} else if (preg_match('/OK:/i', $data)) {
1529
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1530
						$successful_update = true;
1531
					} else if (preg_match('/This tunnel is already associated with this IP address/i', $data)) {
1532
						$status = $status_intro . $success_str . gettext("No Change In IP Address.");
1533
						$successful_update = true;
1534
					} else {
1535
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1536
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1537
						$this->_debug($data);
1538
					}
1539
					break;
1540
				case 'selfhost':
1541
					if (preg_match('/notfqdn/i', $data)) {
1542
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1543
					} else if (preg_match('/nochg/i', $data)) {
1544
						$status = $status_intro . $success_str . gettext("No Change In IP Address.");
1545
						$successful_update = true;
1546
					} else if (preg_match('/good/i', $data)) {
1547
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1548
						$successful_update = true;
1549
					} else if (preg_match('/noauth/i', $data)) {
1550
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1551
					} else {
1552
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1553
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1554
						$this->_debug($data);
1555
					}
1556
					break;
1557
				case 'route53':
1558
					if(preg_match('/ErrorResponse/', $data)){
1559
						$status = $status_intro . $error_str . gettext("Route53 API call failed");
1560
						log_error(sprintf("error message: %s", $data));
1561
						$status_update = false;
1562
					} else {
1563
						$status = $status_intro . $success_str . gettext("IP address changed successfully");
1564
						$successful_update = true;
1565
					}
1566
					break;
1567
				case 'custom':
1568
				case 'custom-v6':
1569
					$successful_update = false;
1570
					if ($this->_dnsResultMatch == "") {
1571
						$successful_update = true;
1572
					} else {
1573
						$this->_dnsResultMatch = str_replace("%IP%", $this->_dnsIP, $this->_dnsResultMatch);
1574
						$matches = preg_split("/(?<!\\\\)\\|/", $this->_dnsResultMatch);
1575
						foreach ($matches as $match) {
1576
							$match= str_replace("\\|", "|", $match);
1577
							if (strcmp($match, trim($data, "\t\n\r")) == 0) {
1578
								$successful_update = true;
1579
							}
1580
						}
1581
						unset ($matches);
1582
					}
1583
					if ($successful_update == true) {
1584
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1585
					} else {
1586
						$status = $status_intro . $error_str . gettext("Result did not match.") . " [" . $data . "]";
1587
					}
1588
					break;
1589
				case 'cloudflare-v6':
1590
				case 'cloudflare':
1591
					$output = json_decode($data);
1592
					if ($output->result->content === $this->_dnsIP) {
1593
						$status = $status_intro . $success_str . sprintf(gettext('%1$s updated to %2$s'), $this->_dnsHost, $this->_dnsIP);
1594
						$successful_update = true;
1595
					} elseif ($output->errors[0]->code === 9103) {
1596
						$status = $status_intro . $error_str . gettext("Invalid Credentials! Don't forget to use API Key for password field with CloudFlare.");
1597
					} elseif (($output->success) && (!$output->result[0]->id)) {
1598
						$status = $status_intro . $error_str . gettext("Zone or Host ID was not found, check the hostname.");
1599
					} else {
1600
						$status = $status_intro . gettext("UNKNOWN ERROR") . " - " . $output->errors[0]->message;
1601
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1602
					}
1603
					break;
1604
				case 'eurodns':
1605
					if (preg_match('/notfqdn/i', $data)) {
1606
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1607
					} else if (preg_match('/nochg/i', $data)) {
1608
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1609
						$successful_update = true;
1610
					} else if (preg_match('/good/i', $data)) {
1611
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1612
						$successful_update = true;
1613
					} else if (preg_match('/badauth/i', $data)) {
1614
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1615
					} else {
1616
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1617
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1618
						$this->_debug($data);
1619
					}
1620
					break;
1621
				case 'gratisdns':
1622
					if (preg_match('/Forkerte værdier/i', $data)) {
1623
						$status = $status_intro . $error_str . gettext("Wrong values - Update could not be completed.");
1624
					} else if (preg_match('/Bruger login: Bruger eksistere ikke/i', $data)) {
1625
						$status = $status_intro . $error_str . gettext("Unknown username - User does not exist.");
1626
					} else if (preg_match('/Bruger login: 1Fejl i kodeord/i', $data)) {
1627
						$status = $status_intro . $error_str . gettext("Wrong password - Remember password is case sensitive.");
1628
					} else if (preg_match('/Domæne kan IKKE administreres af bruger/i', $data)) {
1629
						$status = $status_intro . $error_str . gettext("User unable to administer the selected domain.");
1630
					} else if (preg_match('/OK/i', $data)) {
1631
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1632
						$successful_update = true;
1633
					} else {
1634
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1635
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1636
						$this->_debug($data);
1637
					}
1638
					break;
1639
				case 'dnsimple':
1640
					/* Responds with HTTP 200 on success.
1641
					   Responds with HTTP 4xx on error.
1642
					   Returns JSON data as body */
1643
;
1644
					if (preg_match("/\s200\sOK/i", $header)) {
1645
						$status = $status_intro . $success_str . gettext("IP Address Updated Successfully!");
1646
						$successful_update = true;
1647
					} else if (preg_match("/\s4\d\d\s/i", $header)) {
1648
						$arrbody = json_decode($data, true);
1649
						$message = $arrbody['message'] . ".";
1650
						if (isset($arrbody['errors']['content'])) {
1651
							foreach ($arrbody['errors']['content'] as $key => $content) {
1652
								$message .= " " . $content . ".";
1653
							}
1654
						}
1655
						$status = $status_intro . $error_str . $message;
1656
					} else {
1657
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1658
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1659
						$this->_debug($data);
1660
					}
1661
					break;
1662
				case 'googledomains':
1663
					if (preg_match('/notfqdn/i', $data)) {
1664
						$status = $status_intro . $error_str . gettext("Not A FQDN");
1665
					} else if (preg_match('/nochg/i', $data)) {
1666
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1667
						$successful_update = true;
1668
					} else if (preg_match('/good/i', $data)) {
1669
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1670
						$successful_update = true;
1671
					} else if (preg_match('/badauth/i', $data)) {
1672
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1673
					} else if (preg_match('/nohost/i', $data)) {
1674
						$status = $status_intro . $error_str . gettext("Hostname does not exist or DynDNS not enabled");
1675
					} else if (preg_match('/badagent/i', $data)) {
1676
						$status = $status_intro . $error_str . gettext("Bad request");
1677
					} else if (preg_match('/abuse/i', $data)) {
1678
						$status = $status_intro . $error_str . gettext("Dynamic DNS access has been blocked!");
1679
					} else if (preg_match('/911/i', $data)) {
1680
						$status = $status_intro . $error_str . gettext("Error on Google's end, retry in 5 minutes");
1681
					} else {
1682
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1683
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1684
						$this->_debug($data);
1685
					}
1686
					break;
1687
				case 'dnsmadeeasy':
1688
					switch ($data) {
1689
						case 'success':
1690
							$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1691
							$successful_update = true;
1692
							break;
1693
						case 'error-auth':
1694
							$status = $status_intro . $error_str . gettext("Invalid username or password");
1695
							break;
1696
						case 'error-auth-suspend':
1697
							$status = $status_intro . $error_str . gettext("Account suspended");
1698
							break;
1699
						case 'error-auth-voided':
1700
							$status = $status_intro . $error_str . gettext("Account revoked");
1701
							break;
1702
						case 'error-record-invalid':
1703
							$status = $status_intro . $error_str . gettext("Record does not exist in the system. Unable to update record");
1704
							break;
1705
						case 'error-record-auth':
1706
							$status = $status_intro . $error_str . gettext("User does not have access to this record");
1707
							break;
1708
						case 'error-record-ip-same':
1709
							$status = $status_intro . $success_str . gettext("No Change In IP Address");
1710
							$successful_update = true;
1711
							break;
1712
						case 'error-system':
1713
							$status = $status_intro . $error_str . gettext("General system error recognized by the system");
1714
							break;
1715
						case 'error':
1716
							$status = $status_intro . $error_str . gettext("General system error unrecognized by the system");
1717
							break;
1718
						default:
1719
							$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1720
							log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1721
							$this->_debug($data);
1722
							break;
1723
					}
1724
					break;
1725
				case 'spdyn':
1726
				case 'spdyn-v6':
1727
					if (preg_match('/notfqdn/i', $data)) {
1728
						$status = $status_intro . $error_str . gettext("Not A FQDN!");
1729
					} else if (preg_match('/nohost/i', $data)) {
1730
						$status = $status_intro . $error_str . gettext("No such host");
1731
					} else if (preg_match('/nochg/i', $data)) {
1732
						$status = $status_intro . $success_str . gettext("No Change In IP Address");
1733
						$successful_update = true;
1734
					} else if (preg_match('/good/i', $data)) {
1735
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1736
						$successful_update = true;
1737
					} else if (preg_match('/badauth/i', $data)) {
1738
						$status = $status_intro . $error_str . gettext("User Authorization Failed");
1739
					} else {
1740
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1741
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1742
						$this->_debug($data);
1743
					}
1744
					break;
1745
				case 'all-inkl':
1746
 					if (preg_match('/good\s'.$this->_dnsIP.'/i', $data)) {
1747
							$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1748
 							$successful_update = true;
1749
 					} else if (preg_match('/good/i', $data)) {
1750
						$status = $status_intro . $error_str . gettext("Result did not match.");
1751
					} else if (preg_match("/\s401\sUnauthorized/i", $header)) {
1752
						$status = $status_intro . $error_str . gettext("Invalid username or password");
1753
					} 
1754
					else {
1755
							$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1756
							log_error($status_intro . gettext("PAYLOAD:") . " " . $header.$data);
1757
 							$this->_debug($data);
1758
 							$this->_debug($header);
1759
 					}
1760
 					break;
1761
				case 'hover':
1762
					if (preg_match('/succeeded":true/i', $data)) {
1763
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1764
						$successful_update = true;
1765
					} else {
1766
						$status = $status_intro . "(" . gettext("Unknown Response") . ")";
1767
						log_error($status_intro . gettext("PAYLOAD:") . " " . $data);
1768
						$this->_debug($data);
1769
					}
1770
					break;
1771
				case 'dreamhost':
1772
				case 'dreamhost-v6':
1773
					$result = json_decode($data,true);
1774
					if ($this->_dnsVerboseLog) {
1775
						log_error(sprintf(gettext('_checkStatus() results: %1$s'), $data));
1776
					}
1777
					switch ($result['data']) {
1778
					case 'success':
1779
					case 'record_added':
1780
					case 'record_removed':
1781
						$status = $status_intro . $success_str . gettext("IP Address Changed Successfully!") . " (" . $this->_dnsIP . ")";
1782
						$successful_update = true;
1783
						break;
1784
					case 'no_record':
1785
					case 'no_such_record ':
1786
						$status = $status_intro . $error_str . gettext("No record exists.");
1787
						break;
1788
					case 'no_type':
1789
					case 'no_such_type ':
1790
						$status = $status_intro . $error_str . gettext("No type exists.");
1791
						break;
1792
					case 'no_value':
1793
					case 'no_such_value ':
1794
						$status = $status_intro . $error_str . gettext("No value exists.");
1795
						break;
1796
					case 'no_such_zone':
1797
						$status = $status_intro . $error_str . gettext("No such zone exists.");
1798
						break;
1799
					case 'invalid_record':
1800
						$status = $status_intro . $error_str . gettext("The specified record is invalid.");
1801
						break;
1802
					case 'invalid_type':
1803
						$status = $status_intro . $error_str . gettext("The specified type is invalid.");
1804
						break;
1805
					case 'invalid_value':
1806
						$status = $status_intro . $error_str . gettext("The specified value is invalid.");
1807
						break;
1808
					case 'not_editable ':
1809
						$status = $status_intro . $error_str . gettext("Record is not editable.");
1810
						break;
1811
					case 'record_already_exists_not_editable':
1812
						$status = $status_intro . $error_str . gettext("Record exists but is not editable.");
1813
						break;
1814
					case 'record_already_exists_remove_first':
1815
						$status = $status_intro . $error_str . gettext("Record exists and must be removed before adding.");
1816
						break;
1817
					case 'internal_error_updating_zone':
1818
						$status = $status_intro . $error_str . gettext("A remote server error occurred updating the zone.");
1819
						break;
1820
					case 'internal_error_could_not_load_zone':
1821
						$status = $status_intro . $error_str . gettext("A remote server error occurred loading the zone.");
1822
						break;
1823
					case 'internal_error_could_not_update_zone':
1824
						$status = $status_intro . $error_str . gettext("A remote server error occurred updating the zone.");
1825
						break;
1826
					case 'internal_error_could_not_add_record':
1827
						$status = $status_intro . $error_str . gettext("A remote server error occurred adding a new record.");
1828
						break;
1829
					case 'internal_error_could_not_destroy_record ':
1830
						$status = $status_intro . $error_str . gettext("A remote server error occurred removing an existing record.");
1831
						break;
1832
					default:
1833
						break;
1834
					}
1835
				default:
1836
					break;
1837
			}
1838

    
1839
			if ($successful_update == true) {
1840
				/* Write WAN IP to cache file */
1841
				$wan_ip = $this->_checkIP();
1842
				if ($this->_useIPv6 == false && $wan_ip > 0) {
1843
					$currentTime = time();
1844
					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));
1845
					log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $this->_cacheFile, $wan_ip));
1846
					@file_put_contents($this->_cacheFile, "{$wan_ip}|{$currentTime}");
1847
				} else {
1848
					@unlink($this->_cacheFile);
1849
				}
1850
				if ($this->_useIPv6 == true && $wan_ip > 0) {
1851
					$currentTime = time();
1852
					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));
1853
					log_error(sprintf(gettext('phpDynDNS: updating cache file %1$s: %2$s'), $this->_cacheFile_v6, $wan_ip));
1854
					@file_put_contents($this->_cacheFile_v6, "{$wan_ip}|{$currentTime}");
1855
				} else {
1856
					@unlink($this->_cacheFile_v6);
1857
				}
1858
			}
1859
			$this->status = $status;
1860
			log_error($status);
1861
		}
1862

    
1863
		/*
1864
		 * Private Function (added 12 July 05) [beta]
1865
		 *   Return Error, Set Last Error, and Die.
1866
		 */
1867
		function _error($errorNumber = '1') {
1868
			$err_str = 'phpDynDNS: (' . gettext('ERROR!') . ') ';
1869
			$err_str_r53 = 'Route 53: (' . gettext('Error') . ') ';
1870
			switch ($errorNumber) {
1871
				case 0:
1872
					break;
1873
				case 2:
1874
					$error = $err_str . gettext('No Dynamic DNS Service provider was selected.');
1875
					break;
1876
				case 3:
1877
					$error = $err_str . gettext('No Username Provided.');
1878
					break;
1879
				case 4:
1880
					$error = $err_str . gettext('No Password Provided.');
1881
					break;
1882
				case 5:
1883
					$error = $err_str . gettext('No Hostname Provided.');
1884
					break;
1885
				case 6:
1886
					$error = $err_str . gettext('The Dynamic DNS Service provided is not yet supported.');
1887
					break;
1888
				case 7:
1889
					$error = $err_str . gettext('No Update URL Provided.');
1890
					break;
1891
				case 8:
1892
					$status = $err_str_r53 . gettext("Invalid ZoneID");
1893
					break;
1894
				case 9:
1895
					$status = $err_str_r53 . gettext("Invalid TTL");
1896
					break;
1897
				case 10:
1898
					$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);
1899
					break;
1900
				default:
1901
					$error = $err_str . gettext('Unknown Response.');
1902
					/* FIXME: $data isn't in scope here */
1903
					/* $this->_debug($data); */
1904
					break;
1905
			}
1906
			$this->lastError = $error;
1907
			log_error($error);
1908
		}
1909

    
1910
		/*
1911
		 * Private Function (added 12 July 05) [beta]
1912
		 *   - Detect whether or not IP needs to be updated.
1913
		 *      | Written Specifically for pfSense (https://www.pfsense.org) may
1914
		 *      | work with other systems. pfSense base is FreeBSD.
1915
		 */
1916
		function _detectChange() {
1917
			global $debug;
1918

    
1919
			if ($debug) {
1920
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _detectChange() starting.'), $this->_dnsService, $this->_FQDN));
1921
			}
1922

    
1923
			$currentTime = time();
1924

    
1925
			$wan_ip = $this->_checkIP();
1926
			if ($wan_ip == 0) {
1927
				log_error(sprintf(gettext("Dynamic Dns (%s): Current WAN IP could not be determined, skipping update process."), $this->_FQDN));
1928
				return false;
1929
			}
1930
			$log_error = sprintf(gettext('Dynamic Dns (%1$s): Current WAN IP: %2$s'), $this->_FQDN, $wan_ip) . " ";
1931

    
1932
			if ($this->_useIPv6 == true) {
1933
				if (file_exists($this->_cacheFile_v6)) {
1934
					$contents = file_get_contents($this->_cacheFile_v6);
1935
					list($cacheIP, $cacheTime) = explode('|', $contents);
1936
					$this->_debug($cacheIP.'/'.$cacheTime);
1937
					$initial = false;
1938
					$log_error .= sprintf(gettext("Cached IPv6: %s"), $cacheIP);
1939
				} else {
1940
					$cacheIP = '::';
1941
					@file_put_contents($this->_cacheFile, "::|{$currentTime}");
1942
					$cacheTime = $currentTime;
1943
					$initial = true;
1944
					$log_error .= gettext("No Cached IPv6 found.");
1945
				}
1946
			} else {
1947
				if (file_exists($this->_cacheFile)) {
1948
					$contents = file_get_contents($this->_cacheFile);
1949
					list($cacheIP, $cacheTime) = explode('|', $contents);
1950
					$this->_debug($cacheIP.'/'.$cacheTime);
1951
					$initial = false;
1952
					$log_error .= sprintf(gettext("Cached IP: %s"), $cacheIP);
1953
				} else {
1954
					$cacheIP = '0.0.0.0';
1955
					@file_put_contents($this->_cacheFile, "0.0.0.0|{$currentTime}");
1956
					$cacheTime = $currentTime;
1957
					$initial = true;
1958
					$log_error .= gettext("No Cached IP found.");
1959
				}
1960
			}
1961
			if ($this->_dnsVerboseLog) {
1962
				log_error($log_error);
1963
			}
1964

    
1965
			// Convert seconds = days * hr/day * min/hr * sec/min
1966
			$maxCacheAgeSecs = $this->_dnsMaxCacheAgeDays * 24 * 60 * 60;
1967

    
1968
			$needs_updating = FALSE;
1969
			/* lets determine if the item needs updating */
1970
			if ($cacheIP != $wan_ip) {
1971
				$needs_updating = true;
1972
				$update_reason = gettext("Dynamic Dns: cacheIP != wan_ip. Updating.") . " ";
1973
				$update_reason .= sprintf(gettext('Cached IP: %1$s WAN IP: %2$s'), $cacheIP, $wan_ip) . " ";
1974
			}
1975
			if (($currentTime - $cacheTime) > $maxCacheAgeSecs) {
1976
				$needs_updating = true;
1977
				$this->_forceUpdateNeeded = true;
1978
				$update_reason = sprintf(gettext("Dynamic Dns: More than %s days. Updating."), $this->_dnsMaxCacheAgeDays);
1979
				$update_reason .= " {$currentTime} - {$cacheTime} > {$maxCacheAgeSecs} ";
1980
			}
1981
			if ($initial == true) {
1982
				$needs_updating = true;
1983
				$update_reason .= gettext("Initial update.");
1984
			}
1985

    
1986
			/*   finally if we need updating then store the
1987
			 *   new cache value and return true
1988
			 */
1989
			if ($needs_updating == true) {
1990
				if ($this->_dnsVerboseLog) {
1991
					log_error("DynDns ({$this->_FQDN}): {$update_reason}");
1992
				}
1993
				return true;
1994
			}
1995

    
1996
			return false;
1997
		}
1998

    
1999
		/*
2000
		 * Private Function (added 16 July 05) [beta]
2001
		 *   - Writes debug information to a file.
2002
		 *   - This function is only called when a unknown response
2003
		 *   - status is returned from a DynDNS service provider.
2004
		 */
2005
		function _debug($data) {
2006
			global $g;
2007

    
2008
			if (!$g['debug']) {
2009
				return;
2010
			}
2011
			$string = date('m-d-y h:i:s').' - ('.$this->_debugID.') - ['.$this->_dnsService.'] - '.$data."\n";
2012
			$file = fopen($this->_debugFile, 'a');
2013
			fwrite($file, $string);
2014
			fclose($file);
2015
		}
2016
		function _checkIP() {
2017
			global $debug;
2018

    
2019
			if ($debug) {
2020
				log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): _checkIP() starting.'), $this->_dnsService, $this->_FQDN));
2021
			}
2022

    
2023
			if ($this->_useIPv6 == true) {
2024
				$ip_address = get_interface_ipv6($this->_if);
2025
				if (!is_ipaddrv6($ip_address)) {
2026
					return 0;
2027
				}
2028
			} else {
2029
				$ip_address = get_interface_ip($this->_if);
2030
				if (!is_ipaddr($ip_address)) {
2031
					return 0;
2032
				}
2033
			}
2034
			if ($this->_useIPv6 == false && is_private_ip($ip_address)) {
2035
				$hosttocheck = "checkip.dyndns.org";
2036
				$try = 0;
2037
				while ($try < 3) {
2038
					$checkip = gethostbyname($hosttocheck);
2039
					if (is_ipaddr($checkip)) {
2040
						break;
2041
					}
2042
					$try++;
2043
				}
2044
				if ($try >= 3) {
2045
					log_error(sprintf(gettext('Dynamic DNS %1$s debug information (%2$s): Could not resolve %3$s to IP using interface IP %4$s.'), $this->_dnsService, $this->_FQDN, $hosttocheck, $ip_address));
2046
					return 0;
2047
				}
2048
				$ip_ch = curl_init("http://{$checkip}");
2049
				curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
2050
				curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
2051
				curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address);
2052
				curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
2053
				curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
2054
				if ($this->_useIPv6 == false) {
2055
					curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
2056
				}
2057
				$ip_result_page = curl_exec($ip_ch);
2058
				curl_close($ip_ch);
2059
				$ip_result_decoded = urldecode($ip_result_page);
2060
				preg_match('/Current IP Address: (.*)<\/body>/', $ip_result_decoded, $matches);
2061
				$ip_address = trim($matches[1]);
2062
				if (is_ipaddr($ip_address)) {
2063
					if ($this->_dnsVerboseLog) {
2064
						log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): %3$s extracted from %4$s'), $this->_dnsService, $this->_FQDN, $ip_address, $hosttocheck));
2065
					}
2066
				} else {
2067
					log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): IP address could not be extracted from %3$s'), $this->_dnsService, $this->_FQDN, $hosttocheck));
2068
					return 0;
2069
				}
2070
			} else {
2071
				if ($this->_dnsVerboseLog) {
2072
					log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): %3$s extracted from local system.'), $this->_dnsService, $this->_FQDN, $ip_address));
2073
				}
2074
			}
2075
			$this->_dnsIP = $ip_address;
2076

    
2077
			return $ip_address;
2078
		}
2079

    
2080
	}
2081

    
2082
?>
(12-12/54)