From 815ce3cf24a77f60b5ee66139f03fe928d4e1211 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Sat, 1 Jan 2022 15:30:39 +0000 Subject: [PATCH 01/18] update compose file and scripts to use mosquitto broker. Includes insecure config file for mosquitto --- compose/docker-compose.contained.yml | 11 +++++++++++ docker/mosquitto.conf | 10 ++++++++++ scripts/install-netmaker.sh | 3 +++ scripts/nm-quick.sh | 4 ++++ 4 files changed, 28 insertions(+) create mode 100644 docker/mosquitto.conf diff --git a/compose/docker-compose.contained.yml b/compose/docker-compose.contained.yml index aa3ea175..2d2ef308 100644 --- a/compose/docker-compose.contained.yml +++ b/compose/docker-compose.contained.yml @@ -68,9 +68,20 @@ services: # - $PWD/site:/srv # you could also serve a static site in site folder - caddy_data:/data - caddy_conf:/config + mosquitto: + image: eclipse-mosquitto:2.0.14 + container_name: broker + restart: unless-stopped + network_mode: host + volumes: + - /root/mosquitto.conf:/mosquitto/config/mosquitto.conf + - mosquitto_data:/var/lib/mosquitto + - mosquitto_logs:/var/log/mosquitto/mosquitto.log volumes: caddy_data: {} caddy_conf: {} sqldata: {} dnsconfig: {} + mosquitto_data: {} + mosquitto_logs: {} diff --git a/docker/mosquitto.conf b/docker/mosquitto.conf new file mode 100644 index 00000000..20ab6597 --- /dev/null +++ b/docker/mosquitto.conf @@ -0,0 +1,10 @@ +persitance true +persistance_location /var/lib/mosquitto/ + +log_dest_file /var/log/mosquitto/mosquitto.log + +per_listener_settings true +listener 1883 +allow_anonymous true +bind_interface SERVER_PUBLIC_IP + diff --git a/scripts/install-netmaker.sh b/scripts/install-netmaker.sh index 52232d9a..547dca88 100644 --- a/scripts/install-netmaker.sh +++ b/scripts/install-netmaker.sh @@ -136,6 +136,9 @@ echo "Setting Caddyfile..." sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/Caddyfile sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/Caddyfile +echo "Setting Broker..." +sed -i "s/SERVER_PBLIC_IP/$SERVER_PUBLIC_IP/g" /root/mosquitto.conf + echo "Setting docker-compose..." sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/docker-compose.yml diff --git a/scripts/nm-quick.sh b/scripts/nm-quick.sh index 507e6258..8a9bead4 100755 --- a/scripts/nm-quick.sh +++ b/scripts/nm-quick.sh @@ -135,6 +135,10 @@ wget -q -O /root/Caddyfile https://raw.githubusercontent.com/gravitl/netmaker/ma sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/Caddyfile sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/Caddyfile +echo "setting mosquitto.conf..." + +wget -q -O /root/mosquitto.conf https://raw.githubusercontent.com/gravil/netmaker/master/docker/mosquitto.conf +sed -i "s/SERVER_PUBLIC_IP/$SERVER_PUBLIC_IP/g" /root/mosquitto.conf echo "setting docker-compose..." From 533965b77b79851e637c8754741dc88e8c9c6145 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Sat, 1 Jan 2022 15:43:55 +0000 Subject: [PATCH 02/18] fix typo --- docker/mosquitto.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/mosquitto.conf b/docker/mosquitto.conf index 20ab6597..3594af29 100644 --- a/docker/mosquitto.conf +++ b/docker/mosquitto.conf @@ -1,4 +1,4 @@ -persitance true +persistance true persistance_location /var/lib/mosquitto/ log_dest_file /var/log/mosquitto/mosquitto.log From 07bf9252827220eb3c568b8e002f5979b6bcd073 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Sat, 1 Jan 2022 18:22:06 +0000 Subject: [PATCH 03/18] update mosquitto broker conf and volume info --- compose/docker-compose.contained.yml | 4 ++-- docker/mosquitto.conf | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compose/docker-compose.contained.yml b/compose/docker-compose.contained.yml index 2d2ef308..61512717 100644 --- a/compose/docker-compose.contained.yml +++ b/compose/docker-compose.contained.yml @@ -75,8 +75,8 @@ services: network_mode: host volumes: - /root/mosquitto.conf:/mosquitto/config/mosquitto.conf - - mosquitto_data:/var/lib/mosquitto - - mosquitto_logs:/var/log/mosquitto/mosquitto.log + - mosquitto_data:/mosquitto/data + - mosquitto_logs:/mosquitto/log volumes: caddy_data: {} caddy_conf: {} diff --git a/docker/mosquitto.conf b/docker/mosquitto.conf index 3594af29..85914bad 100644 --- a/docker/mosquitto.conf +++ b/docker/mosquitto.conf @@ -1,10 +1,11 @@ -persistance true -persistance_location /var/lib/mosquitto/ +persistence true +persistence file mosquitto.db +persistance_location mosquitto/data -log_dest_file /var/log/mosquitto/mosquitto.log +log_dest_file mosquitto/log/mosquitto.log per_listener_settings true listener 1883 allow_anonymous true -bind_interface SERVER_PUBLIC_IP +#bind_interface SERVER_PUBLIC_IP From 3e1a85b4b9edbef17f2230b620ee3343b2356c5b Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Sat, 1 Jan 2022 15:30:39 +0000 Subject: [PATCH 04/18] update compose file and scripts to use mosquitto broker. Includes insecure config file for mosquitto --- compose/docker-compose.contained.yml | 11 +++++++++++ docker/mosquitto.conf | 10 ++++++++++ scripts/install-netmaker.sh | 3 +++ scripts/nm-quick.sh | 4 ++++ 4 files changed, 28 insertions(+) create mode 100644 docker/mosquitto.conf diff --git a/compose/docker-compose.contained.yml b/compose/docker-compose.contained.yml index aa3ea175..2d2ef308 100644 --- a/compose/docker-compose.contained.yml +++ b/compose/docker-compose.contained.yml @@ -68,9 +68,20 @@ services: # - $PWD/site:/srv # you could also serve a static site in site folder - caddy_data:/data - caddy_conf:/config + mosquitto: + image: eclipse-mosquitto:2.0.14 + container_name: broker + restart: unless-stopped + network_mode: host + volumes: + - /root/mosquitto.conf:/mosquitto/config/mosquitto.conf + - mosquitto_data:/var/lib/mosquitto + - mosquitto_logs:/var/log/mosquitto/mosquitto.log volumes: caddy_data: {} caddy_conf: {} sqldata: {} dnsconfig: {} + mosquitto_data: {} + mosquitto_logs: {} diff --git a/docker/mosquitto.conf b/docker/mosquitto.conf new file mode 100644 index 00000000..20ab6597 --- /dev/null +++ b/docker/mosquitto.conf @@ -0,0 +1,10 @@ +persitance true +persistance_location /var/lib/mosquitto/ + +log_dest_file /var/log/mosquitto/mosquitto.log + +per_listener_settings true +listener 1883 +allow_anonymous true +bind_interface SERVER_PUBLIC_IP + diff --git a/scripts/install-netmaker.sh b/scripts/install-netmaker.sh index 52232d9a..547dca88 100644 --- a/scripts/install-netmaker.sh +++ b/scripts/install-netmaker.sh @@ -136,6 +136,9 @@ echo "Setting Caddyfile..." sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/Caddyfile sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/Caddyfile +echo "Setting Broker..." +sed -i "s/SERVER_PBLIC_IP/$SERVER_PUBLIC_IP/g" /root/mosquitto.conf + echo "Setting docker-compose..." sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/docker-compose.yml diff --git a/scripts/nm-quick.sh b/scripts/nm-quick.sh index 6e253a09..ebe78b65 100755 --- a/scripts/nm-quick.sh +++ b/scripts/nm-quick.sh @@ -135,6 +135,10 @@ wget -q -O /root/Caddyfile https://raw.githubusercontent.com/gravitl/netmaker/ma sed -i "s/NETMAKER_BASE_DOMAIN/$NETMAKER_BASE_DOMAIN/g" /root/Caddyfile sed -i "s/YOUR_EMAIL/$EMAIL/g" /root/Caddyfile +echo "setting mosquitto.conf..." + +wget -q -O /root/mosquitto.conf https://raw.githubusercontent.com/gravil/netmaker/master/docker/mosquitto.conf +sed -i "s/SERVER_PUBLIC_IP/$SERVER_PUBLIC_IP/g" /root/mosquitto.conf echo "setting docker-compose..." From e337d877281d46095320995dc1dce3ea135aa70f Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Sat, 1 Jan 2022 15:43:55 +0000 Subject: [PATCH 05/18] fix typo --- docker/mosquitto.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/mosquitto.conf b/docker/mosquitto.conf index 20ab6597..3594af29 100644 --- a/docker/mosquitto.conf +++ b/docker/mosquitto.conf @@ -1,4 +1,4 @@ -persitance true +persistance true persistance_location /var/lib/mosquitto/ log_dest_file /var/log/mosquitto/mosquitto.log From bc974859ad611a284270900df5f4fe0c47ba2eaf Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Sat, 1 Jan 2022 18:22:06 +0000 Subject: [PATCH 06/18] update mosquitto broker conf and volume info --- compose/docker-compose.contained.yml | 4 ++-- docker/mosquitto.conf | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compose/docker-compose.contained.yml b/compose/docker-compose.contained.yml index 2d2ef308..61512717 100644 --- a/compose/docker-compose.contained.yml +++ b/compose/docker-compose.contained.yml @@ -75,8 +75,8 @@ services: network_mode: host volumes: - /root/mosquitto.conf:/mosquitto/config/mosquitto.conf - - mosquitto_data:/var/lib/mosquitto - - mosquitto_logs:/var/log/mosquitto/mosquitto.log + - mosquitto_data:/mosquitto/data + - mosquitto_logs:/mosquitto/log volumes: caddy_data: {} caddy_conf: {} diff --git a/docker/mosquitto.conf b/docker/mosquitto.conf index 3594af29..85914bad 100644 --- a/docker/mosquitto.conf +++ b/docker/mosquitto.conf @@ -1,10 +1,11 @@ -persistance true -persistance_location /var/lib/mosquitto/ +persistence true +persistence file mosquitto.db +persistance_location mosquitto/data -log_dest_file /var/log/mosquitto/mosquitto.log +log_dest_file mosquitto/log/mosquitto.log per_listener_settings true listener 1883 allow_anonymous true -bind_interface SERVER_PUBLIC_IP +#bind_interface SERVER_PUBLIC_IP From d11bb575be85f55074b71ca4ab3a34b143188c9c Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Sun, 2 Jan 2022 16:02:59 +0000 Subject: [PATCH 07/18] work in progress for message queue --- go.mod | 6 + go.sum | 13 +++ netclient/cli_options/cmds.go | 9 ++ netclient/command/commands.go | 5 + netclient/functions/daemon.go | 214 ++++++++++++++++++++++++++++++++++ 5 files changed, 247 insertions(+) create mode 100644 netclient/functions/daemon.go diff --git a/go.mod b/go.mod index 4c86fb3f..8c49b6bb 100644 --- a/go.mod +++ b/go.mod @@ -31,10 +31,15 @@ require ( require ( cloud.google.com/go v0.34.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/eclipse/paho.mqtt.golang v1.3.5 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect + github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect github.com/google/go-cmp v0.5.5 // indirect + github.com/google/uuid v1.2.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/mdlayher/genetlink v1.0.0 // indirect @@ -42,5 +47,6 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.0.1 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect google.golang.org/appengine v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 867461fc..5b8fecb5 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/eclipse/paho.mqtt.golang v1.3.5 h1:sWtmgNxYM9P2sP+xEItMozsR3w0cqZFlqnNN1bdl41Y= +github.com/eclipse/paho.mqtt.golang v1.3.5/go.mod h1:eTzb4gxwwyWpqBUHGQZ4ABAV7+Jgm1PklsYT/eo8Hcc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -34,6 +36,8 @@ github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8S github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 h1:dhy9OQKGBh4zVXbjwbxxHjRxMJtLXj3zfgpBYQaR4Q4= +github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= @@ -70,10 +74,14 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -178,6 +186,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -185,6 +194,7 @@ golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -195,6 +205,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -216,6 +228,7 @@ golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/netclient/cli_options/cmds.go b/netclient/cli_options/cmds.go index a43a88c3..5f90c1a8 100644 --- a/netclient/cli_options/cmds.go +++ b/netclient/cli_options/cmds.go @@ -118,5 +118,14 @@ func GetCommands(cliFlags []cli.Flag) []*cli.Command { return err }, }, + { + Name: "daemon", + Usage: "run netclient as daemon", + Flags: cliFlags, + Action: func(c *cli.Context) error { + err := command.Daemon() + return err + }, + }, } } diff --git a/netclient/command/commands.go b/netclient/command/commands.go index 940eb67b..fa8013df 100644 --- a/netclient/command/commands.go +++ b/netclient/command/commands.go @@ -209,3 +209,8 @@ func Uninstall() error { err := functions.Uninstall() return err } + +func Daemon() error { + err := functions.Daemon() + return err +} diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go new file mode 100644 index 00000000..72c7998c --- /dev/null +++ b/netclient/functions/daemon.go @@ -0,0 +1,214 @@ +package functions + +import ( + "encoding/json" + "fmt" + "log" + "time" + + mqtt "github.com/eclipse/paho.mqtt.golang" + "github.com/go-ping/ping" + "github.com/gravitl/netmaker/netclient/config" + "github.com/gravitl/netmaker/netclient/ncutils" + "golang.zx2c4.com/wireguard/wgctrl" +) + +func Daemon() error { + networks, err := ncutils.GetSystemNetworks() + if err != nil { + return err + } + for _, network := range networks { + go Netclient(network) + } + for { + } + return nil +} + +func Netclient(network string) { + var cfg config.ClientConfig + cfg.Network = network + cfg.ReadConfig() + ncutils.Log("daemon started for network:" + network) + //setup MQTT + opts := mqtt.NewClientOptions() + ncutils.Log("setting broker to " + cfg.Server.CoreDNSAddr + ":1883") + opts.AddBroker(cfg.Server.CoreDNSAddr + ":1883") + opts.SetDefaultPublishHandler(All) + opts.SetClientID("netclient-mqttt") + client := mqtt.NewClient(opts) + if token := client.Connect(); token.Wait() && token.Error() != nil { + log.Fatal(token.Error()) + } + if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil { + log.Fatal(token.Error()) + } + client.AddRoute("update/"+network+"/"+cfg.Node.MacAddress, NodeUpdate) + client.AddRoute("update/"+network+"/peers", UpdatePeers) + client.AddRoute("update/"+network+"/keys", UpdateKeys) + client.AddRoute("update/"+network+"/keys/"+cfg.Node.MacAddress, UpdateKeys) + defer client.Disconnect(250) + go Checkin(client, network) + //go Metrics(client, network) + //go Connectivity(client, network) + for { + } +} + +var All mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { + ncutils.Log("Topic: " + string(msg.Topic())) + ncutils.Log("Message: " + string(msg.Payload())) +} + +var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { + ncutils.Log("received message to update node " + string(msg.Payload())) +} + +var UpdatePeers mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { + ncutils.Log("received message to update peers " + string(msg.Payload())) +} + +var UpdateKeys mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { + ncutils.Log("received message to update keys " + string(msg.Payload())) +} + +func Checkin(client mqtt.Client, network string) { + var cfg config.ClientConfig + cfg.Network = network + cfg.ReadConfig() + for { + time.Sleep(time.Duration(cfg.Node.NetworkSettings.DefaultCheckInInterval) * time.Second) + ncutils.Log("Checkin running") + if cfg.Node.Roaming == "yes" && cfg.Node.IsStatic != "yes" { + extIP, err := ncutils.GetPublicIP() + if err != nil { + ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1) + } + if cfg.Node.Endpoint != extIP && extIP != "" { + ncutils.PrintLog("endpoint has changed from "+cfg.Node.Endpoint+" to "+extIP, 1) + UpdateEndpoint(client, network, extIP) + } + intIP, err := getPrivateAddr() + if err != nil { + ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1) + } + if cfg.Node.LocalAddress != intIP && intIP != "" { + ncutils.PrintLog("local Address has changed from "+cfg.Node.LocalAddress+" to "+intIP, 1) + UpdateLocalAddress(client, network, intIP) + } + } else { + localIP, err := ncutils.GetLocalIP(cfg.Node.LocalRange) + if err != nil { + ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1) + } + if cfg.Node.Endpoint != localIP && localIP != "" { + ncutils.PrintLog("endpoint has changed from "+cfg.Node.Endpoint+" to "+localIP, 1) + UpdateEndpoint(client, network, localIP) + } + } + Ping(client, network) + } +} + +func Ping(client mqtt.Client, network string) { + var cfg config.ClientConfig + cfg.Network = network + cfg.ReadConfig() + if token := client.Publish("ping/"+network+"/"+cfg.Node.ID, 0, false, []byte("ping")); token.Wait() && token.Error() != nil { + ncutils.Log("error publishing ping " + token.Error().Error()) + } +} + +func Metrics(client mqtt.Client, network string) { + if token := client.Connect(); token.Wait() && token.Error() != nil { + log.Fatal(token.Error()) + } + var cfg config.ClientConfig + cfg.Network = network + cfg.ReadConfig() + for { + time.Sleep(time.Second * 60) + ncutils.Log("Metrics running") + wg, err := wgctrl.New() + if err != nil { + ncutils.Log("error getting devices " + err.Error()) + break + } + device, err := wg.Device(cfg.Node.Interface) + if err != nil { + ncutils.Log("error readind wg device " + err.Error()) + break + } + bytes, err := json.Marshal(device.Peers) + if err != nil { + ncutils.Log("error marshaling peers " + err.Error()) + break + } + if token := client.Publish("metrics/"+network+"/"+cfg.Node.ID, 1, false, bytes); token.Wait() && token.Error() != nil { + ncutils.Log("error publishing metrics " + token.Error().Error()) + break + } + wg.Close() + } +} + +type PingStat struct { + Name string + Reachable bool +} + +func Connectivity(client mqtt.Client, network string) { + if token := client.Connect(); token.Wait() && token.Error() != nil { + log.Fatal(token.Error()) + } + var cfg config.ClientConfig + cfg.Network = network + cfg.ReadConfig() + for { + time.Sleep(time.Duration(cfg.NetworkSettings.DefaultCheckInInterval) * time.Second) + ncutils.Log("Connectivity running") + var pingStats []PingStat + peers, err := ncutils.GetPeers(cfg.Node.Interface) + if err != nil { + ncutils.Log("error retriving peers " + err.Error()) + break + } + for _, peer := range peers { + var pingStat PingStat + pingStat.Name = peer.PublicKey.String() + pingStat.Reachable = true + ip := peer.Endpoint.IP.String() + fmt.Println("----------", peer.Endpoint.IP, ip) + pinger, err := ping.NewPinger(ip) + if err != nil { + ncutils.Log("error creating pinger " + err.Error()) + break + } + pinger.Timeout = 2 * time.Second + pinger.Run() + stats := pinger.Statistics() + if stats.PacketLoss == 100 { + pingStat.Reachable = false + } + pingStats = append(pingStats, pingStat) + } + bytes, err := json.Marshal(pingStats) + if err != nil { + ncutils.Log("error marshaling stats" + err.Error()) + break + } + if token := client.Publish("connectivity/"+network+"/"+cfg.Node.ID, 1, false, bytes); token.Wait() && token.Error() != nil { + ncutils.Log("error publishing ping stats " + token.Error().Error()) + break + } + } +} + +func UpdateEndpoint(client mqtt.Client, network, ip string) { + ncutils.Log("Updating endpoint") +} + +func UpdateLocalAddress(client mqtt.Client, network, ip string) { + ncutils.Log("Updating local address") +} From 5cd57400ce87a8b84ae42ac50d9c11c7f6f1949a Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Mon, 3 Jan 2022 15:22:26 -0500 Subject: [PATCH 08/18] Replaced ### with - in Node.ID (local copy) to fix mqtt publishing errors added context to all go routines removed connectivity function --- netclient/functions/daemon.go | 191 ++++++++++++++++------------------ 1 file changed, 87 insertions(+), 104 deletions(-) diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go index 72c7998c..2e31d37a 100644 --- a/netclient/functions/daemon.go +++ b/netclient/functions/daemon.go @@ -1,18 +1,22 @@ package functions import ( + "context" "encoding/json" - "fmt" "log" + "os" + "os/signal" + "strings" + "syscall" "time" mqtt "github.com/eclipse/paho.mqtt.golang" - "github.com/go-ping/ping" "github.com/gravitl/netmaker/netclient/config" "github.com/gravitl/netmaker/netclient/ncutils" "golang.zx2c4.com/wireguard/wgctrl" ) +//Daemon runs netclient daemon from command line func Daemon() error { networks, err := ncutils.GetSystemNetworks() if err != nil { @@ -26,59 +30,75 @@ func Daemon() error { return nil } -func Netclient(network string) { - var cfg config.ClientConfig - cfg.Network = network - cfg.ReadConfig() - ncutils.Log("daemon started for network:" + network) - //setup MQTT +//SetupMQTT creates a connection to broker and return client +func SetupMQTT(cfg config.ClientConfig) mqtt.Client { opts := mqtt.NewClientOptions() ncutils.Log("setting broker to " + cfg.Server.CoreDNSAddr + ":1883") opts.AddBroker(cfg.Server.CoreDNSAddr + ":1883") opts.SetDefaultPublishHandler(All) - opts.SetClientID("netclient-mqttt") client := mqtt.NewClient(opts) if token := client.Connect(); token.Wait() && token.Error() != nil { log.Fatal(token.Error()) } + return client +} + +//Netclient sets up Message Queue and subsribes/publishes updates to/from server +func Netclient(network string) { + ctx, cancel := context.WithCancel(context.Background()) + var cfg config.ClientConfig + cfg.Network = network + cfg.ReadConfig() + //fix NodeID to remove ### so NodeID can be used as message topic + //remove with GRA-73 + cfg.Node.ID = strings.ReplaceAll(cfg.Node.ID, "###", "-") + ncutils.Log("daemon started for network:" + network) + client := SetupMQTT(cfg) if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil { log.Fatal(token.Error()) } - client.AddRoute("update/"+network+"/"+cfg.Node.MacAddress, NodeUpdate) - client.AddRoute("update/"+network+"/peers", UpdatePeers) - client.AddRoute("update/"+network+"/keys", UpdateKeys) - client.AddRoute("update/"+network+"/keys/"+cfg.Node.MacAddress, UpdateKeys) + client.AddRoute("update/"+cfg.Node.ID, NodeUpdate) + client.AddRoute("update/peers/"+cfg.Node.ID, UpdatePeers) + client.AddRoute("update/keys/"+cfg.Node.ID, UpdateKeys) defer client.Disconnect(250) - go Checkin(client, network) - //go Metrics(client, network) - //go Connectivity(client, network) - for { - } + go Checkin(ctx, cfg, network) + go Metrics(ctx, cfg, network) + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGTERM, os.Interrupt) + <-quit + cancel() } +//All -- mqtt message hander for all ('#') topics var All mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("Topic: " + string(msg.Topic())) ncutils.Log("Message: " + string(msg.Payload())) } +//NodeUpdate -- mqtt message handler for /update/ topic var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update node " + string(msg.Payload())) } +//NodeUpdate -- mqtt message handler for /update/peers/ topic var UpdatePeers mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update peers " + string(msg.Payload())) } +//NodeUpdate -- mqtt message handler for /update/keys/ topic var UpdateKeys mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update keys " + string(msg.Payload())) } -func Checkin(client mqtt.Client, network string) { - var cfg config.ClientConfig - cfg.Network = network - cfg.ReadConfig() - for { - time.Sleep(time.Duration(cfg.Node.NetworkSettings.DefaultCheckInInterval) * time.Second) +//Checkin -- go routine that checks for public or local ip changes, publishes changes +// if there are no updates, simply "pings" the server as a checkin +func Checkin(ctx context.Context, cfg config.ClientConfig, network string) { + select { + case <-ctx.Done(): + ncutils.Log("Checkin cancelled") + return + //delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ?? + case <-time.After(time.Second * 10): ncutils.Log("Checkin running") if cfg.Node.Roaming == "yes" && cfg.Node.IsStatic != "yes" { extIP, err := ncutils.GetPublicIP() @@ -87,7 +107,7 @@ func Checkin(client mqtt.Client, network string) { } if cfg.Node.Endpoint != extIP && extIP != "" { ncutils.PrintLog("endpoint has changed from "+cfg.Node.Endpoint+" to "+extIP, 1) - UpdateEndpoint(client, network, extIP) + UpdateEndpoint(cfg, network, extIP) } intIP, err := getPrivateAddr() if err != nil { @@ -95,7 +115,7 @@ func Checkin(client mqtt.Client, network string) { } if cfg.Node.LocalAddress != intIP && intIP != "" { ncutils.PrintLog("local Address has changed from "+cfg.Node.LocalAddress+" to "+intIP, 1) - UpdateLocalAddress(client, network, intIP) + UpdateLocalAddress(cfg, network, intIP) } } else { localIP, err := ncutils.GetLocalIP(cfg.Node.LocalRange) @@ -104,31 +124,52 @@ func Checkin(client mqtt.Client, network string) { } if cfg.Node.Endpoint != localIP && localIP != "" { ncutils.PrintLog("endpoint has changed from "+cfg.Node.Endpoint+" to "+localIP, 1) - UpdateEndpoint(client, network, localIP) + UpdateEndpoint(cfg, network, localIP) } } - Ping(client, network) + Hello(cfg, network) + ncutils.Log("Checkin complete") } } -func Ping(client mqtt.Client, network string) { - var cfg config.ClientConfig - cfg.Network = network - cfg.ReadConfig() - if token := client.Publish("ping/"+network+"/"+cfg.Node.ID, 0, false, []byte("ping")); token.Wait() && token.Error() != nil { +//UpdateEndpoint -- publishes an endpoint update to broker +func UpdateEndpoint(cfg config.ClientConfig, network, ip string) { + ncutils.Log("Updating endpoint") + client := SetupMQTT(cfg) + if token := client.Publish("update/ip/"+cfg.Node.ID, 0, false, ip); token.Wait() && token.Error() != nil { + ncutils.Log("error publishing endpoint update " + token.Error().Error()) + } + client.Disconnect(250) +} + +//UpdateLocalAddress -- publishes a local address update to broker +func UpdateLocalAddress(cfg config.ClientConfig, network, ip string) { + ncutils.Log("Updating local address") + client := SetupMQTT(cfg) + if token := client.Publish("update/localaddress/"+cfg.Node.ID, 0, false, ip); token.Wait() && token.Error() != nil { + ncutils.Log("error publishing local address update " + token.Error().Error()) + } + client.Disconnect(250) +} + +//Hello -- ping the broker to let server know node is alive and doing fine +func Hello(cfg config.ClientConfig, network string) { + client := SetupMQTT(cfg) + if token := client.Publish("ping/"+network+"/"+cfg.Node.ID, 0, false, "hello world!"); token.Wait() && token.Error() != nil { ncutils.Log("error publishing ping " + token.Error().Error()) } + client.Disconnect(250) } -func Metrics(client mqtt.Client, network string) { - if token := client.Connect(); token.Wait() && token.Error() != nil { - log.Fatal(token.Error()) - } - var cfg config.ClientConfig - cfg.Network = network - cfg.ReadConfig() - for { - time.Sleep(time.Second * 60) +//Metics -- go routine that collects wireguard metrics and publishes to broker +func Metrics(ctx context.Context, cfg config.ClientConfig, network string) { + select { + case <-ctx.Done(): + ncutils.Log("Metrics collection cancelled") + return + //delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ?? + case <-time.After(time.Second * 60): + ncutils.Log("Metrics collection running") ncutils.Log("Metrics running") wg, err := wgctrl.New() if err != nil { @@ -145,70 +186,12 @@ func Metrics(client mqtt.Client, network string) { ncutils.Log("error marshaling peers " + err.Error()) break } - if token := client.Publish("metrics/"+network+"/"+cfg.Node.ID, 1, false, bytes); token.Wait() && token.Error() != nil { + client := SetupMQTT(cfg) + if token := client.Publish("metrics/"+cfg.Node.ID, 1, false, bytes); token.Wait() && token.Error() != nil { ncutils.Log("error publishing metrics " + token.Error().Error()) - break } wg.Close() + client.Disconnect(250) + ncutils.Log("metrics collection complete") } } - -type PingStat struct { - Name string - Reachable bool -} - -func Connectivity(client mqtt.Client, network string) { - if token := client.Connect(); token.Wait() && token.Error() != nil { - log.Fatal(token.Error()) - } - var cfg config.ClientConfig - cfg.Network = network - cfg.ReadConfig() - for { - time.Sleep(time.Duration(cfg.NetworkSettings.DefaultCheckInInterval) * time.Second) - ncutils.Log("Connectivity running") - var pingStats []PingStat - peers, err := ncutils.GetPeers(cfg.Node.Interface) - if err != nil { - ncutils.Log("error retriving peers " + err.Error()) - break - } - for _, peer := range peers { - var pingStat PingStat - pingStat.Name = peer.PublicKey.String() - pingStat.Reachable = true - ip := peer.Endpoint.IP.String() - fmt.Println("----------", peer.Endpoint.IP, ip) - pinger, err := ping.NewPinger(ip) - if err != nil { - ncutils.Log("error creating pinger " + err.Error()) - break - } - pinger.Timeout = 2 * time.Second - pinger.Run() - stats := pinger.Statistics() - if stats.PacketLoss == 100 { - pingStat.Reachable = false - } - pingStats = append(pingStats, pingStat) - } - bytes, err := json.Marshal(pingStats) - if err != nil { - ncutils.Log("error marshaling stats" + err.Error()) - break - } - if token := client.Publish("connectivity/"+network+"/"+cfg.Node.ID, 1, false, bytes); token.Wait() && token.Error() != nil { - ncutils.Log("error publishing ping stats " + token.Error().Error()) - break - } - } -} - -func UpdateEndpoint(client mqtt.Client, network, ip string) { - ncutils.Log("Updating endpoint") -} - -func UpdateLocalAddress(client mqtt.Client, network, ip string) { - ncutils.Log("Updating local address") -} From 7bc99d3076a17f66b0956cf78e012d5309bf1c1c Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Mon, 3 Jan 2022 16:26:40 -0500 Subject: [PATCH 09/18] move context up a level --- netclient/functions/daemon.go | 58 +++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go index 2e31d37a..43dae42f 100644 --- a/netclient/functions/daemon.go +++ b/netclient/functions/daemon.go @@ -18,15 +18,18 @@ import ( //Daemon runs netclient daemon from command line func Daemon() error { + ctx, cancel := context.WithCancel(context.Background()) networks, err := ncutils.GetSystemNetworks() if err != nil { return err } for _, network := range networks { - go Netclient(network) - } - for { + go Netclient(ctx, network) } + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGTERM, os.Interrupt) + <-quit + cancel() return nil } @@ -44,29 +47,30 @@ func SetupMQTT(cfg config.ClientConfig) mqtt.Client { } //Netclient sets up Message Queue and subsribes/publishes updates to/from server -func Netclient(network string) { - ctx, cancel := context.WithCancel(context.Background()) - var cfg config.ClientConfig - cfg.Network = network - cfg.ReadConfig() - //fix NodeID to remove ### so NodeID can be used as message topic - //remove with GRA-73 - cfg.Node.ID = strings.ReplaceAll(cfg.Node.ID, "###", "-") - ncutils.Log("daemon started for network:" + network) - client := SetupMQTT(cfg) - if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil { - log.Fatal(token.Error()) +func Netclient(ctx context.Context, network string) { + select { + case <-ctx.Done(): + ncutils.Log("shutting down daemon") + return + default: + var cfg config.ClientConfig + cfg.Network = network + cfg.ReadConfig() + //fix NodeID to remove ### so NodeID can be used as message topic + //remove with GRA-73 + cfg.Node.ID = strings.ReplaceAll(cfg.Node.ID, "###", "-") + ncutils.Log("daemon started for network:" + network) + client := SetupMQTT(cfg) + if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil { + log.Fatal(token.Error()) + } + client.AddRoute("update/"+cfg.Node.ID, NodeUpdate) + client.AddRoute("update/peers/"+cfg.Node.ID, UpdatePeers) + client.AddRoute("update/keys/"+cfg.Node.ID, UpdateKeys) + defer client.Disconnect(250) + go Checkin(ctx, cfg, network) + go Metrics(ctx, cfg, network) } - client.AddRoute("update/"+cfg.Node.ID, NodeUpdate) - client.AddRoute("update/peers/"+cfg.Node.ID, UpdatePeers) - client.AddRoute("update/keys/"+cfg.Node.ID, UpdateKeys) - defer client.Disconnect(250) - go Checkin(ctx, cfg, network) - go Metrics(ctx, cfg, network) - quit := make(chan os.Signal, 1) - signal.Notify(quit, syscall.SIGTERM, os.Interrupt) - <-quit - cancel() } //All -- mqtt message hander for all ('#') topics @@ -80,12 +84,12 @@ var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) ncutils.Log("received message to update node " + string(msg.Payload())) } -//NodeUpdate -- mqtt message handler for /update/peers/ topic +//UpdatePeers -- mqtt message handler for /update/peers/ topic var UpdatePeers mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update peers " + string(msg.Payload())) } -//NodeUpdate -- mqtt message handler for /update/keys/ topic +//UpdateKeys -- mqtt message handler for /update/keys/ topic var UpdateKeys mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update keys " + string(msg.Payload())) } From f5aa383541c2892a1a9fdfd86a41982527a5c6a2 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Mon, 3 Jan 2022 22:21:52 +0000 Subject: [PATCH 10/18] go routines now run forever like they are supposed to --- netclient/functions/daemon.go | 176 +++++++++++++++++----------------- 1 file changed, 90 insertions(+), 86 deletions(-) diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go index 43dae42f..e48e8c19 100644 --- a/netclient/functions/daemon.go +++ b/netclient/functions/daemon.go @@ -30,6 +30,7 @@ func Daemon() error { signal.Notify(quit, syscall.SIGTERM, os.Interrupt) <-quit cancel() + ncutils.Log("all done") return nil } @@ -48,29 +49,28 @@ func SetupMQTT(cfg config.ClientConfig) mqtt.Client { //Netclient sets up Message Queue and subsribes/publishes updates to/from server func Netclient(ctx context.Context, network string) { - select { - case <-ctx.Done(): - ncutils.Log("shutting down daemon") - return - default: - var cfg config.ClientConfig - cfg.Network = network - cfg.ReadConfig() - //fix NodeID to remove ### so NodeID can be used as message topic - //remove with GRA-73 - cfg.Node.ID = strings.ReplaceAll(cfg.Node.ID, "###", "-") - ncutils.Log("daemon started for network:" + network) - client := SetupMQTT(cfg) - if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil { - log.Fatal(token.Error()) - } - client.AddRoute("update/"+cfg.Node.ID, NodeUpdate) - client.AddRoute("update/peers/"+cfg.Node.ID, UpdatePeers) - client.AddRoute("update/keys/"+cfg.Node.ID, UpdateKeys) - defer client.Disconnect(250) - go Checkin(ctx, cfg, network) - go Metrics(ctx, cfg, network) + ncutils.Log("netclient go routine started for " + network) + var cfg config.ClientConfig + cfg.Network = network + cfg.ReadConfig() + //fix NodeID to remove ### so NodeID can be used as message topic + //remove with GRA-73 + cfg.Node.ID = strings.ReplaceAll(cfg.Node.ID, "###", "-") + ncutils.Log("daemon started for network:" + network) + client := SetupMQTT(cfg) + if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil { + log.Fatal(token.Error()) } + client.AddRoute("update/"+cfg.Node.ID, NodeUpdate) + client.AddRoute("update/peers/"+cfg.Node.ID, UpdatePeers) + client.AddRoute("update/keys/"+cfg.Node.ID, UpdateKeys) + defer client.Disconnect(250) + go Checkin(ctx, cfg, network) + go Metrics(ctx, cfg, network) + <-ctx.Done() + ncutils.Log("shutting down daemon") + return + ncutils.Log("netclient go routine ended for " + network) } //All -- mqtt message hander for all ('#') topics @@ -97,42 +97,44 @@ var UpdateKeys mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) //Checkin -- go routine that checks for public or local ip changes, publishes changes // if there are no updates, simply "pings" the server as a checkin func Checkin(ctx context.Context, cfg config.ClientConfig, network string) { - select { - case <-ctx.Done(): - ncutils.Log("Checkin cancelled") - return - //delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ?? - case <-time.After(time.Second * 10): - ncutils.Log("Checkin running") - if cfg.Node.Roaming == "yes" && cfg.Node.IsStatic != "yes" { - extIP, err := ncutils.GetPublicIP() - if err != nil { - ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1) - } - if cfg.Node.Endpoint != extIP && extIP != "" { - ncutils.PrintLog("endpoint has changed from "+cfg.Node.Endpoint+" to "+extIP, 1) - UpdateEndpoint(cfg, network, extIP) - } - intIP, err := getPrivateAddr() - if err != nil { - ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1) - } - if cfg.Node.LocalAddress != intIP && intIP != "" { - ncutils.PrintLog("local Address has changed from "+cfg.Node.LocalAddress+" to "+intIP, 1) - UpdateLocalAddress(cfg, network, intIP) - } - } else { - localIP, err := ncutils.GetLocalIP(cfg.Node.LocalRange) - if err != nil { - ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1) - } - if cfg.Node.Endpoint != localIP && localIP != "" { - ncutils.PrintLog("endpoint has changed from "+cfg.Node.Endpoint+" to "+localIP, 1) - UpdateEndpoint(cfg, network, localIP) + for { + select { + case <-ctx.Done(): + ncutils.Log("Checkin cancelled") + return + //delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ?? + case <-time.After(time.Second * 10): + ncutils.Log("Checkin running") + if cfg.Node.Roaming == "yes" && cfg.Node.IsStatic != "yes" { + extIP, err := ncutils.GetPublicIP() + if err != nil { + ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1) + } + if cfg.Node.Endpoint != extIP && extIP != "" { + ncutils.PrintLog("endpoint has changed from "+cfg.Node.Endpoint+" to "+extIP, 1) + UpdateEndpoint(cfg, network, extIP) + } + intIP, err := getPrivateAddr() + if err != nil { + ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1) + } + if cfg.Node.LocalAddress != intIP && intIP != "" { + ncutils.PrintLog("local Address has changed from "+cfg.Node.LocalAddress+" to "+intIP, 1) + UpdateLocalAddress(cfg, network, intIP) + } + } else { + localIP, err := ncutils.GetLocalIP(cfg.Node.LocalRange) + if err != nil { + ncutils.PrintLog("error encountered checking ip addresses: "+err.Error(), 1) + } + if cfg.Node.Endpoint != localIP && localIP != "" { + ncutils.PrintLog("endpoint has changed from "+cfg.Node.Endpoint+" to "+localIP, 1) + UpdateEndpoint(cfg, network, localIP) + } } + Hello(cfg, network) + ncutils.Log("Checkin complete") } - Hello(cfg, network) - ncutils.Log("Checkin complete") } } @@ -159,7 +161,7 @@ func UpdateLocalAddress(cfg config.ClientConfig, network, ip string) { //Hello -- ping the broker to let server know node is alive and doing fine func Hello(cfg config.ClientConfig, network string) { client := SetupMQTT(cfg) - if token := client.Publish("ping/"+network+"/"+cfg.Node.ID, 0, false, "hello world!"); token.Wait() && token.Error() != nil { + if token := client.Publish("ping/"+cfg.Node.ID, 0, false, "hello world!"); token.Wait() && token.Error() != nil { ncutils.Log("error publishing ping " + token.Error().Error()) } client.Disconnect(250) @@ -167,35 +169,37 @@ func Hello(cfg config.ClientConfig, network string) { //Metics -- go routine that collects wireguard metrics and publishes to broker func Metrics(ctx context.Context, cfg config.ClientConfig, network string) { - select { - case <-ctx.Done(): - ncutils.Log("Metrics collection cancelled") - return - //delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ?? - case <-time.After(time.Second * 60): - ncutils.Log("Metrics collection running") - ncutils.Log("Metrics running") - wg, err := wgctrl.New() - if err != nil { - ncutils.Log("error getting devices " + err.Error()) - break + for { + select { + case <-ctx.Done(): + ncutils.Log("Metrics collection cancelled") + return + //delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ?? + case <-time.After(time.Second * 60): + ncutils.Log("Metrics collection running") + ncutils.Log("Metrics running") + wg, err := wgctrl.New() + if err != nil { + ncutils.Log("error getting devices " + err.Error()) + break + } + device, err := wg.Device(cfg.Node.Interface) + if err != nil { + ncutils.Log("error readind wg device " + err.Error()) + break + } + bytes, err := json.Marshal(device.Peers) + if err != nil { + ncutils.Log("error marshaling peers " + err.Error()) + break + } + client := SetupMQTT(cfg) + if token := client.Publish("metrics/"+cfg.Node.ID, 1, false, bytes); token.Wait() && token.Error() != nil { + ncutils.Log("error publishing metrics " + token.Error().Error()) + } + wg.Close() + client.Disconnect(250) + ncutils.Log("metrics collection complete") } - device, err := wg.Device(cfg.Node.Interface) - if err != nil { - ncutils.Log("error readind wg device " + err.Error()) - break - } - bytes, err := json.Marshal(device.Peers) - if err != nil { - ncutils.Log("error marshaling peers " + err.Error()) - break - } - client := SetupMQTT(cfg) - if token := client.Publish("metrics/"+cfg.Node.ID, 1, false, bytes); token.Wait() && token.Error() != nil { - ncutils.Log("error publishing metrics " + token.Error().Error()) - } - wg.Close() - client.Disconnect(250) - ncutils.Log("metrics collection complete") } } From 5e5d97627d1edab44364e3edbb51d0a155f19801 Mon Sep 17 00:00:00 2001 From: 0xdcarns Date: Mon, 3 Jan 2022 18:27:13 -0500 Subject: [PATCH 11/18] linting fixes --- netclient/functions/daemon.go | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go index e48e8c19..45a49d9b 100644 --- a/netclient/functions/daemon.go +++ b/netclient/functions/daemon.go @@ -16,11 +16,12 @@ import ( "golang.zx2c4.com/wireguard/wgctrl" ) -//Daemon runs netclient daemon from command line +// Daemon runs netclient daemon from command line func Daemon() error { ctx, cancel := context.WithCancel(context.Background()) networks, err := ncutils.GetSystemNetworks() if err != nil { + cancel() return err } for _, network := range networks { @@ -34,7 +35,7 @@ func Daemon() error { return nil } -//SetupMQTT creates a connection to broker and return client +// SetupMQTT creates a connection to broker and return client func SetupMQTT(cfg config.ClientConfig) mqtt.Client { opts := mqtt.NewClientOptions() ncutils.Log("setting broker to " + cfg.Server.CoreDNSAddr + ":1883") @@ -47,7 +48,7 @@ func SetupMQTT(cfg config.ClientConfig) mqtt.Client { return client } -//Netclient sets up Message Queue and subsribes/publishes updates to/from server +// Netclient sets up Message Queue and subsribes/publishes updates to/from server func Netclient(ctx context.Context, network string) { ncutils.Log("netclient go routine started for " + network) var cfg config.ClientConfig @@ -55,7 +56,7 @@ func Netclient(ctx context.Context, network string) { cfg.ReadConfig() //fix NodeID to remove ### so NodeID can be used as message topic //remove with GRA-73 - cfg.Node.ID = strings.ReplaceAll(cfg.Node.ID, "###", "-") + cfg.Node.ID = strings.Replace(cfg.Node.ID, "###", "-", 1) ncutils.Log("daemon started for network:" + network) client := SetupMQTT(cfg) if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil { @@ -69,32 +70,30 @@ func Netclient(ctx context.Context, network string) { go Metrics(ctx, cfg, network) <-ctx.Done() ncutils.Log("shutting down daemon") - return - ncutils.Log("netclient go routine ended for " + network) } -//All -- mqtt message hander for all ('#') topics +// All -- mqtt message hander for all ('#') topics var All mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("Topic: " + string(msg.Topic())) ncutils.Log("Message: " + string(msg.Payload())) } -//NodeUpdate -- mqtt message handler for /update/ topic +// NodeUpdate -- mqtt message handler for /update/ topic var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update node " + string(msg.Payload())) } -//UpdatePeers -- mqtt message handler for /update/peers/ topic +// UpdatePeers -- mqtt message handler for /update/peers/ topic var UpdatePeers mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update peers " + string(msg.Payload())) } -//UpdateKeys -- mqtt message handler for /update/keys/ topic +// UpdateKeys -- mqtt message handler for /update/keys/ topic var UpdateKeys mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update keys " + string(msg.Payload())) } -//Checkin -- go routine that checks for public or local ip changes, publishes changes +// Checkin -- go routine that checks for public or local ip changes, publishes changes // if there are no updates, simply "pings" the server as a checkin func Checkin(ctx context.Context, cfg config.ClientConfig, network string) { for { @@ -138,7 +137,7 @@ func Checkin(ctx context.Context, cfg config.ClientConfig, network string) { } } -//UpdateEndpoint -- publishes an endpoint update to broker +// UpdateEndpoint -- publishes an endpoint update to broker func UpdateEndpoint(cfg config.ClientConfig, network, ip string) { ncutils.Log("Updating endpoint") client := SetupMQTT(cfg) @@ -148,7 +147,7 @@ func UpdateEndpoint(cfg config.ClientConfig, network, ip string) { client.Disconnect(250) } -//UpdateLocalAddress -- publishes a local address update to broker +// UpdateLocalAddress -- publishes a local address update to broker func UpdateLocalAddress(cfg config.ClientConfig, network, ip string) { ncutils.Log("Updating local address") client := SetupMQTT(cfg) @@ -158,7 +157,7 @@ func UpdateLocalAddress(cfg config.ClientConfig, network, ip string) { client.Disconnect(250) } -//Hello -- ping the broker to let server know node is alive and doing fine +// Hello -- ping the broker to let server know node is alive and doing fine func Hello(cfg config.ClientConfig, network string) { client := SetupMQTT(cfg) if token := client.Publish("ping/"+cfg.Node.ID, 0, false, "hello world!"); token.Wait() && token.Error() != nil { @@ -167,7 +166,7 @@ func Hello(cfg config.ClientConfig, network string) { client.Disconnect(250) } -//Metics -- go routine that collects wireguard metrics and publishes to broker +// Metics -- go routine that collects wireguard metrics and publishes to broker func Metrics(ctx context.Context, cfg config.ClientConfig, network string) { for { select { From b4deb65cfb041997d7ba2fae3c11122768154bc7 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Tue, 4 Jan 2022 17:24:50 -0500 Subject: [PATCH 12/18] Rebase to develop (#4) * add nameserver in call to CreateUserSpaceConf * fixed user deletion * changed log * go mod tidy and conver azure tenant to env/conf var * added egress relayed addrs to relayed nodes * added post commands for wg quick * refactored ncutils x-platform * log fix * adding egress to relay * fixing egress on relay Co-authored-by: dcarns <75687250+0xdcarns@users.noreply.github.com> Co-authored-by: 0xdcarns Co-authored-by: afeiszli --- .gitignore | 1 + auth/azure-ad.go | 3 +- config/config.go | 15 +++-- controllers/user.go | 2 +- logic/util.go | 71 +++++++++++++++++---- logic/wireguard.go | 3 +- main.go | 2 +- netclient/command/commands.go | 3 +- netclient/ncutils/netclientutils_darwin.go | 15 +++-- netclient/ncutils/netclientutils_freebsd.go | 18 +++--- netclient/ncutils/netclientutils_linux.go | 29 ++++++--- netclient/ncutils/netclientutils_windows.go | 15 +++-- netclient/wireguard/common.go | 6 +- netclient/wireguard/unix.go | 3 +- servercfg/serverconf.go | 11 ++++ 15 files changed, 136 insertions(+), 61 deletions(-) diff --git a/.gitignore b/.gitignore index 995aa2bc..defe793f 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ netclient/netclient32 netclient/netclient.exe config/dnsconfig/ data/ +.vscode/ diff --git a/auth/azure-ad.go b/auth/azure-ad.go index 8ad9a8e3..ffe1a173 100644 --- a/auth/azure-ad.go +++ b/auth/azure-ad.go @@ -5,7 +5,6 @@ import ( "fmt" "io/ioutil" "net/http" - "os" "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" @@ -36,7 +35,7 @@ func initAzureAD(redirectURL string, clientID string, clientSecret string) { ClientID: clientID, ClientSecret: clientSecret, Scopes: []string{"User.Read"}, - Endpoint: microsoft.AzureADEndpoint(os.Getenv("AZURE_TENANT")), + Endpoint: microsoft.AzureADEndpoint(servercfg.GetAzureTenant()), } } diff --git a/config/config.go b/config/config.go index c3b2fbd5..044d1a88 100644 --- a/config/config.go +++ b/config/config.go @@ -12,7 +12,7 @@ import ( "gopkg.in/yaml.v3" ) -//setting dev by default +// setting dev by default func getEnv() string { env := os.Getenv("NETMAKER_ENV") @@ -27,13 +27,13 @@ func getEnv() string { // Config : application config stored as global variable var Config *EnvironmentConfig -// EnvironmentConfig : +// EnvironmentConfig - environment conf struct type EnvironmentConfig struct { Server ServerConfig `yaml:"server"` SQL SQLConfig `yaml:"sql"` } -// ServerConfig : +// ServerConfig - server conf struct type ServerConfig struct { CoreDNSAddr string `yaml:"corednsaddr"` APIConnString string `yaml:"apiconn"` @@ -58,8 +58,8 @@ type ServerConfig struct { Version string `yaml:"version"` SQLConn string `yaml:"sqlconn"` Platform string `yaml:"platform"` - Database string `yaml:database` - CheckinInterval string `yaml:checkininterval` + Database string `yaml:"database"` + CheckinInterval string `yaml:"checkininterval"` DefaultNodeLimit int32 `yaml:"defaultnodelimit"` Verbosity int32 `yaml:"verbosity"` ServerCheckinInterval int64 `yaml:"servercheckininterval"` @@ -68,9 +68,10 @@ type ServerConfig struct { ClientSecret string `yaml:"clientsecret"` FrontendURL string `yaml:"frontendurl"` DisplayKeys string `yaml:"displaykeys"` + AzureTenant string `yaml:"azuretenant"` } -// Generic SQL Config +// SQLConfig - Generic SQL Config type SQLConfig struct { Host string `yaml:"host"` Port int32 `yaml:"port"` @@ -80,7 +81,7 @@ type SQLConfig struct { SSLMode string `yaml:"sslmode"` } -//reading in the env file +// reading in the env file func readConfig() *EnvironmentConfig { file := fmt.Sprintf("config/environments/%s.yaml", getEnv()) f, err := os.Open(file) diff --git a/controllers/user.go b/controllers/user.go index f08328c7..c9e387e3 100644 --- a/controllers/user.go +++ b/controllers/user.go @@ -23,7 +23,7 @@ func userHandlers(r *mux.Router) { r.HandleFunc("/api/users/networks/{username}", securityCheck(true, http.HandlerFunc(updateUserNetworks))).Methods("PUT") r.HandleFunc("/api/users/{username}/adm", securityCheck(true, http.HandlerFunc(updateUserAdm))).Methods("PUT") r.HandleFunc("/api/users/{username}", securityCheck(true, http.HandlerFunc(createUser))).Methods("POST") - r.HandleFunc("/api/users/{username}", securityCheck(false, continueIfUserMatch(http.HandlerFunc(deleteUser)))).Methods("DELETE") + r.HandleFunc("/api/users/{username}", securityCheck(true, http.HandlerFunc(deleteUser))).Methods("DELETE") r.HandleFunc("/api/users/{username}", securityCheck(false, continueIfUserMatch(http.HandlerFunc(getUser)))).Methods("GET") r.HandleFunc("/api/users", securityCheck(true, http.HandlerFunc(getUsers))).Methods("GET") r.HandleFunc("/api/oauth/login", auth.HandleAuthLogin).Methods("GET") diff --git a/logic/util.go b/logic/util.go index d7ce5534..989bff4e 100644 --- a/logic/util.go +++ b/logic/util.go @@ -184,26 +184,18 @@ func GetNode(macaddress string, network string) (models.Node, error) { // GetNodePeers - fetches peers for a given node func GetNodePeers(networkName string, excludeRelayed bool) ([]models.Node, error) { var peers []models.Node - collection, err := database.FetchRecords(database.NODES_TABLE_NAME) + var networkNodes, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName) if err != nil { - if database.IsEmptyRecord(err) { - return peers, nil - } - logger.Log(2, err.Error()) - return nil, err + return peers, nil } + udppeers, errN := database.GetPeers(networkName) if errN != nil { logger.Log(2, errN.Error()) } - for _, value := range collection { - var node = &models.Node{} + + for _, node := range networkNodes { var peer = models.Node{} - err := json.Unmarshal([]byte(value), node) - if err != nil { - logger.Log(2, err.Error()) - continue - } if node.IsEgressGateway == "yes" { // handle egress stuff peer.EgressGatewayRanges = node.EgressGatewayRanges peer.IsEgressGateway = node.IsEgressGateway @@ -211,7 +203,7 @@ func GetNodePeers(networkName string, excludeRelayed bool) ([]models.Node, error allow := node.IsRelayed != "yes" || !excludeRelayed if node.Network == networkName && node.IsPending != "yes" && allow { - peer = setPeerInfo(node) + peer = setPeerInfo(&node) if node.UDPHolePunch == "yes" && errN == nil && CheckEndpoint(udppeers[node.PublicKey]) { endpointstring := udppeers[node.PublicKey] endpointarr := strings.Split(endpointstring, ":") @@ -230,6 +222,11 @@ func GetNodePeers(networkName string, excludeRelayed bool) ([]models.Node, error } else { peer.AllowedIPs = append(peer.AllowedIPs, node.RelayAddrs...) } + for _, egressNode := range egressNetworkNodes { + if egressNode.IsRelayed == "yes" && StringSliceContains(node.RelayAddrs, egressNode.Address) { + peer.AllowedIPs = append(peer.AllowedIPs, egressNode.EgressGatewayRanges...) + } + } } peers = append(peers, peer) } @@ -252,6 +249,14 @@ func GetPeersList(networkName string, excludeRelayed bool, relayedNodeAddr strin network, err := GetNetwork(networkName) if err == nil { peerNode.AllowedIPs = append(peerNode.AllowedIPs, network.AddressRange) + var _, egressNetworkNodes, err = getNetworkEgressAndNodes(networkName) + if err == nil { + for _, egress := range egressNetworkNodes { + if egress.Address != relayedNodeAddr { + peerNode.AllowedIPs = append(peerNode.AllowedIPs, egress.EgressGatewayRanges...) + } + } + } } else { peerNode.AllowedIPs = append(peerNode.AllowedIPs, peerNode.RelayAddrs...) } @@ -286,6 +291,34 @@ func RandomString(length int) string { // == Private Methods == +func getNetworkEgressAndNodes(networkName string) ([]models.Node, []models.Node, error) { + var networkNodes, egressNetworkNodes []models.Node + collection, err := database.FetchRecords(database.NODES_TABLE_NAME) + if err != nil { + if database.IsEmptyRecord(err) { + return networkNodes, egressNetworkNodes, nil + } + logger.Log(2, err.Error()) + return nil, nil, err + } + + for _, value := range collection { + var node = models.Node{} + err := json.Unmarshal([]byte(value), &node) + if err != nil { + logger.Log(2, err.Error()) + continue + } + if node.Network == networkName { + networkNodes = append(networkNodes, node) + if node.IsEgressGateway == "yes" { + egressNetworkNodes = append(egressNetworkNodes, node) + } + } + } + return networkNodes, egressNetworkNodes, nil +} + func setPeerInfo(node *models.Node) models.Node { var peer models.Node peer.RelayAddrs = node.RelayAddrs @@ -326,3 +359,13 @@ func setIPForwardingLinux() error { } return nil } + +// StringSliceContains - sees if a string slice contains a string element +func StringSliceContains(slice []string, item string) bool { + for _, s := range slice { + if s == item { + return true + } + } + return false +} diff --git a/logic/wireguard.go b/logic/wireguard.go index 2090ec18..f903ae43 100644 --- a/logic/wireguard.go +++ b/logic/wireguard.go @@ -87,7 +87,8 @@ func initWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig if !ncutils.IsKernel() { var newConf string - newConf, _ = ncutils.CreateWireGuardConf(node.Address, key.String(), strconv.FormatInt(int64(node.ListenPort), 10), node.MTU, servercfg.GetCoreDNSAddr(), node.PersistentKeepalive, peers) + var nameserver string + newConf, _ = ncutils.CreateWireGuardConf(node.Address, key.String(), strconv.FormatInt(int64(node.ListenPort), 10), node.MTU, nameserver, servercfg.GetCoreDNSAddr(), node.PersistentKeepalive, peers) confPath := ncutils.GetNetclientPathSpecific() + ifacename + ".conf" logger.Log(1, "writing wg conf file to:", confPath) err = ioutil.WriteFile(confPath, []byte(newConf), 0644) diff --git a/main.go b/main.go index 384302d7..c908c5bb 100644 --- a/main.go +++ b/main.go @@ -43,7 +43,7 @@ func initialize() { // Client Mode Prereq Check var authProvider = auth.InitializeAuthProvider() if authProvider != "" { - logger.Log(0, "OAuth provider, ", authProvider, ", initialized") + logger.Log(0, "OAuth provider,", authProvider+",", "initialized") } else { logger.Log(0, "no OAuth provider found or not configured, continuing without OAuth") } diff --git a/netclient/command/commands.go b/netclient/command/commands.go index fa8013df..1aecdb4b 100644 --- a/netclient/command/commands.go +++ b/netclient/command/commands.go @@ -205,8 +205,9 @@ func List(cfg config.ClientConfig) error { // Uninstall - runs uninstall command from cli func Uninstall() error { - ncutils.PrintLog("uninstalling netclient", 0) + ncutils.PrintLog("uninstalling netclient...", 0) err := functions.Uninstall() + ncutils.PrintLog("uninstalled netclient", 0) return err } diff --git a/netclient/ncutils/netclientutils_darwin.go b/netclient/ncutils/netclientutils_darwin.go index 79fc85d7..a073f989 100644 --- a/netclient/ncutils/netclientutils_darwin.go +++ b/netclient/ncutils/netclientutils_darwin.go @@ -7,6 +7,7 @@ import ( "strconv" "strings" + "github.com/gravitl/netmaker/models" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) @@ -33,12 +34,12 @@ func GetEmbedded() error { return nil } -// CreateUserSpaceConf - creates a user space WireGuard conf -func CreateUserSpaceConf(address string, privatekey string, listenPort string, mtu int32, perskeepalive int32, peers []wgtypes.PeerConfig) (string, error) { - peersString, err := parsePeers(perskeepalive, peers) +// CreateWireGuardConf - creates a WireGuard conf string +func CreateWireGuardConf(node *models.Node, privatekey string, listenPort string, dns string, peers []wgtypes.PeerConfig) (string, error) { + peersString, err := parsePeers(node.PersistentKeepalive, peers) var listenPortString string - if mtu <= 0 { - mtu = 1280 + if node.MTU <= 0 { + node.MTU = 1280 } if listenPort != "" { listenPortString += "ListenPort = " + listenPort @@ -55,9 +56,9 @@ MTU = %s %s `, - address+"/32", + node.Address+"/32", privatekey, - strconv.Itoa(int(mtu)), + strconv.Itoa(int(node.MTU)), listenPortString, peersString) return config, nil diff --git a/netclient/ncutils/netclientutils_freebsd.go b/netclient/ncutils/netclientutils_freebsd.go index 19d3aa19..bbacdc6c 100644 --- a/netclient/ncutils/netclientutils_freebsd.go +++ b/netclient/ncutils/netclientutils_freebsd.go @@ -3,13 +3,15 @@ package ncutils import ( "context" "fmt" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "log" "os/exec" "strconv" "strings" "syscall" "time" + + "github.com/gravitl/netmaker/models" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) // RunCmdFormatted - run a command formatted for freebsd @@ -41,12 +43,12 @@ func RunCmd(command string, printerr bool) (string, error) { return string(out), err } -// CreateUserSpaceConf - creates a user space WireGuard conf -func CreateUserSpaceConf(address string, privatekey string, listenPort string, mtu int32, perskeepalive int32, peers []wgtypes.PeerConfig) (string, error) { - peersString, err := parsePeers(perskeepalive, peers) +// CreateWireGuardConf - creates a WireGuard conf string +func CreateWireGuardConf(node *models.Node, privatekey string, listenPort string, dns string, peers []wgtypes.PeerConfig) (string, error) { + peersString, err := parsePeers(node.PersistentKeepalive, peers) var listenPortString string - if mtu <= 0 { - mtu = 1280 + if node.MTU <= 0 { + node.MTU = 1280 } if listenPort != "" { listenPortString += "ListenPort = " + listenPort @@ -63,9 +65,9 @@ MTU = %s %s `, - address+"/32", + node.Address+"/32", privatekey, - strconv.Itoa(int(mtu)), + strconv.Itoa(int(node.MTU)), listenPortString, peersString) return config, nil diff --git a/netclient/ncutils/netclientutils_linux.go b/netclient/ncutils/netclientutils_linux.go index ae40c292..bc4c399e 100644 --- a/netclient/ncutils/netclientutils_linux.go +++ b/netclient/ncutils/netclientutils_linux.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" + "github.com/gravitl/netmaker/models" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) @@ -33,15 +34,23 @@ func GetEmbedded() error { } // CreateWireGuardConf - creates a user space WireGuard conf -func CreateWireGuardConf(address string, privatekey string, listenPort string, mtu int32, dns string, perskeepalive int32, peers []wgtypes.PeerConfig) (string, error) { - peersString, err := parsePeers(perskeepalive, peers) - var listenPortString string - if mtu <= 0 { - mtu = 1280 +func CreateWireGuardConf(node *models.Node, privatekey string, listenPort string, dns string, peers []wgtypes.PeerConfig) (string, error) { + peersString, err := parsePeers(node.PersistentKeepalive, peers) + var listenPortString, postDownString, postUpString string + if node.MTU <= 0 { + node.MTU = 1280 } + if node.PostDown != "" { + postDownString = fmt.Sprintf("PostDown = %s", node.PostDown) + } + if node.PostUp != "" { + postUpString = fmt.Sprintf("PostUp = %s", node.PostUp) + } + if listenPort != "" { - listenPortString += "ListenPort = " + listenPort + listenPortString = fmt.Sprintf("ListenPort = %s", listenPort) } + if err != nil { return "", err } @@ -51,14 +60,18 @@ DNS = %s PrivateKey = %s MTU = %s %s +%s +%s %s `, - address+"/32", + node.Address+"/32", dns, privatekey, - strconv.Itoa(int(mtu)), + strconv.Itoa(int(node.MTU)), + postDownString, + postUpString, listenPortString, peersString) return config, nil diff --git a/netclient/ncutils/netclientutils_windows.go b/netclient/ncutils/netclientutils_windows.go index 45974297..5acf73a7 100644 --- a/netclient/ncutils/netclientutils_windows.go +++ b/netclient/ncutils/netclientutils_windows.go @@ -10,6 +10,7 @@ import ( "strings" "syscall" + "github.com/gravitl/netmaker/models" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) @@ -47,12 +48,12 @@ func RunCmdFormatted(command string, printerr bool) (string, error) { return string(out), err } -// CreateUserSpaceConf - creates a user space WireGuard conf -func CreateUserSpaceConf(address string, privatekey string, listenPort string, mtu int32, perskeepalive int32, peers []wgtypes.PeerConfig) (string, error) { - peersString, err := parsePeers(perskeepalive, peers) +// CreateWireGuardConf - creates a WireGuard conf string +func CreateWireGuardConf(node *models.Node, privatekey string, listenPort string, dns string, peers []wgtypes.PeerConfig) (string, error) { + peersString, err := parsePeers(node.PersistentKeepalive, peers) var listenPortString string - if mtu <= 0 { - mtu = 1280 + if node.MTU <= 0 { + node.MTU = 1280 } if listenPort != "" { listenPortString += "ListenPort = " + listenPort @@ -69,9 +70,9 @@ MTU = %s %s `, - address+"/32", + node.Address+"/32", privatekey, - strconv.Itoa(int(mtu)), + strconv.Itoa(int(node.MTU)), listenPortString, peersString) return config, nil diff --git a/netclient/wireguard/common.go b/netclient/wireguard/common.go index 53613790..f65016dd 100644 --- a/netclient/wireguard/common.go +++ b/netclient/wireguard/common.go @@ -149,9 +149,9 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig } var newConf string if node.UDPHolePunch != "yes" { - newConf, _ = ncutils.CreateWireGuardConf(node.Address, key.String(), strconv.FormatInt(int64(node.ListenPort), 10), node.MTU, nameserver, node.PersistentKeepalive, peers) + newConf, _ = ncutils.CreateWireGuardConf(node, key.String(), strconv.FormatInt(int64(node.ListenPort), 10), nameserver, peers) } else { - newConf, _ = ncutils.CreateWireGuardConf(node.Address, key.String(), "", node.MTU, nameserver, node.PersistentKeepalive, peers) + newConf, _ = ncutils.CreateWireGuardConf(node, key.String(), "", nameserver, peers) } confPath := ncutils.GetNetclientPathSpecific() + ifacename + ".conf" ncutils.PrintLog("writing wg conf file to: "+confPath, 1) @@ -182,7 +182,7 @@ func InitWireguard(node *models.Node, privkey string, peers []wgtypes.PeerConfig } else { d, _ := wgclient.Device(deviceiface) for d != nil && d.Name == deviceiface { - _ = RemoveConf(ifacename, false) // remove interface first + RemoveConf(ifacename, false) // remove interface first time.Sleep(time.Second >> 2) d, _ = wgclient.Device(deviceiface) } diff --git a/netclient/wireguard/unix.go b/netclient/wireguard/unix.go index 8b557d0a..6e9e52af 100644 --- a/netclient/wireguard/unix.go +++ b/netclient/wireguard/unix.go @@ -1,6 +1,7 @@ package wireguard import ( + "fmt" "io/ioutil" "log" "os" @@ -86,7 +87,7 @@ func SyncWGQuickConf(iface string, confPath string) error { // RemoveWGQuickConf - calls wg-quick down func RemoveWGQuickConf(confPath string, printlog bool) error { - _, err := ncutils.RunCmd("wg-quick down "+confPath, printlog) + _, err := ncutils.RunCmd(fmt.Sprintf("wg-quick down %s", confPath), printlog) return err } diff --git a/servercfg/serverconf.go b/servercfg/serverconf.go index fb7a67cb..7c1ebd74 100644 --- a/servercfg/serverconf.go +++ b/servercfg/serverconf.go @@ -502,6 +502,17 @@ func GetAuthProviderInfo() []string { return []string{"", "", ""} } +// GetAzureTenant - retrieve the azure tenant ID from env variable or config file +func GetAzureTenant() string { + var azureTenant = "" + if os.Getenv("AZURE_TENANT") != "" { + azureTenant = os.Getenv("AZURE_TENANT") + } else if config.Config.Server.AzureTenant != "" { + azureTenant = config.Config.Server.AzureTenant + } + return azureTenant +} + // GetMacAddr - get's mac address func getMacAddr() string { ifas, err := net.Interfaces() From d9ff00d4b155f9f0762d2bb4ac7c536cb1e24229 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Wed, 5 Jan 2022 10:05:51 -0500 Subject: [PATCH 13/18] subscribed message handlers implemented --- go.mod | 1 + go.sum | 2 + models/mqtt.go | 14 ++++ netclient/functions/daemon.go | 75 +++++++++++++++++++++ netclient/wireguard/common.go | 123 ++++++++++++++++++++++++++++++++++ 5 files changed, 215 insertions(+) create mode 100644 models/mqtt.go diff --git a/go.mod b/go.mod index 8c49b6bb..781d86a6 100644 --- a/go.mod +++ b/go.mod @@ -49,4 +49,5 @@ require ( github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect google.golang.org/appengine v1.4.0 // indirect + gopkg.in/ini.v1 v1.66.2 // indirect ) diff --git a/go.sum b/go.sum index 5b8fecb5..a1efc4e7 100644 --- a/go.sum +++ b/go.sum @@ -292,6 +292,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= +gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/models/mqtt.go b/models/mqtt.go new file mode 100644 index 00000000..a7e87e1f --- /dev/null +++ b/models/mqtt.go @@ -0,0 +1,14 @@ +package models + +import "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + +type PeerUpdate struct { + Network string + Interface string + Peers []wgtypes.Peer +} + +type KeyUpdate struct { + Network string + Interface string +} diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go index 45a49d9b..fc926bda 100644 --- a/netclient/functions/daemon.go +++ b/netclient/functions/daemon.go @@ -11,9 +11,12 @@ import ( "time" mqtt "github.com/eclipse/paho.mqtt.golang" + "github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/netclient/config" "github.com/gravitl/netmaker/netclient/ncutils" + "github.com/gravitl/netmaker/netclient/wireguard" "golang.zx2c4.com/wireguard/wgctrl" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) // Daemon runs netclient daemon from command line @@ -81,16 +84,88 @@ var All mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { // NodeUpdate -- mqtt message handler for /update/ topic var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update node " + string(msg.Payload())) + //potentiall blocking i/o so do this in a go routine + go func() { + var data models.Node + err := json.Unmarshal(msg.Payload(), &data) + if err != nil { + ncutils.Log("error unmarshalling node update data" + err.Error()) + return + } + var cfg config.ClientConfig + cfg.Network = data.Network + cfg.ReadConfig() + nameserver := cfg.Server.CoreDNSAddr + privateKey, err := wireguard.RetrievePrivKey(data.Network) + if err := wireguard.UpdateWgInterface(cfg.Node.Interface, privateKey, nameserver, data); err != nil { + ncutils.Log("error updating wireguard config " + err.Error()) + return + } + // path hardcoded for now... should be updated + err = wireguard.ApplyWGQuickConf("/etc/netclient/config/" + cfg.Node.Interface + ".conf") + if err != nil { + ncutils.Log("error restarting wg after peer update " + err.Error()) + return + } + }() } // UpdatePeers -- mqtt message handler for /update/peers/ topic var UpdatePeers mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update peers " + string(msg.Payload())) + //potentiall blocking i/o so do this in a go routine + go func() { + var peerUpdate models.PeerUpdate + err := json.Unmarshal(msg.Payload(), &peerUpdate) + if err != nil { + ncutils.Log("error unmarshalling peer data") + return + } + var cfg config.ClientConfig + cfg.Network = peerUpdate.Network + cfg.ReadConfig() + err = wireguard.UpdateWgPeers(cfg.Node.Interface, peerUpdate.Peers) + if err != nil { + ncutils.Log("error updating peers" + err.Error()) + return + } + // path hardcoded for now... should be updated + err = wireguard.ApplyWGQuickConf("/etc/netclient/config/" + cfg.Node.Interface + ".conf") + if err != nil { + ncutils.Log("error restarting wg after peer update " + err.Error()) + return + } + }() } // UpdateKeys -- mqtt message handler for /update/keys/ topic var UpdateKeys mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update keys " + string(msg.Payload())) + //potentiall blocking i/o so do this in a go routine + go func() { + var data models.KeyUpdate + if err := json.Unmarshal(msg.Payload(), &data); err != nil { + ncutils.Log("error unmarshalling key update data" + err.Error()) + return + } + var cfg config.ClientConfig + cfg.Network = data.Network + cfg.ReadConfig() + key, err := wgtypes.GeneratePrivateKey() + if err != nil { + ncutils.Log("error generating privatekey " + err.Error()) + return + } + if err := wireguard.UpdatePrivateKey(data.Interface, key.String()); err != nil { + ncutils.Log("error updating wireguard key " + err.Error()) + return + } + publicKey := key.PublicKey() + if token := client.Publish("update/publickey/"+cfg.Node.ID, 0, false, publicKey.String()); token.Wait() && token.Error() != nil { + ncutils.Log("error publishing publickey update " + token.Error().Error()) + } + client.Disconnect(250) + }() } // Checkin -- go routine that checks for public or local ip changes, publishes changes diff --git a/netclient/wireguard/common.go b/netclient/wireguard/common.go index f65016dd..56c1f241 100644 --- a/netclient/wireguard/common.go +++ b/netclient/wireguard/common.go @@ -17,6 +17,7 @@ import ( "github.com/gravitl/netmaker/netclient/server" "golang.zx2c4.com/wireguard/wgctrl" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "gopkg.in/ini.v1" ) // SetPeers - sets peers on a given WireGuard interface @@ -290,3 +291,125 @@ func ApplyConf(confPath string) error { } return err } + +// WriteWgConfig - creates a wireguard config file +func WriteWgConfig(cfg config.ClientConfig, privateKey string, peers []wgtypes.Peer) error { + options := ini.LoadOptions{ + AllowNonUniqueSections: true, + AllowShadows: true, + } + wireguard := ini.Empty(options) + wireguard.Section("Interface").Key("PrivateKey").SetValue(privateKey) + wireguard.Section("Interface").Key("ListenPort").SetValue(strconv.Itoa(int(cfg.Node.ListenPort))) + if cfg.Node.Address != "" { + wireguard.Section("Interface").Key("Address").SetValue(cfg.Node.Address) + } + if cfg.Node.Address6 != "" { + wireguard.Section("Interface").Key("Address").SetValue(cfg.Node.Address6) + } + if cfg.Node.DNSOn == "yes" { + wireguard.Section("Interface").Key("DNS").SetValue(cfg.Server.CoreDNSAddr) + } + if cfg.Node.PostUp != "" { + wireguard.Section("Interface").Key("PostUp").SetValue(cfg.Node.PostUp) + } + if cfg.Node.PostDown != "" { + wireguard.Section("Interface").Key("PostDown").SetValue(cfg.Node.PostDown) + } + for i, peer := range peers { + wireguard.SectionWithIndex("Peer", i).Key("PublicKey").SetValue(peer.PublicKey.String()) + if peer.PresharedKey.String() != "" { + wireguard.SectionWithIndex("Peer", i).Key("PreSharedKey").SetValue(peer.PresharedKey.String()) + } + if peer.AllowedIPs != nil { + var allowedIPs string + for _, ip := range peer.AllowedIPs { + allowedIPs = allowedIPs + ", " + ip.String() + } + wireguard.SectionWithIndex("Peer", i).Key("AllowedIps").SetValue(allowedIPs) + } + if peer.Endpoint != nil { + wireguard.SectionWithIndex("Peer", i).Key("Endpoint").SetValue(peer.Endpoint.String()) + } + } + if err := wireguard.SaveTo("/etc/netclient/config" + cfg.Node.Interface + ".conf"); err != nil { + return err + } + return nil +} + +// UpdateWgPeers - updates the peers of a network +func UpdateWgPeers(wgInterface string, peers []wgtypes.Peer) error { + //update to get path properly + file := "/etc/netclient/config/" + wgInterface + ".conf" + wireguard, err := ini.ShadowLoad(file) + if err != nil { + return err + } + for i, peer := range peers { + wireguard.SectionWithIndex("Peer", i).Key("PublicKey").SetValue(peer.PublicKey.String()) + if peer.PresharedKey.String() != "" { + wireguard.SectionWithIndex("Peer", i).Key("PreSharedKey").SetValue(peer.PresharedKey.String()) + } + if peer.AllowedIPs != nil { + var allowedIPs string + for _, ip := range peer.AllowedIPs { + allowedIPs = allowedIPs + ", " + ip.String() + } + wireguard.SectionWithIndex("Peer", i).Key("AllowedIps").SetValue(allowedIPs) + } + if peer.Endpoint != nil { + wireguard.SectionWithIndex("Peer", i).Key("Endpoint").SetValue(peer.Endpoint.String()) + } + } + if err := wireguard.SaveTo(file); err != nil { + return err + } + return nil +} + +// UpdateWgInterface - updates the interface section of a wireguard config file +func UpdateWgInterface(wgInterface, privateKey, nameserver string, node models.Node) error { + //update to get path properly + file := "/etc/netclient/config/" + wgInterface + ".conf" + wireguard, err := ini.ShadowLoad(file) + if err != nil { + return err + } + wireguard.Section("Interface").Key("PrivateKey").SetValue(privateKey) + wireguard.Section("Interface").Key("ListenPort").SetValue(strconv.Itoa(int(node.ListenPort))) + if node.Address != "" { + wireguard.Section("Interface").Key("Address").SetValue(node.Address) + } + if node.Address6 != "" { + wireguard.Section("Interface").Key("Address").SetValue(node.Address6) + } + if node.DNSOn == "yes" { + wireguard.Section("Interface").Key("DNS").SetValue(nameserver) + } + if node.PostUp != "" { + wireguard.Section("Interface").Key("PostUp").SetValue(node.PostUp) + } + if node.PostDown != "" { + wireguard.Section("Interface").Key("PostDown").SetValue(node.PostDown) + } + if err := wireguard.SaveTo(file); err != nil { + return err + } + return nil +} + +// UpdatePrivateKey - updates the private key of a wireguard config file +func UpdatePrivateKey(wgInterface, privateKey string) error { + //update to get path properly + file := "/etc/netclient/config/" + wgInterface + ".conf" + wireguard, err := ini.ShadowLoad(file) + if err != nil { + return err + } + wireguard.Section("Interface").Key("PrivateKey").SetValue(privateKey) + if err := wireguard.SaveTo(file); err != nil { + return err + } + return nil +} From 81b75c78bd1cf53db5a7da727a3835c69bddc631 Mon Sep 17 00:00:00 2001 From: 0xdcarns Date: Wed, 5 Jan 2022 10:32:20 -0500 Subject: [PATCH 14/18] constants --- netclient/wireguard/common.go | 59 +++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/netclient/wireguard/common.go b/netclient/wireguard/common.go index 56c1f241..cb83c166 100644 --- a/netclient/wireguard/common.go +++ b/netclient/wireguard/common.go @@ -20,6 +20,11 @@ import ( "gopkg.in/ini.v1" ) +const ( + section_interface = "Interface" + section_peers = "Peer" +) + // SetPeers - sets peers on a given WireGuard interface func SetPeers(iface string, keepalive int32, peers []wgtypes.PeerConfig) error { @@ -299,40 +304,40 @@ func WriteWgConfig(cfg config.ClientConfig, privateKey string, peers []wgtypes.P AllowShadows: true, } wireguard := ini.Empty(options) - wireguard.Section("Interface").Key("PrivateKey").SetValue(privateKey) - wireguard.Section("Interface").Key("ListenPort").SetValue(strconv.Itoa(int(cfg.Node.ListenPort))) + wireguard.Section(section_interface).Key("PrivateKey").SetValue(privateKey) + wireguard.Section(section_interface).Key("ListenPort").SetValue(strconv.Itoa(int(cfg.Node.ListenPort))) if cfg.Node.Address != "" { - wireguard.Section("Interface").Key("Address").SetValue(cfg.Node.Address) + wireguard.Section(section_interface).Key("Address").SetValue(cfg.Node.Address) } if cfg.Node.Address6 != "" { - wireguard.Section("Interface").Key("Address").SetValue(cfg.Node.Address6) + wireguard.Section(section_interface).Key("Address").SetValue(cfg.Node.Address6) } if cfg.Node.DNSOn == "yes" { - wireguard.Section("Interface").Key("DNS").SetValue(cfg.Server.CoreDNSAddr) + wireguard.Section(section_interface).Key("DNS").SetValue(cfg.Server.CoreDNSAddr) } if cfg.Node.PostUp != "" { - wireguard.Section("Interface").Key("PostUp").SetValue(cfg.Node.PostUp) + wireguard.Section(section_interface).Key("PostUp").SetValue(cfg.Node.PostUp) } if cfg.Node.PostDown != "" { - wireguard.Section("Interface").Key("PostDown").SetValue(cfg.Node.PostDown) + wireguard.Section(section_interface).Key("PostDown").SetValue(cfg.Node.PostDown) } for i, peer := range peers { - wireguard.SectionWithIndex("Peer", i).Key("PublicKey").SetValue(peer.PublicKey.String()) + wireguard.SectionWithIndex(section_peers, i).Key("PublicKey").SetValue(peer.PublicKey.String()) if peer.PresharedKey.String() != "" { - wireguard.SectionWithIndex("Peer", i).Key("PreSharedKey").SetValue(peer.PresharedKey.String()) + wireguard.SectionWithIndex(section_peers, i).Key("PreSharedKey").SetValue(peer.PresharedKey.String()) } if peer.AllowedIPs != nil { var allowedIPs string for _, ip := range peer.AllowedIPs { allowedIPs = allowedIPs + ", " + ip.String() } - wireguard.SectionWithIndex("Peer", i).Key("AllowedIps").SetValue(allowedIPs) + wireguard.SectionWithIndex(section_peers, i).Key("AllowedIps").SetValue(allowedIPs) } if peer.Endpoint != nil { - wireguard.SectionWithIndex("Peer", i).Key("Endpoint").SetValue(peer.Endpoint.String()) + wireguard.SectionWithIndex(section_peers, i).Key("Endpoint").SetValue(peer.Endpoint.String()) } } - if err := wireguard.SaveTo("/etc/netclient/config" + cfg.Node.Interface + ".conf"); err != nil { + if err := wireguard.SaveTo(ncutils.GetNetclientPathSpecific() + cfg.Node.Interface + ".conf"); err != nil { return err } return nil @@ -341,25 +346,25 @@ func WriteWgConfig(cfg config.ClientConfig, privateKey string, peers []wgtypes.P // UpdateWgPeers - updates the peers of a network func UpdateWgPeers(wgInterface string, peers []wgtypes.Peer) error { //update to get path properly - file := "/etc/netclient/config/" + wgInterface + ".conf" + file := ncutils.GetNetclientPathSpecific() + wgInterface + ".conf" wireguard, err := ini.ShadowLoad(file) if err != nil { return err } for i, peer := range peers { - wireguard.SectionWithIndex("Peer", i).Key("PublicKey").SetValue(peer.PublicKey.String()) + wireguard.SectionWithIndex(section_peers, i).Key("PublicKey").SetValue(peer.PublicKey.String()) if peer.PresharedKey.String() != "" { - wireguard.SectionWithIndex("Peer", i).Key("PreSharedKey").SetValue(peer.PresharedKey.String()) + wireguard.SectionWithIndex(section_peers, i).Key("PreSharedKey").SetValue(peer.PresharedKey.String()) } if peer.AllowedIPs != nil { var allowedIPs string for _, ip := range peer.AllowedIPs { allowedIPs = allowedIPs + ", " + ip.String() } - wireguard.SectionWithIndex("Peer", i).Key("AllowedIps").SetValue(allowedIPs) + wireguard.SectionWithIndex(section_peers, i).Key("AllowedIps").SetValue(allowedIPs) } if peer.Endpoint != nil { - wireguard.SectionWithIndex("Peer", i).Key("Endpoint").SetValue(peer.Endpoint.String()) + wireguard.SectionWithIndex(section_peers, i).Key("Endpoint").SetValue(peer.Endpoint.String()) } } if err := wireguard.SaveTo(file); err != nil { @@ -371,27 +376,27 @@ func UpdateWgPeers(wgInterface string, peers []wgtypes.Peer) error { // UpdateWgInterface - updates the interface section of a wireguard config file func UpdateWgInterface(wgInterface, privateKey, nameserver string, node models.Node) error { //update to get path properly - file := "/etc/netclient/config/" + wgInterface + ".conf" + file := ncutils.GetNetclientPathSpecific() + wgInterface + ".conf" wireguard, err := ini.ShadowLoad(file) if err != nil { return err } - wireguard.Section("Interface").Key("PrivateKey").SetValue(privateKey) - wireguard.Section("Interface").Key("ListenPort").SetValue(strconv.Itoa(int(node.ListenPort))) + wireguard.Section(section_interface).Key("PrivateKey").SetValue(privateKey) + wireguard.Section(section_interface).Key("ListenPort").SetValue(strconv.Itoa(int(node.ListenPort))) if node.Address != "" { - wireguard.Section("Interface").Key("Address").SetValue(node.Address) + wireguard.Section(section_interface).Key("Address").SetValue(node.Address) } if node.Address6 != "" { - wireguard.Section("Interface").Key("Address").SetValue(node.Address6) + wireguard.Section(section_interface).Key("Address").SetValue(node.Address6) } if node.DNSOn == "yes" { - wireguard.Section("Interface").Key("DNS").SetValue(nameserver) + wireguard.Section(section_interface).Key("DNS").SetValue(nameserver) } if node.PostUp != "" { - wireguard.Section("Interface").Key("PostUp").SetValue(node.PostUp) + wireguard.Section(section_interface).Key("PostUp").SetValue(node.PostUp) } if node.PostDown != "" { - wireguard.Section("Interface").Key("PostDown").SetValue(node.PostDown) + wireguard.Section(section_interface).Key("PostDown").SetValue(node.PostDown) } if err := wireguard.SaveTo(file); err != nil { return err @@ -402,12 +407,12 @@ func UpdateWgInterface(wgInterface, privateKey, nameserver string, node models.N // UpdatePrivateKey - updates the private key of a wireguard config file func UpdatePrivateKey(wgInterface, privateKey string) error { //update to get path properly - file := "/etc/netclient/config/" + wgInterface + ".conf" + file := ncutils.GetNetclientPathSpecific() + wgInterface + ".conf" wireguard, err := ini.ShadowLoad(file) if err != nil { return err } - wireguard.Section("Interface").Key("PrivateKey").SetValue(privateKey) + wireguard.Section(section_interface).Key("PrivateKey").SetValue(privateKey) if err := wireguard.SaveTo(file); err != nil { return err } From 2531af49f24c36ccae090efce7fd55361221b35f Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Wed, 5 Jan 2022 11:07:09 -0500 Subject: [PATCH 15/18] add error handling on failed key generation --- netclient/functions/daemon.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go index fc926bda..8baaa392 100644 --- a/netclient/functions/daemon.go +++ b/netclient/functions/daemon.go @@ -97,6 +97,10 @@ var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) cfg.ReadConfig() nameserver := cfg.Server.CoreDNSAddr privateKey, err := wireguard.RetrievePrivKey(data.Network) + if err != nil { + ncutils.Log("error generating PrivateKey " + err.Error()) + return + } if err := wireguard.UpdateWgInterface(cfg.Node.Interface, privateKey, nameserver, data); err != nil { ncutils.Log("error updating wireguard config " + err.Error()) return From f8a01dfac006f44c5fd6a84bc9177d16cebd51a7 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Mon, 10 Jan 2022 14:35:53 -0500 Subject: [PATCH 16/18] refactor NodeUpdate message queue handler --- netclient/functions/daemon.go | 89 +++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go index 8baaa392..639436ae 100644 --- a/netclient/functions/daemon.go +++ b/netclient/functions/daemon.go @@ -6,6 +6,7 @@ import ( "log" "os" "os/signal" + "runtime" "strings" "syscall" "time" @@ -67,7 +68,8 @@ func Netclient(ctx context.Context, network string) { } client.AddRoute("update/"+cfg.Node.ID, NodeUpdate) client.AddRoute("update/peers/"+cfg.Node.ID, UpdatePeers) - client.AddRoute("update/keys/"+cfg.Node.ID, UpdateKeys) + //handle key updates in node update + //client.AddRoute("update/keys/"+cfg.Node.ID, UpdateKeys) defer client.Disconnect(250) go Checkin(ctx, cfg, network) go Metrics(ctx, cfg, network) @@ -86,19 +88,44 @@ var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) ncutils.Log("received message to update node " + string(msg.Payload())) //potentiall blocking i/o so do this in a go routine go func() { - var data models.Node - err := json.Unmarshal(msg.Payload(), &data) + var newNode models.Node + var cfg config.ClientConfig + cfg.Network = newNode.Network + cfg.ReadConfig() + err := json.Unmarshal(msg.Payload(), &newNode) if err != nil { ncutils.Log("error unmarshalling node update data" + err.Error()) return } - var cfg config.ClientConfig - cfg.Network = data.Network - cfg.ReadConfig() + //check if interface name has changed if so delete. + if cfg.Node.Interface != newNode.Interface { + if err = wireguard.RemoveConf(cfg.Node.Interface, true); err != nil { + ncutils.PrintLog("could not delete old interface "+cfg.Node.Interface+": ", err.Error(), 1) + } + } + newNode.PullChanges = "no" + //ensure that OS never changes + newNode.OS = runtime.GOOS + cfg.Node = newNode + switch newNode.Action { + case models.NODE_DELETE: + if err := RemoveLocalInstance(cfg, cfg.Network); err != nil { + ncutils.Printlog("error deleting local instance: "+err.Error(), 1) + return + } + case models.NODE_UPDATE_KEY: + UpdateKeys(cfg) + case models.NODE_NOOP: + default: + } + //Save new config + if err := config.Write(&cfg, cfg.Network); err != nil { + ncutils.PrintLog("error updating node configuration: "+err.Error(), 1) + } nameserver := cfg.Server.CoreDNSAddr privateKey, err := wireguard.RetrievePrivKey(data.Network) if err != nil { - ncutils.Log("error generating PrivateKey " + err.Error()) + ncutils.Log("error reading PrivateKey " + err.Error()) return } if err := wireguard.UpdateWgInterface(cfg.Node.Interface, privateKey, nameserver, data); err != nil { @@ -108,7 +135,7 @@ var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) // path hardcoded for now... should be updated err = wireguard.ApplyWGQuickConf("/etc/netclient/config/" + cfg.Node.Interface + ".conf") if err != nil { - ncutils.Log("error restarting wg after peer update " + err.Error()) + ncutils.Log("error restarting wg after node update " + err.Error()) return } }() @@ -117,7 +144,6 @@ var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) // UpdatePeers -- mqtt message handler for /update/peers/ topic var UpdatePeers mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { ncutils.Log("received message to update peers " + string(msg.Payload())) - //potentiall blocking i/o so do this in a go routine go func() { var peerUpdate models.PeerUpdate err := json.Unmarshal(msg.Payload(), &peerUpdate) @@ -142,34 +168,27 @@ var UpdatePeers mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) }() } -// UpdateKeys -- mqtt message handler for /update/keys/ topic -var UpdateKeys mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { - ncutils.Log("received message to update keys " + string(msg.Payload())) +// UpdateKeys -- updates private key and returns new publickey +func UpdateKeys(cfg *config.ClientConfig, client mqtt.Client) (*config.ClientConfig, error) { + ncutils.Log("received message to update keys") //potentiall blocking i/o so do this in a go routine - go func() { - var data models.KeyUpdate - if err := json.Unmarshal(msg.Payload(), &data); err != nil { - ncutils.Log("error unmarshalling key update data" + err.Error()) - return - } - var cfg config.ClientConfig - cfg.Network = data.Network - cfg.ReadConfig() - key, err := wgtypes.GeneratePrivateKey() - if err != nil { - ncutils.Log("error generating privatekey " + err.Error()) - return - } - if err := wireguard.UpdatePrivateKey(data.Interface, key.String()); err != nil { - ncutils.Log("error updating wireguard key " + err.Error()) - return - } - publicKey := key.PublicKey() - if token := client.Publish("update/publickey/"+cfg.Node.ID, 0, false, publicKey.String()); token.Wait() && token.Error() != nil { - ncutils.Log("error publishing publickey update " + token.Error().Error()) - } + key, err := wgtypes.GeneratePrivateKey() + if err != nil { + ncutils.Log("error generating privatekey " + err.Error()) + return cfg, err + } + if err := wireguard.UpdatePrivateKey(data.Interface, key.String()); err != nil { + ncutils.Log("error updating wireguard key " + err.Error()) + return cfg, err + } + publicKey := key.PublicKey() + if token := client.Publish("update/publickey/"+cfg.Node.ID, 0, false, publicKey.String()); token.Wait() && token.Error() != nil { + ncutils.Log("error publishing publickey update " + token.Error().Error()) client.Disconnect(250) - }() + return cfg, err + } + client.Disconnect(250) + return cfg, nil } // Checkin -- go routine that checks for public or local ip changes, publishes changes From 206c542c7066b54cc8371a8ca3d9ff7830839289 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Wed, 12 Jan 2022 16:23:34 -0500 Subject: [PATCH 17/18] WIP commit --- .gitignore | 1 + config/config.go | 2 + go.mod | 7 +- go.sum | 8 -- main.go | 57 +++++++++- models/mqtt.go | 5 +- mq/mq.go | 197 ++++++++++++++++++++++++++++++++++ netclient/functions/daemon.go | 14 +-- servercfg/serverconf.go | 27 +++++ 9 files changed, 293 insertions(+), 25 deletions(-) create mode 100644 mq/mq.go diff --git a/.gitignore b/.gitignore index 16721cb9..bf873a65 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ netclient/netclient.exe config/dnsconfig/ data/ .idea/ +.vscode/ diff --git a/config/config.go b/config/config.go index fc1bcbf2..649ef1b9 100644 --- a/config/config.go +++ b/config/config.go @@ -43,12 +43,14 @@ type ServerConfig struct { GRPCHost string `yaml:"grpchost"` GRPCPort string `yaml:"grpcport"` GRPCSecure string `yaml:"grpcsecure"` + MQHOST string `yaml:"mqhost"` MasterKey string `yaml:"masterkey"` DNSKey string `yaml:"dnskey"` AllowedOrigin string `yaml:"allowedorigin"` NodeID string `yaml:"nodeid"` RestBackend string `yaml:"restbackend"` AgentBackend string `yaml:"agentbackend"` + MessageQueueBackend string `yaml:"messagequeuebackend"` ClientMode string `yaml:"clientmode"` DNSMode string `yaml:"dnsmode"` SplitDNS string `yaml:"splitdns"` diff --git a/go.mod b/go.mod index e4df37a3..e4cead57 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/gravitl/netmaker go 1.17 require ( + github.com/eclipse/paho.mqtt.golang v1.3.5 github.com/go-playground/validator/v10 v10.10.0 github.com/golang-jwt/jwt/v4 v4.2.0 github.com/golang/protobuf v1.5.2 // indirect @@ -25,6 +26,7 @@ require ( google.golang.org/genproto v0.0.0-20210201151548-94839c025ad4 // indirect google.golang.org/grpc v1.43.0 google.golang.org/protobuf v1.27.1 + gopkg.in/ini.v1 v1.66.2 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) @@ -32,13 +34,10 @@ require ( cloud.google.com/go v0.34.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/eclipse/paho.mqtt.golang v1.3.5 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect - github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect github.com/google/go-cmp v0.5.5 // indirect - github.com/google/uuid v1.2.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect github.com/leodido/go-urn v1.2.1 // indirect @@ -47,7 +46,5 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.0.1 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect google.golang.org/appengine v1.4.0 // indirect - gopkg.in/ini.v1 v1.66.2 // indirect ) diff --git a/go.sum b/go.sum index 5ffce809..995a9322 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,6 @@ github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8S github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534 h1:dhy9OQKGBh4zVXbjwbxxHjRxMJtLXj3zfgpBYQaR4Q4= -github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= @@ -74,8 +72,6 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= @@ -194,7 +190,6 @@ golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -205,8 +200,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -228,7 +221,6 @@ golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/main.go b/main.go index fd9aad97..52243051 100644 --- a/main.go +++ b/main.go @@ -11,6 +11,7 @@ import ( "sync" "time" + mqtt "github.com/eclipse/paho.mqtt.golang" "github.com/gravitl/netmaker/auth" controller "github.com/gravitl/netmaker/controllers" "github.com/gravitl/netmaker/database" @@ -19,6 +20,7 @@ import ( "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/models" + "github.com/gravitl/netmaker/mq" "github.com/gravitl/netmaker/netclient/ncutils" "github.com/gravitl/netmaker/servercfg" "github.com/gravitl/netmaker/serverctl" @@ -106,8 +108,14 @@ func startControllers() { go controller.HandleRESTRequests(&waitnetwork) } - if !servercfg.IsAgentBackend() && !servercfg.IsRestBackend() { - logger.Log(0, "No Server Mode selected, so nothing is being served! Set either Agent mode (AGENT_BACKEND) or Rest mode (REST_BACKEND) to 'true'.") + //Run MessageQueue + if servercfg.IsMessageQueueBackend() { + waitnetwork.Add(1) + go runMessageQueue(&waitnetwork) + } + + if !servercfg.IsAgentBackend() && !servercfg.IsRestBackend() && !servercfg.IsMessageQueueBackend() { + logger.Log(0, "No Server Mode selected, so nothing is being served! Set Agent mode (AGENT_BACKEND) or Rest mode (REST_BACKEND) or MessageQueue (MESSAGEQUEUE_BACKEND) to 'true'.") } if servercfg.IsClientMode() == "on" { @@ -175,6 +183,51 @@ func runGRPC(wg *sync.WaitGroup) { logger.Log(0, "Closed DB connection.") } +// Should we be using a context vice a waitgroup???????????? +func runMessageQueue(wg *sync.WaitGroup) { + defer wg.Done() + //refactor netclient.functions.SetupMQTT so can be called from here + //setupMQTT + opts := mqtt.NewClientOptions() + opts.AddBroker(servercfg.GetMessageQueueEndpoint()) + logger.Log(0, "setting broker "+servercfg.GetMessageQueueEndpoint()) + opts.SetDefaultPublishHandler(mq.DefaultHandler) + client := mqtt.NewClient(opts) + if token := client.Connect(); token.Wait() && token.Error() != nil { + logger.Log(0, "unable to connect to message queue broker, closing down") + return + } + //Set up Subscriptions + if token := client.Subscribe("#", 0, nil); token.Wait() && token.Error() != nil { + //should make constant for disconnect wait period + client.Disconnect(250) + logger.Log(0, "could not subscribe to message queue ...") + return + } + if token := client.Subscribe("ping/#", 0, mq.Ping); token.Wait() && token.Error() != nil { + client.Disconnect(240) + logger.Log(0, "ping sub failed") + } + if token := client.Subscribe("metrics/#", 0, mq.Metrics); token.Wait() && token.Error() != nil { + client.Disconnect(240) + logger.Log(0, "metrics sub failed") + } + if token := client.Subscribe("update/localaddress/#", 0, mq.LocalAddressUpdate); token.Wait() && token.Error() != nil { + client.Disconnect(240) + logger.Log(0, "metrics sub failed") + } + if token := client.Subscribe("update/ip/#", 0, mq.IPUpdate); token.Wait() && token.Error() != nil { + client.Disconnect(240) + logger.Log(0, "metrics sub failed") + } + if token := client.Subscribe("update/publickey/#", 0, mq.PublicKeyUpdate); token.Wait() && token.Error() != nil { + client.Disconnect(240) + logger.Log(0, "metrics sub failed") + } + for { + } +} + func authServerUnaryInterceptor() grpc.ServerOption { return grpc.UnaryInterceptor(controller.AuthServerUnaryInterceptor) } diff --git a/models/mqtt.go b/models/mqtt.go index a7e87e1f..da7265f3 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -3,9 +3,8 @@ package models import "golang.zx2c4.com/wireguard/wgctrl/wgtypes" type PeerUpdate struct { - Network string - Interface string - Peers []wgtypes.Peer + Network string + Peers []wgtypes.Peer } type KeyUpdate struct { diff --git a/mq/mq.go b/mq/mq.go new file mode 100644 index 00000000..3620b215 --- /dev/null +++ b/mq/mq.go @@ -0,0 +1,197 @@ +package mq + +import ( + "encoding/json" + "errors" + "log" + "net" + "strings" + "time" + + mqtt "github.com/eclipse/paho.mqtt.golang" + "github.com/gravitl/netmaker/database" + "github.com/gravitl/netmaker/logger" + "github.com/gravitl/netmaker/logic" + "github.com/gravitl/netmaker/models" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +var DefaultHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { + logger.Log(0, "MQTT Message: Topic: "+string(msg.Topic())+" Message: "+string(msg.Payload())) +} + +var Metrics mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { + logger.Log(0, "Metrics Handler") +} + +var Ping mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { + logger.Log(0, "Ping Handler") + //test code --- create a node if it doesn't exit for testing only + createnode := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", + Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet"} + if _, err := logic.GetNode("01:02:03:04:05:06", "skynet"); err != nil { + err := logic.CreateNode(&createnode) + if err != nil { + log.Println(err) + } + } + //end of test code + go func() { + mac, net, err := GetMacNetwork(msg.Topic()) + if err != nil { + logger.Log(0, "error getting node.ID sent on ping topic ") + return + } + logger.Log(0, "ping recieved from "+mac+" on net "+net) + node, err := logic.GetNodeByMacAddress(net, mac) + if err != nil { + logger.Log(0, "mq-ping error getting node: "+err.Error()) + record, err := database.FetchRecord(database.NODES_TABLE_NAME, mac+"###"+net) + if err != nil { + logger.Log(0, "error reading database ", err.Error()) + return + } + logger.Log(0, "record from database") + logger.Log(0, record) + return + } + node.SetLastCheckIn() + // --TODO --set client version once feature is implemented. + //node.SetClientVersion(msg.Payload()) + }() +} + +var PublicKeyUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { + logger.Log(0, "PublicKey Handler") + go func() { + logger.Log(0, "public key update "+msg.Topic()) + key := string(msg.Payload()) + mac, network, err := GetMacNetwork(msg.Topic()) + if err != nil { + logger.Log(0, "error getting node.ID sent on "+msg.Topic()+" "+err.Error()) + } + node, err := logic.GetNode(mac, network) + if err != nil { + logger.Log(0, "error retrieving node "+msg.Topic()+" "+err.Error()) + } + node.PublicKey = key + node.SetLastCheckIn() + UpdatePeers(&node, client) + }() +} + +var IPUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { + go func() { + ip := string(msg.Payload()) + logger.Log(0, "IPUpdate Handler") + mac, network, err := GetMacNetwork(msg.Topic()) + logger.Log(0, "ipUpdate recieved from "+mac+" on net "+network) + if err != nil { + logger.Log(0, "error getting node.ID sent on update/ip topic ") + return + } + node, err := logic.GetNode(mac, network) + if err != nil { + logger.Log(0, "invalid ID recieved on update/ip topic: "+err.Error()) + return + } + node.Endpoint = ip + node.SetLastCheckIn() + UpdatePeers(&node, client) + }() +} + +func UpdatePeers(node *models.Node, client mqtt.Client) { + peersToUpdate, err := logic.GetPeers(node) + if err != nil { + logger.Log(0, "error retrieving peers") + return + } + for _, peerToUpdate := range peersToUpdate { + var peerUpdate models.PeerUpdate + peerUpdate.Network = node.Network + + myPeers, err := logic.GetPeers(&peerToUpdate) + if err != nil { + logger.Log(0, "uable to get peers "+err.Error()) + continue + } + for i, myPeer := range myPeers { + var allowedIPs []net.IPNet + var allowedIP net.IPNet + endpoint, err := net.ResolveUDPAddr("udp", myPeer.Address+":"+string(myPeer.ListenPort)) + if err != nil { + logger.Log(0, "error setting endpoint for peer "+err.Error()) + } + for _, ipString := range myPeer.AllowedIPs { + _, ipNet, _ := net.ParseCIDR(ipString) + allowedIP = *ipNet + allowedIPs = append(allowedIPs, allowedIP) + } + key, err := wgtypes.ParseKey(myPeer.PublicKey) + if err != nil { + logger.Log(0, "err parsing publickey") + continue + } + peerUpdate.Peers[i].PublicKey = key + peerUpdate.Peers[i].Endpoint = endpoint + peerUpdate.Peers[i].PersistentKeepaliveInterval = time.Duration(myPeer.PersistentKeepalive) + peerUpdate.Peers[i].AllowedIPs = allowedIPs + peerUpdate.Peers[i].ProtocolVersion = 0 + } + //PublishPeerUpdate(my) + data, err := json.Marshal(peerUpdate) + if err != nil { + logger.Log(0, "err marshalling data for peer update "+err.Error()) + } + if token := client.Publish("update/peers/"+peerToUpdate.ID, 0, false, data); token.Wait() && token.Error() != nil { + logger.Log(0, "error publishing peer update "+token.Error().Error()) + } + client.Disconnect(250) + } +} + +var LocalAddressUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { + logger.Log(0, "LocalAddressUpdate Handler") + go func() { + logger.Log(0, "LocalAddressUpdate handler") + mac, net, err := GetMacNetwork(msg.Topic()) + if err != nil { + logger.Log(0, "error getting node.ID "+msg.Topic()) + return + } + node, err := logic.GetNode(mac, net) + if err != nil { + logger.Log(0, "error get node "+msg.Topic()) + return + } + node.LocalAddress = string(msg.Payload()) + node.SetLastCheckIn() + }() +} + +func GetMacNetwork(topic string) (string, string, error) { + parts := strings.Split(topic, "/") + count := len(parts) + if count == 1 { + return "", "", errors.New("invalid topic") + } + macnet := strings.Split(parts[count-1], "---") + if len(macnet) != 2 { + return "", "", errors.New("topic id not in mac---network format") + } + return macnet[0], macnet[1], nil +} + +func GetID(topic string) (string, error) { + parts := strings.Split(topic, "/") + count := len(parts) + if count == 1 { + return "", errors.New("invalid topic") + } + macnet := strings.Split(parts[count-1], "---") + if len(macnet) != 2 { + return "", errors.New("topic id not in mac---network format") + } + return macnet[0] + "###" + macnet[1], nil +} diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go index 639436ae..a5360319 100644 --- a/netclient/functions/daemon.go +++ b/netclient/functions/daemon.go @@ -100,7 +100,7 @@ var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) //check if interface name has changed if so delete. if cfg.Node.Interface != newNode.Interface { if err = wireguard.RemoveConf(cfg.Node.Interface, true); err != nil { - ncutils.PrintLog("could not delete old interface "+cfg.Node.Interface+": ", err.Error(), 1) + ncutils.PrintLog("could not delete old interface "+cfg.Node.Interface+": "+err.Error(), 1) } } newNode.PullChanges = "no" @@ -109,12 +109,12 @@ var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) cfg.Node = newNode switch newNode.Action { case models.NODE_DELETE: - if err := RemoveLocalInstance(cfg, cfg.Network); err != nil { - ncutils.Printlog("error deleting local instance: "+err.Error(), 1) + if err := RemoveLocalInstance(&cfg, cfg.Network); err != nil { + ncutils.PrintLog("error deleting local instance: "+err.Error(), 1) return } case models.NODE_UPDATE_KEY: - UpdateKeys(cfg) + UpdateKeys(&cfg, client) case models.NODE_NOOP: default: } @@ -123,12 +123,12 @@ var NodeUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) ncutils.PrintLog("error updating node configuration: "+err.Error(), 1) } nameserver := cfg.Server.CoreDNSAddr - privateKey, err := wireguard.RetrievePrivKey(data.Network) + privateKey, err := wireguard.RetrievePrivKey(newNode.Network) if err != nil { ncutils.Log("error reading PrivateKey " + err.Error()) return } - if err := wireguard.UpdateWgInterface(cfg.Node.Interface, privateKey, nameserver, data); err != nil { + if err := wireguard.UpdateWgInterface(cfg.Node.Interface, privateKey, nameserver, newNode); err != nil { ncutils.Log("error updating wireguard config " + err.Error()) return } @@ -177,7 +177,7 @@ func UpdateKeys(cfg *config.ClientConfig, client mqtt.Client) (*config.ClientCon ncutils.Log("error generating privatekey " + err.Error()) return cfg, err } - if err := wireguard.UpdatePrivateKey(data.Interface, key.String()); err != nil { + if err := wireguard.UpdatePrivateKey(cfg.Node.Interface, key.String()); err != nil { ncutils.Log("error updating wireguard key " + err.Error()) return cfg, err } diff --git a/servercfg/serverconf.go b/servercfg/serverconf.go index d15af77a..885ca45f 100644 --- a/servercfg/serverconf.go +++ b/servercfg/serverconf.go @@ -244,6 +244,18 @@ func GetGRPCPort() string { return grpcport } +// GetMessageQueueEndpoint - gets the message queue endpoint +func GetMessageQueueEndpoint() string { + host, _ := GetPublicIP() + if os.Getenv("MQ_HOST") != "" { + host = os.Getenv("MQ_HOST") + } else if config.Config.Server.MQHOST != "" { + host = config.Config.Server.MQHOST + } + //Do we want MQ port configurable??? + return host + ":1883" +} + // GetMasterKey - gets the configured master key of server func GetMasterKey() string { key := "secretkey" @@ -307,6 +319,21 @@ func IsAgentBackend() bool { return isagent } +// IsMessageQueueBackend - checks if message queue is on or off +func IsMessageQueueBackend() bool { + ismessagequeue := true + if os.Getenv("MESSAGEQUEUE_BACKEND") != "" { + if os.Getenv("MESSAGEQUEUE_BACKEND") == "off" { + ismessagequeue = false + } + } else if config.Config.Server.MessageQueueBackend != "" { + if config.Config.Server.MessageQueueBackend == "off" { + ismessagequeue = false + } + } + return ismessagequeue +} + // IsClientMode - checks if it should run in client mode func IsClientMode() string { isclient := "on" From 815cfb9ec9156582e2735321986c66deffdb36d2 Mon Sep 17 00:00:00 2001 From: Matthew R Kasun Date: Fri, 14 Jan 2022 14:30:26 -0500 Subject: [PATCH 18/18] WIP commit to enable rebasing to uuid feature --- main.go | 30 +++--- models/mqtt.go | 7 +- mq/mq.go | 120 ++++++++++++------------ netclient/functions/daemon.go | 35 ++++++- netclient/functions/peers.go | 167 ++++++++++++++++++++++++++++++++++ 5 files changed, 276 insertions(+), 83 deletions(-) create mode 100644 netclient/functions/peers.go diff --git a/main.go b/main.go index 52243051..3d527a0b 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,7 @@ import ( "runtime/debug" "strconv" "sync" - "time" + "syscall" mqtt "github.com/eclipse/paho.mqtt.golang" "github.com/gravitl/netmaker/auth" @@ -118,16 +118,16 @@ func startControllers() { logger.Log(0, "No Server Mode selected, so nothing is being served! Set Agent mode (AGENT_BACKEND) or Rest mode (REST_BACKEND) or MessageQueue (MESSAGEQUEUE_BACKEND) to 'true'.") } - if servercfg.IsClientMode() == "on" { - var checkintime = time.Duration(servercfg.GetServerCheckinInterval()) * time.Second - for { // best effort currently - var serverGroup sync.WaitGroup - serverGroup.Add(1) - go runClient(&serverGroup) - serverGroup.Wait() - time.Sleep(checkintime) - } - } + //if servercfg.IsClientMode() == "on" { + // var checkintime = time.Duration(servercfg.GetServerCheckinInterval()) * time.Second + // for { // best effort currently + // var serverGroup sync.WaitGroup + // serverGroup.Add(1) + // go runClient(&serverGroup) + // serverGroup.Wait() + // time.Sleep(checkintime) + // } + //} waitnetwork.Wait() } @@ -204,7 +204,7 @@ func runMessageQueue(wg *sync.WaitGroup) { logger.Log(0, "could not subscribe to message queue ...") return } - if token := client.Subscribe("ping/#", 0, mq.Ping); token.Wait() && token.Error() != nil { + if token := client.Subscribe("ping/#", 2, mq.Ping); token.Wait() && token.Error() != nil { client.Disconnect(240) logger.Log(0, "ping sub failed") } @@ -224,8 +224,10 @@ func runMessageQueue(wg *sync.WaitGroup) { client.Disconnect(240) logger.Log(0, "metrics sub failed") } - for { - } + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGTERM, os.Interrupt) + <-quit + logger.Log(0, "Message Queue shutting down") } func authServerUnaryInterceptor() grpc.ServerOption { diff --git a/models/mqtt.go b/models/mqtt.go index da7265f3..07bb2157 100644 --- a/models/mqtt.go +++ b/models/mqtt.go @@ -1,10 +1,9 @@ package models -import "golang.zx2c4.com/wireguard/wgctrl/wgtypes" - type PeerUpdate struct { - Network string - Peers []wgtypes.Peer + Network string + Nodes []Node + ExtPeers []ExtPeersResponse } type KeyUpdate struct { diff --git a/mq/mq.go b/mq/mq.go index 3620b215..fd9657a7 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -1,19 +1,15 @@ package mq import ( - "encoding/json" "errors" - "log" - "net" + "fmt" "strings" - "time" mqtt "github.com/eclipse/paho.mqtt.golang" "github.com/gravitl/netmaker/database" "github.com/gravitl/netmaker/logger" "github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/models" - "golang.zx2c4.com/wireguard/wgctrl/wgtypes" ) var DefaultHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { @@ -22,20 +18,11 @@ var DefaultHandler mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Messa var Metrics mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { logger.Log(0, "Metrics Handler") + //TODOD -- handle metrics data ---- store to database? } var Ping mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { - logger.Log(0, "Ping Handler") - //test code --- create a node if it doesn't exit for testing only - createnode := models.Node{PublicKey: "DM5qhLAE20PG9BbfBCger+Ac9D2NDOwCtY1rbYDLf34=", Name: "testnode", - Endpoint: "10.0.0.1", MacAddress: "01:02:03:04:05:06", Password: "password", Network: "skynet"} - if _, err := logic.GetNode("01:02:03:04:05:06", "skynet"); err != nil { - err := logic.CreateNode(&createnode) - if err != nil { - log.Println(err) - } - } - //end of test code + logger.Log(0, "Ping Handler: "+msg.Topic()) go func() { mac, net, err := GetMacNetwork(msg.Topic()) if err != nil { @@ -56,6 +43,7 @@ var Ping mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { return } node.SetLastCheckIn() + logger.Log(0, "ping processed") // --TODO --set client version once feature is implemented. //node.SetClientVersion(msg.Payload()) }() @@ -76,7 +64,9 @@ var PublicKeyUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Mess } node.PublicKey = key node.SetLastCheckIn() - UpdatePeers(&node, client) + if err := UpdatePeers(client, node); err != nil { + logger.Log(0, "error updating peers "+err.Error()) + } }() } @@ -97,58 +87,63 @@ var IPUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { } node.Endpoint = ip node.SetLastCheckIn() - UpdatePeers(&node, client) + if err := UpdatePeers(client, node); err != nil { + logger.Log(0, "error updating peers "+err.Error()) + } }() } -func UpdatePeers(node *models.Node, client mqtt.Client) { - peersToUpdate, err := logic.GetPeers(node) - if err != nil { - logger.Log(0, "error retrieving peers") - return - } - for _, peerToUpdate := range peersToUpdate { - var peerUpdate models.PeerUpdate - peerUpdate.Network = node.Network +func UpdatePeers(client mqtt.Client, node models.Node) error { + var peerUpdate models.PeerUpdate + peerUpdate.Network = node.Network - myPeers, err := logic.GetPeers(&peerToUpdate) - if err != nil { - logger.Log(0, "uable to get peers "+err.Error()) + nodes, err := logic.GetNetworkNodes(node.Network) + if err != nil { + return fmt.Errorf("unable to get network nodes %v: ", err) + } + if token := client.Connect(); token.Wait() && token.Error() != nil { + return token.Error() + } + for _, peer := range nodes { + //don't need to update the initiatiing client + if peer.ID == node.ID { continue } - for i, myPeer := range myPeers { - var allowedIPs []net.IPNet - var allowedIP net.IPNet - endpoint, err := net.ResolveUDPAddr("udp", myPeer.Address+":"+string(myPeer.ListenPort)) - if err != nil { - logger.Log(0, "error setting endpoint for peer "+err.Error()) - } - for _, ipString := range myPeer.AllowedIPs { - _, ipNet, _ := net.ParseCIDR(ipString) - allowedIP = *ipNet - allowedIPs = append(allowedIPs, allowedIP) - } - key, err := wgtypes.ParseKey(myPeer.PublicKey) - if err != nil { - logger.Log(0, "err parsing publickey") - continue - } - peerUpdate.Peers[i].PublicKey = key - peerUpdate.Peers[i].Endpoint = endpoint - peerUpdate.Peers[i].PersistentKeepaliveInterval = time.Duration(myPeer.PersistentKeepalive) - peerUpdate.Peers[i].AllowedIPs = allowedIPs - peerUpdate.Peers[i].ProtocolVersion = 0 - } - //PublishPeerUpdate(my) - data, err := json.Marshal(peerUpdate) + peerUpdate.Nodes = append(peerUpdate.Nodes, peer) + peerUpdate.ExtPeers, err = logic.GetExtPeersList(node.MacAddress, node.Network) if err != nil { - logger.Log(0, "err marshalling data for peer update "+err.Error()) + logger.Log(0) } - if token := client.Publish("update/peers/"+peerToUpdate.ID, 0, false, data); token.Wait() && token.Error() != nil { - logger.Log(0, "error publishing peer update "+token.Error().Error()) + if token := client.Publish("update/peers/"+peer.ID, 0, false, nodes); token.Wait() && token.Error() != nil { + logger.Log(0, "error publishing peer update "+peer.ID+" "+token.Error().Error()) } - client.Disconnect(250) } + + return nil +} + +func UpdateLocalPeers(client mqtt.Client, node models.Node) error { + nodes, err := logic.GetNetworkNodes(node.Network) + if err != nil { + return fmt.Errorf("unable to get network nodes %v: ", err) + } + if token := client.Connect(); token.Wait() && token.Error() != nil { + return token.Error() + } + for _, peer := range nodes { + //don't need to update the initiatiing client + if peer.ID == node.ID { + continue + } + //if peer.Endpoint is on same lan as node.LocalAddress + //if TODO{ + //continue + //} + if token := client.Publish("update/peers/"+peer.ID, 0, false, nodes); token.Wait() && token.Error() != nil { + logger.Log(0, "error publishing peer update "+peer.ID+" "+token.Error().Error()) + } + } + return nil } var LocalAddressUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) { @@ -167,6 +162,9 @@ var LocalAddressUpdate mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.M } node.LocalAddress = string(msg.Payload()) node.SetLastCheckIn() + if err := UpdateLocalPeers(client, node); err != nil { + logger.Log(0, "error updating peers "+err.Error()) + } }() } @@ -176,7 +174,7 @@ func GetMacNetwork(topic string) (string, string, error) { if count == 1 { return "", "", errors.New("invalid topic") } - macnet := strings.Split(parts[count-1], "---") + macnet := strings.Split(parts[count-1], "-") if len(macnet) != 2 { return "", "", errors.New("topic id not in mac---network format") } @@ -189,7 +187,7 @@ func GetID(topic string) (string, error) { if count == 1 { return "", errors.New("invalid topic") } - macnet := strings.Split(parts[count-1], "---") + macnet := strings.Split(parts[count-1], "-") if len(macnet) != 2 { return "", errors.New("topic id not in mac---network format") } diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go index a5360319..6e212c77 100644 --- a/netclient/functions/daemon.go +++ b/netclient/functions/daemon.go @@ -154,9 +154,19 @@ var UpdatePeers mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) var cfg config.ClientConfig cfg.Network = peerUpdate.Network cfg.ReadConfig() - err = wireguard.UpdateWgPeers(cfg.Node.Interface, peerUpdate.Peers) + peers, err := CalculatePeers(cfg.Node, peerUpdate.Nodes, cfg.Node.IsDualStack, cfg.Node.IsEgressGateway, cfg.Node.IsServer) if err != nil { - ncutils.Log("error updating peers" + err.Error()) + ncutils.Log("error calculating Peers " + err.Error()) + return + } + extpeers, err := CalculateExtPeers(cfg.Node, peerUpdate.ExtPeers) + if err != nil { + ncutils.Log("error updated external wireguard peers " + err.Error()) + } + peers = append(peers, extpeers...) + err = wireguard.UpdateWgPeers(cfg.Node.Interface, peers) + if err != nil { + ncutils.Log("error updating wireguard peers" + err.Error()) return } // path hardcoded for now... should be updated @@ -187,7 +197,9 @@ func UpdateKeys(cfg *config.ClientConfig, client mqtt.Client) (*config.ClientCon client.Disconnect(250) return cfg, err } - client.Disconnect(250) + if err := config.ModConfig(&cfg.Node); err != nil { + ncutils.Log("error updating local config " + err.Error()) + } return cfg, nil } @@ -202,6 +214,11 @@ func Checkin(ctx context.Context, cfg config.ClientConfig, network string) { //delay should be configuraable -> use cfg.Node.NetworkSettings.DefaultCheckInInterval ?? case <-time.After(time.Second * 10): ncutils.Log("Checkin running") + //read latest config + cfg.ReadConfig() + //fix NodeID to remove ### so NodeID can be used as message topic + //remove with GRA-73 + cfg.Node.ID = strings.Replace(cfg.Node.ID, "###", "-", 1) if cfg.Node.Roaming == "yes" && cfg.Node.IsStatic != "yes" { extIP, err := ncutils.GetPublicIP() if err != nil { @@ -242,6 +259,10 @@ func UpdateEndpoint(cfg config.ClientConfig, network, ip string) { if token := client.Publish("update/ip/"+cfg.Node.ID, 0, false, ip); token.Wait() && token.Error() != nil { ncutils.Log("error publishing endpoint update " + token.Error().Error()) } + cfg.Node.Endpoint = ip + if err := config.Write(&cfg, cfg.Network); err != nil { + ncutils.Log("error updating local config " + err.Error()) + } client.Disconnect(250) } @@ -252,13 +273,19 @@ func UpdateLocalAddress(cfg config.ClientConfig, network, ip string) { if token := client.Publish("update/localaddress/"+cfg.Node.ID, 0, false, ip); token.Wait() && token.Error() != nil { ncutils.Log("error publishing local address update " + token.Error().Error()) } + cfg.Node.LocalAddress = ip + ncutils.Log("updating local address in local config to: " + cfg.Node.LocalAddress) + if err := config.Write(&cfg, cfg.Network); err != nil { + ncutils.Log("error updating local config " + err.Error()) + } client.Disconnect(250) } // Hello -- ping the broker to let server know node is alive and doing fine func Hello(cfg config.ClientConfig, network string) { client := SetupMQTT(cfg) - if token := client.Publish("ping/"+cfg.Node.ID, 0, false, "hello world!"); token.Wait() && token.Error() != nil { + ncutils.Log("sending ping " + cfg.Node.ID) + if token := client.Publish("ping/"+cfg.Node.ID, 2, false, "hello world!"); token.Wait() && token.Error() != nil { ncutils.Log("error publishing ping " + token.Error().Error()) } client.Disconnect(250) diff --git a/netclient/functions/peers.go b/netclient/functions/peers.go new file mode 100644 index 00000000..833ebc90 --- /dev/null +++ b/netclient/functions/peers.go @@ -0,0 +1,167 @@ +package functions + +import ( + "log" + "net" + "strconv" + "strings" + "time" + + "github.com/gravitl/netmaker/models" + "github.com/gravitl/netmaker/netclient/ncutils" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +func CalculatePeers(thisNode models.Node, peernodes []models.Node, dualstack, egressgateway, server string) ([]wgtypes.Peer, error) { + //hasGateway := false + var gateways []string + var peers []wgtypes.Peer + + keepalive := thisNode.PersistentKeepalive + keepalivedur, _ := time.ParseDuration(strconv.FormatInt(int64(keepalive), 10) + "s") + keepaliveserver, err := time.ParseDuration(strconv.FormatInt(int64(5), 10) + "s") + if err != nil { + log.Fatalf("Issue with format of keepalive value. Please update netconfig: %v", err) + } + for _, node := range peernodes { + pubkey, err := wgtypes.ParseKey(node.PublicKey) + if err != nil { + log.Println("error parsing key") + //return peers, hasGateway, gateways, err + } + + if thisNode.PublicKey == node.PublicKey { + continue + } + if thisNode.Endpoint == node.Endpoint { + if thisNode.LocalAddress != node.LocalAddress && node.LocalAddress != "" { + node.Endpoint = node.LocalAddress + } else { + continue + } + } + + var peer wgtypes.Peer + var peeraddr = net.IPNet{ + IP: net.ParseIP(node.Address), + Mask: net.CIDRMask(32, 32), + } + var allowedips []net.IPNet + allowedips = append(allowedips, peeraddr) + // handle manually set peers + for _, allowedIp := range node.AllowedIPs { + if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil { + nodeEndpointArr := strings.Split(node.Endpoint, ":") + if !ipnet.Contains(net.IP(nodeEndpointArr[0])) && ipnet.IP.String() != node.Address { // don't need to add an allowed ip that already exists.. + allowedips = append(allowedips, *ipnet) + } + } else if appendip := net.ParseIP(allowedIp); appendip != nil && allowedIp != node.Address { + ipnet := net.IPNet{ + IP: net.ParseIP(allowedIp), + Mask: net.CIDRMask(32, 32), + } + allowedips = append(allowedips, ipnet) + } + } + // handle egress gateway peers + if node.IsEgressGateway == "yes" { + //hasGateway = true + ranges := node.EgressGatewayRanges + for _, iprange := range ranges { // go through each cidr for egress gateway + _, ipnet, err := net.ParseCIDR(iprange) // confirming it's valid cidr + if err != nil { + ncutils.PrintLog("could not parse gateway IP range. Not adding "+iprange, 1) + continue // if can't parse CIDR + } + nodeEndpointArr := strings.Split(node.Endpoint, ":") // getting the public ip of node + if ipnet.Contains(net.ParseIP(nodeEndpointArr[0])) { // ensuring egress gateway range does not contain public ip of node + ncutils.PrintLog("egress IP range of "+iprange+" overlaps with "+node.Endpoint+", omitting", 2) + continue // skip adding egress range if overlaps with node's ip + } + if ipnet.Contains(net.ParseIP(thisNode.LocalAddress)) { // ensuring egress gateway range does not contain public ip of node + ncutils.PrintLog("egress IP range of "+iprange+" overlaps with "+thisNode.LocalAddress+", omitting", 2) + continue // skip adding egress range if overlaps with node's local ip + } + gateways = append(gateways, iprange) + if err != nil { + log.Println("ERROR ENCOUNTERED SETTING GATEWAY") + } else { + allowedips = append(allowedips, *ipnet) + } + } + } + if node.Address6 != "" && dualstack == "yes" { + var addr6 = net.IPNet{ + IP: net.ParseIP(node.Address6), + Mask: net.CIDRMask(128, 128), + } + allowedips = append(allowedips, addr6) + } + if thisNode.IsServer == "yes" && !(node.IsServer == "yes") { + peer = wgtypes.Peer{ + PublicKey: pubkey, + PersistentKeepaliveInterval: keepaliveserver, + AllowedIPs: allowedips, + } + } else if keepalive != 0 { + peer = wgtypes.Peer{ + PublicKey: pubkey, + PersistentKeepaliveInterval: keepalivedur, + Endpoint: &net.UDPAddr{ + IP: net.ParseIP(node.Endpoint), + Port: int(node.ListenPort), + }, + AllowedIPs: allowedips, + } + } else { + peer = wgtypes.Peer{ + PublicKey: pubkey, + Endpoint: &net.UDPAddr{ + IP: net.ParseIP(node.Endpoint), + Port: int(node.ListenPort), + }, + AllowedIPs: allowedips, + } + } + peers = append(peers, peer) + } + return peers, nil +} + +func CalculateExtPeers(thisNode models.Node, extPeers []models.ExtPeersResponse) ([]wgtypes.Peer, error) { + var peers []wgtypes.Peer + var err error + for _, extPeer := range extPeers { + pubkey, err := wgtypes.ParseKey(extPeer.PublicKey) + if err != nil { + log.Println("error parsing key") + return peers, err + } + + if thisNode.PublicKey == extPeer.PublicKey { + continue + } + + var peer wgtypes.Peer + var peeraddr = net.IPNet{ + IP: net.ParseIP(extPeer.Address), + Mask: net.CIDRMask(32, 32), + } + var allowedips []net.IPNet + allowedips = append(allowedips, peeraddr) + + if extPeer.Address6 != "" && thisNode.IsDualStack == "yes" { + var addr6 = net.IPNet{ + IP: net.ParseIP(extPeer.Address6), + Mask: net.CIDRMask(128, 128), + } + allowedips = append(allowedips, addr6) + } + peer = wgtypes.Peer{ + PublicKey: pubkey, + AllowedIPs: allowedips, + } + peers = append(peers, peer) + } + return peers, err +}