github.com/akamai/AkamaiOPEN-edgegrid-golang/v4@v4.1.0/pkg/dns/record_lookup.go (about)

     1  package dns
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  
     8  	"encoding/hex"
     9  	"net"
    10  	"strconv"
    11  	"strings"
    12  )
    13  
    14  func (p *dns) FullIPv6(ctx context.Context, ip net.IP) string {
    15  
    16  	logger := p.Log(ctx)
    17  	logger.Debug("FullIPv6")
    18  
    19  	dst := make([]byte, hex.EncodedLen(len(ip)))
    20  	_ = hex.Encode(dst, ip)
    21  	return string(dst[0:4]) + ":" +
    22  		string(dst[4:8]) + ":" +
    23  		string(dst[8:12]) + ":" +
    24  		string(dst[12:16]) + ":" +
    25  		string(dst[16:20]) + ":" +
    26  		string(dst[20:24]) + ":" +
    27  		string(dst[24:28]) + ":" +
    28  		string(dst[28:])
    29  }
    30  
    31  func padvalue(str string) string {
    32  	vstr := strings.Replace(str, "m", "", -1)
    33  	vfloat, err := strconv.ParseFloat(vstr, 32)
    34  	if err != nil {
    35  		return "FAIL"
    36  	}
    37  
    38  	return fmt.Sprintf("%.2f", vfloat)
    39  }
    40  
    41  func (p *dns) PadCoordinates(ctx context.Context, str string) string {
    42  
    43  	logger := p.Log(ctx)
    44  	logger.Debug("PadCoordinates")
    45  
    46  	s := strings.Split(str, " ")
    47  	if len(s) < 12 {
    48  		return ""
    49  	}
    50  
    51  	latd, latm, lats, latDir, longd, longm, longs, longDir, altitude, size, horizPrecision, vertPrecision := s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11]
    52  
    53  	return latd + " " + latm + " " + lats + " " + latDir + " " + longd + " " + longm + " " + longs + " " + longDir + " " + padvalue(altitude) + "m " + padvalue(size) + "m " + padvalue(horizPrecision) + "m " + padvalue(vertPrecision) + "m"
    54  
    55  }
    56  
    57  func (p *dns) GetRecord(ctx context.Context, zone string, name string, recordType string) (*RecordBody, error) {
    58  
    59  	logger := p.Log(ctx)
    60  	logger.Debug("GetRecord")
    61  
    62  	var rec RecordBody
    63  	getURL := fmt.Sprintf("/config-dns/v2/zones/%s/names/%s/types/%s", zone, name, recordType)
    64  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil)
    65  	if err != nil {
    66  		return nil, fmt.Errorf("failed to create GetRecord request: %w", err)
    67  	}
    68  
    69  	resp, err := p.Exec(req, &rec)
    70  	if err != nil {
    71  		return nil, fmt.Errorf("GetRecord request failed: %w", err)
    72  	}
    73  
    74  	if resp.StatusCode != http.StatusOK {
    75  		return nil, p.Error(resp)
    76  	}
    77  
    78  	return &rec, nil
    79  }
    80  
    81  func (p *dns) GetRecordList(ctx context.Context, zone string, _ string, recordType string) (*RecordSetResponse, error) {
    82  
    83  	logger := p.Log(ctx)
    84  	logger.Debug("GetRecordList")
    85  
    86  	var records RecordSetResponse
    87  	getURL := fmt.Sprintf("/config-dns/v2/zones/%s/recordsets?types=%s&showAll=true", zone, recordType)
    88  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, getURL, nil)
    89  	if err != nil {
    90  		return nil, fmt.Errorf("failed to create GetRecordList request: %w", err)
    91  	}
    92  
    93  	resp, err := p.Exec(req, &records)
    94  	if err != nil {
    95  		return nil, fmt.Errorf("GetRecordList request failed: %w", err)
    96  	}
    97  
    98  	if resp.StatusCode != http.StatusOK {
    99  		return nil, p.Error(resp)
   100  	}
   101  
   102  	return &records, nil
   103  }
   104  
   105  func (p *dns) GetRdata(ctx context.Context, zone string, name string, recordType string) ([]string, error) {
   106  
   107  	logger := p.Log(ctx)
   108  	logger.Debug("GetRdata")
   109  
   110  	records, err := p.GetRecordList(ctx, zone, name, recordType)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	var arrLength int
   116  	for _, c := range records.Recordsets {
   117  		if c.Name == name {
   118  			arrLength = len(c.Rdata)
   119  		}
   120  	}
   121  
   122  	rdata := make([]string, 0, arrLength)
   123  
   124  	for _, r := range records.Recordsets {
   125  		if r.Name == name {
   126  			for _, i := range r.Rdata {
   127  				str := i
   128  
   129  				if recordType == "AAAA" {
   130  					addr := net.ParseIP(str)
   131  					result := p.FullIPv6(ctx, addr)
   132  					str = result
   133  				} else if recordType == "LOC" {
   134  					str = p.PadCoordinates(ctx, str)
   135  				}
   136  				rdata = append(rdata, str)
   137  			}
   138  		}
   139  	}
   140  	return rdata, nil
   141  }
   142  
   143  func (p *dns) ProcessRdata(ctx context.Context, rdata []string, rtype string) []string {
   144  
   145  	logger := p.Log(ctx)
   146  	logger.Debug("ProcessRdata")
   147  
   148  	newrdata := make([]string, 0, len(rdata))
   149  	for _, i := range rdata {
   150  		str := i
   151  		if rtype == "AAAA" {
   152  			addr := net.ParseIP(str)
   153  			result := p.FullIPv6(ctx, addr)
   154  			str = result
   155  		} else if rtype == "LOC" {
   156  			str = p.PadCoordinates(ctx, str)
   157  		}
   158  		newrdata = append(newrdata, str)
   159  	}
   160  	return newrdata
   161  
   162  }
   163  
   164  func (p *dns) ParseRData(ctx context.Context, rtype string, rdata []string) map[string]interface{} {
   165  
   166  	logger := p.Log(ctx)
   167  	logger.Debug("ParseRData")
   168  
   169  	fieldMap := make(map[string]interface{}, 0)
   170  	if len(rdata) == 0 {
   171  		return fieldMap
   172  	}
   173  	newrdata := make([]string, 0, len(rdata))
   174  	fieldMap["target"] = newrdata
   175  
   176  	switch rtype {
   177  	case "AFSDB":
   178  		resolveAFSDBType(rdata, newrdata, fieldMap)
   179  
   180  	case "DNSKEY":
   181  		resolveDNSKEYType(rdata, fieldMap)
   182  
   183  	case "DS":
   184  		resolveDSType(rdata, fieldMap)
   185  
   186  	case "HINFO":
   187  		resolveHINFOType(rdata, fieldMap)
   188  	/*
   189  		// too many variations to calculate pri and increment
   190  		case "MX":
   191  			sort.Strings(rdata)
   192  			parts := strings.Split(rdata[0], " ")
   193  			fieldMap["priority"], _ = strconv.Atoi(parts[0])
   194  			if len(rdata) > 1 {
   195  				parts = strings.Split(rdata[1], " ")
   196  				tpri, _ := strconv.Atoi(parts[0])
   197  				fieldMap["priority_increment"] = tpri - fieldMap["priority"].(int)
   198  			}
   199  			for _, rcontent := range rdata {
   200  				parts := strings.Split(rcontent, " ")
   201  				newrdata = append(newrdata, parts[1])
   202  			}
   203  			fieldMap["target"] = newrdata
   204  	*/
   205  
   206  	case "NAPTR":
   207  		resolveNAPTRType(rdata, fieldMap)
   208  
   209  	case "NSEC3":
   210  		resolveNSEC3Type(rdata, fieldMap)
   211  
   212  	case "NSEC3PARAM":
   213  		resolveNSEC3PARAMType(rdata, fieldMap)
   214  
   215  	case "RP":
   216  		resolveRPType(rdata, fieldMap)
   217  
   218  	case "RRSIG":
   219  		resolveRRSIGType(rdata, fieldMap)
   220  
   221  	case "SRV":
   222  		resolveSRVType(rdata, newrdata, fieldMap)
   223  
   224  	case "SSHFP":
   225  		resolveSSHFPType(rdata, fieldMap)
   226  
   227  	case "SOA":
   228  		resolveSOAType(rdata, fieldMap)
   229  
   230  	case "AKAMAITLC":
   231  		resolveAKAMAITLCType(rdata, fieldMap)
   232  
   233  	case "SPF":
   234  		resolveSPFType(rdata, newrdata, fieldMap)
   235  
   236  	case "TXT":
   237  		resolveTXTType(rdata, newrdata, fieldMap)
   238  
   239  	case "AAAA":
   240  		resolveAAAAType(ctx, p, rdata, newrdata, fieldMap)
   241  
   242  	case "LOC":
   243  		resolveLOCType(ctx, p, rdata, newrdata, fieldMap)
   244  
   245  	case "CERT":
   246  		resolveCERTType(rdata, fieldMap)
   247  
   248  	case "TLSA":
   249  		resolveTLSAType(rdata, fieldMap)
   250  
   251  	case "SVCB":
   252  		resolveSVCBType(rdata, fieldMap)
   253  
   254  	case "HTTPS":
   255  		resolveHTTPSType(rdata, fieldMap)
   256  
   257  	default:
   258  		for _, rcontent := range rdata {
   259  			newrdata = append(newrdata, rcontent)
   260  		}
   261  		fieldMap["target"] = newrdata
   262  	}
   263  
   264  	return fieldMap
   265  }
   266  
   267  func resolveAFSDBType(rdata, newrdata []string, fieldMap map[string]interface{}) {
   268  	parts := strings.Split(rdata[0], " ")
   269  	fieldMap["subtype"], _ = strconv.Atoi(parts[0])
   270  	for _, rcontent := range rdata {
   271  		parts = strings.Split(rcontent, " ")
   272  		newrdata = append(newrdata, parts[1])
   273  	}
   274  	fieldMap["target"] = newrdata
   275  }
   276  
   277  func resolveDNSKEYType(rdata []string, fieldMap map[string]interface{}) {
   278  	for _, rcontent := range rdata {
   279  		parts := strings.Split(rcontent, " ")
   280  		fieldMap["flags"], _ = strconv.Atoi(parts[0])
   281  		fieldMap["protocol"], _ = strconv.Atoi(parts[1])
   282  		fieldMap["algorithm"], _ = strconv.Atoi(parts[2])
   283  		key := parts[3]
   284  		// key can have whitespace
   285  		if len(parts) > 4 {
   286  			i := 4
   287  			for i < len(parts) {
   288  				key += " " + parts[i]
   289  			}
   290  		}
   291  		fieldMap["key"] = key
   292  		break
   293  	}
   294  }
   295  
   296  func resolveSVCBType(rdata []string, fieldMap map[string]interface{}) {
   297  	for _, rcontent := range rdata {
   298  		parts := strings.SplitN(rcontent, " ", 3)
   299  		// has to be at least two fields.
   300  		if len(parts) < 2 {
   301  			break
   302  		}
   303  		fieldMap["svc_priority"], _ = strconv.Atoi(parts[0])
   304  		fieldMap["target_name"] = parts[1]
   305  		if len(parts) > 2 {
   306  			fieldMap["svc_params"] = parts[2]
   307  		}
   308  		break
   309  	}
   310  }
   311  
   312  func resolveDSType(rdata []string, fieldMap map[string]interface{}) {
   313  	for _, rcontent := range rdata {
   314  		parts := strings.Split(rcontent, " ")
   315  		fieldMap["keytag"], _ = strconv.Atoi(parts[0])
   316  		fieldMap["digest_type"], _ = strconv.Atoi(parts[2])
   317  		fieldMap["algorithm"], _ = strconv.Atoi(parts[1])
   318  		dig := parts[3]
   319  		// digest can have whitespace
   320  		if len(parts) > 4 {
   321  			i := 4
   322  			for i < len(parts) {
   323  				dig += " " + parts[i]
   324  			}
   325  		}
   326  		fieldMap["digest"] = dig
   327  		break
   328  	}
   329  }
   330  
   331  func resolveHINFOType(rdata []string, fieldMap map[string]interface{}) {
   332  	for _, rcontent := range rdata {
   333  		parts := strings.Split(rcontent, " ")
   334  		fieldMap["hardware"] = parts[0]
   335  		fieldMap["software"] = parts[1]
   336  		break
   337  	}
   338  }
   339  
   340  func resolveNAPTRType(rdata []string, fieldMap map[string]interface{}) {
   341  	for _, rcontent := range rdata {
   342  		parts := strings.Split(rcontent, " ")
   343  		fieldMap["order"], _ = strconv.Atoi(parts[0])
   344  		fieldMap["preference"], _ = strconv.Atoi(parts[1])
   345  		fieldMap["flagsnaptr"] = parts[2]
   346  		fieldMap["service"] = parts[3]
   347  		fieldMap["regexp"] = parts[4]
   348  		fieldMap["replacement"] = parts[5]
   349  		break
   350  	}
   351  }
   352  
   353  func resolveNSEC3Type(rdata []string, fieldMap map[string]interface{}) {
   354  	for _, rcontent := range rdata {
   355  		parts := strings.Split(rcontent, " ")
   356  		fieldMap["flags"], _ = strconv.Atoi(parts[1])
   357  		fieldMap["algorithm"], _ = strconv.Atoi(parts[0])
   358  		fieldMap["iterations"], _ = strconv.Atoi(parts[2])
   359  		fieldMap["salt"] = parts[3]
   360  		fieldMap["next_hashed_owner_name"] = parts[4]
   361  		fieldMap["type_bitmaps"] = parts[5]
   362  		break
   363  	}
   364  }
   365  
   366  func resolveNSEC3PARAMType(rdata []string, fieldMap map[string]interface{}) {
   367  	for _, rcontent := range rdata {
   368  		parts := strings.Split(rcontent, " ")
   369  		fieldMap["flags"], _ = strconv.Atoi(parts[1])
   370  		fieldMap["algorithm"], _ = strconv.Atoi(parts[0])
   371  		fieldMap["iterations"], _ = strconv.Atoi(parts[2])
   372  		fieldMap["salt"] = parts[3]
   373  		break
   374  	}
   375  }
   376  
   377  func resolveRPType(rdata []string, fieldMap map[string]interface{}) {
   378  	for _, rcontent := range rdata {
   379  		parts := strings.Split(rcontent, " ")
   380  		fieldMap["mailbox"] = parts[0]
   381  		fieldMap["txt"] = parts[1]
   382  		break
   383  	}
   384  }
   385  
   386  func resolveRRSIGType(rdata []string, fieldMap map[string]interface{}) {
   387  	for _, rcontent := range rdata {
   388  		parts := strings.Split(rcontent, " ")
   389  		fieldMap["type_covered"] = parts[0]
   390  		fieldMap["algorithm"], _ = strconv.Atoi(parts[1])
   391  		fieldMap["labels"], _ = strconv.Atoi(parts[2])
   392  		fieldMap["original_ttl"], _ = strconv.Atoi(parts[3])
   393  		fieldMap["expiration"] = parts[4]
   394  		fieldMap["inception"] = parts[5]
   395  		fieldMap["signer"] = parts[7]
   396  		fieldMap["keytag"], _ = strconv.Atoi(parts[6])
   397  		sig := parts[8]
   398  		// sig can have whitespace
   399  		if len(parts) > 9 {
   400  			i := 9
   401  			for i < len(parts) {
   402  				sig += " " + parts[i]
   403  			}
   404  		}
   405  		fieldMap["signature"] = sig
   406  		break
   407  	}
   408  }
   409  
   410  func resolveSRVType(rdata, newrdata []string, fieldMap map[string]interface{}) {
   411  	// pull out some fields
   412  	parts := strings.Split(rdata[0], " ")
   413  	fieldMap["priority"], _ = strconv.Atoi(parts[0])
   414  	fieldMap["weight"], _ = strconv.Atoi(parts[1])
   415  	fieldMap["port"], _ = strconv.Atoi(parts[2])
   416  	// populate target
   417  	for _, rcontent := range rdata {
   418  		parts = strings.Split(rcontent, " ")
   419  		newrdata = append(newrdata, parts[3])
   420  	}
   421  	fieldMap["target"] = newrdata
   422  }
   423  
   424  func resolveSSHFPType(rdata []string, fieldMap map[string]interface{}) {
   425  	for _, rcontent := range rdata {
   426  		parts := strings.Split(rcontent, " ")
   427  		fieldMap["algorithm"], _ = strconv.Atoi(parts[0])
   428  		fieldMap["fingerprint_type"], _ = strconv.Atoi(parts[1])
   429  		fieldMap["fingerprint"] = parts[2]
   430  		break
   431  	}
   432  }
   433  
   434  func resolveSOAType(rdata []string, fieldMap map[string]interface{}) {
   435  	for _, rcontent := range rdata {
   436  		parts := strings.Split(rcontent, " ")
   437  		fieldMap["name_server"] = parts[0]
   438  		fieldMap["email_address"] = parts[1]
   439  		fieldMap["serial"], _ = strconv.Atoi(parts[2])
   440  		fieldMap["refresh"], _ = strconv.Atoi(parts[3])
   441  		fieldMap["retry"], _ = strconv.Atoi(parts[4])
   442  		fieldMap["expiry"], _ = strconv.Atoi(parts[5])
   443  		fieldMap["nxdomain_ttl"], _ = strconv.Atoi(parts[6])
   444  		break
   445  	}
   446  }
   447  
   448  func resolveAKAMAITLCType(rdata []string, fieldMap map[string]interface{}) {
   449  	parts := strings.Split(rdata[0], " ")
   450  	fieldMap["answer_type"] = parts[0]
   451  	fieldMap["dns_name"] = parts[1]
   452  }
   453  
   454  func resolveSPFType(rdata, newrdata []string, fieldMap map[string]interface{}) {
   455  	for _, rcontent := range rdata {
   456  		newrdata = append(newrdata, rcontent)
   457  	}
   458  	fieldMap["target"] = newrdata
   459  }
   460  
   461  func resolveTXTType(rdata, newrdata []string, fieldMap map[string]interface{}) {
   462  	for _, rcontent := range rdata {
   463  		newrdata = append(newrdata, rcontent)
   464  	}
   465  	fieldMap["target"] = newrdata
   466  }
   467  
   468  func resolveAAAAType(ctx context.Context, p *dns, rdata, newrdata []string, fieldMap map[string]interface{}) {
   469  	for _, i := range rdata {
   470  		str := i
   471  		addr := net.ParseIP(str)
   472  		result := p.FullIPv6(ctx, addr)
   473  		str = result
   474  		newrdata = append(newrdata, str)
   475  	}
   476  	fieldMap["target"] = newrdata
   477  }
   478  
   479  func resolveLOCType(ctx context.Context, p *dns, rdata, newrdata []string, fieldMap map[string]interface{}) {
   480  	for _, i := range rdata {
   481  		str := i
   482  		str = p.PadCoordinates(ctx, str)
   483  		newrdata = append(newrdata, str)
   484  	}
   485  	fieldMap["target"] = newrdata
   486  }
   487  
   488  func resolveCERTType(rdata []string, fieldMap map[string]interface{}) {
   489  	for _, rcontent := range rdata {
   490  		parts := strings.Split(rcontent, " ")
   491  		val, err := strconv.Atoi(parts[0])
   492  		if err == nil {
   493  			fieldMap["type_value"] = val
   494  		} else {
   495  			fieldMap["type_mnemonic"] = parts[0]
   496  		}
   497  		fieldMap["keytag"], _ = strconv.Atoi(parts[1])
   498  		fieldMap["algorithm"], _ = strconv.Atoi(parts[2])
   499  		fieldMap["certificate"] = parts[3]
   500  		break
   501  	}
   502  }
   503  
   504  func resolveTLSAType(rdata []string, fieldMap map[string]interface{}) {
   505  	for _, rcontent := range rdata {
   506  		parts := strings.Split(rcontent, " ")
   507  		fieldMap["usage"], _ = strconv.Atoi(parts[0])
   508  		fieldMap["selector"], _ = strconv.Atoi(parts[1])
   509  		fieldMap["match_type"], _ = strconv.Atoi(parts[2])
   510  		fieldMap["certificate"] = parts[3]
   511  		break
   512  	}
   513  }
   514  
   515  func resolveHTTPSType(rdata []string, fieldMap map[string]interface{}) {
   516  	for _, rcontent := range rdata {
   517  		parts := strings.SplitN(rcontent, " ", 3)
   518  		// has to be at least two fields.
   519  		if len(parts) < 2 {
   520  			break
   521  		}
   522  		fieldMap["svc_priority"], _ = strconv.Atoi(parts[0])
   523  		fieldMap["target_name"] = parts[1]
   524  		if len(parts) > 2 {
   525  			fieldMap["svc_params"] = parts[2]
   526  		}
   527  		break
   528  	}
   529  }