mirror of
https://github.com/coredns/coredns.git
synced 2026-10-17 07:45:42 -04:00
The proxyproto plugin parsed PROXY protocol v2 headers only to recover the real client address; the TLV vector was discarded, so downstream plugins had no way to read values such as the AWS VPC endpoint ID, SSL client CN, or vendor-specific custom TLVs. Add an opt-in `tlv_metadata` option. When set, the connection's raw PPv2 TLV vector is captured and the plugin, acting as a metadata.Provider, publishes it under the `proxyproto/tlv` label as a hex-encoded string. Consumers decode and split it with proxyproto.SplitTLVs. The option is off by default, so existing deployments skip the extra per-connection processing and behave exactly as before. PROXY protocol v1 connections, which carry no TLVs, are unaffected. Capture spans all transports: dns:// (UDP and TCP), tls:// (DoT), https:// (DoH), grpc://, quic:// (DoQ), and https3:// (DoH3). QUIC-based transports require udp_session_tracking, since the PPv2 header arrives as a standalone first datagram ahead of the QUIC handshake. Includes unit tests for capture, the metadata provider (direct and through the real metadata chain), v1 compatibility, and option parsing, plus README and man page updates. Fixes #8633 Signed-off-by: Mekias Yohannes <mekias@amazon.com> Co-authored-by: Mekias Yohannes <mekias@amazon.com>
105 lines
2.6 KiB
Go
105 lines
2.6 KiB
Go
package dnsserver
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/coredns/caddy"
|
|
cproxyproto "github.com/coredns/coredns/plugin/pkg/proxyproto"
|
|
"github.com/coredns/coredns/plugin/pkg/reuseport"
|
|
"github.com/coredns/coredns/plugin/pkg/transport"
|
|
|
|
"github.com/miekg/dns"
|
|
"github.com/pires/go-proxyproto"
|
|
)
|
|
|
|
// ServerTLS represents an instance of a TLS-over-DNS-server.
|
|
type ServerTLS struct {
|
|
*Server
|
|
tlsConfig *tls.Config
|
|
}
|
|
|
|
// NewServerTLS returns a new CoreDNS TLS server and compiles all plugin in to it.
|
|
func NewServerTLS(addr string, group []*Config) (*ServerTLS, error) {
|
|
tlsConfig, err := sharedTLSConfig(addr, group)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s, err := NewServer(addr, group)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ServerTLS{Server: s, tlsConfig: tlsConfig}, nil
|
|
}
|
|
|
|
// Compile-time check to ensure ServerTLS implements the caddy.GracefulServer interface
|
|
var _ caddy.GracefulServer = &ServerTLS{}
|
|
|
|
// Serve implements caddy.TCPServer interface.
|
|
func (s *ServerTLS) Serve(l net.Listener) error {
|
|
s.m.Lock()
|
|
|
|
if s.tlsConfig != nil {
|
|
l = tls.NewListener(l, s.tlsConfig)
|
|
}
|
|
|
|
// Only fill out the TCP server for this one.
|
|
s.server[tcp] = &dns.Server{Listener: l,
|
|
Net: "tcp-tls",
|
|
TsigSecret: s.TsigSecret,
|
|
MsgAcceptFunc: s.msgAcceptFunc(),
|
|
MaxTCPQueries: s.MaxTCPQueries,
|
|
ReadTimeout: s.ReadTimeout,
|
|
WriteTimeout: s.WriteTimeout,
|
|
IdleTimeout: func() time.Duration {
|
|
return s.IdleTimeout
|
|
},
|
|
Handler: dns.HandlerFunc(func(w dns.ResponseWriter, r *dns.Msg) {
|
|
ctx := context.WithValue(context.Background(), Key{}, s.Server)
|
|
ctx = context.WithValue(ctx, LoopKey{}, 0)
|
|
s.ServeDNS(ctx, w, r)
|
|
})}
|
|
|
|
s.m.Unlock()
|
|
|
|
return s.server[tcp].ActivateAndServe()
|
|
}
|
|
|
|
// ServePacket implements caddy.UDPServer interface.
|
|
func (s *ServerTLS) ServePacket(_p net.PacketConn) error { return nil }
|
|
|
|
// Listen implements caddy.TCPServer interface.
|
|
func (s *ServerTLS) Listen() (net.Listener, error) {
|
|
l, err := reuseport.Listen("tcp", s.Addr[len(transport.TLS+"://"):])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if s.connPolicy != nil {
|
|
if s.proxyProtoTLVMetadata {
|
|
l = cproxyproto.NewTLVListener(l, s.connPolicy)
|
|
} else {
|
|
l = &proxyproto.Listener{Listener: l, ConnPolicy: s.connPolicy}
|
|
}
|
|
}
|
|
return l, nil
|
|
}
|
|
|
|
// ListenPacket implements caddy.UDPServer interface.
|
|
func (s *ServerTLS) ListenPacket() (net.PacketConn, error) { return nil, nil }
|
|
|
|
// OnStartupComplete lists the sites served by this server
|
|
// and any relevant information, assuming Quiet is false.
|
|
func (s *ServerTLS) OnStartupComplete() {
|
|
if Quiet {
|
|
return
|
|
}
|
|
|
|
out := startUpZones(transport.TLS+"://", s.Addr, s.zones)
|
|
if out != "" {
|
|
printStartup(out)
|
|
}
|
|
}
|