Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions NOTICE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17141,12 +17141,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


--------------------------------------------------------------------------------
Dependency : github.com/elastic/gopacket
Version: v1.1.20-0.20241002174017-e8c5fda595e6
Dependency : github.com/samuelvl/gopacket
Version: v0.0.0-20260703114848-a5059dceefc3
Licence type (autodetected): BSD-3-Clause
--------------------------------------------------------------------------------

Contents of probable licence file $GOMODCACHE/github.com/elastic/gopacket@v1.1.20-0.20241002174017-e8c5fda595e6/LICENSE:
Contents of probable licence file $GOMODCACHE/github.com/samuelvl/gopacket@v0.0.0-20260703114848-a5059dceefc3/LICENSE:

Copyright (c) 2012 Google, Inc. All rights reserved.
Copyright (c) 2009-2011 Andreas Krennmair. All rights reserved.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# REQUIRED
# Kind can be one of:
# - breaking-change: a change to previously-documented behavior
# - deprecation: functionality that is being removed in a later release
# - bug-fix: fixes a problem in a previous version
# - enhancement: extends functionality but does not break or fix existing behavior
# - feature: new functionality
# - known-issue: problems that we are aware of in a given version
# - security: impacts on the security of a product or a user’s deployment.
# - upgrade: important information for someone upgrading from a prior version
# - other: does not fit into any of the other categories
kind: bug-fix

# REQUIRED for all kinds
# Change summary; a 80ish characters long description of the change.
summary: Load the Npcap wpcap.dll lazily to avoid blocking Npcap upgrades on Windows

# REQUIRED for breaking-change, deprecation, known-issue
# Long description; in case the summary is not enough to describe the change
# this field accommodate a description without length limits.
description: >
On Windows, importing gopacket/pcap loaded wpcap.dll in the package init, so
every Beat that links Packetbeat's capture code held the DLL open even when it
never captured traffic. This stopped Packetbeat from replacing wpcap.dll while
upgrading Npcap and the install failed. The DLL is now loaded lazily, only when
Packetbeat needs it.

# REQUIRED for breaking-change, deprecation, known-issue
# impact:

# REQUIRED for breaking-change, deprecation, known-issue
# action:

# REQUIRED for all kinds
# Affected component; usually one of "elastic-agent", "fleet-server", "filebeat", "metricbeat", "auditbeat", "all", etc.
component: packetbeat

# AUTOMATED
# OPTIONAL to manually add other PR URLs
# PR URL: A link the PR that added the changeset.
# If not present is automatically filled by the tooling finding the PR where this changelog fragment has been added.
# NOTE: the tooling supports backports, so it's able to fill the original PR number instead of the backport PR number.
# Please provide it if you are adding a fragment for a different PR.
# pr: https://github.com/owner/repo/1234

# AUTOMATED
# OPTIONAL to manually add other issue URLs
# Issue URL; optional; the GitHub issue related to this changeset (either closes or is part of).
# If not present is automatically filled by the tooling with the issue linked to the PR number.
issue: https://github.com/elastic/elastic-agent/issues/14517
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,6 @@ replace (
github.com/dop251/goja => github.com/elastic/goja v0.0.0-20190128172624-dd2ac4456e20
github.com/fsnotify/fsevents => github.com/elastic/fsevents v0.0.0-20181029231046-e1d381a4d270
github.com/fsnotify/fsnotify => github.com/elastic/fsnotify v1.6.1-0.20240920222514-49f82bdbc9e3
github.com/google/gopacket => github.com/elastic/gopacket v1.1.20-0.20241002174017-e8c5fda595e6
github.com/google/gopacket => github.com/samuelvl/gopacket v0.0.0-20260703114848-a5059dceefc3
Comment thread
samuelvl marked this conversation as resolved.
Outdated
github.com/meraki/dashboard-api-go/v3 => github.com/tommyers-elastic/dashboard-api-go/v3 v3.0.0-20250616163611-a325b49669a4
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,6 @@ github.com/elastic/goja v0.0.0-20190128172624-dd2ac4456e20 h1:bVZ3kDKa8Tqw9qvNrD
github.com/elastic/goja v0.0.0-20190128172624-dd2ac4456e20/go.mod h1:A1DWjF89MFVnxzmzTaMF7CwVy9PDem7DalMkm8RIMoY=
github.com/elastic/gokrb5/v8 v8.0.0-20251105095404-23cc45e6a102 h1:HBjzmhV2CkYn0qBDv9DN4/irmJ94xppH3kVL9VgBA8k=
github.com/elastic/gokrb5/v8 v8.0.0-20251105095404-23cc45e6a102/go.mod h1:xoTq5saXNyokdlvOhMz+JQGU+RTzTtYzqo1Bc86q3Fs=
github.com/elastic/gopacket v1.1.20-0.20241002174017-e8c5fda595e6 h1:VgOx6omXIMKozR+R4HhQRT9q1Irm/h13DLtSkejoAJY=
github.com/elastic/gopacket v1.1.20-0.20241002174017-e8c5fda595e6/go.mod h1:riddUzxTSBpJXk3qBHtYr4qOhFhT6k/1c0E3qkQjQpA=
github.com/elastic/gosigar v0.14.4 h1:7NRnWJDFjEKpOjnHhtzrPGZWr9EMrYFsLjF4q0Czosk=
github.com/elastic/gosigar v0.14.4/go.mod h1:tx91Eb3YgFk6y++h88fRAnxic3Si1ZDHooqnJU/hqo8=
github.com/elastic/mito v1.27.0 h1:FM01Ql1OMx6uL3ogW0LoI8Ruc0O6gzmwLNBV8Zk13Yw=
Expand Down Expand Up @@ -987,6 +985,8 @@ github.com/samuel/go-parser v0.0.0-20130731160455-ca8abbf65d0e h1:hUGyBE/4CXRPTh
github.com/samuel/go-parser v0.0.0-20130731160455-ca8abbf65d0e/go.mod h1:Sb6li54lXV0yYEjI4wX8cucdQ9gqUJV3+Ngg3l9g30I=
github.com/samuel/go-thrift v0.0.0-20140522043831-2187045faa54 h1:jbchLJWyhKcmOjkbC4zDvT/n5EEd7g6hnnF760rEyRA=
github.com/samuel/go-thrift v0.0.0-20140522043831-2187045faa54/go.mod h1:Vrkh1pnjV9Bl8c3P9zH0/D4NlOHWP5d4/hF4YTULaec=
github.com/samuelvl/gopacket v0.0.0-20260703114848-a5059dceefc3 h1:2LllNEu3iUcJV/4ajNlbpnLxBRpcTza4GcSrfDMYVxw=
github.com/samuelvl/gopacket v0.0.0-20260703114848-a5059dceefc3/go.mod h1:riddUzxTSBpJXk3qBHtYr4qOhFhT6k/1c0E3qkQjQpA=
github.com/sebdah/goldie v1.0.0 h1:9GNhIat69MSlz/ndaBg48vl9dF5fI+NBB6kfOxgfkMc=
github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4=
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
Expand Down
2 changes: 1 addition & 1 deletion packetbeat/beater/install_npcap.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ func installNpcap(b *beat.Beat, cfg *conf.C) error {
return nil
}

log := b.Info.Logger.Named("npcap_install")
// Only check whether we have been requested to never_install if there
// is already an Npcap installation present. This should not be necessary,
// but the start-up logic of packetbeat is tightly coupled to the presence
// of a backing sniffer. This should really not be necessary, but the changes
// to modify this behaviour are non-trivial, so just avoid the issue.
log := b.Info.Logger.Named("npcap_install")
isInstalled := strings.HasPrefix(npcap.Version(), "Npcap version")
if isInstalled {
canInstall, err := canInstallNpcap(b, cfg, log)
Expand Down
7 changes: 7 additions & 0 deletions packetbeat/beater/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (

"github.com/elastic/beats/v7/packetbeat/config"
"github.com/elastic/beats/v7/packetbeat/flows"
"github.com/elastic/beats/v7/packetbeat/npcap"
"github.com/elastic/beats/v7/packetbeat/procs"
"github.com/elastic/beats/v7/packetbeat/protos"
"github.com/elastic/beats/v7/packetbeat/publish"
Expand Down Expand Up @@ -191,6 +192,12 @@ func (p *processorFactory) create(pipeline beat.PipelineConnector, cfg *conf.C,
if err != nil {
return 0, nil, nil, nil, nil, err
}
// Ensure the DLL is loaded whether Npcap was just installed above
// or was already present from a previous run.
err = npcap.LoadNpcap()
if err != nil {
return 0, nil, nil, nil, nil, err
}
}

publisher, err := publish.NewTransactionPublisher(
Expand Down
8 changes: 7 additions & 1 deletion packetbeat/npcap/npcap.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ func install(ctx context.Context, log *logp.Logger, path, dst string, compat boo
return fmt.Errorf("npcap: failed to install Npcap: %w", err)
}

return nil
}

// LoadNpcap loads the Npcap/WinPcap DLL into the current process. It is
// a no-op on non-Windows platforms and is safe to call repeatedly.
func LoadNpcap() error {
return loadWinPCAP()
}

Expand All @@ -109,7 +115,7 @@ func Version() string {
// have happened due to Npcap not being installed.
// The empty string signifies that no installation
// exists.
recover()
_ = recover()
}()
return pcap.Version()
}
Expand Down
20 changes: 20 additions & 0 deletions x-pack/packetbeat/tests/system/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"io/fs"
"net"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
Expand Down Expand Up @@ -50,6 +52,24 @@ func TestWindowsNpcapInstaller(t *testing.T) {
if !strings.Contains(installedNpcapVersion, NpcapVersion) {
t.Errorf("unexpected npcap version installed: want:%s have:%s", NpcapVersion, installedNpcapVersion)
}

// Importing the packetbeat/npcap package must not load wpcap.dll on its own,
// since other beats would keep the DLL open and block Npcap upgrades on Windows.
// See https://github.com/elastic/elastic-agent/issues/14517.
out, err := runWpcapProbe(t)
require.NoErrorf(t, err, "wpcap.dll must not be held by a process that only imports the capture code:\n%s", out)
}

func runWpcapProbe(t testing.TB) (output string, err error) {
t.Helper()

probe := filepath.Join(t.TempDir(), "wpcapprobe.exe")
if b, err := exec.CommandContext(t.Context(), "go", "build", "-o", probe, filepath.FromSlash("testdata/wpcapprobe.go")).CombinedOutput(); err != nil {
t.Fatalf("failed to build wpcap probe: %v\n%s", err, b)
}

b, err := exec.CommandContext(t.Context(), probe).CombinedOutput()
return strings.TrimSpace(string(b)), err
}

func TestDevices(t *testing.T) {
Expand Down
39 changes: 39 additions & 0 deletions x-pack/packetbeat/tests/system/testdata/wpcapprobe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// 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.

package main

import (
"errors"
"fmt"
"os"

"golang.org/x/sys/windows"

// Import the npcap package like packetbeat does to verify it does not load
// wpcap.dll automatically
_ "github.com/elastic/beats/v7/packetbeat/npcap"
)

func main() {
name, err := windows.UTF16PtrFromString("wpcap.dll")
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(65)
}

var h windows.Handle
err = windows.GetModuleHandleEx(windows.GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, name, &h)
if err != nil {
if errors.Is(err, windows.ERROR_MOD_NOT_FOUND) {
return // not loaded: the expected lazy behavior
}
fmt.Fprintln(os.Stderr, "GetModuleHandleEx:", err)
os.Exit(65)
}
if h != 0 {
fmt.Fprintln(os.Stderr, "wpcap.dll is mapped into a process that only imports the capture code")
os.Exit(1)
}
}
Loading