package main
import (
+ "bufio"
+ "crypto/md5"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
"net"
"net/http"
- "log"
- "strings"
"os"
"os/exec"
- "io"
- "io/ioutil"
- "bufio"
- "encoding/base64"
- "crypto/md5"
- "fmt"
+ "strings"
)
//TODO add parsing of cmdline
const (
- AccFile = "/usr/local/etc/ddnset/ddnset.acc"
- ZoneFile = "/usr/local/etc/ddnset/ddnset.zon"
- Logfile = "/var/log/ddnset/default.log"
+ AccFile = "/usr/local/etc/ddnset/ddnset.acc"
+ ZoneFile = "/usr/local/etc/ddnset/ddnset.zon"
+ Logfile = "/var/log/ddnset/default.log"
ListenPort = "1980"
)
const (
- StatusGood = "good"
- StatusBadAuth = "badauth"
- StatusBadDay = "911"
- StatusNotFQHN = "notfqdn"
- StatusBadHost = "nohost"
- StatusBadZone = "dnserr" //???
- StatusBadIP = "badip"
+ StatusGood = "good"
+ StatusBadAuth = "badauth"
+ StatusBadDay = "911"
+ StatusNotFQHN = "notfqdn"
+ StatusBadHost = "nohost"
+ StatusBadZone = "dnserr" //???
+ StatusBadIP = "badip"
)
-
-func isPrivate (ip net.IP) bool {
+func isPrivate(ip net.IP) bool {
if ip4 := ip.To4(); ip4 != nil {
- return ( (10 == ip4[0] ) || ( 192 == ip4[0] && 168 == ip4[1] ) || ( 172 == ip4[0] && (ip4[1] >= 16 && ip4[1] <= 31) ))
+ return ((10 == ip4[0]) || (192 == ip4[0] && 168 == ip4[1]) || (172 == ip4[0] && (ip4[1] >= 16 && ip4[1] <= 31)))
}
//TODO what about them new v6 addresses!?
- return false;
+ return false
}
// isDomainName checks if a string is a presentation-format domain name
return ok
}
-func checkIP (s string) (string, int, bool) {
+func checkIP(s string) (string, int, bool) {
valid := true
ipver := 4
//parse the hell out of it
- ip := net.ParseIP (s);
- if nil == ip.To4() { ipver = 6 }
- if isPrivate(ip) { valid = false }
- if !ip.IsGlobalUnicast() { valid = false }
- return ip.String(), ipver, valid;
+ ip := net.ParseIP(s)
+ if nil == ip.To4() {
+ ipver = 6
+ }
+ if isPrivate(ip) {
+ valid = false
+ }
+ if !ip.IsGlobalUnicast() {
+ valid = false
+ }
+ return ip.String(), ipver, valid
}
-func isValidAuth (usr, psw string) (bool, string) {
+func isValidAuth(usr, psw string) (bool, string) {
pwentry := fmt.Sprintf("%s:%x", usr, md5.Sum([]byte(psw)))
- acc,err := os.Open(AccFile)
- if (nil == err){
+ acc, err := os.Open(AccFile)
+ if nil == err {
defer acc.Close()
scanner := bufio.NewScanner(acc)
- for scanner.Scan(){
+ for scanner.Scan() {
line := scanner.Text()
- if (strings.HasPrefix(line, pwentry)) {
+ if strings.HasPrefix(line, pwentry) {
//log.Print ("Irasshai!")
- return true, strings.TrimPrefix (line, pwentry + ":")
+ return true, strings.TrimPrefix(line, pwentry+":")
}
}
}
return false, ""
}
-func isValidZone (h string) (bool, string) {
- zon,err := os.Open(ZoneFile)
- if (nil == err){
+func isValidZone(h string) (bool, string) {
+ zon, err := os.Open(ZoneFile)
+ if nil == err {
defer zon.Close()
scanner := bufio.NewScanner(zon)
- for scanner.Scan(){
+ for scanner.Scan() {
line := scanner.Text()
- if (strings.HasSuffix(h, line)) {
-// log.Printf ("%s is in zone %s", h, line)
+ if strings.HasSuffix(h, line) {
+ // log.Printf ("%s is in zone %s", h, line)
return true, line
}
}
}
-// log.Printf ("No zone for the wicked %s", h)
+ // log.Printf ("No zone for the wicked %s", h)
return false, ""
}
//TODO implement no temp file version
func knsupdate(host, ip, zone string, ver int) bool {
rectype := "A"
- if (6 == ver) { rectype = "AAAA" }
+ if 6 == ver {
+ rectype = "AAAA"
+ }
tmpfile, err := ioutil.TempFile("", "knsupdate")
if err != nil {
log.Print(err)
}
//log.Print ("Using ", tmpfile.Name())
defer os.Remove(tmpfile.Name()) // clean up
- fmt.Fprintf (tmpfile, "server 127.0.0.1\n");
- fmt.Fprintf (tmpfile, "zone %s\n", zone);
- fmt.Fprintf (tmpfile, "del %s 300 IN %s\n", host, rectype);
- fmt.Fprintf (tmpfile, "add %s 300 IN %s %s\n", host, rectype, ip);
- fmt.Fprintf (tmpfile, "send\n");
+ fmt.Fprintf(tmpfile, "server 127.0.0.1\n")
+ fmt.Fprintf(tmpfile, "zone %s\n", zone)
+ fmt.Fprintf(tmpfile, "del %s 300 IN %s\n", host, rectype)
+ fmt.Fprintf(tmpfile, "add %s 300 IN %s %s\n", host, rectype, ip)
+ fmt.Fprintf(tmpfile, "send\n")
tmpfile.Close()
out, err := exec.Command("/usr/bin/knsupdate", tmpfile.Name()).Output()
-
+
if err != nil {
log.Print(err)
return false
}
-
- if (strings.Contains(string(out), "Error")) {
- log.Printf("%q", out);
- return false;
+
+ if strings.Contains(string(out), "Error") {
+ log.Printf("%q", out)
+ return false
}
-
+
return true
}
-
-
-func myipHandle(w http.ResponseWriter, r *http.Request){
- log.Print(r.RemoteAddr, " ", r.Method, " ", r.URL.String());
- clientIP, _, err := net.SplitHostPort(r.RemoteAddr);
+func myipHandle(w http.ResponseWriter, r *http.Request) {
+ log.Print(r.RemoteAddr, " ", r.Method, " ", r.URL.String())
+ clientIP, _, err := net.SplitHostPort(r.RemoteAddr)
//TODO support more proxy headers and
//walk them until first valid address
//fallback to r.RemoteAddr if none are available
- if nil != err { log.Print(err); return ;}
+ if nil != err {
+ log.Print(err)
+ return
+ }
if prior, ok := r.Header["X-Forwarded-For"]; ok {
- log.Print ("XFF header present")
+ log.Print("XFF header present")
clientIP = strings.Split(prior[0], ",")[0]
}
clientIP, _, _ = checkIP(clientIP)
- log.Printf ("Client IP = %s", clientIP);
+ log.Printf("Client IP = %s", clientIP)
io.WriteString(w, clientIP)
}
-func rootHandle(w http.ResponseWriter, r *http.Request){
+func rootHandle(w http.ResponseWriter, r *http.Request) {
- log.Print(r.RemoteAddr, " ", r.Method, " ", r.URL.String());
+ log.Print(r.RemoteAddr, " ", r.Method, " ", r.URL.String())
//check auth
authok := false
hosts := ""
if hdr_auth, ok := r.Header["Authorization"]; ok {
- log.Print ("Authorization header present")
- for _, auth := range (hdr_auth) {
- auth := strings.Split (auth, " ")
- log.Print ("Method: ", auth[0])
- if ("Basic" == auth[0]){
+ log.Print("Authorization header present")
+ for _, auth := range hdr_auth {
+ auth := strings.Split(auth, " ")
+ log.Print("Method: ", auth[0])
+ if "Basic" == auth[0] {
authdec, err := base64.StdEncoding.DecodeString(auth[1])
- if nil != err { continue }
- usrpw := strings.Split (string(authdec), ":")
- log.Printf ("User: %s", usrpw[0]);
+ if nil != err {
+ continue
+ }
+ usrpw := strings.Split(string(authdec), ":")
+ log.Printf("User: %s", usrpw[0])
authok, hosts = isValidAuth(usrpw[0], usrpw[1])
}
}
}
if false == authok {
- log.Print("StatusBadAuth");
- io.WriteString(w, StatusBadAuth + "\n");
- return;
+ log.Print("StatusBadAuth")
+ io.WriteString(w, StatusBadAuth+"\n")
+ return
}
-
- log.Print ("User hosts: ", hosts);
+
+ log.Print("User hosts: ", hosts)
//check ip
q := r.URL.Query()
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;
+ log.Printf("IP: %s (valid:%v, ver:%d)", myip, valid, ver)
+ if !valid {
+ log.Print("StatusBadIP")
+ io.WriteString(w, StatusBadIP+"\n")
+ return
}
//update
- for _, host := range (hostnames) {
+ for _, host := range hostnames {
if !isDomainName(host) {
- log.Print("StatusNotFQHN");
- io.WriteString(w, StatusNotFQHN + "\n");
+ log.Print("StatusNotFQHN")
+ io.WriteString(w, StatusNotFQHN+"\n")
continue
}
vz, zone := isValidZone(host)
if !vz {
- log.Print("StatusBadZone");
- io.WriteString(w, StatusBadZone + "\n");
+ log.Print("StatusBadZone")
+ io.WriteString(w, StatusBadZone+"\n")
continue
}
- if (strings.Contains (hosts, host)) {
- log.Printf ("Updating %s to IP %s", host, myip);
- updated := knsupdate (host, myip, zone, ver)
+ 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");
+ log.Print("StatusGood")
+ io.WriteString(w, StatusGood+"\n")
} else {
- log.Print("StatusBadDay");
- io.WriteString(w, StatusBadDay + "\n");
+ log.Print("StatusBadDay")
+ io.WriteString(w, StatusBadDay+"\n")
}
} else {
- log.Print("StatusBadHost");
- io.WriteString(w, StatusBadHost + "\n");
+ log.Print("StatusBadHost")
+ io.WriteString(w, StatusBadHost+"\n")
}
}
}
func main() {
- http.HandleFunc("/myip", myipHandle);
- http.HandleFunc("/myip.php", myipHandle);
- http.HandleFunc("/", rootHandle);
- logf, err := os.OpenFile(Logfile, os.O_CREATE | os.O_WRONLY | os.O_APPEND, 0644)
- if nil == err{
+ http.HandleFunc("/myip", myipHandle)
+ http.HandleFunc("/myip.php", myipHandle)
+ http.HandleFunc("/", rootHandle)
+ logf, err := os.OpenFile(Logfile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
+ if nil == err {
defer logf.Close()
- log.SetOutput (logf)
+ log.SetOutput(logf)
} else {
- log.Print (err)
+ log.Print(err)
}
- log.Fatal(http.ListenAndServe(":" + ListenPort, nil));
+ log.Fatal(http.ListenAndServe(":"+ListenPort, nil))
}