Implement IPSECKEY
IPSECKEY is kinda strange because it has a type selector which tells what type a later rdata field has. The type can be a domainname, address or v6 address. You sort of wish Go would have a union type for this, but alas. Currently this is implemented as: GatewayA net.IP `dns:"a"` GatewayAAAA net.IP `dns:"aaaa"` GatewayName string `dns:"domain-name"` In the IPSECKEY. Only one of these is active at any one time. When parsing/packing and unpacking the value of GatewayType is checked to see what to do. Parsing from strings is also implemented properly and tested. The Unpack function still needs work.
This commit is contained in:
parent
3fcd28bab1
commit
477cb4d3fa
|
@ -96,7 +96,8 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
|
|||
* 3225 - DO bit (DNSSEC OK)
|
||||
* 340{1,2,3} - NAPTR record
|
||||
* 3445 - Limiting the scope of (DNS)KEY
|
||||
* 3597 - Unkown RRs
|
||||
* 3597 - Unknown RRs
|
||||
* 4025 - IPSECKEY
|
||||
* 403{3,4,5} - DNSSEC + validation functions
|
||||
* 4255 - SSHFP record
|
||||
* 4343 - Case insensitivity
|
||||
|
|
14
dns_test.go
14
dns_test.go
|
@ -509,3 +509,17 @@ func TestCopy(t *testing.T) {
|
|||
t.Fatalf("Copy() failed %s != %s", rr.String(), rr1.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackIPSECKEY(t *testing.T) {
|
||||
// TODO(miek): finish
|
||||
tests := []string{
|
||||
"38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.3 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"38.1.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0 7200 IN IPSECKEY ( 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
}
|
||||
buf := make([]byte, 1024)
|
||||
rr, _ := NewRR(tests[0])
|
||||
PackRR(rr, buf, 0, nil, false)
|
||||
}
|
||||
|
|
19
msg.go
19
msg.go
|
@ -652,6 +652,12 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
|
|||
off += len(b)
|
||||
}
|
||||
case `dns:"a"`:
|
||||
if val.Type().String() == "dns.IPSECKEY" {
|
||||
// Field(2) is GatewayType, must be 1
|
||||
if val.Field(2).Uint() != 1 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
// It must be a slice of 4, even if it is 16, we encode
|
||||
// only the first 4
|
||||
if off+net.IPv4len > lenmsg {
|
||||
|
@ -676,6 +682,12 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
|
|||
return lenmsg, &Error{err: "overflow packing a"}
|
||||
}
|
||||
case `dns:"aaaa"`:
|
||||
if val.Type().String() == "dns.IPSECKEY" {
|
||||
// Field(2) is GatewayType, must be 2
|
||||
if val.Field(2).Uint() != 2 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if fv.Len() == 0 {
|
||||
break
|
||||
}
|
||||
|
@ -821,6 +833,13 @@ func packStructValue(val reflect.Value, msg []byte, off int, compression map[str
|
|||
copy(msg[off:off+len(b64)], b64)
|
||||
off += len(b64)
|
||||
case `dns:"domain-name"`:
|
||||
if val.Type().String() == "dns.IPSECKEY" {
|
||||
// Field(2) is GatewayType, 1 and 2 or used for addresses
|
||||
x := val.Field(2).Uint()
|
||||
if x == 1 || x == 2 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if off, err = PackDomainName(s, msg, off, compression, false && compress); err != nil {
|
||||
return lenmsg, err
|
||||
}
|
||||
|
|
|
@ -1373,3 +1373,37 @@ func TestPrintfVerbsRdata(t *testing.T) {
|
|||
t.Errorf("should be empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseIPSECKEY(t *testing.T) {
|
||||
tests := []string{
|
||||
"38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"38.2.0.192.in-addr.arpa.\t7200\tIN\tIPSECKEY\t10 1 2 192.0.2.38 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==",
|
||||
|
||||
"38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"38.2.0.192.in-addr.arpa.\t7200\tIN\tIPSECKEY\t10 0 2 . AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==",
|
||||
|
||||
"38.2.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 1 2 192.0.2.3 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"38.2.0.192.in-addr.arpa.\t7200\tIN\tIPSECKEY\t10 1 2 192.0.2.3 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==",
|
||||
|
||||
"38.1.0.192.in-addr.arpa. 7200 IN IPSECKEY ( 10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"38.1.0.192.in-addr.arpa.\t7200\tIN\tIPSECKEY\t10 3 2 mygateway.example.com. AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==",
|
||||
|
||||
"0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0 7200 IN IPSECKEY ( 10 2 2 2001:0DB8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ== )",
|
||||
"0.d.4.0.3.0.e.f.f.f.3.f.0.1.2.0.\t7200\tIN\tIPSECKEY\t10 2 2 2001:db8:0:8002::2000:1 AQNRU3mG7TVTO2BkR47usntb102uFJtugbo6BSGvgqt4AQ==",
|
||||
}
|
||||
for i := 0; i < len(tests)-1; i++ {
|
||||
t1 := tests[i]
|
||||
e1 := tests[i+1]
|
||||
r, e := NewRR(t1)
|
||||
if e != nil {
|
||||
t.Logf("failed to parse IPSECKEY %s", e)
|
||||
continue
|
||||
}
|
||||
if r.String() != e1 {
|
||||
t.Logf("these two IPSECKEY records should match")
|
||||
t.Logf("\n%s\n%s\n", r.String(), e1)
|
||||
t.Fail()
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
|
45
types.go
45
types.go
|
@ -1031,28 +1031,57 @@ func (rr *SSHFP) String() string {
|
|||
type IPSECKEY struct {
|
||||
Hdr RR_Header
|
||||
Precedence uint8
|
||||
// GatewayType: 1: A record, 2: AAAA record, 3: domainname.
|
||||
// 0 is use for no type and GatewayName should be "." then.
|
||||
GatewayType uint8
|
||||
Algorithm uint8
|
||||
Gateway string `dns:"ipseckey"`
|
||||
// Gateway can be an A record, AAAA record or a domain name.
|
||||
GatewayA net.IP `dns:"a"`
|
||||
GatewayAAAA net.IP `dns:"aaaa"`
|
||||
GatewayName string `dns:"domain-name"`
|
||||
PublicKey string `dns:"base64"`
|
||||
}
|
||||
|
||||
func (rr *IPSECKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *IPSECKEY) copy() RR {
|
||||
return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, rr.Gateway, rr.PublicKey}
|
||||
return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, rr.GatewayA, rr.GatewayAAAA, rr.GatewayName, rr.PublicKey}
|
||||
}
|
||||
|
||||
func (rr *IPSECKEY) String() string {
|
||||
return rr.Hdr.String() + strconv.Itoa(int(rr.Precedence)) +
|
||||
s := rr.Hdr.String() + strconv.Itoa(int(rr.Precedence)) +
|
||||
" " + strconv.Itoa(int(rr.GatewayType)) +
|
||||
" " + strconv.Itoa(int(rr.Algorithm)) +
|
||||
" " + rr.Gateway +
|
||||
" " + rr.PublicKey
|
||||
" " + strconv.Itoa(int(rr.Algorithm))
|
||||
switch rr.GatewayType {
|
||||
case 0:
|
||||
fallthrough
|
||||
case 3:
|
||||
s += " " + rr.GatewayName
|
||||
case 1:
|
||||
s += " " + rr.GatewayA.String()
|
||||
case 2:
|
||||
s += " " + rr.GatewayAAAA.String()
|
||||
default:
|
||||
s += " ."
|
||||
}
|
||||
s += " " + rr.PublicKey
|
||||
return s
|
||||
}
|
||||
|
||||
func (rr *IPSECKEY) len() int {
|
||||
return rr.Hdr.len() + 3 + len(rr.Gateway) + 1 +
|
||||
base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
l := rr.Hdr.len() + 3 + 1
|
||||
switch rr.GatewayType {
|
||||
default:
|
||||
fallthrough
|
||||
case 0:
|
||||
fallthrough
|
||||
case 3:
|
||||
l += len(rr.GatewayName)
|
||||
case 1:
|
||||
l += 4
|
||||
case 2:
|
||||
l += 16
|
||||
}
|
||||
return l + base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
}
|
||||
|
||||
type KEY struct {
|
||||
|
|
105
zscan_rr.go
105
zscan_rr.go
|
@ -1847,44 +1847,6 @@ func setURI(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
|||
return rr, nil, c1
|
||||
}
|
||||
|
||||
func setIPSECKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||
rr := new(IPSECKEY)
|
||||
rr.Hdr = h
|
||||
|
||||
l := <-c
|
||||
if l.length == 0 {
|
||||
return rr, nil, l.comment
|
||||
}
|
||||
if i, e := strconv.Atoi(l.token); e != nil {
|
||||
return nil, &ParseError{f, "bad IPSECKEY Precedence", l}, ""
|
||||
} else {
|
||||
rr.Precedence = uint8(i)
|
||||
}
|
||||
<-c // _BLANK
|
||||
l = <-c
|
||||
if i, e := strconv.Atoi(l.token); e != nil {
|
||||
return nil, &ParseError{f, "bad IPSECKEY GatewayType", l}, ""
|
||||
} else {
|
||||
rr.GatewayType = uint8(i)
|
||||
}
|
||||
<-c // _BLANK
|
||||
l = <-c
|
||||
if i, e := strconv.Atoi(l.token); e != nil {
|
||||
return nil, &ParseError{f, "bad IPSECKEY Algorithm", l}, ""
|
||||
} else {
|
||||
rr.Algorithm = uint8(i)
|
||||
}
|
||||
<-c
|
||||
l = <-c
|
||||
rr.Gateway = l.token
|
||||
s, e, c1 := endingToString(c, "bad IPSECKEY PublicKey", f)
|
||||
if e != nil {
|
||||
return nil, e, c1
|
||||
}
|
||||
rr.PublicKey = s
|
||||
return rr, nil, c1
|
||||
}
|
||||
|
||||
func setDHCID(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||
// awesome record to parse!
|
||||
rr := new(DHCID)
|
||||
|
@ -2087,6 +2049,73 @@ func setPX(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
|||
return rr, nil, ""
|
||||
}
|
||||
|
||||
func setIPSECKEY(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||
rr := new(IPSECKEY)
|
||||
rr.Hdr = h
|
||||
l := <-c
|
||||
if l.length == 0 {
|
||||
return rr, nil, l.comment
|
||||
}
|
||||
if i, err := strconv.Atoi(l.token); err != nil {
|
||||
return nil, &ParseError{f, "bad IPSECKEY Precedence", l}, ""
|
||||
} else {
|
||||
rr.Precedence = uint8(i)
|
||||
}
|
||||
<-c // _BLANK
|
||||
l = <-c
|
||||
if i, err := strconv.Atoi(l.token); err != nil {
|
||||
return nil, &ParseError{f, "bad IPSECKEY GatewayType", l}, ""
|
||||
} else {
|
||||
rr.GatewayType = uint8(i)
|
||||
}
|
||||
<-c // _BLANK
|
||||
l = <-c
|
||||
if i, err := strconv.Atoi(l.token); err != nil {
|
||||
return nil, &ParseError{f, "bad IPSECKEY Algorithm", l}, ""
|
||||
} else {
|
||||
rr.Algorithm = uint8(i)
|
||||
}
|
||||
|
||||
// Now according to GatewayType we can have different elements here
|
||||
<-c // _BLANK
|
||||
l = <-c
|
||||
switch rr.GatewayType {
|
||||
case 0:
|
||||
fallthrough
|
||||
case 3:
|
||||
rr.GatewayName = l.token
|
||||
if l.token == "@" {
|
||||
rr.GatewayName = o
|
||||
}
|
||||
_, ok := IsDomainName(l.token)
|
||||
if !ok {
|
||||
return nil, &ParseError{f, "bad IPSECKEY GatewayName", l}, ""
|
||||
}
|
||||
if rr.GatewayName[l.length-1] != '.' {
|
||||
rr.GatewayName = appendOrigin(rr.GatewayName, o)
|
||||
}
|
||||
case 1:
|
||||
rr.GatewayA = net.ParseIP(l.token)
|
||||
if rr.GatewayA == nil {
|
||||
return nil, &ParseError{f, "bad IPSECKEY GatewayA", l}, ""
|
||||
}
|
||||
case 2:
|
||||
rr.GatewayAAAA = net.ParseIP(l.token)
|
||||
if rr.GatewayAAAA == nil {
|
||||
return nil, &ParseError{f, "bad IPSECKEY GatewayAAAA", l}, ""
|
||||
}
|
||||
default:
|
||||
return nil, &ParseError{f, "bad IPSECKEY GatewayType", l}, ""
|
||||
}
|
||||
|
||||
s, e, c1 := endingToString(c, "bad IPSECKEY PublicKey", f)
|
||||
if e != nil {
|
||||
return nil, e, c1
|
||||
}
|
||||
rr.PublicKey = s
|
||||
return rr, nil, c1
|
||||
}
|
||||
|
||||
var typeToparserFunc = map[uint16]parserFunc{
|
||||
TypeAAAA: parserFunc{setAAAA, false},
|
||||
TypeAFSDB: parserFunc{setAFSDB, false},
|
||||
|
|
Loading…
Reference in New Issue