Skip to content
Snippets Groups Projects
dyndnsd-client.go 3.14 KiB
Newer Older
Erick Hitter's avatar
Erick Hitter committed
package main

Erick Hitter's avatar
Erick Hitter committed
import (
Erick Hitter's avatar
Erick Hitter committed
	"flag"
Erick Hitter's avatar
Erick Hitter committed
	"fmt"
	"github.com/joshbetz/config"
	"io/ioutil"
Erick Hitter's avatar
Erick Hitter committed
	"log"
Erick Hitter's avatar
Erick Hitter committed
	"net"
Erick Hitter's avatar
Erick Hitter committed
	"net/http"
	"net/url"
Erick Hitter's avatar
Erick Hitter committed
	"os"
Erick Hitter's avatar
Erick Hitter committed
)

var (
	cfg          *config.Config
	ipv4Endpoint string
	ipv6Endpoint string
Erick Hitter's avatar
Erick Hitter committed

	logger *log.Logger
Erick Hitter's avatar
Erick Hitter committed
// Preparations
Erick Hitter's avatar
Erick Hitter committed
func init() {
Erick Hitter's avatar
Erick Hitter committed
	// Logging
	logOpts := log.Ldate | log.Ltime | log.LUTC | log.Lshortfile
	logger = log.New(os.Stdout, "", logOpts)

	logger.Println("PINGING dyndnsd ENDPOINT")
Erick Hitter's avatar
Erick Hitter committed
	// Configuration
Erick Hitter's avatar
Erick Hitter committed
	var configPath string
	flag.StringVar(&configPath, "config", "", "Config file path")
	flag.Parse()

	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		fmt.Println("Config path does not exist. Aborting!\n")
		flag.Usage()
		os.Exit(3)
	}

	cfg = config.New(configPath)
Erick Hitter's avatar
Erick Hitter committed
	cfg.Get("ipv4_endpoint", &ipv4Endpoint)
	cfg.Get("ipv6_endpoint", &ipv6Endpoint)
}

// Do the update!
Erick Hitter's avatar
Erick Hitter committed
func main() {
Erick Hitter's avatar
Erick Hitter committed
	// Base URL
	endpoint, err := buildEndpointUrl()
	if err != nil {
Erick Hitter's avatar
Erick Hitter committed
		logger.Println("Couldn't build endpoint URL")
		logger.Printf("%s", err)
Erick Hitter's avatar
Erick Hitter committed
		return
	}

	// IPv4 is required
Erick Hitter's avatar
Erick Hitter committed
	if ipv4, err := getUrl(ipv4Endpoint); err == nil {
Erick Hitter's avatar
Erick Hitter committed
		if ipv4Valid := net.ParseIP(ipv4); ipv4Valid == nil {
			logger.Println("Invalid IPv4 address")
			logger.Printf("%s", err)
			return
		} else {
			query := endpoint.Query()
			query.Set("myip", ipv4Valid.String())
			endpoint.RawQuery = query.Encode()
		}
Erick Hitter's avatar
Erick Hitter committed
	} else {
Erick Hitter's avatar
Erick Hitter committed
		logger.Println("Couldn't retrieve IPv4 address")
		logger.Printf("%s", err)
Erick Hitter's avatar
Erick Hitter committed
		return
	}

	// IPv6 is optional
Erick Hitter's avatar
Erick Hitter committed
	if ipv6, err := getUrl(ipv6Endpoint); err == nil {
Erick Hitter's avatar
Erick Hitter committed
		if ipv6Valid := net.ParseIP(ipv6); ipv6Valid == nil {
			logger.Println("Invalid IPv6 address")
			logger.Printf("%s", err)
		} else {
			// TODO: parse to /64, use ::1.

			query := endpoint.Query()
			query.Set("myip6", ipv6Valid.String())
Erick Hitter's avatar
Erick Hitter committed
			endpoint.RawQuery = query.Encode()
		}
Erick Hitter's avatar
Erick Hitter committed
	} else {
		logger.Println("Couldn't retrieve IPv6 address")
		logger.Printf("%s", err)
Erick Hitter's avatar
Erick Hitter committed
	}

	// Send the update
	dyndns, err := getUrl(endpoint.String())
	if err != nil {
Erick Hitter's avatar
Erick Hitter committed
		logger.Println("Couldn't update dyndnsd endpoint")
		logger.Printf("%s", err)
Erick Hitter's avatar
Erick Hitter committed
	logger.Println("SUCCESS! Ping sent.")
	logger.Printf("%s", dyndns)
Erick Hitter's avatar
Erick Hitter committed
}

// Build endpoint URL from configuration
func buildEndpointUrl() (*url.URL, error) {
	var username string
	var password string
	var protocol string
	var host string
	var port int
	var path string
	var hostname string

	cfg.Get("username", &username)
	cfg.Get("password", &password)
	cfg.Get("protocol", &protocol)
	cfg.Get("host", &host)
	cfg.Get("port", &port)
	cfg.Get("path", &path)
	cfg.Get("dns_hostname", &hostname)

	daemonUrl, err := url.Parse("")
	if err != nil {
		return nil, err
	}

	daemonUrl.Scheme = protocol
	daemonUrl.Host = fmt.Sprintf("%s:%d", host, port)
	daemonUrl.Path = path

	userInfo := url.UserPassword(username, password)
	daemonUrl.User = userInfo

	query := daemonUrl.Query()
	query.Set("hostname", hostname)
	daemonUrl.RawQuery = query.Encode()

	return daemonUrl, nil
}

// Retrieve given URL
func getUrl(url string) (string, error) {
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}

	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)

	if err != nil {
		return "", err
	}

	respBodyString := string(respBody)
	return respBodyString, nil
Erick Hitter's avatar
Erick Hitter committed
}