0

I'm currently trying to make a DDNS script that interacts with the Cloudflare API to catch changes in my ip address and automatically fix the ip address change for my web server. Everything is working correctly so far except I can't get $IP to be put properly in the curl statement. I first run a python script from within the bash script to get the ip address, then run the curl statement in the bash script. Here's what the python script looks like (it returns an ip address like "1.1.1.1" with quotations included because the curl command requires the quotations)

#!/usr/bin/python3

import subprocess as sp

def main():
    command = "dig +short myip.opendns.com @resolver1.opendns.com";
    ip = sp.check_output(command, shell=True).decode('utf-8').strip('\n');
    ip_tmp = ip;
    ip_tmp = '"' + ip + '"';
    ip = ip_tmp;
    print(ip);


if __name__ == "__main__":
    main();

And the bash script looks like this:

#!/bin/bash

IP=$("./getIP.py")

curl -X PUT "https://api.cloudflare.com/client/v4/zones/zone_id/dns_records/dns_id" \
     -H "X-Auth-Email: example.com" \
     -H "X-Auth-Key: authkey" \
     -H "Content-Type: application/json" \
     --data '{"type":"A","name":"example.com","content":$IP,"ttl":120,"proxied":true}'

I've tried to have the python script only return numbers and then added the quotations in the bash script and now vice versa and I can't seem to get it to work. The last line should end up looking like this once the variable replaces with quotations around the ip address:

'{"type":"A","name":"example.com","content":"127.0.0.1","ttl":120,"proxied":true}'
3
  • Why run a Python script that in turn starts a dig command to inject that in a bash variable instead of using dig directly from bash, like in: IP=$(dig +short myip.opendns.com @resolver1.opendns.com) ? And if you need the doublequotes in the string: IP=$(echo '"'$(dig +short myip.opendns.com @resolver1.opendns.com)'"') Commented Aug 22, 2018 at 21:22
  • I was using the command curl ipinfo.io/ip to get the ip, but that returned a bunch of other garbage with it and I'm way more familiar with Python than Bash as far as string manipulation goes. Then I found the dig command made life way easier but didn't get around to deleting the py script I didn't need anymore yet Commented Aug 22, 2018 at 21:44
  • Use better source :-) curl api.ipify.org will nicely just reply with just your IP. See ipify.org even for other output formats. Of course you then depend on this site to work when you need to get your IP. Commented Aug 22, 2018 at 21:48

2 Answers 2

3

The single quotes around your json structure prevent the variable from expanding.

You have a few options that are readily available.

Ugly quote escaping inside/around your json.

"{\"type\":\"A\",\"name\":\"example.com\",\"content\":$IP,\"ttl\":120,\"proxied\":true}"

Having the python write this data to a file and telling curl to use that file for the source of the post data.

curl -X PUT "https://api.cloudflare.com/client/v4/zones/zone_id/dns_records/dns_id" \
 -H "X-Auth-Email: example.com" \
 -H "X-Auth-Key: authkey" \
 -H "Content-Type: application/json" \
 --data @file_you_wrote_your_json_to.json

Using the python requests or urllib modules to issue the request to cloud flare.

Update your main() function to return the IP instead of print it.

my_ip = main()
url = "https://api.cloudflare.com/client/v4/zones/zone_id/dns_records/dns_id"

myheaders = {
    "X-Auth-Email": "example.com",
    "X-Auth-Key": "authkey",
    "Content-Type": "application/json"
}

myjson = {
    "type":"A",
    "name":"example.com",
    "content":my_ip,
    "ttl":120,
    "proxied":true
}

requests.put(url, headers=myheaders, data=myjson)
Sign up to request clarification or add additional context in comments.

2 Comments

@glennjackman fair enough. Hopped on the ol laptop to add something.
Slightly more palatable quoting: '{"start of json" :..., "content": "'"$IP"'","and so on"}'
0

Better yet, just do it in bash. Cloudflare DDNS on github.

One shot to fetch the dynamic A-record ID:

curl -X GET "https://api.cloudflare.com/client/v4/zones/**Zone ID** \
                    /dns_records?type=A&name=dynamic" \
     -H "Host: api.cloudflare.com" \
     -H "User-Agent: ddclient/3.9.0" \
     -H "Connection: close" \
     -H "X-Auth-Email: [email protected]" \
     -H "X-Auth-Key: "**Authorization key**" \
     -H "Content-Type: application/json"

Cron job (* * * * *) to set the dynamic A-record:

#/usr/bin/env sh

[email protected]
AUTH_KEY=** CF Authorization  key **
ZONE_ID=** CF Zone ID **
A_RECORD_NAME="dynamic"
A_RECORD_ID=** CF A-record ID from cloudflare-dns-id.sh **

IP_RECORD="/tmp/ip-record"
RECORDED_IP=`cat $IP_RECORD`
PUBLIC_IP=$(curl --silent https://api.ipify.org) || exit 1

if [ "$PUBLIC_IP" = "$RECORDED_IP" ]; then
    exit 0
fi

echo $PUBLIC_IP > $IP_RECORD

RECORD=$(cat <<EOF
{ "type": "A",
  "name": "$A_RECORD_NAME",
  "content": "$PUBLIC_IP",
  "ttl": 180,
  "proxied": false }
EOF
)
curl "https://api.cloudflare.com/client/v4/zones/$ZONE_ID \
             /dns_records/$A_RECORD_ID" \
     -X PUT \
     -H "Content-Type: application/json" \
     -H "X-Auth-Email: $AUTH_EMAIL" \
     -H "X-Auth-Key: $AUTH_KEY" \
     -d "$RECORD"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.