package dns
import (
"bytes"
"fmt"
"net"
"strconv"
"strings"
"time"
)
type (
Type uint16
Class uint16
Name string
)
const (
TypeNone uint16 = 0
TypeA uint16 = 1
TypeNS uint16 = 2
TypeMD uint16 = 3
TypeMF uint16 = 4
TypeCNAME uint16 = 5
TypeSOA uint16 = 6
TypeMB uint16 = 7
TypeMG uint16 = 8
TypeMR uint16 = 9
TypeNULL uint16 = 10
TypePTR uint16 = 12
TypeHINFO uint16 = 13
TypeMINFO uint16 = 14
TypeMX uint16 = 15
TypeTXT uint16 = 16
TypeRP uint16 = 17
TypeAFSDB uint16 = 18
TypeX25 uint16 = 19
TypeISDN uint16 = 20
TypeRT uint16 = 21
TypeNSAPPTR uint16 = 23
TypeSIG uint16 = 24
TypeKEY uint16 = 25
TypePX uint16 = 26
TypeGPOS uint16 = 27
TypeAAAA uint16 = 28
TypeLOC uint16 = 29
TypeNXT uint16 = 30
TypeEID uint16 = 31
TypeNIMLOC uint16 = 32
TypeSRV uint16 = 33
TypeATMA uint16 = 34
TypeNAPTR uint16 = 35
TypeKX uint16 = 36
TypeCERT uint16 = 37
TypeDNAME uint16 = 39
TypeOPT uint16 = 41
TypeAPL uint16 = 42
TypeDS uint16 = 43
TypeSSHFP uint16 = 44
TypeIPSECKEY uint16 = 45
TypeRRSIG uint16 = 46
TypeNSEC uint16 = 47
TypeDNSKEY uint16 = 48
TypeDHCID uint16 = 49
TypeNSEC3 uint16 = 50
TypeNSEC3PARAM uint16 = 51
TypeTLSA uint16 = 52
TypeSMIMEA uint16 = 53
TypeHIP uint16 = 55
TypeNINFO uint16 = 56
TypeRKEY uint16 = 57
TypeTALINK uint16 = 58
TypeCDS uint16 = 59
TypeCDNSKEY uint16 = 60
TypeOPENPGPKEY uint16 = 61
TypeCSYNC uint16 = 62
TypeZONEMD uint16 = 63
TypeSVCB uint16 = 64
TypeHTTPS uint16 = 65
TypeSPF uint16 = 99
TypeUINFO uint16 = 100
TypeUID uint16 = 101
TypeGID uint16 = 102
TypeUNSPEC uint16 = 103
TypeNID uint16 = 104
TypeL32 uint16 = 105
TypeL64 uint16 = 106
TypeLP uint16 = 107
TypeEUI48 uint16 = 108
TypeEUI64 uint16 = 109
TypeNXNAME uint16 = 128
TypeURI uint16 = 256
TypeCAA uint16 = 257
TypeAVC uint16 = 258
TypeAMTRELAY uint16 = 260
TypeRESINFO uint16 = 261
TypeTKEY uint16 = 249
TypeTSIG uint16 = 250
TypeIXFR uint16 = 251
TypeAXFR uint16 = 252
TypeMAILB uint16 = 253
TypeMAILA uint16 = 254
TypeANY uint16 = 255
TypeTA uint16 = 32768
TypeDLV uint16 = 32769
TypeReserved uint16 = 65535
ClassINET = 1
ClassCSNET = 2
ClassCHAOS = 3
ClassHESIOD = 4
ClassNONE = 254
ClassANY = 255
RcodeSuccess = 0
RcodeFormatError = 1
RcodeServerFailure = 2
RcodeNameError = 3
RcodeNotImplemented = 4
RcodeRefused = 5
RcodeYXDomain = 6
RcodeYXRrset = 7
RcodeNXRrset = 8
RcodeNotAuth = 9
RcodeNotZone = 10
RcodeStatefulTypeNotImplemented = 11
RcodeBadSig = 16
RcodeBadVers = 16
RcodeBadKey = 17
RcodeBadTime = 18
RcodeBadMode = 19
RcodeBadName = 20
RcodeBadAlg = 21
RcodeBadTrunc = 22
RcodeBadCookie = 23
OpcodeQuery = 0
OpcodeIQuery = 1
OpcodeStatus = 2
OpcodeNotify = 4
OpcodeUpdate = 5
OpcodeStateful = 6
)
const (
ZoneMDSchemeSimple = 1
ZoneMDHashAlgSHA384 = 1
ZoneMDHashAlgSHA512 = 2
)
const (
IPSECGatewayNone uint8 = iota
IPSECGatewayIPv4
IPSECGatewayIPv6
IPSECGatewayHost
)
const (
AMTRELAYNone = IPSECGatewayNone
AMTRELAYIPv4 = IPSECGatewayIPv4
AMTRELAYIPv6 = IPSECGatewayIPv6
AMTRELAYHost = IPSECGatewayHost
)
const (
StatefulTypeKeepAlive uint16 = iota + 1
StatefulTypeRetryDelay
StatefulTypeEncryptionPadding
)
var StatefulTypeToString = map [uint16 ]string {
StatefulTypeKeepAlive : "KeepAlive" ,
StatefulTypeRetryDelay : "RetryDelay" ,
StatefulTypeEncryptionPadding : "EncryptionPadding" ,
}
type Header struct {
Id uint16
Bits uint16
Qdcount, Ancount, Nscount, Arcount uint16
}
const (
headerSize = 12
_QR = 1 << 15
_AA = 1 << 10
_TC = 1 << 9
_RD = 1 << 8
_RA = 1 << 7
_Z = 1 << 6
_AD = 1 << 5
_CD = 1 << 4
)
const (
LOC_EQUATOR = 1 << 31
LOC_PRIMEMERIDIAN = 1 << 31
LOC_HOURS = 60 * 1000
LOC_DEGREES = 60 * LOC_HOURS
LOC_ALTITUDEBASE = 100000
)
const (
CertPKIX = 1 + iota
CertSPKI
CertPGP
CertIPIX
CertISPKI
CertIPGP
CertACPKIX
CertIACPKIX
CertURI = 253
CertOID = 254
)
var CertTypeToString = map [uint16 ]string {
CertPKIX : "PKIX" ,
CertSPKI : "SPKI" ,
CertPGP : "PGP" ,
CertIPIX : "IPIX" ,
CertISPKI : "ISPKI" ,
CertIPGP : "IPGP" ,
CertACPKIX : "ACPKIX" ,
CertIACPKIX : "IACPKIX" ,
CertURI : "URI" ,
CertOID : "OID" ,
}
const ipv4InIPv6Prefix = "::ffff:"
type Question struct {
Name string `dns:"cdomain-name"`
Qtype uint16
Qclass uint16
}
func (q *Question ) len (off int , compression map [string ]struct {}) int {
l := domainNameLen (q .Name , off , compression , true )
l += 2 + 2
return l
}
func (q *Question ) String () (s string ) {
s = ";" + sprintName (q .Name ) + "\t"
s += Class (q .Qclass ).String () + "\t"
s += " " + Type (q .Qtype ).String ()
return s
}
type ANY struct {
Hdr RR_Header
}
func (rr *ANY ) String () string { return rr .Hdr .String () }
func (*ANY ) parse (c *zlexer , origin string ) *ParseError {
return &ParseError {err : "ANY records do not have a presentation format" }
}
type NULL struct {
Hdr RR_Header
Data string `dns:"any"`
}
func (rr *NULL ) String () string {
return ";" + rr .Hdr .String () + rr .Data
}
func (*NULL ) parse (c *zlexer , origin string ) *ParseError {
return &ParseError {err : "NULL records do not have a presentation format" }
}
type NXNAME struct {
Hdr RR_Header
}
func (rr *NXNAME ) String () string { return rr .Hdr .String () }
func (*NXNAME ) parse (c *zlexer , origin string ) *ParseError {
return &ParseError {err : "NXNAME records do not have a presentation format" }
}
type CNAME struct {
Hdr RR_Header
Target string `dns:"cdomain-name"`
}
func (rr *CNAME ) String () string { return rr .Hdr .String () + sprintName (rr .Target ) }
type HINFO struct {
Hdr RR_Header
Cpu string
Os string
}
func (rr *HINFO ) String () string {
return rr .Hdr .String () + sprintTxt ([]string {rr .Cpu , rr .Os })
}
type MB struct {
Hdr RR_Header
Mb string `dns:"cdomain-name"`
}
func (rr *MB ) String () string { return rr .Hdr .String () + sprintName (rr .Mb ) }
type MG struct {
Hdr RR_Header
Mg string `dns:"cdomain-name"`
}
func (rr *MG ) String () string { return rr .Hdr .String () + sprintName (rr .Mg ) }
type MINFO struct {
Hdr RR_Header
Rmail string `dns:"cdomain-name"`
Email string `dns:"cdomain-name"`
}
func (rr *MINFO ) String () string {
return rr .Hdr .String () + sprintName (rr .Rmail ) + " " + sprintName (rr .Email )
}
type MR struct {
Hdr RR_Header
Mr string `dns:"cdomain-name"`
}
func (rr *MR ) String () string {
return rr .Hdr .String () + sprintName (rr .Mr )
}
type MF struct {
Hdr RR_Header
Mf string `dns:"cdomain-name"`
}
func (rr *MF ) String () string {
return rr .Hdr .String () + sprintName (rr .Mf )
}
type MD struct {
Hdr RR_Header
Md string `dns:"cdomain-name"`
}
func (rr *MD ) String () string {
return rr .Hdr .String () + sprintName (rr .Md )
}
type MX struct {
Hdr RR_Header
Preference uint16
Mx string `dns:"cdomain-name"`
}
func (rr *MX ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .Preference )) + " " + sprintName (rr .Mx )
}
type AFSDB struct {
Hdr RR_Header
Subtype uint16
Hostname string `dns:"domain-name"`
}
func (rr *AFSDB ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .Subtype )) + " " + sprintName (rr .Hostname )
}
type X25 struct {
Hdr RR_Header
PSDNAddress string
}
func (rr *X25 ) String () string {
return rr .Hdr .String () + rr .PSDNAddress
}
type ISDN struct {
Hdr RR_Header
Address string
SubAddress string
}
func (rr *ISDN ) String () string {
return rr .Hdr .String () + sprintTxt ([]string {rr .Address , rr .SubAddress })
}
type RT struct {
Hdr RR_Header
Preference uint16
Host string `dns:"domain-name"`
}
func (rr *RT ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .Preference )) + " " + sprintName (rr .Host )
}
type NS struct {
Hdr RR_Header
Ns string `dns:"cdomain-name"`
}
func (rr *NS ) String () string {
return rr .Hdr .String () + sprintName (rr .Ns )
}
type PTR struct {
Hdr RR_Header
Ptr string `dns:"cdomain-name"`
}
func (rr *PTR ) String () string {
return rr .Hdr .String () + sprintName (rr .Ptr )
}
type RP struct {
Hdr RR_Header
Mbox string `dns:"domain-name"`
Txt string `dns:"domain-name"`
}
func (rr *RP ) String () string {
return rr .Hdr .String () + sprintName (rr .Mbox ) + " " + sprintName (rr .Txt )
}
type SOA struct {
Hdr RR_Header
Ns string `dns:"cdomain-name"`
Mbox string `dns:"cdomain-name"`
Serial uint32
Refresh uint32
Retry uint32
Expire uint32
Minttl uint32
}
func (rr *SOA ) String () string {
return rr .Hdr .String () + sprintName (rr .Ns ) + " " + sprintName (rr .Mbox ) +
" " + strconv .FormatInt (int64 (rr .Serial ), 10 ) +
" " + strconv .FormatInt (int64 (rr .Refresh ), 10 ) +
" " + strconv .FormatInt (int64 (rr .Retry ), 10 ) +
" " + strconv .FormatInt (int64 (rr .Expire ), 10 ) +
" " + strconv .FormatInt (int64 (rr .Minttl ), 10 )
}
type TXT struct {
Hdr RR_Header
Txt []string `dns:"txt"`
}
func (rr *TXT ) String () string { return rr .Hdr .String () + sprintTxt (rr .Txt ) }
func sprintName(s string ) string {
var dst strings .Builder
for i := 0 ; i < len (s ); {
if s [i ] == '.' {
if dst .Len () != 0 {
dst .WriteByte ('.' )
}
i ++
continue
}
b , n := nextByte (s , i )
if n == 0 {
if dst .Len () == 0 {
return s [:i ]
}
break
}
if isDomainNameLabelSpecial (b ) {
if dst .Len () == 0 {
dst .Grow (len (s ) * 2 )
dst .WriteString (s [:i ])
}
dst .WriteByte ('\\' )
dst .WriteByte (b )
} else if b < ' ' || b > '~' {
if dst .Len () == 0 {
dst .Grow (len (s ) * 2 )
dst .WriteString (s [:i ])
}
dst .WriteString (escapeByte (b ))
} else {
if dst .Len () != 0 {
dst .WriteByte (b )
}
}
i += n
}
if dst .Len () == 0 {
return s
}
return dst .String ()
}
func sprintTxtOctet(s string ) string {
var dst strings .Builder
dst .Grow (2 + len (s ))
dst .WriteByte ('"' )
for i := 0 ; i < len (s ); {
if i +1 < len (s ) && s [i ] == '\\' && s [i +1 ] == '.' {
dst .WriteString (s [i : i +2 ])
i += 2
continue
}
b , n := nextByte (s , i )
if n == 0 {
i ++
} else {
writeTXTStringByte (&dst , b )
}
i += n
}
dst .WriteByte ('"' )
return dst .String ()
}
func sprintTxt(txt []string ) string {
var out strings .Builder
for i , s := range txt {
out .Grow (3 + len (s ))
if i > 0 {
out .WriteString (` "` )
} else {
out .WriteByte ('"' )
}
for j := 0 ; j < len (s ); {
b , n := nextByte (s , j )
if n == 0 {
break
}
writeTXTStringByte (&out , b )
j += n
}
out .WriteByte ('"' )
}
return out .String ()
}
func writeTXTStringByte(s *strings .Builder , b byte ) {
switch {
case b == '"' || b == '\\' :
s .WriteByte ('\\' )
s .WriteByte (b )
case b < ' ' || b > '~' :
s .WriteString (escapeByte (b ))
default :
s .WriteByte (b )
}
}
const (
escapedByteSmall = "" +
`\000\001\002\003\004\005\006\007\008\009` +
`\010\011\012\013\014\015\016\017\018\019` +
`\020\021\022\023\024\025\026\027\028\029` +
`\030\031`
escapedByteLarge = `\127\128\129` +
`\130\131\132\133\134\135\136\137\138\139` +
`\140\141\142\143\144\145\146\147\148\149` +
`\150\151\152\153\154\155\156\157\158\159` +
`\160\161\162\163\164\165\166\167\168\169` +
`\170\171\172\173\174\175\176\177\178\179` +
`\180\181\182\183\184\185\186\187\188\189` +
`\190\191\192\193\194\195\196\197\198\199` +
`\200\201\202\203\204\205\206\207\208\209` +
`\210\211\212\213\214\215\216\217\218\219` +
`\220\221\222\223\224\225\226\227\228\229` +
`\230\231\232\233\234\235\236\237\238\239` +
`\240\241\242\243\244\245\246\247\248\249` +
`\250\251\252\253\254\255`
)
func escapeByte(b byte ) string {
if b < ' ' {
return escapedByteSmall [b *4 : b *4 +4 ]
}
b -= '~' + 1
return escapedByteLarge [int (b )*4 : int (b )*4 +4 ]
}
func isDomainNameLabelSpecial(b byte ) bool {
switch b {
case '.' , ' ' , '\'' , '@' , ';' , '(' , ')' , '"' , '\\' :
return true
}
return false
}
func nextByte(s string , offset int ) (byte , int ) {
if offset >= len (s ) {
return 0 , 0
}
if s [offset ] != '\\' {
return s [offset ], 1
}
switch len (s ) - offset {
case 1 :
return 0 , 0
case 2 , 3 :
default :
if isDDD (s [offset +1 :]) {
return dddToByte (s [offset +1 :]), 4
}
}
return s [offset +1 ], 2
}
type SPF struct {
Hdr RR_Header
Txt []string `dns:"txt"`
}
func (rr *SPF ) String () string { return rr .Hdr .String () + sprintTxt (rr .Txt ) }
type AVC struct {
Hdr RR_Header
Txt []string `dns:"txt"`
}
func (rr *AVC ) String () string { return rr .Hdr .String () + sprintTxt (rr .Txt ) }
type SRV struct {
Hdr RR_Header
Priority uint16
Weight uint16
Port uint16
Target string `dns:"domain-name"`
}
func (rr *SRV ) String () string {
return rr .Hdr .String () +
strconv .Itoa (int (rr .Priority )) + " " +
strconv .Itoa (int (rr .Weight )) + " " +
strconv .Itoa (int (rr .Port )) + " " + sprintName (rr .Target )
}
type NAPTR struct {
Hdr RR_Header
Order uint16
Preference uint16
Flags string
Service string
Regexp string
Replacement string `dns:"domain-name"`
}
func (rr *NAPTR ) String () string {
return rr .Hdr .String () +
strconv .Itoa (int (rr .Order )) + " " +
strconv .Itoa (int (rr .Preference )) + " " +
"\"" + rr .Flags + "\" " +
"\"" + rr .Service + "\" " +
"\"" + rr .Regexp + "\" " +
rr .Replacement
}
type CERT struct {
Hdr RR_Header
Type uint16
KeyTag uint16
Algorithm uint8
Certificate string `dns:"base64"`
}
func (rr *CERT ) String () string {
var (
ok bool
certtype , algorithm string
)
if certtype , ok = CertTypeToString [rr .Type ]; !ok {
certtype = strconv .Itoa (int (rr .Type ))
}
if algorithm , ok = AlgorithmToString [rr .Algorithm ]; !ok {
algorithm = strconv .Itoa (int (rr .Algorithm ))
}
return rr .Hdr .String () + certtype +
" " + strconv .Itoa (int (rr .KeyTag )) +
" " + algorithm +
" " + rr .Certificate
}
type DNAME struct {
Hdr RR_Header
Target string `dns:"domain-name"`
}
func (rr *DNAME ) String () string {
return rr .Hdr .String () + sprintName (rr .Target )
}
type A struct {
Hdr RR_Header
A net .IP `dns:"a"`
}
func (rr *A ) String () string {
if rr .A == nil {
return rr .Hdr .String ()
}
return rr .Hdr .String () + rr .A .String ()
}
type AAAA struct {
Hdr RR_Header
AAAA net .IP `dns:"aaaa"`
}
func (rr *AAAA ) String () string {
if rr .AAAA == nil {
return rr .Hdr .String ()
}
if rr .AAAA .To4 () != nil {
return rr .Hdr .String () + ipv4InIPv6Prefix + rr .AAAA .String ()
}
return rr .Hdr .String () + rr .AAAA .String ()
}
type PX struct {
Hdr RR_Header
Preference uint16
Map822 string `dns:"domain-name"`
Mapx400 string `dns:"domain-name"`
}
func (rr *PX ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .Preference )) + " " + sprintName (rr .Map822 ) + " " + sprintName (rr .Mapx400 )
}
type GPOS struct {
Hdr RR_Header
Longitude string
Latitude string
Altitude string
}
func (rr *GPOS ) String () string {
return rr .Hdr .String () + rr .Longitude + " " + rr .Latitude + " " + rr .Altitude
}
type LOC struct {
Hdr RR_Header
Version uint8
Size uint8
HorizPre uint8
VertPre uint8
Latitude uint32
Longitude uint32
Altitude uint32
}
func cmToM(x uint8 ) string {
m := x & 0xf0 >> 4
e := x & 0x0f
if e < 2 {
if e == 1 {
m *= 10
}
return fmt .Sprintf ("0.%02d" , m )
}
s := fmt .Sprintf ("%d" , m )
for e > 2 {
s += "0"
e --
}
return s
}
func (rr *LOC ) String () string {
s := rr .Hdr .String ()
lat := rr .Latitude
ns := "N"
if lat > LOC_EQUATOR {
lat = lat - LOC_EQUATOR
} else {
ns = "S"
lat = LOC_EQUATOR - lat
}
h := lat / LOC_DEGREES
lat = lat % LOC_DEGREES
m := lat / LOC_HOURS
lat = lat % LOC_HOURS
s += fmt .Sprintf ("%02d %02d %0.3f %s " , h , m , float64 (lat )/1000 , ns )
lon := rr .Longitude
ew := "E"
if lon > LOC_PRIMEMERIDIAN {
lon = lon - LOC_PRIMEMERIDIAN
} else {
ew = "W"
lon = LOC_PRIMEMERIDIAN - lon
}
h = lon / LOC_DEGREES
lon = lon % LOC_DEGREES
m = lon / LOC_HOURS
lon = lon % LOC_HOURS
s += fmt .Sprintf ("%02d %02d %0.3f %s " , h , m , float64 (lon )/1000 , ew )
alt := float64 (rr .Altitude ) / 100
alt -= LOC_ALTITUDEBASE
if rr .Altitude %100 != 0 {
s += fmt .Sprintf ("%.2fm " , alt )
} else {
s += fmt .Sprintf ("%.0fm " , alt )
}
s += cmToM (rr .Size ) + "m "
s += cmToM (rr .HorizPre ) + "m "
s += cmToM (rr .VertPre ) + "m"
return s
}
type SIG struct {
RRSIG
}
type RRSIG struct {
Hdr RR_Header
TypeCovered uint16
Algorithm uint8
Labels uint8
OrigTtl uint32
Expiration uint32
Inception uint32
KeyTag uint16
SignerName string `dns:"domain-name"`
Signature string `dns:"base64"`
}
func (rr *RRSIG ) String () string {
s := rr .Hdr .String ()
s += Type (rr .TypeCovered ).String ()
s += " " + strconv .Itoa (int (rr .Algorithm )) +
" " + strconv .Itoa (int (rr .Labels )) +
" " + strconv .FormatInt (int64 (rr .OrigTtl ), 10 ) +
" " + TimeToString (rr .Expiration ) +
" " + TimeToString (rr .Inception ) +
" " + strconv .Itoa (int (rr .KeyTag )) +
" " + sprintName (rr .SignerName ) +
" " + rr .Signature
return s
}
type NXT struct {
NSEC
}
type NSEC struct {
Hdr RR_Header
NextDomain string `dns:"domain-name"`
TypeBitMap []uint16 `dns:"nsec"`
}
func (rr *NSEC ) String () string {
s := rr .Hdr .String () + sprintName (rr .NextDomain )
for _ , t := range rr .TypeBitMap {
s += " " + Type (t ).String ()
}
return s
}
func (rr *NSEC ) len (off int , compression map [string ]struct {}) int {
l := rr .Hdr .len (off , compression )
l += domainNameLen (rr .NextDomain , off +l , compression , false )
l += typeBitMapLen (rr .TypeBitMap )
return l
}
type DLV struct { DS }
type CDS struct { DS }
type DS struct {
Hdr RR_Header
KeyTag uint16
Algorithm uint8
DigestType uint8
Digest string `dns:"hex"`
}
func (rr *DS ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .KeyTag )) +
" " + strconv .Itoa (int (rr .Algorithm )) +
" " + strconv .Itoa (int (rr .DigestType )) +
" " + strings .ToUpper (rr .Digest )
}
type KX struct {
Hdr RR_Header
Preference uint16
Exchanger string `dns:"domain-name"`
}
func (rr *KX ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .Preference )) +
" " + sprintName (rr .Exchanger )
}
type TA struct {
Hdr RR_Header
KeyTag uint16
Algorithm uint8
DigestType uint8
Digest string `dns:"hex"`
}
func (rr *TA ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .KeyTag )) +
" " + strconv .Itoa (int (rr .Algorithm )) +
" " + strconv .Itoa (int (rr .DigestType )) +
" " + strings .ToUpper (rr .Digest )
}
type TALINK struct {
Hdr RR_Header
PreviousName string `dns:"domain-name"`
NextName string `dns:"domain-name"`
}
func (rr *TALINK ) String () string {
return rr .Hdr .String () +
sprintName (rr .PreviousName ) + " " + sprintName (rr .NextName )
}
type SSHFP struct {
Hdr RR_Header
Algorithm uint8
Type uint8
FingerPrint string `dns:"hex"`
}
func (rr *SSHFP ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .Algorithm )) +
" " + strconv .Itoa (int (rr .Type )) +
" " + strings .ToUpper (rr .FingerPrint )
}
type KEY struct {
DNSKEY
}
type CDNSKEY struct {
DNSKEY
}
type DNSKEY struct {
Hdr RR_Header
Flags uint16
Protocol uint8
Algorithm uint8
PublicKey string `dns:"base64"`
}
func (rr *DNSKEY ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .Flags )) +
" " + strconv .Itoa (int (rr .Protocol )) +
" " + strconv .Itoa (int (rr .Algorithm )) +
" " + rr .PublicKey
}
type IPSECKEY struct {
Hdr RR_Header
Precedence uint8
GatewayType uint8
Algorithm uint8
GatewayAddr net .IP `dns:"-"`
GatewayHost string `dns:"ipsechost"`
PublicKey string `dns:"base64"`
}
func (rr *IPSECKEY ) String () string {
var gateway string
switch rr .GatewayType {
case IPSECGatewayIPv4 , IPSECGatewayIPv6 :
gateway = rr .GatewayAddr .String ()
case IPSECGatewayHost :
gateway = rr .GatewayHost
case IPSECGatewayNone :
fallthrough
default :
gateway = "."
}
return rr .Hdr .String () + strconv .Itoa (int (rr .Precedence )) +
" " + strconv .Itoa (int (rr .GatewayType )) +
" " + strconv .Itoa (int (rr .Algorithm )) +
" " + gateway +
" " + rr .PublicKey
}
type AMTRELAY struct {
Hdr RR_Header
Precedence uint8
GatewayType uint8
GatewayAddr net .IP `dns:"-"`
GatewayHost string `dns:"amtrelayhost"`
}
func (rr *AMTRELAY ) String () string {
var gateway string
switch rr .GatewayType & 0x7f {
case AMTRELAYIPv4 , AMTRELAYIPv6 :
gateway = rr .GatewayAddr .String ()
case AMTRELAYHost :
gateway = rr .GatewayHost
case AMTRELAYNone :
fallthrough
default :
gateway = "."
}
boolS := "0"
if rr .GatewayType &0x80 == 0x80 {
boolS = "1"
}
return rr .Hdr .String () + strconv .Itoa (int (rr .Precedence )) +
" " + boolS +
" " + strconv .Itoa (int (rr .GatewayType &0x7f )) +
" " + gateway
}
type RKEY struct {
Hdr RR_Header
Flags uint16
Protocol uint8
Algorithm uint8
PublicKey string `dns:"base64"`
}
func (rr *RKEY ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .Flags )) +
" " + strconv .Itoa (int (rr .Protocol )) +
" " + strconv .Itoa (int (rr .Algorithm )) +
" " + rr .PublicKey
}
type NSAPPTR struct {
Hdr RR_Header
Ptr string `dns:"domain-name"`
}
func (rr *NSAPPTR ) String () string { return rr .Hdr .String () + sprintName (rr .Ptr ) }
type NSEC3 struct {
Hdr RR_Header
Hash uint8
Flags uint8
Iterations uint16
SaltLength uint8
Salt string `dns:"size-hex:SaltLength"`
HashLength uint8
NextDomain string `dns:"size-base32:HashLength"`
TypeBitMap []uint16 `dns:"nsec"`
}
func (rr *NSEC3 ) String () string {
s := rr .Hdr .String ()
s += strconv .Itoa (int (rr .Hash )) +
" " + strconv .Itoa (int (rr .Flags )) +
" " + strconv .Itoa (int (rr .Iterations )) +
" " + saltToString (rr .Salt ) +
" " + rr .NextDomain
for _ , t := range rr .TypeBitMap {
s += " " + Type (t ).String ()
}
return s
}
func (rr *NSEC3 ) len (off int , compression map [string ]struct {}) int {
l := rr .Hdr .len (off , compression )
l += 6 + len (rr .Salt )/2 + 1 + len (rr .NextDomain ) + 1
l += typeBitMapLen (rr .TypeBitMap )
return l
}
type NSEC3PARAM struct {
Hdr RR_Header
Hash uint8
Flags uint8
Iterations uint16
SaltLength uint8
Salt string `dns:"size-hex:SaltLength"`
}
func (rr *NSEC3PARAM ) String () string {
s := rr .Hdr .String ()
s += strconv .Itoa (int (rr .Hash )) +
" " + strconv .Itoa (int (rr .Flags )) +
" " + strconv .Itoa (int (rr .Iterations )) +
" " + saltToString (rr .Salt )
return s
}
type TKEY struct {
Hdr RR_Header
Algorithm string `dns:"domain-name"`
Inception uint32
Expiration uint32
Mode uint16
Error uint16
KeySize uint16
Key string `dns:"size-hex:KeySize"`
OtherLen uint16
OtherData string `dns:"size-hex:OtherLen"`
}
func (rr *TKEY ) String () string {
s := ";" + rr .Hdr .String () +
" " + rr .Algorithm +
" " + TimeToString (rr .Inception ) +
" " + TimeToString (rr .Expiration ) +
" " + strconv .Itoa (int (rr .Mode )) +
" " + strconv .Itoa (int (rr .Error )) +
" " + strconv .Itoa (int (rr .KeySize )) +
" " + rr .Key +
" " + strconv .Itoa (int (rr .OtherLen )) +
" " + rr .OtherData
return s
}
type RFC3597 struct {
Hdr RR_Header
Rdata string `dns:"hex"`
}
func (rr *RFC3597 ) String () string {
s := rfc3597Header (rr .Hdr )
s += "\\# " + strconv .Itoa (len (rr .Rdata )/2 ) + " " + rr .Rdata
return s
}
func rfc3597Header(h RR_Header ) string {
var s string
s += sprintName (h .Name ) + "\t"
s += strconv .FormatInt (int64 (h .Ttl ), 10 ) + "\t"
s += "CLASS" + strconv .Itoa (int (h .Class )) + "\t"
s += "TYPE" + strconv .Itoa (int (h .Rrtype )) + "\t"
return s
}
type URI struct {
Hdr RR_Header
Priority uint16
Weight uint16
Target string `dns:"octet"`
}
func (rr *URI ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .Priority )) +
" " + strconv .Itoa (int (rr .Weight )) + " " + sprintTxtOctet (rr .Target )
}
type DHCID struct {
Hdr RR_Header
Digest string `dns:"base64"`
}
func (rr *DHCID ) String () string { return rr .Hdr .String () + rr .Digest }
type TLSA struct {
Hdr RR_Header
Usage uint8
Selector uint8
MatchingType uint8
Certificate string `dns:"hex"`
}
func (rr *TLSA ) String () string {
return rr .Hdr .String () +
strconv .Itoa (int (rr .Usage )) +
" " + strconv .Itoa (int (rr .Selector )) +
" " + strconv .Itoa (int (rr .MatchingType )) +
" " + rr .Certificate
}
type SMIMEA struct {
Hdr RR_Header
Usage uint8
Selector uint8
MatchingType uint8
Certificate string `dns:"hex"`
}
func (rr *SMIMEA ) String () string {
s := rr .Hdr .String () +
strconv .Itoa (int (rr .Usage )) +
" " + strconv .Itoa (int (rr .Selector )) +
" " + strconv .Itoa (int (rr .MatchingType ))
sx := splitN (rr .Certificate , 1024 )
s += " " + strings .Join (sx , " " )
return s
}
type HIP struct {
Hdr RR_Header
HitLength uint8
PublicKeyAlgorithm uint8
PublicKeyLength uint16
Hit string `dns:"size-hex:HitLength"`
PublicKey string `dns:"size-base64:PublicKeyLength"`
RendezvousServers []string `dns:"domain-name"`
}
func (rr *HIP ) String () string {
s := rr .Hdr .String () +
strconv .Itoa (int (rr .PublicKeyAlgorithm )) +
" " + rr .Hit +
" " + rr .PublicKey
for _ , d := range rr .RendezvousServers {
s += " " + sprintName (d )
}
return s
}
type NINFO struct {
Hdr RR_Header
ZSData []string `dns:"txt"`
}
func (rr *NINFO ) String () string { return rr .Hdr .String () + sprintTxt (rr .ZSData ) }
type NID struct {
Hdr RR_Header
Preference uint16
NodeID uint64
}
func (rr *NID ) String () string {
s := rr .Hdr .String () + strconv .Itoa (int (rr .Preference ))
node := fmt .Sprintf ("%0.16x" , rr .NodeID )
s += " " + node [0 :4 ] + ":" + node [4 :8 ] + ":" + node [8 :12 ] + ":" + node [12 :16 ]
return s
}
type L32 struct {
Hdr RR_Header
Preference uint16
Locator32 net .IP `dns:"a"`
}
func (rr *L32 ) String () string {
if rr .Locator32 == nil {
return rr .Hdr .String () + strconv .Itoa (int (rr .Preference ))
}
return rr .Hdr .String () + strconv .Itoa (int (rr .Preference )) +
" " + rr .Locator32 .String ()
}
type L64 struct {
Hdr RR_Header
Preference uint16
Locator64 uint64
}
func (rr *L64 ) String () string {
s := rr .Hdr .String () + strconv .Itoa (int (rr .Preference ))
node := fmt .Sprintf ("%0.16X" , rr .Locator64 )
s += " " + node [0 :4 ] + ":" + node [4 :8 ] + ":" + node [8 :12 ] + ":" + node [12 :16 ]
return s
}
type LP struct {
Hdr RR_Header
Preference uint16
Fqdn string `dns:"domain-name"`
}
func (rr *LP ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .Preference )) + " " + sprintName (rr .Fqdn )
}
type EUI48 struct {
Hdr RR_Header
Address uint64 `dns:"uint48"`
}
func (rr *EUI48 ) String () string { return rr .Hdr .String () + euiToString (rr .Address , 48 ) }
type EUI64 struct {
Hdr RR_Header
Address uint64
}
func (rr *EUI64 ) String () string { return rr .Hdr .String () + euiToString (rr .Address , 64 ) }
type CAA struct {
Hdr RR_Header
Flag uint8
Tag string
Value string `dns:"octet"`
}
func (rr *CAA ) String () string {
return rr .Hdr .String () + strconv .Itoa (int (rr .Flag )) + " " + rr .Tag + " " + sprintTxtOctet (rr .Value )
}
type UID struct {
Hdr RR_Header
Uid uint32
}
func (rr *UID ) String () string { return rr .Hdr .String () + strconv .FormatInt (int64 (rr .Uid ), 10 ) }
type GID struct {
Hdr RR_Header
Gid uint32
}
func (rr *GID ) String () string { return rr .Hdr .String () + strconv .FormatInt (int64 (rr .Gid ), 10 ) }
type UINFO struct {
Hdr RR_Header
Uinfo string
}
func (rr *UINFO ) String () string { return rr .Hdr .String () + sprintTxt ([]string {rr .Uinfo }) }
type EID struct {
Hdr RR_Header
Endpoint string `dns:"hex"`
}
func (rr *EID ) String () string { return rr .Hdr .String () + strings .ToUpper (rr .Endpoint ) }
type NIMLOC struct {
Hdr RR_Header
Locator string `dns:"hex"`
}
func (rr *NIMLOC ) String () string { return rr .Hdr .String () + strings .ToUpper (rr .Locator ) }
type OPENPGPKEY struct {
Hdr RR_Header
PublicKey string `dns:"base64"`
}
func (rr *OPENPGPKEY ) String () string { return rr .Hdr .String () + rr .PublicKey }
type CSYNC struct {
Hdr RR_Header
Serial uint32
Flags uint16
TypeBitMap []uint16 `dns:"nsec"`
}
func (rr *CSYNC ) String () string {
s := rr .Hdr .String () + strconv .FormatInt (int64 (rr .Serial ), 10 ) + " " + strconv .Itoa (int (rr .Flags ))
for _ , t := range rr .TypeBitMap {
s += " " + Type (t ).String ()
}
return s
}
func (rr *CSYNC ) len (off int , compression map [string ]struct {}) int {
l := rr .Hdr .len (off , compression )
l += 4 + 2
l += typeBitMapLen (rr .TypeBitMap )
return l
}
type ZONEMD struct {
Hdr RR_Header
Serial uint32
Scheme uint8
Hash uint8
Digest string `dns:"hex"`
}
func (rr *ZONEMD ) String () string {
return rr .Hdr .String () +
strconv .Itoa (int (rr .Serial )) +
" " + strconv .Itoa (int (rr .Scheme )) +
" " + strconv .Itoa (int (rr .Hash )) +
" " + rr .Digest
}
type RESINFO struct {
Hdr RR_Header
Txt []string `dns:"txt"`
}
func (rr *RESINFO ) String () string { return rr .Hdr .String () + sprintTxt (rr .Txt ) }
type APL struct {
Hdr RR_Header
Prefixes []APLPrefix `dns:"apl"`
}
type APLPrefix struct {
Negation bool
Network net .IPNet
}
func (rr *APL ) String () string {
var sb strings .Builder
sb .WriteString (rr .Hdr .String ())
for i , p := range rr .Prefixes {
if i > 0 {
sb .WriteByte (' ' )
}
sb .WriteString (p .str ())
}
return sb .String ()
}
func (a *APLPrefix ) str () string {
var sb strings .Builder
if a .Negation {
sb .WriteByte ('!' )
}
switch len (a .Network .IP ) {
case net .IPv4len :
sb .WriteByte ('1' )
case net .IPv6len :
sb .WriteByte ('2' )
}
sb .WriteByte (':' )
switch len (a .Network .IP ) {
case net .IPv4len :
sb .WriteString (a .Network .IP .String ())
case net .IPv6len :
if v4 := a .Network .IP .To4 (); v4 != nil {
sb .WriteString (ipv4InIPv6Prefix )
}
sb .WriteString (a .Network .IP .String ())
}
sb .WriteByte ('/' )
prefix , _ := a .Network .Mask .Size ()
sb .WriteString (strconv .Itoa (prefix ))
return sb .String ()
}
func (a *APLPrefix ) equals (b *APLPrefix ) bool {
return a .Negation == b .Negation &&
a .Network .IP .Equal (b .Network .IP ) &&
bytes .Equal (a .Network .Mask , b .Network .Mask )
}
func (a *APLPrefix ) copy () APLPrefix {
return APLPrefix {
Negation : a .Negation ,
Network : copyNet (a .Network ),
}
}
func (a *APLPrefix ) len () int {
prefix , _ := a .Network .Mask .Size ()
return 4 + (prefix +7 )/8
}
func TimeToString (t uint32 ) string {
mod := (int64 (t )-time .Now ().Unix ())/year68 - 1
if mod < 0 {
mod = 0
}
ti := time .Unix (int64 (t )-mod *year68 , 0 ).UTC ()
return ti .Format ("20060102150405" )
}
func StringToTime (s string ) (uint32 , error ) {
t , err := time .Parse ("20060102150405" , s )
if err != nil {
return 0 , err
}
mod := t .Unix ()/year68 - 1
if mod < 0 {
mod = 0
}
return uint32 (t .Unix () - mod *year68 ), nil
}
func saltToString(s string ) string {
if s == "" {
return "-"
}
return strings .ToUpper (s )
}
func euiToString(eui uint64 , bits int ) (hex string ) {
switch bits {
case 64 :
hex = fmt .Sprintf ("%16.16x" , eui )
hex = hex [0 :2 ] + "-" + hex [2 :4 ] + "-" + hex [4 :6 ] + "-" + hex [6 :8 ] +
"-" + hex [8 :10 ] + "-" + hex [10 :12 ] + "-" + hex [12 :14 ] + "-" + hex [14 :16 ]
case 48 :
hex = fmt .Sprintf ("%12.12x" , eui )
hex = hex [0 :2 ] + "-" + hex [2 :4 ] + "-" + hex [4 :6 ] + "-" + hex [6 :8 ] +
"-" + hex [8 :10 ] + "-" + hex [10 :12 ]
}
return
}
func cloneSlice[E any , S ~[]E ](s S ) S {
if s == nil {
return nil
}
return append (S (nil ), s ...)
}
func copyNet(n net .IPNet ) net .IPNet {
return net .IPNet {
IP : cloneSlice (n .IP ),
Mask : cloneSlice (n .Mask ),
}
}
func splitN(s string , n int ) []string {
if len (s ) < n {
return []string {s }
}
sx := []string {}
p , i := 0 , n
for {
if i <= len (s ) {
sx = append (sx , s [p :i ])
} else {
sx = append (sx , s [p :])
break
}
p , i = p +n , i +n
}
return sx
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .