mirror of
https://git.hackfreedom.org/mesh.cat/meshname.git
synced 2026-05-22 06:22:32 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 38781e39fe | |||
| 92a819e45a | |||
| 6610db601b | |||
| 166705fc60 | |||
| d006a19738 |
@@ -13,85 +13,17 @@ 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).
|
||||
For a standalone .meshname stub resolver see `USAGE.md`
|
||||
|
||||
## systemd unit
|
||||
## Alternative implementations
|
||||
|
||||
Look for `meshnamed.service` in the source directory for a systemd unit file.
|
||||
[Mario DNS](https://notabug.org/acetone/mario-dns) by acetone, a C++ implementation with a web interface.
|
||||
|
||||
## 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.
|
||||
[Ruby gem](https://rubygems.org/gems/meshname) by marek22k, [source](https://github.com/marek22k/meshname).
|
||||
|
||||
## See also
|
||||
|
||||
|
||||
@@ -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.
|
||||
+4
-34
@@ -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
|
||||
listenAddr, networksconf string
|
||||
getName, getIP string
|
||||
debug, noMeshIP, allowRemote bool
|
||||
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,vapordns=::/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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,9 +60,6 @@ src_install() {
|
||||
}
|
||||
|
||||
pkg_postinst() {
|
||||
elog "The meshname config file must be generated before use:"
|
||||
elog " # meshnamed -genconf <IPv6> -subdomain meshname | tee /etc/meshnamed.conf"
|
||||
elog
|
||||
elog "The meshname daemon will have to be started before use:"
|
||||
if use systemd ; then
|
||||
elog " # systemctl start meshnamed"
|
||||
|
||||
@@ -6,7 +6,7 @@ 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' -useconffile /etc/meshnamed.conf"
|
||||
start_stop_daemon_args="--user nobody --group nobody -listenaddr '[::1]:53535'"
|
||||
|
||||
start() {
|
||||
ebegin "Starting Distributed naming system for IPv6 mesh networks"
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
+1
-34
@@ -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,14 +96,6 @@ 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)
|
||||
@@ -132,8 +110,6 @@ func (s *MeshnameServer) handleMeshnameRequest(w dns.ResponseWriter, r *dns.Msg)
|
||||
s.log.Debugln("Error: subnet doesn't match")
|
||||
}
|
||||
}
|
||||
}
|
||||
s.dnsRecordsLock.RUnlock()
|
||||
|
||||
for remoteServer, questions := range remoteLookups {
|
||||
rm := new(dns.Msg)
|
||||
@@ -183,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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
Reference in New Issue
Block a user