package cloudflare import ( "encoding/json" "fmt" "net/http" "net/url" "strconv" "agent-wdd/log" ) // DNSRecord represents a DNS record in Cloudflare type DNSRecord struct { ID string `json:"id,omitempty"` Name string `json:"name"` Type string `json:"type"` Content string `json:"content"` Priority int `json:"priority,omitempty"` Proxiable bool `json:"proxiable,omitempty"` Proxied bool `json:"proxied"` TTL int `json:"ttl"` Settings map[string]interface{} `json:"settings,omitempty"` Meta map[string]interface{} `json:"meta,omitempty"` Comment string `json:"comment,omitempty"` Tags []string `json:"tags,omitempty"` CreatedOn string `json:"created_on,omitempty"` ModifiedOn string `json:"modified_on,omitempty"` CommentModifiedOn string `json:"comment_modified_on,omitempty"` } // DNSRecordFilter represents filters for listing DNS records type DNSRecordFilter struct { Type string Name string Content string Page int PerPage int Order string Direction string Match string } // ListDNSRecords retrieves all DNS records for a zone // // Parameters: // - zoneID: The zone ID // - filter: Optional filter to apply to the DNS records list // // Returns: // - []DNSRecord: List of DNS records // - error: Any errors that occurred during the request func (c *CloudflareClient) ListDNSRecords(zoneID string, filter *DNSRecordFilter) ([]DNSRecord, error) { log.Debug("Listing DNS records for zone ID: %s with filter: %+v", zoneID, filter) // Build URL and query parameters endpoint := fmt.Sprintf("%s/zones/%s/dns_records", c.baseURL, zoneID) u, err := url.Parse(endpoint) if err != nil { log.Error("Failed to parse URL: %v", err) return nil, fmt.Errorf("failed to parse URL: %w", err) } q := u.Query() if filter != nil { if filter.Type != "" { q.Add("type", filter.Type) } if filter.Name != "" { q.Add("name", filter.Name) } if filter.Content != "" { q.Add("content", filter.Content) } if filter.Page > 0 { q.Add("page", strconv.Itoa(filter.Page)) } if filter.PerPage > 0 { q.Add("per_page", strconv.Itoa(filter.PerPage)) } if filter.Order != "" { q.Add("order", filter.Order) } if filter.Direction != "" { q.Add("direction", filter.Direction) } if filter.Match != "" { q.Add("match", filter.Match) } } u.RawQuery = q.Encode() // Make request resp, err := c.doRequest(http.MethodGet, u.String(), nil) if err != nil { log.Error("Failed to list DNS records: %v", err) return nil, fmt.Errorf("failed to list DNS records: %w", err) } // Parse response var records []DNSRecord result, err := json.Marshal(resp.Result) if err != nil { log.Error("Failed to marshal result: %v", err) return nil, fmt.Errorf("failed to marshal result: %w", err) } if err := json.Unmarshal(result, &records); err != nil { log.Error("Failed to unmarshal DNS records: %v", err) return nil, fmt.Errorf("failed to unmarshal DNS records: %w", err) } log.Info("Successfully retrieved %d DNS records for zone ID: %s", len(records), zoneID) return records, nil } // CreateDNSRecord creates a new DNS record in the specified zone // // Parameters: // - zoneID: The zone ID // - record: The DNS record to create // // Returns: // - *DNSRecord: The created DNS record // - error: Any errors that occurred during the request func (c *CloudflareClient) CreateDNSRecord(zoneID string, record DNSRecord) (*DNSRecord, error) { log.Debug("Creating DNS record in zone ID: %s with data: %+v", zoneID, record) // Build URL endpoint := fmt.Sprintf("%s/zones/%s/dns_records", c.baseURL, zoneID) // Make request resp, err := c.doRequest(http.MethodPost, endpoint, record) if err != nil { log.Error("Failed to create DNS record: %v", err) return nil, fmt.Errorf("failed to create DNS record: %w", err) } // Parse response var createdRecord DNSRecord result, err := json.Marshal(resp.Result) if err != nil { log.Error("Failed to marshal result: %v", err) return nil, fmt.Errorf("failed to marshal result: %w", err) } if err := json.Unmarshal(result, &createdRecord); err != nil { log.Error("Failed to unmarshal created DNS record: %v", err) return nil, fmt.Errorf("failed to unmarshal created DNS record: %w", err) } log.Info("Successfully created DNS record: %s (%s) in zone ID: %s", createdRecord.Name, createdRecord.ID, zoneID) return &createdRecord, nil } // GetDNSRecord retrieves a specific DNS record by ID // // Parameters: // - zoneID: The zone ID // - recordID: The DNS record ID // // Returns: // - *DNSRecord: The DNS record // - error: Any errors that occurred during the request func (c *CloudflareClient) GetDNSRecord(zoneID, recordID string) (*DNSRecord, error) { log.Debug("Getting DNS record ID: %s in zone ID: %s", recordID, zoneID) // Build URL endpoint := fmt.Sprintf("%s/zones/%s/dns_records/%s", c.baseURL, zoneID, recordID) // Make request resp, err := c.doRequest(http.MethodGet, endpoint, nil) if err != nil { log.Error("Failed to get DNS record: %v", err) return nil, fmt.Errorf("failed to get DNS record: %w", err) } // Parse response var record DNSRecord result, err := json.Marshal(resp.Result) if err != nil { log.Error("Failed to marshal result: %v", err) return nil, fmt.Errorf("failed to marshal result: %w", err) } if err := json.Unmarshal(result, &record); err != nil { log.Error("Failed to unmarshal DNS record: %v", err) return nil, fmt.Errorf("failed to unmarshal DNS record: %w", err) } log.Info("Successfully retrieved DNS record: %s (%s) from zone ID: %s", record.Name, record.ID, zoneID) return &record, nil } // UpdateDNSRecord updates an existing DNS record // // Parameters: // - zoneID: The zone ID // - recordID: The DNS record ID // - record: The updated DNS record data // // Returns: // - *DNSRecord: The updated DNS record // - error: Any errors that occurred during the request func (c *CloudflareClient) UpdateDNSRecord(zoneID, recordID string, record DNSRecord) (*DNSRecord, error) { log.Debug("Updating DNS record ID: %s in zone ID: %s with data: %+v", recordID, zoneID, record) // Build URL endpoint := fmt.Sprintf("%s/zones/%s/dns_records/%s", c.baseURL, zoneID, recordID) // Make request resp, err := c.doRequest(http.MethodPut, endpoint, record) if err != nil { log.Error("Failed to update DNS record: %v", err) return nil, fmt.Errorf("failed to update DNS record: %w", err) } // Parse response var updatedRecord DNSRecord result, err := json.Marshal(resp.Result) if err != nil { log.Error("Failed to marshal result: %v", err) return nil, fmt.Errorf("failed to marshal result: %w", err) } if err := json.Unmarshal(result, &updatedRecord); err != nil { log.Error("Failed to unmarshal updated DNS record: %v", err) return nil, fmt.Errorf("failed to unmarshal updated DNS record: %w", err) } log.Info("Successfully updated DNS record: %s (%s) in zone ID: %s", updatedRecord.Name, updatedRecord.ID, zoneID) return &updatedRecord, nil } // DeleteDNSRecord deletes a DNS record // // Parameters: // - zoneID: The zone ID // - recordID: The DNS record ID // // Returns: // - bool: True if the record was deleted successfully // - error: Any errors that occurred during the request func (c *CloudflareClient) DeleteDNSRecord(zoneID, recordID string) (bool, error) { log.Debug("Deleting DNS record ID: %s in zone ID: %s", recordID, zoneID) // Build URL endpoint := fmt.Sprintf("%s/zones/%s/dns_records/%s", c.baseURL, zoneID, recordID) // Make request resp, err := c.doRequest(http.MethodDelete, endpoint, nil) if err != nil { log.Error("Failed to delete DNS record: %v", err) return false, fmt.Errorf("failed to delete DNS record: %w", err) } // Parse response result, ok := resp.Result.(map[string]interface{}) if !ok { log.Error("Unexpected response format for DNS record deletion") return false, fmt.Errorf("unexpected response format for DNS record deletion") } id, ok := result["id"].(string) if !ok { log.Error("Failed to extract ID from deletion response") return false, fmt.Errorf("failed to extract ID from deletion response") } log.Info("Successfully deleted DNS record ID: %s from zone ID: %s", id, zoneID) return true, nil } // FindDNSRecord finds a DNS record by name and type // // Parameters: // - zoneID: The zone ID // - name: The DNS record name // - recordType: The DNS record type (A, AAAA, CNAME, etc.) // // Returns: // - *DNSRecord: The found DNS record, or nil if not found // - error: Any errors that occurred during the request func (c *CloudflareClient) FindDNSRecord(zoneID, name, recordType string) (*DNSRecord, error) { log.Debug("Finding DNS record with name: %s and type: %s in zone ID: %s", name, recordType, zoneID) filter := &DNSRecordFilter{ Name: name, Type: recordType, } records, err := c.ListDNSRecords(zoneID, filter) if err != nil { return nil, err } if len(records) == 0 { log.Warning("No DNS record found with name: %s and type: %s in zone ID: %s", name, recordType, zoneID) return nil, nil } log.Info("Found DNS record: %s (%s) with type: %s in zone ID: %s", records[0].Name, records[0].ID, records[0].Type, zoneID) return &records[0], nil }