From 8e1bfe1296403dbd1f788f9436eb77fa7892933b Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Mon, 22 Nov 2021 16:46:54 +1030 Subject: [PATCH 01/26] packetbeat: add npcap installer hooks wip --- NOTICE.txt | 74 +++--- go.mod | 2 +- .../_meta/config/beat.reference.yml.tmpl | 1 + packetbeat/_meta/config/beat.yml.tmpl | 1 + .../_meta/config/windows_npcap.yml.tmpl | 16 ++ packetbeat/beater/install_npcap.go | 143 +++++++++++ packetbeat/beater/packetbeat.go | 6 + packetbeat/internal/npcap/npcap.go | 223 ++++++++++++++++++ packetbeat/internal/npcap/npcap_other.go | 23 ++ packetbeat/internal/npcap/npcap_windows.go | 25 ++ .../internal/npcap/npcap_windows_test.go | 94 ++++++++ .../internal/npcap/testdata/mock_installer.go | 35 +++ packetbeat/packetbeat.reference.yml | 17 ++ packetbeat/packetbeat.yml | 17 ++ x-pack/packetbeat/packetbeat.reference.yml | 17 ++ x-pack/packetbeat/packetbeat.yml | 17 ++ 16 files changed, 673 insertions(+), 38 deletions(-) create mode 100644 packetbeat/_meta/config/windows_npcap.yml.tmpl create mode 100644 packetbeat/beater/install_npcap.go create mode 100644 packetbeat/internal/npcap/npcap.go create mode 100644 packetbeat/internal/npcap/npcap_other.go create mode 100644 packetbeat/internal/npcap/npcap_windows.go create mode 100644 packetbeat/internal/npcap/npcap_windows_test.go create mode 100644 packetbeat/internal/npcap/testdata/mock_installer.go diff --git a/NOTICE.txt b/NOTICE.txt index 148e4680e06..853c448d3a9 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -16728,6 +16728,43 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +-------------------------------------------------------------------------------- +Dependency : golang.org/x/mod +Version: v0.5.1 +Licence type (autodetected): BSD-3-Clause +-------------------------------------------------------------------------------- + +Contents of probable licence file $GOMODCACHE/golang.org/x/mod@v0.5.1/LICENSE: + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + -------------------------------------------------------------------------------- Dependency : golang.org/x/net Version: v0.0.0-20211020060615-d418f374d309 @@ -34519,43 +34556,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------------------------------------------------------- -Dependency : golang.org/x/mod -Version: v0.5.1 -Licence type (autodetected): BSD-3-Clause --------------------------------------------------------------------------------- - -Contents of probable licence file $GOMODCACHE/golang.org/x/mod@v0.5.1/LICENSE: - -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -------------------------------------------------------------------------------- Dependency : golang.org/x/term Version: v0.0.0-20210615171337-6886f2dfbf5b diff --git a/go.mod b/go.mod index 4cf5253b1a1..339aadf41c4 100644 --- a/go.mod +++ b/go.mod @@ -164,6 +164,7 @@ require ( go.uber.org/zap v1.14.1 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 + golang.org/x/mod v0.5.1 golang.org/x/net v0.0.0-20211020060615-d418f374d309 golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c @@ -268,7 +269,6 @@ require ( github.com/xdg/stringprep v1.0.3 // indirect go.elastic.co/fastjson v1.1.0 // indirect go.opencensus.io v0.23.0 // indirect - golang.org/x/mod v0.5.1 // indirect golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/packetbeat/_meta/config/beat.reference.yml.tmpl b/packetbeat/_meta/config/beat.reference.yml.tmpl index 5d8d8fa9c7a..6dbc2837582 100644 --- a/packetbeat/_meta/config/beat.reference.yml.tmpl +++ b/packetbeat/_meta/config/beat.reference.yml.tmpl @@ -57,6 +57,7 @@ packetbeat.interfaces.internal_networks: # can stay enabled even after beat is shut down. #packetbeat.interfaces.auto_promisc_mode: true +{{template "windows_npcap.yml.tmpl" .}} {{header "Flows"}} packetbeat.flows: diff --git a/packetbeat/_meta/config/beat.yml.tmpl b/packetbeat/_meta/config/beat.yml.tmpl index 2a69df42517..b93a425db0c 100644 --- a/packetbeat/_meta/config/beat.yml.tmpl +++ b/packetbeat/_meta/config/beat.yml.tmpl @@ -23,6 +23,7 @@ packetbeat.interfaces.device: {{ call .device .GOOS }} packetbeat.interfaces.internal_networks: - private +{{template "windows_npcap.yml.tmpl" .}} {{header "Flows"}} # Set `enabled: false` or comment out all options to disable flows reporting. diff --git a/packetbeat/_meta/config/windows_npcap.yml.tmpl b/packetbeat/_meta/config/windows_npcap.yml.tmpl new file mode 100644 index 00000000000..6b39a7906a3 --- /dev/null +++ b/packetbeat/_meta/config/windows_npcap.yml.tmpl @@ -0,0 +1,16 @@ +{{header "Windows Npcap installation settings"}} + +# Windows Npcap installation options. These options specify how the Npcap packet +# capture library for Windows should be obtained and installed. +#npcap: +# # installer_location is either a URL or a bare path. The URL may have an http, +# # https or file scheme. If it is empty or unset, a default URL pointing to the +# # current latest version is used. +# installer_location: "" +# install_timeout: 120s +# # retain_download specifies that a downloaded installer will be kept on the host +# # filesystem and its location will be recorded in the logs. +# retain_download: false +# # By default Npcap will be installed only when a newer version of Npcap is available. +# # force_reinstall forces a new installation of Npcap in all cases. +# force_reinstall: false diff --git a/packetbeat/beater/install_npcap.go b/packetbeat/beater/install_npcap.go new file mode 100644 index 00000000000..c15657d382a --- /dev/null +++ b/packetbeat/beater/install_npcap.go @@ -0,0 +1,143 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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 +// +// http://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 beater + +import ( + "context" + "net/url" + "os" + "path/filepath" + "runtime" + "time" + + "github.com/elastic/beats/v7/libbeat/common" + "github.com/elastic/beats/v7/libbeat/logp" + "github.com/elastic/beats/v7/packetbeat/internal/npcap" +) + +func installNpcap(cfg *common.Config) error { + if runtime.GOOS != "windows" { + return nil + } + + reinstall, err := configBool(cfg, "npcap.force_reinstall") + if err != nil { + return err + } + if !npcap.Upgradeable() && !reinstall { + return nil + } + + timeout, err := configDuration(cfg, "npcap.install_timeout") + if err != nil { + return err + } + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + rawURI, err := configString(cfg, "npcap.installer_location") + if err != nil { + return err + } + if rawURI == "" { + rawURI = npcap.InstallerURL + } + uri, err := url.Parse(rawURI) + if err != nil { + return err + } + + log := logp.NewLogger("npcap_install") + + if uri.Scheme == "" || uri.Scheme == "file" { + return npcap.Install(ctx, log, uri.Path, false) + } + + retain, err := configBool(cfg, "npcap.retain_download") + if err != nil { + return err + } + + dir, err := os.MkdirTemp("", "packetbeat-npcap-*") + if err != nil { + return err + } + if retain { + log.Infof("working in %s", dir) + } else { + defer os.RemoveAll(dir) + } + path := filepath.Join(dir, npcap.CurrentVersion) + + h, err := npcap.Fetch(ctx, log, uri.String(), path) + if err != nil { + return err + } + err = npcap.Verify(path, h) + if err != nil { + return err + } + return npcap.Install(ctx, log, path, false) +} + +func configBool(cfg *common.Config, path string) (bool, error) { + ok, err := cfg.Has(path, -1) + if err != nil { + return false, err + } + if !ok { + return false, nil + } + v, err := cfg.Bool(path, -1) + if err != nil { + return false, err + } + return v, nil +} + +func configString(cfg *common.Config, path string) (string, error) { + ok, err := cfg.Has(path, -1) + if err != nil { + return "", err + } + if !ok { + return "", nil + } + v, err := cfg.String(path, -1) + if err != nil { + return "", err + } + return v, nil +} + +func configDuration(cfg *common.Config, path string) (time.Duration, error) { + const defaultTimeout = 120 * time.Second + + v, err := configString(cfg, path) + if err != nil { + return 0, err + } + if v == "" { + return defaultTimeout, nil + } + d, err := time.ParseDuration(v) + if err != nil { + return 0, err + } + return d, nil +} diff --git a/packetbeat/beater/packetbeat.go b/packetbeat/beater/packetbeat.go index d72a98d4a5f..6aed4227524 100644 --- a/packetbeat/beater/packetbeat.go +++ b/packetbeat/beater/packetbeat.go @@ -111,6 +111,12 @@ func (pb *packetbeat) Run(b *beat.Beat) error { } }() + // Install Npcap if needed. + err := installNpcap(b.BeatConfig) + if err != nil { + return err + } + if !b.Manager.Enabled() { return pb.runStatic(b, pb.factory) } diff --git a/packetbeat/internal/npcap/npcap.go b/packetbeat/internal/npcap/npcap.go new file mode 100644 index 00000000000..4f14d888ef5 --- /dev/null +++ b/packetbeat/internal/npcap/npcap.go @@ -0,0 +1,223 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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 +// +// http://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 npcap handles fetching and installing Npcap fow Windows. +package npcap + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + + "github.com/google/gopacket/pcap" + "golang.org/x/mod/semver" + + "github.com/elastic/beats/v7/libbeat/logp" +) + +// TODO: Currently the latest version is statically defined. When we have +// a location to serve from, we can make this dynamically defined with a +// function find the URL to the latest version and update Npcap for users +// without updating the beat version. + +const ( + // CurrentVersion is the current version to install. + CurrentVersion = "1.55" + + // CurrentInstaller is the executable name of the current versions installer. + CurrentInstaller = "npcap-" + CurrentVersion + "-oem.exe" + + // InstallerURL is the URL for the current Npcap version installer. + InstallerURL = "https://artifacts.elastic.co/downloads/npcap/" + CurrentInstaller // FIXME: This is a placeholder. +) + +func init() { + // This is included to ensure that if NMAP.org change their versioning + // approach we get a signal to change our ordering implementation to match. + if !semver.IsValid("v" + CurrentVersion) { + panic(fmt.Sprintf("npcap: invalid version for semver: %s", CurrentVersion)) + } +} + +// Fetch downloads the Npcap installer, writes the content to the given filepath +// and returns the sha256 hash of the downloaded object. +func Fetch(ctx context.Context, log *logp.Logger, url, path string) (hash []byte, err error) { + if runtime.GOOS != "windows" { + return nil, errors.New("npcap: called Fetch on non-Windows platform") + } + + log.Infof("download %s to %s", url, path) + + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return + } + + var client http.Client + res, err := client.Do(req) + if err != nil { + return + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + b, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Errorf("failed to read the error response body: %v", err) + } + b = bytes.TrimSpace(b) + if len(b) == 0 { + return nil, fmt.Errorf("npcap: failed to fetch %s, status: %d, message: empty", url, res.StatusCode) + } + return nil, fmt.Errorf("npcap: failed to fetch %s, status: %d, message: %s", url, res.StatusCode, b) + } + + dst, err := os.Create(path) + if err != nil { + return + } + defer dst.Close() + + h := sha256.New() + _, err = io.Copy(io.MultiWriter(h, dst), res.Body) + if err != nil { + return nil, err + } + return h.Sum(nil), nil +} + +// Verify compares the provided hash against the expected hash for the +// installer at the given path. +func Verify(path string, hash []byte) error { + base := filepath.Base(path) + h := hex.EncodeToString(hash) + want, ok := hashes[base] + if !ok { + return fmt.Errorf("npcap: unknown Npcap installer version: %s", base) + } + if want != h { + return fmt.Errorf("npcap: hash mismatch for %s: want:%s got:%s", path, want, h) + } + return nil +} + +// hashes is the mapping of Npcap installer versions to their sha256 hash. +var hashes = map[string]string{ + "npcap-1.55-oem.exe": "1f035c0498863b41b64df87099ec20f80c6db26b12d27b5afef1c1ad3fa28690", +} + +// Install runs the Npcap installer at the provided path. +func Install(ctx context.Context, log *logp.Logger, path string, compat bool) error { + if runtime.GOOS != "windows" { + return errors.New("npcap: called Install on non-Windows platform") + } + + args := []string{"/S", "/winpcap_mode=no"} + if compat { + args[1] = "/winpcap_mode=yes" + } + cmd := exec.CommandContext(ctx, path, args...) + var outBuf, errBuf bytes.Buffer + cmd.Stdout = &outBuf + cmd.Stderr = &errBuf + + err := cmd.Start() + if err != nil { + return fmt.Errorf("npcap: failed to start Npcap installer: %w", err) + } + + err = cmd.Wait() + if outBuf.Len() != 0 { + log.Info(&outBuf) + } + if err != nil { + log.Error(&errBuf) + return fmt.Errorf("npcap: failed to install Npcap: %w", err) + } + + // gopacket/pcap does not provide a mechanism to reload the pcap DLL + // so if we are upgrading we wait for the next startup of packetbeat. + // Otherwise we can make sure that the DLL is loaded by calling + // pcap.LoadWinPCAP. pcap.LoadWinPCAP is called on pcap package + // initialization and if successful, subsequent calls are no-op, but + // if Npcap/WinPCAP was not installed, it will have failed and can be + // called now. So this is safe in all cases. + err = loadWinPCAP() + + return err +} + +func Upgradeable() bool { + // pcap.Version() returns a string in the form: + // + // Npcap version 1.55, based on libpcap version 1.10.2-PRE-GIT + // + // if an Npcap version is installed. See https://nmap.org/npcap/guide/npcap-devguide.html#npcap-detect + installed := pcap.Version() + if !strings.HasPrefix(installed, "Npcap version") { + return true + } + installed = strings.TrimPrefix(installed, "Npcap version ") + idx := strings.Index(installed, ",") + if idx < 0 { + return true + } + installed = installed[:idx] + return semver.Compare("v"+installed, "v"+CurrentVersion) < 0 +} + +// Uninstall uninstalls the Npcap tools. +func Uninstall(ctx context.Context, log *logp.Logger) error { + if runtime.GOOS != "windows" { + return errors.New("npcap: called Uninstall on non-Windows platform") + } + if pcap.Version() == "" { + return nil + } + + const uninstaller = `C:\Program Files\Npcap\Uninstall.exe` + cmd := exec.CommandContext(ctx, uninstaller, `/S`) + var outBuf, errBuf bytes.Buffer + cmd.Stdout = &outBuf + cmd.Stderr = &errBuf + + err := cmd.Start() + if err != nil { + return fmt.Errorf("npcap: failed to start Npcap uninstaller: %w", err) + } + + err = cmd.Wait() + if outBuf.Len() != 0 { + log.Info(&outBuf) + } + if err != nil { + log.Error(&errBuf) + return fmt.Errorf("npcap: failed to uninstall Npcap: %w", err) + } + return nil +} diff --git a/packetbeat/internal/npcap/npcap_other.go b/packetbeat/internal/npcap/npcap_other.go new file mode 100644 index 00000000000..47fc8a8bd6a --- /dev/null +++ b/packetbeat/internal/npcap/npcap_other.go @@ -0,0 +1,23 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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 +// +// http://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. + +//go:build !windows +// +build !windows + +package npcap + +func loadWinPCAP() error { return nil } diff --git a/packetbeat/internal/npcap/npcap_windows.go b/packetbeat/internal/npcap/npcap_windows.go new file mode 100644 index 00000000000..36a8a72900c --- /dev/null +++ b/packetbeat/internal/npcap/npcap_windows.go @@ -0,0 +1,25 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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 +// +// http://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. + +//go:build windows +// +build windows + +package npcap + +import "github.com/google/gopacket/pcap" + +func loadWinPCAP() error { return pcap.LoadWinPCAP() } diff --git a/packetbeat/internal/npcap/npcap_windows_test.go b/packetbeat/internal/npcap/npcap_windows_test.go new file mode 100644 index 00000000000..9265ad20d02 --- /dev/null +++ b/packetbeat/internal/npcap/npcap_windows_test.go @@ -0,0 +1,94 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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 +// +// http://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. + +//go:build windows +// +build windows + +package npcap + +import ( + "context" + "io" + "net/http" + "net/http/httptest" + "os" + "os/exec" + "path/filepath" + "testing" + + "github.com/elastic/beats/v7/libbeat/logp" +) + +func TestNpcap(t *testing.T) { + const installer = "This is an installer. Honest!\n" + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + io.WriteString(w, installer) + })) + defer srv.Close() + + dir, err := os.MkdirTemp("", "packetbeat-npcap-*") + if err != nil { + t.Fatalf("failed to create working directory: %v", err) + } + defer os.RemoveAll(dir) + path := filepath.Join(dir, CurrentInstaller) + + var hash []byte + t.Run("Fetch", func(t *testing.T) { + log := logp.NewLogger("npcap_test_fetch") + hash, err = Fetch(context.Background(), log, srv.URL, path) + if err != nil { + t.Fatalf("failed to fetch installer: %v", err) + } + + got, err := os.ReadFile(path) + if err != nil { + t.Fatalf("failed to read artifact: %v", err) + } + if string(got) != installer { + t.Errorf("unexpected download: got:%q want:%q", got, installer) + } + }) + + t.Run("Verify", func(t *testing.T) { + // Dirty global manipulation. Tests may not be run in parallel. + hashes["test-artifact"] = "bc3e42210a58873b55554af5100db1f9439b606efde4fd20c98d7af2d6c5419b" + defer delete(hashes, "test-artifact") + + err = Verify("test-artifact", hash) + if err != nil { + t.Errorf("failed to verify download: %v", err) + } + }) + + t.Run("Install", func(t *testing.T) { + err := os.Remove(path) + if err != nil { + t.Fatalf("failed to remove download: %v", err) + } + build := exec.Command("go", "build", "-o", path, filepath.FromSlash("testdata/mock_installer.go")) + b, err := build.CombinedOutput() + if err != nil { + t.Fatalf("failed to build mock installer: %v\n%s", err, b) + } + log := logp.NewLogger("npcap_test_install") + err = Install(context.Background(), log, path, false) + if err != nil { + t.Errorf("unexpected error running installer: %v", err) + } + }) +} diff --git a/packetbeat/internal/npcap/testdata/mock_installer.go b/packetbeat/internal/npcap/testdata/mock_installer.go new file mode 100644 index 00000000000..d0c310519d8 --- /dev/null +++ b/packetbeat/internal/npcap/testdata/mock_installer.go @@ -0,0 +1,35 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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 +// +// http://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 ( + "log" + "os" +) + +func main() { + if len(os.Args) != 3 { + log.Fatalf("unexpected number of argument: want 3 but got:%q", os.Args) + } + if os.Args[1] != "/S" { + log.Fatalf(`unexpected first argument: want:"/S" got:%q`, os.Args[1]) + } + if os.Args[2] != "/winpcap_mode=yes" && os.Args[2] != "/winpcap_mode=no" { + log.Fatalf(`unexpected second argument: want:"/winpcap_mode={yes,no}" got:%q`, os.Args[2]) + } +} diff --git a/packetbeat/packetbeat.reference.yml b/packetbeat/packetbeat.reference.yml index 3d9d0f604bf..62aff3c1d9c 100644 --- a/packetbeat/packetbeat.reference.yml +++ b/packetbeat/packetbeat.reference.yml @@ -57,6 +57,23 @@ packetbeat.interfaces.internal_networks: # can stay enabled even after beat is shut down. #packetbeat.interfaces.auto_promisc_mode: true +# ==================== Windows Npcap installation settings ===================== + +# Windows Npcap installation options. These options specify how the Npcap packet +# capture library for Windows should be obtained and installed. +#npcap: +# # installer_location is either a URL or a bare path. The URL may have an http, +# # https or file scheme. If it is empty or unset, a default URL pointing to the +# # current latest version is used. +# installer_location: "" +# install_timeout: 120s +# # retain_download specifies that a downloaded installer will be kept on the host +# # filesystem and its location will be recorded in the logs. +# retain_download: false +# # By default Npcap will be installed only when a newer version of Npcap is available. +# # force_reinstall forces a new installation of Npcap in all cases. +# force_reinstall: false + # =================================== Flows ==================================== packetbeat.flows: diff --git a/packetbeat/packetbeat.yml b/packetbeat/packetbeat.yml index 15a0df9ebd1..b0e21e36ce1 100644 --- a/packetbeat/packetbeat.yml +++ b/packetbeat/packetbeat.yml @@ -23,6 +23,23 @@ packetbeat.interfaces.device: any packetbeat.interfaces.internal_networks: - private +# ==================== Windows Npcap installation settings ===================== + +# Windows Npcap installation options. These options specify how the Npcap packet +# capture library for Windows should be obtained and installed. +#npcap: +# # installer_location is either a URL or a bare path. The URL may have an http, +# # https or file scheme. If it is empty or unset, a default URL pointing to the +# # current latest version is used. +# installer_location: "" +# install_timeout: 120s +# # retain_download specifies that a downloaded installer will be kept on the host +# # filesystem and its location will be recorded in the logs. +# retain_download: false +# # By default Npcap will be installed only when a newer version of Npcap is available. +# # force_reinstall forces a new installation of Npcap in all cases. +# force_reinstall: false + # =================================== Flows ==================================== # Set `enabled: false` or comment out all options to disable flows reporting. diff --git a/x-pack/packetbeat/packetbeat.reference.yml b/x-pack/packetbeat/packetbeat.reference.yml index 3d9d0f604bf..62aff3c1d9c 100644 --- a/x-pack/packetbeat/packetbeat.reference.yml +++ b/x-pack/packetbeat/packetbeat.reference.yml @@ -57,6 +57,23 @@ packetbeat.interfaces.internal_networks: # can stay enabled even after beat is shut down. #packetbeat.interfaces.auto_promisc_mode: true +# ==================== Windows Npcap installation settings ===================== + +# Windows Npcap installation options. These options specify how the Npcap packet +# capture library for Windows should be obtained and installed. +#npcap: +# # installer_location is either a URL or a bare path. The URL may have an http, +# # https or file scheme. If it is empty or unset, a default URL pointing to the +# # current latest version is used. +# installer_location: "" +# install_timeout: 120s +# # retain_download specifies that a downloaded installer will be kept on the host +# # filesystem and its location will be recorded in the logs. +# retain_download: false +# # By default Npcap will be installed only when a newer version of Npcap is available. +# # force_reinstall forces a new installation of Npcap in all cases. +# force_reinstall: false + # =================================== Flows ==================================== packetbeat.flows: diff --git a/x-pack/packetbeat/packetbeat.yml b/x-pack/packetbeat/packetbeat.yml index 15a0df9ebd1..b0e21e36ce1 100644 --- a/x-pack/packetbeat/packetbeat.yml +++ b/x-pack/packetbeat/packetbeat.yml @@ -23,6 +23,23 @@ packetbeat.interfaces.device: any packetbeat.interfaces.internal_networks: - private +# ==================== Windows Npcap installation settings ===================== + +# Windows Npcap installation options. These options specify how the Npcap packet +# capture library for Windows should be obtained and installed. +#npcap: +# # installer_location is either a URL or a bare path. The URL may have an http, +# # https or file scheme. If it is empty or unset, a default URL pointing to the +# # current latest version is used. +# installer_location: "" +# install_timeout: 120s +# # retain_download specifies that a downloaded installer will be kept on the host +# # filesystem and its location will be recorded in the logs. +# retain_download: false +# # By default Npcap will be installed only when a newer version of Npcap is available. +# # force_reinstall forces a new installation of Npcap in all cases. +# force_reinstall: false + # =================================== Flows ==================================== # Set `enabled: false` or comment out all options to disable flows reporting. From e58c8322e4fc110ec2644b441e88eae147110dde Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Wed, 24 Nov 2021 16:58:06 +1030 Subject: [PATCH 02/26] packetbeat: use a remote registry --- packetbeat/beater/install_npcap.go | 42 ++++--- packetbeat/internal/npcap/npcap.go | 113 ++++++++++-------- .../internal/npcap/npcap_windows_test.go | 68 ++++++++--- 3 files changed, 142 insertions(+), 81 deletions(-) diff --git a/packetbeat/beater/install_npcap.go b/packetbeat/beater/install_npcap.go index c15657d382a..c350126f887 100644 --- a/packetbeat/beater/install_npcap.go +++ b/packetbeat/beater/install_npcap.go @@ -19,8 +19,10 @@ package beater import ( "context" + "fmt" "net/url" "os" + "path" "path/filepath" "runtime" "time" @@ -39,35 +41,42 @@ func installNpcap(cfg *common.Config) error { if err != nil { return err } - if !npcap.Upgradeable() && !reinstall { - return nil - } - timeout, err := configDuration(cfg, "npcap.install_timeout") if err != nil { return err } - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - rawURI, err := configString(cfg, "npcap.installer_location") if err != nil { return err } if rawURI == "" { - rawURI = npcap.InstallerURL + rawURI = npcap.Registry } + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + log := logp.NewLogger("npcap_install") + uri, err := url.Parse(rawURI) if err != nil { return err } - - log := logp.NewLogger("npcap_install") - + // If a file or bare path is specified, go ahead and install it. if uri.Scheme == "" || uri.Scheme == "file" { return npcap.Install(ctx, log, uri.Path, false) } + version, download, wantHash, err := npcap.CurrentVersion(ctx, log, rawURI) + if err != nil { + return err + } + + // Is a more recent version available or are we forcing install. + if !npcap.Upgradeable(version) && !reinstall { + return nil + } + retain, err := configBool(cfg, "npcap.retain_download") if err != nil { return err @@ -82,16 +91,17 @@ func installNpcap(cfg *common.Config) error { } else { defer os.RemoveAll(dir) } - path := filepath.Join(dir, npcap.CurrentVersion) + path := filepath.Join(dir, path.Base(download)) - h, err := npcap.Fetch(ctx, log, uri.String(), path) + gotHash, err := npcap.Fetch(ctx, log, download, path) if err != nil { return err } - err = npcap.Verify(path, h) - if err != nil { - return err + + if gotHash != wantHash { + return fmt.Errorf("npcap: hash mismatch for %s: want:%s got:%s", download, wantHash, gotHash) } + return npcap.Install(ctx, log, path, false) } diff --git a/packetbeat/internal/npcap/npcap.go b/packetbeat/internal/npcap/npcap.go index 4f14d888ef5..5ae8636cc34 100644 --- a/packetbeat/internal/npcap/npcap.go +++ b/packetbeat/internal/npcap/npcap.go @@ -16,6 +16,18 @@ // under the License. // Package npcap handles fetching and installing Npcap fow Windows. +// +// The npcap package interacts with a registry and download server that +// provides a current_version end point that serves a JSON message that +// corresponds to the this Go type: +// +// struct { +// Version string // The semverish version of the Npcap installer. +// URL string // The location of the Npcap installer. +// Hash string // The sha256 hash of the Npcap installer. +// } +// +// The URL field will point to the location of anb Npcap installer. package npcap import ( @@ -23,6 +35,7 @@ import ( "context" "crypto/sha256" "encoding/hex" + "encoding/json" "errors" "fmt" "io" @@ -30,7 +43,6 @@ import ( "net/http" "os" "os/exec" - "path/filepath" "runtime" "strings" @@ -40,48 +52,71 @@ import ( "github.com/elastic/beats/v7/libbeat/logp" ) -// TODO: Currently the latest version is statically defined. When we have -// a location to serve from, we can make this dynamically defined with a -// function find the URL to the latest version and update Npcap for users -// without updating the beat version. +// Registry is the location of current Npcap version information. +const Registry = "https://artifacts.elastic.co/downloads/npcap/current_version" -const ( - // CurrentVersion is the current version to install. - CurrentVersion = "1.55" +// Fetch downloads the Npcap installer, writes the content to the given filepath +// and returns the sha256 hash of the downloaded object. +func CurrentVersion(ctx context.Context, log *logp.Logger, registry string) (version, url, hash string, err error) { + if runtime.GOOS != "windows" { + return "", "", "", errors.New("npcap: called Fetch on non-Windows platform") + } - // CurrentInstaller is the executable name of the current versions installer. - CurrentInstaller = "npcap-" + CurrentVersion + "-oem.exe" + req, err := http.NewRequestWithContext(ctx, "GET", registry, nil) + if err != nil { + return "", "", "", err + } - // InstallerURL is the URL for the current Npcap version installer. - InstallerURL = "https://artifacts.elastic.co/downloads/npcap/" + CurrentInstaller // FIXME: This is a placeholder. -) + var client http.Client + res, err := client.Do(req) + if err != nil { + return "", "", "", err + } + defer res.Body.Close() + + b, err := ioutil.ReadAll(res.Body) + if res.StatusCode != http.StatusOK { + if err != nil { + log.Errorf("failed to read the error response body: %v", err) + } + b = bytes.TrimSpace(b) + if len(b) == 0 { + return "", "", "", fmt.Errorf("npcap: failed to fetch %s, status: %d, message: empty", url, res.StatusCode) + } + return "", "", "", fmt.Errorf("npcap: failed to fetch %s, status: %d, message: %s", url, res.StatusCode, b) + } -func init() { - // This is included to ensure that if NMAP.org change their versioning - // approach we get a signal to change our ordering implementation to match. - if !semver.IsValid("v" + CurrentVersion) { - panic(fmt.Sprintf("npcap: invalid version for semver: %s", CurrentVersion)) + var info struct { + Version string + URL string + Hash string + } + err = json.Unmarshal(b, &info) + if err != nil { + return "", "", "", err } + + return info.Version, info.URL, info.Hash, nil } // Fetch downloads the Npcap installer, writes the content to the given filepath // and returns the sha256 hash of the downloaded object. -func Fetch(ctx context.Context, log *logp.Logger, url, path string) (hash []byte, err error) { +func Fetch(ctx context.Context, log *logp.Logger, url, path string) (hash string, err error) { if runtime.GOOS != "windows" { - return nil, errors.New("npcap: called Fetch on non-Windows platform") + return "", errors.New("npcap: called Fetch on non-Windows platform") } log.Infof("download %s to %s", url, path) req, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { - return + return "", err } var client http.Client res, err := client.Do(req) if err != nil { - return + return "", err } defer res.Body.Close() @@ -92,43 +127,23 @@ func Fetch(ctx context.Context, log *logp.Logger, url, path string) (hash []byte } b = bytes.TrimSpace(b) if len(b) == 0 { - return nil, fmt.Errorf("npcap: failed to fetch %s, status: %d, message: empty", url, res.StatusCode) + return "", fmt.Errorf("npcap: failed to fetch %s, status: %d, message: empty", url, res.StatusCode) } - return nil, fmt.Errorf("npcap: failed to fetch %s, status: %d, message: %s", url, res.StatusCode, b) + return "", fmt.Errorf("npcap: failed to fetch %s, status: %d, message: %s", url, res.StatusCode, b) } dst, err := os.Create(path) if err != nil { - return + return "", err } defer dst.Close() h := sha256.New() _, err = io.Copy(io.MultiWriter(h, dst), res.Body) if err != nil { - return nil, err - } - return h.Sum(nil), nil -} - -// Verify compares the provided hash against the expected hash for the -// installer at the given path. -func Verify(path string, hash []byte) error { - base := filepath.Base(path) - h := hex.EncodeToString(hash) - want, ok := hashes[base] - if !ok { - return fmt.Errorf("npcap: unknown Npcap installer version: %s", base) + return "", err } - if want != h { - return fmt.Errorf("npcap: hash mismatch for %s: want:%s got:%s", path, want, h) - } - return nil -} - -// hashes is the mapping of Npcap installer versions to their sha256 hash. -var hashes = map[string]string{ - "npcap-1.55-oem.exe": "1f035c0498863b41b64df87099ec20f80c6db26b12d27b5afef1c1ad3fa28690", + return hex.EncodeToString(h.Sum(nil)), nil } // Install runs the Npcap installer at the provided path. @@ -172,7 +187,7 @@ func Install(ctx context.Context, log *logp.Logger, path string, compat bool) er return err } -func Upgradeable() bool { +func Upgradeable(version string) bool { // pcap.Version() returns a string in the form: // // Npcap version 1.55, based on libpcap version 1.10.2-PRE-GIT @@ -188,7 +203,7 @@ func Upgradeable() bool { return true } installed = installed[:idx] - return semver.Compare("v"+installed, "v"+CurrentVersion) < 0 + return semver.Compare("v"+installed, "v"+version) < 0 } // Uninstall uninstalls the Npcap tools. diff --git a/packetbeat/internal/npcap/npcap_windows_test.go b/packetbeat/internal/npcap/npcap_windows_test.go index 9265ad20d02..53d68eba2f1 100644 --- a/packetbeat/internal/npcap/npcap_windows_test.go +++ b/packetbeat/internal/npcap/npcap_windows_test.go @@ -25,6 +25,7 @@ import ( "io" "net/http" "net/http/httptest" + "net/url" "os" "os/exec" "path/filepath" @@ -34,23 +35,66 @@ import ( ) func TestNpcap(t *testing.T) { - const installer = "This is an installer. Honest!\n" - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + // Elements of truth. + const ( + registryEndPoint = "/npcap/latest_installer" + latestVersion = "0.0" + latestInstaller = "npcap-0.0-oem.exe" + latestHash = "bc3e42210a58873b55554af5100db1f9439b606efde4fd20c98d7af2d6c5419b" + latestInstallerPath = "/npcap/" + latestInstaller + installer = "This is an installer. Honest!\n" + ) + var latestVersionInfo string + + // Mock registry and download server. + mux := http.NewServeMux() + mux.HandleFunc(registryEndPoint, func(w http.ResponseWriter, req *http.Request) { + io.WriteString(w, latestVersionInfo) + }) + mux.HandleFunc(latestInstallerPath, func(w http.ResponseWriter, req *http.Request) { io.WriteString(w, installer) - })) + }) + srv := httptest.NewServer(mux) + u, err := url.Parse(srv.URL) + if err != nil { + t.Fatalf("failed to parse server root URL: %v", err) + } + u.Path = latestInstallerPath + latestInstallerURL := u.String() + latestVersionInfo = `{"url":"` + latestInstallerURL + `","version":"` + latestVersion + `","hash":"` + latestHash + `"}` defer srv.Close() + // Working space. dir, err := os.MkdirTemp("", "packetbeat-npcap-*") if err != nil { t.Fatalf("failed to create working directory: %v", err) } defer os.RemoveAll(dir) - path := filepath.Join(dir, CurrentInstaller) + path := filepath.Join(dir, latestVersion) + + t.Run("Query Version", func(t *testing.T) { + u.Path = registryEndPoint + + log := logp.NewLogger("npcap_test_query_version") + gotVersion, gotURL, gotHash, err := CurrentVersion(context.Background(), log, u.String()) + if err != nil { + t.Fatalf("failed to fetch installer: %v", err) + } + + if gotVersion != latestVersion { + t.Errorf("unexpected version: got:%q want:%q", gotVersion, latestVersion) + } + if gotURL != latestInstallerURL { + t.Errorf("unexpected download location: got:%q want:%q", gotURL, latestInstallerURL) + } + if gotHash != latestHash { + t.Errorf("unexpected hash: got:%q want:%q", gotHash, latestHash) + } + }) - var hash []byte t.Run("Fetch", func(t *testing.T) { log := logp.NewLogger("npcap_test_fetch") - hash, err = Fetch(context.Background(), log, srv.URL, path) + hash, err := Fetch(context.Background(), log, latestInstallerURL, path) if err != nil { t.Fatalf("failed to fetch installer: %v", err) } @@ -62,16 +106,8 @@ func TestNpcap(t *testing.T) { if string(got) != installer { t.Errorf("unexpected download: got:%q want:%q", got, installer) } - }) - - t.Run("Verify", func(t *testing.T) { - // Dirty global manipulation. Tests may not be run in parallel. - hashes["test-artifact"] = "bc3e42210a58873b55554af5100db1f9439b606efde4fd20c98d7af2d6c5419b" - defer delete(hashes, "test-artifact") - - err = Verify("test-artifact", hash) - if err != nil { - t.Errorf("failed to verify download: %v", err) + if hash != latestHash { + t.Errorf("unexpected download hash: got:%s want:%s", hash, latestHash) } }) From 59a33e62a1d9a4c769cc2535a321a9419b98a924 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 25 Nov 2021 08:09:37 +1030 Subject: [PATCH 03/26] packetbeat: allow specification of Npcap install location Also make test failures log mock installer output. --- .../_meta/config/windows_npcap.yml.tmpl | 3 + packetbeat/beater/install_npcap.go | 13 +++-- packetbeat/internal/npcap/npcap.go | 40 +++++++++++-- .../{npcap_windows_test.go => npcap_test.go} | 57 ++++++++++++++++--- .../internal/npcap/testdata/mock_installer.go | 13 ++++- .../npcap/testdata/mock_uninstaller.go | 34 +++++++++++ packetbeat/packetbeat.reference.yml | 3 + packetbeat/packetbeat.yml | 3 + x-pack/packetbeat/packetbeat.reference.yml | 3 + x-pack/packetbeat/packetbeat.yml | 3 + 10 files changed, 154 insertions(+), 18 deletions(-) rename packetbeat/internal/npcap/{npcap_windows_test.go => npcap_test.go} (71%) create mode 100644 packetbeat/internal/npcap/testdata/mock_uninstaller.go diff --git a/packetbeat/_meta/config/windows_npcap.yml.tmpl b/packetbeat/_meta/config/windows_npcap.yml.tmpl index 6b39a7906a3..07c399c37d1 100644 --- a/packetbeat/_meta/config/windows_npcap.yml.tmpl +++ b/packetbeat/_meta/config/windows_npcap.yml.tmpl @@ -7,6 +7,9 @@ # # https or file scheme. If it is empty or unset, a default URL pointing to the # # current latest version is used. # installer_location: "" +# # install_destination allows configuration of the location that the Npcap will +# # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. +# install_destination: "" # install_timeout: 120s # # retain_download specifies that a downloaded installer will be kept on the host # # filesystem and its location will be recorded in the logs. diff --git a/packetbeat/beater/install_npcap.go b/packetbeat/beater/install_npcap.go index c350126f887..739c4a4d2c2 100644 --- a/packetbeat/beater/install_npcap.go +++ b/packetbeat/beater/install_npcap.go @@ -49,6 +49,10 @@ func installNpcap(cfg *common.Config) error { if err != nil { return err } + installDst, err := configString(cfg, "npcap.install_destination") + if err != nil { + return err + } if rawURI == "" { rawURI = npcap.Registry } @@ -62,9 +66,10 @@ func installNpcap(cfg *common.Config) error { if err != nil { return err } + // If a file or bare path is specified, go ahead and install it. if uri.Scheme == "" || uri.Scheme == "file" { - return npcap.Install(ctx, log, uri.Path, false) + return npcap.Install(ctx, log, uri.Path, installDst, false) } version, download, wantHash, err := npcap.CurrentVersion(ctx, log, rawURI) @@ -91,9 +96,9 @@ func installNpcap(cfg *common.Config) error { } else { defer os.RemoveAll(dir) } - path := filepath.Join(dir, path.Base(download)) + pth := filepath.Join(dir, path.Base(download)) - gotHash, err := npcap.Fetch(ctx, log, download, path) + gotHash, err := npcap.Fetch(ctx, log, download, pth) if err != nil { return err } @@ -102,7 +107,7 @@ func installNpcap(cfg *common.Config) error { return fmt.Errorf("npcap: hash mismatch for %s: want:%s got:%s", download, wantHash, gotHash) } - return npcap.Install(ctx, log, path, false) + return npcap.Install(ctx, log, pth, installDst, false) } func configBool(cfg *common.Config, path string) (bool, error) { diff --git a/packetbeat/internal/npcap/npcap.go b/packetbeat/internal/npcap/npcap.go index 5ae8636cc34..8a12a03296d 100644 --- a/packetbeat/internal/npcap/npcap.go +++ b/packetbeat/internal/npcap/npcap.go @@ -61,7 +61,10 @@ func CurrentVersion(ctx context.Context, log *logp.Logger, registry string) (ver if runtime.GOOS != "windows" { return "", "", "", errors.New("npcap: called Fetch on non-Windows platform") } + return currentVersion(ctx, log, registry) +} +func currentVersion(ctx context.Context, log *logp.Logger, registry string) (version, url, hash string, err error) { req, err := http.NewRequestWithContext(ctx, "GET", registry, nil) if err != nil { return "", "", "", err @@ -105,7 +108,10 @@ func Fetch(ctx context.Context, log *logp.Logger, url, path string) (hash string if runtime.GOOS != "windows" { return "", errors.New("npcap: called Fetch on non-Windows platform") } + return fetch(ctx, log, url, path) +} +func fetch(ctx context.Context, log *logp.Logger, url, path string) (hash string, err error) { log.Infof("download %s to %s", url, path) req, err := http.NewRequestWithContext(ctx, "GET", url, nil) @@ -146,16 +152,30 @@ func Fetch(ctx context.Context, log *logp.Logger, url, path string) (hash string return hex.EncodeToString(h.Sum(nil)), nil } -// Install runs the Npcap installer at the provided path. -func Install(ctx context.Context, log *logp.Logger, path string, compat bool) error { +// Install runs the Npcap installer at the provided path. The install +// destination is specified by dst and installation using WinPcap +// API-compatible Mode is specifed by compat. If dst is the empty string +// the default install location is used. +// +// See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options +// for details. +func Install(ctx context.Context, log *logp.Logger, path, dst string, compat bool) error { if runtime.GOOS != "windows" { return errors.New("npcap: called Install on non-Windows platform") } + return install(ctx, log, path, dst, compat) +} +func install(ctx context.Context, log *logp.Logger, path, dst string, compat bool) error { args := []string{"/S", "/winpcap_mode=no"} if compat { args[1] = "/winpcap_mode=yes" } + if dst != "" { + // The destination switch must be last as it uses unquoted spaces. + // See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. + args = append(args, "/D="+dst) + } cmd := exec.CommandContext(ctx, path, args...) var outBuf, errBuf bytes.Buffer cmd.Stdout = &outBuf @@ -206,17 +226,27 @@ func Upgradeable(version string) bool { return semver.Compare("v"+installed, "v"+version) < 0 } -// Uninstall uninstalls the Npcap tools. -func Uninstall(ctx context.Context, log *logp.Logger) error { +// Uninstall uninstalls the Npcap tools. The path to the uninstaller can +// be provided, otherwise the default install location in used. +// +// See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options +// for details. +func Uninstall(ctx context.Context, log *logp.Logger, path string) error { if runtime.GOOS != "windows" { return errors.New("npcap: called Uninstall on non-Windows platform") } if pcap.Version() == "" { return nil } + return uninstall(ctx, log, path) +} +func uninstall(ctx context.Context, log *logp.Logger, path string) error { const uninstaller = `C:\Program Files\Npcap\Uninstall.exe` - cmd := exec.CommandContext(ctx, uninstaller, `/S`) + if path == "" { + path = uninstaller + } + cmd := exec.CommandContext(ctx, path, `/S`) var outBuf, errBuf bytes.Buffer cmd.Stdout = &outBuf cmd.Stderr = &errBuf diff --git a/packetbeat/internal/npcap/npcap_windows_test.go b/packetbeat/internal/npcap/npcap_test.go similarity index 71% rename from packetbeat/internal/npcap/npcap_windows_test.go rename to packetbeat/internal/npcap/npcap_test.go index 53d68eba2f1..da31d6b25b8 100644 --- a/packetbeat/internal/npcap/npcap_windows_test.go +++ b/packetbeat/internal/npcap/npcap_test.go @@ -15,9 +15,6 @@ // specific language governing permissions and limitations // under the License. -//go:build windows -// +build windows - package npcap import ( @@ -46,6 +43,12 @@ func TestNpcap(t *testing.T) { ) var latestVersionInfo string + // Ugh. + var lcfg logp.Config + logp.ToObserverOutput()(&lcfg) + logp.Configure(lcfg) + obs := logp.ObserverLogs() + // Mock registry and download server. mux := http.NewServeMux() mux.HandleFunc(registryEndPoint, func(w http.ResponseWriter, req *http.Request) { @@ -76,9 +79,13 @@ func TestNpcap(t *testing.T) { u.Path = registryEndPoint log := logp.NewLogger("npcap_test_query_version") - gotVersion, gotURL, gotHash, err := CurrentVersion(context.Background(), log, u.String()) + gotVersion, gotURL, gotHash, err := currentVersion(context.Background(), log, u.String()) + messages := obs.TakeAll() if err != nil { t.Fatalf("failed to fetch installer: %v", err) + for _, e := range messages { + t.Log(e.Message) + } } if gotVersion != latestVersion { @@ -94,9 +101,13 @@ func TestNpcap(t *testing.T) { t.Run("Fetch", func(t *testing.T) { log := logp.NewLogger("npcap_test_fetch") - hash, err := Fetch(context.Background(), log, latestInstallerURL, path) + hash, err := fetch(context.Background(), log, latestInstallerURL, path) + messages := obs.TakeAll() if err != nil { t.Fatalf("failed to fetch installer: %v", err) + for _, e := range messages { + t.Log(e.Message) + } } got, err := os.ReadFile(path) @@ -122,9 +133,41 @@ func TestNpcap(t *testing.T) { t.Fatalf("failed to build mock installer: %v\n%s", err, b) } log := logp.NewLogger("npcap_test_install") - err = Install(context.Background(), log, path, false) + for _, compat := range []bool{false, true} { + for _, dst := range []string{ + "", // Default. + `C:\some\other\location`, + } { + err = install(context.Background(), log, path, dst, compat) + messages := obs.TakeAll() + if err != nil { + if dst == "" { + dst = "default location" + } + t.Errorf("unexpected error running installer to %s with compat=%t: %v", dst, compat, err) + for _, e := range messages { + t.Log(e.Message) + } + } + } + } + }) + + t.Run("Uninstall", func(t *testing.T) { + path = filepath.Join(filepath.Dir(path), "Uninstall.exe") + build := exec.Command("go", "build", "-o", path, filepath.FromSlash("testdata/mock_uninstaller.go")) + b, err := build.CombinedOutput() + if err != nil { + t.Fatalf("failed to build mock uninstaller: %v\n%s", err, b) + } + log := logp.NewLogger("npcap_test_uninstall") + err = uninstall(context.Background(), log, path) + messages := obs.TakeAll() if err != nil { - t.Errorf("unexpected error running installer: %v", err) + t.Errorf("unexpected error running uninstaller: %v", err) + for _, e := range messages { + t.Log(e.Message) + } } }) } diff --git a/packetbeat/internal/npcap/testdata/mock_installer.go b/packetbeat/internal/npcap/testdata/mock_installer.go index d0c310519d8..cb82464d8b0 100644 --- a/packetbeat/internal/npcap/testdata/mock_installer.go +++ b/packetbeat/internal/npcap/testdata/mock_installer.go @@ -20,11 +20,17 @@ package main import ( "log" "os" + "strings" ) func main() { - if len(os.Args) != 3 { - log.Fatalf("unexpected number of argument: want 3 but got:%q", os.Args) + log.SetFlags(0) + log.SetPrefix("installer message: ") + switch len(os.Args) { + case 3, 4: + // OK + default: + log.Fatalf("unexpected number of argument: want 3 or 4 but got:%q", os.Args) } if os.Args[1] != "/S" { log.Fatalf(`unexpected first argument: want:"/S" got:%q`, os.Args[1]) @@ -32,4 +38,7 @@ func main() { if os.Args[2] != "/winpcap_mode=yes" && os.Args[2] != "/winpcap_mode=no" { log.Fatalf(`unexpected second argument: want:"/winpcap_mode={yes,no}" got:%q`, os.Args[2]) } + if len(os.Args) > 3 && !strings.HasPrefix(os.Args[len(os.Args)-1], "/D=") { + log.Fatalf(`unexpected final argument: want:"/D=" got:%#q`, os.Args[3]) + } } diff --git a/packetbeat/internal/npcap/testdata/mock_uninstaller.go b/packetbeat/internal/npcap/testdata/mock_uninstaller.go new file mode 100644 index 00000000000..f86472cb990 --- /dev/null +++ b/packetbeat/internal/npcap/testdata/mock_uninstaller.go @@ -0,0 +1,34 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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 +// +// http://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 ( + "log" + "os" +) + +func main() { + log.SetFlags(0) + log.SetPrefix("uninstaller message: ") + if len(os.Args) != 2 { + log.Fatalf("unexpected number of argument: want 2 but got:%q", os.Args) + } + if os.Args[1] != "/S" { + log.Fatalf(`unexpected first argument: want:"/S" got:%q`, os.Args[1]) + } +} diff --git a/packetbeat/packetbeat.reference.yml b/packetbeat/packetbeat.reference.yml index 62aff3c1d9c..86159d479ca 100644 --- a/packetbeat/packetbeat.reference.yml +++ b/packetbeat/packetbeat.reference.yml @@ -66,6 +66,9 @@ packetbeat.interfaces.internal_networks: # # https or file scheme. If it is empty or unset, a default URL pointing to the # # current latest version is used. # installer_location: "" +# # install_destination allows configuration of the location that the Npcap will +# # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. +# install_destination: "" # install_timeout: 120s # # retain_download specifies that a downloaded installer will be kept on the host # # filesystem and its location will be recorded in the logs. diff --git a/packetbeat/packetbeat.yml b/packetbeat/packetbeat.yml index b0e21e36ce1..5f6e508ebbb 100644 --- a/packetbeat/packetbeat.yml +++ b/packetbeat/packetbeat.yml @@ -32,6 +32,9 @@ packetbeat.interfaces.internal_networks: # # https or file scheme. If it is empty or unset, a default URL pointing to the # # current latest version is used. # installer_location: "" +# # install_destination allows configuration of the location that the Npcap will +# # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. +# install_destination: "" # install_timeout: 120s # # retain_download specifies that a downloaded installer will be kept on the host # # filesystem and its location will be recorded in the logs. diff --git a/x-pack/packetbeat/packetbeat.reference.yml b/x-pack/packetbeat/packetbeat.reference.yml index 62aff3c1d9c..86159d479ca 100644 --- a/x-pack/packetbeat/packetbeat.reference.yml +++ b/x-pack/packetbeat/packetbeat.reference.yml @@ -66,6 +66,9 @@ packetbeat.interfaces.internal_networks: # # https or file scheme. If it is empty or unset, a default URL pointing to the # # current latest version is used. # installer_location: "" +# # install_destination allows configuration of the location that the Npcap will +# # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. +# install_destination: "" # install_timeout: 120s # # retain_download specifies that a downloaded installer will be kept on the host # # filesystem and its location will be recorded in the logs. diff --git a/x-pack/packetbeat/packetbeat.yml b/x-pack/packetbeat/packetbeat.yml index b0e21e36ce1..5f6e508ebbb 100644 --- a/x-pack/packetbeat/packetbeat.yml +++ b/x-pack/packetbeat/packetbeat.yml @@ -32,6 +32,9 @@ packetbeat.interfaces.internal_networks: # # https or file scheme. If it is empty or unset, a default URL pointing to the # # current latest version is used. # installer_location: "" +# # install_destination allows configuration of the location that the Npcap will +# # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. +# install_destination: "" # install_timeout: 120s # # retain_download specifies that a downloaded installer will be kept on the host # # filesystem and its location will be recorded in the logs. From 0be3fa539dbab0eee596b986f858223b5aeef1d0 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 25 Nov 2021 11:12:43 +1030 Subject: [PATCH 04/26] packetbeat: fix error handling and make failure an option --- .../_meta/config/windows_npcap.yml.tmpl | 3 ++ packetbeat/beater/install_npcap.go | 9 ++++++ packetbeat/internal/npcap/npcap.go | 32 +++++++++++++------ packetbeat/packetbeat.reference.yml | 3 ++ packetbeat/packetbeat.yml | 3 ++ x-pack/packetbeat/packetbeat.reference.yml | 3 ++ x-pack/packetbeat/packetbeat.yml | 3 ++ 7 files changed, 47 insertions(+), 9 deletions(-) diff --git a/packetbeat/_meta/config/windows_npcap.yml.tmpl b/packetbeat/_meta/config/windows_npcap.yml.tmpl index 07c399c37d1..e336f8a4dbc 100644 --- a/packetbeat/_meta/config/windows_npcap.yml.tmpl +++ b/packetbeat/_meta/config/windows_npcap.yml.tmpl @@ -14,6 +14,9 @@ # # retain_download specifies that a downloaded installer will be kept on the host # # filesystem and its location will be recorded in the logs. # retain_download: false +# # ignore_missing_registry specifies that failure to query the registry server +# # will be ignored with a logged warning. +# ignore_missing_registry: false # # By default Npcap will be installed only when a newer version of Npcap is available. # # force_reinstall forces a new installation of Npcap in all cases. # force_reinstall: false diff --git a/packetbeat/beater/install_npcap.go b/packetbeat/beater/install_npcap.go index 739c4a4d2c2..a9c307bfcb3 100644 --- a/packetbeat/beater/install_npcap.go +++ b/packetbeat/beater/install_npcap.go @@ -19,6 +19,7 @@ package beater import ( "context" + "errors" "fmt" "net/url" "os" @@ -72,8 +73,16 @@ func installNpcap(cfg *common.Config) error { return npcap.Install(ctx, log, uri.Path, installDst, false) } + canFail, err := configBool(cfg, "npcap.ignore_misssing_registry") + if err != nil { + return err + } version, download, wantHash, err := npcap.CurrentVersion(ctx, log, rawURI) if err != nil { + if canFail && errors.Is(err, npcap.RegistryNotFound) { + log.Warnf("%v: did not install Npcap", err) + return nil + } return err } diff --git a/packetbeat/internal/npcap/npcap.go b/packetbeat/internal/npcap/npcap.go index 8a12a03296d..be51a9ff3bf 100644 --- a/packetbeat/internal/npcap/npcap.go +++ b/packetbeat/internal/npcap/npcap.go @@ -52,11 +52,16 @@ import ( "github.com/elastic/beats/v7/libbeat/logp" ) +// RegistryNotFound is returned by CurrentVersion if the network request +// returns a 404 status code. +var RegistryNotFound = errors.New("npcap: registry not found") + // Registry is the location of current Npcap version information. const Registry = "https://artifacts.elastic.co/downloads/npcap/current_version" // Fetch downloads the Npcap installer, writes the content to the given filepath -// and returns the sha256 hash of the downloaded object. +// and returns the sha256 hash of the downloaded object. If the registry is not +// found RegistryNotFound is returned. func CurrentVersion(ctx context.Context, log *logp.Logger, registry string) (version, url, hash string, err error) { if runtime.GOOS != "windows" { return "", "", "", errors.New("npcap: called Fetch on non-Windows platform") @@ -78,15 +83,21 @@ func currentVersion(ctx context.Context, log *logp.Logger, registry string) (ver defer res.Body.Close() b, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Errorf("failed to read the error response body: %v", err) + } + b = bytes.TrimSpace(b) + if len(b) == 0 { + b = []byte("empty") + } if res.StatusCode != http.StatusOK { - if err != nil { - log.Errorf("failed to read the error response body: %v", err) + if res.StatusCode == http.StatusNotFound { + return "", "", "", fmt.Errorf("%w: %s", RegistryNotFound, registry) } - b = bytes.TrimSpace(b) - if len(b) == 0 { - return "", "", "", fmt.Errorf("npcap: failed to fetch %s, status: %d, message: empty", url, res.StatusCode) + if registry == "" { + registry = `""` } - return "", "", "", fmt.Errorf("npcap: failed to fetch %s, status: %d, message: %s", url, res.StatusCode, b) + return "", "", "", fmt.Errorf("npcap: failed to fetch version info at %s, status: %d, message: %s", registry, res.StatusCode, b) } var info struct { @@ -133,9 +144,12 @@ func fetch(ctx context.Context, log *logp.Logger, url, path string) (hash string } b = bytes.TrimSpace(b) if len(b) == 0 { - return "", fmt.Errorf("npcap: failed to fetch %s, status: %d, message: empty", url, res.StatusCode) + b = []byte("empty") + } + if url == "" { + url = `""` } - return "", fmt.Errorf("npcap: failed to fetch %s, status: %d, message: %s", url, res.StatusCode, b) + return "", fmt.Errorf("npcap: failed to fetch installer at %s, status: %d, message: %s", url, res.StatusCode, b) } dst, err := os.Create(path) diff --git a/packetbeat/packetbeat.reference.yml b/packetbeat/packetbeat.reference.yml index 86159d479ca..595dfaaa38f 100644 --- a/packetbeat/packetbeat.reference.yml +++ b/packetbeat/packetbeat.reference.yml @@ -73,6 +73,9 @@ packetbeat.interfaces.internal_networks: # # retain_download specifies that a downloaded installer will be kept on the host # # filesystem and its location will be recorded in the logs. # retain_download: false +# # ignore_missing_registry specifies that failure to query the registry server +# # will be ignored with a logged warning. +# ignore_missing_registry: false # # By default Npcap will be installed only when a newer version of Npcap is available. # # force_reinstall forces a new installation of Npcap in all cases. # force_reinstall: false diff --git a/packetbeat/packetbeat.yml b/packetbeat/packetbeat.yml index 5f6e508ebbb..6d87aa4616d 100644 --- a/packetbeat/packetbeat.yml +++ b/packetbeat/packetbeat.yml @@ -39,6 +39,9 @@ packetbeat.interfaces.internal_networks: # # retain_download specifies that a downloaded installer will be kept on the host # # filesystem and its location will be recorded in the logs. # retain_download: false +# # ignore_missing_registry specifies that failure to query the registry server +# # will be ignored with a logged warning. +# ignore_missing_registry: false # # By default Npcap will be installed only when a newer version of Npcap is available. # # force_reinstall forces a new installation of Npcap in all cases. # force_reinstall: false diff --git a/x-pack/packetbeat/packetbeat.reference.yml b/x-pack/packetbeat/packetbeat.reference.yml index 86159d479ca..595dfaaa38f 100644 --- a/x-pack/packetbeat/packetbeat.reference.yml +++ b/x-pack/packetbeat/packetbeat.reference.yml @@ -73,6 +73,9 @@ packetbeat.interfaces.internal_networks: # # retain_download specifies that a downloaded installer will be kept on the host # # filesystem and its location will be recorded in the logs. # retain_download: false +# # ignore_missing_registry specifies that failure to query the registry server +# # will be ignored with a logged warning. +# ignore_missing_registry: false # # By default Npcap will be installed only when a newer version of Npcap is available. # # force_reinstall forces a new installation of Npcap in all cases. # force_reinstall: false diff --git a/x-pack/packetbeat/packetbeat.yml b/x-pack/packetbeat/packetbeat.yml index 5f6e508ebbb..6d87aa4616d 100644 --- a/x-pack/packetbeat/packetbeat.yml +++ b/x-pack/packetbeat/packetbeat.yml @@ -39,6 +39,9 @@ packetbeat.interfaces.internal_networks: # # retain_download specifies that a downloaded installer will be kept on the host # # filesystem and its location will be recorded in the logs. # retain_download: false +# # ignore_missing_registry specifies that failure to query the registry server +# # will be ignored with a logged warning. +# ignore_missing_registry: false # # By default Npcap will be installed only when a newer version of Npcap is available. # # force_reinstall forces a new installation of Npcap in all cases. # force_reinstall: false From 910081648443ab3fa45e8784917ed0a758935cd6 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 25 Nov 2021 12:25:01 +1030 Subject: [PATCH 05/26] add changelog line --- CHANGELOG.next.asciidoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.next.asciidoc b/CHANGELOG.next.asciidoc index 50cb3176b8f..97886173be4 100644 --- a/CHANGELOG.next.asciidoc +++ b/CHANGELOG.next.asciidoc @@ -285,6 +285,8 @@ https://github.com/elastic/beats/compare/v7.0.0-alpha2...master[Check the HEAD d *Packetbeat* +- Add automated OEM Npcap installation handling. {pull}29112[29112] + *Functionbeat* From ed25fa3fa166d9715807634ac4f31f2cacb090d3 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Mon, 29 Nov 2021 12:19:29 +1030 Subject: [PATCH 06/26] improve error reporting --- packetbeat/internal/npcap/npcap.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packetbeat/internal/npcap/npcap.go b/packetbeat/internal/npcap/npcap.go index be51a9ff3bf..1fc3429c2bc 100644 --- a/packetbeat/internal/npcap/npcap.go +++ b/packetbeat/internal/npcap/npcap.go @@ -88,6 +88,7 @@ func currentVersion(ctx context.Context, log *logp.Logger, registry string) (ver } b = bytes.TrimSpace(b) if len(b) == 0 { + // Give a meaningful error message and make json error if we have no body. b = []byte("empty") } if res.StatusCode != http.StatusOK { @@ -107,7 +108,7 @@ func currentVersion(ctx context.Context, log *logp.Logger, registry string) (ver } err = json.Unmarshal(b, &info) if err != nil { - return "", "", "", err + return "", "", "", fmt.Errorf("%w: %#q", err, b) } return info.Version, info.URL, info.Hash, nil From f464744076a109c25bfd239ffc605a8cc1db213b Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Tue, 30 Nov 2021 10:24:02 +1030 Subject: [PATCH 07/26] restrict oem npcap installation to elastic licensed use --- packetbeat/beater/install_npcap.go | 7 ++++++- packetbeat/beater/packetbeat.go | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packetbeat/beater/install_npcap.go b/packetbeat/beater/install_npcap.go index a9c307bfcb3..b7b22c68e04 100644 --- a/packetbeat/beater/install_npcap.go +++ b/packetbeat/beater/install_npcap.go @@ -28,16 +28,21 @@ import ( "runtime" "time" + "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/common" "github.com/elastic/beats/v7/libbeat/logp" "github.com/elastic/beats/v7/packetbeat/internal/npcap" ) -func installNpcap(cfg *common.Config) error { +func installNpcap(b *beat.Beat) error { + if !b.Info.ElasticLicensed { + return nil + } if runtime.GOOS != "windows" { return nil } + cfg := b.BeatConfig reinstall, err := configBool(cfg, "npcap.force_reinstall") if err != nil { return err diff --git a/packetbeat/beater/packetbeat.go b/packetbeat/beater/packetbeat.go index 6aed4227524..3a1f7d6c2d9 100644 --- a/packetbeat/beater/packetbeat.go +++ b/packetbeat/beater/packetbeat.go @@ -112,7 +112,7 @@ func (pb *packetbeat) Run(b *beat.Beat) error { }() // Install Npcap if needed. - err := installNpcap(b.BeatConfig) + err := installNpcap(b) if err != nil { return err } From 21d493110ed3e8c8cca394124d5991a6a61bd1fc Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 2 Dec 2021 09:07:13 +1030 Subject: [PATCH 08/26] add logic for installing from embedded byte artifact --- packetbeat/beater/install_npcap.go | 36 +++++++++++++++++++++++++++--- packetbeat/internal/npcap/npcap.go | 3 --- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/packetbeat/beater/install_npcap.go b/packetbeat/beater/install_npcap.go index b7b22c68e04..74c699cd8ad 100644 --- a/packetbeat/beater/install_npcap.go +++ b/packetbeat/beater/install_npcap.go @@ -34,6 +34,14 @@ import ( "github.com/elastic/beats/v7/packetbeat/internal/npcap" ) +var ( + // installer holds the embedded installer when run with x-pack. + installer []byte + + // embeddedInstallerVersion holds the version of the embedded installer. + embeddedInstallerVersion string +) + func installNpcap(b *beat.Beat) error { if !b.Info.ElasticLicensed { return nil @@ -59,15 +67,37 @@ func installNpcap(b *beat.Beat) error { if err != nil { return err } - if rawURI == "" { - rawURI = npcap.Registry - } ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() log := logp.NewLogger("npcap_install") + // If no location is provided, go ahead and install from the embedded installer. + if rawURI == "" { + if installer == nil || !npcap.Upgradeable(embeddedInstallerVersion) { + return nil + } + tmp, err := os.MkdirTemp("", "") + if err != nil { + return fmt.Errorf("could not create installation temporary directory: %w", err) + } + defer func() { + // The init sequence duplicates the embedded binary. + // Get rid of the part we can. The remainder is in + // the packetbeat text section as a string. + installer = nil + // Remove the installer from the file system. + os.RemoveAll(tmp) + }() + installerPath := filepath.Join(tmp, "npcap.exe") + err = os.WriteFile(installerPath, installer, 0o700) + if err != nil { + return fmt.Errorf("could not create installation temporary file: %w", err) + } + return npcap.Install(ctx, log, installerPath, installDst, false) + } + uri, err := url.Parse(rawURI) if err != nil { return err diff --git a/packetbeat/internal/npcap/npcap.go b/packetbeat/internal/npcap/npcap.go index 1fc3429c2bc..e3af639f792 100644 --- a/packetbeat/internal/npcap/npcap.go +++ b/packetbeat/internal/npcap/npcap.go @@ -56,9 +56,6 @@ import ( // returns a 404 status code. var RegistryNotFound = errors.New("npcap: registry not found") -// Registry is the location of current Npcap version information. -const Registry = "https://artifacts.elastic.co/downloads/npcap/current_version" - // Fetch downloads the Npcap installer, writes the content to the given filepath // and returns the sha256 hash of the downloaded object. If the registry is not // found RegistryNotFound is returned. From dfc114bf244837ec7a36a14655f669f059321e6b Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 2 Dec 2021 09:08:31 +1030 Subject: [PATCH 09/26] make npcap installer code visible from x-pack --- packetbeat/beater/install_npcap.go | 20 ++++++++----------- packetbeat/{internal => }/npcap/npcap.go | 8 ++++++++ .../{internal => }/npcap/npcap_other.go | 0 packetbeat/{internal => }/npcap/npcap_test.go | 0 .../{internal => }/npcap/npcap_windows.go | 0 .../npcap/testdata/mock_installer.go | 0 .../npcap/testdata/mock_uninstaller.go | 0 7 files changed, 16 insertions(+), 12 deletions(-) rename packetbeat/{internal => }/npcap/npcap.go (97%) rename packetbeat/{internal => }/npcap/npcap_other.go (100%) rename packetbeat/{internal => }/npcap/npcap_test.go (100%) rename packetbeat/{internal => }/npcap/npcap_windows.go (100%) rename packetbeat/{internal => }/npcap/testdata/mock_installer.go (100%) rename packetbeat/{internal => }/npcap/testdata/mock_uninstaller.go (100%) diff --git a/packetbeat/beater/install_npcap.go b/packetbeat/beater/install_npcap.go index 74c699cd8ad..a65e97de32d 100644 --- a/packetbeat/beater/install_npcap.go +++ b/packetbeat/beater/install_npcap.go @@ -31,15 +31,7 @@ import ( "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/common" "github.com/elastic/beats/v7/libbeat/logp" - "github.com/elastic/beats/v7/packetbeat/internal/npcap" -) - -var ( - // installer holds the embedded installer when run with x-pack. - installer []byte - - // embeddedInstallerVersion holds the version of the embedded installer. - embeddedInstallerVersion string + "github.com/elastic/beats/v7/packetbeat/npcap" ) func installNpcap(b *beat.Beat) error { @@ -75,7 +67,11 @@ func installNpcap(b *beat.Beat) error { // If no location is provided, go ahead and install from the embedded installer. if rawURI == "" { - if installer == nil || !npcap.Upgradeable(embeddedInstallerVersion) { + if npcap.Installer == nil { + return nil + } + if !npcap.Upgradeable(npcap.EmbeddedInstallerVersion) { + npcap.Installer = nil return nil } tmp, err := os.MkdirTemp("", "") @@ -86,12 +82,12 @@ func installNpcap(b *beat.Beat) error { // The init sequence duplicates the embedded binary. // Get rid of the part we can. The remainder is in // the packetbeat text section as a string. - installer = nil + npcap.Installer = nil // Remove the installer from the file system. os.RemoveAll(tmp) }() installerPath := filepath.Join(tmp, "npcap.exe") - err = os.WriteFile(installerPath, installer, 0o700) + err = os.WriteFile(installerPath, npcap.Installer, 0o700) if err != nil { return fmt.Errorf("could not create installation temporary file: %w", err) } diff --git a/packetbeat/internal/npcap/npcap.go b/packetbeat/npcap/npcap.go similarity index 97% rename from packetbeat/internal/npcap/npcap.go rename to packetbeat/npcap/npcap.go index e3af639f792..5264a856a8f 100644 --- a/packetbeat/internal/npcap/npcap.go +++ b/packetbeat/npcap/npcap.go @@ -56,6 +56,14 @@ import ( // returns a 404 status code. var RegistryNotFound = errors.New("npcap: registry not found") +var ( + // Installer holds the embedded installer when run with x-pack. + Installer []byte + + // EmbeddedInstallerVersion holds the version of the embedded installer. + EmbeddedInstallerVersion string +) + // Fetch downloads the Npcap installer, writes the content to the given filepath // and returns the sha256 hash of the downloaded object. If the registry is not // found RegistryNotFound is returned. diff --git a/packetbeat/internal/npcap/npcap_other.go b/packetbeat/npcap/npcap_other.go similarity index 100% rename from packetbeat/internal/npcap/npcap_other.go rename to packetbeat/npcap/npcap_other.go diff --git a/packetbeat/internal/npcap/npcap_test.go b/packetbeat/npcap/npcap_test.go similarity index 100% rename from packetbeat/internal/npcap/npcap_test.go rename to packetbeat/npcap/npcap_test.go diff --git a/packetbeat/internal/npcap/npcap_windows.go b/packetbeat/npcap/npcap_windows.go similarity index 100% rename from packetbeat/internal/npcap/npcap_windows.go rename to packetbeat/npcap/npcap_windows.go diff --git a/packetbeat/internal/npcap/testdata/mock_installer.go b/packetbeat/npcap/testdata/mock_installer.go similarity index 100% rename from packetbeat/internal/npcap/testdata/mock_installer.go rename to packetbeat/npcap/testdata/mock_installer.go diff --git a/packetbeat/internal/npcap/testdata/mock_uninstaller.go b/packetbeat/npcap/testdata/mock_uninstaller.go similarity index 100% rename from packetbeat/internal/npcap/testdata/mock_uninstaller.go rename to packetbeat/npcap/testdata/mock_uninstaller.go From 2b16d6ca3d4ad44a90ba040f4a9f7a425eb964e6 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 2 Dec 2021 11:26:29 +1030 Subject: [PATCH 10/26] allow installation of npcap from embedded npcap installer --- x-pack/packetbeat/cmd/root.go | 3 ++ x-pack/packetbeat/npcap/installer/README | 5 +++ x-pack/packetbeat/npcap/npcap_other.go | 9 +++++ x-pack/packetbeat/npcap/npcap_windows.go | 47 ++++++++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 x-pack/packetbeat/npcap/installer/README create mode 100644 x-pack/packetbeat/npcap/npcap_other.go create mode 100644 x-pack/packetbeat/npcap/npcap_windows.go diff --git a/x-pack/packetbeat/cmd/root.go b/x-pack/packetbeat/cmd/root.go index c7c15b058be..407d24570df 100644 --- a/x-pack/packetbeat/cmd/root.go +++ b/x-pack/packetbeat/cmd/root.go @@ -9,6 +9,9 @@ import ( packetbeatCmd "github.com/elastic/beats/v7/packetbeat/cmd" _ "github.com/elastic/beats/v7/x-pack/libbeat/include" + + // This registers the Npcap installer on Windows. + _ "github.com/elastic/beats/v7/x-pack/packetbeat/npcap" ) // Name of this beat. diff --git a/x-pack/packetbeat/npcap/installer/README b/x-pack/packetbeat/npcap/installer/README new file mode 100644 index 00000000000..ce30555be7f --- /dev/null +++ b/x-pack/packetbeat/npcap/installer/README @@ -0,0 +1,5 @@ +This directory is pinned to allow placement of the Npcap OEM installer +during x-pack Packetbeat builds. + +Only one exe file may be placed here and this should be the most recent +available Npcap installer. diff --git a/x-pack/packetbeat/npcap/npcap_other.go b/x-pack/packetbeat/npcap/npcap_other.go new file mode 100644 index 00000000000..647eab35bff --- /dev/null +++ b/x-pack/packetbeat/npcap/npcap_other.go @@ -0,0 +1,9 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +//go:build !windows +// +build !windows + +// Package npcap provides an embedded Npcap OEM installer on Windows systems. +package npcap diff --git a/x-pack/packetbeat/npcap/npcap_windows.go b/x-pack/packetbeat/npcap/npcap_windows.go new file mode 100644 index 00000000000..f6ee91d2863 --- /dev/null +++ b/x-pack/packetbeat/npcap/npcap_windows.go @@ -0,0 +1,47 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +//go:build windows +// +build windows + +// Package npcap provides an embedded Npcap OEM installer. The embedded installer +// must be placed in the installer directory and have a name that matches the pattern +// "npcap-([0-9]\.[0-9]+)(?:|-oem)\.exe" where the capture is the installer version. +package npcap + +import ( + "embed" + "fmt" + "path" + "strings" + + "github.com/elastic/beats/v7/packetbeat/npcap" +) + +//go:embed installer/*.exe +var fs embed.FS + +func init() { + list, err := fs.ReadDir("installer") + if err != nil { + panic(fmt.Sprintf("failed to set up npcap installer: %v", err)) + } + if len(list) == 0 { + return + } + if len(list) > 1 { + panic(fmt.Sprintf("unexpected number of installers found: want only one but got %d", len(list))) + } + installer := list[0].Name() + + version := strings.TrimPrefix(installer, "npcap-") + version = strings.TrimSuffix(version, ".exe") + version = strings.TrimSuffix(version, "-oem") + npcap.EmbeddedInstallerVersion = version + + npcap.Installer, err = fs.ReadFile(path.Join("installer", installer)) + if err != nil { + panic(fmt.Sprintf("failed to set up npcap installer: %v", err)) + } +} From 4c1ceae92f1a283f60c59cec9f4ef814cd0795d0 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 2 Dec 2021 11:56:52 +1030 Subject: [PATCH 11/26] reload npcap dll on install --- packetbeat/npcap/npcap.go | 11 +---------- packetbeat/npcap/npcap_other.go | 2 ++ packetbeat/npcap/npcap_windows.go | 8 ++++++++ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packetbeat/npcap/npcap.go b/packetbeat/npcap/npcap.go index 5264a856a8f..ef9536bed23 100644 --- a/packetbeat/npcap/npcap.go +++ b/packetbeat/npcap/npcap.go @@ -215,16 +215,7 @@ func install(ctx context.Context, log *logp.Logger, path, dst string, compat boo return fmt.Errorf("npcap: failed to install Npcap: %w", err) } - // gopacket/pcap does not provide a mechanism to reload the pcap DLL - // so if we are upgrading we wait for the next startup of packetbeat. - // Otherwise we can make sure that the DLL is loaded by calling - // pcap.LoadWinPCAP. pcap.LoadWinPCAP is called on pcap package - // initialization and if successful, subsequent calls are no-op, but - // if Npcap/WinPCAP was not installed, it will have failed and can be - // called now. So this is safe in all cases. - err = loadWinPCAP() - - return err + return reloadWinPCAP() } func Upgradeable(version string) bool { diff --git a/packetbeat/npcap/npcap_other.go b/packetbeat/npcap/npcap_other.go index 47fc8a8bd6a..c813644d471 100644 --- a/packetbeat/npcap/npcap_other.go +++ b/packetbeat/npcap/npcap_other.go @@ -21,3 +21,5 @@ package npcap func loadWinPCAP() error { return nil } + +func reloadWinPCAP() error { return nil } diff --git a/packetbeat/npcap/npcap_windows.go b/packetbeat/npcap/npcap_windows.go index 36a8a72900c..44d0053820f 100644 --- a/packetbeat/npcap/npcap_windows.go +++ b/packetbeat/npcap/npcap_windows.go @@ -23,3 +23,11 @@ package npcap import "github.com/google/gopacket/pcap" func loadWinPCAP() error { return pcap.LoadWinPCAP() } + +func reloadWinPCAP() error { + err := pcap.UnloadWinPCAP() + if err != nil { + return err + } + return pcap.LoadWinPCAP() +} From 9432b725e2c761dae47394e43e7cc58f58793306 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 2 Dec 2021 12:37:33 +1030 Subject: [PATCH 12/26] make compilation succeed and handle un-bundled case --- packetbeat/npcap/npcap.go | 5 +++++ x-pack/packetbeat/npcap/installer/README | 4 +++- x-pack/packetbeat/npcap/installer/npcap-0.00.exe | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 x-pack/packetbeat/npcap/installer/npcap-0.00.exe diff --git a/packetbeat/npcap/npcap.go b/packetbeat/npcap/npcap.go index ef9536bed23..ab356ca394d 100644 --- a/packetbeat/npcap/npcap.go +++ b/packetbeat/npcap/npcap.go @@ -219,6 +219,11 @@ func install(ctx context.Context, log *logp.Logger, path, dst string, compat boo } func Upgradeable(version string) bool { + // Chack for the place-holder file. + if version == "0.00" { + return false + } + // pcap.Version() returns a string in the form: // // Npcap version 1.55, based on libpcap version 1.10.2-PRE-GIT diff --git a/x-pack/packetbeat/npcap/installer/README b/x-pack/packetbeat/npcap/installer/README index ce30555be7f..18382c2ab8d 100644 --- a/x-pack/packetbeat/npcap/installer/README +++ b/x-pack/packetbeat/npcap/installer/README @@ -2,4 +2,6 @@ This directory is pinned to allow placement of the Npcap OEM installer during x-pack Packetbeat builds. Only one exe file may be placed here and this should be the most recent -available Npcap installer. +available Npcap installer. As part of the distribution a place-holder file +is put here to allow compilation. This file must be removed when a real +installer in included for the build. diff --git a/x-pack/packetbeat/npcap/installer/npcap-0.00.exe b/x-pack/packetbeat/npcap/installer/npcap-0.00.exe new file mode 100644 index 00000000000..43d4762b1ed --- /dev/null +++ b/x-pack/packetbeat/npcap/installer/npcap-0.00.exe @@ -0,0 +1 @@ +This is not the installer you are looking for. \ No newline at end of file From 20d10c3f015ea776389f15aff3f8324ea4d88e01 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 2 Dec 2021 12:49:26 +1030 Subject: [PATCH 13/26] update docs for new approach and note limiting use to x-pack --- packetbeat/_meta/config/windows_npcap.yml.tmpl | 5 +++-- packetbeat/packetbeat.reference.yml | 5 +++-- packetbeat/packetbeat.yml | 5 +++-- x-pack/packetbeat/packetbeat.reference.yml | 5 +++-- x-pack/packetbeat/packetbeat.yml | 5 +++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packetbeat/_meta/config/windows_npcap.yml.tmpl b/packetbeat/_meta/config/windows_npcap.yml.tmpl index e336f8a4dbc..98c411f6287 100644 --- a/packetbeat/_meta/config/windows_npcap.yml.tmpl +++ b/packetbeat/_meta/config/windows_npcap.yml.tmpl @@ -2,10 +2,11 @@ # Windows Npcap installation options. These options specify how the Npcap packet # capture library for Windows should be obtained and installed. +# Windows Npcap installation is only available with x-pack. #npcap: # # installer_location is either a URL or a bare path. The URL may have an http, -# # https or file scheme. If it is empty or unset, a default URL pointing to the -# # current latest version is used. +# # https or file scheme. If it is empty or unset, a bundled installer is used +# # and the retain_download and ignore_missing_registry are ignored. # installer_location: "" # # install_destination allows configuration of the location that the Npcap will # # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. diff --git a/packetbeat/packetbeat.reference.yml b/packetbeat/packetbeat.reference.yml index 595dfaaa38f..a1793156180 100644 --- a/packetbeat/packetbeat.reference.yml +++ b/packetbeat/packetbeat.reference.yml @@ -61,10 +61,11 @@ packetbeat.interfaces.internal_networks: # Windows Npcap installation options. These options specify how the Npcap packet # capture library for Windows should be obtained and installed. +# Windows Npcap installation is only available with x-pack. #npcap: # # installer_location is either a URL or a bare path. The URL may have an http, -# # https or file scheme. If it is empty or unset, a default URL pointing to the -# # current latest version is used. +# # https or file scheme. If it is empty or unset, a bundled installer is used +# # and the retain_download and ignore_missing_registry are ignored. # installer_location: "" # # install_destination allows configuration of the location that the Npcap will # # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. diff --git a/packetbeat/packetbeat.yml b/packetbeat/packetbeat.yml index 6d87aa4616d..8169b9b7dd4 100644 --- a/packetbeat/packetbeat.yml +++ b/packetbeat/packetbeat.yml @@ -27,10 +27,11 @@ packetbeat.interfaces.internal_networks: # Windows Npcap installation options. These options specify how the Npcap packet # capture library for Windows should be obtained and installed. +# Windows Npcap installation is only available with x-pack. #npcap: # # installer_location is either a URL or a bare path. The URL may have an http, -# # https or file scheme. If it is empty or unset, a default URL pointing to the -# # current latest version is used. +# # https or file scheme. If it is empty or unset, a bundled installer is used +# # and the retain_download and ignore_missing_registry are ignored. # installer_location: "" # # install_destination allows configuration of the location that the Npcap will # # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. diff --git a/x-pack/packetbeat/packetbeat.reference.yml b/x-pack/packetbeat/packetbeat.reference.yml index 595dfaaa38f..a1793156180 100644 --- a/x-pack/packetbeat/packetbeat.reference.yml +++ b/x-pack/packetbeat/packetbeat.reference.yml @@ -61,10 +61,11 @@ packetbeat.interfaces.internal_networks: # Windows Npcap installation options. These options specify how the Npcap packet # capture library for Windows should be obtained and installed. +# Windows Npcap installation is only available with x-pack. #npcap: # # installer_location is either a URL or a bare path. The URL may have an http, -# # https or file scheme. If it is empty or unset, a default URL pointing to the -# # current latest version is used. +# # https or file scheme. If it is empty or unset, a bundled installer is used +# # and the retain_download and ignore_missing_registry are ignored. # installer_location: "" # # install_destination allows configuration of the location that the Npcap will # # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. diff --git a/x-pack/packetbeat/packetbeat.yml b/x-pack/packetbeat/packetbeat.yml index 6d87aa4616d..8169b9b7dd4 100644 --- a/x-pack/packetbeat/packetbeat.yml +++ b/x-pack/packetbeat/packetbeat.yml @@ -27,10 +27,11 @@ packetbeat.interfaces.internal_networks: # Windows Npcap installation options. These options specify how the Npcap packet # capture library for Windows should be obtained and installed. +# Windows Npcap installation is only available with x-pack. #npcap: # # installer_location is either a URL or a bare path. The URL may have an http, -# # https or file scheme. If it is empty or unset, a default URL pointing to the -# # current latest version is used. +# # https or file scheme. If it is empty or unset, a bundled installer is used +# # and the retain_download and ignore_missing_registry are ignored. # installer_location: "" # # install_destination allows configuration of the location that the Npcap will # # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. From 4ce44a2120502d500c905f5796e77dd098ef389e Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Fri, 3 Dec 2021 15:07:49 +1030 Subject: [PATCH 14/26] remove option to retain downloaded installer file This was a holdover from the previous approach for distribution to air-gapped devices and is not needed now. --- packetbeat/_meta/config/windows_npcap.yml.tmpl | 3 --- packetbeat/beater/install_npcap.go | 11 +---------- packetbeat/packetbeat.reference.yml | 3 --- packetbeat/packetbeat.yml | 3 --- x-pack/packetbeat/packetbeat.reference.yml | 3 --- x-pack/packetbeat/packetbeat.yml | 3 --- 6 files changed, 1 insertion(+), 25 deletions(-) diff --git a/packetbeat/_meta/config/windows_npcap.yml.tmpl b/packetbeat/_meta/config/windows_npcap.yml.tmpl index 98c411f6287..36c9fba6470 100644 --- a/packetbeat/_meta/config/windows_npcap.yml.tmpl +++ b/packetbeat/_meta/config/windows_npcap.yml.tmpl @@ -12,9 +12,6 @@ # # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. # install_destination: "" # install_timeout: 120s -# # retain_download specifies that a downloaded installer will be kept on the host -# # filesystem and its location will be recorded in the logs. -# retain_download: false # # ignore_missing_registry specifies that failure to query the registry server # # will be ignored with a logged warning. # ignore_missing_registry: false diff --git a/packetbeat/beater/install_npcap.go b/packetbeat/beater/install_npcap.go index a65e97de32d..96e5320f83f 100644 --- a/packetbeat/beater/install_npcap.go +++ b/packetbeat/beater/install_npcap.go @@ -122,20 +122,11 @@ func installNpcap(b *beat.Beat) error { return nil } - retain, err := configBool(cfg, "npcap.retain_download") - if err != nil { - return err - } - dir, err := os.MkdirTemp("", "packetbeat-npcap-*") if err != nil { return err } - if retain { - log.Infof("working in %s", dir) - } else { - defer os.RemoveAll(dir) - } + defer os.RemoveAll(dir) pth := filepath.Join(dir, path.Base(download)) gotHash, err := npcap.Fetch(ctx, log, download, pth) diff --git a/packetbeat/packetbeat.reference.yml b/packetbeat/packetbeat.reference.yml index a1793156180..c6ba2b30aa6 100644 --- a/packetbeat/packetbeat.reference.yml +++ b/packetbeat/packetbeat.reference.yml @@ -71,9 +71,6 @@ packetbeat.interfaces.internal_networks: # # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. # install_destination: "" # install_timeout: 120s -# # retain_download specifies that a downloaded installer will be kept on the host -# # filesystem and its location will be recorded in the logs. -# retain_download: false # # ignore_missing_registry specifies that failure to query the registry server # # will be ignored with a logged warning. # ignore_missing_registry: false diff --git a/packetbeat/packetbeat.yml b/packetbeat/packetbeat.yml index 8169b9b7dd4..2e4da22484d 100644 --- a/packetbeat/packetbeat.yml +++ b/packetbeat/packetbeat.yml @@ -37,9 +37,6 @@ packetbeat.interfaces.internal_networks: # # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. # install_destination: "" # install_timeout: 120s -# # retain_download specifies that a downloaded installer will be kept on the host -# # filesystem and its location will be recorded in the logs. -# retain_download: false # # ignore_missing_registry specifies that failure to query the registry server # # will be ignored with a logged warning. # ignore_missing_registry: false diff --git a/x-pack/packetbeat/packetbeat.reference.yml b/x-pack/packetbeat/packetbeat.reference.yml index a1793156180..c6ba2b30aa6 100644 --- a/x-pack/packetbeat/packetbeat.reference.yml +++ b/x-pack/packetbeat/packetbeat.reference.yml @@ -71,9 +71,6 @@ packetbeat.interfaces.internal_networks: # # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. # install_destination: "" # install_timeout: 120s -# # retain_download specifies that a downloaded installer will be kept on the host -# # filesystem and its location will be recorded in the logs. -# retain_download: false # # ignore_missing_registry specifies that failure to query the registry server # # will be ignored with a logged warning. # ignore_missing_registry: false diff --git a/x-pack/packetbeat/packetbeat.yml b/x-pack/packetbeat/packetbeat.yml index 8169b9b7dd4..2e4da22484d 100644 --- a/x-pack/packetbeat/packetbeat.yml +++ b/x-pack/packetbeat/packetbeat.yml @@ -37,9 +37,6 @@ packetbeat.interfaces.internal_networks: # # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. # install_destination: "" # install_timeout: 120s -# # retain_download specifies that a downloaded installer will be kept on the host -# # filesystem and its location will be recorded in the logs. -# retain_download: false # # ignore_missing_registry specifies that failure to query the registry server # # will be ignored with a logged warning. # ignore_missing_registry: false From ad80f3ac9a0935cbb25ff18d00f417c2c36a431c Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 9 Dec 2021 10:51:28 +1030 Subject: [PATCH 15/26] only include Npcap config options on Windows when Elastic Licensed --- dev-tools/mage/config.go | 1 + .../_meta/config/beat.reference.yml.tmpl | 3 ++- packetbeat/_meta/config/beat.yml.tmpl | 3 ++- .../_meta/config/windows_npcap.yml.tmpl | 3 +++ packetbeat/packetbeat.reference.yml | 21 ------------------- packetbeat/packetbeat.yml | 21 ------------------- x-pack/packetbeat/packetbeat.reference.yml | 21 ------------------- x-pack/packetbeat/packetbeat.yml | 21 ------------------- 8 files changed, 8 insertions(+), 86 deletions(-) diff --git a/dev-tools/mage/config.go b/dev-tools/mage/config.go index da54123e916..b80bd9a197b 100644 --- a/dev-tools/mage/config.go +++ b/dev-tools/mage/config.go @@ -149,6 +149,7 @@ func makeConfigTemplate(destination string, mode os.FileMode, confParams ConfigF params := map[string]interface{}{ "GOOS": EnvOr("DEV_OS", "linux"), "GOARCH": EnvOr("DEV_ARCH", "amd64"), + "BeatLicense": BeatLicense, "Reference": false, "Docker": false, "ExcludeConsole": false, diff --git a/packetbeat/_meta/config/beat.reference.yml.tmpl b/packetbeat/_meta/config/beat.reference.yml.tmpl index 6dbc2837582..856a9475fe9 100644 --- a/packetbeat/_meta/config/beat.reference.yml.tmpl +++ b/packetbeat/_meta/config/beat.reference.yml.tmpl @@ -57,7 +57,8 @@ packetbeat.interfaces.internal_networks: # can stay enabled even after beat is shut down. #packetbeat.interfaces.auto_promisc_mode: true -{{template "windows_npcap.yml.tmpl" .}} +{{- template "windows_npcap.yml.tmpl" .}} + {{header "Flows"}} packetbeat.flows: diff --git a/packetbeat/_meta/config/beat.yml.tmpl b/packetbeat/_meta/config/beat.yml.tmpl index b93a425db0c..95410045593 100644 --- a/packetbeat/_meta/config/beat.yml.tmpl +++ b/packetbeat/_meta/config/beat.yml.tmpl @@ -23,7 +23,8 @@ packetbeat.interfaces.device: {{ call .device .GOOS }} packetbeat.interfaces.internal_networks: - private -{{template "windows_npcap.yml.tmpl" .}} +{{- template "windows_npcap.yml.tmpl" .}} + {{header "Flows"}} # Set `enabled: false` or comment out all options to disable flows reporting. diff --git a/packetbeat/_meta/config/windows_npcap.yml.tmpl b/packetbeat/_meta/config/windows_npcap.yml.tmpl index 36c9fba6470..21bcaf3b2b6 100644 --- a/packetbeat/_meta/config/windows_npcap.yml.tmpl +++ b/packetbeat/_meta/config/windows_npcap.yml.tmpl @@ -1,3 +1,5 @@ +{{if and (eq .BeatLicense "Elastic License") (eq .GOOS "windows")}} + {{header "Windows Npcap installation settings"}} # Windows Npcap installation options. These options specify how the Npcap packet @@ -18,3 +20,4 @@ # # By default Npcap will be installed only when a newer version of Npcap is available. # # force_reinstall forces a new installation of Npcap in all cases. # force_reinstall: false +{{- end -}} diff --git a/packetbeat/packetbeat.reference.yml b/packetbeat/packetbeat.reference.yml index c6ba2b30aa6..3d9d0f604bf 100644 --- a/packetbeat/packetbeat.reference.yml +++ b/packetbeat/packetbeat.reference.yml @@ -57,27 +57,6 @@ packetbeat.interfaces.internal_networks: # can stay enabled even after beat is shut down. #packetbeat.interfaces.auto_promisc_mode: true -# ==================== Windows Npcap installation settings ===================== - -# Windows Npcap installation options. These options specify how the Npcap packet -# capture library for Windows should be obtained and installed. -# Windows Npcap installation is only available with x-pack. -#npcap: -# # installer_location is either a URL or a bare path. The URL may have an http, -# # https or file scheme. If it is empty or unset, a bundled installer is used -# # and the retain_download and ignore_missing_registry are ignored. -# installer_location: "" -# # install_destination allows configuration of the location that the Npcap will -# # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. -# install_destination: "" -# install_timeout: 120s -# # ignore_missing_registry specifies that failure to query the registry server -# # will be ignored with a logged warning. -# ignore_missing_registry: false -# # By default Npcap will be installed only when a newer version of Npcap is available. -# # force_reinstall forces a new installation of Npcap in all cases. -# force_reinstall: false - # =================================== Flows ==================================== packetbeat.flows: diff --git a/packetbeat/packetbeat.yml b/packetbeat/packetbeat.yml index 2e4da22484d..15a0df9ebd1 100644 --- a/packetbeat/packetbeat.yml +++ b/packetbeat/packetbeat.yml @@ -23,27 +23,6 @@ packetbeat.interfaces.device: any packetbeat.interfaces.internal_networks: - private -# ==================== Windows Npcap installation settings ===================== - -# Windows Npcap installation options. These options specify how the Npcap packet -# capture library for Windows should be obtained and installed. -# Windows Npcap installation is only available with x-pack. -#npcap: -# # installer_location is either a URL or a bare path. The URL may have an http, -# # https or file scheme. If it is empty or unset, a bundled installer is used -# # and the retain_download and ignore_missing_registry are ignored. -# installer_location: "" -# # install_destination allows configuration of the location that the Npcap will -# # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. -# install_destination: "" -# install_timeout: 120s -# # ignore_missing_registry specifies that failure to query the registry server -# # will be ignored with a logged warning. -# ignore_missing_registry: false -# # By default Npcap will be installed only when a newer version of Npcap is available. -# # force_reinstall forces a new installation of Npcap in all cases. -# force_reinstall: false - # =================================== Flows ==================================== # Set `enabled: false` or comment out all options to disable flows reporting. diff --git a/x-pack/packetbeat/packetbeat.reference.yml b/x-pack/packetbeat/packetbeat.reference.yml index c6ba2b30aa6..3d9d0f604bf 100644 --- a/x-pack/packetbeat/packetbeat.reference.yml +++ b/x-pack/packetbeat/packetbeat.reference.yml @@ -57,27 +57,6 @@ packetbeat.interfaces.internal_networks: # can stay enabled even after beat is shut down. #packetbeat.interfaces.auto_promisc_mode: true -# ==================== Windows Npcap installation settings ===================== - -# Windows Npcap installation options. These options specify how the Npcap packet -# capture library for Windows should be obtained and installed. -# Windows Npcap installation is only available with x-pack. -#npcap: -# # installer_location is either a URL or a bare path. The URL may have an http, -# # https or file scheme. If it is empty or unset, a bundled installer is used -# # and the retain_download and ignore_missing_registry are ignored. -# installer_location: "" -# # install_destination allows configuration of the location that the Npcap will -# # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. -# install_destination: "" -# install_timeout: 120s -# # ignore_missing_registry specifies that failure to query the registry server -# # will be ignored with a logged warning. -# ignore_missing_registry: false -# # By default Npcap will be installed only when a newer version of Npcap is available. -# # force_reinstall forces a new installation of Npcap in all cases. -# force_reinstall: false - # =================================== Flows ==================================== packetbeat.flows: diff --git a/x-pack/packetbeat/packetbeat.yml b/x-pack/packetbeat/packetbeat.yml index 2e4da22484d..15a0df9ebd1 100644 --- a/x-pack/packetbeat/packetbeat.yml +++ b/x-pack/packetbeat/packetbeat.yml @@ -23,27 +23,6 @@ packetbeat.interfaces.device: any packetbeat.interfaces.internal_networks: - private -# ==================== Windows Npcap installation settings ===================== - -# Windows Npcap installation options. These options specify how the Npcap packet -# capture library for Windows should be obtained and installed. -# Windows Npcap installation is only available with x-pack. -#npcap: -# # installer_location is either a URL or a bare path. The URL may have an http, -# # https or file scheme. If it is empty or unset, a bundled installer is used -# # and the retain_download and ignore_missing_registry are ignored. -# installer_location: "" -# # install_destination allows configuration of the location that the Npcap will -# # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. -# install_destination: "" -# install_timeout: 120s -# # ignore_missing_registry specifies that failure to query the registry server -# # will be ignored with a logged warning. -# ignore_missing_registry: false -# # By default Npcap will be installed only when a newer version of Npcap is available. -# # force_reinstall forces a new installation of Npcap in all cases. -# force_reinstall: false - # =================================== Flows ==================================== # Set `enabled: false` or comment out all options to disable flows reporting. From a38af7cf6e2faeecd10a1d2018e95d58d34e61b2 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 9 Dec 2021 11:17:12 +1030 Subject: [PATCH 16/26] back out remote provisioning of installer --- packetbeat/beater/install_npcap.go | 94 +++++----------------- packetbeat/npcap/npcap.go | 125 +---------------------------- packetbeat/npcap/npcap_test.go | 90 ++------------------- 3 files changed, 27 insertions(+), 282 deletions(-) diff --git a/packetbeat/beater/install_npcap.go b/packetbeat/beater/install_npcap.go index 96e5320f83f..df5ccd0c6cf 100644 --- a/packetbeat/beater/install_npcap.go +++ b/packetbeat/beater/install_npcap.go @@ -19,11 +19,8 @@ package beater import ( "context" - "errors" "fmt" - "net/url" "os" - "path" "path/filepath" "runtime" "time" @@ -51,10 +48,6 @@ func installNpcap(b *beat.Beat) error { if err != nil { return err } - rawURI, err := configString(cfg, "npcap.installer_location") - if err != nil { - return err - } installDst, err := configString(cfg, "npcap.install_destination") if err != nil { return err @@ -65,80 +58,31 @@ func installNpcap(b *beat.Beat) error { log := logp.NewLogger("npcap_install") - // If no location is provided, go ahead and install from the embedded installer. - if rawURI == "" { - if npcap.Installer == nil { - return nil - } - if !npcap.Upgradeable(npcap.EmbeddedInstallerVersion) { - npcap.Installer = nil - return nil - } - tmp, err := os.MkdirTemp("", "") - if err != nil { - return fmt.Errorf("could not create installation temporary directory: %w", err) - } - defer func() { - // The init sequence duplicates the embedded binary. - // Get rid of the part we can. The remainder is in - // the packetbeat text section as a string. - npcap.Installer = nil - // Remove the installer from the file system. - os.RemoveAll(tmp) - }() - installerPath := filepath.Join(tmp, "npcap.exe") - err = os.WriteFile(installerPath, npcap.Installer, 0o700) - if err != nil { - return fmt.Errorf("could not create installation temporary file: %w", err) - } - return npcap.Install(ctx, log, installerPath, installDst, false) - } - - uri, err := url.Parse(rawURI) - if err != nil { - return err - } - - // If a file or bare path is specified, go ahead and install it. - if uri.Scheme == "" || uri.Scheme == "file" { - return npcap.Install(ctx, log, uri.Path, installDst, false) - } - - canFail, err := configBool(cfg, "npcap.ignore_misssing_registry") - if err != nil { - return err - } - version, download, wantHash, err := npcap.CurrentVersion(ctx, log, rawURI) - if err != nil { - if canFail && errors.Is(err, npcap.RegistryNotFound) { - log.Warnf("%v: did not install Npcap", err) - return nil - } - return err + if npcap.Installer == nil { + return nil } - - // Is a more recent version available or are we forcing install. - if !npcap.Upgradeable(version) && !reinstall { + if !reinstall && !npcap.Upgradeable() { + npcap.Installer = nil return nil } - - dir, err := os.MkdirTemp("", "packetbeat-npcap-*") + tmp, err := os.MkdirTemp("", "") if err != nil { - return err - } - defer os.RemoveAll(dir) - pth := filepath.Join(dir, path.Base(download)) - - gotHash, err := npcap.Fetch(ctx, log, download, pth) + return fmt.Errorf("could not create installation temporary directory: %w", err) + } + defer func() { + // The init sequence duplicates the embedded binary. + // Get rid of the part we can. The remainder is in + // the packetbeat text section as a string. + npcap.Installer = nil + // Remove the installer from the file system. + os.RemoveAll(tmp) + }() + installerPath := filepath.Join(tmp, "npcap.exe") + err = os.WriteFile(installerPath, npcap.Installer, 0o700) if err != nil { - return err + return fmt.Errorf("could not create installation temporary file: %w", err) } - - if gotHash != wantHash { - return fmt.Errorf("npcap: hash mismatch for %s: want:%s got:%s", download, wantHash, gotHash) - } - - return npcap.Install(ctx, log, pth, installDst, false) + return npcap.Install(ctx, log, installerPath, installDst, false) } func configBool(cfg *common.Config, path string) (bool, error) { diff --git a/packetbeat/npcap/npcap.go b/packetbeat/npcap/npcap.go index ab356ca394d..8efddbea2fc 100644 --- a/packetbeat/npcap/npcap.go +++ b/packetbeat/npcap/npcap.go @@ -33,15 +33,8 @@ package npcap import ( "bytes" "context" - "crypto/sha256" - "encoding/hex" - "encoding/json" "errors" "fmt" - "io" - "io/ioutil" - "net/http" - "os" "os/exec" "runtime" "strings" @@ -52,10 +45,6 @@ import ( "github.com/elastic/beats/v7/libbeat/logp" ) -// RegistryNotFound is returned by CurrentVersion if the network request -// returns a 404 status code. -var RegistryNotFound = errors.New("npcap: registry not found") - var ( // Installer holds the embedded installer when run with x-pack. Installer []byte @@ -64,114 +53,6 @@ var ( EmbeddedInstallerVersion string ) -// Fetch downloads the Npcap installer, writes the content to the given filepath -// and returns the sha256 hash of the downloaded object. If the registry is not -// found RegistryNotFound is returned. -func CurrentVersion(ctx context.Context, log *logp.Logger, registry string) (version, url, hash string, err error) { - if runtime.GOOS != "windows" { - return "", "", "", errors.New("npcap: called Fetch on non-Windows platform") - } - return currentVersion(ctx, log, registry) -} - -func currentVersion(ctx context.Context, log *logp.Logger, registry string) (version, url, hash string, err error) { - req, err := http.NewRequestWithContext(ctx, "GET", registry, nil) - if err != nil { - return "", "", "", err - } - - var client http.Client - res, err := client.Do(req) - if err != nil { - return "", "", "", err - } - defer res.Body.Close() - - b, err := ioutil.ReadAll(res.Body) - if err != nil { - log.Errorf("failed to read the error response body: %v", err) - } - b = bytes.TrimSpace(b) - if len(b) == 0 { - // Give a meaningful error message and make json error if we have no body. - b = []byte("empty") - } - if res.StatusCode != http.StatusOK { - if res.StatusCode == http.StatusNotFound { - return "", "", "", fmt.Errorf("%w: %s", RegistryNotFound, registry) - } - if registry == "" { - registry = `""` - } - return "", "", "", fmt.Errorf("npcap: failed to fetch version info at %s, status: %d, message: %s", registry, res.StatusCode, b) - } - - var info struct { - Version string - URL string - Hash string - } - err = json.Unmarshal(b, &info) - if err != nil { - return "", "", "", fmt.Errorf("%w: %#q", err, b) - } - - return info.Version, info.URL, info.Hash, nil -} - -// Fetch downloads the Npcap installer, writes the content to the given filepath -// and returns the sha256 hash of the downloaded object. -func Fetch(ctx context.Context, log *logp.Logger, url, path string) (hash string, err error) { - if runtime.GOOS != "windows" { - return "", errors.New("npcap: called Fetch on non-Windows platform") - } - return fetch(ctx, log, url, path) -} - -func fetch(ctx context.Context, log *logp.Logger, url, path string) (hash string, err error) { - log.Infof("download %s to %s", url, path) - - req, err := http.NewRequestWithContext(ctx, "GET", url, nil) - if err != nil { - return "", err - } - - var client http.Client - res, err := client.Do(req) - if err != nil { - return "", err - } - defer res.Body.Close() - - if res.StatusCode != http.StatusOK { - b, err := ioutil.ReadAll(res.Body) - if err != nil { - log.Errorf("failed to read the error response body: %v", err) - } - b = bytes.TrimSpace(b) - if len(b) == 0 { - b = []byte("empty") - } - if url == "" { - url = `""` - } - return "", fmt.Errorf("npcap: failed to fetch installer at %s, status: %d, message: %s", url, res.StatusCode, b) - } - - dst, err := os.Create(path) - if err != nil { - return "", err - } - defer dst.Close() - - h := sha256.New() - _, err = io.Copy(io.MultiWriter(h, dst), res.Body) - if err != nil { - return "", err - } - return hex.EncodeToString(h.Sum(nil)), nil -} - // Install runs the Npcap installer at the provided path. The install // destination is specified by dst and installation using WinPcap // API-compatible Mode is specifed by compat. If dst is the empty string @@ -218,9 +99,9 @@ func install(ctx context.Context, log *logp.Logger, path, dst string, compat boo return reloadWinPCAP() } -func Upgradeable(version string) bool { +func Upgradeable() bool { // Chack for the place-holder file. - if version == "0.00" { + if EmbeddedInstallerVersion == "0.00" { return false } @@ -239,7 +120,7 @@ func Upgradeable(version string) bool { return true } installed = installed[:idx] - return semver.Compare("v"+installed, "v"+version) < 0 + return semver.Compare("v"+installed, "v"+EmbeddedInstallerVersion) < 0 } // Uninstall uninstalls the Npcap tools. The path to the uninstaller can diff --git a/packetbeat/npcap/npcap_test.go b/packetbeat/npcap/npcap_test.go index da31d6b25b8..e0f1a3e4eaf 100644 --- a/packetbeat/npcap/npcap_test.go +++ b/packetbeat/npcap/npcap_test.go @@ -19,114 +19,34 @@ package npcap import ( "context" - "io" - "net/http" - "net/http/httptest" - "net/url" "os" "os/exec" "path/filepath" + "runtime" "testing" "github.com/elastic/beats/v7/libbeat/logp" ) func TestNpcap(t *testing.T) { - // Elements of truth. - const ( - registryEndPoint = "/npcap/latest_installer" - latestVersion = "0.0" - latestInstaller = "npcap-0.0-oem.exe" - latestHash = "bc3e42210a58873b55554af5100db1f9439b606efde4fd20c98d7af2d6c5419b" - latestInstallerPath = "/npcap/" + latestInstaller - installer = "This is an installer. Honest!\n" - ) - var latestVersionInfo string - // Ugh. var lcfg logp.Config logp.ToObserverOutput()(&lcfg) logp.Configure(lcfg) obs := logp.ObserverLogs() - // Mock registry and download server. - mux := http.NewServeMux() - mux.HandleFunc(registryEndPoint, func(w http.ResponseWriter, req *http.Request) { - io.WriteString(w, latestVersionInfo) - }) - mux.HandleFunc(latestInstallerPath, func(w http.ResponseWriter, req *http.Request) { - io.WriteString(w, installer) - }) - srv := httptest.NewServer(mux) - u, err := url.Parse(srv.URL) - if err != nil { - t.Fatalf("failed to parse server root URL: %v", err) - } - u.Path = latestInstallerPath - latestInstallerURL := u.String() - latestVersionInfo = `{"url":"` + latestInstallerURL + `","version":"` + latestVersion + `","hash":"` + latestHash + `"}` - defer srv.Close() - // Working space. dir, err := os.MkdirTemp("", "packetbeat-npcap-*") if err != nil { t.Fatalf("failed to create working directory: %v", err) } defer os.RemoveAll(dir) - path := filepath.Join(dir, latestVersion) - - t.Run("Query Version", func(t *testing.T) { - u.Path = registryEndPoint - - log := logp.NewLogger("npcap_test_query_version") - gotVersion, gotURL, gotHash, err := currentVersion(context.Background(), log, u.String()) - messages := obs.TakeAll() - if err != nil { - t.Fatalf("failed to fetch installer: %v", err) - for _, e := range messages { - t.Log(e.Message) - } - } - - if gotVersion != latestVersion { - t.Errorf("unexpected version: got:%q want:%q", gotVersion, latestVersion) - } - if gotURL != latestInstallerURL { - t.Errorf("unexpected download location: got:%q want:%q", gotURL, latestInstallerURL) - } - if gotHash != latestHash { - t.Errorf("unexpected hash: got:%q want:%q", gotHash, latestHash) - } - }) - - t.Run("Fetch", func(t *testing.T) { - log := logp.NewLogger("npcap_test_fetch") - hash, err := fetch(context.Background(), log, latestInstallerURL, path) - messages := obs.TakeAll() - if err != nil { - t.Fatalf("failed to fetch installer: %v", err) - for _, e := range messages { - t.Log(e.Message) - } - } - - got, err := os.ReadFile(path) - if err != nil { - t.Fatalf("failed to read artifact: %v", err) - } - if string(got) != installer { - t.Errorf("unexpected download: got:%q want:%q", got, installer) - } - if hash != latestHash { - t.Errorf("unexpected download hash: got:%s want:%s", hash, latestHash) - } - }) + path := filepath.Join(dir, "installer") + if runtime.GOOS == "windows" { + path += ".exe" + } t.Run("Install", func(t *testing.T) { - err := os.Remove(path) - if err != nil { - t.Fatalf("failed to remove download: %v", err) - } build := exec.Command("go", "build", "-o", path, filepath.FromSlash("testdata/mock_installer.go")) b, err := build.CombinedOutput() if err != nil { From 6db9a67cf701e8d5337a86b23f8f7b26a6c5b74b Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 9 Dec 2021 11:21:29 +1030 Subject: [PATCH 17/26] be explicit about included files in installer --- x-pack/packetbeat/npcap/installer/.gitignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 x-pack/packetbeat/npcap/installer/.gitignore diff --git a/x-pack/packetbeat/npcap/installer/.gitignore b/x-pack/packetbeat/npcap/installer/.gitignore new file mode 100644 index 00000000000..43c0420c171 --- /dev/null +++ b/x-pack/packetbeat/npcap/installer/.gitignore @@ -0,0 +1,5 @@ +# Ignore everything but the README and the place-holder. +* +!.gitignore +!README +!npcap-0.00.exe From 466f1fc153dd8bf26fc14f2169357e5a231f82ab Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 9 Dec 2021 11:40:16 +1030 Subject: [PATCH 18/26] allow the tree to remain clean during packaging --- packetbeat/npcap/npcap.go | 5 +++-- x-pack/packetbeat/npcap/installer/README | 7 +++---- x-pack/packetbeat/npcap/npcap_windows.go | 15 +++++++++++---- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/packetbeat/npcap/npcap.go b/packetbeat/npcap/npcap.go index 8efddbea2fc..c81d1ce731d 100644 --- a/packetbeat/npcap/npcap.go +++ b/packetbeat/npcap/npcap.go @@ -100,8 +100,9 @@ func install(ctx context.Context, log *logp.Logger, path, dst string, compat boo } func Upgradeable() bool { - // Chack for the place-holder file. - if EmbeddedInstallerVersion == "0.00" { + // This is only set when a real installer is placed in + // x-pack/packetbeat/npcap/installer. + if EmbeddedInstallerVersion == "" { return false } diff --git a/x-pack/packetbeat/npcap/installer/README b/x-pack/packetbeat/npcap/installer/README index 18382c2ab8d..0e317875e52 100644 --- a/x-pack/packetbeat/npcap/installer/README +++ b/x-pack/packetbeat/npcap/installer/README @@ -1,7 +1,6 @@ This directory is pinned to allow placement of the Npcap OEM installer during x-pack Packetbeat builds. -Only one exe file may be placed here and this should be the most recent -available Npcap installer. As part of the distribution a place-holder file -is put here to allow compilation. This file must be removed when a real -installer in included for the build. +Only one additional exe file may be placed here beyond the place-holder +and this should be the most recent available Npcap installer. As part of the +distribution a place-holder file is put here to allow compilation. diff --git a/x-pack/packetbeat/npcap/npcap_windows.go b/x-pack/packetbeat/npcap/npcap_windows.go index f6ee91d2863..0eab2f5c67c 100644 --- a/x-pack/packetbeat/npcap/npcap_windows.go +++ b/x-pack/packetbeat/npcap/npcap_windows.go @@ -27,13 +27,20 @@ func init() { if err != nil { panic(fmt.Sprintf("failed to set up npcap installer: %v", err)) } - if len(list) == 0 { + var installer string + for _, f := range list { + name := f.Name() + if name != "npcap-0.00.exe" { + installer = name + break + } + } + if installer == "" { return } - if len(list) > 1 { - panic(fmt.Sprintf("unexpected number of installers found: want only one but got %d", len(list))) + if len(list) > 2 { + panic(fmt.Sprintf("unexpected number of installers found: want only one but got %d", len(list)-1)) } - installer := list[0].Name() version := strings.TrimPrefix(installer, "npcap-") version = strings.TrimSuffix(version, ".exe") From 3a36636f548fc426c2b3b3180244d21b45073b07 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 9 Dec 2021 12:03:41 +1030 Subject: [PATCH 19/26] use config struct and allow user to block install --- .../_meta/config/windows_npcap.yml.tmpl | 8 +- packetbeat/beater/install_npcap.go | 81 +++++-------------- 2 files changed, 24 insertions(+), 65 deletions(-) diff --git a/packetbeat/_meta/config/windows_npcap.yml.tmpl b/packetbeat/_meta/config/windows_npcap.yml.tmpl index 21bcaf3b2b6..89d29da858c 100644 --- a/packetbeat/_meta/config/windows_npcap.yml.tmpl +++ b/packetbeat/_meta/config/windows_npcap.yml.tmpl @@ -6,10 +6,6 @@ # capture library for Windows should be obtained and installed. # Windows Npcap installation is only available with x-pack. #npcap: -# # installer_location is either a URL or a bare path. The URL may have an http, -# # https or file scheme. If it is empty or unset, a bundled installer is used -# # and the retain_download and ignore_missing_registry are ignored. -# installer_location: "" # # install_destination allows configuration of the location that the Npcap will # # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. # install_destination: "" @@ -20,4 +16,8 @@ # # By default Npcap will be installed only when a newer version of Npcap is available. # # force_reinstall forces a new installation of Npcap in all cases. # force_reinstall: false +# # If a specific local version of Npcap is required installation by packetbeat +# # can be blocked by setting never_install to true. No action is taken if this +# # option is set to true. +# never_install: false {{- end -}} diff --git a/packetbeat/beater/install_npcap.go b/packetbeat/beater/install_npcap.go index df5ccd0c6cf..f0143f12552 100644 --- a/packetbeat/beater/install_npcap.go +++ b/packetbeat/beater/install_npcap.go @@ -26,11 +26,22 @@ import ( "time" "github.com/elastic/beats/v7/libbeat/beat" - "github.com/elastic/beats/v7/libbeat/common" "github.com/elastic/beats/v7/libbeat/logp" "github.com/elastic/beats/v7/packetbeat/npcap" ) +type npcapConfig struct { + NeverInstall bool `config:"npcap.never_install"` + ForceReinstall bool `config:"npcap.force_reinstall"` + InstallTimeout time.Duration `config:"npcap.install_timeout"` + InstallDestination string `config:"npcal.install_destination"` +} + +func (c *npcapConfig) Init() { + // Set defaults. + c.InstallTimeout = 120 * time.Second +} + func installNpcap(b *beat.Beat) error { if !b.Info.ElasticLicensed { return nil @@ -39,21 +50,16 @@ func installNpcap(b *beat.Beat) error { return nil } - cfg := b.BeatConfig - reinstall, err := configBool(cfg, "npcap.force_reinstall") + var cfg npcapConfig + err := b.BeatConfig.Unpack(&cfg) if err != nil { - return err + return fmt.Errorf("failed to unpack npcap config: %w", err) } - timeout, err := configDuration(cfg, "npcap.install_timeout") - if err != nil { - return err - } - installDst, err := configString(cfg, "npcap.install_destination") - if err != nil { - return err + if cfg.NeverInstall { + return nil } - ctx, cancel := context.WithTimeout(context.Background(), timeout) + ctx, cancel := context.WithTimeout(context.Background(), cfg.InstallTimeout) defer cancel() log := logp.NewLogger("npcap_install") @@ -61,7 +67,7 @@ func installNpcap(b *beat.Beat) error { if npcap.Installer == nil { return nil } - if !reinstall && !npcap.Upgradeable() { + if !cfg.ForceReinstall && !npcap.Upgradeable() { npcap.Installer = nil return nil } @@ -82,52 +88,5 @@ func installNpcap(b *beat.Beat) error { if err != nil { return fmt.Errorf("could not create installation temporary file: %w", err) } - return npcap.Install(ctx, log, installerPath, installDst, false) -} - -func configBool(cfg *common.Config, path string) (bool, error) { - ok, err := cfg.Has(path, -1) - if err != nil { - return false, err - } - if !ok { - return false, nil - } - v, err := cfg.Bool(path, -1) - if err != nil { - return false, err - } - return v, nil -} - -func configString(cfg *common.Config, path string) (string, error) { - ok, err := cfg.Has(path, -1) - if err != nil { - return "", err - } - if !ok { - return "", nil - } - v, err := cfg.String(path, -1) - if err != nil { - return "", err - } - return v, nil -} - -func configDuration(cfg *common.Config, path string) (time.Duration, error) { - const defaultTimeout = 120 * time.Second - - v, err := configString(cfg, path) - if err != nil { - return 0, err - } - if v == "" { - return defaultTimeout, nil - } - d, err := time.ParseDuration(v) - if err != nil { - return 0, err - } - return d, nil + return npcap.Install(ctx, log, installerPath, cfg.InstallDestination, false) } From bc8149ede87d3a8f632fcc053a5619cf7d4ccb4d Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Fri, 10 Dec 2021 14:13:22 +1030 Subject: [PATCH 20/26] test config file contents --- dev-tools/packaging/package_test.go | 50 +++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/dev-tools/packaging/package_test.go b/dev-tools/packaging/package_test.go index 249bd0bb6db..5e57c4f6c34 100644 --- a/dev-tools/packaging/package_test.go +++ b/dev-tools/packaging/package_test.go @@ -23,6 +23,7 @@ package dev_tools import ( "archive/tar" "archive/zip" + "bufio" "bytes" "compress/gzip" "encoding/json" @@ -169,7 +170,7 @@ func checkTar(t *testing.T, file string) { } func checkZip(t *testing.T, file string) { - p, err := readZip(file) + p, err := readZip(t, file, checkNpcapNotices) if err != nil { t.Error(err) return @@ -183,6 +184,34 @@ func checkZip(t *testing.T, file string) { checkLicensesPresent(t, "", p) } +var npcapConfigPattern = regexp.MustCompile("Windows Npcap installation settings") + +func checkNpcapNotices(pkg, file string, contents io.Reader) error { + if !strings.Contains(pkg, "packetbeat") || !strings.Contains(pkg, "windows") { + return nil + } + + wantNotices := strings.Contains(pkg, "windows") + + // If the packetbeat README.md is made to be generated + // conditionally then it should also be checked here. + pkg = filepath.Base(pkg) + file, err := filepath.Rel(pkg[:len(pkg)-len(filepath.Ext(pkg))], file) + if err != nil { + return err + } + switch file { + case "packetbeat.yml", "packetbeat.reference.yml": + if npcapConfigPattern.MatchReader(bufio.NewReader(contents)) != wantNotices { + if wantNotices { + return fmt.Errorf("Npcap config section not found in config file %s in %s", file, pkg) + } + return fmt.Errorf("unexpected Npcap config section found in config file %s in %s", file, pkg) + } + } + return nil +} + func checkDocker(t *testing.T, file string) { p, info, err := readDocker(file) if err != nil { @@ -623,7 +652,11 @@ func readTarContents(tarName string, data io.Reader) (*packageFile, error) { return p, nil } -func readZip(zipFile string) (*packageFile, error) { +// inspector is a file contents inspector. It vets the contents of the file +// within a package for a requirement and returns an error if it is not met. +type inspector func(pkg, file string, contents io.Reader) error + +func readZip(t *testing.T, zipFile string, inspectors ...inspector) (*packageFile, error) { r, err := zip.OpenReader(zipFile) if err != nil { return nil, err @@ -636,6 +669,18 @@ func readZip(zipFile string) (*packageFile, error) { File: f.Name, Mode: f.Mode(), } + for _, inspect := range inspectors { + r, err := f.Open() + if err != nil { + t.Errorf("failed to open %s in %s: %v", f.Name, zipFile, err) + break + } + err = inspect(zipFile, f.Name, r) + if err != nil { + t.Error(err) + } + r.Close() + } } return p, nil @@ -740,7 +785,6 @@ func readDockerManifest(r io.Reader) (*dockerManifest, error) { err = json.Unmarshal(data, &manifests) if err != nil { return nil, err - } if len(manifests) != 1 { From 784353bea552efee5746a276ce93a2977b914837 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 13 Jan 2022 09:34:44 +1030 Subject: [PATCH 21/26] log pcap version for windows platforms --- packetbeat/beater/install_npcap.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packetbeat/beater/install_npcap.go b/packetbeat/beater/install_npcap.go index f0143f12552..ef9edd5617b 100644 --- a/packetbeat/beater/install_npcap.go +++ b/packetbeat/beater/install_npcap.go @@ -25,6 +25,8 @@ import ( "runtime" "time" + "github.com/google/gopacket/pcap" + "github.com/elastic/beats/v7/libbeat/beat" "github.com/elastic/beats/v7/libbeat/logp" "github.com/elastic/beats/v7/packetbeat/npcap" @@ -50,6 +52,16 @@ func installNpcap(b *beat.Beat) error { return nil } + defer func() { + log := logp.NewLogger("npcap") + npcapVersion := pcap.Version() + if npcapVersion == "" { + log.Warn("no version available for npcap") + } else { + log.Infof("npcap version: %s", npcapVersion) + } + }() + var cfg npcapConfig err := b.BeatConfig.Unpack(&cfg) if err != nil { From 5222fc2de2410b454a1c5f7c3a88e84dfe672d64 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Fri, 3 Dec 2021 11:34:42 +1030 Subject: [PATCH 22/26] x-pack/packetbeat: add license notices Also hold license at ELv1. --- NOTICE.txt | 1 - dev-tools/notice/NOTICE.txt.tmpl | 4 +- dev-tools/packaging/package_test.go | 34 ++- packetbeat/README.md | 14 ++ .../_meta/config/windows_npcap.yml.tmpl | 15 +- packetbeat/scripts/mage/package.go | 29 +++ x-pack/packetbeat/LICENSE-Npcap.txt | 228 +++++++++++++++++ x-pack/packetbeat/magefile.go | 5 + x-pack/packetbeat/npcap/installer/LICENSE | 229 ++++++++++++++++++ x-pack/packetbeat/npcap/installer/README | 13 + 10 files changed, 565 insertions(+), 7 deletions(-) create mode 100644 x-pack/packetbeat/LICENSE-Npcap.txt create mode 100644 x-pack/packetbeat/npcap/installer/LICENSE diff --git a/NOTICE.txt b/NOTICE.txt index 853c448d3a9..b7297edf10d 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -37624,4 +37624,3 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/dev-tools/notice/NOTICE.txt.tmpl b/dev-tools/notice/NOTICE.txt.tmpl index b32b4e808ca..5477a22975e 100644 --- a/dev-tools/notice/NOTICE.txt.tmpl +++ b/dev-tools/notice/NOTICE.txt.tmpl @@ -26,5 +26,5 @@ Third party libraries used by the Elastic Beats project: {{ "=" | line }} Indirect dependencies -{{ template "depInfo" .Indirect }} -{{ end }} +{{ template "depInfo" .Indirect -}} +{{- end}} diff --git a/dev-tools/packaging/package_test.go b/dev-tools/packaging/package_test.go index 5e57c4f6c34..9759568de6a 100644 --- a/dev-tools/packaging/package_test.go +++ b/dev-tools/packaging/package_test.go @@ -184,14 +184,35 @@ func checkZip(t *testing.T, file string) { checkLicensesPresent(t, "", p) } -var npcapConfigPattern = regexp.MustCompile("Windows Npcap installation settings") +const ( + npcapSettings = "Windows Npcap installation settings" + npcapGrant = `Insecure.Com LLC \(“The Nmap Project”\) has granted Elasticsearch` + npcapLicense = `Dependency : Npcap \(https://nmap.org/npcap/\)` + libpcapLicense = `Dependency : Libpcap \(http://www.tcpdump.org/\)` + winpcapLicense = `Dependency : Winpcap \(https://www.winpcap.org/\)` + radiotapLicense = `Dependency : ieee80211_radiotap.h Header File` +) + +var ( + // These reflect the order that the licenses and notices appear in the relevant files. + npcapConfigPattern = regexp.MustCompile( + "(?s)" + npcapSettings + + ".*" + npcapGrant, + ) + npcapLicensePattern = regexp.MustCompile( + "(?s)" + npcapLicense + + ".*" + libpcapLicense + + ".*" + winpcapLicense + + ".*" + radiotapLicense, + ) +) func checkNpcapNotices(pkg, file string, contents io.Reader) error { - if !strings.Contains(pkg, "packetbeat") || !strings.Contains(pkg, "windows") { + if !strings.Contains(pkg, "packetbeat") { return nil } - wantNotices := strings.Contains(pkg, "windows") + wantNotices := strings.Contains(pkg, "windows") && !strings.Contains(pkg, "oss") // If the packetbeat README.md is made to be generated // conditionally then it should also be checked here. @@ -208,6 +229,13 @@ func checkNpcapNotices(pkg, file string, contents io.Reader) error { } return fmt.Errorf("unexpected Npcap config section found in config file %s in %s", file, pkg) } + case "NOTICE.txt": + if npcapLicensePattern.MatchReader(bufio.NewReader(contents)) != wantNotices { + if wantNotices { + return fmt.Errorf("Npcap license section not found in %s file in %s", file, pkg) + } + return fmt.Errorf("unexpected Npcap license section found in %s file in %s", file, pkg) + } } return nil } diff --git a/packetbeat/README.md b/packetbeat/README.md index fcda826edbf..0ce898ac499 100644 --- a/packetbeat/README.md +++ b/packetbeat/README.md @@ -39,3 +39,17 @@ If you are sure you found a bug or have a feature request, open an issue on We love contributions from our community! Please read the [CONTRIBUTING.md](../CONTRIBUTING.md) file. + +## LICENSE NOTICE for Windows users of Packetbeat + +The default distribution of Packetbeat for Windows comes bundled with the Npcap +library. This is not available in the OSS-only distribution of Packetbeat. + +**Restrictions on Distribution** + +Insecure.Com LLC (“The Nmap Project”) has granted Elasticsearch BV and its +affiliates the right to include Npcap with this distribution of Packetbeat. +You may not distribute this version of Packetbeat or any other package from +Elastic that includes Npcap. If you wish to distribute Npcap, or any package +that includes Npcap, you should reach out to The Nmap Project to obtain a +distribution license. See https://nmap.org/npcap/ for more details. diff --git a/packetbeat/_meta/config/windows_npcap.yml.tmpl b/packetbeat/_meta/config/windows_npcap.yml.tmpl index 89d29da858c..a6c13db4a53 100644 --- a/packetbeat/_meta/config/windows_npcap.yml.tmpl +++ b/packetbeat/_meta/config/windows_npcap.yml.tmpl @@ -4,7 +4,20 @@ # Windows Npcap installation options. These options specify how the Npcap packet # capture library for Windows should be obtained and installed. -# Windows Npcap installation is only available with x-pack. +# Npcap installation is only available in the default distribution of Packetbeat +# for Windows and is not available in the OSS-only distribution of Packetbeat. +# +# LICENSE NOTICE +# +# Restrictions on Distribution +# +# Insecure.Com LLC (“The Nmap Project”) has granted Elasticsearch BV and its +# affiliates the right to include Npcap with this distribution of Packetbeat. +# You may not distribute this version of Packetbeat or any other package from +# Elastic that includes Npcap. If you wish to distribute Npcap, or any package +# that includes Npcap, you should reach out to The Nmap Project to obtain a +# distribution license. See https://nmap.org/npcap/ for more details. +# #npcap: # # install_destination allows configuration of the location that the Npcap will # # place the Npcap library and associated files. See https://nmap.org/npcap/guide/npcap-users-guide.html#npcap-installation-uninstall-options. diff --git a/packetbeat/scripts/mage/package.go b/packetbeat/scripts/mage/package.go index 55f26493cf5..4ff693c918c 100644 --- a/packetbeat/scripts/mage/package.go +++ b/packetbeat/scripts/mage/package.go @@ -18,6 +18,9 @@ package mage import ( + "os" + "path/filepath" + "github.com/pkg/errors" devtools "github.com/elastic/beats/v7/dev-tools/mage" @@ -48,6 +51,29 @@ func CustomizePackaging() { return devtools.Config(devtools.ReferenceConfigType, c, spec.MustExpand("{{.PackageDir}}")) }, } + npcapNoticeTxt = devtools.PackageFile{ + Mode: 0o644, + Source: "{{.PackageDir}}/NOTICE.txt", + Dep: func(spec devtools.PackageSpec) error { + repo, err := devtools.GetProjectRepoInfo() + if err != nil { + return err + } + + notice, err := os.ReadFile(filepath.Join(repo.RootDir, "NOTICE.txt")) + if err != nil { + return err + } + + license, err := os.ReadFile(devtools.XPackBeatDir("npcap/installer/LICENSE")) + if err != nil { + return err + } + notice = append(notice, license...) + + return os.WriteFile(spec.MustExpand("{{.PackageDir}}/NOTICE.txt"), notice, 0o644) + }, + } ) for _, args := range devtools.Packages { @@ -56,6 +82,9 @@ func CustomizePackaging() { case devtools.TarGz, devtools.Zip: args.Spec.ReplaceFile("{{.BeatName}}.yml", configYml) args.Spec.ReplaceFile("{{.BeatName}}.reference.yml", referenceConfigYml) + if devtools.BeatLicense == "Elastic License" && args.OS == "windows" { + args.Spec.ReplaceFile("NOTICE.txt", npcapNoticeTxt) + } case devtools.Deb, devtools.RPM, devtools.DMG: args.Spec.ReplaceFile("/etc/{{.BeatName}}/{{.BeatName}}.yml", configYml) args.Spec.ReplaceFile("/etc/{{.BeatName}}/{{.BeatName}}.reference.yml", referenceConfigYml) diff --git a/x-pack/packetbeat/LICENSE-Npcap.txt b/x-pack/packetbeat/LICENSE-Npcap.txt new file mode 100644 index 00000000000..850c567c317 --- /dev/null +++ b/x-pack/packetbeat/LICENSE-Npcap.txt @@ -0,0 +1,228 @@ + +NPCAP COPYRIGHT / END USER LICENSE AGREEMENT + +Npcap is a Windows packet sniffing driver and library and is copyright +(c) 2013-2021 by Insecure.Com LLC ("The Nmap Project"). All rights +reserved. + +Even though Npcap source code is publicly available for review, it is +not open source software and may not be redistributed without special +permission from the Nmap Project. The standard version is also +limited to installation on five systems. We fund the Npcap project by +selling two types of commercial licenses to a special Npcap OEM +edition: + +1) Npcap OEM Redistribution License allows companies to redistribute +Npcap with their products. + +2) Npcap OEM Internal Use License allows companies to use Npcap OEM +internally in excess of the free/demo version's normal 5-system +limitation. + +Both of these licenses include updates and support as well as a +warranty. Npcap OEM also includes a silent installer for unattended +installation. Further details about Npcap OEM are available from +https://nmap.org/npcap/oem/, and you are also welcome to contact us at +sales@nmap.com to ask any questions or set up a license for your +organization. + +Free and open source software producers are also welcome to contact us +for redistribution requests. However, we normally recommend that such +authors instead ask your users to download and install Npcap themselves. + +If the Nmap Project (directly or through one of our commercial +licensing customers) has granted you additional rights to Npcap or +Npcap OEM, those additional rights take precedence where they conflict +with the terms of this license agreement. + +Since the Npcap source code is available for download and review, +users sometimes contribute code patches to fix bugs or add new +features. By sending these changes to the Nmap Project (including +through direct email or our mailing lists or submitting pull requests +through our source code repository), it is understood unless you +specify otherwise that you are offering the Nmap Project the +unlimited, non-exclusive right to reuse, modify, and relicence your +code contribution so that we may (but are not obligated to) +incorporate it into Npcap. If you wish to specify special license +conditions or restrictions on your contributions, just say so when you +send them. + +This copy of Npcap (the "Software") and accompanying documentation is +licensed and not sold. This Software is protected by copyright laws +and treaties, as well as laws and treaties related to other forms of +intellectual property. The Nmap Project owns intellectual property +rights in the Software. The Licensee's ("you" or "your") license to +download, use, copy, or change the Software is subject to these rights +and to all the terms and conditions of this End User License Agreement +("Agreement"). + +ACCEPTANCE + +By accepting this agreement or by downloading, installing, using, or +copying the Software, or by clicking "I Agree", you agree to be bound +by the terms of this EULA. If you do not agree to the terms of this +EULA, do not install, use, or copy the Software. + +LICENSE GRANT + +This Agreement entitles you to install and use five (5) copies of the +Software. In addition, you may make archival copies of the Software +which may only be used for the reinstallation of the Software. This +Agreement does not permit the installation or use of more than 5 +copies of the Software, or the installation of the Software on more +than five computer at any given time, on a system that allows shared +used of applications by more than five users, or on any configuration +or system of computers that allows more than five users. A user may +only have one instance of this Agreement active at once. For example, +downloading the software multiple times, downloading multiple versions +of the software, and/or executing the software installer multiple +times do not grant any additional rights such as using the software on +more machines. + +The terms "computer" and "machine" in this license include any +computing device, including software computing instances such as +virtual machines and Docker containers. + +Copies of Npcap do not count toward the five copy, five computer, or +five user limitations imposed by this section if they are installed +and used solely in conjunction with any of the following software: + +o The Nmap Security Scanner, as distributed from https://nmap.org + +o The Wireshark network protocol analyzer, as distributed from + https://www.wireshark.org/ + +o Microsoft Defender for Identity, as distributed from + https://www.microsoft.com/en-us/microsoft-365/security/identity-defender + +Users wishing to redistribute Npcap or exceed the usage limits imposed +by this free license or benefit from commercial support and features +such as a silent installer should contact sales@nmap.com to obtain an +appropriate commercial license agreement. More details on our OEM +edition is also available from https://nmap.org/npcap/oem/. + +DISCLAIMER OF WARRANTIES AND LIMITATION OF LIABILITY + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +RESTRICTIONS ON TRANSFER + +Without first obtaining the express written consent of the Nmap +Project, you may not assign your rights and obligations under this +Agreement, or redistribute, encumber, sell, rent, lease, sublicense, +or otherwise transfer your rights to the Software Product. + +RESTRICTIONS ON USE + +You may not use, copy, or install the Software Product on more than +five computers, or permit the use, copying, or installation of the +Software Product by more than five users or on more than five +computers. + +RESTRICTIONS ON COPYING + +You may not copy any part of the Software except to the extent that +licensed use inherently demands the creation of a temporary copy +stored in computer memory and not permanently affixed on storage +medium. You may make archival copies as well. + +DISCLAIMER OF WARRANTIES AND LIMITATION OF LIABILITY + +UNLESS OTHERWISE EXPLICITLY AGREED TO IN WRITING BY THE NMAP PROJECT, +THE NMAP PROJECT MAKES NO OTHER WARRANTIES, EXPRESS OR IMPLIED, IN +FACT OR IN LAW, INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES +OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE OTHER THAN AS +SET FORTH IN THIS AGREEMENT OR IN THE LIMITED WARRANTY DOCUMENTS +PROVIDED WITH THE SOFTWARE. + +The Nmap Project makes no warranty that the Software will meet your +requirements or operate under your specific conditions of use. The +Nmap Project makes no warranty that operation of the Software Product +will be secure, error free, or free from interruption. YOU MUST +DETERMINE WHETHER THE SOFTWARE SUFFICIENTLY MEETS YOUR REQUIREMENTS +FOR SECURITY AND UNINTERRUPTABILITY. YOU BEAR SOLE RESPONSIBILITY AND +ALL LIABILITY FOR ANY LOSS INCURRED DUE TO FAILURE OF THE SOFTWARE TO +MEET YOUR REQUIREMENTS. THE NMAP PROJECT WILL NOT, UNDER ANY +CIRCUMSTANCES, BE RESPONSIBLE OR LIABLE FOR THE LOSS OF DATA ON ANY +COMPUTER OR INFORMATION STORAGE DEVICE. + +UNDER NO CIRCUMSTANCES SHALL THE NMAP PROJECT, ITS DIRECTORS, +OFFICERS, EMPLOYEES OR AGENTS BE LIABLE TO YOU OR ANY OTHER PARTY FOR +INDIRECT, CONSEQUENTIAL, SPECIAL, INCIDENTAL, PUNITIVE, OR EXEMPLARY +DAMAGES OF ANY KIND (INCLUDING LOST REVENUES OR PROFITS OR LOSS OF +BUSINESS) RESULTING FROM THIS AGREEMENT, OR FROM THE FURNISHING, +PERFORMANCE, INSTALLATION, OR USE OF THE SOFTWARE, WHETHER DUE TO A +BREACH OF CONTRACT, BREACH OF WARRANTY, OR THE NEGLIGENCE OF THE NMAP +PROJECT OR ANY OTHER PARTY, EVEN IF THE NMAP PROJECT IS ADVISED +BEFOREHAND OF THE POSSIBILITY OF SUCH DAMAGES. TO THE EXTENT THAT THE +APPLICABLE JURISDICTION LIMITS THE NMAP PROJECT'S ABILITY TO DISCLAIM +ANY IMPLIED WARRANTIES, THIS DISCLAIMER SHALL BE EFFECTIVE TO THE +MAXIMUM EXTENT PERMITTED. + +LIMITATIONS OF REMEDIES AND DAMAGES + +Your remedy for a breach of this Agreement or of any warranty included +in this Agreement is the correction or replacement of the Software or +a refund of the purchase price of the Software, exclusive of any costs +for shipping and handling. Selection of whether to correct or replace +or refund shall be solely at the discretion of the Nmap Project. The +Nmap Project reserves the right to substitute a functionally +equivalent copy of the Software Product as a replacement. + +Any claim must be made within the applicable warranty period. All +warranties cover only defects arising under normal use and do not +include malfunctions or failure resulting from misuse, abuse, neglect, +alteration, problems with electrical power, acts of nature, unusual +temperatures or humidity, improper installation, or damage determined +by the Nmap Project to have been caused by you. All limited warranties +on the Software Product are granted only to you and are +non-transferable. + +You agree to indemnify and hold the Nmap Project harmless from all +claims, judgments, liabilities, expenses, or costs arising from your +breach of this Agreement and/or acts or omissions. + +GOVERNING LAW, JURISDICTION AND COSTS + +This Agreement is governed by the laws the United States of America +and Washington State, without regard to Washington's conflict or +choice of law provisions. + +SEVERABILITY + +If any provision of this Agreement shall be held to be invalid or +unenforceable, the remainder of this Agreement shall remain in full +force and effect. To the extent any express or implied restrictions +are not permitted by applicable laws, these express or implied +restrictions shall remain in force and effect to the maximum extent +permitted by such applicable laws. + +THIRD PARTY SOFTWARE ATTRIBUTION + +Npcap uses several 3rd party open source software libraries: + +* The libpcap portable packet capturing library from https://tcpdump.org +* The Winpcap packet capturing library. It has been abandoned, but is + currently still available from https://www.winpcap.org/. +* The ieee80211_radiotap.h header file from David Young + +All of these are open source with BSD-style licenses that allow for +unlimited use and royalty-free redistribution within other software +(including commercial/proprietary software). Some include a warranty +disclaimer (relating to the original authors) and require a small +amount of acknowledgment text be added somewhere in the documentation +of any software which includes them (including indirect inclusion +through Npcap). + +The required acknowledgement text as well as full license text and +source details for these libraries is available from: +https://npcap.org/src/docs/Npcap-Third-Party-Open-Source.pdf . + +Since Insecure.Com LLC is not the author of this 3rd party code, we +can not waive or modify it’s software copyright or license. Npcap +users and redistributors must comply with the relevant Npcap license +(either the free/demo license or a commercial Npcap OEM license they +may have purchased) as well as the minimal requirements of this 3rd +party open source software. diff --git a/x-pack/packetbeat/magefile.go b/x-pack/packetbeat/magefile.go index f5e930c5156..8d064654ff5 100644 --- a/x-pack/packetbeat/magefile.go +++ b/x-pack/packetbeat/magefile.go @@ -32,6 +32,11 @@ func init() { devtools.BeatDescription = "Packetbeat analyzes network traffic and sends the data to Elasticsearch." devtools.BeatLicense = "Elastic License" + if devtools.Platform.GOOS == "windows" { + // Explicitly hold at ELv1 to satisfy Npcap licensing on Windows. + // Do not alter this without checking with the licensing policy. + devtools.BeatLicense = "Elastic License" + } } // Update updates the generated files. diff --git a/x-pack/packetbeat/npcap/installer/LICENSE b/x-pack/packetbeat/npcap/installer/LICENSE new file mode 100644 index 00000000000..5d52febbd91 --- /dev/null +++ b/x-pack/packetbeat/npcap/installer/LICENSE @@ -0,0 +1,229 @@ +-------------------------------------------------------------------------------- +Dependency : Npcap (https://nmap.org/npcap/) +Version: 1.55 +Licence type: Commercial +-------------------------------------------------------------------------------- + +Npcap is Copyright (c) 2013-2021 Insecure.Com LLC. All rights reserved. +See https://npcap.org for details. + +Portions of Npcap are Copyright (c) 1999 - 2005 NetGroup, Politecnico di +Torino (Italy). +Portions of Npcap are Copyright (c) 2005 - 2010 CACE Technologies, +Davis (California). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. Neither the name of the Politecnico di Torino, CACE Technologies + nor the names of its contributors may be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +This product includes software developed by the University of California, +Lawrence Berkeley Laboratory and its contributors. + +Portions of Npcap are Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, +1996, 1997 The Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. + +Portions of Npcap are Copyright (c) 2003, 2004 David Young. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright notice, + thislist of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of David Young may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL DAVID YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +Dependency : Libpcap (http://www.tcpdump.org/) +Version: 1.10 +Licence type: BSD +-------------------------------------------------------------------------------- + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The names of the authors may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +-------------------------------------------------------------------------------- +Dependency : Winpcap (https://www.winpcap.org/) +Version: 4.1.3 +Licence type: BSD +-------------------------------------------------------------------------------- + +Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy). +Copyright (c) 2005 - 2010 CACE Technologies, Davis (California). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. Neither the name of the Politecnico di Torino, CACE Technologies + nor the names of its contributors may be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +This product includes software developed by the University of California, +Lawrence Berkeley Laboratory and its contributors. +Portions Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 The +Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. + + +-------------------------------------------------------------------------------- +Dependency : ieee80211_radiotap.h Header File +Version: Unversioned +Licence type: BSD +-------------------------------------------------------------------------------- + +Copyright (c) 2003, 2004 David Young. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + 3. The name of David Young may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL DAVID YOUNG BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/x-pack/packetbeat/npcap/installer/README b/x-pack/packetbeat/npcap/installer/README index 0e317875e52..404d6617dd1 100644 --- a/x-pack/packetbeat/npcap/installer/README +++ b/x-pack/packetbeat/npcap/installer/README @@ -4,3 +4,16 @@ during x-pack Packetbeat builds. Only one additional exe file may be placed here beyond the place-holder and this should be the most recent available Npcap installer. As part of the distribution a place-holder file is put here to allow compilation. + +LICENSE NOTICE + +Restrictions on Distribution + +Insecure.Com LLC (“The Nmap Project”) has granted Elasticsearch BV and its +affiliates the right to include Npcap with this distribution of Packetbeat. +You may not distribute this version of Packetbeat or any other package from +Elastic that includes Npcap. If you wish to distribute Npcap, or any package +that includes Npcap, you should reach out to The Nmap Project to obtain a +distribution license. See https://nmap.org/npcap/ for more details. + +See the LICENSE file in this directory. From 64ec3b5a6fc5f588982f1c1c5bf8b2ca1b2a3605 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 16 Dec 2021 07:12:51 +1030 Subject: [PATCH 23/26] remove license hold --- x-pack/packetbeat/magefile.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/x-pack/packetbeat/magefile.go b/x-pack/packetbeat/magefile.go index 8d064654ff5..f5e930c5156 100644 --- a/x-pack/packetbeat/magefile.go +++ b/x-pack/packetbeat/magefile.go @@ -32,11 +32,6 @@ func init() { devtools.BeatDescription = "Packetbeat analyzes network traffic and sends the data to Elasticsearch." devtools.BeatLicense = "Elastic License" - if devtools.Platform.GOOS == "windows" { - // Explicitly hold at ELv1 to satisfy Npcap licensing on Windows. - // Do not alter this without checking with the licensing policy. - devtools.BeatLicense = "Elastic License" - } } // Update updates the generated files. From 636cfaad7c44a7db6e7f215fc5cfe329a7fe9bbc Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Thu, 16 Dec 2021 20:34:23 +1030 Subject: [PATCH 24/26] experiment: always write notice but conditionally add npcap licenses --- packetbeat/scripts/mage/package.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packetbeat/scripts/mage/package.go b/packetbeat/scripts/mage/package.go index 4ff693c918c..b0a5637527f 100644 --- a/packetbeat/scripts/mage/package.go +++ b/packetbeat/scripts/mage/package.go @@ -69,7 +69,9 @@ func CustomizePackaging() { if err != nil { return err } - notice = append(notice, license...) + if spec.OS == "windows" && spec.License == "Elastic License" { + notice = append(notice, license...) + } return os.WriteFile(spec.MustExpand("{{.PackageDir}}/NOTICE.txt"), notice, 0o644) }, @@ -82,9 +84,7 @@ func CustomizePackaging() { case devtools.TarGz, devtools.Zip: args.Spec.ReplaceFile("{{.BeatName}}.yml", configYml) args.Spec.ReplaceFile("{{.BeatName}}.reference.yml", referenceConfigYml) - if devtools.BeatLicense == "Elastic License" && args.OS == "windows" { - args.Spec.ReplaceFile("NOTICE.txt", npcapNoticeTxt) - } + args.Spec.ReplaceFile("NOTICE.txt", npcapNoticeTxt) case devtools.Deb, devtools.RPM, devtools.DMG: args.Spec.ReplaceFile("/etc/{{.BeatName}}/{{.BeatName}}.yml", configYml) args.Spec.ReplaceFile("/etc/{{.BeatName}}/{{.BeatName}}.reference.yml", referenceConfigYml) From ac71149203bc7647fc9c8521625b8cfff71abcec Mon Sep 17 00:00:00 2001 From: Andrew Kroh Date: Thu, 16 Dec 2021 15:09:14 -0500 Subject: [PATCH 25/26] Create PackageDir before WriteFile --- packetbeat/scripts/mage/package.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packetbeat/scripts/mage/package.go b/packetbeat/scripts/mage/package.go index b0a5637527f..031ca09c894 100644 --- a/packetbeat/scripts/mage/package.go +++ b/packetbeat/scripts/mage/package.go @@ -65,15 +65,15 @@ func CustomizePackaging() { return err } - license, err := os.ReadFile(devtools.XPackBeatDir("npcap/installer/LICENSE")) - if err != nil { - return err - } if spec.OS == "windows" && spec.License == "Elastic License" { + license, err := os.ReadFile(devtools.XPackBeatDir("npcap/installer/LICENSE")) + if err != nil { + return err + } notice = append(notice, license...) } - return os.WriteFile(spec.MustExpand("{{.PackageDir}}/NOTICE.txt"), notice, 0o644) + return os.WriteFile(devtools.CreateDir(spec.MustExpand("{{.PackageDir}}/NOTICE.txt")), notice, 0o644) }, } ) From a58e5e500cee56faee3cf4838df85b94e5dd1249 Mon Sep 17 00:00:00 2001 From: Dan Kortschak Date: Wed, 5 Jan 2022 07:24:05 +1030 Subject: [PATCH 26/26] bump Npcap version --- x-pack/packetbeat/npcap/installer/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/packetbeat/npcap/installer/LICENSE b/x-pack/packetbeat/npcap/installer/LICENSE index 5d52febbd91..94134072930 100644 --- a/x-pack/packetbeat/npcap/installer/LICENSE +++ b/x-pack/packetbeat/npcap/installer/LICENSE @@ -1,6 +1,6 @@ -------------------------------------------------------------------------------- Dependency : Npcap (https://nmap.org/npcap/) -Version: 1.55 +Version: 1.60 Licence type: Commercial --------------------------------------------------------------------------------