From 15595d01ac8f996b7477c36b993c2eb7ab82ef36 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 28 Jul 2024 00:26:49 -0400 Subject: [PATCH 01/10] gandi: Delete unnecessary comment --- ddclient.in | 1 - 1 file changed, 1 deletion(-) diff --git a/ddclient.in b/ddclient.in index 99e4095..c50f099 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6905,7 +6905,6 @@ EoEXAMPLE ###################################################################### sub nic_gandi_update { debug("\nnic_gandi_update -------------------"); - # Update each set configured host. for my $h (@_) { for my $ipv ('ipv4', 'ipv6') { my $ip = delete $config{$h}{"want$ipv"}; From 2ccdefff9395bc88c7d36f41cdb4b453cdc18c95 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 28 Jul 2024 00:30:15 -0400 Subject: [PATCH 02/10] gandi: Whitespace fixes --- ddclient.in | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/ddclient.in b/ddclient.in index c50f099..833ae37 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6908,14 +6908,13 @@ sub nic_gandi_update { for my $h (@_) { for my $ipv ('ipv4', 'ipv6') { my $ip = delete $config{$h}{"want$ipv"}; - if(!$ip) { + if (!$ip) { next; } (my $hostname = $h) =~ s/\.\Q$config{$h}{zone}\E$//; info("%s -- Setting IP address to %s.", $h, $ip); - my $headers; - $headers = "Content-Type: application/json\n"; + $headers = "Content-Type: application/json\n"; if ($config{$h}{'use-personal-access-token'} == 1) { $headers .= "Authorization: Bearer $config{$h}{'password'}\n"; } @@ -6923,31 +6922,25 @@ sub nic_gandi_update { { $headers .= "Authorization: Apikey $config{$h}{'password'}\n"; } - - - my $rrset_type = $ipv eq 'ipv6' ? 'AAAA' : 'A'; my $url; - $url = "https://$config{$h}{'server'}$config{$h}{'script'}"; + $url = "https://$config{$h}{'server'}$config{$h}{'script'}"; $url .= "/livedns/domains/$config{$h}{'zone'}/records/$hostname/$rrset_type"; - my $reply = geturl( - proxy => opt('proxy'), - url => $url, - headers => $headers, - method => 'GET' + proxy => opt('proxy'), + url => $url, + headers => $headers, + method => 'GET' ); my $ok = header_ok($h, $reply); - $reply =~ s/^.*?\n\n//s; my $response = eval { decode_json($reply) }; if (!defined($response)) { $config{$h}{"status-$ipv"} = "bad"; - failed("%s -- Unexpected service response.", $h); next; } - if($response->{'rrset_values'}->[0] eq $ip && (!defined($config{$h}{'ttl'}) || + if ($response->{'rrset_values'}->[0] eq $ip && (!defined($config{$h}{'ttl'}) || $response->{'rrset_ttl'} eq $config{$h}{'ttl'})) { $config{$h}{'ip'} = $ip; $config{$h}{'mtime'} = $now; @@ -6955,17 +6948,16 @@ sub nic_gandi_update { success("updating %s: skipped: address was already set to %s.", $h, $ip); next; } - my $data = encode_json({ defined($config{$h}{'ttl'}) ? (rrset_ttl => $config{$h}{'ttl'}) : (), rrset_values => [$ip], }); $reply = geturl( - proxy => opt('proxy'), - url => $url, - headers => $headers, - method => 'PUT', - data => $data, + proxy => opt('proxy'), + url => $url, + headers => $headers, + method => 'PUT', + data => $data, ); $ok = header_ok($h, $reply); if ($ok) { @@ -6988,6 +6980,7 @@ sub nic_gandi_update { } } } + ###################################################################### ## nic_keysystems_examples ###################################################################### From 325eb10536d34f08cfba6f33ebe91f3e5442bffc Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 28 Jul 2024 00:33:15 -0400 Subject: [PATCH 03/10] gandi: Style fixes for readability --- ddclient.in | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/ddclient.in b/ddclient.in index 833ae37..e863e4e 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6907,30 +6907,22 @@ sub nic_gandi_update { debug("\nnic_gandi_update -------------------"); for my $h (@_) { for my $ipv ('ipv4', 'ipv6') { - my $ip = delete $config{$h}{"want$ipv"}; - if (!$ip) { - next; - } + my $ip = delete $config{$h}{"want$ipv"} or next; (my $hostname = $h) =~ s/\.\Q$config{$h}{zone}\E$//; info("%s -- Setting IP address to %s.", $h, $ip); - my $headers; - $headers = "Content-Type: application/json\n"; + my $headers = "Content-Type: application/json\n"; if ($config{$h}{'use-personal-access-token'} == 1) { $headers .= "Authorization: Bearer $config{$h}{'password'}\n"; - } - else - { + } else { $headers .= "Authorization: Apikey $config{$h}{'password'}\n"; } my $rrset_type = $ipv eq 'ipv6' ? 'AAAA' : 'A'; - my $url; - $url = "https://$config{$h}{'server'}$config{$h}{'script'}"; - $url .= "/livedns/domains/$config{$h}{'zone'}/records/$hostname/$rrset_type"; + my $url = "https://$config{$h}{'server'}$config{$h}{'script'}/livedns/domains/$config{$h}{'zone'}/records/$hostname/$rrset_type"; my $reply = geturl( proxy => opt('proxy'), url => $url, headers => $headers, - method => 'GET' + method => 'GET', ); my $ok = header_ok($h, $reply); $reply =~ s/^.*?\n\n//s; From 12d5539abc1d41156460caf6e30542269d9ab16f Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 28 Jul 2024 01:08:42 -0400 Subject: [PATCH 04/10] gandi: Don't ignore HTTP response code --- ddclient.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ddclient.in b/ddclient.in index e863e4e..36244d5 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6924,7 +6924,7 @@ sub nic_gandi_update { headers => $headers, method => 'GET', ); - my $ok = header_ok($h, $reply); + next if !header_ok($h, $reply); $reply =~ s/^.*?\n\n//s; my $response = eval { decode_json($reply) }; if (!defined($response)) { @@ -6951,7 +6951,7 @@ sub nic_gandi_update { method => 'PUT', data => $data, ); - $ok = header_ok($h, $reply); + my $ok = header_ok($h, $reply); if ($ok) { $config{$h}{'ip'} = $ip; $config{$h}{'mtime'} = $now; From b1ddaa0ce89b5a852a1da5352ac66cd270e88b19 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 28 Jul 2024 01:17:52 -0400 Subject: [PATCH 05/10] gandi: Log message improvements --- ddclient.in | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ddclient.in b/ddclient.in index 36244d5..0a30be7 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6909,7 +6909,7 @@ sub nic_gandi_update { for my $ipv ('ipv4', 'ipv6') { my $ip = delete $config{$h}{"want$ipv"} or next; (my $hostname = $h) =~ s/\.\Q$config{$h}{zone}\E$//; - info("%s -- Setting IP address to %s.", $h, $ip); + info("$h: setting IP address to $ip"); my $headers = "Content-Type: application/json\n"; if ($config{$h}{'use-personal-access-token'} == 1) { $headers .= "Authorization: Bearer $config{$h}{'password'}\n"; @@ -6929,7 +6929,7 @@ sub nic_gandi_update { my $response = eval { decode_json($reply) }; if (!defined($response)) { $config{$h}{"status-$ipv"} = "bad"; - failed("%s -- Unexpected service response.", $h); + failed("$h: unexpected service response"); next; } if ($response->{'rrset_values'}->[0] eq $ip && (!defined($config{$h}{'ttl'}) || @@ -6937,7 +6937,7 @@ sub nic_gandi_update { $config{$h}{'ip'} = $ip; $config{$h}{'mtime'} = $now; $config{$h}{"status-$ipv"} = "good"; - success("updating %s: skipped: address was already set to %s.", $h, $ip); + success("$h: skipped: address was already set to $ip"); next; } my $data = encode_json({ @@ -6956,7 +6956,7 @@ sub nic_gandi_update { $config{$h}{'ip'} = $ip; $config{$h}{'mtime'} = $now; $config{$h}{"status-$ipv"} = "good"; - success("%s -- Updated successfully to %s.", $h, $ip); + success("$h: updated successfully to $ip"); } else { $config{$h}{"status-$ipv"} = "bad"; if (defined($response->{status}) && $response->{status} eq "error") { @@ -6964,9 +6964,9 @@ sub nic_gandi_update { for my $err (@{$response->{errors}}) { push(@errors, $err->{description}); } - failed("%s -- %s.", $h, join(", ", @errors)); + failed("$h: " . join(", ", @errors)); } else { - failed("%s -- Unexpected service response.", $h); + failed("$h: unexpected service response"); } } } From a890b089355d7374886da967cffa2214946589e6 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 28 Jul 2024 01:47:32 -0400 Subject: [PATCH 06/10] gandi: Check for JSON object, not just definedness --- ddclient.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ddclient.in b/ddclient.in index 0a30be7..a95b149 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6927,9 +6927,9 @@ sub nic_gandi_update { next if !header_ok($h, $reply); $reply =~ s/^.*?\n\n//s; my $response = eval { decode_json($reply) }; - if (!defined($response)) { + if (ref($response) ne 'HASH') { $config{$h}{"status-$ipv"} = "bad"; - failed("$h: unexpected service response"); + failed("$h: response is not a JSON object: $reply"); next; } if ($response->{'rrset_values'}->[0] eq $ip && (!defined($config{$h}{'ttl'}) || From 5e52f728ada5f9b53009978641de354d6f542d8e Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 28 Jul 2024 02:02:45 -0400 Subject: [PATCH 07/10] gandi: Use an array for headers for readability --- ddclient.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index a95b149..60bbcdf 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6910,18 +6910,18 @@ sub nic_gandi_update { my $ip = delete $config{$h}{"want$ipv"} or next; (my $hostname = $h) =~ s/\.\Q$config{$h}{zone}\E$//; info("$h: setting IP address to $ip"); - my $headers = "Content-Type: application/json\n"; + my @headers = ('Content-Type: application/json'); if ($config{$h}{'use-personal-access-token'} == 1) { - $headers .= "Authorization: Bearer $config{$h}{'password'}\n"; + push(@headers, "Authorization: Bearer $config{$h}{'password'}"); } else { - $headers .= "Authorization: Apikey $config{$h}{'password'}\n"; + push(@headers, "Authorization: Apikey $config{$h}{'password'}"); } my $rrset_type = $ipv eq 'ipv6' ? 'AAAA' : 'A'; my $url = "https://$config{$h}{'server'}$config{$h}{'script'}/livedns/domains/$config{$h}{'zone'}/records/$hostname/$rrset_type"; my $reply = geturl( proxy => opt('proxy'), url => $url, - headers => $headers, + headers => \@headers, method => 'GET', ); next if !header_ok($h, $reply); @@ -6947,7 +6947,7 @@ sub nic_gandi_update { $reply = geturl( proxy => opt('proxy'), url => $url, - headers => $headers, + headers => \@headers, method => 'PUT', data => $data, ); From 6f505e6538543c0ae627c1b151473332bddf25cd Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 28 Jul 2024 02:09:05 -0400 Subject: [PATCH 08/10] gandi: Inline an unnecessary variable --- ddclient.in | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ddclient.in b/ddclient.in index 60bbcdf..9207153 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6940,16 +6940,15 @@ sub nic_gandi_update { success("$h: skipped: address was already set to $ip"); next; } - my $data = encode_json({ - defined($config{$h}{'ttl'}) ? (rrset_ttl => $config{$h}{'ttl'}) : (), - rrset_values => [$ip], - }); $reply = geturl( proxy => opt('proxy'), url => $url, headers => \@headers, method => 'PUT', - data => $data, + data => encode_json({ + defined($config{$h}{'ttl'}) ? (rrset_ttl => $config{$h}{'ttl'}) : (), + rrset_values => [$ip], + }), ); my $ok = header_ok($h, $reply); if ($ok) { From 06c3dd582569e570538d41bede891bc361715f83 Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 28 Jul 2024 02:20:08 -0400 Subject: [PATCH 09/10] gandi: Invert condition to improve readability --- ddclient.in | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ddclient.in b/ddclient.in index 9207153..71c4cbb 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6950,13 +6950,7 @@ sub nic_gandi_update { rrset_values => [$ip], }), ); - my $ok = header_ok($h, $reply); - if ($ok) { - $config{$h}{'ip'} = $ip; - $config{$h}{'mtime'} = $now; - $config{$h}{"status-$ipv"} = "good"; - success("$h: updated successfully to $ip"); - } else { + if (!header_ok($h, $reply)) { $config{$h}{"status-$ipv"} = "bad"; if (defined($response->{status}) && $response->{status} eq "error") { my @errors; @@ -6967,7 +6961,12 @@ sub nic_gandi_update { } else { failed("$h: unexpected service response"); } + next; } + $config{$h}{'ip'} = $ip; + $config{$h}{'mtime'} = $now; + $config{$h}{"status-$ipv"} = "good"; + success("$h: updated successfully to $ip"); } } } From 0b30df4b69bfdf15e34341bd8d90985bbe3ec7bd Mon Sep 17 00:00:00 2001 From: Richard Hansen Date: Sun, 28 Jul 2024 02:43:56 -0400 Subject: [PATCH 10/10] gandi: Fix processing of `PUT` error responses Before, the returned JSON wasn't even parsed -- the error handling code was reusing the parsed response from the earlier `GET`. Also, it was reading object properties that were not documented in the Gandi API documentation. --- ChangeLog.md | 2 ++ ddclient.in | 12 +++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 11bd94e..f7b0f67 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -142,6 +142,8 @@ repository history](https://github.com/ddclient/ddclient/commits/master). [#719](https://github.com/ddclient/ddclient/pull/719) * `yandex`: Errors are now retried. [#719](https://github.com/ddclient/ddclient/pull/719) + * `gandi`: Fixed handling of error responses. + [#721](https://github.com/ddclient/ddclient/pull/721) ## 2023-11-23 v3.11.2 diff --git a/ddclient.in b/ddclient.in index 71c4cbb..6658bae 100755 --- a/ddclient.in +++ b/ddclient.in @@ -6952,14 +6952,12 @@ sub nic_gandi_update { ); if (!header_ok($h, $reply)) { $config{$h}{"status-$ipv"} = "bad"; - if (defined($response->{status}) && $response->{status} eq "error") { - my @errors; - for my $err (@{$response->{errors}}) { - push(@errors, $err->{description}); - } - failed("$h: " . join(", ", @errors)); + $reply =~ s/^.*?\n\n//s; + my $response = eval { decode_json($reply) }; + if (ref($response) eq 'HASH' && ($response->{message} // '') ne '') { + failed("$h: $response->{message}"); } else { - failed("$h: unexpected service response"); + failed("$h: unexpected error response: $reply"); } next; }