added gandi support
This commit is contained in:
parent
daf7f88148
commit
7fd7334ee7
|
@ -0,0 +1,64 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/go-gandi/go-gandi"
|
||||||
|
"github.com/go-gandi/go-gandi/config"
|
||||||
|
"github.com/go-gandi/go-gandi/livedns"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
gandiEmailRecords = []livedns.DomainRecord{
|
||||||
|
{
|
||||||
|
RrsetType: "MX",
|
||||||
|
RrsetTTL: 10800,
|
||||||
|
RrsetName: "@",
|
||||||
|
RrsetValues: []string{"10 spool.mail.gandi.net.", "50 fb.mail.gandi.net."},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RrsetType: "TXT",
|
||||||
|
RrsetTTL: 10800,
|
||||||
|
RrsetName: "@",
|
||||||
|
RrsetValues: []string{`"v=spf1 include:_mailcust.gandi.net ?all"`},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type Gandi struct{}
|
||||||
|
|
||||||
|
func (g Gandi) IPSet(reqs []IPSetRequest) error {
|
||||||
|
if len(reqs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := g.EnsureAllDomainsAreSame(reqs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pwd := reqs[0].Password
|
||||||
|
domain := reqs[0].Domain
|
||||||
|
records := make([]livedns.DomainRecord, len(reqs))
|
||||||
|
for index, req := range reqs {
|
||||||
|
records[index] = livedns.DomainRecord{
|
||||||
|
RrsetType: "A",
|
||||||
|
RrsetTTL: 300,
|
||||||
|
RrsetName: req.Host,
|
||||||
|
RrsetValues: []string{req.IP},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
records = append(records, gandiEmailRecords...)
|
||||||
|
|
||||||
|
_, err := gandi.NewLiveDNSClient(config.Config{
|
||||||
|
APIKey: pwd,
|
||||||
|
}).UpdateDomainRecords(domain, records)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Gandi) EnsureAllDomainsAreSame(reqs []IPSetRequest) error {
|
||||||
|
first := reqs[0].Domain
|
||||||
|
for _, dom := range reqs {
|
||||||
|
if first != dom.Domain {
|
||||||
|
return fmt.Errorf("domain mismatch: %s != %s", first, dom.Domain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
6
go.mod
6
go.mod
|
@ -1,3 +1,9 @@
|
||||||
module ncddns
|
module ncddns
|
||||||
|
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-gandi/go-gandi v0.4.0 // indirect
|
||||||
|
github.com/peterhellberg/link v1.1.0 // indirect
|
||||||
|
moul.io/http2curl v1.0.0 // indirect
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
github.com/go-gandi/go-gandi v0.4.0 h1:iFVD+x3nJrI611fYvVMk6TKOlUOND/bKnvdQxuZKPSI=
|
||||||
|
github.com/go-gandi/go-gandi v0.4.0/go.mod h1:9NoYyfWCjFosClPiWjkbbRK5UViaZ4ctpT8/pKSSFlw=
|
||||||
|
github.com/peterhellberg/link v1.1.0 h1:s2+RH8EGuI/mI4QwrWGSYQCRz7uNgip9BaM04HKu5kc=
|
||||||
|
github.com/peterhellberg/link v1.1.0/go.mod h1:gtSlOT4jmkY8P47hbTc8PTgiDDWpdPbFYl75keYyBB8=
|
||||||
|
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
||||||
|
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
76
main.go
76
main.go
|
@ -6,7 +6,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -15,9 +14,28 @@ const (
|
||||||
baseURL = "https://dynamicdns.park-your-domain.com/update?"
|
baseURL = "https://dynamicdns.park-your-domain.com/update?"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
byName = map[string]IPSetter{
|
||||||
|
"namecheap": NameCheap{},
|
||||||
|
"gandi": Gandi{},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type IPSetRequest struct {
|
||||||
|
IP string
|
||||||
|
Domain string
|
||||||
|
Password string
|
||||||
|
Host string
|
||||||
|
}
|
||||||
|
|
||||||
|
type IPSetter interface {
|
||||||
|
IPSet([]IPSetRequest) error
|
||||||
|
}
|
||||||
|
|
||||||
type DomainTuple struct {
|
type DomainTuple struct {
|
||||||
Domain string
|
Domain string
|
||||||
Password string
|
Password string
|
||||||
|
Setter IPSetter
|
||||||
}
|
}
|
||||||
|
|
||||||
func Config(path string) ([]DomainTuple, error) {
|
func Config(path string) ([]DomainTuple, error) {
|
||||||
|
@ -28,16 +46,21 @@ func Config(path string) ([]DomainTuple, error) {
|
||||||
tuples := []DomainTuple{}
|
tuples := []DomainTuple{}
|
||||||
for _, line := range strings.Split(string(conf), "\n") {
|
for _, line := range strings.Split(string(conf), "\n") {
|
||||||
line := strings.TrimSpace(line)
|
line := strings.TrimSpace(line)
|
||||||
if !strings.Contains(line, "=") {
|
if !strings.Contains(line, ",") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
parts := strings.SplitN(line, "=", 2)
|
parts := strings.SplitN(line, ",", 3)
|
||||||
if len(parts) != 2 {
|
if len(parts) != 3 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
setter, ok := byName[parts[0]]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("line [%s] has unsupported provider [%s]", line, parts[0])
|
||||||
|
}
|
||||||
tuples = append(tuples, DomainTuple{
|
tuples = append(tuples, DomainTuple{
|
||||||
Domain: parts[0],
|
Domain: parts[1],
|
||||||
Password: parts[1],
|
Password: parts[2],
|
||||||
|
Setter: setter,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return tuples, nil
|
return tuples, nil
|
||||||
|
@ -60,9 +83,20 @@ func main() {
|
||||||
fatal("config", err)
|
fatal("config", err)
|
||||||
for _, cfgEntry := range cfg {
|
for _, cfgEntry := range cfg {
|
||||||
fmt.Println(cfgEntry.Domain)
|
fmt.Println(cfgEntry.Domain)
|
||||||
err = Set(ip, cfgEntry.Domain, cfgEntry.Password, "*")
|
err = cfgEntry.Setter.IPSet([]IPSetRequest{
|
||||||
fatal(cfgEntry.Domain, err)
|
{
|
||||||
err = Set(ip, cfgEntry.Domain, cfgEntry.Password, "@")
|
IP: ip,
|
||||||
|
Domain: cfgEntry.Domain,
|
||||||
|
Password: cfgEntry.Password,
|
||||||
|
Host: "*",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
IP: ip,
|
||||||
|
Domain: cfgEntry.Domain,
|
||||||
|
Password: cfgEntry.Password,
|
||||||
|
Host: "@",
|
||||||
|
},
|
||||||
|
})
|
||||||
fatal(cfgEntry.Domain, err)
|
fatal(cfgEntry.Domain, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,27 +115,3 @@ func IP() (string, error) {
|
||||||
|
|
||||||
return string(body), nil
|
return string(body), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Set(ip, domain, password, host string) error {
|
|
||||||
params := url.Values{}
|
|
||||||
params.Add("host", host)
|
|
||||||
params.Add("domain", domain)
|
|
||||||
params.Add("password", password)
|
|
||||||
params.Add("ip", ip)
|
|
||||||
|
|
||||||
resp, err := http.Get(fmt.Sprintf("%s%s", baseURL, params.Encode()))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("request: %w", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
data, err := io.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("read body: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
fmt.Fprintf(os.Stderr, "got status [%d]: %s\n", resp.StatusCode, string(data))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NameCheap struct{}
|
||||||
|
|
||||||
|
func (nc NameCheap) IPSet(reqs []IPSetRequest) error {
|
||||||
|
for _, req := range reqs {
|
||||||
|
if err := nc.SetSingle(req); err != nil {
|
||||||
|
return fmt.Errorf("%s: %w", req.Domain, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (NameCheap) SetSingle(req IPSetRequest) error {
|
||||||
|
params := url.Values{}
|
||||||
|
params.Add("host", req.Host)
|
||||||
|
params.Add("domain", req.Domain)
|
||||||
|
params.Add("password", req.Password)
|
||||||
|
params.Add("ip", req.IP)
|
||||||
|
|
||||||
|
resp, err := http.Get(fmt.Sprintf("%s%s", baseURL, params.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("request: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
data, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("read body: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
fmt.Fprintf(os.Stderr, "got status [%d]: %s\n", resp.StatusCode, string(data))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue