Compare commits

...

29 Commits

Author SHA1 Message Date
cynic
ebc2393d96 proper support for mocking spongebob dns encoding 2024-08-18 22:09:12 +00:00
cynic
0de7bd35f3 proper support for mocking spongebob dns encoding 2024-08-18 21:45:55 +00:00
cynic
6a10139785 support mocking spongebob dns encoding 2024-08-18 20:57:28 +00:00
cynic
4a163fde36 fix bug caused by Google's attack on DNS infrastructure. 2024-08-18 18:30:59 +00:00
cynic
7e32f63216 better logging 2024-08-08 15:03:35 +00:00
cynic
507b16fbd0 add ip=true optional parameter 2024-08-08 14:54:19 +00:00
cynic
46b3388b83 comments 2024-07-24 06:18:34 +00:00
cynic
d0033bc409 use alternative port for everything on top of port 53 2024-07-24 06:11:54 +00:00
cynic
df90e5947e support ipv4 DNS resolution 2024-07-22 05:55:55 +00:00
cynic
a288e99bda add alternative port for _acme-challenge 2024-07-07 06:53:50 +00:00
cynic
2b23be6f74 add alternative port for _acme-challenge 2024-07-07 06:47:31 +00:00
cynic
d0fc2ff8e6 comment out ipv4 section 2024-07-04 06:47:13 +00:00
cynic
b51cca5347 check for ip in reverse proxy header 2024-06-14 05:25:27 +00:00
cynic
54be47f844 tabs 2024-06-14 04:55:12 +00:00
cynic
32e9a42493 tabs 2024-06-14 04:54:29 +00:00
cynic
fce8a51ed8 add to .PHONY list 2024-06-14 04:25:02 +00:00
cynic
6adda5f544 rename file 2024-06-14 04:12:05 +00:00
cynic
4ad4578103 move whoami to its own directory 2024-06-14 03:59:14 +00:00
cynic
4b0f083f72 add command line flags 2024-06-14 03:49:28 +00:00
cynic
a1d3313299 add port argument 2024-06-13 21:03:17 +00:00
cynic
5bbc9b922c add port argument 2024-06-13 21:02:13 +00:00
cynic
4201a704f8 add whoami 2024-06-13 10:04:38 +00:00
cynic
be529a50d1 set edns 2024-06-10 04:53:42 +00:00
cynic
f7c594af5a generate proper response for missing A record 2024-06-10 04:09:00 +00:00
cynic
17a8ed4414 make validation case-insensitive 2024-06-03 01:07:45 +00:00
cynic
5b4fd41ffa remove comments and debug stuff 2024-05-25 06:12:57 +00:00
cynic
9f31f76d02 make meshname default, delegate to meship function if appropriate 2024-05-25 05:53:22 +00:00
cynic
1919aed4e6 fixed hostname processing 2024-05-21 08:50:54 +00:00
root
73c604e9c4 accept custom meship domains 2024-05-21 03:21:12 +00:00
4 changed files with 164 additions and 39 deletions

View File

@ -2,13 +2,19 @@ GOARCH := $(GOARCH)
GOOS := $(GOOS)
FLAGS := -ldflags "-s -w"
all:
all: meshnamed whoami
meshnamed:
GOARCH=$$GOARCH GOOS=$$GOOS go build $(FLAGS) ./cmd/meshnamed
whoami:
GOARCH=$$GOARCH GOOS=$$GOOS go build $(FLAGS) ./cmd/whoami
clean:
$(RM) meshnamed meshnamed.exe
$(RM) meshnamed meshnamed.exe whoami whoami.exe
test:
go test pkg/meshname/*_test.go
.PHONY: all clean test
.PHONY: all meshnamed whoami clean test

View File

@ -30,16 +30,20 @@ func parseNetworks(networksconf string) (map[string]*net.IPNet, error) {
var (
listenAddr, networksconf string
meshipNetworksconf string
getName, getIP string
acmePort string
debug, noMeshIP bool
)
func init() {
flag.StringVar(&listenAddr, "listenaddr", "[::1]:53535", "address to listen on")
flag.StringVar(&networksconf, "networks", "ygg=200::/7,cjd=fc00::/8,meshname=::/0,popura=::/0", "TLD=subnet list separated by comma")
flag.StringVar(&meshipNetworksconf, "meshipnetworks", "meship=::/0", "TLD=subnet list separated by comma")
flag.BoolVar(&noMeshIP, "nomeship", false, "disable .meship resolver")
flag.StringVar(&getName, "getname", "", "convert IPv6 address to a name")
flag.StringVar(&getIP, "getip", "", "convert a name to IPv6 address")
flag.StringVar(&acmePort, "acmeport", "53536", "try alternative port for acme challenges")
flag.BoolVar(&debug, "debug", false, "enable debug logging")
}
@ -73,11 +77,12 @@ func main() {
}
networks, err := parseNetworks(networksconf)
meshipNetworks, err := parseNetworks(meshipNetworksconf)
if err != nil {
logger.Fatalln(err)
}
s := meshname.New(logger, listenAddr, networks, !noMeshIP)
s := meshname.New(logger, listenAddr, networks, meshipNetworks, !noMeshIP, acmePort)
if err := s.Start(); err != nil {
logger.Fatal(err)

69
cmd/whoami/main.go Normal file
View File

@ -0,0 +1,69 @@
package main
import (
"net/http"
"net"
"encoding/base32"
"strings"
"flag"
"log"
)
// define tld
var tld = flag.String("tld", "mesh.cat", "The top level domain for our network")
// domainFromIP derives a meshname subdomain for the authoritative DNS server address
func domainFromIP(target net.IP) string {
host := strings.ToLower(base32.StdEncoding.EncodeToString(target)[0:26])
domain := host + "." + *tld
return domain
}
// handle HTTP requests
func handler(w http.ResponseWriter, r *http.Request) {
// parse query parameters
params := r.URL.Query()
ipParam := params.Get("ip")
// check if the "ip" query parameter is set to "true"
showIP := ipParam == "true"
// get client's ip address
ip, port, err := net.SplitHostPort(r.RemoteAddr)
_, _ = port, err
// check if we're behind a reverse proxy
xForwardedFor := r.Header.Get("X-Forwarded-For")
if xForwardedFor != "" {
ip = xForwardedFor
}
parsedIP := net.ParseIP(ip)
// return domain for IPv6 only
if parsedIP.To4() == nil {
if (showIP) {
w.Write([]byte(ip + "\n"))
log.Println(ip)
} else {
domain := domainFromIP(parsedIP)
w.Write([]byte(domain + "\n"))
log.Println(domain)
}
} else {
// set the response status code to 422
w.WriteHeader(http.StatusUnprocessableEntity)
w.Write([]byte("ipv4 not supported\n"))
}
}
func main() {
// define path
http.HandleFunc("/", handler)
// define ip address
address := flag.String("address", "[::0]", "The interface address to listen on")
// define port
port := flag.String("port", "8008", "The port to listen on")
// parse the command-line arguments
flag.Parse()
// construct listening address
listenAddr := *address + ":" + *port
print("Listening on address: ", listenAddr, "\n")
// start server
http.ListenAndServe(listenAddr, nil)
}

View File

@ -4,34 +4,39 @@ import (
"errors"
"net"
"sync"
"strings"
"github.com/gologme/log"
"github.com/miekg/dns"
)
type MeshnameServer struct {
log *log.Logger
listenAddr string
dnsClient *dns.Client
dnsServer *dns.Server
networks map[string]*net.IPNet
enableMeshIP bool
log *log.Logger
listenAddr string
dnsClient *dns.Client
dnsServer *dns.Server
networks map[string]*net.IPNet
meshipNetworks map[string]*net.IPNet
enableMeshIP bool
acmePort string
startedLock sync.RWMutex
started bool
startedLock sync.RWMutex
started bool
}
// New is a constructor for MeshnameServer
func New(log *log.Logger, listenAddr string, networks map[string]*net.IPNet, enableMeshIP bool) *MeshnameServer {
func New(log *log.Logger, listenAddr string, networks map[string]*net.IPNet, meshipNetworks map[string]*net.IPNet, enableMeshIP bool, acmePort string) *MeshnameServer {
dnsClient := new(dns.Client)
dnsClient.Timeout = 5000000000 // increased 5 seconds timeout
return &MeshnameServer{
log: log,
listenAddr: listenAddr,
networks: networks,
dnsClient: dnsClient,
enableMeshIP: enableMeshIP,
log: log,
listenAddr: listenAddr,
networks: networks,
meshipNetworks: meshipNetworks,
dnsClient: dnsClient,
enableMeshIP: enableMeshIP,
acmePort: acmePort,
}
}
@ -58,14 +63,16 @@ func (s *MeshnameServer) Start() error {
Net: "udp",
NotifyStartedFunc: func() { close(waitStarted) },
}
if s.enableMeshIP {
for mtld, subnet := range s.meshipNetworks {
dns.HandleFunc(mtld, s.handleMeshIPRequest)
s.log.Debugln("Handling as meship:", mtld, subnet)
}
}
for tld, subnet := range s.networks {
dns.HandleFunc(tld, s.handleMeshnameRequest)
s.log.Debugln("Handling:", tld, subnet)
}
if s.enableMeshIP {
dns.HandleFunc("meship", s.handleMeshIPRequest)
s.log.Debugln("Handling: meship ::/0")
}
go func() {
if err := s.dnsServer.ListenAndServe(); err != nil {
@ -86,7 +93,11 @@ func (s *MeshnameServer) handleMeshnameRequest(w dns.ResponseWriter, r *dns.Msg)
var remoteLookups = make(map[string][]dns.Question)
m := new(dns.Msg)
m.SetReply(r)
s.log.Debugln(r.String())
var tldList []string
for tld := range s.networks {
tldList = append(tldList, tld)
}
for _, q := range r.Question {
labels := dns.SplitDomainName(q.Name)
@ -94,16 +105,35 @@ func (s *MeshnameServer) handleMeshnameRequest(w dns.ResponseWriter, r *dns.Msg)
s.log.Debugln("Error: invalid domain requested")
continue
}
subDomain := labels[len(labels)-2]
// process domain
input := strings.ToLower(strings.TrimSuffix(q.Name, "."))
subDomain := ""
tld := ""
for i := range tldList {
t := strings.ToLower(tldList[i])
if strings.HasSuffix(input, "."+t) {
// define tld
tld = t
domainParts := strings.SplitN(input, "."+t, 2)
firstPart := domainParts[0]
firstPartLabels := dns.SplitDomainName(firstPart)
// define hostname ("subDomain")
subDomain = firstPartLabels[len(firstPartLabels)-1]
if len(firstPartLabels) == 1 && q.Qtype == dns.TypeAAAA {
s.handleMeshIPRequest(w, r)
return
}
}
}
resolvedAddr, err := IPFromDomain(&subDomain)
if err != nil {
s.log.Debugln(err)
continue
}
// check subnet validity
tld := labels[len(labels)-1]
// check subnet validity
if subnet, ok := s.networks[tld]; ok && subnet.Contains(resolvedAddr) {
remoteLookups[resolvedAddr.String()] = append(remoteLookups[resolvedAddr.String()], q)
} else {
@ -115,15 +145,35 @@ func (s *MeshnameServer) handleMeshnameRequest(w dns.ResponseWriter, r *dns.Msg)
rm := new(dns.Msg)
rm.RecursionDesired = true
rm.Question = questions
resp, _, err := s.dnsClient.Exchange(rm, "["+remoteServer+"]:53") // no retries
// always use lowercase internally among meshname instances
originalQuestionName := rm.Question[0].Name
// mocking spongebob dns encoding support
rm.Question[0].Name = strings.ToLower(originalQuestionName)
// add alternative port number
portNumbers := []string{"53"}
portNumbers = append([]string{s.acmePort}, portNumbers...) // TODO: rename acmePort to alternativePort
// make request
err := error(nil)
for _, port := range portNumbers {
s.log.Debugln("trying port:"+port)
resp, _, err := s.dnsClient.Exchange(rm, "["+remoteServer+"]:"+port)
// if we had success we don't keep trying other ports
if err == nil {
if len(resp.Answer) > 0 {
// mocking spongebob dns encoding support
resp.Question[0].Name = originalQuestionName
resp.Answer[0].Header().Name = originalQuestionName
}
s.log.Debugln(resp.String())
m.Answer = append(m.Answer, resp.Answer...)
m.Ns = append(m.Ns, resp.Ns...)
m.Extra = append(m.Extra, resp.Extra...)
break
}
}
if err != nil {
s.log.Debugln(err)
continue
}
s.log.Debugln(resp.String())
m.Answer = append(m.Answer, resp.Answer...)
m.Ns = append(m.Ns, resp.Ns...)
m.Extra = append(m.Extra, resp.Extra...)
}
if err := w.WriteMsg(m); err != nil {
@ -134,21 +184,16 @@ func (s *MeshnameServer) handleMeshnameRequest(w dns.ResponseWriter, r *dns.Msg)
func (s *MeshnameServer) handleMeshIPRequest(w dns.ResponseWriter, r *dns.Msg) {
m := new(dns.Msg)
m.SetReply(r)
m.Authoritative = true
for _, q := range r.Question {
labels := dns.SplitDomainName(q.Name)
// resolve only 2nd level domains and AAAA type
if len(labels) != 2 || q.Qtype != dns.TypeAAAA || q.Qclass != dns.ClassINET {
s.log.Debugln("Error: invalid resource requested")
continue
}
if resolvedAddr, err := IPFromDomain(&labels[0]); err == nil {
answer := new(dns.AAAA)
answer.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 3600}
answer.AAAA = resolvedAddr
m.Answer = append(m.Answer, answer)
s.log.Debugln(m)
} else {
s.log.Debugln(err)
}