After a couple of years updating my IP update script with IPv6 but it's not working as intended

What happens is:

  • The IPv4 A record gets deleted
  • A second AAAA record (for the same domain) gets added with the new IP

My fault or?

Here’s the script:

<?php
//
// Authorisation and config variables
//
$headers = [
  'X-Auth-Email: EMAIL',
  'X-Auth-Key: API_KEY',
  'Content-Type: application/json'
];

// Type, domain and record
$type   = "AAAA";
$domain = "zkitzo.one";
$record = "zkitzo.one";



//
// Functions (https://www.php.net/manual/en/function.array-search.php#122288)
//
function array_recursive_search_key_map($needle, $haystack) {
    foreach($haystack as $first_level_key=>$value) {
        if ($needle === $value) {
            return array($first_level_key);
        } elseif (is_array($value)) {
            $callback = array_recursive_search_key_map($needle, $value);
            if ($callback) {
                return array_merge(array($first_level_key), $callback);
            }
        }
    }
    return false;
}

function array_get_nested_value($keymap, $array)
{
    $nest_depth = sizeof($keymap);
    $value = $array;
    for ($i = 0; $i < $nest_depth; $i++) {
        $value = $value[$keymap[$i]];
    }

    return $value;
}


// IPv4 or IPv6 URL
if ($type == "A") {
  $url = "https://api.ipify.org";
}
elseif ($type == "AAAA") {
  $url = "https://api6.ipify.org";
}

// Save IP in a variable
$ch=curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, 'PHP version: ' . phpversion());

$ip = curl_exec($ch);
if(curl_errno($ch)) {
  exit("Internet down? Error: " . curl_error($ch));
}
curl_close($ch);

// The data we want to modify if needed
$data = [
  'type' => $type,
  'name' => $record,
  'content' => $ip
];



//
// Get ZoneID
//
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones?name=$domein");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$result = curl_exec($ch);
if(curl_errno($ch)) {
  exit("Error: " . curl_error($ch));
}
curl_close($ch);

$json = json_decode($result, true);

// Set the ZoneID
$ZoneID = $json['result']['0']['id'];
echo "ZoneID: " . $ZoneID . PHP_EOL;



//
// Get DNSID
//
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones/$ZoneID/dns_records?name=$record");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$result = curl_exec($ch);
if(curl_errno($ch)) {
  exit("Error: " . curl_error($ch));
}
curl_close($ch);

$json = json_decode($result, true);
// var_dump($json);
$search_value = $type;
$array_keymap = array_recursive_search_key_map($search_value, $json);
// var_dump($array_keymap);
$array_nested_value = array_get_nested_value($array_keymap, $json);
// echo array_get_nested_value($array_keymap, $json) . PHP_EOL; // AAAA

// Set the DNSID
$DNSID = $json['result']['0']['id'];
echo "DNSID: " . $DNSID . PHP_EOL;



//
// Check if IP has to replaced
//
$cf_ip = $json[$array_keymap['0']][$array_keymap['1']]['content'];

if(empty($cf_ip)) {
  exit("CloudFlare didn't send a IP... We'll try again soon!");
}

echo "CloudFlare IP: $cf_ip" . PHP_EOL;
echo "Current IP: $ip" . PHP_EOL;
if($cf_ip === $ip) {
  echo "The IP doesn't have to be replaced!" . PHP_EOL;
}
else {
  echo "The IP has to be replaced!" . PHP_EOL;
  $ch = curl_init();

  curl_setopt($ch, CURLOPT_URL, "https://api.cloudflare.com/client/v4/zones/$ZoneID/dns_records/$DNSID");
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  $result = curl_exec($ch);
  
  if(curl_errno($ch)) {
    exit("Error: " . curl_error($ch) . PHP_EOL . "Something went wrong with replacing the IP!" . PHP_EOL);
  }
  else {
    $json = json_decode($result, true);
    // var_dump($json);
    if ($json['success'] == false) {
      exit("No success! " . $json['message'] . PHP_EOL);
    }
    echo "The IP has been replaced to $ip! " . PHP_EOL;
  }
}

I am afraid the forum here is not really for third party code. You better ask such a question on StackOverflow or Reddit.

If you believe you found an issue with the API, then the forum is definitely the right place, but then you’d need to point out what you believe the issue is. General debugging, not the right place :slight_smile:

I am sending a AAAA PATCH but the A record gets edited instead of the AAAA one.

Double check that you actually use the right ID.

If you send a request for AAAA and an IPv6 address, the API can’t update an A record. I just checked that. There’ll be some issue with your code.

From the audit:

Date:2022-06-15T17:22:37+02:00
User IP Address:IPv6-Address
Resource:DNS record
New Value:
{
  "Content": "IPv6-Address",
  "Id": "f691c8838aaa9d635f6c52eeb1fa499c",
  "Name": "zkitzo.one",
  "Proxied": true,
  "Ttl": 1,
  "Type": "AAAA",
  "Zone id": "dd32ed3eebb3c18fa59ff982cc2d5af4",
  "Zone name": "zkitzo.one"
}
Old Value:
{
  "Content": "IPv4-Address",
  "Id": "f691c8838aaa9d635f6c52eeb1fa499c",
  "Name": "zkitzo.one",
  "Proxied": true,
  "Ttl": 1,
  "Type": "A",
  "Zone id": "dd32ed3eebb3c18fa59ff982cc2d5af4",
  "Zone name": "zkitzo.one"
}
Interface:API
Audit Record:13a812fd-0f7b-4255-9179-845b2717a0fb
Metadata:
{
  "Zone name": "zkitzo.one"
}

It really does that.

You changed the record from A to AAAA. What’s exactly the issue?

I want to replace the IPv6 if it’s changed, but instead of changing the IPv6 address it changes the IPv4 one. They are in the same ZoneID.

And there is already a AAAA record but it add’s a second one, because the A is changed to a AAAA record.

It doesn’t change the IPv4 one, it changes the record with the ID you specified, which happens to be an A record. As I said before

array(5) {
  ["result"]=>
  array(6) {
    [0]=>
    array(13) {
      ["id"]=>
      string(32) "f691c8838aaa9d635f6c52eeb1fa499c"
      ["zone_id"]=>
      string(32) "dd32ed3eebb3c18fa59ff982cc2d5af4"
      ["zone_name"]=>
      string(10) "zkitzo.one"
      ["name"]=>
      string(10) "zkitzo.one"
      ["type"]=>
      string(1) "A"
      ["content"]=>
      string(14) "Redacted-IPv4-Address"
      ["proxiable"]=>
      bool(true)
      ["proxied"]=>
      bool(true)
      ["ttl"]=>
      int(1)
      ["locked"]=>
      bool(false)
      ["meta"]=>
      array(4) {
        ["auto_added"]=>
        bool(false)
        ["managed_by_apps"]=>
        bool(false)
        ["managed_by_argo_tunnel"]=>
        bool(false)
        ["source"]=>
        string(7) "primary"
      }
      ["created_on"]=>
      string(27) "2022-06-15T14:13:34.235978Z"
      ["modified_on"]=>
      string(27) "2022-06-15T14:13:34.235978Z"
    }
    [1]=>
    array(13) {
      ["id"]=>
      string(32) "3364fc446d51ed183436bcf99a612fa1"
      ["zone_id"]=>
      string(32) "dd32ed3eebb3c18fa59ff982cc2d5af4"
      ["zone_name"]=>
      string(10) "zkitzo.one"
      ["name"]=>
      string(10) "zkitzo.one"
      ["type"]=>
      string(4) "AAAA"
      ["content"]=>
      string(20) "Redacted-IPv6-Address"
      ["proxiable"]=>
      bool(true)
      ["proxied"]=>
      bool(true)
      ["ttl"]=>
      int(1)
      ["locked"]=>
      bool(false)
      ["meta"]=>
      array(4) {
        ["auto_added"]=>
        bool(false)
        ["managed_by_apps"]=>
        bool(false)
        ["managed_by_argo_tunnel"]=>
        bool(false)
        ["source"]=>
        string(7) "primary"
      }
      ["created_on"]=>
      string(27) "2022-06-15T14:07:04.982061Z"
      ["modified_on"]=>
      string(27) "2022-06-15T14:12:37.917471Z"
    }

See for yourself :slight_smile:

What is this supposed to tell me?

The record in question is an IPv4 record, hence it did what you told it :wink:

Sorry :slight_smile:

No worries. printf (or whatever the language offers) is usually your best debugging friend :slight_smile:

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.