2018-01-17 09:44:03 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math/rand"
|
|
|
|
"net"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/jedisct1/dlog"
|
|
|
|
"github.com/miekg/dns"
|
|
|
|
)
|
|
|
|
|
|
|
|
type PluginForwardEntry struct {
|
|
|
|
domain string
|
|
|
|
servers []string
|
|
|
|
}
|
|
|
|
|
|
|
|
type PluginForward struct {
|
|
|
|
forwardMap []PluginForwardEntry
|
|
|
|
}
|
|
|
|
|
|
|
|
func (plugin *PluginForward) Name() string {
|
|
|
|
return "forward"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (plugin *PluginForward) Description() string {
|
|
|
|
return "Route queries matching specific domains to a dedicated set of servers"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (plugin *PluginForward) Init(proxy *Proxy) error {
|
|
|
|
dlog.Noticef("Loading the set of forwarding rules from [%s]", proxy.forwardFile)
|
2023-06-24 22:08:01 +02:00
|
|
|
lines, err := ReadTextFile(proxy.forwardFile)
|
2018-01-17 09:44:03 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-06-24 22:08:01 +02:00
|
|
|
for lineNo, line := range strings.Split(lines, "\n") {
|
2020-01-25 15:45:23 +01:00
|
|
|
line = TrimAndStripInlineComments(line)
|
|
|
|
if len(line) == 0 {
|
2018-01-17 12:27:29 +01:00
|
|
|
continue
|
|
|
|
}
|
2018-01-17 16:06:30 +01:00
|
|
|
domain, serversStr, ok := StringTwoFields(line)
|
|
|
|
if !ok {
|
2020-04-05 20:49:30 +02:00
|
|
|
return fmt.Errorf(
|
2020-04-05 20:50:28 +02:00
|
|
|
"Syntax error for a forwarding rule at line %d. Expected syntax: example.com 9.9.9.9,8.8.8.8",
|
2020-04-05 20:49:30 +02:00
|
|
|
1+lineNo,
|
|
|
|
)
|
2018-01-17 09:44:03 +01:00
|
|
|
}
|
2018-01-17 16:06:30 +01:00
|
|
|
domain = strings.ToLower(domain)
|
2018-01-17 09:44:03 +01:00
|
|
|
var servers []string
|
|
|
|
for _, server := range strings.Split(serversStr, ",") {
|
2021-04-05 11:46:57 +02:00
|
|
|
server = strings.TrimSpace(server)
|
2018-01-17 09:44:03 +01:00
|
|
|
if net.ParseIP(server) != nil {
|
|
|
|
server = fmt.Sprintf("%s:%d", server, 53)
|
|
|
|
}
|
|
|
|
servers = append(servers, server)
|
|
|
|
}
|
|
|
|
if len(servers) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
plugin.forwardMap = append(plugin.forwardMap, PluginForwardEntry{
|
2020-04-05 20:49:30 +02:00
|
|
|
domain: domain,
|
|
|
|
servers: servers,
|
2018-01-17 09:44:03 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (plugin *PluginForward) Drop() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (plugin *PluginForward) Reload() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (plugin *PluginForward) Eval(pluginsState *PluginsState, msg *dns.Msg) error {
|
2019-12-17 09:38:53 +01:00
|
|
|
qName := pluginsState.qName
|
|
|
|
qNameLen := len(qName)
|
2018-01-17 09:44:03 +01:00
|
|
|
var servers []string
|
|
|
|
for _, candidate := range plugin.forwardMap {
|
|
|
|
candidateLen := len(candidate.domain)
|
2019-12-17 09:38:53 +01:00
|
|
|
if candidateLen > qNameLen {
|
2018-01-17 09:44:03 +01:00
|
|
|
continue
|
|
|
|
}
|
2022-03-23 17:48:48 +01:00
|
|
|
if qName[qNameLen-candidateLen:] == candidate.domain &&
|
|
|
|
(candidateLen == qNameLen || (qName[qNameLen-candidateLen-1] == '.')) {
|
2018-01-17 09:44:03 +01:00
|
|
|
servers = candidate.servers
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(servers) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
server := servers[rand.Intn(len(servers))]
|
2019-09-11 14:17:11 +02:00
|
|
|
pluginsState.serverName = server
|
2020-04-17 20:57:23 +02:00
|
|
|
client := dns.Client{Net: pluginsState.serverProto, Timeout: pluginsState.timeout}
|
2020-02-05 02:44:43 +01:00
|
|
|
respMsg, _, err := client.Exchange(msg, server)
|
2018-01-17 09:44:03 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-02-05 02:44:43 +01:00
|
|
|
if respMsg.Truncated {
|
|
|
|
client.Net = "tcp"
|
|
|
|
respMsg, _, err = client.Exchange(msg, server)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2019-12-11 09:41:16 +01:00
|
|
|
if edns0 := respMsg.IsEdns0(); edns0 == nil || !edns0.Do() {
|
|
|
|
respMsg.AuthenticatedData = false
|
|
|
|
}
|
2020-02-05 02:52:54 +01:00
|
|
|
respMsg.Id = msg.Id
|
2018-01-17 09:44:03 +01:00
|
|
|
pluginsState.synthResponse = respMsg
|
|
|
|
pluginsState.action = PluginsActionSynth
|
2019-12-17 19:19:36 +01:00
|
|
|
pluginsState.returnCode = PluginsReturnCodeForward
|
2018-01-17 09:44:03 +01:00
|
|
|
return nil
|
|
|
|
}
|