Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
linkonoid committed Dec 11, 2017
1 parent 3a8308a commit bb08dc1
Show file tree
Hide file tree
Showing 3 changed files with 363 additions and 0 deletions.
218 changes: 218 additions & 0 deletions caddy-dyndns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
package dyndns

import (
"fmt"
"io/ioutil"
"net"
"net/http"
"strings"

"github.com/mholt/caddy"
"github.com/robfig/cron"
)

type Authentification struct {
Apikey string
Email string
}

type Config struct {
Provider string
Ipaddress string
Auth Authentification
Domains []string
Period string
Ipupdate string
}

func init() {
caddy.RegisterPlugin("dyndns", caddy.Plugin{Action: startup})
}

func startup(c *caddy.Controller) error {
return registerCallback(c, c.OnFirstStartup)
}

func getExternalIP(url string) (string, error) {
var addr string
client := &http.Client{}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return addr, err
}
resp, err := client.Do(req)
if err != nil {
return addr, err
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return addr, err
}
defer resp.Body.Close()
addr = strings.Trim(string(body), " \r\n")

if addr != "" {
ip := net.ParseIP(addr)
if ip == nil {
return addr, err
}
}
return addr, nil
}

func getIP(intf string) string {
myip := intf

if intf == "remote" {
list, err := net.Interfaces()
if err != nil {
panic(err)
}
for _, iface := range list {
//fmt.Printf("%d name=%s %v\n", i, iface.Name, iface)
addrs, err := iface.Addrs()
if err != nil {
panic(err)
}
for _, addr := range addrs {
fmt.Println(iface.Name, "->", addr.(*net.IPNet).IP)
if ipnet, ok := addr.(*net.IPNet); ok && isPublicIP(ipnet.IP) {
myip = ipnet.IP.String()
}
}
}
}

if intf == "local" {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err == nil {
ipnet := conn.LocalAddr().(*net.UDPAddr)
myip = ipnet.IP.String()
}
defer conn.Close()
}

if strings.Contains(intf, "http") {
var err error
myip, err = getExternalIP(intf)
if err != nil {
myip = ""
}
}

return myip
}

func isPublicIP(IP net.IP) bool {
if IP.IsLoopback() || IP.IsLinkLocalMulticast() || IP.IsLinkLocalUnicast() {
return false
}
if ip4 := IP.To4(); ip4 != nil {
switch true {
case ip4[0] == 10:
return false
case ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31:
return false
case ip4[0] == 192 && ip4[1] == 168:
return false
default:
return true
}
}
return false
}

func registerCallback(c *caddy.Controller, registerFunc func(func() error)) error {
var funcs []func() error
configs, err := parse(c)
if err != nil {
return err
}
for _, conf := range configs {
fn := func() error {
//<-------Cron begin
cr := cron.New()
cr.AddFunc("@every "+conf.Period, func() {
//Update record DNS
conf.Ipupdate = ""
if conf.Ipaddress != "" {
conf.Ipupdate = getIP(conf.Ipaddress)
}
switch conf.Provider {
case "cloudflare":
err = cloudflareupd(conf)
case "yandex":
err = yandexupd(conf)
default:
err = cloudflareupd(conf)
}
})
cr.Start()
//Cron end------->
if err != nil {
return err
}
return nil
}
funcs = append(funcs, fn)
}

return c.OncePerServerBlock(func() error {
for _, fn := range funcs {
registerFunc(fn)
}
return nil
})
}

func parse(c *caddy.Controller) ([]Config, error) {
var configs []Config
for c.Next() { // skip the directive name
conf := Config{}
//No extra args expected
if len(c.RemainingArgs()) > 0 {
return configs, c.ArgErr()
}
for c.NextBlock() {
switch c.Val() {
case "provider":
if !c.NextArg() {
return configs, c.ArgErr()
}
conf.Provider = c.Val()
case "ipaddress":
if !c.NextArg() {
return configs, c.ArgErr()
}
conf.Ipaddress = c.Val()
case "auth":
args := c.RemainingArgs()
if len(args) > 2 {
return configs, c.ArgErr()
}
if len(args) == 0 {
return configs, c.ArgErr()
}
conf.Auth.Apikey = args[0]
if len(args) == 2 {
conf.Auth.Email = args[1]
}
case "domains":
args := c.RemainingArgs()
if len(args) == 0 {
return configs, c.ArgErr()
}
conf.Domains = args
case "period":
if !c.NextArg() {
return configs, c.ArgErr()
}
conf.Period = c.Val()
default:
return configs, c.ArgErr()
}
}
configs = append(configs, conf)
}
return configs, nil
}
55 changes: 55 additions & 0 deletions cloudflare.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package dyndns

import (
"strings"

cloudfl "github.com/cloudflare/cloudflare-go"
)

func cloudflareupd(configs Config) error {

api, err := cloudfl.New(configs.Auth.Apikey, configs.Auth.Email)
if err != nil {
return err
}

for _, domain := range configs.Domains {

zoneID := ""
zones, err := api.ListZones()
if err != nil {
return err
}
for _, zone := range zones {
if strings.HasSuffix(domain, zone.Name) {
zoneID = zone.ID
}
}

recordID := ""
records, err := api.DNSRecords(zoneID, cloudfl.DNSRecord{})
if err != nil {
return err
}
for _, r := range records {
if r.Type == "A" && r.Name == domain {
recordID = r.ID
}
}

record, err := api.DNSRecord(zoneID, recordID)
if err != nil {
return err
}

if configs.Ipupdate != record.Content {
record.Content = configs.Ipupdate
err = api.UpdateDNSRecord(zoneID, recordID, record)
if err != nil {
return err
}
}
}

return nil
}
90 changes: 90 additions & 0 deletions yandex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package dyndns

import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"strings"
)

func yandexupd(configs Config) error {

//get record id from domain name
for _, domainname := range configs.Domains {

domainarray := strings.Split(domainname, ".")
getdomain := domainarray[len(domainarray)-2] + "." + domainarray[len(domainarray)-1]

client := &http.Client{}
req, err := http.NewRequest("GET", "https://pddimp.yandex.ru/api2/admin/dns/list?domain="+getdomain, nil)
if err != nil {
return err
}
req.Header.Set("PddToken", configs.Auth.Apikey)
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}

var f interface{}
err = json.Unmarshal(body, &f)
info := f.(map[string]interface{})

if success, ok := info["success"].(string); ok {
if success == "ok" {
for _, v := range info["records"].([]interface{}) {
inforecord := v.(map[string]interface{})
if recordtype, ok := inforecord["type"].(string); ok && (recordtype == "A") {
if domain, ok := inforecord["fqdn"].(string); ok {
if subdomain, ok := inforecord["subdomain"].(string); ok {
if record_id, ok := inforecord["record_id"].(float64); ok && (domainname == domain) {
ipaddr := inforecord["content"].(string)
ttl := inforecord["ttl"].(float64)

if configs.Ipupdate != ipaddr {
urltpl := "https://pddimp.yandex.ru/api2/admin/dns/edit?domain=%s&subdomain=%s&record_id=%s&ttl=%d&content=%s"
url := fmt.Sprintf(urltpl, getdomain, subdomain, strconv.Itoa(int(record_id)), strconv.Itoa(int(ttl)), configs.Ipupdate)

req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err
}
req.Header.Set("PddToken", configs.Auth.Apikey)
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}

err = json.Unmarshal(body, &f)
info := f.(map[string]interface{})

if success, ok := info["success"].(string); ok {
if success == "ok" {
println("IP ", domainname, " change")
return nil
}
}
}
}
}
}
}
}
}
}
}

return nil
}

0 comments on commit bb08dc1

Please sign in to comment.