Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

    
400
			unlock($dyndnslck);
401
		}
402

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

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

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

    
420
			$ch = curl_init();
421

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1152
			$ch = curl_init();
1153

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

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

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

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

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

    
1220
			$ch = curl_init();
1221

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

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

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

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

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

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

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

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

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

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

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

    
2187
			$currentTime = time();
2188

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

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

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

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

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

    
2260
			return false;
2261
		}
2262

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

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

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

    
2287
			if ($this->_useIPv6 == true) {
2288
				$ip_address = get_interface_ipv6($this->_if);
2289
				if (!is_ipaddrv6($ip_address)) {
2290
					return 0;
2291
				}
2292
			} else {
2293
				$ip_address = get_interface_ip($this->_if);
2294
				if (!is_ipaddr($ip_address)) {
2295
					return 0;
2296
				}
2297
			}
2298
			if ($this->_useIPv6 == false && is_private_ip($ip_address)) {
2299
				$hosttocheck = "checkip.dyndns.org";
2300
				$try = 0;
2301
				while ($try < 3) {
2302
					$checkip = gethostbyname($hosttocheck);
2303
					if (is_ipaddr($checkip)) {
2304
						break;
2305
					}
2306
					$try++;
2307
				}
2308
				if ($try >= 3) {
2309
					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));
2310
					return 0;
2311
				}
2312
				$ip_ch = curl_init("http://{$checkip}");
2313
				curl_setopt($ip_ch, CURLOPT_RETURNTRANSFER, 1);
2314
				curl_setopt($ip_ch, CURLOPT_SSL_VERIFYPEER, FALSE);
2315
				curl_setopt($ip_ch, CURLOPT_INTERFACE, 'host!' . $ip_address);
2316
				curl_setopt($ip_ch, CURLOPT_CONNECTTIMEOUT, '30');
2317
				curl_setopt($ip_ch, CURLOPT_TIMEOUT, 120);
2318
				if ($this->_useIPv6 == false) {
2319
					curl_setopt($ip_ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
2320
				}
2321
				$ip_result_page = curl_exec($ip_ch);
2322
				curl_close($ip_ch);
2323
				$ip_result_decoded = urldecode($ip_result_page);
2324
				preg_match('/Current IP Address: (.*)<\/body>/', $ip_result_decoded, $matches);
2325
				$ip_address = trim($matches[1]);
2326
				if (is_ipaddr($ip_address)) {
2327
					if ($this->_dnsVerboseLog) {
2328
						log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): %3$s extracted from %4$s'), $this->_dnsService, $this->_FQDN, $ip_address, $hosttocheck));
2329
					}
2330
				} else {
2331
					log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): IP address could not be extracted from %3$s'), $this->_dnsService, $this->_FQDN, $hosttocheck));
2332
					return 0;
2333
				}
2334
			} else {
2335
				if ($this->_dnsVerboseLog) {
2336
					log_error(sprintf(gettext('Dynamic DNS %1$s (%2$s): %3$s extracted from local system.'), $this->_dnsService, $this->_FQDN, $ip_address));
2337
				}
2338
			}
2339
			$this->_dnsIP = $ip_address;
2340

    
2341
			return $ip_address;
2342
		}
2343

    
2344
	}
2345

    
2346
?>
(14-14/60)