Skip to content

Instantly share code, notes, and snippets.

@chrsan
Forked from dvalfrid/joker.sh
Last active August 29, 2015 14:19
Show Gist options
  • Save chrsan/d59f219cfccc196e4c35 to your computer and use it in GitHub Desktop.
Save chrsan/d59f219cfccc196e4c35 to your computer and use it in GitHub Desktop.
package main
// Fetch dependencies: go get golang.org/x/net/html
// Run as a shell script: go run joker.go -h
// Build as a static binary: go build joker.go && ./joker -h
//
// '-h' displays the command line flags
//
// Author: chrsan
import (
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"strings"
"golang.org/x/net/html"
)
// Walk the node n to find the IP address text.
func extractIP(n *html.Node) (string, bool) {
if n.Type == html.TextNode && strings.HasPrefix(n.Data, `Current IP Address:`) {
return strings.TrimPrefix(n.Data, `Current IP Address: `), true
}
// Traverse the child nodes.
for c := n.FirstChild; c != nil; c = c.NextSibling {
if s, found := extractIP(c); found {
return strings.TrimSpace(s), true
}
}
return "", false
}
// Fetch the current IP address.
func fetchIP() (string, bool) {
res, err := http.Get("https://svc.joker.com/nic/checkip")
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
doc, err := html.Parse(res.Body)
if err != nil {
log.Fatal(err)
}
return extractIP(doc)
}
// Struct holding the old IP address and file it was read from.
type oldIPFile struct {
file *os.File
ip string
}
// Open the file containing the old IP address.
func openOldIPFile(path string) *oldIPFile {
if f, err := os.OpenFile(path, os.O_RDWR, 0); err != nil {
// The file didn't exist, let's create it.
f, err := os.Create(path)
if err != nil {
log.Fatal(err)
}
return &oldIPFile{file: f}
} else {
// The file did exist, read its content.
b, err := ioutil.ReadAll(f)
if err != nil {
log.Fatal(err)
}
return &oldIPFile{file: f, ip: strings.TrimSpace(string(b))}
}
}
// Write the IP address to the file pointed to.
func (f *oldIPFile) write() error {
if err := f.file.Truncate(0); err != nil {
return err
}
if n, err := f.file.WriteString(f.ip); err != nil {
return err
} else if n != len(f.ip) {
return fmt.Errorf("Could not write %d expected bytes to %s", n, f.file.Name())
}
return nil
}
// Update the DNS
func updateDNS(ip, username, password, domain string) {
r, err := http.NewRequest("GET", "https://svc.joker.com/nic/update", nil)
if err != nil {
log.Fatal(err)
}
// URL parameters
v := url.Values{}
v.Set("myip", ip)
v.Set("username", username)
v.Set("password", password)
v.Set("hostname", domain)
v.Set("wildcard", "NOCHG")
v.Set("mx", "NOCHG")
v.Set("backmx", "NOCHG")
r.Form = v
resp, err := http.DefaultClient.Do(r)
if err != nil {
log.Fatal(err)
}
if resp.StatusCode != http.StatusOK {
log.Fatal("Failed to update DNS provider")
}
}
// Command line flags.
var (
oldIpFileFlag = flag.String("f", "", "path to old IP file")
usernameFlag = flag.String("u", "", "username")
passwordFlag = flag.String("p", "", "password")
domainFlag = flag.String("d", "", "domain")
)
// Check that none of the command line flag values are empty.
func checkFlags() bool {
for _, f := range []*string{oldIpFileFlag, usernameFlag, passwordFlag, domainFlag} {
if *f == "" {
return false
}
}
return true
}
func main() {
flag.Parse()
// Check the command line flags state.
if flag.NFlag() != 4 || flag.NArg() != 0 || !checkFlags() {
flag.Usage()
os.Exit(1)
}
ip, ok := fetchIP()
if !ok {
log.Fatal("Could not determine IP address")
}
log.Printf("Fetched IP address: %s\n", ip)
old := openOldIPFile(*oldIpFileFlag)
defer old.file.Close()
if ip == old.ip {
log.Printf("Same IP address: %s\n", ip)
} else {
log.Printf("%q != %q, updating DNS\n", ip, old.ip)
old.ip = ip
if err := old.write(); err != nil {
log.Fatal(err)
}
// TODO: Uncomment the line below to do the real thing
// updateDNS(ip, *usernameFlag, *passwordFlag, *domainFlag)
}
}
#!/bin/bash
# Fetching IP adress from joker.com
# Format: <html><head><title>Current IP Check</title></head><body>Current IP Address: 88.80.167.132</body></html>
function fetchIP {
local _returnParam=$1
local _response=$(curl --silent https://svc.joker.com/nic/checkip)
local _exit_code=$?
if [ $_exit_code -ne 0 ]; then
(
logger "Faild to fetch new IP adress"
)
fi
eval $_returnParam="'$_response'"
}
# Extract IP adress from response
function extractIP {
local _returnParam=$1 # <html><head><title>Current IP Check</title></head><body>Current IP Address: 88.80.167.132</body></html>
local _current_ip=$(echo $2 | sed -n -e 's/.*IP Address: \([0-9\.]*\).*/\1/p')
local _exit_code=$?
if [ $_exit_code -ne 0 ]; then
logger "[WARNING] Faild to match IP number"
fi
eval $_returnParam="$_current_ip"
}
# Fetching old IP from file
function oldIP {
local _returnParam=$1
local _file=$2
if [ ! -f "$_file" ]; then # Check if file exists
touch "$_file" # Create file
fi
eval $_returnParam="`cat $_file`"
}
# Update DNS Server
function updateDNS {
local _current_ip=$1
local _updateResponse=$(curl --write-out %{http_code} --silent --output /dev/null $3)
local _update_exit_code=$?
if [ $_update_exit_code -ne 0 ]; then # Curl could not make the call
(
logger "[Warning] Failed to update DNS provider, exit code: $_update_exit_code"
)
else
(
if [ $_updateResponse -ne 200 ]; then # Response call was not 200
(
logger "[Warning] Faild to update DNS provider, response code: $_updateResponse"
)
else
(
echo $_current_ip > $2 # Save current IP to file
logger "[Info] Old IP: $old_ip, New IP: $_current_ip"
)
fi
)
fi
}
# Main program
logger "[Info] DNS update started"
file="/usr/local/var/log/myip.file3" # Local storage for IP number
fetchIP response # Fetching the IP
extractIP currnet_ip "$response" # Extracting IP from response
oldIP old_ip "$file" # Read old IP adress from file
if [ "$currnet_ip" == "$old_ip" ]; then # Check if old and current IP are same
(
logger "[Info] Same IP adress: $old_ip"
)
else # They are not the same
(
updateDNS $currnet_ip $file "https://svc.joker.com/nic/update?username=<username>&password=<passowrd>&hostname=<domain>&myip=$currnet_ip&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG"
)
fi
logger "[Info] DNS update finished"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment