Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use crypto/rand for random id generation. #1044

Merged
merged 3 commits into from Dec 11, 2019
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 9 additions & 41 deletions msg.go
Expand Up @@ -15,10 +15,8 @@ import (
"encoding/binary"
"fmt"
"math/big"
"math/rand"
miekg marked this conversation as resolved.
Show resolved Hide resolved
"strconv"
"strings"
"sync"
)

const (
Expand Down Expand Up @@ -73,53 +71,23 @@ var (
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
// message id. The random provided should be good enough. This being a
// variable the function can be reassigned to a custom function.
// For instance, to make it return a static value:
// Id by default, returns a 16 bit random number (from crypto/rand) to
// be used as a message id. This being a variable the function can be
miekg marked this conversation as resolved.
Show resolved Hide resolved
// reassigned to a custom function. For instance, to make it return a
// static value:
//
// dns.Id = func() uint16 { return 3 }
var Id = id

var (
idLock sync.Mutex
idRand *rand.Rand
)

// id returns a 16 bits random number to be used as a
// message id. The random provided should be good enough.
func id() uint16 {
idLock.Lock()

if idRand == nil {
// This (partially) works around
// 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))
var v uint16
miekg marked this conversation as resolved.
Show resolved Hide resolved
err := binary.Read(crand.Reader, binary.BigEndian, &v)
if err != nil {
panic(fmt.Sprintf("failed to get randomness: %s", err))
miekg marked this conversation as resolved.
Show resolved Hide resolved
}

// 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
return v
}

// MsgHdr is a a manually-unpacked version of (id, bits).
Expand Down