Initial commit

This commit is contained in:
2022-08-05 23:44:21 +02:00
commit aa7a98f984
7 changed files with 458 additions and 0 deletions

37
cmd/qddns-client/main.go Normal file
View File

@@ -0,0 +1,37 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"github.com/thequux/pdns-auto-update/common"
"io/ioutil"
"net/http"
"os"
"strings"
)
var server = flag.String("server", "https://dyn.thequux.com", "The URL of the DDNS server")
var domain = flag.String("domain", "", "The domain to update")
var token = flag.String("token", "", "The authorization token")
func main() {
req, err := http.NewRequest("POST", *server+"/update/"+*domain, strings.NewReader(""))
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create request: %v", err)
os.Exit(1)
}
req.Header["Authorization"] = []string{"bearer " + *token}
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Fprintf(os.Stdout, "Failed to send request: %v", err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to read response")
}
rj := common.Response{}
json.Unmarshal(body, &rj)
fmt.Printf("%v\n", rj)
}

97
cmd/qddns-server/main.go Normal file
View File

@@ -0,0 +1,97 @@
package main
import (
"context"
"fmt"
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/thequux/pdns-auto-update/common"
_ "go.uber.org/zap"
"net"
"net/http"
"os"
"strings"
)
var db *pgxpool.Pool
func main() {
conn, err := pgxpool.Connect(context.Background(), os.Getenv("QDDNS_DB"))
if err != nil {
fmt.Fprintf(os.Stderr, "Unabled to connect to database: %v")
os.Exit(1)
}
defer conn.Close()
db = conn
// Set up server
r := gin.Default()
r.POST("/update/:domain", func(c *gin.Context) {
authHdr := strings.Fields(c.GetHeader("Authorization"))
domain := c.Param("domain");
clientIP := c.ClientIP()
ip := net.ParseIP(clientIP)
var token string
if len(authHdr) == 0 || authHdr[0] != "bearer" {
// we have a token; check if it's valid for domain
token = authHdr[1]
} else {
c.JSON(http.StatusUnauthorized, common.Response{Status: "error", Message: "Missing bearer token", Code: "QDA0001"})
return
}
if ip == nil {
c.JSON(http.StatusBadRequest, common.Response{Status: "error", Message: "Unable to determine client IP (got " + clientIP + ")", Code: "QDE0003"})
return
}
// get a connection
tx, err := db.Begin(c)
defer tx.Rollback(c)
if err != nil {
c.JSON(http.StatusInternalServerError, common.Response{Status: "error", Message: "Failed to access database", Code: "QDE0001"})
return
}
// check token validity
row := tx.QueryRow(c, "SELECT COUNT(*) from qddns_auth WHERE token = $1 AND domain = $2", token, domain);
var rcount int
if err := row.Scan(&rcount); err != nil {
c.JSON(http.StatusInternalServerError, common.Response{Status: "error", Message: "Failed to check token " + err.Error(), Code: "QDE0002"})
return
} else if rcount < 1 {
c.JSON(http.StatusUnauthorized, common.Response{Status: "error", Message: "Not authorized for domain " + domain, Code: "QDA0002"})
return
}
// Identify the type of address
var recordType string
if ip.To4() == nil {
recordType = "AAAA"
clientIP = ip.To16().String()
} else {
recordType = "A"
clientIP = ip.To4().String()
}
// Do the update
tag, err := tx.Exec(c, "UPDATE records SET content = $1 WHERE domain = $2 AND type = $3", clientIP, domain, recordType)
if err != nil {
c.JSON(http.StatusInternalServerError, common.Response{
Status: "error",
Message: "Failed to update record: " + err.Error(),
Code: "QDD0001",
})
return
}
if tag.RowsAffected() != 1 {
c.JSON(http.StatusInternalServerError, common.Response{
Status: "error",
Message: "Wrong number of rows affected: " + string(tag.RowsAffected()),
})
return
}
tx.Commit(c)
})
}