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
|
||||
|
||||
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/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
@ -15,9 +14,28 @@ const (
|
|||
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 {
|
||||
Domain string
|
||||
Password string
|
||||
Setter IPSetter
|
||||
}
|
||||
|
||||
func Config(path string) ([]DomainTuple, error) {
|
||||
|
@ -28,16 +46,21 @@ func Config(path string) ([]DomainTuple, error) {
|
|||
tuples := []DomainTuple{}
|
||||
for _, line := range strings.Split(string(conf), "\n") {
|
||||
line := strings.TrimSpace(line)
|
||||
if !strings.Contains(line, "=") {
|
||||
if !strings.Contains(line, ",") {
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(line, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
parts := strings.SplitN(line, ",", 3)
|
||||
if len(parts) != 3 {
|
||||
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{
|
||||
Domain: parts[0],
|
||||
Password: parts[1],
|
||||
Domain: parts[1],
|
||||
Password: parts[2],
|
||||
Setter: setter,
|
||||
})
|
||||
}
|
||||
return tuples, nil
|
||||
|
@ -60,9 +83,20 @@ func main() {
|
|||
fatal("config", err)
|
||||
for _, cfgEntry := range cfg {
|
||||
fmt.Println(cfgEntry.Domain)
|
||||
err = Set(ip, cfgEntry.Domain, cfgEntry.Password, "*")
|
||||
fatal(cfgEntry.Domain, err)
|
||||
err = Set(ip, cfgEntry.Domain, cfgEntry.Password, "@")
|
||||
err = cfgEntry.Setter.IPSet([]IPSetRequest{
|
||||
{
|
||||
IP: ip,
|
||||
Domain: cfgEntry.Domain,
|
||||
Password: cfgEntry.Password,
|
||||
Host: "*",
|
||||
},
|
||||
{
|
||||
IP: ip,
|
||||
Domain: cfgEntry.Domain,
|
||||
Password: cfgEntry.Password,
|
||||
Host: "@",
|
||||
},
|
||||
})
|
||||
fatal(cfgEntry.Domain, err)
|
||||
}
|
||||
}
|
||||
|
@ -81,27 +115,3 @@ func IP() (string, error) {
|
|||
|
||||
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