Massive dependencies update
This commit is contained in:
parent
e6ccf7f3c0
commit
4f4daf41b7
|
@ -23,7 +23,7 @@
|
|||
branch = "master"
|
||||
name = "github.com/aead/chacha20"
|
||||
packages = ["chacha"]
|
||||
revision = "52db354a4a380462fc762185d72dffb206e50a42"
|
||||
revision = "e2538746bfea853aaa589feb8ec46bd46ee78f86"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -116,7 +116,7 @@
|
|||
branch = "master"
|
||||
name = "github.com/jedisct1/xsecretbox"
|
||||
packages = ["."]
|
||||
revision = "e790e3a36d5cdde0f309753d16100f2e7b396482"
|
||||
revision = "7a679c0bcd9a5bbfe097fb7d48497bc06d17be76"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/k-sone/critbitgo"
|
||||
|
@ -139,8 +139,8 @@
|
|||
[[projects]]
|
||||
name = "github.com/miekg/dns"
|
||||
packages = ["."]
|
||||
revision = "83c435cc65d2862736428b9b4d07d0ab10ad3e4d"
|
||||
version = "v1.0.5"
|
||||
revision = "eac804ceef194db2da6ee80c728d7658c8c805ff"
|
||||
version = "v1.0.6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -154,7 +154,7 @@
|
|||
"poly1305",
|
||||
"salsa20/salsa"
|
||||
]
|
||||
revision = "76a954637dfa3223c13edb4529f981f0d62cfa26"
|
||||
revision = "2d027ae1dddd4694d54f7a8b6cbe78dca8720226"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -168,10 +168,9 @@
|
|||
"internal/iana",
|
||||
"internal/socket",
|
||||
"ipv4",
|
||||
"ipv6",
|
||||
"lex/httplex"
|
||||
"ipv6"
|
||||
]
|
||||
revision = "640f4622ab692b87c2f3a94265e6f579fe38263d"
|
||||
revision = "f73e4c9ed3b7ebdd5f699a16a880c2b1994e50dd"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -184,7 +183,7 @@
|
|||
"windows/svc/eventlog",
|
||||
"windows/svc/mgr"
|
||||
]
|
||||
revision = "78d5f264b493f125018180c204871ecf58a2dce1"
|
||||
revision = "7dfd1290c7917b7ba22824b9d24954ab3002fe24"
|
||||
|
||||
[[projects]]
|
||||
name = "golang.org/x/text"
|
||||
|
|
|
@ -6,8 +6,11 @@ go:
|
|||
- "1.10.x"
|
||||
|
||||
env:
|
||||
- ARCH=x86_64
|
||||
- ARCH=i686
|
||||
- TRAVIS_GOARCH=amd64
|
||||
- TRAVIS_GOARCH=386
|
||||
|
||||
before_install:
|
||||
- export GOARCH=$TRAVIS_GOARCH
|
||||
|
||||
branches:
|
||||
only:
|
||||
|
|
|
@ -52,10 +52,9 @@ func hChaCha20(out *[32]byte, nonce *[16]byte, key *[32]byte) {
|
|||
}
|
||||
|
||||
func xorKeyStream(dst, src []byte, block, state *[64]byte, rounds int) int {
|
||||
switch {
|
||||
case useSSE2:
|
||||
if useSSE2 {
|
||||
return xorKeyStreamSSE2(dst, src, block, state, rounds)
|
||||
default:
|
||||
} else {
|
||||
return xorKeyStreamGeneric(dst, src, block, state, rounds)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
branch = "master"
|
||||
name = "github.com/aead/chacha20"
|
||||
packages = ["chacha"]
|
||||
revision = "8457f65383c5be6183d33e992fbf1786d6ab3e76"
|
||||
revision = "e2538746bfea853aaa589feb8ec46bd46ee78f86"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -17,7 +17,13 @@
|
|||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["curve25519"]
|
||||
revision = "b49d69b5da943f7ef3c9cf91c8777c1f78a0cc3c"
|
||||
revision = "4ec37c66abab2c7e02ae775328b2ff001c3f025a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["cpu"]
|
||||
revision = "7db1c3b1a98089d0071c84f646ff5c96aad43682"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
|
|
|
@ -21,6 +21,13 @@ func isUpstart() bool {
|
|||
if _, err := os.Stat("/sbin/upstart-udev-bridge"); err == nil {
|
||||
return true
|
||||
}
|
||||
if _, err := os.Stat("/sbin/init"); err == nil {
|
||||
if out, err := exec.Command("/sbin/init", "--version").Output(); err == nil {
|
||||
if strings.Contains(string(out), "init (upstart") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
|||
// AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's.
|
||||
var AlgorithmToHash = map[uint8]crypto.Hash{
|
||||
RSAMD5: crypto.MD5, // Deprecated in RFC 6725
|
||||
DSA: crypto.SHA1,
|
||||
RSASHA1: crypto.SHA1,
|
||||
RSASHA1NSEC3SHA1: crypto.SHA1,
|
||||
RSASHA256: crypto.SHA256,
|
||||
|
|
|
@ -73,11 +73,11 @@ and port to use for the connection:
|
|||
Port: 12345,
|
||||
Zone: "",
|
||||
}
|
||||
d := net.Dialer{
|
||||
c.Dialer := &net.Dialer{
|
||||
Timeout: 200 * time.Millisecond,
|
||||
LocalAddr: &laddr,
|
||||
}
|
||||
in, rtt, err := c.ExchangeWithDialer(&d, m1, "8.8.8.8:53")
|
||||
in, rtt, err := c.Exchange(m1, "8.8.8.8:53")
|
||||
|
||||
If these "advanced" features are not needed, a simple UDP query can be sent,
|
||||
with:
|
||||
|
|
|
@ -9,12 +9,19 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Maximum number of TCP queries before we close the socket.
|
||||
const maxTCPQueries = 128
|
||||
|
||||
// Interval for stop worker if no load
|
||||
const idleWorkerTimeout = 10 * time.Second
|
||||
|
||||
// Maximum number of workers
|
||||
const maxWorkersCount = 10000
|
||||
|
||||
// Handler is implemented by any value that implements ServeDNS.
|
||||
type Handler interface {
|
||||
ServeDNS(w ResponseWriter, r *Msg)
|
||||
|
@ -43,6 +50,7 @@ type ResponseWriter interface {
|
|||
}
|
||||
|
||||
type response struct {
|
||||
msg []byte
|
||||
hijacked bool // connection has been hijacked by handler
|
||||
tsigStatus error
|
||||
tsigTimersOnly bool
|
||||
|
@ -51,7 +59,6 @@ type response struct {
|
|||
udp *net.UDPConn // i/o connection if UDP was used
|
||||
tcp net.Conn // i/o connection if TCP was used
|
||||
udpSession *SessionUDP // oob data to get egress interface right
|
||||
remoteAddr net.Addr // address of the client
|
||||
writer Writer // writer to output the raw DNS bits
|
||||
}
|
||||
|
||||
|
@ -297,11 +304,60 @@ type Server struct {
|
|||
// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
|
||||
DecorateWriter DecorateWriter
|
||||
|
||||
// UDP packet or TCP connection queue
|
||||
queue chan *response
|
||||
// Workers count
|
||||
workersCount int32
|
||||
// Shutdown handling
|
||||
lock sync.RWMutex
|
||||
started bool
|
||||
}
|
||||
|
||||
func (srv *Server) worker(w *response) {
|
||||
srv.serve(w)
|
||||
|
||||
for {
|
||||
count := atomic.LoadInt32(&srv.workersCount)
|
||||
if count > maxWorkersCount {
|
||||
return
|
||||
}
|
||||
if atomic.CompareAndSwapInt32(&srv.workersCount, count, count+1) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
defer atomic.AddInt32(&srv.workersCount, -1)
|
||||
|
||||
inUse := false
|
||||
timeout := time.NewTimer(idleWorkerTimeout)
|
||||
defer timeout.Stop()
|
||||
LOOP:
|
||||
for {
|
||||
select {
|
||||
case w, ok := <-srv.queue:
|
||||
if !ok {
|
||||
break LOOP
|
||||
}
|
||||
inUse = true
|
||||
srv.serve(w)
|
||||
case <-timeout.C:
|
||||
if !inUse {
|
||||
break LOOP
|
||||
}
|
||||
inUse = false
|
||||
timeout.Reset(idleWorkerTimeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *Server) spawnWorker(w *response) {
|
||||
select {
|
||||
case srv.queue <- w:
|
||||
default:
|
||||
go srv.worker(w)
|
||||
}
|
||||
}
|
||||
|
||||
// ListenAndServe starts a nameserver on the configured address in *Server.
|
||||
func (srv *Server) ListenAndServe() error {
|
||||
srv.lock.Lock()
|
||||
|
@ -309,6 +365,7 @@ func (srv *Server) ListenAndServe() error {
|
|||
if srv.started {
|
||||
return &Error{err: "server already started"}
|
||||
}
|
||||
|
||||
addr := srv.Addr
|
||||
if addr == "" {
|
||||
addr = ":domain"
|
||||
|
@ -316,6 +373,8 @@ func (srv *Server) ListenAndServe() error {
|
|||
if srv.UDPSize == 0 {
|
||||
srv.UDPSize = MinMsgSize
|
||||
}
|
||||
srv.queue = make(chan *response)
|
||||
defer close(srv.queue)
|
||||
switch srv.Net {
|
||||
case "tcp", "tcp4", "tcp6":
|
||||
a, err := net.ResolveTCPAddr(srv.Net, addr)
|
||||
|
@ -380,8 +439,11 @@ func (srv *Server) ActivateAndServe() error {
|
|||
if srv.started {
|
||||
return &Error{err: "server already started"}
|
||||
}
|
||||
|
||||
pConn := srv.PacketConn
|
||||
l := srv.Listener
|
||||
srv.queue = make(chan *response)
|
||||
defer close(srv.queue)
|
||||
if pConn != nil {
|
||||
if srv.UDPSize == 0 {
|
||||
srv.UDPSize = MinMsgSize
|
||||
|
@ -439,7 +501,6 @@ func (srv *Server) getReadTimeout() time.Duration {
|
|||
}
|
||||
|
||||
// serveTCP starts a TCP listener for the server.
|
||||
// Each request is handled in a separate goroutine.
|
||||
func (srv *Server) serveTCP(l net.Listener) error {
|
||||
defer l.Close()
|
||||
|
||||
|
@ -447,17 +508,6 @@ func (srv *Server) serveTCP(l net.Listener) error {
|
|||
srv.NotifyStartedFunc()
|
||||
}
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
|
||||
handler := srv.Handler
|
||||
if handler == nil {
|
||||
handler = DefaultServeMux
|
||||
}
|
||||
rtimeout := srv.getReadTimeout()
|
||||
// deadline is not used here
|
||||
for {
|
||||
rw, err := l.Accept()
|
||||
srv.lock.RLock()
|
||||
|
@ -472,19 +522,11 @@ func (srv *Server) serveTCP(l net.Listener) error {
|
|||
}
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
m, err := reader.ReadTCP(rw, rtimeout)
|
||||
if err != nil {
|
||||
rw.Close()
|
||||
return
|
||||
}
|
||||
srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
|
||||
}()
|
||||
srv.spawnWorker(&response{tsigSecret: srv.TsigSecret, tcp: rw})
|
||||
}
|
||||
}
|
||||
|
||||
// serveUDP starts a UDP listener for the server.
|
||||
// Each request is handled in a separate goroutine.
|
||||
func (srv *Server) serveUDP(l *net.UDPConn) error {
|
||||
defer l.Close()
|
||||
|
||||
|
@ -497,10 +539,6 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
|||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
|
||||
handler := srv.Handler
|
||||
if handler == nil {
|
||||
handler = DefaultServeMux
|
||||
}
|
||||
rtimeout := srv.getReadTimeout()
|
||||
// deadline is not used here
|
||||
for {
|
||||
|
@ -520,80 +558,94 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
|||
if len(m) < headerSize {
|
||||
continue
|
||||
}
|
||||
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
|
||||
srv.spawnWorker(&response{msg: m, tsigSecret: srv.TsigSecret, udp: l, udpSession: s})
|
||||
}
|
||||
}
|
||||
|
||||
// Serve a new connection.
|
||||
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t net.Conn) {
|
||||
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
|
||||
func (srv *Server) serve(w *response) {
|
||||
if srv.DecorateWriter != nil {
|
||||
w.writer = srv.DecorateWriter(w)
|
||||
} else {
|
||||
w.writer = w
|
||||
}
|
||||
|
||||
q := 0 // counter for the amount of TCP queries we get
|
||||
if w.udp != nil {
|
||||
// serve UDP
|
||||
srv.serveDNS(w)
|
||||
return
|
||||
}
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
Redo:
|
||||
|
||||
defer func() {
|
||||
if !w.hijacked {
|
||||
w.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
idleTimeout := tcpIdleTimeout
|
||||
if srv.IdleTimeout != nil {
|
||||
idleTimeout = srv.IdleTimeout()
|
||||
}
|
||||
|
||||
timeout := srv.getReadTimeout()
|
||||
|
||||
// TODO(miek): make maxTCPQueries configurable?
|
||||
for q := 0; q < maxTCPQueries; q++ {
|
||||
var err error
|
||||
w.msg, err = reader.ReadTCP(w.tcp, timeout)
|
||||
if err != nil {
|
||||
// TODO(tmthrgd): handle error
|
||||
break
|
||||
}
|
||||
srv.serveDNS(w)
|
||||
if w.tcp == nil {
|
||||
break // Close() was called
|
||||
}
|
||||
if w.hijacked {
|
||||
break // client will call Close() themselves
|
||||
}
|
||||
// The first read uses the read timeout, the rest use the
|
||||
// idle timeout.
|
||||
timeout = idleTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *Server) serveDNS(w *response) {
|
||||
req := new(Msg)
|
||||
err := req.Unpack(m)
|
||||
err := req.Unpack(w.msg)
|
||||
if err != nil { // Send a FormatError back
|
||||
x := new(Msg)
|
||||
x.SetRcodeFormatError(req)
|
||||
w.WriteMsg(x)
|
||||
goto Exit
|
||||
return
|
||||
}
|
||||
if !srv.Unsafe && req.Response {
|
||||
goto Exit
|
||||
return
|
||||
}
|
||||
|
||||
w.tsigStatus = nil
|
||||
if w.tsigSecret != nil {
|
||||
if t := req.IsTsig(); t != nil {
|
||||
secret := t.Hdr.Name
|
||||
if _, ok := w.tsigSecret[secret]; !ok {
|
||||
w.tsigStatus = ErrKeyAlg
|
||||
if secret, ok := w.tsigSecret[t.Hdr.Name]; ok {
|
||||
w.tsigStatus = TsigVerify(w.msg, secret, "", false)
|
||||
} else {
|
||||
w.tsigStatus = ErrSecret
|
||||
}
|
||||
w.tsigStatus = TsigVerify(m, w.tsigSecret[secret], "", false)
|
||||
w.tsigTimersOnly = false
|
||||
w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC
|
||||
}
|
||||
}
|
||||
h.ServeDNS(w, req) // Writes back to the client
|
||||
|
||||
Exit:
|
||||
if w.tcp == nil {
|
||||
return
|
||||
}
|
||||
// TODO(miek): make this number configurable?
|
||||
if q > maxTCPQueries { // close socket after this many queries
|
||||
w.Close()
|
||||
return
|
||||
handler := srv.Handler
|
||||
if handler == nil {
|
||||
handler = DefaultServeMux
|
||||
}
|
||||
|
||||
if w.hijacked {
|
||||
return // client calls Close()
|
||||
}
|
||||
if u != nil { // UDP, "close" and return
|
||||
w.Close()
|
||||
return
|
||||
}
|
||||
idleTimeout := tcpIdleTimeout
|
||||
if srv.IdleTimeout != nil {
|
||||
idleTimeout = srv.IdleTimeout()
|
||||
}
|
||||
m, err = reader.ReadTCP(w.tcp, idleTimeout)
|
||||
if err == nil {
|
||||
q++
|
||||
goto Redo
|
||||
}
|
||||
w.Close()
|
||||
return
|
||||
handler.ServeDNS(w, req) // Writes back to the client
|
||||
}
|
||||
|
||||
func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
|
||||
|
@ -696,7 +748,12 @@ func (w *response) LocalAddr() net.Addr {
|
|||
}
|
||||
|
||||
// RemoteAddr implements the ResponseWriter.RemoteAddr method.
|
||||
func (w *response) RemoteAddr() net.Addr { return w.remoteAddr }
|
||||
func (w *response) RemoteAddr() net.Addr {
|
||||
if w.tcp != nil {
|
||||
return w.tcp.RemoteAddr()
|
||||
}
|
||||
return w.udpSession.RemoteAddr()
|
||||
}
|
||||
|
||||
// TsigStatus implements the ResponseWriter.TsigStatus method.
|
||||
func (w *response) TsigStatus() error { return w.tsigStatus }
|
||||
|
|
|
@ -9,6 +9,22 @@ import (
|
|||
"golang.org/x/net/ipv6"
|
||||
)
|
||||
|
||||
// This is the required size of the OOB buffer to pass to ReadMsgUDP.
|
||||
var udpOOBSize = func() int {
|
||||
// We can't know whether we'll get an IPv4 control message or an
|
||||
// IPv6 control message ahead of time. To get around this, we size
|
||||
// the buffer equal to the largest of the two.
|
||||
|
||||
oob4 := ipv4.NewControlMessage(ipv4.FlagDst | ipv4.FlagInterface)
|
||||
oob6 := ipv6.NewControlMessage(ipv6.FlagDst | ipv6.FlagInterface)
|
||||
|
||||
if len(oob4) > len(oob6) {
|
||||
return len(oob4)
|
||||
}
|
||||
|
||||
return len(oob6)
|
||||
}()
|
||||
|
||||
// SessionUDP holds the remote address and the associated
|
||||
// out-of-band data.
|
||||
type SessionUDP struct {
|
||||
|
@ -22,7 +38,7 @@ func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
|||
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
||||
// net.UDPAddr.
|
||||
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
||||
oob := make([]byte, 40)
|
||||
oob := make([]byte, udpOOBSize)
|
||||
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
|
||||
if err != nil {
|
||||
return n, nil, err
|
||||
|
@ -53,18 +69,15 @@ func parseDstFromOOB(oob []byte) net.IP {
|
|||
// Start with IPv6 and then fallback to IPv4
|
||||
// TODO(fastest963): Figure out a way to prefer one or the other. Looking at
|
||||
// the lvl of the header for a 0 or 41 isn't cross-platform.
|
||||
var dst net.IP
|
||||
cm6 := new(ipv6.ControlMessage)
|
||||
if cm6.Parse(oob) == nil {
|
||||
dst = cm6.Dst
|
||||
if cm6.Parse(oob) == nil && cm6.Dst != nil {
|
||||
return cm6.Dst
|
||||
}
|
||||
if dst == nil {
|
||||
cm4 := new(ipv4.ControlMessage)
|
||||
if cm4.Parse(oob) == nil {
|
||||
dst = cm4.Dst
|
||||
if cm4.Parse(oob) == nil && cm4.Dst != nil {
|
||||
return cm4.Dst
|
||||
}
|
||||
}
|
||||
return dst
|
||||
return nil
|
||||
}
|
||||
|
||||
// correctSource takes oob data and returns new oob data with the Src equal to the Dst
|
||||
|
|
|
@ -5,6 +5,7 @@ package dns
|
|||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -74,6 +75,14 @@ func TestSetUDPSocketOptions(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestParseDstFromOOB(t *testing.T) {
|
||||
if runtime.GOARCH != "amd64" {
|
||||
// The cmsghdr struct differs in the width (32/64-bit) of
|
||||
// lengths and the struct padding between architectures.
|
||||
// The data below was only written with amd64 in mind, and
|
||||
// thus the test must be skipped on other architectures.
|
||||
t.Skip("skipping test on unsupported architecture")
|
||||
}
|
||||
|
||||
// dst is :ffff:100.100.100.100
|
||||
oob := []byte{36, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 100, 100, 100, 100, 2, 0, 0, 0}
|
||||
dst := parseDstFromOOB(oob)
|
||||
|
@ -106,6 +115,11 @@ func TestParseDstFromOOB(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestCorrectSource(t *testing.T) {
|
||||
if runtime.GOARCH != "amd64" {
|
||||
// See comment above in TestParseDstFromOOB.
|
||||
t.Skip("skipping test on unsupported architecture")
|
||||
}
|
||||
|
||||
// dst is :ffff:100.100.100.100 which should be counted as IPv4
|
||||
oob := []byte{36, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 100, 100, 100, 100, 2, 0, 0, 0}
|
||||
soob := correctSource(oob)
|
||||
|
|
|
@ -3,7 +3,7 @@ package dns
|
|||
import "fmt"
|
||||
|
||||
// Version is current version of this library.
|
||||
var Version = V{1, 0, 5}
|
||||
var Version = V{1, 0, 6}
|
||||
|
||||
// V holds the version of this library.
|
||||
type V struct {
|
||||
|
|
|
@ -32,7 +32,7 @@ import (
|
|||
// be either 8 or 24 bytes long.
|
||||
func XORKeyStream(out, in []byte, nonce []byte, key *[32]byte) {
|
||||
if len(out) < len(in) {
|
||||
in = in[:len(out)]
|
||||
panic("salsa20: output smaller than input")
|
||||
}
|
||||
|
||||
var subNonce [16]byte
|
||||
|
|
|
@ -14,6 +14,21 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// SniffedContentType reports whether ct is a Content-Type that is known
|
||||
// to cause client-side content sniffing.
|
||||
//
|
||||
// This provides just a partial implementation of mime.ParseMediaType
|
||||
// with the assumption that the Content-Type is not attacker controlled.
|
||||
func SniffedContentType(ct string) bool {
|
||||
if i := strings.Index(ct, ";"); i != -1 {
|
||||
ct = ct[:i]
|
||||
}
|
||||
ct = strings.ToLower(strings.TrimSpace(ct))
|
||||
return ct == "text/plain" || ct == "application/octet-stream" ||
|
||||
ct == "application/unknown" || ct == "unknown/unknown" || ct == "*/*" ||
|
||||
!strings.Contains(ct, "/")
|
||||
}
|
||||
|
||||
// ValidTrailerHeader reports whether name is a valid header field name to appear
|
||||
// in trailers.
|
||||
// See RFC 7230, Section 4.1.2
|
||||
|
|
|
@ -2,12 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package httplex contains rules around lexical matters of various
|
||||
// HTTP-related specifications.
|
||||
//
|
||||
// This package is shared by the standard library (which vendors it)
|
||||
// and x/net/http2. It comes with no API stability promise.
|
||||
package httplex
|
||||
package httpguts
|
||||
|
||||
import (
|
||||
"net"
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package httplex
|
||||
package httpguts
|
||||
|
||||
import (
|
||||
"testing"
|
|
@ -14,8 +14,8 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"golang.org/x/net/lex/httplex"
|
||||
)
|
||||
|
||||
const frameHeaderLen = 9
|
||||
|
@ -1462,7 +1462,7 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) {
|
|||
if VerboseLogs && fr.logReads {
|
||||
fr.debugReadLoggerf("http2: decoded hpack field %+v", hf)
|
||||
}
|
||||
if !httplex.ValidHeaderFieldValue(hf.Value) {
|
||||
if !httpguts.ValidHeaderFieldValue(hf.Value) {
|
||||
invalid = headerFieldValueError(hf.Value)
|
||||
}
|
||||
isPseudo := strings.HasPrefix(hf.Name, ":")
|
||||
|
|
|
@ -389,6 +389,12 @@ func (d *Decoder) callEmit(hf HeaderField) error {
|
|||
|
||||
// (same invariants and behavior as parseHeaderFieldRepr)
|
||||
func (d *Decoder) parseDynamicTableSizeUpdate() error {
|
||||
// RFC 7541, sec 4.2: This dynamic table size update MUST occur at the
|
||||
// beginning of the first header block following the change to the dynamic table size.
|
||||
if d.dynTab.size > 0 {
|
||||
return DecodingError{errors.New("dynamic table size update MUST occur at the beginning of a header block")}
|
||||
}
|
||||
|
||||
buf := d.buf
|
||||
size, buf, err := readVarInt(5, buf)
|
||||
if err != nil {
|
||||
|
|
|
@ -720,3 +720,22 @@ func TestSaveBufLimit(t *testing.T) {
|
|||
t.Fatalf("Write error = %v; want ErrStringLength", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDynamicSizeUpdate(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
enc := NewEncoder(&buf)
|
||||
enc.SetMaxDynamicTableSize(255)
|
||||
enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
|
||||
|
||||
d := NewDecoder(4096, nil)
|
||||
_, err := d.DecodeFull(buf.Bytes())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: got = %v", err)
|
||||
}
|
||||
|
||||
// must fail since the dynamic table update must be at the beginning
|
||||
_, err = d.DecodeFull(buf.Bytes())
|
||||
if err == nil {
|
||||
t.Fatalf("dynamic table size update not at the beginning of a header block")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/net/lex/httplex"
|
||||
"golang.org/x/net/http/httpguts"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -179,7 +179,7 @@ var (
|
|||
)
|
||||
|
||||
// validWireHeaderFieldName reports whether v is a valid header field
|
||||
// name (key). See httplex.ValidHeaderName for the base rules.
|
||||
// name (key). See httpguts.ValidHeaderName for the base rules.
|
||||
//
|
||||
// Further, http2 says:
|
||||
// "Just as in HTTP/1.x, header field names are strings of ASCII
|
||||
|
@ -191,7 +191,7 @@ func validWireHeaderFieldName(v string) bool {
|
|||
return false
|
||||
}
|
||||
for _, r := range v {
|
||||
if !httplex.IsTokenRune(r) {
|
||||
if !httpguts.IsTokenRune(r) {
|
||||
return false
|
||||
}
|
||||
if 'A' <= r && r <= 'Z' {
|
||||
|
|
|
@ -2309,6 +2309,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
|||
isHeadResp := rws.req.Method == "HEAD"
|
||||
if !rws.sentHeader {
|
||||
rws.sentHeader = true
|
||||
|
||||
var ctype, clen string
|
||||
if clen = rws.snapHeader.Get("Content-Length"); clen != "" {
|
||||
rws.snapHeader.Del("Content-Length")
|
||||
|
@ -2322,6 +2323,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
|||
if clen == "" && rws.handlerDone && bodyAllowedForStatus(rws.status) && (len(p) > 0 || !isHeadResp) {
|
||||
clen = strconv.Itoa(len(p))
|
||||
}
|
||||
|
||||
_, hasContentType := rws.snapHeader["Content-Type"]
|
||||
if !hasContentType && bodyAllowedForStatus(rws.status) && len(p) > 0 {
|
||||
if cto := rws.snapHeader.Get("X-Content-Type-Options"); strings.EqualFold("nosniff", cto) {
|
||||
|
@ -2334,6 +2336,20 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
|||
ctype = http.DetectContentType(p)
|
||||
}
|
||||
}
|
||||
|
||||
var noSniff bool
|
||||
if bodyAllowedForStatus(rws.status) && (rws.sentContentLen > 0 || len(p) > 0) {
|
||||
// If the content type triggers client-side sniffing on old browsers,
|
||||
// attach a X-Content-Type-Options header if not present (or explicitly nil).
|
||||
if _, ok := rws.snapHeader["X-Content-Type-Options"]; !ok {
|
||||
if hasContentType {
|
||||
noSniff = httpguts.SniffedContentType(rws.snapHeader.Get("Content-Type"))
|
||||
} else if ctype != "" {
|
||||
noSniff = httpguts.SniffedContentType(ctype)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var date string
|
||||
if _, ok := rws.snapHeader["Date"]; !ok {
|
||||
// TODO(bradfitz): be faster here, like net/http? measure.
|
||||
|
@ -2352,6 +2368,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
|
|||
endStream: endStream,
|
||||
contentType: ctype,
|
||||
contentLength: clen,
|
||||
noSniff: noSniff,
|
||||
date: date,
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -1810,6 +1810,7 @@ func TestServer_Response_TransferEncoding_chunked(t *testing.T) {
|
|||
{":status", "200"},
|
||||
{"content-type", "text/plain; charset=utf-8"},
|
||||
{"content-length", strconv.Itoa(len(msg))},
|
||||
{"x-content-type-options", "nosniff"},
|
||||
}
|
||||
if !reflect.DeepEqual(goth, wanth) {
|
||||
t.Errorf("Got headers %v; want %v", goth, wanth)
|
||||
|
@ -1998,6 +1999,7 @@ func TestServer_Response_LargeWrite(t *testing.T) {
|
|||
wanth := [][2]string{
|
||||
{":status", "200"},
|
||||
{"content-type", "text/plain; charset=utf-8"}, // sniffed
|
||||
{"x-content-type-options", "nosniff"},
|
||||
// and no content-length
|
||||
}
|
||||
if !reflect.DeepEqual(goth, wanth) {
|
||||
|
@ -2212,6 +2214,7 @@ func TestServer_Response_Automatic100Continue(t *testing.T) {
|
|||
{":status", "200"},
|
||||
{"content-type", "text/plain; charset=utf-8"},
|
||||
{"content-length", strconv.Itoa(len(reply))},
|
||||
{"x-content-type-options", "nosniff"},
|
||||
}
|
||||
if !reflect.DeepEqual(goth, wanth) {
|
||||
t.Errorf("Got headers %v; want %v", goth, wanth)
|
||||
|
@ -2935,6 +2938,7 @@ func testServerWritesTrailers(t *testing.T, withFlush bool) {
|
|||
{"trailer", "Transfer-Encoding, Content-Length, Trailer"},
|
||||
{"content-type", "text/plain; charset=utf-8"},
|
||||
{"content-length", "5"},
|
||||
{"x-content-type-options", "nosniff"},
|
||||
}
|
||||
if !reflect.DeepEqual(goth, wanth) {
|
||||
t.Errorf("Header mismatch.\n got: %v\nwant: %v", goth, wanth)
|
||||
|
@ -3326,6 +3330,7 @@ func TestServerNoDuplicateContentType(t *testing.T) {
|
|||
{":status", "200"},
|
||||
{"content-type", ""},
|
||||
{"content-length", "41"},
|
||||
{"x-content-type-options", "nosniff"},
|
||||
}
|
||||
if !reflect.DeepEqual(headers, want) {
|
||||
t.Errorf("Headers mismatch.\n got: %q\nwant: %q\n", headers, want)
|
||||
|
|
|
@ -27,9 +27,9 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"golang.org/x/net/idna"
|
||||
"golang.org/x/net/lex/httplex"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -567,6 +567,10 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
|
|||
// henc in response to SETTINGS frames?
|
||||
cc.henc = hpack.NewEncoder(&cc.hbuf)
|
||||
|
||||
if t.AllowHTTP {
|
||||
cc.nextStreamID = 3
|
||||
}
|
||||
|
||||
if cs, ok := c.(connectionStater); ok {
|
||||
state := cs.ConnectionState()
|
||||
cc.tlsState = &state
|
||||
|
@ -1177,7 +1181,7 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
|
|||
if host == "" {
|
||||
host = req.URL.Host
|
||||
}
|
||||
host, err := httplex.PunycodeHostPort(host)
|
||||
host, err := httpguts.PunycodeHostPort(host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1202,11 +1206,11 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
|
|||
// potentially pollute our hpack state. (We want to be able to
|
||||
// continue to reuse the hpack encoder for future requests)
|
||||
for k, vv := range req.Header {
|
||||
if !httplex.ValidHeaderFieldName(k) {
|
||||
if !httpguts.ValidHeaderFieldName(k) {
|
||||
return nil, fmt.Errorf("invalid HTTP header name %q", k)
|
||||
}
|
||||
for _, v := range vv {
|
||||
if !httplex.ValidHeaderFieldValue(v) {
|
||||
if !httpguts.ValidHeaderFieldValue(v) {
|
||||
return nil, fmt.Errorf("invalid HTTP header value %q for header %q", v, k)
|
||||
}
|
||||
}
|
||||
|
@ -2247,7 +2251,7 @@ func (t *Transport) getBodyWriterState(cs *clientStream, body io.Reader) (s body
|
|||
}
|
||||
s.delay = t.expectContinueTimeout()
|
||||
if s.delay == 0 ||
|
||||
!httplex.HeaderValuesContainsToken(
|
||||
!httpguts.HeaderValuesContainsToken(
|
||||
cs.req.Header["Expect"],
|
||||
"100-continue") {
|
||||
return
|
||||
|
@ -2302,5 +2306,5 @@ func (s bodyWriterState) scheduleBodyWrite() {
|
|||
// isConnectionCloseRequest reports whether req should use its own
|
||||
// connection for a single request and then close the connection.
|
||||
func isConnectionCloseRequest(req *http.Request) bool {
|
||||
return req.Close || httplex.HeaderValuesContainsToken(req.Header["Connection"], "close")
|
||||
return req.Close || httpguts.HeaderValuesContainsToken(req.Header["Connection"], "close")
|
||||
}
|
||||
|
|
|
@ -146,6 +146,7 @@ func TestTransport(t *testing.T) {
|
|||
}
|
||||
wantHeader := http.Header{
|
||||
"Content-Length": []string{"3"},
|
||||
"X-Content-Type-Options": []string{"nosniff"},
|
||||
"Content-Type": []string{"text/plain; charset=utf-8"},
|
||||
"Date": []string{"XXX"}, // see cleanDate
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ import (
|
|||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"golang.org/x/net/lex/httplex"
|
||||
)
|
||||
|
||||
// writeFramer is implemented by any type that is used to write frames.
|
||||
|
@ -186,6 +186,7 @@ type writeResHeaders struct {
|
|||
date string
|
||||
contentType string
|
||||
contentLength string
|
||||
noSniff bool
|
||||
}
|
||||
|
||||
func encKV(enc *hpack.Encoder, k, v string) {
|
||||
|
@ -222,6 +223,9 @@ func (w *writeResHeaders) writeFrame(ctx writeContext) error {
|
|||
if w.contentLength != "" {
|
||||
encKV(enc, "content-length", w.contentLength)
|
||||
}
|
||||
if w.noSniff {
|
||||
encKV(enc, "x-content-type-options", "nosniff")
|
||||
}
|
||||
if w.date != "" {
|
||||
encKV(enc, "date", w.date)
|
||||
}
|
||||
|
@ -350,7 +354,7 @@ func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) {
|
|||
}
|
||||
isTE := k == "transfer-encoding"
|
||||
for _, v := range vv {
|
||||
if !httplex.ValidHeaderFieldValue(v) {
|
||||
if !httpguts.ValidHeaderFieldValue(v) {
|
||||
// TODO: return an error? golang.org/issue/14048
|
||||
// For now just omit it.
|
||||
continue
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
func TestAMD64minimalFeatures(t *testing.T) {
|
||||
if runtime.GOARCH == "amd64" {
|
||||
if !cpu.X86.HasSSE2 {
|
||||
t.Fatalf("HasSSE2 expected true, got false")
|
||||
t.Fatal("HasSSE2 expected true, got false")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ func TestAMD64minimalFeatures(t *testing.T) {
|
|||
func TestAVX2hasAVX(t *testing.T) {
|
||||
if runtime.GOARCH == "amd64" {
|
||||
if cpu.X86.HasAVX2 && !cpu.X86.HasAVX {
|
||||
t.Fatalf("HasAVX expected true, got false")
|
||||
t.Fatal("HasAVX expected true, got false")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
// System calls for 386, Windows are implemented in runtime/syscall_windows.goc
|
||||
//
|
||||
|
||||
TEXT ·getprocaddress(SB), 7, $0-8
|
||||
TEXT ·getprocaddress(SB), 7, $0-16
|
||||
JMP syscall·getprocaddress(SB)
|
||||
|
||||
TEXT ·loadlibrary(SB), 7, $0-4
|
||||
TEXT ·loadlibrary(SB), 7, $0-12
|
||||
JMP syscall·loadlibrary(SB)
|
||||
|
|
|
@ -121,7 +121,7 @@ func (s *Service) Config() (Config, error) {
|
|||
}
|
||||
|
||||
func updateDescription(handle windows.Handle, desc string) error {
|
||||
d := windows.SERVICE_DESCRIPTION{toPtr(desc)}
|
||||
d := windows.SERVICE_DESCRIPTION{Description: toPtr(desc)}
|
||||
return windows.ChangeServiceConfig2(handle,
|
||||
windows.SERVICE_CONFIG_DESCRIPTION, (*byte)(unsafe.Pointer(&d)))
|
||||
}
|
||||
|
|
|
@ -334,8 +334,8 @@ func Run(name string, handler Handler) error {
|
|||
var svcmain uintptr
|
||||
getServiceMain(&svcmain)
|
||||
t := []windows.SERVICE_TABLE_ENTRY{
|
||||
{syscall.StringToUTF16Ptr(s.name), svcmain},
|
||||
{nil, 0},
|
||||
{ServiceName: syscall.StringToUTF16Ptr(s.name), ServiceProc: svcmain},
|
||||
{ServiceName: nil, ServiceProc: 0},
|
||||
}
|
||||
|
||||
goWaitsH = uintptr(s.goWaits.h)
|
||||
|
|
Loading…
Reference in New Issue