From c44a18acb3fd0911d98615cfb99ba51cda8df09f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20B=C3=B6hm?= Date: Sat, 12 Jul 2014 22:37:00 +0200 Subject: [PATCH] Added first working web interface version --- .gitignore | 5 ++ connection/connection.go | 82 +++++++++++++++++++++++++++++++++ ddns.go | 99 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 connection/connection.go create mode 100644 ddns.go diff --git a/.gitignore b/.gitignore index 51cbe85..cfc3dc3 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,8 @@ coverage.xml # Sphinx documentation docs/_build/ +*.swp +pdns.conf +pdns_backend.py +ddns +dump.rdb diff --git a/connection/connection.go b/connection/connection.go new file mode 100644 index 0000000..0fe0af4 --- /dev/null +++ b/connection/connection.go @@ -0,0 +1,82 @@ +package connection + +import ( + "crypto/sha1" + "fmt" + "github.com/garyburd/redigo/redis" + "log" + "time" + "strings" +) + +const HostExpirationSeconds int = 10 * 24 * 60 * 60 // 10 Days + +func HandleErr(err error) { + if err != nil { + log.Fatal(err) + } +} + +func OpenConnection() *RedisConnection { + conn, conn_err := redis.Dial("tcp", ":6379") + if conn_err != nil { + log.Fatal(conn_err) + } + + return &RedisConnection{conn} +} + +type RedisConnection struct { + redis.Conn +} + +func (self *RedisConnection) GetHost(name string) *Host { + host := Host{Hostname: name} + + if self.HostExist(name) { + data, err := redis.Values(self.Do("HGETALL", host.Hostname)) + HandleErr(err) + + HandleErr(redis.ScanStruct(data, &host)) + } + + return &host +} + +func (self *RedisConnection) SaveHost(host *Host) { + _, err := self.Do("HMSET", redis.Args{}.Add(host.Hostname).AddFlat(host)...) + HandleErr(err) + + _, err = self.Do("EXPIRE", host.Hostname, HostExpirationSeconds) + HandleErr(err) +} + +func (self *RedisConnection) HostExist(name string) bool { + exists, err := redis.Bool(self.Do("EXISTS", name)) + HandleErr(err) + + return exists +} + +type Host struct { + Hostname string `redis:"-"` + Ip string `redis:"ip"` + Token string `redis:"token"` +} + +func (self *Host) GenerateAndSetToken() { + hash := sha1.New() + hash.Write([]byte(fmt.Sprintf("%d", time.Now().UnixNano()))) + hash.Write([]byte(self.Hostname)) + + self.Token = fmt.Sprintf("%x", hash.Sum(nil)) +} + +// Returns true when this host has a IPv4 Address and false if IPv6 +func (self *Host) IsIPv4() bool { + if strings.Contains(self.Ip, ".") { + return true + } + + return False +} diff --git a/ddns.go b/ddns.go new file mode 100644 index 0000000..dedbe5c --- /dev/null +++ b/ddns.go @@ -0,0 +1,99 @@ +package main + +import ( + "fmt" + "github.com/gin-gonic/gin" + "github.com/pboehm/ddns/connection" + "log" + "net" + "os" +) + +func HandleErr(err error) { + if err != nil { + log.Fatal(err) + } +} + +func RunBackend() { + /* code */ +} + +func RunWebService() { + conn := connection.OpenConnection() + defer conn.Close() + + r := gin.Default() + r.GET("/new/:hostname", func(c *gin.Context) { + hostname := c.Params.ByName("hostname") + + if conn.HostExist(hostname) { + c.String(403, "This hostname has already been registered.") + return + } + + host := &connection.Host{Hostname: hostname, Ip: "127.0.0.1"} + host.GenerateAndSetToken() + + conn.SaveHost(host) + + c.String(200, fmt.Sprintf( + "Go to /update/%s/%s for updating your IP address", + host.Hostname, host.Token)) + }) + + r.GET("/update/:hostname/:token", func(c *gin.Context) { + hostname := c.Params.ByName("hostname") + token := c.Params.ByName("token") + + if !conn.HostExist(hostname) { + c.String(404, + "This hostname has not been registered or is expired.") + return + } + + host := conn.GetHost(hostname) + + if host.Token != token { + c.String(403, + "You have supplied the wrong token to manipulate this host") + return + } + + ip, _, err := net.SplitHostPort(c.Req.RemoteAddr) + if err != nil { + c.String(500, "You sender IP address is not in the right format") + } + + host.Ip = ip + conn.SaveHost(host) + + c.String(200, fmt.Sprintf("Your current IP is %s", ip)) + }) + + r.Run(":8080") +} + +func main() { + + if len(os.Args) < 2 { + usage() + } + + cmd := os.Args[1] + + switch cmd { + case "backend": + log.Printf("Starting PDNS Backend\n") + RunBackend() + case "web": + log.Printf("Starting Web Service\n") + RunWebService() + default: + usage() + } +} + +func usage() { + log.Fatal("Usage: ./ddns [backend|web]") +}