Explorar o código

:art: Expose DNS management to API

Ettore Di Giacinto %!s(int64=3) %!d(string=hai) anos
pai
achega
4b9afce66c

+ 37 - 0
api/api.go

@@ -24,11 +24,13 @@ import (
 
 	"github.com/libp2p/go-libp2p-core/network"
 	"github.com/libp2p/go-libp2p-core/peer"
+	"github.com/miekg/dns"
 	apiTypes "github.com/mudler/edgevpn/api/types"
 
 	"github.com/labstack/echo/v4"
 	"github.com/mudler/edgevpn/pkg/node"
 	"github.com/mudler/edgevpn/pkg/protocol"
+	"github.com/mudler/edgevpn/pkg/services"
 	"github.com/mudler/edgevpn/pkg/types"
 )
 
@@ -172,6 +174,41 @@ func API(ctx context.Context, l string, defaultInterval, timeout time.Duration,
 		return c.JSON(http.StatusOK, announcing)
 	})
 
+	ec.GET("/api/dns", func(c echo.Context) error {
+		res := []apiTypes.DNS{}
+		for r, e := range ledger.CurrentData()[protocol.DNSKey] {
+			var t types.DNS
+			e.Unmarshal(&t)
+			d := map[string]string{}
+
+			for k, v := range t {
+				d[dns.TypeToString[uint16(k)]] = v
+			}
+
+			res = append(res,
+				apiTypes.DNS{
+					Regex:   r,
+					Records: d,
+				})
+		}
+		return c.JSON(http.StatusOK, res)
+	})
+
+	// Announce dns
+	ec.POST("/api/dns", func(c echo.Context) error {
+		d := new(apiTypes.DNS)
+		if err := c.Bind(d); err != nil {
+			return echo.NewHTTPError(http.StatusBadRequest, err.Error())
+		}
+
+		entry := make(types.DNS)
+		for r, e := range d.Records {
+			entry[dns.Type(dns.StringToType[r])] = e
+		}
+		services.PersistDNSRecord(context.Background(), ledger, defaultInterval, timeout, d.Regex, entry)
+		return c.JSON(http.StatusOK, announcing)
+	})
+
 	// Delete data from ledger
 	ec.DELETE("/api/ledger/:bucket", func(c echo.Context) error {
 		bucket := c.Param("bucket")

+ 4 - 0
api/public/blockchain.html

@@ -61,6 +61,10 @@
           <i class="fas fa-ethernet"></i>&nbsp;
           Nodes
         </a>
+        <a class="navbar-item" href="/dns.html">
+          <i class="fas fa-globe"></i>&nbsp;
+          DNS
+        </a>
       </div>
       <div class="navbar-end">
         <div class="navbar-item">

+ 163 - 0
api/public/dns.html

@@ -0,0 +1,163 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+  <link href="/css/fonts.css" rel="stylesheet"> 
+  <link rel="stylesheet" href="/css/bulma.min.css" />
+  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css" integrity="sha384-DyZ88mC6Up2uqS4h/KRgHuoeGwBcD4Ng9SiP4dIRy0EXTlnuz47vAwmeGwVChigm" crossorigin="anonymous">
+  <script src="/js/jquery.min.js"></script> 
+  <link rel="stylesheet" type="text/css" href="/css/dt.min.css">
+  <script type="text/javascript" charset="utf8" src="/js/dt.min.js"></script>
+  <script src="/js/dt.js"></script> 
+  <script src="/js/common.js"></script> 
+  <link rel="stylesheet" type="text/css" href="/css/style.css">
+
+<title>EdgeVPN - DNS index</title>
+</head>
+
+<body>
+  <nav class="navbar is-light is-spaced has-shadow" role="navigation" aria-label="main navigation">
+    <div class="navbar-brand">
+      <a class="navbar-item" href="/">
+        <img src="/images/logo.png" > &nbsp;
+        EdgeVPN
+      </a>
+  
+      <a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="menu">
+        <span aria-hidden="true"></span>
+        <span aria-hidden="true"></span>
+        <span aria-hidden="true"></span>
+      </a>
+    </div>
+    <div id="menu" class="navbar-menu">
+      <div class="navbar-start">
+        <a class="navbar-item" href="/machines.html">
+          <i class="fas fa-server"></i>&nbsp;
+          Machines
+        </a>
+        <a class="navbar-item" href="/services.html">
+          <i class="fas fa-project-diagram"></i>&nbsp;
+          Services
+        </a>
+        <a class="navbar-item" href="/files.html">
+          <i class="fas fa-file-upload"></i>&nbsp;
+          Files
+        </a>
+        <a class="navbar-item" href="/users.html">
+          <i class="fas fa-user-clock"></i>&nbsp;
+          Users
+        </a>
+        <a class="navbar-item" href="/blockchain.html">
+          <i class="fas fa-dice-d20"></i>&nbsp;
+          Blockchain
+        </a>
+        <a class="navbar-item" href="/peerstore.html">
+          <i class="fas fa-database"></i>&nbsp;
+          Peerstore
+        </a>
+        <a class="navbar-item" href="/nodes.html">
+          <i class="fas fa-ethernet"></i>&nbsp;
+          Nodes
+        </a>
+        <a class="navbar-item" href="/dns.html">
+          <i class="fas fa-globe"></i>&nbsp;
+          DNS
+        </a>
+      </div>
+      <div class="navbar-end">
+        <div class="navbar-item">
+          <div class="buttons">
+            <a class="button is-link" href="https://github.com/mudler/edgevpn" target=_blank>
+             <strong><i class="fab fa-github-alt"></i> GitHub</strong>
+            </a>
+            <a class="button is-light" href="https://github.com/mudler/edgevpn/issues/new" target=_blank>
+             <i class="fas fa-bug"></i>&nbsp; Report issue
+            </a>
+          </div>
+        </div>
+      </div>
+    </div>
+  </nav>
+
+    <section class="hero">
+      <div class="hero-body">
+        <div class="container">
+          <h1 class="title">
+            <i class="fas fa-globe"></i> DNS registered
+          </h1>
+          <h2 class="subtitle">
+            Accessible via api at <a href="/api/dns" target=_blank><code> /api/dns </code></a><br>
+          </h2>
+          <div class="notification is-info is-light">
+            <h1>Add a DNS record</h1>
+
+          You can add a new record with curl: <br>
+          <code>
+            curl -X POST /api/dns --header "Content-Type: application/json" -d '{ "Regex": "foo.bar", "Records": { "A": "2.2.2.2" } }'
+          </code>
+          </div>
+        </div>
+      </div>
+    </section>
+    <section class="section">
+    <div class="container">
+        <table  data-toggle="table"
+          data-search="true"
+          data-show-columns="true"
+          id="table"  >
+          <thead>
+        
+          <tr>
+              <th ><abbr title="regex">Regex</abbr></th>
+              <th ><abbr title="records">Records</abbr></th>
+            </tr>
+          </thead>
+        </table> 
+
+      </div>
+    </section>
+
+      
+        <script type="text/javascript">
+            $(document).ready(function() {
+                var table = $('#table').DataTable( {
+                    "processing": true,
+                    "ajax": {
+                        "url": "/api/dns",
+                        "type": "GET",
+                        "dataSrc": '',
+                    },
+                    'language':{ 
+                      "loadingRecords": "",
+                      "processing": ""
+                    },
+                    "columns": [
+                        { "data": "Regex" },
+                        { 
+                          "data": "Records", 
+                        "render": function ( data, type, row, meta ) {
+                          return '<code>'+JSON.stringify(data)+'</code>';
+                         },
+                         
+                        },
+                    ],
+                } );
+
+                setInterval( function () {
+                    table.ajax.reload();
+                }, 5000 ); // 5 s
+            } );
+        </script>
+        <footer class="footer">
+          <div class="content has-text-centered">
+            <p>
+              <strong>EdgeVPN</strong> by <a href="https://github.com/mudler/edgevpn">Ettore Di Giacinto</a>. The source code is licensed
+              <a href="https://github.com/mudler/edgevpn/blob/master/LICENSE">GPLv3</a>.
+              Logo originally made by <a href="https://www.flaticon.com/authors/uniconlabs" title="Uniconlabs">Uniconlabs</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
+            </p>
+          </div>
+        </footer>  
+    </body>
+</html>

+ 4 - 0
api/public/files.html

@@ -62,6 +62,10 @@
           <i class="fas fa-ethernet"></i>&nbsp;
           Nodes
         </a>
+        <a class="navbar-item" href="/dns.html">
+          <i class="fas fa-globe"></i>&nbsp;
+          DNS
+        </a>
       </div>
       <div class="navbar-end">
         <div class="navbar-item">

+ 4 - 0
api/public/index.html

@@ -62,6 +62,10 @@
           <i class="fas fa-ethernet"></i>&nbsp;
           Nodes
         </a>
+        <a class="navbar-item" href="/dns.html">
+          <i class="fas fa-globe"></i>&nbsp;
+          DNS
+        </a>
       </div>
       <div class="navbar-end">
         <div class="navbar-item">

+ 4 - 0
api/public/machines.html

@@ -61,6 +61,10 @@
           <i class="fas fa-ethernet"></i>&nbsp;
           Nodes
         </a>
+        <a class="navbar-item" href="/dns.html">
+          <i class="fas fa-globe"></i>&nbsp;
+          DNS
+        </a>
       </div>
       <div class="navbar-end">
         <div class="navbar-item">

+ 4 - 0
api/public/nodes.html

@@ -61,6 +61,10 @@
           <i class="fas fa-ethernet"></i>&nbsp;
           Nodes
         </a>
+        <a class="navbar-item" href="/dns.html">
+          <i class="fas fa-globe"></i>&nbsp;
+          DNS
+        </a>
       </div>
       <div class="navbar-end">
         <div class="navbar-item">

+ 4 - 0
api/public/peerstore.html

@@ -61,6 +61,10 @@
           <i class="fas fa-ethernet"></i>&nbsp;
           Nodes
         </a>
+        <a class="navbar-item" href="/dns.html">
+          <i class="fas fa-globe"></i>&nbsp;
+          DNS
+        </a>
       </div>
       <div class="navbar-end">
         <div class="navbar-item">

+ 4 - 0
api/public/services.html

@@ -62,6 +62,10 @@
           <i class="fas fa-ethernet"></i>&nbsp;
           Nodes
         </a>
+        <a class="navbar-item" href="/dns.html">
+          <i class="fas fa-globe"></i>&nbsp;
+          DNS
+        </a>
       </div>
       <div class="navbar-end">
         <div class="navbar-item">

+ 4 - 0
api/public/users.html

@@ -61,6 +61,10 @@
           <i class="fas fa-ethernet"></i>&nbsp;
           Nodes
         </a>
+        <a class="navbar-item" href="/dns.html">
+          <i class="fas fa-globe"></i>&nbsp;
+          DNS
+        </a>
       </div>
       <div class="navbar-end">
         <div class="navbar-item">

+ 21 - 0
api/types/dns.go

@@ -0,0 +1,21 @@
+// Copyright © 2022 Ettore Di Giacinto <[email protected]>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, see <http://www.gnu.org/licenses/>.
+
+package types
+
+type DNS struct {
+	Regex   string
+	Records map[string]string
+}

+ 1 - 0
cmd/file.go

@@ -88,6 +88,7 @@ This is also the ID used to refer when receiving it.`,
 			}
 
 			for {
+				time.Sleep(2 * time.Second)
 			}
 		},
 	}

+ 35 - 0
cmd/main.go

@@ -79,6 +79,29 @@ func MainFlags() []cli.Flag {
 			EnvVar: "ADDRESS",
 			Value:  "10.1.0.1/24",
 		},
+		&cli.StringFlag{
+			Name:   "dns",
+			Usage:  "DNS listening address. Empty to disable dns server",
+			EnvVar: "DNSADDRESS",
+			Value:  "",
+		},
+		&cli.BoolTFlag{
+			Name:   "dns-forwarder",
+			Usage:  "Enables dns forwarding",
+			EnvVar: "DNSFORWARD",
+		},
+		&cli.IntFlag{
+			Name:   "dns-cache-size",
+			Usage:  "DNS LRU cache size",
+			EnvVar: "DNSCACHESIZE",
+			Value:  200,
+		},
+		&cli.StringSliceFlag{
+			Name:   "dns-forward-server",
+			Usage:  "List of DNS forward server, e.g. 8.8.8.8:53, 192.168.1.1:53 ...",
+			EnvVar: "DNSFORWARDSERVER",
+			Value:  &cli.StringSlice{"8.8.8.8:53", "1.1.1.1:53"},
+		},
 		&cli.StringFlag{
 			Name:   "router",
 			Usage:  "Sends all packets to this node",
@@ -109,6 +132,7 @@ func Main() func(c *cli.Context) error {
 
 		o = append(o, services.Alive(30*time.Second, 10*time.Minute)...)
 		if c.Bool("dhcp") {
+			// Adds DHCP server
 			address, _, err := net.ParseCIDR(c.String("address"))
 			if err != nil {
 				return err
@@ -118,6 +142,17 @@ func Main() func(c *cli.Context) error {
 			vpnOpts = append(vpnOpts, vO...)
 		}
 
+		dns := c.String("dns")
+		if dns != "" {
+			// Adds DNS Server
+			o = append(o,
+				services.DNS(dns,
+					c.Bool("dns-forwarder"),
+					c.StringSlice("dns-forward-server"),
+					c.Int("dns-cache-size"),
+				)...)
+		}
+
 		opts, err := vpn.Register(vpnOpts...)
 		if err != nil {
 			return err

+ 1 - 0
cmd/service.go

@@ -83,6 +83,7 @@ For example, '192.168.1.1:80', or '127.0.0.1:22'.`,
 			}
 
 			for {
+				time.Sleep(2 * time.Second)
 			}
 		},
 	}