#!/usr/bin/env python3
#-*- encoding: utf-8 -*-

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import requests
import json
import re
import socket
import ipaddress

# Config
domain="soutade.fr"
API_KEY = "YOUR_API_KEY"
livedns_api = "https://dns.api.gandi.net/api/v5/"
# https://api.gandi.net/v5/livedns/domains/{fqdn}/records
dyndns_url = 'http://checkip.dyndns.com/'
headers = {
    'X-Api-Key': API_KEY,
}
A_RECORD_NAME="@" # Target record to update

# https://www.programcreek.com/python/?CodeExample=get+local+address
def get_ipv6():
    s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
    s.connect(('2001:4860:4860::8888', 1))
    return s.getsockname()[0]

def get_ipv4():
    response = requests.get(dyndns_url)
    if response.ok:
        pattern = re.compile('[^:]*(\d+\.\d+\.\d+\.\d+)')
        result = pattern.search(response.text, 0)
        if result == None:
            print("No IP found")
            exit(1) 
        else:
            return result.group(0).strip()
    # Bad gateway
    elif response.status_code in (502,504):
        exit(0)
    else:
        print("Connexion error")
        response.raise_for_status()
        exit(1)
    
def update_gandi_record(domain_records_href, target, value):
    # Get recorded IP
    response = requests.get(f'{domain_records_href}/{A_RECORD_NAME}/{target}', headers=headers)

    if (response.ok):
        record = response.json()
    else:
        print("Failed to look for recorded IP")
        if response.status_code != 502: # Bad gateway
            response.raise_for_status()
        exit(1)

    if value != record['rrset_values'][0]:
        record['rrset_values'][0] = value

        print(f'URL {domain_records_href}/{A_RECORD_NAME}/{target}')
        
        # PUT new IP
        response = requests.put(f'{domain_records_href}/{A_RECORD_NAME}/{target}',
                                headers=headers, json=record)

        if (response.ok):
            print("IP updated")
        else:
            print("something went wrong")
            if response.status_code != 502: # Bad gateway
                response.raise_for_status()
            exit(1)
        
        return 34 # IP updated return !!
    
    return 0

def create_gandi_record(domain_records_href, name, _type, value):
    request = {
        'rrset_name':name,
        'rrset_type': _type,
        'rrset_values': [value],
        'rrset_ttl': 300
        }

    response = requests.post(f'{domain_records_href}', headers=headers, json=request)

    if response.status_code == 201:
        return 0
    else:
        print(response)
        return 1

def delete_gandi_records(domain_records_href, _type):
    response = requests.get(f'{domain_records_href}?rrset_type={_type}', headers=headers)
    
    if (response.ok):
        json_resp = response.json()
        for record in json_resp:
            requests.delete(record['rrset_href'], headers=headers)
        return 0
    else:
        print(response)
        return 1

# Get current IP
current_ip_v4 = get_ipv4()
print(f'Your Current IP is {current_ip_v4}')

# Retrieve domains address
response = requests.get(livedns_api + "domains", headers=headers)
if (response.ok):
    domains = response.json()
else:
    if response.status_code != 502: # Bad gateway
        response.raise_for_status()
    exit(1)

domain_index = next((index for (index, d) in enumerate(domains) if d["fqdn"] == domain), None)

if domain_index == None:
    # domain not found
    print("The requested domain {domain} was not found in this gandi account")
    exit(1)

domain_records_href = domains[domain_index]["domain_records_href"]
ret = update_gandi_record(domain_records_href, 'A', current_ip_v4)
    
current_ip_v6 = get_ipv6()
print(f'Your Current IP is {current_ip_v6}')

domain_records_href = domains[domain_index]["domain_records_href"]
ret |= update_gandi_record(domain_records_href, 'AAAA', current_ip_v6)

if ret == 34:
    # Delete all PTR records
    delete_gandi_records(domain_records_href, 'PTR')
    
    # Update PTR v4
    reverse_ip = '.'.join(current_ip_v4.split('.')[::-1])
    ptr_ip = f'{reverse_ip}.in-addr.arpa'
    create_gandi_record(domain_records_href, ptr_ip, 'PTR', f'{domain}.')

    # Update PTR v6
    full_ip = ipaddress.ip_address(current_ip_v6).exploded
    reverse_ip = '.'.join(full_ip.replace(':', '')[::-1])
    ptr_ip = f'{reverse_ip}.ip6.arpa'
    create_gandi_record(domain_records_href, ptr_ip, 'PTR', f'{domain}.')


exit(ret)
