7 Commits

Author SHA1 Message Date
George 92a819e45a Remove old tests 2021-10-31 18:49:38 +00:00
George 6610db601b Remove the useless remote IP check 2021-10-31 18:46:29 +00:00
George 166705fc60 Remove DNS records storage, use dnsmasq or PopuraDNS instead 2021-10-31 18:37:11 +00:00
George d006a19738 Update README.md 2021-10-26 17:17:18 +00:00
George 117923cdcb Add .vapordns subdomain by default 2021-07-06 19:23:10 +03:00
George aef2ae70d5 Copy all answer sections from the upstream server 2021-06-12 13:19:50 -04:00
George ce2342cb8f add Gentoo ebuild and openrc init file (fix #16) 2021-06-12 12:56:54 -04:00
9 changed files with 178 additions and 261 deletions
+3 -77
View File
@@ -13,85 +13,11 @@ Implements the [Meshname protocol](https://github.com/zhoreeq/meshname/blob/mast
- Q: *Meshname domains are ugly.*
- A: Yes, if you want decentralization, you either have ugly names or a blockchain. Meshname has ugly names, but it works at least!
## How to install and use
## How to use meshname domains?
Minimum go version 1.12 is required.
Use a full-featured DNS server with the meshname protocol support, i.e. [PopuraDNS](https://github.com/popura-network/PopuraDNS).
1) Get the source code and compile
```
git clone https://github.com/zhoreeq/meshname.git
cd meshname
make
```
2) Generate the default config for your host
```
./meshnamed -genconf 200:6fc8:9220:f400:5cc2:305a:4ac6:967e -subdomain meshname | tee /tmp/meshnamed.conf
```
3) Run the daemon
```
./meshnamed -useconffile /tmp/meshnamed.conf
```
4) Optionally, set configuration flags
```
./meshnamed -listenaddr [::1]:53535 -debug -useconffile /tmp/meshnamed.conf
```
5) See the list of all configuration flags
```
./meshnamed -help
```
Add custom DNS records to the configuration file and restart the daemon to apply settings.
A DNS record can be of any valid string form parsed by [miekg/dns#NewRR](https://godoc.org/github.com/miekg/dns#NewRR) function (see example configuration file below).
## systemd unit
Look for `meshnamed.service` in the source directory for a systemd unit file.
## Example configuration file
In this example, meshnamed is configured as authoritative server for two domain zones:
{
"aiag7sesed2aaxgcgbnevruwpy": [
"aiag7sesed2aaxgcgbnevruwpy.meshname. AAAA 200:6fc8:9220:f400:5cc2:305a:4ac6:967e",
"_xmpp-client._tcp.aiag7sesed2aaxgcgbnevruwpy.meshname. SRV 5 0 5222 xmpp.aiag7sesed2aaxgcgbnevruwpy.meshname",
"_xmpp-server._tcp.aiag7sesed2aaxgcgbnevruwpy.meshname. SRV 5 0 5269 xmpp.aiag7sesed2aaxgcgbnevruwpy.meshname",
"xmpp.aiag7sesed2aaxgcgbnevruwpy.meshname. AAAA 300:6fc8:9220:f400::1",
"forum.aiag7sesed2aaxgcgbnevruwpy.meshname. CNAME amag7sesed2aaaaaaaaaaaaaau.meshname."
],
"amag7sesed2aaaaaaaaaaaaaau": [
"amag7sesed2aaaaaaaaaaaaaau.meshname. AAAA 300:6fc8:9220:f400::5"
]
}
## Configure dnsmasq as a primary DNS resolver with "meshname." support
`/etc/dnsmasq.conf`
port=53
domain-needed
bogus-priv
server=/meshname/::1#53535
server=8.8.8.8
## Using meshnamed as a standalone DNS server
Set the flag to listen on all interfaces and a standard DNS server port
./meshnamed -listenaddr [::]:53 -useconffile /tmp/meshnamed.conf
Run as root and allow incoming connections to port 53/UDP in firewall settings.
## Custom top level domains (TLD) and subnet filtering
meshnamed can be configured to resolve custom TLDs.
To run meshnamed for TLD `.newmesh` with addresses in `fd00::/8`
set a flag `-networks newmesh=fd00::/8`.
By default, in addition to `.meshname` it also resolves `.ygg` for IPv6 addresses in
`200::/7` subnet and `.cjd` for `fc00::/8`.
Requests are filtered by subnet validation. Request is ignored if a decoded
IPv6 address doesn't match the specified subnet for a TLD.
For a standalone .meshname stub resolver see `USAGE.md`
## See also
+58
View File
@@ -0,0 +1,58 @@
# How to install and use
Minimum go version 1.12 is required.
1) Get the source code and compile
```
git clone https://github.com/zhoreeq/meshname.git
cd meshname
make
```
2) Run the daemon
```
./meshnamed
```
3) Optionally, set configuration flags
```
./meshnamed -listenaddr [::1]:53535 -debug
```
4) See the list of all available flags
```
./meshnamed -help
```
## Get meshname subdomain from an IPv6 address
```
./meshnamed -getname 200:f8b1:f974:967f:dd32:145d:1cc0:3679
aiaprmpzoslh7xjscrorzqbwpe
```
Use this subdomain with a .meshname TLD to configure DNS records
on your authoritative server, (i.e. dnsmasq, bind or PopuraDNS).
## systemd unit
Look for `meshnamed.service` in the source directory for a systemd unit file.
## Configure dnsmasq as a primary DNS resolver with "meshname." support
`/etc/dnsmasq.conf`
port=53
domain-needed
bogus-priv
server=/meshname/::1#53535
server=8.8.8.8
## Custom top level domains (TLD) and subnet filtering
meshnamed can be configured to resolve custom TLDs.
To run meshnamed for TLD `.newmesh` with addresses in `fd00::/8`
set a flag `-networks newmesh=fd00::/8`.
By default, in addition to `.meshname` it also resolves `.ygg` for IPv6 addresses in
`200::/7` subnet and `.cjd` for `fc00::/8`.
Requests are filtered by subnet validation. Request is ignored if a decoded
IPv6 address doesn't match the specified subnet for a TLD.
+5 -35
View File
@@ -28,30 +28,18 @@ func parseNetworks(networksconf string) (map[string]*net.IPNet, error) {
return networks, nil
}
func loadConfig(s *meshname.MeshnameServer, confPath string) error {
dnsRecords, err := meshname.ParseConfigFile(confPath)
if err == nil {
s.ConfigureDNSRecords(dnsRecords)
}
return err
}
var (
genconf, subdomain, useconffile, listenAddr, networksconf string
getName, getIP string
debug, noMeshIP, allowRemote bool
listenAddr, networksconf string
getName, getIP string
debug, noMeshIP bool
)
func init() {
flag.StringVar(&genconf, "genconf", "", "generate a new config for IP address")
flag.StringVar(&subdomain, "subdomain", "meshname.", "subdomain used to generate config")
flag.StringVar(&useconffile, "useconffile", "", "run daemon with a config file")
flag.StringVar(&listenAddr, "listenaddr", "[::1]:53535", "address to listen on")
flag.StringVar(&networksconf, "networks", "ygg=200::/7,cjd=fc00::/8,meshname=::/0", "TLD=subnet list separated by comma")
flag.StringVar(&networksconf, "networks", "ygg=200::/7,cjd=fc00::/8,meshname=::/0,popura=::/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.BoolVar(&allowRemote, "allowremote", false, "allow remote queries from any IP address")
flag.BoolVar(&debug, "debug", false, "enable debug logging")
}
@@ -82,13 +70,6 @@ func main() {
}
fmt.Println(ip)
return
} else if genconf != "" {
if conf, err := meshname.GenConf(genconf, subdomain); err == nil {
fmt.Println(conf)
} else {
logger.Errorln(err)
}
return
}
networks, err := parseNetworks(networksconf)
@@ -96,12 +77,7 @@ func main() {
logger.Fatalln(err)
}
s := meshname.New(logger, listenAddr, networks, !noMeshIP, allowRemote)
if useconffile != "" {
if err := loadConfig(s, useconffile); err != nil {
logger.Fatalln(err)
}
}
s := meshname.New(logger, listenAddr, networks, !noMeshIP)
if err := s.Start(); err != nil {
logger.Fatal(err)
@@ -117,12 +93,6 @@ func main() {
select {
case <-c:
return
case <-r:
if useconffile != "" {
if err := loadConfig(s, useconffile); err != nil {
logger.Errorln(err)
}
}
}
}
}
+69
View File
@@ -0,0 +1,69 @@
# Distributed under the terms of the GNU General Public License v2
EAPI="7"
inherit go-module
DESCRIPTION="Meshname, a universal naming system for all IPv6-based mesh networks, including CJDNS and Yggdrasil"
HOMEPAGE="https://github.com/zhoreeq/meshname"
EGO_SUM=(
"github.com/gologme/log v1.2.0"
"github.com/gologme/log v1.2.0/go.mod"
"github.com/miekg/dns v1.1.27"
"github.com/miekg/dns v1.1.27/go.mod"
"golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod"
"golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550"
"golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod"
"golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod"
"golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod"
"golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod"
"golang.org/x/net v0.0.0-20190923162816-aa69164e4478"
"golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod"
"golang.org/x/sync v0.0.0-20190423024810-112230192c58"
"golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod"
"golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod"
"golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod"
"golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe"
"golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod"
"golang.org/x/text v0.3.0/go.mod"
"golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod"
"golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod"
)
go-module_set_globals
if [[ ${PV} != *9999* ]]; then
SRC_URI="https://github.com/zhoreeq/${PN}/archive/v${PV}.tar.gz -> ${P}.tar.gz"
KEYWORDS="amd64 ~amd64 x86 ~x86"
else
EGIT_REPO_URI="https://github.com/zhoreeq/${PN}.git"
KEYWORDS="amd64 x86"
fi
SRC_URI+="${EGO_SUM_SRC_URI}"
LICENSE="MIT"
SLOT="0"
IUSE="systemd"
DEPEND=">dev-lang/go-1.12"
src_install() {
echo ""
exeinto /usr/bin
doexe meshnamed
dodoc README.md protocol.md
if use systemd ; then
systemd_newunit "${PN}d.service" ${PN}d.service
else
newinitd "${FILESDIR}/${PN}d.initd" ${PN}d
fi
}
pkg_postinst() {
elog "The meshname daemon will have to be started before use:"
if use systemd ; then
elog " # systemctl start meshnamed"
else
elog " # rc-service meshnamed start"
fi
}
+28
View File
@@ -0,0 +1,28 @@
#!/sbin/openrc-run
# Distributed under the terms of the GNU General Public License v2
extra_started_commands="reload"
command="/usr/bin/meshnamed"
description="Distributed naming system for IPv6 mesh networks"
pidfile="/run/meshnamed.pid"
logfile="/var/run/meshnamed.log"
start_stop_daemon_args="--user nobody --group nobody -listenaddr '[::1]:53535'"
start() {
ebegin "Starting Distributed naming system for IPv6 mesh networks"
start-stop-daemon --start --exec "${command}" --pidfile "${pidfile}" --background \
--stdout "${logfile}" --stderr "${logfile}"
eend $?
}
stop() {
ebegin "Distributed naming system for IPv6 mesh networks"
start-stop-daemon --stop --exec "${command}" --pidfile "${pidfile}"
eend $?
}
reload() {
stop
sleep 5
start
}
+1 -1
View File
@@ -9,7 +9,7 @@ Group=nogroup
ProtectHome=true
ProtectSystem=true
SyslogIdentifier=meshnamed
ExecStart=/usr/local/bin/meshnamed -listenaddr [::1]:53535 -useconffile /etc/meshnamed.conf
ExecStart=/usr/local/bin/meshnamed -listenaddr [::1]:53535
Restart=always
TimeoutStopSec=5
-52
View File
@@ -1,52 +0,0 @@
package meshname
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net"
"github.com/miekg/dns"
)
func GenConf(target, zone string) (string, error) {
ip := net.ParseIP(target)
if ip == nil {
return "", errors.New("Invalid IP address")
}
subDomain := DomainFromIP(&ip)
selfRecord := fmt.Sprintf("\t\t\"%s.%s AAAA %s\"\n", subDomain, zone, target)
confString := fmt.Sprintf("{\n\t\"%s\":[\n%s\t]\n}", subDomain, selfRecord)
return confString, nil
}
// Load dnsRecords from a JSON file
func ParseConfigFile(configPath string) (map[string][]dns.RR, error) {
conf, err := ioutil.ReadFile(configPath)
if err != nil {
return nil, err
}
var dat map[string][]string
if err := json.Unmarshal(conf, &dat); err == nil {
return ParseDNSRecordsMap(dat)
} else {
return nil, err
}
}
// ParseDNSRecordsMap takes a string map and returns a resource record map
func ParseDNSRecordsMap(dnsRecordsMap map[string][]string) (map[string][]dns.RR, error) {
var dnsRecords = make(map[string][]dns.RR)
for subDomain, records := range dnsRecordsMap {
for _, r := range records {
if rr, err := dns.NewRR(r); err == nil {
dnsRecords[subDomain] = append(dnsRecords[subDomain], rr)
} else {
return nil, err
}
}
}
return dnsRecords, nil
}
+14 -45
View File
@@ -3,7 +3,6 @@ package meshname
import (
"errors"
"net"
"strings"
"sync"
"github.com/gologme/log"
@@ -17,28 +16,22 @@ type MeshnameServer struct {
dnsServer *dns.Server
networks map[string]*net.IPNet
enableMeshIP bool
allowRemote bool
dnsRecordsLock sync.RWMutex
dnsRecords map[string][]dns.RR
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, allowRemote bool) *MeshnameServer {
func New(log *log.Logger, listenAddr string, networks map[string]*net.IPNet, enableMeshIP bool) *MeshnameServer {
dnsClient := new(dns.Client)
dnsClient.Timeout = 5000000000 // increased 5 seconds timeout
return &MeshnameServer{
log: log,
listenAddr: listenAddr,
dnsRecords: make(map[string][]dns.RR),
networks: networks,
dnsClient: dnsClient,
enableMeshIP: enableMeshIP,
allowRemote: allowRemote,
}
}
@@ -89,19 +82,12 @@ func (s *MeshnameServer) Start() error {
}
}
func (s *MeshnameServer) ConfigureDNSRecords(dnsRecords map[string][]dns.RR) {
s.dnsRecordsLock.Lock()
s.dnsRecords = dnsRecords
s.dnsRecordsLock.Unlock()
}
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())
s.dnsRecordsLock.RLock()
for _, q := range r.Question {
labels := dns.SplitDomainName(q.Name)
if len(labels) < 2 {
@@ -110,30 +96,20 @@ func (s *MeshnameServer) handleMeshnameRequest(w dns.ResponseWriter, r *dns.Msg)
}
subDomain := labels[len(labels)-2]
if records, ok := s.dnsRecords[subDomain]; ok {
for _, rec := range records {
if h := rec.Header(); h.Name == q.Name && h.Rrtype == q.Qtype && h.Class == q.Qclass {
m.Answer = append(m.Answer, rec)
}
}
} else if s.isRemoteLookupAllowed(w.RemoteAddr()) {
// do remote lookups only for local clients
resolvedAddr, err := IPFromDomain(&subDomain)
if err != nil {
s.log.Debugln(err)
continue
}
// check subnet validity
tld := labels[len(labels)-1]
resolvedAddr, err := IPFromDomain(&subDomain)
if err != nil {
s.log.Debugln(err)
continue
}
// check subnet validity
tld := labels[len(labels)-1]
if subnet, ok := s.networks[tld]; ok && subnet.Contains(resolvedAddr) {
remoteLookups[resolvedAddr.String()] = append(remoteLookups[resolvedAddr.String()], q)
} else {
s.log.Debugln("Error: subnet doesn't match")
}
if subnet, ok := s.networks[tld]; ok && subnet.Contains(resolvedAddr) {
remoteLookups[resolvedAddr.String()] = append(remoteLookups[resolvedAddr.String()], q)
} else {
s.log.Debugln("Error: subnet doesn't match")
}
}
s.dnsRecordsLock.RUnlock()
for remoteServer, questions := range remoteLookups {
rm := new(dns.Msg)
@@ -146,6 +122,8 @@ func (s *MeshnameServer) handleMeshnameRequest(w dns.ResponseWriter, r *dns.Msg)
}
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 {
@@ -181,15 +159,6 @@ func (s *MeshnameServer) handleMeshIPRequest(w dns.ResponseWriter, r *dns.Msg) {
}
}
func (s *MeshnameServer) isRemoteLookupAllowed(addr net.Addr) bool {
// TODO prefix whitelists ?
if s.allowRemote {
return true
}
ra := addr.String()
return strings.HasPrefix(ra, "[::1]:") || strings.HasPrefix(ra, "127.0.0.1:")
}
func (s *MeshnameServer) IsStarted() bool {
s.startedLock.RLock()
started := s.started
-51
View File
@@ -1,51 +0,0 @@
package meshname
import (
"net"
"os"
"strings"
"testing"
"github.com/gologme/log"
"github.com/miekg/dns"
"github.com/zhoreeq/meshname/pkg/meshname"
)
func TestServerLocalDomain(t *testing.T) {
bindAddr := "[::1]:54545"
log := log.New(os.Stdout, "", log.Flags())
yggIPNet := &net.IPNet{IP: net.ParseIP("200::"), Mask: net.CIDRMask(7, 128)}
networks := map[string]*net.IPNet{"meshname": yggIPNet}
allowRemote := false
ts := meshname.New(log, bindAddr, networks, allowRemote)
exampleConfig := make(map[string][]string)
exampleConfig["aiarnf2wpqjxkp6rhivuxbondy"] = append(exampleConfig["aiarnf2wpqjxkp6rhivuxbondy"],
"test.aiarnf2wpqjxkp6rhivuxbondy.meshname. AAAA 201:1697:567c:1375:3fd1:3a2b:4b85:cd1e")
if dnsRecords, err := meshname.ParseDNSRecordsMap(exampleConfig); err == nil {
ts.ConfigureDNSRecords(dnsRecords)
} else {
t.Fatalf("meshname: Failed to parse Meshname config: %s", err)
}
ts.Start()
tc := new(dns.Client)
m := new(dns.Msg)
m.SetQuestion("test.aiarnf2wpqjxkp6rhivuxbondy.meshname.", dns.TypeAAAA)
resp, _, err := tc.Exchange(m, bindAddr)
if err != nil {
t.Fatal(err)
}
if len(resp.Answer) != 1 {
t.Fatalf("Invalid response: %s", resp.String())
}
if !strings.Contains(resp.Answer[0].String(), "201:1697:567c:1375:3fd1:3a2b:4b85:cd1e") {
t.Fatalf("Invalid IP in response: %s", resp.Answer[0].String())
}
ts.Stop()
}