Skip to content

Instantly share code, notes, and snippets.

@nirui
Last active February 25, 2021 15:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nirui/d71791822c11b49191ab21afc49171d2 to your computer and use it in GitHub Desktop.
Save nirui/d71791822c11b49191ab21afc49171d2 to your computer and use it in GitHub Desktop.
// This program and script allows you to map the dns request to [domain].<lan-hostname>.svc.lan to <lan-hostname>.
//
// 1. Setup the OpenWrt. File /etc/config/dhcp
//
// config dnsmasq
// ....
// list server '/svc.lan/127.0.0.1#5333'
// list rebind_domain 'svc.lan'
//
// 2. Init.d Script: /etc/init.d/dnsf.sh
//
// #!/bin/sh /etc/rc.common
// USE_PROCD=1
// START=95
// STOP=01
// start_service() {
// procd_open_instance
// procd_set_param user nobody
// procd_set_param command /etc/dnsf
// procd_close_instance
// }
//
// 3. Compile:
//
// $ GOOS=linux GOARCH=mipsle GOMIPS=softfloat go build -ldflags="-s -w"
// $ upx dnsf
package main
import (
"log"
"strings"
"sync"
"time"
"github.com/miekg/dns"
)
const listen = "127.0.0.1:5333"
const queryTimeout = 5 * time.Second
const upstream = "localhost:53"
const localDomain = ".svc.lan."
const localDomainSuffixLen = len(localDomain) - 1
func handler(cli *dns.Client, w dns.ResponseWriter, m *dns.Msg) {
defer w.Close()
resultMap := make(map[string]string, len(m.Question))
newm := m.Copy()
for i := range newm.Question {
newQName := newm.Question[i].Name
if !strings.HasSuffix(newQName, localDomain) {
continue
}
newQName = newQName[:len(newQName)-localDomainSuffixLen]
if len(newQName) <= 0 {
continue
}
lastDim := strings.LastIndex(newQName[:len(newQName)-1], ".")
if lastDim >= 0 {
newQName = newQName[lastDim+1:]
}
log.Printf(
"Transform domain %s to %s",
newm.Question[i].Name,
newQName,
)
resultMap[newQName] = newm.Question[i].Name
newm.Question[i].Name = newQName
}
respond, _, err := cli.Exchange(newm, upstream)
if err != nil {
log.Printf("Unable to query: %s", err)
return
}
for i := range respond.Question {
mapped, has := resultMap[respond.Question[i].Name]
if !has {
continue
}
respond.Question[i].Name = mapped
}
for i := range respond.Answer {
answer := respond.Answer[i]
answerHeader := answer.Header()
mapped, has := resultMap[answerHeader.Name]
if !has {
continue
}
answerHeader.Name = mapped
respond.Answer[i] = answer
}
err = w.WriteMsg(respond)
if err != nil {
log.Printf("Unable to reply: %s", err)
return
}
}
func main() {
cli := &dns.Client{
Net: "udp",
Timeout: queryTimeout,
}
wg := sync.WaitGroup{}
wg.Add(2)
defer wg.Wait()
go func() {
defer wg.Done()
log.Print((&dns.Server{
Addr: listen,
Net: "udp",
Handler: dns.HandlerFunc(func(rw dns.ResponseWriter, m *dns.Msg) {
handler(cli, rw, m)
}),
}).ListenAndServe())
}()
go func() {
defer wg.Done()
log.Print((&dns.Server{
Addr: listen,
Net: "tcp",
Handler: dns.HandlerFunc(func(rw dns.ResponseWriter, m *dns.Msg) {
handler(cli, rw, m)
}),
}).ListenAndServe())
}()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment