Implement the IPv6 block plugin

This commit is contained in:
Frank Denis 2018-01-10 17:23:20 +01:00
parent fb16eadb24
commit f283105866
5 changed files with 88 additions and 15 deletions

View File

@ -17,6 +17,7 @@ type Config struct {
ForceTCP bool `toml:"force_tcp"`
Timeout int `toml:"timeout_ms"`
CertRefreshDelay int `toml:"cert_refresh_delay"`
BlockIPv6 bool `toml:"block_ipv6"`
ServersConfig map[string]ServerConfig `toml:"servers"`
}
@ -56,6 +57,7 @@ func ConfigLoad(proxy *Proxy, config_file string) error {
}
proxy.listenAddresses = config.ListenAddresses
proxy.daemonize = config.Daemonize
proxy.pluginBlockIPv6 = config.BlockIPv6
if len(config.ServerNames) == 0 {
for serverName := range config.ServersConfig {
config.ServerNames = append(config.ServerNames, serverName)

View File

@ -40,6 +40,13 @@ timeout = 2500
cert_refresh_delay = 30
############## Filters ##############
## Immediately respond to IPv6-related queries with an empty response
## This makes things faster when there is no IPv6 connectivity
block_ipv6 = false
############## Servers ##############

View File

@ -18,6 +18,15 @@ func TruncatedResponse(packet []byte) ([]byte, error) {
return dstMsg.Pack()
}
func EmptyResponseFromMessage(srcMsg *dns.Msg) (*dns.Msg, error) {
dstMsg := srcMsg
dstMsg.Response = true
dstMsg.Answer = make([]dns.RR, 0)
dstMsg.Ns = make([]dns.RR, 0)
dstMsg.Extra = make([]dns.RR, 0)
return dstMsg, nil
}
func HasTCFlag(packet []byte) bool {
return packet[2]&2 == 2
}

View File

@ -23,6 +23,7 @@ type Proxy struct {
listenAddresses []string
daemonize bool
registeredServers []RegisteredServer
pluginBlockIPv6 bool
}
func main() {
@ -163,22 +164,33 @@ func (proxy *Proxy) processIncomingQuery(serverInfo *ServerInfo, serverProto str
if clientAddr == nil {
clientProto = "tcp"
}
pluginsState := NewPluginsState(clientProto)
pluginsState := NewPluginsState(proxy, clientProto)
query, _ = pluginsState.ApplyQueryPlugins(query)
encryptedQuery, clientNonce, err := proxy.Encrypt(serverInfo, query, serverProto)
if err != nil {
return
}
serverInfo.noticeBegin(proxy)
var response []byte
if serverProto == "udp" {
response, err = proxy.exchangeWithUDPServer(serverInfo, encryptedQuery, clientNonce)
} else {
response, err = proxy.exchangeWithTCPServer(serverInfo, encryptedQuery, clientNonce)
var err error
if pluginsState.action != PluginsActionForward {
if pluginsState.synthResponse != nil {
response, err = pluginsState.synthResponse.PackBuffer(response)
if err != nil {
return
}
}
}
if err != nil {
serverInfo.noticeFailure(proxy)
return
if len(response) == 0 {
encryptedQuery, clientNonce, err := proxy.Encrypt(serverInfo, query, serverProto)
if err != nil {
return
}
serverInfo.noticeBegin(proxy)
if serverProto == "udp" {
response, err = proxy.exchangeWithUDPServer(serverInfo, encryptedQuery, clientNonce)
} else {
response, err = proxy.exchangeWithTCPServer(serverInfo, encryptedQuery, clientNonce)
}
if err != nil {
serverInfo.noticeFailure(proxy)
return
}
}
if clientAddr != nil {
if len(response) > MaxDNSUDPPacketSize {

View File

@ -11,6 +11,7 @@ const (
PluginsActionForward = 1
PluginsActionDrop = 2
PluginsActionReject = 3
PluginsActionSynth = 4
)
type PluginsState struct {
@ -21,6 +22,7 @@ type PluginsState struct {
proto string
queryPlugins *[]Plugin
responsePlugins *[]Plugin
synthResponse *dns.Msg
}
type Plugin interface {
@ -29,9 +31,15 @@ type Plugin interface {
Eval(pluginsState *PluginsState, msg *dns.Msg) error
}
func NewPluginsState(proto string) PluginsState {
queryPlugins := &[]Plugin{Plugin(new(PluginGetSetPayloadSize))}
func NewPluginsState(proxy *Proxy, proto string) PluginsState {
queryPlugins := &[]Plugin{}
if proxy.pluginBlockIPv6 {
*queryPlugins = append(*queryPlugins, Plugin(new(PluginBlockIPv6)))
}
*queryPlugins = append(*queryPlugins, Plugin(new(PluginGetSetPayloadSize)))
responsePlugins := &[]Plugin{}
return PluginsState{action: PluginsActionForward, maxPayloadSize: MaxDNSUDPPacketSize - ResponseOverhead,
queryPlugins: queryPlugins, responsePlugins: responsePlugins, proto: proto}
}
@ -47,6 +55,9 @@ func (pluginsState *PluginsState) ApplyQueryPlugins(packet []byte) ([]byte, erro
pluginsState.action = PluginsActionDrop
return packet, ret
}
if pluginsState.action != PluginsActionForward {
break
}
}
packet2, err := msg.PackBuffer(packet)
if err != nil {
@ -55,6 +66,8 @@ func (pluginsState *PluginsState) ApplyQueryPlugins(packet []byte) ([]byte, erro
return packet2, nil
}
// -------- get_set_payload_size plugin --------
type PluginGetSetPayloadSize struct{}
func (plugin *PluginGetSetPayloadSize) Name() string {
@ -86,3 +99,33 @@ func (plugin *PluginGetSetPayloadSize) Eval(pluginsState *PluginsState, msg *dns
}
return nil
}
// -------- block_ipv6 plugin --------
type PluginBlockIPv6 struct{}
func (plugin *PluginBlockIPv6) Name() string {
return "block_ipv6"
}
func (plugin *PluginBlockIPv6) Description() string {
return "Immediately return a synthetic response to AAAA queries"
}
func (plugin *PluginBlockIPv6) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
questions := msg.Question
if len(questions) != 1 {
return nil
}
question := questions[0]
if question.Qclass != dns.ClassINET || question.Qtype != dns.TypeAAAA {
return nil
}
synth, err := EmptyResponseFromMessage(msg)
if err != nil {
return err
}
pluginsState.synthResponse = synth
pluginsState.action = PluginsActionSynth
return nil
}