Skip to content

Commit

Permalink
feat: allow omitting subdomain
Browse files Browse the repository at this point in the history
  • Loading branch information
davidramiro committed Nov 30, 2024
1 parent f04e277 commit a9ee623
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 31 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ Also available as a HomeAssistant addon.
- e.g. `yourdomain.com`
- Replace `{SUBDOMAIN}` with your subdomain or comma separated subdomains
- e.g. `subdomain` or `sudomain1,subdomain2`
- If you just want to use the base domain without subdomain, remove the `&subdomain={SUBDOMAIN}` parameter.
- Enter the full domain in the `Domain Name` field
- e.g. `subdomain.domain.com` (if you use multiple subdomains, just choose any of those)
- or `domain.com` if no subdomain parameter given
- Enter the registrar name in the `Username` field, either `gandi`, `cloudflare` or `porkbun`
- Enter any value in the `Password` field
- Unused, but required by the FritzBox interface
Expand Down
19 changes: 11 additions & 8 deletions internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,12 @@ func (u *UpdateApi) HandleUpdateRequest(c echo.Context) error {

subdomains := strings.Split(request.Subdomains, ",")

count := len(subdomains)

if count == 0 || subdomains[0] == "" {
logger.Error().Err(ErrMissingParameter).Msg(ErrMissingParameter.Error())
return c.String(http.StatusBadRequest, ErrMissingParameter.Error())
if subdomains == nil {
subdomains = []string{""}
}

for i := range subdomains {
logger.Debug().Msgf("handling subdomain %d of %d", i+1, len(subdomains))
logger.Debug().Msgf("handling request %d of %d", i+1, len(subdomains))

service, err := u.dnsServiceFactory.Find(services.Registrar(request.Registrar))
if err != nil {
Expand All @@ -82,9 +79,15 @@ func (u *UpdateApi) HandleUpdateRequest(c echo.Context) error {

}

logger.Info().Int("updates", count).Msg("successfully created")
logger.Info().Int("updates", len(subdomains)).Msg("successfully created")

return c.String(http.StatusOK, fmt.Sprintf("created %d entries for subdomains %s on %s: %s", count, request.Subdomains, request.Domain, request.IP))
return c.String(http.StatusOK,
fmt.Sprintf("created %d entries for subdomains %s on %s: %s",
len(subdomains),
request.Subdomains,
request.Domain,
request.IP),
)
}

func (u *UpdateApi) HandleStatusCheck(c echo.Context) error {
Expand Down
79 changes: 61 additions & 18 deletions services/cloudflare.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ func NewCloudflareDnsUpdateService(client HTTPClient) (*CloudflareDnsUpdateServi
}

type CloudflareApiRequest struct {
Subdomain string `json:"name"`
Type string `json:"type"`
TTL int `json:"ttl"`
IP string `json:"content"`
Name string `json:"name"`
Type string `json:"type"`
TTL int `json:"ttl"`
IP string `json:"content"`
}

type CloudflareQueryResponse struct {
Expand All @@ -67,10 +67,20 @@ func (c *CloudflareDnsUpdateService) UpdateRecord(request *DynDnsRequest) error
endpoint := fmt.Sprintf("%s/zones/%s/dns_records", c.baseUrl,
c.zoneId)

logger := log.With().Str("func", "UpdateRecord").Str("registrar", "cloudflare").Str("endpoint", endpoint).Str("domain", request.Domain).Str("subdomain", request.Subdomain).Logger()
logger := log.With().
Str("func", "UpdateRecord").
Str("registrar", "cloudflare").
Str("endpoint", endpoint).
Str("domain", request.Domain).
Str("subdomain", request.Subdomain).Logger()

logger.Debug().Msg("building update request")

req, err := http.NewRequest("GET", endpoint, nil)
if err != nil {
logger.Error().Err(err).Msg(ErrBuildingRequest.Error())
return ErrBuildingRequest
}

var r CloudflareQueryResponse

Expand All @@ -83,9 +93,13 @@ func (c *CloudflareDnsUpdateService) UpdateRecord(request *DynDnsRequest) error
return ErrBuildingRequest
}

b, _ := io.ReadAll(resp.Body)
err = json.Unmarshal(b, &r)
b, err := io.ReadAll(resp.Body)
if err != nil {
logger.Error().Err(err).Msg(ErrParsingResponse.Error())
return err
}

err = json.Unmarshal(b, &r)
if err != nil {
logger.Error().Err(err).Msg(ErrParsingResponse.Error())
return err
Expand All @@ -101,7 +115,14 @@ func (c *CloudflareDnsUpdateService) UpdateRecord(request *DynDnsRequest) error
if len(r.Errors) == 0 && len(r.Result) > 0 {
logger.Debug().Int("entries", len(r.Result)).Msg("comparing entries with update request")
for _, e := range r.Result {
if e.Name == fmt.Sprintf("%s.%s", request.Subdomain, request.Domain) {
var match string
if request.Subdomain == "" {
match = request.Domain
} else {
match = fmt.Sprintf("%s.%s", request.Subdomain, request.Domain)
}

if e.Name == match {
id = e.Id
}
}
Expand All @@ -117,17 +138,32 @@ func (c *CloudflareDnsUpdateService) UpdateRecord(request *DynDnsRequest) error
}

func (c *CloudflareDnsUpdateService) newRecord(request *DynDnsRequest) error {

var name string
if request.Subdomain != "" {
name = fmt.Sprintf("%s.%s", request.Subdomain, request.Domain)
} else {
name = request.Domain
}

cloudflareRequest := &CloudflareApiRequest{
Subdomain: fmt.Sprintf("%s.%s", request.Subdomain, request.Domain),
IP: request.IP,
TTL: c.ttl,
Type: "A",
Name: name,
IP: request.IP,
TTL: c.ttl,
Type: "A",
}

endpoint := fmt.Sprintf("%s/zones/%s/dns_records", c.baseUrl,
c.zoneId)

logger := log.With().Str("func", "newRecord").Str("registrar", "cloudflare").Str("subdomain", cloudflareRequest.Subdomain).Str("endpoint", endpoint).Str("IP", cloudflareRequest.IP).Logger()
logger := log.With().
Str("func", "newRecord").
Str("registrar", "cloudflare").
Str("fqdn", cloudflareRequest.Name).
Str("endpoint", endpoint).
Str("IP", cloudflareRequest.IP).
Logger()

logger.Debug().Msg("building new record request")

body, err := json.Marshal(cloudflareRequest)
Expand Down Expand Up @@ -164,17 +200,24 @@ func (c *CloudflareDnsUpdateService) newRecord(request *DynDnsRequest) error {
}

func (c *CloudflareDnsUpdateService) editExistingRecord(request *DynDnsRequest, id string) error {
var name string
if request.Subdomain != "" {
name = fmt.Sprintf("%s.%s", request.Subdomain, request.Domain)
} else {
name = request.Domain
}

cloudflareRequest := &CloudflareApiRequest{
Subdomain: fmt.Sprintf("%s.%s", request.Subdomain, request.Domain),
IP: request.IP,
TTL: c.ttl,
Type: "A",
Name: name,
IP: request.IP,
TTL: c.ttl,
Type: "A",
}

endpoint := fmt.Sprintf("%s/zones/%s/dns_records/%s", c.baseUrl,
c.zoneId, id)

logger := log.With().Str("func", "editExistingRecord").Str("registrar", "cloudflare").Str("subdomain", cloudflareRequest.Subdomain).Str("endpoint", endpoint).Str("IP", cloudflareRequest.IP).Logger()
logger := log.With().Str("func", "editExistingRecord").Str("registrar", "cloudflare").Str("subdomain", cloudflareRequest.Name).Str("endpoint", endpoint).Str("IP", cloudflareRequest.IP).Logger()
logger.Info().Msg("building request to edit record")

body, err := json.Marshal(cloudflareRequest)
Expand Down
4 changes: 4 additions & 0 deletions services/gandi.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ type GandiApiRequest struct {

func (g *GandiDnsUpdateService) UpdateRecord(request *DynDnsRequest) error {

if request.Subdomain == "" {
request.Subdomain = "@"
}

gandiRequest := &GandiApiRequest{
Subdomain: request.Subdomain,
IPValues: []string{request.IP},
Expand Down
17 changes: 12 additions & 5 deletions services/porkbun.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func NewPorkbunDnsUpdateService(client HTTPClient) (*PorkbunDnsUpdateService, er
}

type PorkbunApiRequest struct {
Subdomain string `json:"name"`
Name string `json:"name"`
Type string `json:"type"`
TTL int `json:"ttl"`
IP string `json:"content"`
Expand All @@ -61,9 +61,8 @@ type PorkbunQueryResponse struct {
}

func (p *PorkbunDnsUpdateService) UpdateRecord(request *DynDnsRequest) error {

porkbunRequest := &PorkbunApiRequest{
Subdomain: request.Subdomain,
Name: request.Subdomain,
IP: request.IP,
TTL: p.ttl,
Type: "A",
Expand Down Expand Up @@ -128,7 +127,15 @@ func (p *PorkbunDnsUpdateService) queryRecordExists(request *DynDnsRequest, pork
if r.Status == "SUCCESS" && len(r.Records) > 0 {
for _, e := range r.Records {
logger.Info().Msg("record found")
if e.Name == fmt.Sprintf("%s.%s", request.Subdomain, request.Domain) {

var match string
if request.Subdomain == "" {
match = request.Domain
} else {
match = fmt.Sprintf("%s.%s", request.Subdomain, request.Domain)
}

if e.Name == match {
return true, nil
}
}
Expand Down Expand Up @@ -179,7 +186,7 @@ func (p *PorkbunDnsUpdateService) updateRecord(request *DynDnsRequest, porkbunRe
}

func (p *PorkbunDnsUpdateService) executeRequest(endpoint string, porkbunRequest *PorkbunApiRequest) (*http.Response, error) {
logger := log.With().Str("func", "executeRequest").Str("registrar", "porkbun").Str("endpoint", endpoint).Str("subdomain", porkbunRequest.Subdomain).Logger()
logger := log.With().Str("func", "executeRequest").Str("registrar", "porkbun").Str("endpoint", endpoint).Str("subdomain", porkbunRequest.Name).Logger()
logger.Info().Msg("building update request")

body, err := json.Marshal(porkbunRequest)
Expand Down

0 comments on commit a9ee623

Please sign in to comment.