mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-12-09 13:46:07 +08:00
CLOUDFLARE: Add LOC support (#3857)
Fixes #2798. I tested this locally and it seems to update the `LOC` record correctly.
This commit is contained in:
parent
c073f2e654
commit
ec9a9e23af
4 changed files with 141 additions and 60 deletions
|
|
@ -158,7 +158,7 @@ Jump to a table:
|
|||
| [`AZURE_PRIVATE_DNS`](azure_private_dns.md) | ❌ | ❔ | ❌ | ✅ | ❔ |
|
||||
| [`BIND`](bind.md) | ❔ | ✅ | ✅ | ✅ | ✅ |
|
||||
| [`BUNNY_DNS`](bunny_dns.md) | ✅ | ❔ | ❌ | ✅ | ❌ |
|
||||
| [`CLOUDFLAREAPI`](cloudflareapi.md) | ✅ | ❔ | ❌ | ✅ | ❔ |
|
||||
| [`CLOUDFLAREAPI`](cloudflareapi.md) | ✅ | ❔ | ✅ | ✅ | ❔ |
|
||||
| [`CLOUDNS`](cloudns.md) | ✅ | ✅ | ✅ | ✅ | ❔ |
|
||||
| [`CNR`](cnr.md) | ✅ | ❌ | ❌ | ✅ | ❌ |
|
||||
| [`DESEC`](desec.md) | ❔ | ❔ | ❔ | ✅ | ❔ |
|
||||
|
|
|
|||
|
|
@ -99,26 +99,20 @@ func (rc *RecordConfig) calculateLOCFields(d1 uint8, m1 uint8, s1 float32, ns st
|
|||
) error {
|
||||
// Crazy hairy shit happens here.
|
||||
// We already got the useful "string" version earlier. ¯\_(ツ)_/¯ code golf...
|
||||
const LOCEquator uint64 = 0x80000000 // 1 << 31 // RFC 1876, Section 2.
|
||||
const LOCPrimeMeridian uint64 = 0x80000000 // 1 << 31 // RFC 1876, Section 2.
|
||||
const LOCHours uint32 = 60 * 1000
|
||||
const LOCDegrees = 60 * LOCHours
|
||||
const LOCAltitudeBase int32 = 100000
|
||||
|
||||
lat := uint64((uint32(d1) * LOCDegrees) + (uint32(m1) * LOCHours) + uint32(s1*1000))
|
||||
lon := uint64((uint32(d2) * LOCDegrees) + (uint32(m2) * LOCHours) + uint32(s2*1000))
|
||||
lat := uint32(d1)*dns.LOC_DEGREES + uint32(m1)*dns.LOC_HOURS + uint32(s1*1000)
|
||||
lon := uint32(d2)*dns.LOC_DEGREES + uint32(m2)*dns.LOC_HOURS + uint32(s2*1000)
|
||||
if strings.ToUpper(ns) == "N" {
|
||||
rc.LocLatitude = uint32(LOCEquator + lat)
|
||||
rc.LocLatitude = dns.LOC_EQUATOR + lat
|
||||
} else { // "S"
|
||||
rc.LocLatitude = uint32(LOCEquator - lat)
|
||||
rc.LocLatitude = dns.LOC_EQUATOR - lat
|
||||
}
|
||||
if strings.ToUpper(ew) == "E" {
|
||||
rc.LocLongitude = uint32(LOCPrimeMeridian + lon)
|
||||
rc.LocLongitude = dns.LOC_PRIMEMERIDIAN + lon
|
||||
} else { // "W"
|
||||
rc.LocLongitude = uint32(LOCPrimeMeridian - lon)
|
||||
rc.LocLongitude = dns.LOC_PRIMEMERIDIAN - lon
|
||||
}
|
||||
// Altitude
|
||||
altitude := (float64(al) + float64(LOCAltitudeBase)) * 100
|
||||
altitude := (float64(al) + dns.LOC_ALTITUDEBASE) * 100
|
||||
clampedAltitude := math.Min(math.Max(0, altitude), float64(math.MaxUint32))
|
||||
rc.LocAltitude = uint32(clampedAltitude)
|
||||
|
||||
|
|
@ -205,3 +199,54 @@ func getENotationInt(x float32) (uint8, error) {
|
|||
|
||||
return packedValue, nil
|
||||
}
|
||||
|
||||
func ReverseLatitude(lat uint32) (string, uint8, uint8, float64) {
|
||||
var hemisphere string
|
||||
if lat >= dns.LOC_EQUATOR {
|
||||
hemisphere = "N"
|
||||
lat = lat - dns.LOC_EQUATOR
|
||||
} else {
|
||||
hemisphere = "S"
|
||||
lat = dns.LOC_EQUATOR - lat
|
||||
}
|
||||
degrees := uint8(lat / dns.LOC_DEGREES)
|
||||
lat -= uint32(degrees) * dns.LOC_DEGREES
|
||||
minutes := uint8(lat / dns.LOC_HOURS)
|
||||
lat -= uint32(minutes) * dns.LOC_HOURS
|
||||
seconds := float64(lat) / 1000
|
||||
|
||||
return hemisphere, degrees, minutes, seconds
|
||||
}
|
||||
|
||||
func ReverseLongitude(lon uint32) (string, uint8, uint8, float64) {
|
||||
var hemisphere string
|
||||
if lon >= dns.LOC_PRIMEMERIDIAN {
|
||||
hemisphere = "E"
|
||||
lon = lon - dns.LOC_PRIMEMERIDIAN
|
||||
} else {
|
||||
hemisphere = "W"
|
||||
lon = dns.LOC_PRIMEMERIDIAN - lon
|
||||
}
|
||||
degrees := uint8(lon / dns.LOC_DEGREES)
|
||||
lon -= uint32(degrees) * dns.LOC_DEGREES
|
||||
minutes := uint8(lon / dns.LOC_HOURS)
|
||||
lon -= uint32(minutes) * dns.LOC_HOURS
|
||||
seconds := float64(lon) / 1000
|
||||
|
||||
return hemisphere, degrees, minutes, seconds
|
||||
}
|
||||
|
||||
func ReverseAltitude(packedAltitude uint32) float64 {
|
||||
return float64(packedAltitude)/100 - 100000
|
||||
}
|
||||
|
||||
// ReverseENotationInt produces a number from a mantissa_exponent 4bits:4bits uint8
|
||||
func ReverseENotationInt(packedValue uint8) float64 {
|
||||
mantissa := float64((packedValue >> 4) & 0x0F)
|
||||
exponent := int(packedValue & 0x0F)
|
||||
|
||||
centimeters := mantissa * math.Pow10(exponent)
|
||||
|
||||
// Return in meters
|
||||
return centimeters / 100
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ var features = providers.DocumentationNotes{
|
|||
providers.CanUseDS: providers.Can(),
|
||||
providers.CanUseDSForChildren: providers.Can(),
|
||||
providers.CanUseHTTPS: providers.Can(),
|
||||
providers.CanUseLOC: providers.Cannot(),
|
||||
providers.CanUseLOC: providers.Can(),
|
||||
providers.CanUseNAPTR: providers.Can(),
|
||||
providers.CanUsePTR: providers.Can(),
|
||||
providers.CanUseSRV: providers.Can(),
|
||||
|
|
@ -708,28 +708,40 @@ func newCloudflare(m map[string]string, metadata json.RawMessage) (providers.DNS
|
|||
|
||||
// Used on the "existing" records.
|
||||
type cfRecData struct {
|
||||
Name string `json:"name"`
|
||||
Target cfTarget `json:"target"`
|
||||
Service string `json:"service"` // SRV
|
||||
Proto string `json:"proto"` // SRV
|
||||
Priority uint16 `json:"priority"` // SRV
|
||||
Weight uint16 `json:"weight"` // SRV
|
||||
Port uint16 `json:"port"` // SRV
|
||||
Tag string `json:"tag"` // CAA
|
||||
Flags uint16 `json:"flags"` // CAA/DNSKEY
|
||||
Value string `json:"value"` // CAA
|
||||
Usage uint8 `json:"usage"` // TLSA
|
||||
Selector uint8 `json:"selector"` // TLSA
|
||||
MatchingType uint8 `json:"matching_type"` // TLSA
|
||||
Certificate string `json:"certificate"` // TLSA
|
||||
Algorithm uint8 `json:"algorithm"` // SSHFP/DNSKEY/DS
|
||||
HashType uint8 `json:"type"` // SSHFP
|
||||
Fingerprint string `json:"fingerprint"` // SSHFP
|
||||
Protocol uint8 `json:"protocol"` // DNSKEY
|
||||
PublicKey string `json:"public_key"` // DNSKEY
|
||||
KeyTag uint16 `json:"key_tag"` // DS
|
||||
DigestType uint8 `json:"digest_type"` // DS
|
||||
Digest string `json:"digest"` // DS
|
||||
Name string `json:"name"`
|
||||
Target cfTarget `json:"target"`
|
||||
Service string `json:"service"` // SRV
|
||||
Proto string `json:"proto"` // SRV
|
||||
Priority uint16 `json:"priority"` // SRV
|
||||
Weight uint16 `json:"weight"` // SRV
|
||||
Port uint16 `json:"port"` // SRV
|
||||
Tag string `json:"tag"` // CAA
|
||||
Flags uint16 `json:"flags"` // CAA/DNSKEY
|
||||
Value string `json:"value"` // CAA
|
||||
Usage uint8 `json:"usage"` // TLSA
|
||||
Selector uint8 `json:"selector"` // TLSA
|
||||
MatchingType uint8 `json:"matching_type"` // TLSA
|
||||
Certificate string `json:"certificate"` // TLSA
|
||||
Algorithm uint8 `json:"algorithm"` // SSHFP/DNSKEY/DS
|
||||
HashType uint8 `json:"type"` // SSHFP
|
||||
Fingerprint string `json:"fingerprint"` // SSHFP
|
||||
Protocol uint8 `json:"protocol"` // DNSKEY
|
||||
PublicKey string `json:"public_key"` // DNSKEY
|
||||
KeyTag uint16 `json:"key_tag"` // DS
|
||||
DigestType uint8 `json:"digest_type"` // DS
|
||||
Digest string `json:"digest"` // DS
|
||||
Altitude float64 `json:"altitude"` // LOC
|
||||
LatDegrees uint8 `json:"lat_degrees"` // LOC
|
||||
LatDirection string `json:"lat_direction"` // LOC
|
||||
LatMinutes uint8 `json:"lat_minutes"` // LOC
|
||||
LatSeconds float64 `json:"lat_seconds"` // LOC
|
||||
LongDegrees uint8 `json:"long_degrees"` // LOC
|
||||
LongDirection string `json:"long_direction"` // LOC
|
||||
LongMinutes uint8 `json:"long_minutes"` // LOC
|
||||
LongSeconds float64 `json:"long_seconds"` // LOC
|
||||
PrecisionHorz float64 `json:"precision_horz"` // LOC
|
||||
PrecisionVert float64 `json:"precision_vert"` // LOC
|
||||
Size float64 `json:"size"` // LOC
|
||||
}
|
||||
|
||||
// cfTarget is a SRV target. A null target is represented by an empty string, but
|
||||
|
|
|
|||
|
|
@ -137,6 +137,26 @@ func cfSvcbData(rec *models.RecordConfig) *cfRecData {
|
|||
}
|
||||
}
|
||||
|
||||
func cfLocData(rec *models.RecordConfig) *cfRecData {
|
||||
latDir, latDeg, latMin, latSec := models.ReverseLatitude(rec.LocLatitude)
|
||||
longDir, longDeg, longMin, longSec := models.ReverseLongitude(rec.LocLongitude)
|
||||
|
||||
return &cfRecData{
|
||||
Altitude: models.ReverseAltitude(rec.LocAltitude),
|
||||
LatDegrees: latDeg,
|
||||
LatDirection: latDir,
|
||||
LatMinutes: latMin,
|
||||
LatSeconds: latSec,
|
||||
LongDegrees: longDeg,
|
||||
LongDirection: longDir,
|
||||
LongMinutes: longMin,
|
||||
LongSeconds: longSec,
|
||||
PrecisionHorz: models.ReverseENotationInt(rec.LocHorizPre),
|
||||
PrecisionVert: models.ReverseENotationInt(rec.LocVertPre),
|
||||
Size: models.ReverseENotationInt(rec.LocSize),
|
||||
}
|
||||
}
|
||||
|
||||
func cfNaptrData(rec *models.RecordConfig) *cfNaptrRecData {
|
||||
return &cfNaptrRecData{
|
||||
Flags: rec.NaptrFlags,
|
||||
|
|
@ -154,13 +174,12 @@ func (c *cloudflareProvider) createRecDiff2(rec *models.RecordConfig, domainID s
|
|||
content = rec.Metadata[metaOriginalIP]
|
||||
}
|
||||
prio := ""
|
||||
if rec.Type == "MX" {
|
||||
switch rec.Type {
|
||||
case "MX":
|
||||
prio = fmt.Sprintf(" %d ", rec.MxPreference)
|
||||
}
|
||||
if rec.Type == "TXT" {
|
||||
case "TXT":
|
||||
content = rec.GetTargetTXTJoined()
|
||||
}
|
||||
if rec.Type == "DS" {
|
||||
case "DS":
|
||||
content = fmt.Sprintf("%d %d %d %s", rec.DsKeyTag, rec.DsAlgorithm, rec.DsDigestType, rec.DsDigest)
|
||||
}
|
||||
if msg == "" {
|
||||
|
|
@ -179,28 +198,31 @@ func (c *cloudflareProvider) createRecDiff2(rec *models.RecordConfig, domainID s
|
|||
Content: content,
|
||||
Priority: &rec.MxPreference,
|
||||
}
|
||||
if rec.Type == "SRV" {
|
||||
switch rec.Type {
|
||||
case "SRV":
|
||||
cf.Data = cfSrvData(rec)
|
||||
cf.Name = rec.GetLabelFQDN()
|
||||
} else if rec.Type == "CAA" {
|
||||
case "CAA":
|
||||
cf.Data = cfCaaData(rec)
|
||||
cf.Name = rec.GetLabelFQDN()
|
||||
cf.Content = ""
|
||||
} else if rec.Type == "TLSA" {
|
||||
case "TLSA":
|
||||
cf.Data = cfTlsaData(rec)
|
||||
cf.Name = rec.GetLabelFQDN()
|
||||
} else if rec.Type == "SSHFP" {
|
||||
case "SSHFP":
|
||||
cf.Data = cfSshfpData(rec)
|
||||
cf.Name = rec.GetLabelFQDN()
|
||||
} else if rec.Type == "DNSKEY" {
|
||||
case "DNSKEY":
|
||||
cf.Data = cfDnskeyData(rec)
|
||||
} else if rec.Type == "DS" {
|
||||
case "DS":
|
||||
cf.Data = cfDSData(rec)
|
||||
} else if rec.Type == "NAPTR" {
|
||||
case "NAPTR":
|
||||
cf.Data = cfNaptrData(rec)
|
||||
cf.Name = rec.GetLabelFQDN()
|
||||
} else if rec.Type == "HTTPS" || rec.Type == "SVCB" {
|
||||
case "HTTPS", "SVCB":
|
||||
cf.Data = cfSvcbData(rec)
|
||||
case "LOC":
|
||||
cf.Data = cfLocData(rec)
|
||||
}
|
||||
resp, err := c.cfClient.CreateDNSRecord(context.Background(), cloudflare.ZoneIdentifier(domainID), cf)
|
||||
if err != nil {
|
||||
|
|
@ -232,33 +254,35 @@ func (c *cloudflareProvider) modifyRecord(domainID, recID string, proxied bool,
|
|||
Priority: &rec.MxPreference,
|
||||
TTL: int(rec.TTL),
|
||||
}
|
||||
if rec.Type == "TXT" {
|
||||
switch rec.Type {
|
||||
case "TXT":
|
||||
r.Content = rec.GetTargetTXTJoined()
|
||||
}
|
||||
if rec.Type == "SRV" {
|
||||
case "SRV":
|
||||
r.Data = cfSrvData(rec)
|
||||
r.Name = rec.GetLabelFQDN()
|
||||
} else if rec.Type == "CAA" {
|
||||
case "CAA":
|
||||
r.Data = cfCaaData(rec)
|
||||
r.Name = rec.GetLabelFQDN()
|
||||
r.Content = ""
|
||||
} else if rec.Type == "TLSA" {
|
||||
case "TLSA":
|
||||
r.Data = cfTlsaData(rec)
|
||||
r.Name = rec.GetLabelFQDN()
|
||||
} else if rec.Type == "SSHFP" {
|
||||
case "SSHFP":
|
||||
r.Data = cfSshfpData(rec)
|
||||
r.Name = rec.GetLabelFQDN()
|
||||
} else if rec.Type == "DNSKEY" {
|
||||
case "DNSKEY":
|
||||
r.Data = cfDnskeyData(rec)
|
||||
r.Content = ""
|
||||
} else if rec.Type == "DS" {
|
||||
case "DS":
|
||||
r.Data = cfDSData(rec)
|
||||
r.Content = ""
|
||||
} else if rec.Type == "NAPTR" {
|
||||
case "NAPTR":
|
||||
r.Data = cfNaptrData(rec)
|
||||
r.Name = rec.GetLabelFQDN()
|
||||
} else if rec.Type == "HTTPS" || rec.Type == "SVCB" {
|
||||
case "HTTPS", "SVCB":
|
||||
r.Data = cfSvcbData(rec)
|
||||
case "LOC":
|
||||
r.Data = cfLocData(rec)
|
||||
}
|
||||
_, err := c.cfClient.UpdateDNSRecord(context.Background(), cloudflare.ZoneIdentifier(domainID), r)
|
||||
return err
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue