/hostip - query current IP address of user host
authorvolpol <volpol@packet-gain.de>
Sat, 16 Jun 2018 15:34:29 +0000 (17:34 +0200)
committervolpol <volpol@packet-gain.de>
Sat, 16 Jun 2018 15:34:29 +0000 (17:34 +0200)
ddnset.go

index 416a9a79418da96a2762322f3318fc710fa9f162..4328d78f0258954b8113705ad1eaac0eaad92f90 100644 (file)
--- a/ddnset.go
+++ b/ddnset.go
@@ -6,6 +6,7 @@ import (
        "encoding/base64"
        "flag"
        "fmt"
+       "github.com/miekg/dns"
        "io"
        "io/ioutil"
        "log"
@@ -17,16 +18,18 @@ import (
 )
 
 const (
-       DefaultAccFile    = "/usr/local/etc/ddnset/ddnset.acc"
-       DefaultZoneFile   = "/usr/local/etc/ddnset/ddnset.zon"
-       DefaultLogFile    = "/var/log/ddnset/default.log"
-       DefaultListenPort = 1980
+       DefaultAccFile      = "/usr/local/etc/ddnset/ddnset.acc"
+       DefaultZoneFile     = "/usr/local/etc/ddnset/ddnset.zon"
+       DefaultLogFile      = "/var/log/ddnset/default.log"
+       DefaultListenPort   = 1980
+       DefaultAuthorityDNS = "localhost"
 )
 
 var AccFile = flag.String("a", DefaultAccFile, "Path to account file")
 var ZoneFile = flag.String("z", DefaultZoneFile, "Path to zone file")
 var LogFile = flag.String("l", DefaultLogFile, "Path to log file")
 var ListenPort = flag.Uint("p", DefaultListenPort, "Port to listen on")
+var AuthorityDNS = flag.String("s", DefaultAuthorityDNS, "Authoritative name server")
 
 var Help = flag.Bool("h", false, "Show usage")
 
@@ -190,6 +193,50 @@ func knsupdate(host, ip, zone string, ver int) bool {
        return true
 }
 
+func resolveWithAuthority(target, rectype string) string {
+       res := ""
+       c := dns.Client{}
+       m := dns.Msg{}
+
+       if rectype == "A" || rectype == "" {
+               m.SetQuestion(target+".", dns.TypeA)
+               r, _, err := c.Exchange(&m, *AuthorityDNS+":53")
+
+               if err == nil {
+                       if len(r.Answer) == 0 {
+                               log.Printf("%s. has no A record", target)
+                       }
+
+                       for _, ans := range r.Answer {
+                               record := ans.(*dns.A)
+                               log.Printf("%s. has IP %s", target, record.A)
+                               res = res + record.A.String() + ","
+                       }
+               } else {
+                       log.Print(err)
+               }
+       }
+
+       if rectype == "AAAA" || rectype == "" {
+               m.SetQuestion(target+".", dns.TypeAAAA)
+               r, _, err := c.Exchange(&m, *AuthorityDNS+":53")
+
+               if err == nil {
+                       if len(r.Answer) == 0 {
+                               log.Print(target, ". has no AAAA record")
+                       }
+                       for _, ans := range r.Answer {
+                               record := ans.(*dns.AAAA)
+                               log.Printf("%s. has IPv6 %s", target, record.AAAA)
+                               res = res + record.AAAA.String() + ","
+                       }
+               } else {
+                       log.Print(err)
+               }
+       }
+       return strings.TrimSuffix(res, ",")
+}
+
 func myipHandle(w http.ResponseWriter, r *http.Request) {
        log.Print(r.RemoteAddr, " ", r.Method, " ", r.URL.String())
        clientIP, _, err := net.SplitHostPort(r.RemoteAddr)
@@ -215,6 +262,8 @@ func rootHandle(w http.ResponseWriter, r *http.Request) {
        //check auth
        authok := false
        hosts := ""
+       hostip := (r.URL.Path == "/hostip")
+
        if hdr_auth, ok := r.Header["Authorization"]; ok {
                log.Print("Authorization header present")
                for _, auth := range hdr_auth {
@@ -240,16 +289,31 @@ func rootHandle(w http.ResponseWriter, r *http.Request) {
        log.Print("User hosts: ", hosts)
        //check ip
        q := r.URL.Query()
+
+       myip := "0.0.0.0"
+       ver := 4
+       valid := false
+       myip_count := len(q["myip"])
+       log.Print("myips: ", myip_count)
+       if !hostip {
+               if myip_count == 1 {
+                       myip, ver, valid = checkIP(q["myip"][0]) //one IP to rule them all
+               }
+               log.Printf("IP: %s (valid:%v, ver:%d)", myip, valid, ver)
+               if !valid {
+                       log.Print("StatusBadIP")
+                       io.WriteString(w, StatusBadIP+"\n")
+                       return
+               }
+       }
+       //update or reportip
        hostnames := q["hostname"]
-       myip, ver, valid := checkIP(q["myip"][0]) //one IP to rule them all
-       log.Printf("IP: %s (valid:%v, ver:%d)", myip, valid, ver)
-       if !valid {
-               log.Print("StatusBadIP")
-               io.WriteString(w, StatusBadIP+"\n")
-               return
+       rectype := ""
+       if len(q["rectype"]) == 1 {
+               rectype = q["rectype"][0]
        }
-       //update
        for _, host := range hostnames {
+               log.Print("Host:", host)
                if !isDomainName(host) {
                        log.Print("StatusNotFQHN")
                        io.WriteString(w, StatusNotFQHN+"\n")
@@ -262,14 +326,18 @@ func rootHandle(w http.ResponseWriter, r *http.Request) {
                        continue
                }
                if strings.Contains(hosts, host) {
-                       log.Printf("Updating %s to IP %s", host, myip)
-                       updated := knsupdate(host, myip, zone, ver)
-                       if updated {
-                               log.Print("StatusGood")
-                               io.WriteString(w, StatusGood+"\n")
+                       if !hostip {
+                               log.Printf("Updating %s to IP %s", host, myip)
+                               updated := knsupdate(host, myip, zone, ver)
+                               if updated {
+                                       log.Print("StatusGood")
+                                       io.WriteString(w, StatusGood+"\n")
+                               } else {
+                                       log.Print("StatusBadDay")
+                                       io.WriteString(w, StatusBadDay+"\n")
+                               }
                        } else {
-                               log.Print("StatusBadDay")
-                               io.WriteString(w, StatusBadDay+"\n")
+                               io.WriteString(w, resolveWithAuthority(host, rectype)+"\n")
                        }
                } else {
                        log.Print("StatusBadHost")
@@ -290,6 +358,7 @@ func main() {
        http.HandleFunc("/myip", myipHandle)
        http.HandleFunc("/myip.php", myipHandle)
        http.HandleFunc("/", rootHandle)
+       http.HandleFunc("/hostip", rootHandle)
        logf, err := os.OpenFile(*LogFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
        if nil == err {
                defer logf.Close()