-
-
Notifications
You must be signed in to change notification settings - Fork 159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provider Porkbun: Delete Default Parked DNS Entry for *.domain.tld #774
base: master
Are you sure you want to change the base?
Provider Porkbun: Delete Default Parked DNS Entry for *.domain.tld #774
Conversation
a76b6a3
to
e30c143
Compare
As commented elsewhere, probably should scrap this and just move the logic higher in the program. i.e. on a failed check, after 5 minutes re-check if the domain is in-fact wrong and needs updating still. Though, this would get into a scenario where ostensibly you might be failing to update 1 provider, but another provider has the correct DNS, and so it obfuscates the error. |
e30c143
to
f678492
Compare
I'm having the 400 error problem, but the problem is not resolved by restarting the container with:
The Here is my
|
I think #485 would solve it, and we can log a warning if that period is less than the ttl of the record. I will mark it as 🚨 urgent, but will hold off a few days to start working on it (got other issues to attend to!)
One more reason we need a period per setting to clarify/simplify all this 😄 @Bananas-Are-Yellow First of all bananas can be brown and black too 🍌 !
That's odd, @bentemple any idea why that could be? @Bananas-Are-Yellow can you share your logs, running the container with
It's not, the program resolves the domain name (abc.domain.com) every period and compares it to your public ip address. updates.json is only used to store changes for the web ui AND is used by cloudflare when |
It looks like I misunderstood how
For me, "restarting the DDNS-Updater service after the domain has successfully propogated", makes no difference. But the main issue is certainly true:
That's what I see too. |
We may end up merging this, since there is also another person with the same problem on Porkbun. But I would ideally like to understand the root cause of this since it may apply to other registrars. I'm also wondering if this is specific to porkbun being slow at propagating updates 🤔 since I have not seen similar issues for other registrars. |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as off-topic.
This comment was marked as off-topic.
I wonder if it actually makes sense to update the logic to:
Ultimately, we want to create the A / AAAA entries if none exist, but we really only want to be messing with CNAME and ALIAS conflicts if they're expected values. Just need to queue the user in better to the reason for the failure, and sadly the porkbun API generates worthless error messages. "400, something went wrong" |
TLDR: let's do your version! Longer story: |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
sounds good. I'll update it accordingly. Sorry went to Defcon this last week so just busy life. |
This comment was marked as off-topic.
This comment was marked as off-topic.
No pressure at all, the existing version already works more or less fine 😉 Ps: I saved that picture 😄 |
8e8c50e
to
bf424f7
Compare
5a4fbdf
to
81875b6
Compare
59ff9c0
to
8a11f19
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
A few comments, many nits (apologies) and a few important changes to make (without the nit
prefix 😄). Feel free to skip nit
s if you want.
I took a pass at deleting the I kept that separate as it's own commit, so it's both easy to see the change, and we can trivially revert it if it's not the direction you were thinking. Side-note: I really appreciate all the nits. Code homogeneity is really important, and nits are a really great way to level up code quality (imo) so thank you for taking the time! |
b91e9c1
to
afeb6bb
Compare
} | ||
defer response.Body.Close() | ||
|
||
if response.StatusCode != http.StatusOK { | ||
return nil, fmt.Errorf("%w: %d: %s", errors.ErrHTTPStatusNotValid, | ||
return nil, fmt.Errorf("%s - %w: %d: %s", recordType, errors.ErrHTTPStatusNotValid, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't entirely sure the best way to format these error messages to include the recordType. I welcome any input (always)
I thought about just leaving them alone, but given how abysmal the error messages are that Porkbun returns, thought it would be better to keep it everywhere possible to provide the most context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed! And, although repetitive, it feels logical to wrap the recordType (and owner) within the function instead of by the caller I would say with the code as is.
However, I managed to refactor the code to use a generic function
func httpPost[T any](ctx context.Context, client *http.Client,
url string, requestData any, decodeBody bool) (responseData T, err error)
to remove a lot of the repetition (in terms of raw http client code and error wrappings), and now the error wrapping gets done at the caller level, for example:
responseData, err := httpPost[jsonResponseData](ctx, client, url, postRecordsParams, decodeBody)
if err != nil {
return nil, fmt.Errorf("for record type %s and record owner %s: %w",
recordType, owner, err)
}
e617e37
to
8e9e23e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the re-work! And sorry for the 3 weeks delay, but I'm more or less back on the keyboard now. 😉
} | ||
defer response.Body.Close() | ||
|
||
if response.StatusCode != http.StatusOK { | ||
return nil, fmt.Errorf("%w: %d: %s", errors.ErrHTTPStatusNotValid, | ||
return nil, fmt.Errorf("%s - %w: %d: %s", recordType, errors.ErrHTTPStatusNotValid, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed! And, although repetitive, it feels logical to wrap the recordType (and owner) within the function instead of by the caller I would say with the code as is.
However, I managed to refactor the code to use a generic function
func httpPost[T any](ctx context.Context, client *http.Client,
url string, requestData any, decodeBody bool) (responseData T, err error)
to remove a lot of the repetition (in terms of raw http client code and error wrappings), and now the error wrapping gets done at the caller level, for example:
responseData, err := httpPost[jsonResponseData](ctx, client, url, postRecordsParams, decodeBody)
if err != nil {
return nil, fmt.Errorf("for record type %s and record owner %s: %w",
recordType, owner, err)
}
err = p.createRecord(ctx, client, recordType, ipStr) | ||
if err != nil { | ||
return netip.Addr{}, fmt.Errorf("creating record: %w", err) | ||
if len(records) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted to len(recordIDs) == 0
given the new function deleteDefaultConflictingRecordsIfNeeded
not taking as many lines in the if block 😉 (to have less deltas)
// For new domains, Porkbun Creates 2 Default DNS Records which point to their "parked" domain page: | ||
// ALIAS domain.tld -> pixie.porkbun.com | ||
// CNAME *.domain.tld -> pixie.porkbun.com | ||
// ALIAS and CNAME records conflict with A and AAAA records, and attempting to create an A or AAAA record | ||
// will return a 400 error if they aren't first deleted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resumed the comment with
// deleteDefaultConflictingRecordsIfNeeded deletes any default records that would conflict with a new record,
// see https://github.com/qdm12/ddns-updater/blob/master/docs/porkbun.md#record-creation
// CNAME *.domain.tld -> pixie.porkbun.com | ||
// ALIAS and CNAME records conflict with A and AAAA records, and attempting to create an A or AAAA record | ||
// will return a 400 error if they aren't first deleted. | ||
porkbunParkedDomain := "pixie.porkbun.com" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed this to
const porkbunParkedDomain = "pixie.porkbun.com"
because constants are always nicer if possible 😉
// ALIAS and CNAME records conflict with A and AAAA records, and attempting to create an A or AAAA record | ||
// will return a 400 error if they aren't first deleted. | ||
porkbunParkedDomain := "pixie.porkbun.com" | ||
switch { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed to switch p.owner {
directly
// Delete ALIAS domain.tld -> pixie.porkbun.com record | ||
err = p.deleteSingleMatchingRecord(ctx, client, constants.ALIAS, "@", porkbunParkedDomain) | ||
if err != nil { | ||
return netip.Addr{}, fmt.Errorf("deleting default parked domain record: %w", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed error wrapping to
fmt.Errorf("deleting default ALIAS @ parked domain record: %w", err)
// Error is ignored as the ALIAS could be set to something besides the parked domain. Failure here is non-fatal. | ||
_ = p.deleteSingleMatchingRecord(ctx, client, constants.ALIAS, "@", porkbunParkedDomain) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eh it should be a fatal error if we get an API error for example, so I changed it to
err = p.deleteSingleMatchingRecord(ctx, client, constants.ALIAS, "@", porkbunParkedDomain)
if err != nil && !stderrors.Is(err, errors.ErrConflictingRecord) {
// allow conflict ALIAS records to be set to something besides the parked domain
return fmt.Errorf("deleting default ALIAS @ parked domain record: %w", err)
}
55223ba
to
e94838b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I allowed myself to push that generic http post function refactor commit to the master branch at 8c1b3e5 in order to only have relevant deltas in this PR, and then rebased your branch on the master branch resolving conflicts. I also pushed 2 small-ish commits on top of your commits.
Please review the code and perhaps test the program to double check it works fine (even basic update should do the test trick), and then I'm happy to merge it 😉
Description: By default, Porkbun creates default ALIAS and CNAME domain records pointing to `pixie.porkbun.com` (Porkbun's parked domain website) The current logic flow prior to this PR would look for an A or AAAA domain record, and if none exists, attempt to delete the ALIAS record for any subdomain. This updates the logic flow to only look for a conflicting ALIAS record for the top level `domain.tld`, and a conflicting CNAME record for the `*.domain.tld`. Additionally, we verify that the content of this record matches `pixie.porkbun.com` and we only delete for the expected default values. If the value does not match the expected `pixie.porkbun.com` we produce more helpful error messages. Note: Any other domain name we simply attempt to create a record if no record exists, which will return a 400 error with no helpful error reason if there is a conflicting record of another type. We may want to consider checking for any conflicting records to produce a more helpful error for the user, but that change is well outside of the scope of this PR, and should likely be done in a more general way and apply to all DNS providers, rather than porkbun exclusively. Test-Plan: Created a new domain.tld on Porkbun Verified the default records were created: `ALIAS domain.tld -> pixie.porkbun.com` `CNAME *.domain.tld -> pixie.porkbun.com` Started DDNS-Updater Verified that both domain records were successfully deleted and updated Reset the ALIAS domain record to point to `not-pixie.porkbun.com` Reset the CNAME domain record to point to `not-pixie.porkbun.com` Started DDNS-Updater Verified that both domain records failed with the expected conflicting record error message. ![screenshot_2024-08-17-0210 20](https://github.com/user-attachments/assets/eb567401-ad4b-454d-a7aa-70ab1db1e3e9)
Imorting suggested changes. More fixes to come to address remaining comments. Co-authored-by: Quentin McGaw <[email protected]>
Fix lint, again. :rip: Remove href to https://pixie.porkbun.com/ since that url doesn't actually load and caused the tests to fail
- add `deleteDefaultConflictingRecordsIfNeeded` method - handle non conflicting errors from `deleteSingleMatchingRecord` - simplify comments by linking to documentation - improve error wrappings
e94838b
to
2827fd4
Compare
Description:
Porkbun creates default ALIAS and CNAME domain records pointing to
pixie.porkbun.com
(Porkbun's parked domain website)The current logic flow prior to this PR would look for an A or AAAA domain record, and if none exists, attempt to delete the ALIAS record for any subdomain and then proceed with the record creation.
This updates the logic flow to only look for a conflicting ALIAS record for the top level
domain.tld
, and a conflicting CNAME record for the*.domain.tld
. Additionally, we verify that the content of this record matchespixie.porkbun.com
and we only delete for the expected default value.If the value does not match the expected
pixie.porkbun.com
we produce more helpful error messages.Note: Any other domain name we simply attempt to create a record if no record exists, which will return a 400 error with no helpful error reason if there is a conflicting record of another type. We may want to consider checking for any conflicting records to produce a more helpful error for the user, but that change is well outside of the scope of this PR, and should likely be done in a more general way and apply to all DNS providers, rather than porkbun exclusively.
Test-Plan:
Created a new domain.tld on Porkbun
Verified the default records were created:
ALIAS domain.tld -> pixie.porkbun.com
CNAME *.domain.tld -> pixie.porkbun.com
Started DDNS-Updater
Verified that both domain records were successfully deleted and updated
Reset the ALIAS domain record to point to
not-pixie.porkbun.com
Reset the CNAME domain record to point to
not-pixie.porkbun.com
Started DDNS-Updater
Verified that both domain records failed with the expected conflicting record error message.