2011-01-08 20:51:20 +00:00
|
|
|
package dns
|
|
|
|
|
2011-01-08 21:39:15 +00:00
|
|
|
import (
|
2011-01-17 20:10:48 +00:00
|
|
|
"crypto/hmac"
|
2012-01-27 23:35:37 +00:00
|
|
|
"crypto/sha1"
|
|
|
|
"crypto/sha256"
|
2015-01-23 09:51:56 +00:00
|
|
|
"crypto/sha512"
|
2016-06-08 15:38:42 +00:00
|
|
|
"encoding/binary"
|
2011-01-09 14:54:23 +00:00
|
|
|
"encoding/hex"
|
2012-01-27 23:35:37 +00:00
|
|
|
"hash"
|
2012-03-02 22:07:25 +00:00
|
|
|
"strconv"
|
2011-12-09 10:16:49 +00:00
|
|
|
"strings"
|
|
|
|
"time"
|
2011-01-08 21:39:15 +00:00
|
|
|
)
|
|
|
|
|
2011-01-27 08:29:11 +00:00
|
|
|
// HMAC hashing codes. These are transmitted as domain names.
|
2011-01-08 21:39:15 +00:00
|
|
|
const (
|
2011-03-14 11:28:04 +00:00
|
|
|
HmacSHA1 = "hmac-sha1."
|
2020-07-22 04:29:04 +00:00
|
|
|
HmacSHA224 = "hmac-sha224."
|
2011-03-14 11:28:04 +00:00
|
|
|
HmacSHA256 = "hmac-sha256."
|
2020-07-22 04:29:04 +00:00
|
|
|
HmacSHA384 = "hmac-sha384."
|
2015-01-23 09:51:56 +00:00
|
|
|
HmacSHA512 = "hmac-sha512."
|
2020-10-24 11:57:51 +00:00
|
|
|
|
|
|
|
HmacMD5 = "hmac-md5.sig-alg.reg.int." // Deprecated: HmacMD5 is no longer supported.
|
2011-01-08 21:39:15 +00:00
|
|
|
)
|
|
|
|
|
2021-01-07 14:28:20 +00:00
|
|
|
// TsigProvider provides the API to plug-in a custom TSIG implementation.
|
|
|
|
type TsigProvider interface {
|
|
|
|
// Generate is passed the DNS message to be signed and the partial TSIG RR. It returns the signature and nil, otherwise an error.
|
|
|
|
Generate(msg []byte, t *TSIG) ([]byte, error)
|
|
|
|
// Verify is passed the DNS message to be verified and the TSIG RR. If the signature is valid it will return nil, otherwise an error.
|
|
|
|
Verify(msg []byte, t *TSIG) error
|
|
|
|
}
|
|
|
|
|
|
|
|
type tsigHMACProvider string
|
|
|
|
|
|
|
|
func (key tsigHMACProvider) Generate(msg []byte, t *TSIG) ([]byte, error) {
|
|
|
|
// If we barf here, the caller is to blame
|
|
|
|
rawsecret, err := fromBase64([]byte(key))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var h hash.Hash
|
|
|
|
switch CanonicalName(t.Algorithm) {
|
|
|
|
case HmacSHA1:
|
|
|
|
h = hmac.New(sha1.New, rawsecret)
|
|
|
|
case HmacSHA224:
|
|
|
|
h = hmac.New(sha256.New224, rawsecret)
|
|
|
|
case HmacSHA256:
|
|
|
|
h = hmac.New(sha256.New, rawsecret)
|
|
|
|
case HmacSHA384:
|
|
|
|
h = hmac.New(sha512.New384, rawsecret)
|
|
|
|
case HmacSHA512:
|
|
|
|
h = hmac.New(sha512.New, rawsecret)
|
|
|
|
default:
|
|
|
|
return nil, ErrKeyAlg
|
|
|
|
}
|
|
|
|
h.Write(msg)
|
|
|
|
return h.Sum(nil), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (key tsigHMACProvider) Verify(msg []byte, t *TSIG) error {
|
|
|
|
b, err := key.Generate(msg, t)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
mac, err := hex.DecodeString(t.MAC)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !hmac.Equal(b, mac) {
|
|
|
|
return ErrSig
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-02-05 00:23:49 +00:00
|
|
|
type tsigSecretProvider map[string]string
|
|
|
|
|
|
|
|
func (ts tsigSecretProvider) Generate(msg []byte, t *TSIG) ([]byte, error) {
|
|
|
|
key, ok := ts[t.Hdr.Name]
|
|
|
|
if !ok {
|
|
|
|
return nil, ErrSecret
|
|
|
|
}
|
|
|
|
return tsigHMACProvider(key).Generate(msg, t)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ts tsigSecretProvider) Verify(msg []byte, t *TSIG) error {
|
|
|
|
key, ok := ts[t.Hdr.Name]
|
|
|
|
if !ok {
|
|
|
|
return ErrSecret
|
|
|
|
}
|
|
|
|
return tsigHMACProvider(key).Verify(msg, t)
|
|
|
|
}
|
|
|
|
|
2015-02-19 09:58:33 +00:00
|
|
|
// TSIG is the RR the holds the transaction signature of a message.
|
|
|
|
// See RFC 2845 and RFC 4635.
|
2012-12-09 18:23:25 +00:00
|
|
|
type TSIG struct {
|
2012-03-02 22:07:25 +00:00
|
|
|
Hdr RR_Header
|
2012-04-29 19:55:29 +00:00
|
|
|
Algorithm string `dns:"domain-name"`
|
2012-11-19 11:26:13 +00:00
|
|
|
TimeSigned uint64 `dns:"uint48"`
|
2012-03-02 22:07:25 +00:00
|
|
|
Fudge uint16
|
|
|
|
MACSize uint16
|
2016-06-12 17:31:50 +00:00
|
|
|
MAC string `dns:"size-hex:MACSize"`
|
2012-03-02 22:07:25 +00:00
|
|
|
OrigId uint16
|
|
|
|
Error uint16
|
|
|
|
OtherLen uint16
|
2016-06-12 17:31:50 +00:00
|
|
|
OtherData string `dns:"size-hex:OtherLen"`
|
2012-03-02 22:07:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TSIG has no official presentation format, but this will suffice.
|
2012-05-08 12:17:17 +00:00
|
|
|
|
2012-12-09 18:23:25 +00:00
|
|
|
func (rr *TSIG) String() string {
|
2019-12-17 15:18:05 +00:00
|
|
|
s := "\n;; TSIG PSEUDOSECTION:\n; " // add another semi-colon to signify TSIG does not have a presentation format
|
2012-03-02 22:07:25 +00:00
|
|
|
s += rr.Hdr.String() +
|
|
|
|
" " + rr.Algorithm +
|
2012-09-11 19:45:21 +00:00
|
|
|
" " + tsigTimeToString(rr.TimeSigned) +
|
2012-03-02 22:07:25 +00:00
|
|
|
" " + strconv.Itoa(int(rr.Fudge)) +
|
|
|
|
" " + strconv.Itoa(int(rr.MACSize)) +
|
|
|
|
" " + strings.ToUpper(rr.MAC) +
|
|
|
|
" " + strconv.Itoa(int(rr.OrigId)) +
|
|
|
|
" " + strconv.Itoa(int(rr.Error)) + // BIND prints NOERROR
|
|
|
|
" " + strconv.Itoa(int(rr.OtherLen)) +
|
|
|
|
" " + rr.OtherData
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
Support parsing known RR types in RFC 3597 format (#1211)
* Support parsing known RR types in RFC 3597 format
This is the format used for "Unknown DNS Resource Records", but it's
also useful to support parsing known RR types in this way.
RFC 3597 says:
An implementation MAY also choose to represent some RRs of known type
using the above generic representations for the type, class and/or
RDATA, which carries the benefit of making the resulting master file
portable to servers where these types are unknown. Using the generic
representation for the RDATA of an RR of known type can also be
useful in the case of an RR type where the text format varies
depending on a version, protocol, or similar field (or several)
embedded in the RDATA when such a field has a value for which no text
format is known, e.g., a LOC RR [RFC1876] with a VERSION other than
0.
Even though an RR of known type represented in the \# format is
effectively treated as an unknown type for the purpose of parsing the
RDATA text representation, all further processing by the server MUST
treat it as a known type and take into account any applicable type-
specific rules regarding compression, canonicalization, etc.
* Correct mistakes in TestZoneParserAddressAAAA
This was spotted when writing TestParseKnownRRAsRFC3597.
* Eliminate canParseAsRR
This has the advantage that concrete types will now be returned for
parsed ANY, NULL, OPT and TSIG records.
* Expand TestDynamicUpdateParsing for RFC 3597
This ensures we're properly handling empty RDATA for RFC 3597 parsed
records.
2021-01-30 13:05:25 +00:00
|
|
|
func (*TSIG) parse(c *zlexer, origin string) *ParseError {
|
|
|
|
return &ParseError{err: "TSIG records do not have a presentation format"}
|
2019-01-06 04:06:16 +00:00
|
|
|
}
|
|
|
|
|
2011-01-17 20:10:48 +00:00
|
|
|
// The following values must be put in wireformat, so that the MAC can be calculated.
|
|
|
|
// RFC 2845, section 3.4.2. TSIG Variables.
|
2011-01-14 10:57:28 +00:00
|
|
|
type tsigWireFmt struct {
|
2012-02-29 21:00:39 +00:00
|
|
|
// From RR_Header
|
2012-04-29 19:55:29 +00:00
|
|
|
Name string `dns:"domain-name"`
|
2011-01-08 20:51:20 +00:00
|
|
|
Class uint16
|
|
|
|
Ttl uint32
|
|
|
|
// Rdata of the TSIG
|
2012-04-29 19:55:29 +00:00
|
|
|
Algorithm string `dns:"domain-name"`
|
2012-12-13 12:44:27 +00:00
|
|
|
TimeSigned uint64 `dns:"uint48"`
|
2011-01-08 20:51:20 +00:00
|
|
|
Fudge uint16
|
|
|
|
// MACSize, MAC and OrigId excluded
|
|
|
|
Error uint16
|
|
|
|
OtherLen uint16
|
2016-06-12 17:31:50 +00:00
|
|
|
OtherData string `dns:"size-hex:OtherLen"`
|
2011-01-08 20:51:20 +00:00
|
|
|
}
|
|
|
|
|
2016-06-12 20:06:46 +00:00
|
|
|
// If we have the MAC use this type to convert it to wiredata. Section 3.4.3. Request MAC
|
2011-03-14 11:28:04 +00:00
|
|
|
type macWireFmt struct {
|
2011-03-14 20:16:45 +00:00
|
|
|
MACSize uint16
|
2016-06-12 17:31:50 +00:00
|
|
|
MAC string `dns:"size-hex:MACSize"`
|
2011-03-14 11:28:04 +00:00
|
|
|
}
|
|
|
|
|
2011-03-15 18:36:03 +00:00
|
|
|
// 3.3. Time values used in TSIG calculations
|
|
|
|
type timerWireFmt struct {
|
2012-12-13 12:44:27 +00:00
|
|
|
TimeSigned uint64 `dns:"uint48"`
|
2011-03-15 18:36:03 +00:00
|
|
|
Fudge uint16
|
|
|
|
}
|
|
|
|
|
2012-03-01 21:40:34 +00:00
|
|
|
// TsigGenerate fills out the TSIG record attached to the message.
|
2022-06-21 08:37:36 +00:00
|
|
|
// The message should contain a "stub" TSIG RR with the algorithm, key name
|
|
|
|
// (owner name of the RR), time fudge (defaults to 300 seconds) and the current
|
|
|
|
// time The TSIG MAC is saved in that Tsig RR. When TsigGenerate is called for
|
|
|
|
// the first time requestMAC should be set to the empty string and timersOnly to
|
|
|
|
// false.
|
2012-03-01 21:40:34 +00:00
|
|
|
func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
|
2022-06-21 08:37:36 +00:00
|
|
|
return TsigGenerateWithProvider(m, tsigHMACProvider(secret), requestMAC, timersOnly)
|
2021-01-07 14:28:20 +00:00
|
|
|
}
|
|
|
|
|
2022-06-21 08:37:36 +00:00
|
|
|
// TsigGenerateWithProvider is similar to TsigGenerate, but allows for a custom TsigProvider.
|
|
|
|
func TsigGenerateWithProvider(m *Msg, provider TsigProvider, requestMAC string, timersOnly bool) ([]byte, string, error) {
|
2012-08-25 09:24:01 +00:00
|
|
|
if m.IsTsig() == nil {
|
2012-08-28 16:21:23 +00:00
|
|
|
panic("dns: TSIG not last RR in additional")
|
2011-04-22 14:37:26 +00:00
|
|
|
}
|
2011-03-20 19:55:27 +00:00
|
|
|
|
2012-12-09 18:23:25 +00:00
|
|
|
rr := m.Extra[len(m.Extra)-1].(*TSIG)
|
2011-04-22 14:37:26 +00:00
|
|
|
m.Extra = m.Extra[0 : len(m.Extra)-1] // kill the TSIG from the msg
|
2012-10-09 19:17:54 +00:00
|
|
|
mbuf, err := m.Pack()
|
|
|
|
if err != nil {
|
|
|
|
return nil, "", err
|
2012-03-01 21:40:34 +00:00
|
|
|
}
|
2021-12-20 09:31:57 +00:00
|
|
|
|
2020-07-21 06:04:57 +00:00
|
|
|
buf, err := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
|
|
|
|
if err != nil {
|
|
|
|
return nil, "", err
|
|
|
|
}
|
2011-04-18 20:08:12 +00:00
|
|
|
|
2012-12-09 18:23:25 +00:00
|
|
|
t := new(TSIG)
|
2021-12-20 09:31:57 +00:00
|
|
|
// Copy all TSIG fields except MAC, its size, and time signed which are filled when signing.
|
2020-07-21 15:55:03 +00:00
|
|
|
*t = *rr
|
2021-12-20 09:31:57 +00:00
|
|
|
t.TimeSigned = 0
|
|
|
|
t.MAC = ""
|
|
|
|
t.MACSize = 0
|
|
|
|
|
|
|
|
// Sign unless there is a key or MAC validation error (RFC 8945 5.3.2)
|
|
|
|
if rr.Error != RcodeBadKey && rr.Error != RcodeBadSig {
|
|
|
|
mac, err := provider.Generate(buf, rr)
|
|
|
|
if err != nil {
|
|
|
|
return nil, "", err
|
|
|
|
}
|
|
|
|
t.TimeSigned = rr.TimeSigned
|
|
|
|
t.MAC = hex.EncodeToString(mac)
|
|
|
|
t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
|
2021-01-07 14:28:20 +00:00
|
|
|
}
|
2011-03-20 20:40:10 +00:00
|
|
|
|
2018-11-29 23:33:41 +00:00
|
|
|
tbuf := make([]byte, Len(t))
|
2019-01-04 10:19:42 +00:00
|
|
|
off, err := PackRR(t, tbuf, 0, nil, false)
|
|
|
|
if err != nil {
|
2012-10-09 19:17:54 +00:00
|
|
|
return nil, "", err
|
2012-03-01 21:40:34 +00:00
|
|
|
}
|
2019-01-04 10:19:42 +00:00
|
|
|
mbuf = append(mbuf, tbuf[:off]...)
|
2016-06-13 18:44:38 +00:00
|
|
|
// Update the ArCount directly in the buffer.
|
|
|
|
binary.BigEndian.PutUint16(mbuf[10:], uint16(len(m.Extra)+1))
|
|
|
|
|
2012-03-01 21:40:34 +00:00
|
|
|
return mbuf, t.MAC, nil
|
2011-03-20 19:55:27 +00:00
|
|
|
}
|
|
|
|
|
2022-06-21 08:37:36 +00:00
|
|
|
// TsigVerify verifies the TSIG on a message. If the signature does not
|
|
|
|
// validate the returned error contains the cause. If the signature is OK, the
|
|
|
|
// error is nil.
|
2011-11-02 22:06:54 +00:00
|
|
|
func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
|
2021-01-07 14:28:20 +00:00
|
|
|
return tsigVerify(msg, tsigHMACProvider(secret), requestMAC, timersOnly, uint64(time.Now().Unix()))
|
|
|
|
}
|
|
|
|
|
2022-06-21 08:37:36 +00:00
|
|
|
// TsigVerifyWithProvider is similar to TsigVerify, but allows for a custom TsigProvider.
|
|
|
|
func TsigVerifyWithProvider(msg []byte, provider TsigProvider, requestMAC string, timersOnly bool) error {
|
2021-01-07 14:28:20 +00:00
|
|
|
return tsigVerify(msg, provider, requestMAC, timersOnly, uint64(time.Now().Unix()))
|
2020-07-18 06:06:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// actual implementation of TsigVerify, taking the current time ('now') as a parameter for the convenience of tests.
|
2021-01-07 14:28:20 +00:00
|
|
|
func tsigVerify(msg []byte, provider TsigProvider, requestMAC string, timersOnly bool, now uint64) error {
|
2014-01-24 03:28:08 +00:00
|
|
|
// Strip the TSIG from the incoming msg
|
2011-04-19 09:31:47 +00:00
|
|
|
stripped, tsig, err := stripTsig(msg)
|
2011-03-25 13:46:30 +00:00
|
|
|
if err != nil {
|
2011-09-10 14:50:27 +00:00
|
|
|
return err
|
2011-03-20 19:55:27 +00:00
|
|
|
}
|
|
|
|
|
2020-07-21 06:04:57 +00:00
|
|
|
buf, err := tsigBuffer(stripped, tsig, requestMAC, timersOnly)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-11-11 17:58:12 +00:00
|
|
|
|
2021-01-07 14:28:20 +00:00
|
|
|
if err := provider.Verify(buf, tsig); err != nil {
|
|
|
|
return err
|
2011-11-02 22:06:54 +00:00
|
|
|
}
|
2020-07-18 06:06:18 +00:00
|
|
|
|
|
|
|
// Fudge factor works both ways. A message can arrive before it was signed because
|
|
|
|
// of clock skew.
|
|
|
|
// We check this after verifying the signature, following draft-ietf-dnsop-rfc2845bis
|
|
|
|
// instead of RFC2845, in order to prevent a security vulnerability as reported in CVE-2017-3142/3143.
|
|
|
|
ti := now - tsig.TimeSigned
|
|
|
|
if now < tsig.TimeSigned {
|
|
|
|
ti = tsig.TimeSigned - now
|
|
|
|
}
|
|
|
|
if uint64(tsig.Fudge) < ti {
|
|
|
|
return ErrTime
|
|
|
|
}
|
|
|
|
|
2011-11-02 22:06:54 +00:00
|
|
|
return nil
|
2011-01-25 21:29:48 +00:00
|
|
|
}
|
|
|
|
|
2011-03-23 18:07:06 +00:00
|
|
|
// Create a wiredata buffer for the MAC calculation.
|
2020-07-21 06:04:57 +00:00
|
|
|
func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) ([]byte, error) {
|
2012-03-05 21:03:18 +00:00
|
|
|
var buf []byte
|
2011-04-22 14:37:26 +00:00
|
|
|
if rr.TimeSigned == 0 {
|
2011-12-09 10:16:49 +00:00
|
|
|
rr.TimeSigned = uint64(time.Now().Unix())
|
2011-04-22 14:37:26 +00:00
|
|
|
}
|
|
|
|
if rr.Fudge == 0 {
|
2011-11-02 22:06:54 +00:00
|
|
|
rr.Fudge = 300 // Standard (RFC) default.
|
2011-04-22 14:37:26 +00:00
|
|
|
}
|
2011-03-20 19:55:27 +00:00
|
|
|
|
2017-08-12 19:21:44 +00:00
|
|
|
// Replace message ID in header with original ID from TSIG
|
|
|
|
binary.BigEndian.PutUint16(msgbuf[0:2], rr.OrigId)
|
|
|
|
|
2011-04-22 14:37:26 +00:00
|
|
|
if requestMAC != "" {
|
2011-03-20 19:55:27 +00:00
|
|
|
m := new(macWireFmt)
|
2011-04-22 14:37:26 +00:00
|
|
|
m.MACSize = uint16(len(requestMAC) / 2)
|
|
|
|
m.MAC = requestMAC
|
2012-05-05 15:37:48 +00:00
|
|
|
buf = make([]byte, len(requestMAC)) // long enough
|
2020-07-21 06:04:57 +00:00
|
|
|
n, err := packMacWire(m, buf)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2012-03-05 21:03:18 +00:00
|
|
|
buf = buf[:n]
|
2011-03-20 19:55:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tsigvar := make([]byte, DefaultMsgSize)
|
2011-04-18 20:08:12 +00:00
|
|
|
if timersOnly {
|
2011-03-21 10:39:04 +00:00
|
|
|
tsig := new(timerWireFmt)
|
2011-04-18 20:08:12 +00:00
|
|
|
tsig.TimeSigned = rr.TimeSigned
|
|
|
|
tsig.Fudge = rr.Fudge
|
2020-07-21 06:04:57 +00:00
|
|
|
n, err := packTimerWire(tsig, tsigvar)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2011-03-20 19:55:27 +00:00
|
|
|
tsigvar = tsigvar[:n]
|
|
|
|
} else {
|
2011-03-21 10:39:04 +00:00
|
|
|
tsig := new(tsigWireFmt)
|
2020-03-18 10:21:59 +00:00
|
|
|
tsig.Name = CanonicalName(rr.Hdr.Name)
|
2011-03-21 10:39:04 +00:00
|
|
|
tsig.Class = ClassANY
|
2011-04-22 14:37:26 +00:00
|
|
|
tsig.Ttl = rr.Hdr.Ttl
|
2020-03-18 10:21:59 +00:00
|
|
|
tsig.Algorithm = CanonicalName(rr.Algorithm)
|
2011-04-18 20:08:12 +00:00
|
|
|
tsig.TimeSigned = rr.TimeSigned
|
|
|
|
tsig.Fudge = rr.Fudge
|
2011-04-22 14:37:26 +00:00
|
|
|
tsig.Error = rr.Error
|
|
|
|
tsig.OtherLen = rr.OtherLen
|
|
|
|
tsig.OtherData = rr.OtherData
|
2020-07-21 06:04:57 +00:00
|
|
|
n, err := packTsigWire(tsig, tsigvar)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2011-03-20 19:55:27 +00:00
|
|
|
tsigvar = tsigvar[:n]
|
|
|
|
}
|
2012-03-05 21:03:18 +00:00
|
|
|
|
|
|
|
if requestMAC != "" {
|
|
|
|
x := append(buf, msgbuf...)
|
2011-03-20 19:55:27 +00:00
|
|
|
buf = append(x, tsigvar...)
|
|
|
|
} else {
|
2011-04-18 20:08:12 +00:00
|
|
|
buf = append(msgbuf, tsigvar...)
|
2011-03-20 19:55:27 +00:00
|
|
|
}
|
2020-07-21 06:04:57 +00:00
|
|
|
return buf, nil
|
2011-03-20 19:55:27 +00:00
|
|
|
}
|
2011-04-19 09:31:47 +00:00
|
|
|
|
2014-07-30 06:35:06 +00:00
|
|
|
// Strip the TSIG from the raw message.
|
2012-12-09 18:23:25 +00:00
|
|
|
func stripTsig(msg []byte) ([]byte, *TSIG, error) {
|
2016-06-12 20:06:46 +00:00
|
|
|
// Copied from msg.go's Unpack() Header, but modified.
|
|
|
|
var (
|
|
|
|
dh Header
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
off, tsigoff := 0, 0
|
|
|
|
|
|
|
|
if dh, off, err = unpackMsgHdr(msg, off); err != nil {
|
2012-10-09 19:17:54 +00:00
|
|
|
return nil, nil, err
|
2011-03-15 17:43:05 +00:00
|
|
|
}
|
|
|
|
if dh.Arcount == 0 {
|
2011-04-19 09:31:47 +00:00
|
|
|
return nil, nil, ErrNoSig
|
2011-03-15 17:43:05 +00:00
|
|
|
}
|
2016-06-12 20:06:46 +00:00
|
|
|
|
2011-04-22 14:37:26 +00:00
|
|
|
// Rcode, see msg.go Unpack()
|
|
|
|
if int(dh.Bits&0xF) == RcodeNotAuth {
|
|
|
|
return nil, nil, ErrAuth
|
|
|
|
}
|
2011-03-15 17:43:05 +00:00
|
|
|
|
2016-06-12 20:06:46 +00:00
|
|
|
for i := 0; i < int(dh.Qdcount); i++ {
|
|
|
|
_, off, err = unpackQuestion(msg, off)
|
2012-10-09 19:17:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2011-03-15 17:43:05 +00:00
|
|
|
}
|
2016-06-12 20:06:46 +00:00
|
|
|
|
|
|
|
_, off, err = unpackRRslice(int(dh.Ancount), msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
2011-03-15 17:43:05 +00:00
|
|
|
}
|
2016-06-12 20:06:46 +00:00
|
|
|
_, off, err = unpackRRslice(int(dh.Nscount), msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
2011-03-15 17:43:05 +00:00
|
|
|
}
|
2016-06-12 20:06:46 +00:00
|
|
|
|
|
|
|
rr := new(TSIG)
|
|
|
|
var extra RR
|
|
|
|
for i := 0; i < int(dh.Arcount); i++ {
|
2011-03-15 17:43:05 +00:00
|
|
|
tsigoff = off
|
2016-06-12 20:06:46 +00:00
|
|
|
extra, off, err = UnpackRR(msg, off)
|
2012-10-09 19:17:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
2016-06-12 20:06:46 +00:00
|
|
|
if extra.Header().Rrtype == TypeTSIG {
|
|
|
|
rr = extra.(*TSIG)
|
2011-03-15 17:43:05 +00:00
|
|
|
// Adjust Arcount.
|
2016-06-08 15:38:42 +00:00
|
|
|
arcount := binary.BigEndian.Uint16(msg[10:])
|
|
|
|
binary.BigEndian.PutUint16(msg[10:], arcount-1)
|
2011-03-15 17:43:05 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2011-04-22 14:37:26 +00:00
|
|
|
if rr == nil {
|
2011-04-19 09:31:47 +00:00
|
|
|
return nil, nil, ErrNoSig
|
2011-04-22 14:37:26 +00:00
|
|
|
}
|
2011-04-19 09:31:47 +00:00
|
|
|
return msg[:tsigoff], rr, nil
|
2011-03-15 15:18:13 +00:00
|
|
|
}
|
2012-03-02 22:12:23 +00:00
|
|
|
|
|
|
|
// Translate the TSIG time signed into a date. There is no
|
|
|
|
// need for RFC1982 calculations as this date is 48 bits.
|
2012-09-11 19:45:21 +00:00
|
|
|
func tsigTimeToString(t uint64) string {
|
2012-03-05 21:03:18 +00:00
|
|
|
ti := time.Unix(int64(t), 0).UTC()
|
|
|
|
return ti.Format("20060102150405")
|
2012-03-02 22:12:23 +00:00
|
|
|
}
|
2016-06-12 20:06:46 +00:00
|
|
|
|
|
|
|
func packTsigWire(tw *tsigWireFmt, msg []byte) (int, error) {
|
|
|
|
// copied from zmsg.go TSIG packing
|
|
|
|
// RR_Header
|
|
|
|
off, err := PackDomainName(tw.Name, msg, 0, nil, false)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
off, err = packUint16(tw.Class, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
off, err = packUint32(tw.Ttl, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
|
|
|
|
off, err = PackDomainName(tw.Algorithm, msg, off, nil, false)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
off, err = packUint48(tw.TimeSigned, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
off, err = packUint16(tw.Fudge, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
|
|
|
|
off, err = packUint16(tw.Error, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
off, err = packUint16(tw.OtherLen, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
off, err = packStringHex(tw.OtherData, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
return off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func packMacWire(mw *macWireFmt, msg []byte) (int, error) {
|
|
|
|
off, err := packUint16(mw.MACSize, msg, 0)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
off, err = packStringHex(mw.MAC, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
return off, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func packTimerWire(tw *timerWireFmt, msg []byte) (int, error) {
|
|
|
|
off, err := packUint48(tw.TimeSigned, msg, 0)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
off, err = packUint16(tw.Fudge, msg, off)
|
|
|
|
if err != nil {
|
|
|
|
return off, err
|
|
|
|
}
|
|
|
|
return off, nil
|
|
|
|
}
|