700 lines
19 KiB
Go
700 lines
19 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
type (
|
|
// JSONArray is an array of JSONInput
|
|
JSONArray []*JSONInput
|
|
|
|
// JSONRPCResponse is a jsonRPC response structure
|
|
JSONRPCResponse struct {
|
|
ID int `json:"id"`
|
|
JSONRPC string `json:"jsonrpc"`
|
|
Result []*JSONRPCResult `json:"result"`
|
|
}
|
|
// JSONRPCError is a jsonRPC error structure
|
|
JSONRPCError struct {
|
|
ID int `json:"id"`
|
|
JSONRPC string `json:"jsonrpc"`
|
|
Error struct {
|
|
Code int `json:"code"`
|
|
Message string `json:"message"`
|
|
} `json:"error"`
|
|
}
|
|
|
|
// JSONInput is a json rpc 2.0 compatible structure for the PDNS API
|
|
JSONInput struct {
|
|
Method string `json:"method"`
|
|
Params JSONInputParams `json:"params"`
|
|
ID int `json:"id"`
|
|
ignoreBadDomain bool
|
|
user string
|
|
listFilters []*regexp.Regexp
|
|
}
|
|
// JSONInputParams encode the parameters of the method
|
|
JSONInputParams struct {
|
|
Name string `json:"name"`
|
|
Value string `json:"value"`
|
|
TTL int `json:"ttl"`
|
|
ForceReverse bool `json:"reverse"`
|
|
Append bool `json:"append"`
|
|
Priority int `json:"priority"`
|
|
Comment string `json:"comment"`
|
|
DryRun bool `json:"dry-run"`
|
|
IgnoreError bool `json:"ignore-error"`
|
|
Nonce string `json:"nonce"`
|
|
}
|
|
// JSONRPCResult is the type of the response of the API
|
|
JSONRPCResult struct {
|
|
Changes string `json:"changes"`
|
|
Comment string `json:"comment"`
|
|
Result string `json:"result"`
|
|
Raw []interface{} `json:"raw"`
|
|
Error string `json:"error"`
|
|
}
|
|
)
|
|
|
|
// JSONRPCResult creates new result
|
|
func (j JSONInput) JSONRPCResult(content, comment string, err error) *JSONRPCResult {
|
|
ret := &JSONRPCResult{
|
|
Changes: content,
|
|
Comment: comment,
|
|
Raw: []interface{}{},
|
|
}
|
|
if err != nil {
|
|
ret.Comment = "There was an error"
|
|
ret.Error = err.Error()
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// IsError returns if this response is an error or not
|
|
func (r *JSONRPCResult) IsError() bool {
|
|
return len(r.Error) > 0
|
|
}
|
|
|
|
// JSONInput try to convert back a JSONInput to the original command line
|
|
func (j JSONInput) String() string {
|
|
ret := ""
|
|
if j.Params.TTL != 172800 || j.Method == "ttl" {
|
|
ret += fmt.Sprintf("-t %d ", j.Params.TTL)
|
|
}
|
|
if j.Params.ForceReverse {
|
|
ret += "-f "
|
|
}
|
|
if j.Params.Append {
|
|
ret += "-a "
|
|
}
|
|
if j.Method == "mx" {
|
|
ret += fmt.Sprintf("-p %d ", j.Params.Priority)
|
|
}
|
|
if len(j.Params.Comment) > 0 {
|
|
ret += fmt.Sprintf("-c \"%s\" ", j.Params.Comment)
|
|
}
|
|
if j.Params.DryRun {
|
|
ret += "-n "
|
|
}
|
|
return fmt.Sprintf("%s %s %s %s", ret, j.Method, j.Params.Name, j.Params.Value)
|
|
}
|
|
|
|
// SetDefaults modify the input by setting the right default parameters
|
|
func (ja JSONArray) SetDefaults(p *PowerDNS) JSONArray {
|
|
for i, j := range ja {
|
|
if j.Params.TTL == 0 {
|
|
ja[i].Params.TTL = p.DefaultTTL
|
|
}
|
|
}
|
|
return ja
|
|
}
|
|
|
|
// Run the actions defined in the json structure
|
|
func (ja JSONArray) Run(h *HTTPServer, user string, wasArray, textOnly bool) string {
|
|
listResult := []interface{}{}
|
|
plain := ""
|
|
for _, j := range ja {
|
|
result := j.Run(h, user)
|
|
for _, line := range result {
|
|
plain = plain + line.Changes
|
|
}
|
|
log.Printf("[jsonRPC API] User %s used command \"jsonrpc %s\"\n", user, j.String())
|
|
if len(result) == 0 {
|
|
listResult = append(listResult, JSONRPCResponse{ID: j.ID, JSONRPC: "2.0"})
|
|
continue
|
|
}
|
|
// check if the last entry of the result is an error
|
|
last := result[len(result)-1]
|
|
if !last.IsError() {
|
|
listResult = append(listResult, JSONRPCResponse{ID: j.ID, JSONRPC: "2.0", Result: result})
|
|
continue
|
|
}
|
|
listResult = append(listResult, JSONRPCNewError(-32000, j.ID, last.Error))
|
|
h.dns.LogDebug(last.Error)
|
|
if !j.Params.IgnoreError {
|
|
break
|
|
}
|
|
}
|
|
if textOnly {
|
|
return plain
|
|
}
|
|
if wasArray {
|
|
return string(printJSON(listResult))
|
|
}
|
|
if len(listResult) > 0 {
|
|
return string(printJSON(listResult[0]))
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// Run the action defined in the json structure
|
|
func (j *JSONInput) Run(h *HTTPServer, user string) []*JSONRPCResult {
|
|
// store the username
|
|
j.user = user
|
|
ret := []*JSONRPCResult{}
|
|
// normalize the query, and do some checks
|
|
if err := j.Normalize(); err != nil {
|
|
return append(ret, j.JSONRPCResult("", "", err))
|
|
}
|
|
switch j.Method {
|
|
// list is a spacial case, it doesn't imply a DNSQuery() object
|
|
case "list":
|
|
result, err := h.dns.ListZones(j.Params.Name)
|
|
// we apply the acl after the fact for the list method
|
|
result = j.FilterList(result)
|
|
|
|
if err == nil && len(result) == 0 {
|
|
err = errors.New("Unknown domain")
|
|
}
|
|
res := j.JSONRPCResult(result.List("\n"), "", err)
|
|
for i := range result {
|
|
res.Raw = append(res.Raw, result[i].Name)
|
|
}
|
|
return append(ret, res)
|
|
case "domain":
|
|
parentName, err := h.dns.GetDomain(j.Params.Name)
|
|
res := j.JSONRPCResult(parentName, "", err)
|
|
res.Raw = append(res.Raw, parentName)
|
|
return append(ret, res)
|
|
}
|
|
actions, err := j.DNSQueries(h)
|
|
if err != nil {
|
|
return append(ret, j.JSONRPCResult("", "", err))
|
|
}
|
|
for _, act := range actions {
|
|
// always add a comment
|
|
if j.Params.Comment == "" && !j.Params.DryRun {
|
|
j.Params.Comment = "-"
|
|
}
|
|
// add comment, ttl, and cleanup the payload
|
|
if j.Method != "dump" && j.Method != "search" {
|
|
act.AddCommentAndTTL(user, j.Params.Comment, j.Params.TTL)
|
|
}
|
|
result := j.JSONRPCResult("", strings.Join(act.PlainTexts(), "\n"), nil)
|
|
result.Changes = act.String()
|
|
result.Raw = append(result.Raw, act)
|
|
|
|
// if we are in dry run mode, stop here
|
|
if j.Params.DryRun {
|
|
result.Result = "Dry Run, nothing done"
|
|
ret = append(ret, result)
|
|
continue
|
|
}
|
|
// no domain, it will failed if executed
|
|
// can be the output of a zone creation
|
|
if !act.HasDomain() {
|
|
ret = append(ret, result)
|
|
continue
|
|
}
|
|
code, _, err := h.dns.Execute(act)
|
|
switch {
|
|
case err == nil && code == 204:
|
|
result.Result = "Command Successfull"
|
|
case err != nil:
|
|
result.Error = err.Error()
|
|
default:
|
|
result.Error = fmt.Sprintf("The return code was %d", code)
|
|
}
|
|
ret = append(ret, result)
|
|
if err != nil {
|
|
break
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// Normalize make some case change on the JSONInput and limit the wildcards in
|
|
// the name
|
|
func (j *JSONInput) Normalize() error {
|
|
// normalize Name (lower case, add a final .)
|
|
j.Params.Name = strings.ToLower(j.Params.Name)
|
|
j.Params.Name = addPoint(j.Params.Name)
|
|
if j.Method != "txt" {
|
|
j.Params.Value = strings.ToLower(j.Params.Value)
|
|
}
|
|
switch j.Method {
|
|
case "list":
|
|
case "search":
|
|
case "newzone":
|
|
if !validName(j.Params.Name, false) {
|
|
return errors.New("invalid name")
|
|
}
|
|
case "ptr":
|
|
if !validName(j.Params.Name, false) {
|
|
return errors.New("invalid name")
|
|
}
|
|
case "srv":
|
|
if !validSRVName(j.Params.Name) {
|
|
return errors.New("invalid name")
|
|
}
|
|
case "txt":
|
|
j.Params.Value = addQuotes(j.Params.Value)
|
|
case "domain":
|
|
if !validName(j.Params.Name, false) {
|
|
return errors.New("invalid name")
|
|
}
|
|
default:
|
|
if !validName(j.Params.Name, true) {
|
|
return errors.New("invalid name")
|
|
}
|
|
}
|
|
// add a final . to the value
|
|
for _, m := range []string{"cname", "mx", "dname", "ns", "ptr", "srv"} {
|
|
if j.Method == m {
|
|
j.Params.Value = addPoint(j.Params.Value)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DNSQueries takes a JSONInput and returns a usable []DNSQuery to be sent to
|
|
// pdns. It can change the content of j to force dry run mode
|
|
func (j *JSONInput) DNSQueries(h *HTTPServer) ([]*DNSQuery, error) {
|
|
var err error
|
|
switch j.Method {
|
|
case "search":
|
|
result, err := h.dns.Search(j.Params.Name)
|
|
// we apply the acl after the fact for the search method
|
|
result = j.FilterSearch(result)
|
|
j.Params.DryRun = true
|
|
return []*DNSQuery{result.DNSQuery()}, err
|
|
case "dump":
|
|
result, err := h.dns.Zone(j.Params.Name)
|
|
j.Params.DryRun = true
|
|
return []*DNSQuery{result}, err
|
|
case "newzone":
|
|
newZone, otherActions, err := j.NewZone(h)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if j.Params.DryRun {
|
|
return append(otherActions, newZone.TransformIntoDNSQuery()), nil
|
|
}
|
|
result := &DNSQuery{}
|
|
code, _, err := h.dns.ExecuteZone(newZone, result)
|
|
if err == nil && code != 201 {
|
|
err = fmt.Errorf("The return code was %d for the creation of zone %s", code, j.Params.Name)
|
|
}
|
|
return append(otherActions, result), err
|
|
}
|
|
current, err := h.dns.GetRecord(j.Params.Name, j.Method, j.ignoreBadDomain)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
switch j.Method {
|
|
case "ttl":
|
|
return j.DNSQueriesTTL(current)
|
|
case "delete":
|
|
return j.DNSQueriesDelete(h, current)
|
|
}
|
|
// test if there is something to add
|
|
if current.Useless(j.Params.Name, j.Params.Value, j.Params.Append) {
|
|
j.Params.DryRun = true
|
|
current.AddPlainText(0, "Nothing to do, the record is unchanged")
|
|
return []*DNSQuery{current}, nil
|
|
}
|
|
switch j.Method {
|
|
case "ns":
|
|
return j.DNSQueriesNS(h, current)
|
|
case "a":
|
|
return j.DNSQueriesA(h, current)
|
|
case "aaaa":
|
|
return j.DNSQueriesA(h, current)
|
|
case "cname":
|
|
if err = j.CheckCNAME(h); err == nil {
|
|
return j.DNSQueriesGeneric(current)
|
|
}
|
|
case "dname":
|
|
if err = j.CheckCNAME(h); err == nil {
|
|
return j.DNSQueriesGeneric(current)
|
|
}
|
|
case "mx":
|
|
if err = j.CheckMX(h); err == nil {
|
|
return j.DNSQueriesGeneric(current)
|
|
}
|
|
case "srv":
|
|
if err = j.CheckSRV(h); err == nil {
|
|
return j.DNSQueriesGeneric(current)
|
|
}
|
|
case "ptr":
|
|
if err = j.CheckPTR(h); err == nil {
|
|
return j.DNSQueriesGeneric(current)
|
|
}
|
|
case "caa":
|
|
if err = j.CheckCAA(); err == nil {
|
|
return j.DNSQueriesGeneric(current)
|
|
}
|
|
case "txt":
|
|
return j.DNSQueriesGeneric(current)
|
|
default:
|
|
err = errors.New("unknown action")
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
// DNSQueriesGeneric is the DNSQueries method for the most commands
|
|
func (j *JSONInput) DNSQueriesGeneric(current *DNSQuery) ([]*DNSQuery, error) {
|
|
// just change the value
|
|
current.ChangeValue(j.Params.Name, j.Params.Value, j.Method,
|
|
current.Len() > 0 && !j.Params.Append, false)
|
|
return []*DNSQuery{current}, nil
|
|
}
|
|
|
|
// DNSQueriesNS change the NS of a record
|
|
func (j *JSONInput) DNSQueriesNS(h *HTTPServer, current *DNSQuery) ([]*DNSQuery, error) {
|
|
if trimPoint(j.Params.Name) == trimPoint(current.Domain) {
|
|
return nil, fmt.Errorf("You cannot change the NS of a local zone")
|
|
}
|
|
subZone, err := h.dns.Zone(j.Params.Name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
currentNS := map[string]bool{j.Params.Value: true}
|
|
currentGlue := map[string]bool{}
|
|
for _, entry := range subZone.RRSets {
|
|
if entry.Type == "NS" && entry.Name == j.Params.Name {
|
|
for _, v := range entry.Records {
|
|
currentNS[v.Content] = true
|
|
}
|
|
continue
|
|
}
|
|
if entry.Type == "A" || entry.Type == "AAAA" {
|
|
currentGlue[entry.Name] = true
|
|
continue
|
|
}
|
|
return nil, fmt.Errorf(
|
|
"There are records that will be masked if you delegate the zone\nPlease delete them first")
|
|
}
|
|
fmt.Println(currentNS, currentGlue)
|
|
for ns := range currentNS {
|
|
if !strings.HasSuffix(ns, "."+addPoint(j.Params.Name)) {
|
|
continue
|
|
}
|
|
if _, ok := currentGlue[ns]; !ok {
|
|
return nil, fmt.Errorf("You must first create a glue record to resolve %s", j.Params.Value)
|
|
}
|
|
}
|
|
for glue := range currentGlue {
|
|
if _, ok := currentNS[glue]; !ok {
|
|
return nil, fmt.Errorf(
|
|
"There are records that will be masked if you delegate the zone\nPlease delete them first")
|
|
}
|
|
}
|
|
current.ChangeValue(j.Params.Name, j.Params.Value, j.Method, !j.Params.Append, false)
|
|
return []*DNSQuery{current}, nil
|
|
}
|
|
|
|
// DNSQueriesTTL change the TTL of a record
|
|
func (j *JSONInput) DNSQueriesTTL(current *DNSQuery) ([]*DNSQuery, error) {
|
|
todo := []int{}
|
|
for i := range current.RRSets {
|
|
if current.RRSets[i].TTL == j.Params.TTL {
|
|
continue
|
|
}
|
|
if j.Params.Value == "" {
|
|
todo = append(todo, i)
|
|
continue
|
|
}
|
|
for _, v := range current.RRSets[i].Records {
|
|
if v.Content == j.Params.Value {
|
|
todo = append(todo, i)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if len(todo) == 0 {
|
|
j.Params.DryRun = true
|
|
return nil, fmt.Errorf("Nothing to do, the record is unchanged")
|
|
}
|
|
newRRSets := []*DNSRRSet{}
|
|
for _, i := range todo {
|
|
newRRSets = append(newRRSets, current.RRSets[i])
|
|
}
|
|
current.RRSets = newRRSets
|
|
return []*DNSQuery{current}, nil
|
|
}
|
|
|
|
// DNSQueriesA is the DNSQueries method for the A and AAAA commands
|
|
// it checks the command is legal, and can make reverse DNS changes if needed
|
|
func (j *JSONInput) DNSQueriesA(h *HTTPServer, forward *DNSQuery) ([]*DNSQuery, error) {
|
|
reverse, err := h.dns.GetReverse(j.Params.Value, j.Method == "a")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// If we manage the reverse .arpa zone, we set it if either there is no
|
|
// reverse, or the forceReverse parameter is set
|
|
askForReverse := reverse != nil && (j.Params.ForceReverse || reverse.Len() == 0)
|
|
if askForReverse && j.Params.Name[0] == '*' {
|
|
return nil, errors.New("Can't set a reverse to a wildcard")
|
|
}
|
|
// simple case : the name didn't exist, or we do an append
|
|
if forward.Len() == 0 || j.Params.Append {
|
|
forward.ChangeValue(j.Params.Name, j.Params.Value, j.Method, false, askForReverse)
|
|
return []*DNSQuery{forward}, nil
|
|
}
|
|
actions, err := h.dns.ReverseChanges(forward, j.Params.Value)
|
|
forward.ChangeValue(j.Params.Name, j.Params.Value, j.Method, true, askForReverse)
|
|
return append(actions, forward), err
|
|
}
|
|
|
|
// DNSQueriesDelete is the DNSQueries method for the Delete command
|
|
func (j *JSONInput) DNSQueriesDelete(h *HTTPServer, current *DNSQuery) ([]*DNSQuery, error) {
|
|
reverses, useful, err := current.SplitDeletionQuery(j.Params.Name, j.Params.Value)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !useful {
|
|
j.Params.DryRun = true
|
|
current.AddPlainText(0, "Nothing to do, the record is unchanged")
|
|
return []*DNSQuery{current}, nil
|
|
}
|
|
ret := []*DNSQuery{current}
|
|
// add the reverse changes if needed
|
|
for _, r := range reverses {
|
|
parentName, err := h.dns.GetDomain(r.Name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ret = append(ret, r.DNSQuery(parentName))
|
|
if !r.IsDeletion() {
|
|
continue
|
|
}
|
|
ip := ptrToIP(r.Name)
|
|
if h.dns.IsUsed(ip, j.Params.Name, []string{"A", "AAAA"}) {
|
|
message := "Reverse issue : %s is the reverse for %s and will be removed\n"
|
|
message += "But other records are pointing to %s as well. Please cleanup first\n"
|
|
return ret, fmt.Errorf(message, j.Params.Name, ip, ip)
|
|
}
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
// CheckPTR validates that the query is a valid PTR
|
|
func (j *JSONInput) CheckPTR(h *HTTPServer) error {
|
|
ip := ptrToIP(j.Params.Name)
|
|
if ip == "" {
|
|
return fmt.Errorf("%s is not a valid PTR", j.Params.Name)
|
|
}
|
|
target := &DNSQuery{}
|
|
if err := h.dns.CanCreate(j.Params.Value, true, target); err != nil || target.Len() == 0 {
|
|
return err
|
|
}
|
|
for _, rec := range target.RRSets[0].Records {
|
|
if rec.Content == ip {
|
|
return nil
|
|
}
|
|
}
|
|
return fmt.Errorf("%s must point to %s", j.Params.Value, ip)
|
|
}
|
|
|
|
// CheckSRV validates that the query is a valid SRV
|
|
func (j *JSONInput) CheckSRV(h *HTTPServer) error {
|
|
name := validSRV(j.Params.Value)
|
|
if name == "" {
|
|
return fmt.Errorf("%s is not a valid SRV", j.Params.Value)
|
|
}
|
|
return h.dns.CanCreate(name, false, nil)
|
|
}
|
|
|
|
// CheckCAA validates that the query is a valid CAA
|
|
func (j *JSONInput) CheckCAA() error {
|
|
v := validCAA(j.Params.Value)
|
|
if v == "" {
|
|
return fmt.Errorf("%s is not a valid CAA", j.Params.Value)
|
|
}
|
|
j.Params.Value = v
|
|
return nil
|
|
}
|
|
|
|
// CheckMX validates that the query is a valid MX
|
|
func (j *JSONInput) CheckMX(h *HTTPServer) error {
|
|
name := validMX(j.Params.Value)
|
|
if name == "" {
|
|
return fmt.Errorf("%s is not a valid MX", j.Params.Value)
|
|
}
|
|
return h.dns.CanCreate(name, true, nil)
|
|
}
|
|
|
|
// CheckCNAME validates that the query is a valid CNAME
|
|
func (j *JSONInput) CheckCNAME(h *HTTPServer) error {
|
|
test := net.ParseIP(trimPoint(j.Params.Value))
|
|
if test != nil {
|
|
return fmt.Errorf("%s is an IP, not a DNS Name", j.Params.Value)
|
|
}
|
|
if !validName(j.Params.Value, false) {
|
|
return fmt.Errorf("%s is not a valid DNS Name", j.Params.Value)
|
|
}
|
|
return h.dns.CanCreate(j.Params.Value, false, nil)
|
|
}
|
|
|
|
// NewZone create a new zone in the DNS.
|
|
// If the new zone is a subzone of an existing one, it will move potential
|
|
// existing entries into the new zone
|
|
func (j *JSONInput) NewZone(h *HTTPServer) (z *DNSZone, otherActions []*DNSQuery, err error) {
|
|
// get the zone parameters
|
|
zoneType, soa, nameServers, defaults, autoInc, err := h.GetZoneConfig(j.Params.Name)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if soa == "" {
|
|
soa = fmt.Sprintf("%s hostmaster.%s 0 28800 7200 604800 86400", nameServers[0], j.Params.Name)
|
|
}
|
|
parentName, zoneErr := h.dns.GetDomain(j.Params.Name)
|
|
parentName = trimPoint(parentName)
|
|
|
|
z, err = h.dns.NewZone(j.Params.Name, zoneType, soa, j.user, j.Params.Comment,
|
|
j.Params.TTL, nameServers, autoInc)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
// check if there is a parent zone
|
|
if zoneErr == nil && parentName == trimPoint(j.Params.Name) {
|
|
return nil, nil, fmt.Errorf("%s already exists", j.Params.Name)
|
|
}
|
|
|
|
// we didn't find a parent zone, we must create the default entries
|
|
if zoneErr != nil {
|
|
for _, d := range defaults {
|
|
// make a copy
|
|
entry := *d
|
|
if d.Params.Name == "" {
|
|
entry.Params.Name = j.Params.Name
|
|
} else {
|
|
entry.Params.Name = fmt.Sprintf("%s.%s", d.Params.Name, j.Params.Name)
|
|
}
|
|
if err := entry.Normalize(); err != nil {
|
|
h.dns.LogDebug(err)
|
|
continue
|
|
}
|
|
actions, err := entry.DNSQueries(h)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
for _, a := range actions {
|
|
a.ChangeDomain(j.Params.Name)
|
|
a.AddCommentAndTTL(j.user, j.Params.Comment, j.Params.TTL)
|
|
z.AddEntries(a)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
// we must create the NS records in the parent zone too
|
|
glue, err := h.dns.SetNameServers(j.Params.Name, parentName, nameServers)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
otherActions = append(otherActions, glue)
|
|
|
|
// check if there are records in the parent zone
|
|
records, err := h.dns.Zone(j.Params.Name)
|
|
if err != nil {
|
|
err = nil
|
|
return
|
|
}
|
|
// if there are records, we must add them in the new zone...
|
|
records.SetPlainTexts("Add", false)
|
|
z.AddEntries(records)
|
|
|
|
// and delete them in the parent
|
|
delete, err := h.dns.Zone(j.Params.Name)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
delete.EmptyZone()
|
|
delete.ChangeDomain(parentName)
|
|
otherActions = append(otherActions, delete)
|
|
return
|
|
}
|
|
|
|
// FilterSearch prune the DNSSearch according to the restrictions in j.listFilters
|
|
func (j *JSONInput) FilterSearch(z []*DNSSearchEntry) []*DNSSearchEntry {
|
|
if len(z) == 0 {
|
|
return z
|
|
}
|
|
good := []int{}
|
|
for i := range z {
|
|
name := trimPoint(z[i].Name)
|
|
for _, re := range j.listFilters {
|
|
if re.MatchString(name) {
|
|
good = append(good, i)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
newList := []*DNSSearchEntry{}
|
|
for _, i := range good {
|
|
newList = append(newList, z[i])
|
|
}
|
|
return newList
|
|
}
|
|
|
|
// FilterList prune the DNSZones according to the restrictions in j.listFilters
|
|
func (j *JSONInput) FilterList(z []*DNSZone) []*DNSZone {
|
|
if len(z) == 0 {
|
|
return z
|
|
}
|
|
good := []int{}
|
|
for i := range z {
|
|
name := trimPoint(z[i].Name)
|
|
for _, re := range j.listFilters {
|
|
if re.MatchString(name) {
|
|
good = append(good, i)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
newList := []*DNSZone{}
|
|
for _, i := range good {
|
|
newList = append(newList, z[i])
|
|
}
|
|
return newList
|
|
}
|
|
|
|
// ParsejsonRPCRequest read the payload of the query and put it in the structure
|
|
func ParsejsonRPCRequest(s []byte, d *PowerDNS) (JSONArray, bool, error) {
|
|
var inSimple *JSONInput
|
|
var inArray JSONArray
|
|
if json.Unmarshal(s, &inArray); len(inArray) > 0 {
|
|
return inArray.SetDefaults(d), true, nil
|
|
}
|
|
if err := json.Unmarshal(s, &inSimple); err != nil {
|
|
return nil, false, err
|
|
}
|
|
return JSONArray{inSimple}.SetDefaults(d), false, nil
|
|
}
|
|
|
|
func isDryRun(j JSONArray) bool {
|
|
for _, cmd := range j {
|
|
if !cmd.Params.DryRun {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|