commit 289a8a57ee57d1fa4091d68a7b6a648a473456d1
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2022-03-13T19:03:34Z |
| subject | Basic Login / Select Domain / Add Record |
commit 289a8a57ee57d1fa4091d68a7b6a648a473456d1
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2022-03-13T19:03:34Z
Basic Login / Select Domain / Add Record
---
freedns/freedns.go | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++
main.go | 5 +-
2 files changed, 211 insertions(+), 4 deletions(-)
diff --git a/freedns/freedns.go b/freedns/freedns.go
new file mode 100755
index 0000000..fd9bdec
--- /dev/null
+++ b/freedns/freedns.go
@@ -0,0 +1,210 @@
+package freedns
+
+import (
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "golang.org/x/net/html"
+)
+
+type FreeDNSOperations interface {
+ Login()
+ SelectDomain()
+ AddRecord()
+}
+
+type FreeDNS struct {
+ AuthCookie *http.Cookie
+ DomainId string
+}
+
+const URI_LOGIN string = "https://freedns.afraid.org/zc.php?step=2"
+const URI_DOMAIN string = "https://freedns.afraid.org/domain/"
+const URI_ADD_RECORD string = "https://freedns.afraid.org/subdomain/save.php?step=2"
+
+// const URI_LOGIN string = "http://127.0.0.1:1234/"
+
+func _HttpRequest(method string, url string, PostData url.Values, ExCookie *http.Cookie) (*http.Response, string, error) {
+ client := http.Client{
+ CheckRedirect: func(req *http.Request, via []*http.Request) error {
+ return http.ErrUseLastResponse
+ },
+ }
+
+ var req *http.Request
+ var err error
+
+ if method == "GET" {
+ req, err = http.NewRequest(method, url, nil)
+ } else if method == "POST" {
+ req, err = http.NewRequest(method, url, strings.NewReader(PostData.Encode()))
+ req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
+ } else {
+ return nil, "", errors.New("Method + \"" + method + "\" is not supported")
+ }
+
+ if err != nil {
+ return nil, "", err
+ }
+
+ if ExCookie != nil {
+ req.AddCookie(ExCookie)
+ }
+
+ resp, err := client.Do(req)
+ if err != nil {
+ return resp, "", err
+ }
+
+ respData, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+
+ if err != nil {
+ return resp, "", err
+ }
+
+ return resp, string(respData), nil
+}
+
+func (dnsObj *FreeDNS) Login(Username string, Password string) error {
+
+ authData := url.Values{}
+ authData.Set("username", Username)
+ authData.Set("password", Password)
+ authData.Set("submit", "Login")
+ authData.Set("action", "auth")
+
+ resp, respString, err := _HttpRequest("POST", URI_LOGIN, authData, nil)
+ if err != nil {
+ return err
+ }
+
+ if strings.Contains(respString, "Invalid UserID/Pass") {
+ return errors.New("Invalid UserID/Pass")
+ }
+
+ for _, cookie := range resp.Cookies() {
+ if cookie.Name == "dns_cookie" {
+ dnsObj.AuthCookie = cookie
+ }
+ }
+
+ return nil
+}
+
+func (dnsObj *FreeDNS) SelectDomain(DomainName string) error {
+ if dnsObj.AuthCookie == nil {
+ return errors.New("Not logged in")
+ }
+
+ resp, respStr, err := _HttpRequest("GET", URI_DOMAIN, nil, dnsObj.AuthCookie)
+ if err != nil {
+ return err
+ }
+
+ if resp.StatusCode == 302 {
+ return errors.New("dns_cookie maybe expired")
+ }
+
+ htmlTokens := html.NewTokenizer(strings.NewReader(respStr))
+
+ inBold := false
+ lookForA := false
+ dnsObj.DomainId = ""
+loop:
+ for {
+ tt := htmlTokens.Next()
+ switch tt {
+ case html.ErrorToken:
+ break loop
+ case html.TextToken:
+ if inBold && strings.TrimSpace(htmlTokens.Token().Data) == DomainName {
+ fmt.Println("Found " + DomainName + ", looking for domain id")
+ lookForA = true
+ }
+ case html.StartTagToken:
+ _t, hasAttr := htmlTokens.TagName()
+ tagName := string(_t)
+ inBold = tagName == "b"
+ if lookForA && tagName == "a" && hasAttr {
+ for {
+ attrKey, attrValue, moreAttr := htmlTokens.TagAttr()
+ _href := string(attrValue)
+ if string(attrKey) == "href" && strings.Contains(_href, "/subdomain/?limit=") {
+ dnsObj.DomainId = strings.TrimLeft(_href, "/subdomain/?limit=")
+ fmt.Printf("Domain id for \"%s\" is %s\n", DomainName, dnsObj.DomainId)
+ break loop
+ }
+ if !moreAttr {
+ break
+ }
+ }
+ }
+ }
+ }
+
+ if dnsObj.DomainId == "" {
+ return errors.New(fmt.Sprintf("Unable to locate domain id for \"%s\" under /domain/ page", DomainName))
+ }
+
+ return nil
+}
+
+func (dnsObj *FreeDNS) AddRecord(RecordType string, Subdomain string, Address string, Wildcard bool, ttl string) error {
+ if dnsObj.DomainId == "" {
+ return errors.New("No domain selected")
+ }
+ recordData := url.Values{}
+ recordData.Set("type", RecordType)
+ recordData.Set("domain_id", dnsObj.DomainId)
+ recordData.Set("subdomain", Subdomain)
+ recordData.Set("address", Address)
+ recordData.Set("send", "Save!")
+ if Wildcard {
+ recordData.Set("wildcard", "1")
+ }
+
+ resp, respStr, err := _HttpRequest("POST", URI_ADD_RECORD, recordData, dnsObj.AuthCookie)
+ if err != nil {
+ return err
+ }
+
+ if resp.StatusCode != 302 {
+
+ // Record already exists, treated as success
+ if strings.Contains(respStr, "already have another already existent") {
+ fmt.Println("Record already exists")
+ return nil
+ }
+
+ htmlTokens := html.NewTokenizer(strings.NewReader(respStr))
+ loop:
+ for {
+ tt := htmlTokens.Next()
+ switch tt {
+ case html.ErrorToken:
+ break loop
+ case html.TextToken:
+ case html.StartTagToken:
+ }
+ }
+
+ return errors.New("Unknown error while submitting record")
+ }
+
+ _Location, err := resp.Location()
+ if err != nil {
+ return err
+ }
+
+ if strings.Contains(_Location.Path, "/zc.php") {
+ fmt.Println("Error on AddRecord: Cookie expired")
+ return errors.New("Cookie exipired")
+ }
+
+ return nil
+}
diff --git a/main.go b/main.go
index 52d8bf1..305aee3 100644
--- a/main.go
+++ b/main.go
@@ -93,9 +93,6 @@ func (c *customDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error {
return err
}
- // TODO: do something more useful with the decoded configuration
- fmt.Printf("Decoded configuration %v", cfg)
-
secretName := cfg.SecretRef
secretObj, err := c.client.CoreV1().Secrets(ch.ResourceNamespace).Get(context.Background(), secretName, metav1.GetOptions{})
if err != nil {
@@ -105,7 +102,7 @@ func (c *customDNSProviderSolver) Present(ch *v1alpha1.ChallengeRequest) error {
username := string(secretObj.Data["username"])
password := string(secretObj.Data["password"])
- fmt.Printf("Domain: %s, Auth: %s %s", cfg.Domain, username, password)
+ fmt.Printf("Domain: %s, Auth: %s %s\n", cfg.Domain, username, password)
// TODO: add code that sets a record in the DNS provider's console
return nil