Use crypto/rand for random id generation. (#1044)
* Use crypto/rand for random id generation. Fixes #1043 and #1037 * Panic on rare crypto/rand error. * Fixes in response to review.
This commit is contained in:
parent
6d0449f981
commit
8ebf2e419d
52
msg.go
52
msg.go
|
@ -11,14 +11,12 @@ package dns
|
||||||
//go:generate go run msg_generate.go
|
//go:generate go run msg_generate.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
crand "crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -73,53 +71,23 @@ var (
|
||||||
ErrTime error = &Error{err: "bad time"} // ErrTime indicates a timing error in TSIG authentication.
|
ErrTime error = &Error{err: "bad time"} // ErrTime indicates a timing error in TSIG authentication.
|
||||||
)
|
)
|
||||||
|
|
||||||
// Id by default, returns a 16 bits random number to be used as a
|
// Id by default returns a 16-bit random number to be used as a message id. The
|
||||||
// message id. The random provided should be good enough. This being a
|
// number is drawn from a cryptographically secure random number generator.
|
||||||
// variable the function can be reassigned to a custom function.
|
// This being a variable the function can be reassigned to a custom function.
|
||||||
// For instance, to make it return a static value:
|
// For instance, to make it return a static value for testing:
|
||||||
//
|
//
|
||||||
// dns.Id = func() uint16 { return 3 }
|
// dns.Id = func() uint16 { return 3 }
|
||||||
var Id = id
|
var Id = id
|
||||||
|
|
||||||
var (
|
|
||||||
idLock sync.Mutex
|
|
||||||
idRand *rand.Rand
|
|
||||||
)
|
|
||||||
|
|
||||||
// id returns a 16 bits random number to be used as a
|
// id returns a 16 bits random number to be used as a
|
||||||
// message id. The random provided should be good enough.
|
// message id. The random provided should be good enough.
|
||||||
func id() uint16 {
|
func id() uint16 {
|
||||||
idLock.Lock()
|
var output uint16
|
||||||
|
err := binary.Read(rand.Reader, binary.BigEndian, &output)
|
||||||
if idRand == nil {
|
if err != nil {
|
||||||
// This (partially) works around
|
panic("dns: reading random id failed: " + err.Error())
|
||||||
// https://github.com/golang/go/issues/11833 by only
|
|
||||||
// seeding idRand upon the first call to id.
|
|
||||||
|
|
||||||
var seed int64
|
|
||||||
var buf [8]byte
|
|
||||||
|
|
||||||
if _, err := crand.Read(buf[:]); err == nil {
|
|
||||||
seed = int64(binary.LittleEndian.Uint64(buf[:]))
|
|
||||||
} else {
|
|
||||||
seed = rand.Int63()
|
|
||||||
}
|
|
||||||
|
|
||||||
idRand = rand.New(rand.NewSource(seed))
|
|
||||||
}
|
}
|
||||||
|
return output
|
||||||
// The call to idRand.Uint32 must be within the
|
|
||||||
// mutex lock because *rand.Rand is not safe for
|
|
||||||
// concurrent use.
|
|
||||||
//
|
|
||||||
// There is no added performance overhead to calling
|
|
||||||
// idRand.Uint32 inside a mutex lock over just
|
|
||||||
// calling rand.Uint32 as the global math/rand rng
|
|
||||||
// is internally protected by a sync.Mutex.
|
|
||||||
id := uint16(idRand.Uint32())
|
|
||||||
|
|
||||||
idLock.Unlock()
|
|
||||||
return id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MsgHdr is a a manually-unpacked version of (id, bits).
|
// MsgHdr is a a manually-unpacked version of (id, bits).
|
||||||
|
|
Loading…
Reference in New Issue