From fecc3e02f3c014a2f0aa0f9a20ee91f8a9dd3b56 Mon Sep 17 00:00:00 2001 From: Shawn Carey Date: Tue, 3 Dec 2019 14:42:58 -0500 Subject: [PATCH 1/5] added linux process manager files --- .../etc/systemd/system/ziti-tunnel.env | 3 + .../etc/systemd/system/ziti-tunnel.service | 26 ++++ .../linux/sysvinit/etc/init.d/ziti-tunnel | 113 ++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 ziti-tunnel/deployment/linux/systemd/etc/systemd/system/ziti-tunnel.env create mode 100644 ziti-tunnel/deployment/linux/systemd/etc/systemd/system/ziti-tunnel.service create mode 100644 ziti-tunnel/deployment/linux/sysvinit/etc/init.d/ziti-tunnel diff --git a/ziti-tunnel/deployment/linux/systemd/etc/systemd/system/ziti-tunnel.env b/ziti-tunnel/deployment/linux/systemd/etc/systemd/system/ziti-tunnel.env new file mode 100644 index 000000000..6f09c127b --- /dev/null +++ b/ziti-tunnel/deployment/linux/systemd/etc/systemd/system/ziti-tunnel.env @@ -0,0 +1,3 @@ +IDENTITY_JSON=/opt/netfoundry/etc/ziti-client-identity.json +RESOLVER_OPTS=none +INTERCEPT_MODE=tproxy diff --git a/ziti-tunnel/deployment/linux/systemd/etc/systemd/system/ziti-tunnel.service b/ziti-tunnel/deployment/linux/systemd/etc/systemd/system/ziti-tunnel.service new file mode 100644 index 000000000..127fa47b3 --- /dev/null +++ b/ziti-tunnel/deployment/linux/systemd/etc/systemd/system/ziti-tunnel.service @@ -0,0 +1,26 @@ +# Copyright (c) 2017-2019 NetFoundry, Inc. +# All rights reserved. +# https://netfoundry.io + + +[Unit] +Description=NetFoundry Ziti Tunnel +After=network-online.target + +[Service] +EnvironmentFile=/etc/systemd/system/ziti-tunnel.env +ExecStart=/opt/netfoundry/bin/ziti-tunnel --identity "${IDENTITY_JSON}" --resolver "${RESOLVER_OPTS}" ${INTERCEPT_MODE} +Restart=always +RestartSec=1 + +[Install] +WantedBy=network-online.target + +# capabilities don't work for tproxy, because it shells out to `iptables` which does things +# that require CAP_NET_RAW. Unfortunately (for us), CAP_NET_RAW is not in the inheritable +# capability set of /sbin/iptables. +#CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE +#ProtectSystem=full +#ProtectHome=true +#ProtectKernelTunables=true +#ProtectKernelModules=true \ No newline at end of file diff --git a/ziti-tunnel/deployment/linux/sysvinit/etc/init.d/ziti-tunnel b/ziti-tunnel/deployment/linux/sysvinit/etc/init.d/ziti-tunnel new file mode 100644 index 000000000..40cfd06d5 --- /dev/null +++ b/ziti-tunnel/deployment/linux/sysvinit/etc/init.d/ziti-tunnel @@ -0,0 +1,113 @@ +#!/bin/bash +# +# ziti-tunnel Start up the ziti-tunnel client +# +# +# chkconfig: 345 28 72 +# descripttion: Intercept network traffic for NetFoundry/Ziti services. + +### BEGIN INIT INFO +# Provides: ziti-tunnel +# Required-Start: $local_fs $network +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start Ziti Tunnel +### END INIT INFO + +ziti_dir=/opt/netfoundry/ziti +service=$(basename $(readlink -f "${0}")) +logfile="/var/log/${service}.log" +pidfile="/var/run/${service}.pid" +cfgfile="${ziti_dir}/cfg/${service}.json" +jwtfile="${ziti_dir}/cfg/${service}.jwt" + +# source function library +. /etc/init.d/functions + +# pull in sysconfig settings +[ -f "/etc/sysconfig/${service}" ] && . "/etc/sysconfig/${service}" + + +do_enroll() +{ + if [ ! -f "${cfgfile}" ]; then + echo -n $"Enrolling ${service}: " + if [ -f "${jwtfile}" ]; then + "${ziti_dir}/bin/ziti-enroller" --jwt "${jwtfile}" --out "${cfgfile}" >> "${logfile}" 2>&1 + if [ ${?} -ne 0 -o ! -f "${cfgfile}" ]; then + failure $"Enrolling ${service}" + echo "" + exit 1 + fi + else + echo "${cfgfile} does not exist, nor does ${jwtfile}" >> "${logfile}" + failure $"Enrolling ${service}" + echo "" + exit 1 + fi + success $"Enrolling ${service}" + echo "" + fi +} + +do_start() +{ + if [ "${VERBOSE}" = "YES" ]; then + verbose_opts="--verbose" + fi + if [ -n "${RESOLVER}" ]; then + resolver_opts="--resolver ${RESOLVER}" + fi + + do_enroll + echo -n $"Starting ${service}: " + ("${ziti_dir}/bin/ziti-tunnel" run ${verbose_opts} ${resolver_opts} "${cfgfile}" >> "${logfile}" 2>&1 & echo "${!}" > "${pidfile}" && sleep 1; ps -p "${!}" > /dev/null) + ec=${?} + if [ ${ec} -eq 0 ]; then + success $"logging to ${logfile}" + else + failure $"see ${logfile}" + fi + echo "" + return ${ec} +} + +do_stop() +{ + echo -n $"Stopping ${service}: " + killproc -p "${pidfile}" "${ziti_dir}/bin/ziti-tunnel" + echo "" +} + +do_status() +{ + status -p "${pidfile}" "${service}" +} + +do_status_q() +{ + do_status > /dev/null 2>&1 +} + +case "${1}" in + start) + do_status_q && exit 0 + do_start + ;; + stop) + do_status_q && do_stop + ;; + restart) + do_stop + sleep 1 + do_start + ;; + status) + do_status + ;; + *) + echo "Usage: /etc/init.d/ziti-tunnel {start|stop|restart}" >&2 + exit 1 + ;; +esac From da06e0e12a351be9cfa977574b1eb4c8e6efe26f Mon Sep 17 00:00:00 2001 From: Shawn Carey Date: Tue, 3 Dec 2019 14:45:45 -0500 Subject: [PATCH 2/5] moved command sources into subdirectory --- ziti-tunnel/cmd/main.go | 34 +++++++++ ziti-tunnel/cmd/subcmd/proxy.go | 86 ++++++++++++++++++++++ ziti-tunnel/cmd/subcmd/root.go | 118 ++++++++++++++++++++++++++++++ ziti-tunnel/cmd/subcmd/run.go | 71 ++++++++++++++++++ ziti-tunnel/cmd/subcmd/tproxy.go | 45 ++++++++++++ ziti-tunnel/cmd/subcmd/tun.go | 57 +++++++++++++++ ziti-tunnel/cmd/subcmd/version.go | 35 +++++++++ 7 files changed, 446 insertions(+) create mode 100644 ziti-tunnel/cmd/main.go create mode 100644 ziti-tunnel/cmd/subcmd/proxy.go create mode 100644 ziti-tunnel/cmd/subcmd/root.go create mode 100644 ziti-tunnel/cmd/subcmd/run.go create mode 100644 ziti-tunnel/cmd/subcmd/tproxy.go create mode 100644 ziti-tunnel/cmd/subcmd/tun.go create mode 100644 ziti-tunnel/cmd/subcmd/version.go diff --git a/ziti-tunnel/cmd/main.go b/ziti-tunnel/cmd/main.go new file mode 100644 index 000000000..4ea63f0b3 --- /dev/null +++ b/ziti-tunnel/cmd/main.go @@ -0,0 +1,34 @@ +/* + Copyright 2019 Netfoundry, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import ( + "github.com/netfoundry/ziti-cmd/ziti-tunnel/cmd/subcmd" + "github.com/netfoundry/ziti-foundation/util/debugz" + "github.com/michaelquigley/pfxlog" + "github.com/sirupsen/logrus" +) + +func init() { + pfxlog.Global(logrus.InfoLevel) + pfxlog.SetPrefix("bitbucket.org/netfoundry/") +} + +func main() { + debugz.AddStackDumpHandler() + subcmd.Execute() +} diff --git a/ziti-tunnel/cmd/subcmd/proxy.go b/ziti-tunnel/cmd/subcmd/proxy.go new file mode 100644 index 000000000..cbf665a02 --- /dev/null +++ b/ziti-tunnel/cmd/subcmd/proxy.go @@ -0,0 +1,86 @@ +/* + Copyright 2019 Netfoundry, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package subcmd + +import ( + "github.com/netfoundry/ziti-edge/tunnel/intercept" + "github.com/netfoundry/ziti-edge/tunnel/intercept/proxy" + "fmt" + "github.com/spf13/cobra" + "math" + "net" + "strconv" + "strings" +) + +var runProxyCmd = &cobra.Command{ + Use: "proxy [sevice-name:port]", + Short: "Run in 'proxy' mode", + Long: "The 'proxy' intercept mode creates a network listener for each service that is intercepted.", + Args: cobra.MinimumNArgs(1), + RunE: runProxy, +} + +func init() { + root.AddCommand(runProxyCmd) +} + +func runProxy(_ *cobra.Command, args []string) error { + services := make(map[string]*proxy.Service, len(args)) + + for _, arg := range args { + parts := strings.Split(arg, ":") + if len(parts) < 2 || len(parts) > 3 { + return fmt.Errorf("invalid argument '%s'", arg) + } + + port, err := strconv.Atoi(parts[1]) + if err != nil { + return fmt.Errorf("invalid port specified in '%s'", arg) + } + + service := &proxy.Service{ + Name: parts[0], + Port: port, + Protocol: intercept.TCP, + } + + if len(parts) == 3 { + protocol := parts[2] + if protocol == "udp" { + service.Protocol = intercept.UDP + } else if protocol != "tcp" { + return fmt.Errorf("invalid protocol specified in '%s', must be tcp or udp", arg) + } + } + services[parts[0]] = service + } + + // Fiddle with the poll rate and resolver settings if the user didn't wan't anything special. + if !root.Flag(svcPollRateFlag).Changed { + _ = root.PersistentFlags().Set(svcPollRateFlag, strconv.FormatUint(math.MaxUint32, 10)) + } + if !root.Flag(resolverCfgFlag).Changed { + _ = root.PersistentFlags().Set(resolverCfgFlag, "") + } + var err error + interceptor, err = proxy.New(net.IPv4zero, services) + if err != nil { + return fmt.Errorf("failed to initialize proxy interceptor: %v", err) + } + return nil +} diff --git a/ziti-tunnel/cmd/subcmd/root.go b/ziti-tunnel/cmd/subcmd/root.go new file mode 100644 index 000000000..4211a7700 --- /dev/null +++ b/ziti-tunnel/cmd/subcmd/root.go @@ -0,0 +1,118 @@ +/* + Copyright 2019 Netfoundry, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package subcmd + +import ( + "github.com/netfoundry/ziti-edge/sdk/ziti" + "github.com/netfoundry/ziti-edge/sdk/ziti/config" + "github.com/netfoundry/ziti-edge/tunnel/dns" + "github.com/netfoundry/ziti-edge/tunnel/intercept" + "fmt" + "github.com/michaelquigley/pfxlog" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "os" + "os/signal" + "path/filepath" + "syscall" + "time" +) + +const ( + svcPollRateFlag = "svcPollRate" + resolverCfgFlag = "resolver" +) + +func init() { + root.PersistentFlags().BoolP("verbose", "v", false, "Enable verbose mode") + root.PersistentFlags().StringP("identity", "i", "", "Path to JSON file that contains an enrolled identity") + root.PersistentFlags().Uint(svcPollRateFlag, 15, "Set poll rate for service updates (seconds)") + root.PersistentFlags().StringP(resolverCfgFlag, "r", "udp://127.0.0.1:53", "Resolver configuration") + root.PersistentFlags().StringVar(&logFormatter, "log-formatter", "", "Specify log formatter [json|pfxlog|text]") +} + +var root = &cobra.Command{ + Use: filepath.Base(os.Args[0]), + Short: "Ziti Tunnel", + PersistentPreRun: rootPreRun, + PersistentPostRun: rootPostRun, +} + +var interceptor intercept.Interceptor +var resolver dns.Resolver +var logFormatter string + +func Execute() { + if err := root.Execute(); err != nil { + fmt.Printf("error: %s", err) + } +} + +func rootPreRun(cmd *cobra.Command, args []string) { + verbose, err := cmd.Flags().GetBool("verbose") + if err != nil { + println("err") + } + if verbose { + logrus.SetLevel(logrus.DebugLevel) + } + + switch logFormatter { + case "pfxlog": + logrus.SetFormatter(pfxlog.NewFormatterStartingToday()) + case "json": + logrus.SetFormatter(&logrus.JSONFormatter{}) + case "text": + logrus.SetFormatter(&logrus.TextFormatter{}) + default: + // let logrus do its own thing + } +} + +func rootPostRun(cmd *cobra.Command, args []string) { + log := pfxlog.Logger() + + identityJson := cmd.Flag("identity").Value.String() + zitiCfg, err := config.NewFromFile(identityJson) + if err != nil { + log.Fatalf("failed to load ziti configuration from %s: %v", identityJson, err) + } + rootPrivateContext := ziti.NewContextWithConfig(zitiCfg) + if err != nil { + log.Fatalf("failed to initialize Ziti SDK: %v", err) + } + + sig := make(chan os.Signal) + signal.Notify(sig) + go func() { + for { + s := <-sig + log.Debugf("caught signal %v", s) + switch s { + case os.Interrupt, os.Kill, syscall.SIGTERM: + interceptor.Stop() + os.Exit(0) + } + } + }() + + svcPollRate, _ := cmd.Flags().GetUint(svcPollRateFlag) + resolverConfig := cmd.Flag("resolver").Value.String() + resolver = dns.NewResolver(resolverConfig) + + intercept.ServicePoller(rootPrivateContext, interceptor, resolver, time.Duration(svcPollRate)*time.Second) +} diff --git a/ziti-tunnel/cmd/subcmd/run.go b/ziti-tunnel/cmd/subcmd/run.go new file mode 100644 index 000000000..026ce7734 --- /dev/null +++ b/ziti-tunnel/cmd/subcmd/run.go @@ -0,0 +1,71 @@ +// +build linux + +/* + Copyright 2019 Netfoundry, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package subcmd + +import ( + "github.com/netfoundry/ziti-edge/tunnel/intercept" + "github.com/netfoundry/ziti-edge/tunnel/intercept/tproxy" + "github.com/netfoundry/ziti-edge/tunnel/intercept/tun" + "github.com/michaelquigley/pfxlog" + "github.com/spf13/cobra" +) + +var runCmd = &cobra.Command{ + Use: "run ", + Short: "Auto-select interceptor", + Long: "Provided for backwards compatibility with scripts that were coded around older ziti-tunnel versions.", + Args: cobra.MaximumNArgs(1), + Run: run, +} + +func init() { + root.AddCommand(runCmd) +} + +func run(cmd *cobra.Command, args []string) { + log := pfxlog.Logger() + var err error + var tProxyInterceptor, tunInterceptor intercept.Interceptor + + if len(args) != 0 { + _ = cmd.Flag("identity").Value.Set(args[0]) + } + + tProxyInterceptor, err = tproxy.New() + if err != nil { + log.Infof("tproxy initialization failed: %v", err) + } else { + log.Info("using tproxy interceptor") + interceptor = tProxyInterceptor + return + } + + tunInterceptor, err = tun.New("", tunMtuDefault) + if err != nil { + log.Infof("tun initialization failed: %v", err) + } else { + log.Info("using tun interceptor") + interceptor = tunInterceptor + return + } + + if interceptor == nil { + log.Fatal("failed to initialize an interceptor") + } +} \ No newline at end of file diff --git a/ziti-tunnel/cmd/subcmd/tproxy.go b/ziti-tunnel/cmd/subcmd/tproxy.go new file mode 100644 index 000000000..3616cbe02 --- /dev/null +++ b/ziti-tunnel/cmd/subcmd/tproxy.go @@ -0,0 +1,45 @@ +// +build linux + +/* + Copyright 2019 Netfoundry, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package subcmd + +import ( + "github.com/netfoundry/ziti-edge/tunnel/intercept/tproxy" + "fmt" + "github.com/spf13/cobra" +) + +var runTProxyCmd = &cobra.Command{ + Use: "tproxy", + Short: "Use the 'tproxy' interceptor", + Long: "The 'tproxy' interceptor captures packets by using the TPROXY iptables target.", + RunE: runTProxy, +} + +func init() { + root.AddCommand(runTProxyCmd) +} + +func runTProxy(cmd *cobra.Command, args []string) error { + var err error + interceptor, err = tproxy.New() + if err != nil { + return fmt.Errorf("failed to initialize tproxy interceptor: %v", err) + } + return nil +} diff --git a/ziti-tunnel/cmd/subcmd/tun.go b/ziti-tunnel/cmd/subcmd/tun.go new file mode 100644 index 000000000..7db66d7d1 --- /dev/null +++ b/ziti-tunnel/cmd/subcmd/tun.go @@ -0,0 +1,57 @@ +// +build linux + +/* + Copyright 2019 Netfoundry, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package subcmd + +import ( + "github.com/netfoundry/ziti-edge/tunnel/intercept/tun" + "fmt" + "github.com/michaelquigley/pfxlog" + "github.com/spf13/cobra" +) + +const ( + tunMtuFlag = "mtu" + tunMtuDefault = 65535 +) + +func init() { + tunCmd.PersistentFlags().Uint(tunMtuFlag, tunMtuDefault, "Set MTU of ephemeral tun interface") + root.AddCommand(tunCmd) +} + +var tunCmd = &cobra.Command{ + Use: "tun ", + Short: "Intercept packets with tun interface", + Args: cobra.NoArgs, + RunE: runTun, +} + +func runTun(cmd *cobra.Command, args []string) error { + log := pfxlog.Logger() + mtu, err := cmd.Flags().GetUint(tunMtuFlag) + if err != nil { + log.WithError(err).Warn("error getting MTU") + } + + interceptor, err = tun.New("", mtu) + if err != nil { + return fmt.Errorf("failed to initialize tun interceptor: %v", err) + } + return nil +} diff --git a/ziti-tunnel/cmd/subcmd/version.go b/ziti-tunnel/cmd/subcmd/version.go new file mode 100644 index 000000000..20c3d4e1c --- /dev/null +++ b/ziti-tunnel/cmd/subcmd/version.go @@ -0,0 +1,35 @@ +/* + Copyright 2019 Netfoundry, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package subcmd + +import ( + "github.com/netfoundry/ziti-cmd/common/version" + "fmt" + "github.com/spf13/cobra" +) + +func init() { + root.AddCommand(versionCmd) +} + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Show component version", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(version.GetVersion()) + }, +} From c08ad74ffab64f2bef46881bafc6857853a532bd Mon Sep 17 00:00:00 2001 From: Shawn Carey Date: Tue, 3 Dec 2019 14:47:11 -0500 Subject: [PATCH 3/5] moved command sources into subdirectory --- ziti-tunnel/main.go | 34 ---------- ziti-tunnel/subcmd/proxy.go | 86 ------------------------- ziti-tunnel/subcmd/root.go | 118 ---------------------------------- ziti-tunnel/subcmd/run.go | 71 -------------------- ziti-tunnel/subcmd/tproxy.go | 45 ------------- ziti-tunnel/subcmd/tun.go | 57 ---------------- ziti-tunnel/subcmd/version.go | 35 ---------- 7 files changed, 446 deletions(-) delete mode 100644 ziti-tunnel/main.go delete mode 100644 ziti-tunnel/subcmd/proxy.go delete mode 100644 ziti-tunnel/subcmd/root.go delete mode 100644 ziti-tunnel/subcmd/run.go delete mode 100644 ziti-tunnel/subcmd/tproxy.go delete mode 100644 ziti-tunnel/subcmd/tun.go delete mode 100644 ziti-tunnel/subcmd/version.go diff --git a/ziti-tunnel/main.go b/ziti-tunnel/main.go deleted file mode 100644 index c06d29cb0..000000000 --- a/ziti-tunnel/main.go +++ /dev/null @@ -1,34 +0,0 @@ -/* - Copyright 2019 Netfoundry, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package main - -import ( - "github.com/netfoundry/ziti-cmd/ziti-tunnel/subcmd" - "github.com/netfoundry/ziti-foundation/util/debugz" - "github.com/michaelquigley/pfxlog" - "github.com/sirupsen/logrus" -) - -func init() { - pfxlog.Global(logrus.InfoLevel) - pfxlog.SetPrefix("bitbucket.org/netfoundry/") -} - -func main() { - debugz.AddStackDumpHandler() - subcmd.Execute() -} diff --git a/ziti-tunnel/subcmd/proxy.go b/ziti-tunnel/subcmd/proxy.go deleted file mode 100644 index cbf665a02..000000000 --- a/ziti-tunnel/subcmd/proxy.go +++ /dev/null @@ -1,86 +0,0 @@ -/* - Copyright 2019 Netfoundry, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package subcmd - -import ( - "github.com/netfoundry/ziti-edge/tunnel/intercept" - "github.com/netfoundry/ziti-edge/tunnel/intercept/proxy" - "fmt" - "github.com/spf13/cobra" - "math" - "net" - "strconv" - "strings" -) - -var runProxyCmd = &cobra.Command{ - Use: "proxy [sevice-name:port]", - Short: "Run in 'proxy' mode", - Long: "The 'proxy' intercept mode creates a network listener for each service that is intercepted.", - Args: cobra.MinimumNArgs(1), - RunE: runProxy, -} - -func init() { - root.AddCommand(runProxyCmd) -} - -func runProxy(_ *cobra.Command, args []string) error { - services := make(map[string]*proxy.Service, len(args)) - - for _, arg := range args { - parts := strings.Split(arg, ":") - if len(parts) < 2 || len(parts) > 3 { - return fmt.Errorf("invalid argument '%s'", arg) - } - - port, err := strconv.Atoi(parts[1]) - if err != nil { - return fmt.Errorf("invalid port specified in '%s'", arg) - } - - service := &proxy.Service{ - Name: parts[0], - Port: port, - Protocol: intercept.TCP, - } - - if len(parts) == 3 { - protocol := parts[2] - if protocol == "udp" { - service.Protocol = intercept.UDP - } else if protocol != "tcp" { - return fmt.Errorf("invalid protocol specified in '%s', must be tcp or udp", arg) - } - } - services[parts[0]] = service - } - - // Fiddle with the poll rate and resolver settings if the user didn't wan't anything special. - if !root.Flag(svcPollRateFlag).Changed { - _ = root.PersistentFlags().Set(svcPollRateFlag, strconv.FormatUint(math.MaxUint32, 10)) - } - if !root.Flag(resolverCfgFlag).Changed { - _ = root.PersistentFlags().Set(resolverCfgFlag, "") - } - var err error - interceptor, err = proxy.New(net.IPv4zero, services) - if err != nil { - return fmt.Errorf("failed to initialize proxy interceptor: %v", err) - } - return nil -} diff --git a/ziti-tunnel/subcmd/root.go b/ziti-tunnel/subcmd/root.go deleted file mode 100644 index 4211a7700..000000000 --- a/ziti-tunnel/subcmd/root.go +++ /dev/null @@ -1,118 +0,0 @@ -/* - Copyright 2019 Netfoundry, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package subcmd - -import ( - "github.com/netfoundry/ziti-edge/sdk/ziti" - "github.com/netfoundry/ziti-edge/sdk/ziti/config" - "github.com/netfoundry/ziti-edge/tunnel/dns" - "github.com/netfoundry/ziti-edge/tunnel/intercept" - "fmt" - "github.com/michaelquigley/pfxlog" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "os" - "os/signal" - "path/filepath" - "syscall" - "time" -) - -const ( - svcPollRateFlag = "svcPollRate" - resolverCfgFlag = "resolver" -) - -func init() { - root.PersistentFlags().BoolP("verbose", "v", false, "Enable verbose mode") - root.PersistentFlags().StringP("identity", "i", "", "Path to JSON file that contains an enrolled identity") - root.PersistentFlags().Uint(svcPollRateFlag, 15, "Set poll rate for service updates (seconds)") - root.PersistentFlags().StringP(resolverCfgFlag, "r", "udp://127.0.0.1:53", "Resolver configuration") - root.PersistentFlags().StringVar(&logFormatter, "log-formatter", "", "Specify log formatter [json|pfxlog|text]") -} - -var root = &cobra.Command{ - Use: filepath.Base(os.Args[0]), - Short: "Ziti Tunnel", - PersistentPreRun: rootPreRun, - PersistentPostRun: rootPostRun, -} - -var interceptor intercept.Interceptor -var resolver dns.Resolver -var logFormatter string - -func Execute() { - if err := root.Execute(); err != nil { - fmt.Printf("error: %s", err) - } -} - -func rootPreRun(cmd *cobra.Command, args []string) { - verbose, err := cmd.Flags().GetBool("verbose") - if err != nil { - println("err") - } - if verbose { - logrus.SetLevel(logrus.DebugLevel) - } - - switch logFormatter { - case "pfxlog": - logrus.SetFormatter(pfxlog.NewFormatterStartingToday()) - case "json": - logrus.SetFormatter(&logrus.JSONFormatter{}) - case "text": - logrus.SetFormatter(&logrus.TextFormatter{}) - default: - // let logrus do its own thing - } -} - -func rootPostRun(cmd *cobra.Command, args []string) { - log := pfxlog.Logger() - - identityJson := cmd.Flag("identity").Value.String() - zitiCfg, err := config.NewFromFile(identityJson) - if err != nil { - log.Fatalf("failed to load ziti configuration from %s: %v", identityJson, err) - } - rootPrivateContext := ziti.NewContextWithConfig(zitiCfg) - if err != nil { - log.Fatalf("failed to initialize Ziti SDK: %v", err) - } - - sig := make(chan os.Signal) - signal.Notify(sig) - go func() { - for { - s := <-sig - log.Debugf("caught signal %v", s) - switch s { - case os.Interrupt, os.Kill, syscall.SIGTERM: - interceptor.Stop() - os.Exit(0) - } - } - }() - - svcPollRate, _ := cmd.Flags().GetUint(svcPollRateFlag) - resolverConfig := cmd.Flag("resolver").Value.String() - resolver = dns.NewResolver(resolverConfig) - - intercept.ServicePoller(rootPrivateContext, interceptor, resolver, time.Duration(svcPollRate)*time.Second) -} diff --git a/ziti-tunnel/subcmd/run.go b/ziti-tunnel/subcmd/run.go deleted file mode 100644 index 026ce7734..000000000 --- a/ziti-tunnel/subcmd/run.go +++ /dev/null @@ -1,71 +0,0 @@ -// +build linux - -/* - Copyright 2019 Netfoundry, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package subcmd - -import ( - "github.com/netfoundry/ziti-edge/tunnel/intercept" - "github.com/netfoundry/ziti-edge/tunnel/intercept/tproxy" - "github.com/netfoundry/ziti-edge/tunnel/intercept/tun" - "github.com/michaelquigley/pfxlog" - "github.com/spf13/cobra" -) - -var runCmd = &cobra.Command{ - Use: "run ", - Short: "Auto-select interceptor", - Long: "Provided for backwards compatibility with scripts that were coded around older ziti-tunnel versions.", - Args: cobra.MaximumNArgs(1), - Run: run, -} - -func init() { - root.AddCommand(runCmd) -} - -func run(cmd *cobra.Command, args []string) { - log := pfxlog.Logger() - var err error - var tProxyInterceptor, tunInterceptor intercept.Interceptor - - if len(args) != 0 { - _ = cmd.Flag("identity").Value.Set(args[0]) - } - - tProxyInterceptor, err = tproxy.New() - if err != nil { - log.Infof("tproxy initialization failed: %v", err) - } else { - log.Info("using tproxy interceptor") - interceptor = tProxyInterceptor - return - } - - tunInterceptor, err = tun.New("", tunMtuDefault) - if err != nil { - log.Infof("tun initialization failed: %v", err) - } else { - log.Info("using tun interceptor") - interceptor = tunInterceptor - return - } - - if interceptor == nil { - log.Fatal("failed to initialize an interceptor") - } -} \ No newline at end of file diff --git a/ziti-tunnel/subcmd/tproxy.go b/ziti-tunnel/subcmd/tproxy.go deleted file mode 100644 index 3616cbe02..000000000 --- a/ziti-tunnel/subcmd/tproxy.go +++ /dev/null @@ -1,45 +0,0 @@ -// +build linux - -/* - Copyright 2019 Netfoundry, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package subcmd - -import ( - "github.com/netfoundry/ziti-edge/tunnel/intercept/tproxy" - "fmt" - "github.com/spf13/cobra" -) - -var runTProxyCmd = &cobra.Command{ - Use: "tproxy", - Short: "Use the 'tproxy' interceptor", - Long: "The 'tproxy' interceptor captures packets by using the TPROXY iptables target.", - RunE: runTProxy, -} - -func init() { - root.AddCommand(runTProxyCmd) -} - -func runTProxy(cmd *cobra.Command, args []string) error { - var err error - interceptor, err = tproxy.New() - if err != nil { - return fmt.Errorf("failed to initialize tproxy interceptor: %v", err) - } - return nil -} diff --git a/ziti-tunnel/subcmd/tun.go b/ziti-tunnel/subcmd/tun.go deleted file mode 100644 index 7db66d7d1..000000000 --- a/ziti-tunnel/subcmd/tun.go +++ /dev/null @@ -1,57 +0,0 @@ -// +build linux - -/* - Copyright 2019 Netfoundry, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package subcmd - -import ( - "github.com/netfoundry/ziti-edge/tunnel/intercept/tun" - "fmt" - "github.com/michaelquigley/pfxlog" - "github.com/spf13/cobra" -) - -const ( - tunMtuFlag = "mtu" - tunMtuDefault = 65535 -) - -func init() { - tunCmd.PersistentFlags().Uint(tunMtuFlag, tunMtuDefault, "Set MTU of ephemeral tun interface") - root.AddCommand(tunCmd) -} - -var tunCmd = &cobra.Command{ - Use: "tun ", - Short: "Intercept packets with tun interface", - Args: cobra.NoArgs, - RunE: runTun, -} - -func runTun(cmd *cobra.Command, args []string) error { - log := pfxlog.Logger() - mtu, err := cmd.Flags().GetUint(tunMtuFlag) - if err != nil { - log.WithError(err).Warn("error getting MTU") - } - - interceptor, err = tun.New("", mtu) - if err != nil { - return fmt.Errorf("failed to initialize tun interceptor: %v", err) - } - return nil -} diff --git a/ziti-tunnel/subcmd/version.go b/ziti-tunnel/subcmd/version.go deleted file mode 100644 index 20c3d4e1c..000000000 --- a/ziti-tunnel/subcmd/version.go +++ /dev/null @@ -1,35 +0,0 @@ -/* - Copyright 2019 Netfoundry, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package subcmd - -import ( - "github.com/netfoundry/ziti-cmd/common/version" - "fmt" - "github.com/spf13/cobra" -) - -func init() { - root.AddCommand(versionCmd) -} - -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Show component version", - Run: func(cmd *cobra.Command, args []string) { - fmt.Println(version.GetVersion()) - }, -} From 01836722a4ecc9be4669fe651880043124db05d9 Mon Sep 17 00:00:00 2001 From: Shawn Carey Date: Tue, 3 Dec 2019 15:01:03 -0500 Subject: [PATCH 4/5] bring README.md over from ziti-edge, as it is command-centric. --- ziti-tunnel/README.md | 276 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 ziti-tunnel/README.md diff --git a/ziti-tunnel/README.md b/ziti-tunnel/README.md new file mode 100644 index 000000000..abf593578 --- /dev/null +++ b/ziti-tunnel/README.md @@ -0,0 +1,276 @@ +# ziti-tunnel + +`ziti-tunnel` intercepts outbound transport layer packets to Ziti service addresses +and proxies them through Ziti. + +The services that are proxied are determined by the app-wan membership of the +identity that is defined in the configuration file. + +## Configuration File + +A configuration file is created when an identity is successfully enrolled with +a Ziti edge controller. Here's an example of a configuration file that +`ziti-tunnel` accepts: + + { + "ztAPI": "https://ziti-dev-controller01.localhost:1080/", + "versions": { + "api": "1.0.0", + "enrollmentApi": "1.0.0" + }, + "id": { + "cert": "file:///root/device01.3rdparty.client.cert.pem", + "key": "file:///root/device01.3rdparty.client.key.pem", + "ca": "file:///root/ziti-dev-ingress01.external.chain.cert.pem" + } + } + +## Usage + +ziti-tunnel authenticates with the edge controller in the config file, and +periodically queries the controller for services that the identity is allowed to +use. Whenever a new service is found, ziti-tunnel invokes the selected intercept +mode with the details of the service. + +`ziti-tunnel` supports several intercept modes, which are specified with a sub-command. +Typically you will run `ziti-tunnel` with the _run_ sub-command, which determines +the preferred intercept mode based on the kernel drivers that are available on the +host. + + $ sudo ziti-tunnel run ziti.json + [ 0.000] INFO ziti/tunnel/intercept/tproxy.New: tproxy listening on 127.0.0.1:33641 + [ 0.006] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.run: using tproxy interceptor + ... + +When started on a host that lacks __iptables__, the tproxy intercept mode initializer +fails and `ziti-tunnel` attempts to use the tun intercept mode: + + $ sudo ziti-tunnel run ziti.json + [ 0.001] INFO ziti/tunnel/intercept/tproxy.New: tproxy listening on 127.0.0.1:37313 + [ 0.001] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.run: tproxy initialization failed: failed to initialize iptables handle: exec: "iptables": executable file not found in $PATH + [ 0.009] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.run: using tun interceptor + +`ziti-tunnel` fails to start if no intercept modes can be successfully initialized: + + $ sudo ziti-tunnel run ziti.json + [ 0.000] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.run: tproxy initialization failed: failed to initialize iptables handle: exec: "iptables": executable file not found in $PATH + [ 0.001] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.run: tun initialization failed: failed to open tun interface (name='', mtu=0): ioctl failed with 'invalid argument' + [ 0.001] FATAL ziti/tunnel/cmd/ziti-tunnel/subcmd.run: failed to initialize an interceptor + + +## Intercept Modes + +### tproxy + +tproxy is the preferred intercept mode when running on a Linux kernel that has the +__ip_tables__ kernel module installed. + + $ lsmod | grep ip_tables + ip_tables 32768 5 iptable_filter,iptable_security,iptable_raw,iptable_nat,iptable_mangle + +`ziti-tunnel` manipulates routing tables and firewall rules when using the tproxy +intercept mode. The NET_ADMIN Linux capability is required for these actions. The +usage example here runs ziti-tunnel with sudo as a simple way to obtain +NET_ADMIN: + + $ sudo ziti-tunnel --identity ziti.json tproxy + [ 0.000] INFO ziti/tunnel/intercept/tproxy.New: tproxy listening on 127.0.0.1:33355 + [ 0.010] INFO ziti/tunnel/dns.NewDnsServer: starting dns server... + [ 2.018] INFO ziti/tunnel/dns.NewDnsServer: dns server running at 127.0.0.1:53 + [ 2.018] INFO ziti/tunnel/dns.(*resolver).AddHostname: adding ziti-tunnel.resolver.test = 19.65.28.94 to resolver + [ 2.033] INFO ziti/tunnel/dns.(*resolver).RemoveHostname: removing ziti-tunnel.resolver.test from resolver + [ 2.096] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.updateServices: starting tunnel for newly available service wttr.in + [ 2.290] INFO ziti/tunnel/dns.(*resolver).AddHostname: adding wttr.in = 5.9.243.187 to resolver + [ 2.300] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.updateServices: service wttr.in not hostable + [ 2.300] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.updateServices: starting tunnel for newly available service ssh-scarey + [ 2.570] INFO ziti/tunnel/dns.(*resolver).AddHostname: adding scarey.io = 169.254.1.1 to resolver + +The tproxy intercept mode creates a network listener that accepts connections at a +randomly selected port on the loopback interface. Intercepted ziti service traffic +directed to the listener by two mechanisms: + +* Firewall Rules (iptables) + + The TPROXY iptables target is the primary intercept mechanism used by the tproxy + intercept mode. The TPROXY target essentially sends packets to a local listener + without actually modifying the packet's destination address fields. See + https://www.kernel.org/doc/Documentation/networking/tproxy.txt and + `iptables-extensions(8)` for more details on the TPROXY target. + + First, the tproxy interceptor links a new iptables chain to the PREROUTING chain: + + $ sudo iptables -nt mangle -L PREROUTING | grep NF-INTERCEPT + NF-INTERCEPT all -- 0.0.0.0/0 0.0.0.0/0 + + Then it creates rules in the new chain for each intercepted service. You can view + the tproxy rules in play: + + $ sudo iptables -nt mangle -L NF-INTERCEPT + Chain NF-INTERCEPT (1 references) + target prot opt source destination + TPROXY tcp -- 0.0.0.0/0 5.9.243.187 /* wttr.in */ tcp dpt:443 TPROXY redirect 127.0.0.1:33355 mark 0x1/0x1 + TPROXY tcp -- 0.0.0.0/0 169.254.1.1 /* ssh-scarey */ tcp dpt:22 TPROXY redirect 127.0.0.1:33355 mark 0x1/0x1 + TPROXY tcp -- 0.0.0.0/0 1.2.3.4 /* netcat */ tcp dpt:22169 TPROXY redirect 127.0.0.1:33355 mark 0x1/0x1 + + Packets with a destination address that matches the intercept address of a Ziti + service are directed to ziti-tunnel's network listener (127.0.0.1:33355 in the + examples above). This effectively enables `ziti-tunnel` to capture packets that + are destined for any address using a single listener (and a single port). + + NOTE: _netfilter_ rules were considered when implementing ziti-tunnel's tproxy + intercept mode. _netfilter_ is a slightly more modern than _iptables_ and has + a supported netlink API for manipulating rules without "shelling out" to the + `iptables` command line utility. _netfilter_ was ultimately abandoned because + netfilter tproxy support requires kernel configuration options (`CONFIG_NFT_TPROXY`, + `CONFIG_NFT_SOCKET`) that are not enabled in the default kernels of many common + Linux distributions. + +* Local Routes + + The TPROXY target is only valid in the PREROUTING iptables chain, which is + traversed by incoming packets that were routed to the host over the network. A + _local_ route is necessary in order to get locally generated packets to traverse + the PREROUTING chain: + + $ ip route show table local + local 1.2.3.4 dev lo proto kernel scope host src 1.2.3.4 + local 5.9.243.187 dev lo proto kernel scope host src 5.9.243.187 + local 169.254.1.1 dev lo proto kernel scope host src 169.254.1.1 + +### tun + +The tun intercept mode creates an ephemeral tun interface and configures it with the +IP addresses of the services that are being proxied. + +`ziti-tunnel` manipulates network interfaces when using the tun intercept mode, +which requires the NET_ADMIN Linux capability. The usage example here runs +ziti-tunnel with sudo as a simple way to obtain NET_ADMIN: + + $ sudo ziti-tunnel --identity ziti.json tun + [ 0.010] INFO ziti/tunnel/dns.NewDnsServer: starting dns server... + [ 2.012] INFO ziti/tunnel/dns.NewDnsServer: dns server running at 127.0.0.1:53 + [ 2.012] INFO ziti/tunnel/dns.(*resolver).AddHostname: adding ziti-tunnel.resolver.test = 19.65.28.94 to resolver + [ 2.031] INFO ziti/tunnel/dns.(*resolver).RemoveHostname: removing ziti-tunnel.resolver.test from resolver + [ 2.089] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.updateServices: starting tunnel for newly available service wttr.in + [ 2.280] INFO ziti/tunnel/dns.(*resolver).AddHostname: adding wttr.in = 5.9.243.187 to resolver + [ 2.282] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.updateServices: service wttr.in not hostable + [ 2.282] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.updateServices: starting tunnel for newly available service ssh-scarey + [ 2.502] INFO ziti/tunnel/dns.(*resolver).AddHostname: adding scarey.io = 169.254.1.2 to resolver + [ 2.505] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.updateServices: service ssh-scarey not hostable + [ 2.505] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.updateServices: starting tunnel for newly available service netcat + [ 2.506] INFO ziti/tunnel/cmd/ziti-tunnel/subcmd.updateServices: service netcat not hostable + ... + +The addresses that `ziti-tunnel` adds to the tun interface are __point-to-point__ +addresses: + + $ ip addr show dev tun0 + 10: tun0: mtu 65535 qdisc fq_codel state UNKNOWN group default qlen 500 + link/none + inet 169.254.1.1/32 scope host tun0 + valid_lft forever preferred_lft forever + inet 169.254.1.1 peer 5.9.243.187/32 scope host tun0 + valid_lft forever preferred_lft forever + inet 169.254.1.1 peer 169.254.1.2/32 scope host tun0 + valid_lft forever preferred_lft forever + inet 169.254.1.1 peer 1.2.3.4/32 scope host tun0 + valid_lft forever preferred_lft forever + +The tun interface itself is assigned a link-local address, 169.254.1.1 in this +case, and each intercepted service is represented by a point-to-point address with +the remote address matching the intercept IP of the Ziti service. The tun intercept +mode uses point-to-point addresses instead of local routes because local routes +would result in the Linux networking stack receiving the packets that are routed to +the tun interface. The point-to-point addresses ensure that the packets are delivered +"to the wire", which mean that, for a tun interface, the packets will be picked up +by `ziti-tunnel` when it reads data from the tun interface. + +### proxy + +The proxy intercept mode creates a network listener for each Ziti service that is +intercepted. The services to intercept, and the ports that they are intercepted on, +are specified on the command line (as opposed to using the service definitions that +are retrieved from the edge controller): + + $ ziti-tunnel --identity ziti.json proxy wttr.in:8443 ssh-scarey:2222 netcat:22169 + [ 0.004] INFO ziti/tunnel/intercept/proxy.(*proxyInterceptor).Start: starting proxy interceptor + [ 0.120] INFO ziti/tunnel/intercept.updateServices: starting tunnel for newly available service ssh-scarey + [ 0.183] INFO ziti/tunnel/intercept.updateServices: service ssh-scarey not hostable + [ 0.183] INFO ziti/tunnel/intercept.updateServices: starting tunnel for newly available service netcat + [ 0.183] INFO ziti/tunnel/intercept/proxy.proxyInterceptor.runServiceListener: {addr=[0.0.0.0:2222] service=[ssh-scarey]} service is listening + [ 0.203] INFO ziti/tunnel/intercept.updateServices: service netcat not hostable + [ 0.203] INFO ziti/tunnel/intercept/proxy.proxyInterceptor.runServiceListener: {addr=[0.0.0.0:22169] service=[netcat]} service is listening + [ 0.203] INFO ziti/tunnel/intercept.updateServices: starting tunnel for newly available service wttr.in + [ 0.226] INFO ziti/tunnel/intercept.updateServices: service wttr.in not hostable + [ 0.226] INFO ziti/tunnel/intercept/proxy.proxyInterceptor.runServiceListener: {addr=[0.0.0.0:8443] service=[wttr.in]} service is listening + +All network listeners bind to local network interfaces (0.0.0.0): + + $ netstat -tnl | fgrep 0.0.0.0 + Active Internet connections (only servers) + Proto Recv-Q Send-Q Local Address Foreign Address State + tcp 0 0 0.0.0.0:2222 0.0.0.0:* LISTEN + tcp 0 0 0.0.0.0:22169 0.0.0.0:* LISTEN + tcp 0 0 0.0.0.0:8443 0.0.0.0:* LISTEN + +Proxy mode is intended to be a developer tool, most useful in situations where root +privileges are not available. + +## DNS Server +ziti-tunnel runs an internal DNS server by default. The DNS server must be first in the host's resolver +configuration (e.g. resolve.conf). A self-test is performed when ziti-tunnel starts to ensure that its +internal DNS server is configured in the system resolver: + + INFO[0002] dns server started on 127.0.0.1:53 + INFO[0002] adding ziti-tunnel.resolver.test -> 19.65.28.94 to resolver + INFO[0002] removing ziti-tunnel.resolver.test from resolver + +The test involves inserting a known hostname/IP address into the internal DNS server, and using the system +resolver to retrieve the address of the hostname. *ziti-tunnel will exit if the DNS self-test fails.* + +Linux distributions typically manage the contents of /etc/resolv.conf, so simply editing the file +will only work for a short time until /etc/resolv.conf is overwritten by the managing process. + +Resolver configuration changes must survive restarts of the Linux name resolution manager. Linux +distrubutions use one of several name resolution managers. The simplest way to determine which name +resolution manager is being used by your Linux distrubtion is to look at /etc/resolv.conf: + + $ ls -l /etc/resolv.conf + +* If /etc/resolv.conf is a regular file, then it is most likely being managed by `dhclient`. +* If /etc/resolv.conf is a symlink to a file in /run/systemd/resolve, then it is being + managed by `systemd-resolved` + +#### dhclient + +If your Linux distribution uses dhclient, you can configure the system resolver to use +ziti-tunnel's internal DNS server first by adding the following to /etc/dhcp/dhclient.conf: + + prepend domain-name-servers 127.0.0.1; + +Then restart network manager. Unless you know the name of the NetworkManager systemd +service on your Linux distrubtion, it's probably easiest to reboot the host. + +#### systemd-resolved + + $ sudo ln -sf /run/systemd/resolve/resolv.conf /etc + $ echo -e "[Resolve]\nDNS=127.0.0.1" | sudo tee /etc/systemd/resolved.conf.d/ziti-tunnel.conf + $ sudo systemctl restart systemd-resolved + +If you are unable to control the resolver on your operating system, ziti-tunnel can use/update a hosts file for +any hostnames that it tunnels: + + ziti-tunnel run --resolver file:///etc/hosts "${HOME}/ziti.json" + +### IP Address Assignment + +If the service specifies a hostname for its address, ziti-tunnel resolves the hostname and adds the result to its +internal DNS server: + + [0127] INFO adding myservice.mydomain.com -> 45.60.32.165 to resolver + +If the service hostname does not resolve, ziti-tunnel will find an unused link-local address and assign it to +the route for the service: + + [0012] INFO adding bogushost.net -> 169.254.1.4 to resolver + [0012] INFO ziti/tunnel/protocols/tcp.Listen: Accepting on 169.254.1.4:25 service=telnet \ No newline at end of file From a0dc6da88031e26934673411133c83e75c3666e1 Mon Sep 17 00:00:00 2001 From: Shawn Carey Date: Tue, 3 Dec 2019 16:22:51 -0500 Subject: [PATCH 5/5] incorporated https://github.com/netfoundry/ziti-cmd/pull/2 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index f369eb670..9b55835f4 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19 github.com/michaelquigley/pfxlog v0.0.0-20190813191113-2be43bd0dccc - github.com/netfoundry/ziti-edge v0.0.0-20191203174636-7a58c10c01b1 + github.com/netfoundry/ziti-edge v0.0.0-20191203205045-c1d47f2cacf4 github.com/netfoundry/ziti-fabric v0.0.0-20191203174113-af4eb6e60864 github.com/netfoundry/ziti-foundation v0.0.0-20191203170231-5c1204e0e65d github.com/pborman/uuid v1.2.0 diff --git a/go.sum b/go.sum index 3c12850f4..e38763fe7 100644 --- a/go.sum +++ b/go.sum @@ -196,6 +196,8 @@ github.com/netfoundry/ziti-edge v0.0.0-20191203171740-9debc34cc63a h1:8VN2KhcyN8 github.com/netfoundry/ziti-edge v0.0.0-20191203171740-9debc34cc63a/go.mod h1:vmLEvxm8egKrZbuXtUadyH9cgsrWKBPMspi+G/CD9nU= github.com/netfoundry/ziti-edge v0.0.0-20191203174636-7a58c10c01b1 h1:5qw2xQbfmqPrSZJzRhZf8ot8arMwfbfQs3sV1zC/YA8= github.com/netfoundry/ziti-edge v0.0.0-20191203174636-7a58c10c01b1/go.mod h1:CxNFWjGAIX4Ii3tSQG5yHsdXVZCxzsNwMUJgHFC8hso= +github.com/netfoundry/ziti-edge v0.0.0-20191203205045-c1d47f2cacf4 h1:uUhIlQ0IS7Nen/GDfyl/YSPpRcTlJCMjEBhBGx5ykZE= +github.com/netfoundry/ziti-edge v0.0.0-20191203205045-c1d47f2cacf4/go.mod h1:CxNFWjGAIX4Ii3tSQG5yHsdXVZCxzsNwMUJgHFC8hso= github.com/netfoundry/ziti-fabric v0.0.0-20191203170918-f312601f55c9/go.mod h1:ktqE4LYK1Z4MGBpP29ylnUvEsSNwk7jXBfq2K/kq4nw= github.com/netfoundry/ziti-fabric v0.0.0-20191203174113-af4eb6e60864 h1:GGMpVeTIqeN+ZFC2MJX3qQNX+V9Zkda9lquhw1Toh+k= github.com/netfoundry/ziti-fabric v0.0.0-20191203174113-af4eb6e60864/go.mod h1:ktqE4LYK1Z4MGBpP29ylnUvEsSNwk7jXBfq2K/kq4nw=