Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ebc2393d96 | ||
|
0de7bd35f3 | ||
|
6a10139785 | ||
|
4a163fde36 | ||
|
7e32f63216 | ||
|
507b16fbd0 | ||
|
46b3388b83 | ||
|
d0033bc409 | ||
|
df90e5947e | ||
|
a288e99bda | ||
|
2b23be6f74 | ||
|
d0fc2ff8e6 | ||
|
b51cca5347 | ||
|
54be47f844 | ||
|
32e9a42493 | ||
|
fce8a51ed8 | ||
|
6adda5f544 | ||
|
4ad4578103 | ||
|
4b0f083f72 | ||
|
a1d3313299 | ||
|
5bbc9b922c | ||
|
4201a704f8 | ||
|
be529a50d1 | ||
|
f7c594af5a | ||
|
17a8ed4414 | ||
|
5b4fd41ffa | ||
|
9f31f76d02 | ||
|
1919aed4e6 | ||
|
73c604e9c4 |
12
Makefile
12
Makefile
@ -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
|
||||
|
||||
|
@ -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
69
cmd/whoami/main.go
Normal 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)
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user