parent
3710182f0f
commit
dea4cb300a
35
server.go
35
server.go
|
@ -44,9 +44,10 @@ type response struct {
|
||||||
tsigTimersOnly bool
|
tsigTimersOnly bool
|
||||||
tsigRequestMAC string
|
tsigRequestMAC string
|
||||||
tsigSecret map[string]string // the tsig secrets
|
tsigSecret map[string]string // the tsig secrets
|
||||||
udp *net.UDPConn // i/o connection if UDP was used
|
udp *UDPConn // i/o connection if UDP was used
|
||||||
tcp *net.TCPConn // i/o connection if TCP was used
|
udpSession *UDPSession
|
||||||
remoteAddr net.Addr // address of the client
|
tcp *net.TCPConn // i/o connection if TCP was used
|
||||||
|
remoteAddr net.Addr // address of the client
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeMux is an DNS request multiplexer. It matches the
|
// ServeMux is an DNS request multiplexer. It matches the
|
||||||
|
@ -242,7 +243,13 @@ func (srv *Server) ListenAndServe() error {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
return srv.serveUDP(l)
|
|
||||||
|
ll, e := NewUDPConn(l)
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
return srv.serveUDP(ll)
|
||||||
}
|
}
|
||||||
return &Error{err: "bad network"}
|
return &Error{err: "bad network"}
|
||||||
}
|
}
|
||||||
|
@ -268,14 +275,14 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
go srv.serve(rw.RemoteAddr(), handler, m, nil, rw)
|
go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
|
||||||
}
|
}
|
||||||
panic("dns: not reached")
|
panic("dns: not reached")
|
||||||
}
|
}
|
||||||
|
|
||||||
// serveUDP starts a UDP listener for the server.
|
// serveUDP starts a UDP listener for the server.
|
||||||
// Each request is handled in a seperate goroutine.
|
// Each request is handled in a seperate goroutine.
|
||||||
func (srv *Server) serveUDP(l *net.UDPConn) error {
|
func (srv *Server) serveUDP(l *UDPConn) error {
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
handler := srv.Handler
|
handler := srv.Handler
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
|
@ -286,19 +293,19 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
||||||
rtimeout = srv.ReadTimeout
|
rtimeout = srv.ReadTimeout
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
m, a, e := srv.readUDP(l, rtimeout)
|
m, s, e := srv.readUDP(l, rtimeout)
|
||||||
if e != nil {
|
if e != nil {
|
||||||
// TODO(miek): logging?
|
// TODO(miek): logging?
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
go srv.serve(a, handler, m, l, nil)
|
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
|
||||||
}
|
}
|
||||||
panic("dns: not reached")
|
panic("dns: not reached")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve a new connection.
|
// Serve a new connection.
|
||||||
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, t *net.TCPConn) {
|
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *UDPConn, s *UDPSession, t *net.TCPConn) {
|
||||||
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a}
|
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
|
||||||
q := 0
|
q := 0
|
||||||
Redo:
|
Redo:
|
||||||
req := new(Msg)
|
req := new(Msg)
|
||||||
|
@ -385,9 +392,9 @@ func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, er
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, net.Addr, error) {
|
func (srv *Server) readUDP(conn *UDPConn, timeout time.Duration) ([]byte, *UDPSession, error) {
|
||||||
m := make([]byte, srv.UDPSize)
|
m := make([]byte, srv.UDPSize)
|
||||||
n, a, e := conn.ReadFromUDP(m)
|
n, s, e := conn.ReadFromSessionUDP(m)
|
||||||
if e != nil || n == 0 {
|
if e != nil || n == 0 {
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return nil, nil, e
|
return nil, nil, e
|
||||||
|
@ -395,7 +402,7 @@ func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, ne
|
||||||
return nil, nil, ErrShortRead
|
return nil, nil, ErrShortRead
|
||||||
}
|
}
|
||||||
m = m[:n]
|
m = m[:n]
|
||||||
return m, a, nil
|
return m, s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteMsg implements the ResponseWriter.WriteMsg method.
|
// WriteMsg implements the ResponseWriter.WriteMsg method.
|
||||||
|
@ -423,7 +430,7 @@ func (w *response) WriteMsg(m *Msg) (err error) {
|
||||||
func (w *response) Write(m []byte) (int, error) {
|
func (w *response) Write(m []byte) (int, error) {
|
||||||
switch {
|
switch {
|
||||||
case w.udp != nil:
|
case w.udp != nil:
|
||||||
n, err := w.udp.WriteTo(m, w.remoteAddr)
|
n, err := w.udp.WriteToSessionUDP(m, w.udpSession)
|
||||||
return n, err
|
return n, err
|
||||||
case w.tcp != nil:
|
case w.tcp != nil:
|
||||||
lm := len(m)
|
lm := len(m)
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UDPSession struct {
|
||||||
|
raddr *net.UDPAddr
|
||||||
|
context []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (session *UDPSession) RemoteAddr() net.Addr {
|
||||||
|
return session.raddr
|
||||||
|
}
|
||||||
|
|
||||||
|
type UDPConn struct {
|
||||||
|
*net.UDPConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUDPConn(conn *net.UDPConn) (newconn *UDPConn, err error) {
|
||||||
|
err = udpSocketOobData(conn)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return &UDPConn{conn}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *UDPConn) ReadFromSessionUDP(b []byte) (n int, session *UDPSession, err error) {
|
||||||
|
oob := make([]byte, 1024)
|
||||||
|
|
||||||
|
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
session = &UDPSession{raddr, oob[:oobn]}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *UDPConn) WriteToSessionUDP(b []byte, session *UDPSession) (n int, err error) {
|
||||||
|
n, _, err = conn.WriteMsgUDP(b, session.context, session.raddr)
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func udpSocketOobData(conn *net.UDPConn) (err error) {
|
||||||
|
file, err := conn.File()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
// +build !linux
|
||||||
|
|
||||||
|
package dns
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func udpSocketOobData(conn *net.UDPConn) (err error) {
|
||||||
|
return
|
||||||
|
}
|
Loading…
Reference in New Issue