dsosession

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

README

Go Reference Coverage Status CI

dsosession

dsosession provides RFC 8490 DNS Stateful Operations and RFC 8765 DNS Push Notifications session machinery.

See Also

[coredns-dso][https://github.com/Kentzo/coredns-dso] for extended example.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrState       = fmt.Errorf("bad DSO state")
	ErrStateClosed = fmt.Errorf("%w - closed", ErrState)
)
View Source
var ErrDuplicateSub = errors.New("duplicate Push subscription")
View Source
var SessionGracefulCloseTimeout = 5 * time.Second

SessionGracefulCloseTimeout is amount of time before aborting after termination is initiated.

RFC 8490, Section 6.6.1: After sending a DSO Retry Delay message, the server SHOULD allow the client five seconds to close the connection.

Functions

func AbortConn

func AbortConn(conn net.Conn) error

AbortConn aborts connection using NetConn() and SetLinger(), if available.

Types

type Push

type Push struct {
	// contains filtered or unexported fields
}

Push stores DSO Push subscriptions.

func NewPush

func NewPush(classes, types []uint16) *Push

NewPush returns new Push service.

Classes and types, which Push takes ownership of, control allowed subscriptions and wildcard expansion. Must be sorted in increasing order.

func (*Push) Add

func (push *Push) Add(id uint16, sub PushSubscribe)

Add adds subscription.

func (*Push) CanAdd

func (push *Push) CanAdd(id uint16, tlv dsomessage.Subscribe) (sub PushSubscribe, rcode uint8, err error)

CanAdd checks if subscription can be added.

Non-nil error indicates fatal protocol violation. Rcode indicates whether and how subscription request should be rejected. Only dns.RcodeSuccess indicates that subscription is vetted for Push.Add.

func (*Push) IsActive

func (push *Push) IsActive() bool

IsActive returns whether there are active subscriptions.

func (*Push) Reconfirm

func (push *Push) Reconfirm(tlv dsomessage.Reconfirm)

Reconfirm schedules check that confirms whether RDATA is accurate.

func (*Push) Refresh

func (push *Push) Refresh()

Refresh subscriptions ahead of periodic interval.

func (*Push) Remove

func (push *Push) Remove(tlv dsomessage.Unsubscribe) (dsomessage.Subscribe, bool)

Remove stops refreshing subscription. It's permitted to remove non-existent subscriptions.

func (*Push) Serve

func (push *Push) Serve(ctx context.Context, writer io.Writer, upstream PushLookuper, debounceDelay, refreshInterval time.Duration) error

Serve serves Push session by updating clients until context is cancelled.

Subscriptions are periodically refreshed (refreshInterval) via upstream lookups. Initial subscription burst is countered by debounceDelay. The difference is sent to client.

See also PushDebugWriter.

Returns context.Context.Err if stopped gracefully. Otherwise returns resolving, packing or writing error.

func (*Push) Subscriptions

func (push *Push) Subscriptions() iter.Seq[dsomessage.Subscribe]

Subscriptions returns currently active subscriptions.

type PushDebugWriter added in v0.2.0

type PushDebugWriter interface {
	io.Writer

	// WritePushChange receives deep copy of change after it's written.
	WritePushChange(change []dns.RR)
}

PushDebugWriter can be optionally implemented by writer passed to Push.Serve to observe changes sent to client.

type PushLookuper

type PushLookuper interface {
	// Lookup returns RRset that corresponds to given subscription.
	//
	// Lookup can be abandoned once context is cancelled.
	// Returned RRset must follow RFC 8765, Section 6.3.1
	LookupPushSubscription(ctx context.Context, tlv dsomessage.Subscribe) (rrs []dns.RR, ok bool)
}

PushLookuper resolves subscription on behalf of Push.

type PushSubscribe

type PushSubscribe struct {
	dsomessage.Subscribe
	// contains filtered or unexported fields
}

PushSubscribe is dsomessage.Subscribe vetted by Push.CanAdd.

type Session

type Session struct {
	Conn net.Conn
	// contains filtered or unexported fields
}

Session implements server-side state management of RFC 8490 DNS Stateful Operations session.

  1. Initially, state is StateWaiting
  2. First written DSO response with RCODE=0 is establishing response, it changes state to StatePending
  3. If write fails state is reset back to StateWaiting. Otherwise it's changed to StateEstablished
  4. First written unidirectional with dsomessage.RetryDelay primary TLV initiates termination and changes state to StateClosing
  5. Once connection is closed, state is changed to StateClosed

Once session termination is initiated, no more messages can be written. If write of terminating message fails state remains StateClosing until Session.Close or Session.Abort is called.

func New

func New(conn net.Conn) (s *Session)

New creates new Session.

func (*Session) Abort

func (s *Session) Abort() error

Abort forcibly closes underlying connection, e.g. with RST.

Abort is implemented by calling NetConn() and SetLinger(0) on underlying connection, if possible.

func (*Session) Close

func (s *Session) Close() error

Close closes underlying connection.

func (*Session) Drain

func (s *Session) Drain() (err error)

Drain drains connection including its underlying transport, if any.

Draining makes peer responsible to send FIN and thus avoids TIME-WAIT on socket behind Session.Conn.

RFC 8490, Section 5.3: Where this specification requires a connection to be closed gracefully, the requirement to initiate that graceful close is placed on the client in order to place the burden of TCP's TIME-WAIT state on the client rather than the server.

func (*Session) ReadMsg

func (s *Session) ReadMsg(deadline time.Time) (msg []byte, err error)

ReadMsg reads and returns one DNS message without length-prefix.

func (*Session) State

func (s *Session) State() (state State)

State returns current state.

func (*Session) Write

func (s *Session) Write(msg []byte) (n int, err error)

Write writes length-prefixed message and updates session's state if needed.

Returns ErrStateClosed if session is closed, ErrState if it's in wrong state. Otherwise IO error is returned, if any.

Session terminating dsomessage.RetryDelay unidirectional is recognized: it's last allowed message.

type State

type State uint32
const (
	// StateWaiting is state where session is waiting for establishing response:
	//  - Any DNS can be read or written
	//  - Only DSO requests can be read
	//  - Only DSO responses can be written
	StateWaiting State = iota
	// StatePending is state where session is handling writing establishing response:
	//  - Any DNS can be read or written
	//  - Any DSO can be read
	//  - Only DSO responses can be written
	StatePending
	// StateEstablished is state where session is successfully established:
	//  - Any DNS can be read or written
	//  - Any DSO can be read or written
	StateEstablished
	// StateClosing is state where session is closed but underlying connect may still functional:
	//  - Any DNS can be read or written
	//  - Any DSO can be read
	//  - No DSO can be written
	StateClosing
	// StateClosed is state where session is closed and underlying connection is non-functional:
	//  - No DNS can be read or written
	//  - No DSO can be read or written
	StateClosed
)

func (State) String

func (s State) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL