mirror of
https://github.com/netbirdio/netbird.git
synced 2025-04-24 19:39:45 +02:00
feature: add check of Wireguard kernel module existence (Linux only)
This commit is contained in:
parent
8dfccfc800
commit
dd72a01ecf
1
go.mod
1
go.mod
@ -12,6 +12,7 @@ require (
|
|||||||
github.com/vishvananda/netlink v1.1.0
|
github.com/vishvananda/netlink v1.1.0
|
||||||
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df
|
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df
|
||||||
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf
|
golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2
|
golang.zx2c4.com/wireguard v0.0.0-20210604143328-f9b48a961cd2
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210506160403-92e472f520a5
|
||||||
golang.zx2c4.com/wireguard/windows v0.3.14
|
golang.zx2c4.com/wireguard/windows v0.3.14
|
||||||
|
140
iface/mod.go
Normal file
140
iface/mod.go
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package iface
|
||||||
|
|
||||||
|
// Holds logic to check existence of Wireguard kernel module
|
||||||
|
// Copied from https://github.com/paultag/go-modprobe
|
||||||
|
|
||||||
|
import (
|
||||||
|
"debug/elf"
|
||||||
|
"fmt"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// get the root directory for the kernel modules. If this line panics,
|
||||||
|
// it's because getModuleRoot has failed to get the uname of the running
|
||||||
|
// kernel (likely a non-POSIX system, but maybe a broken kernel?)
|
||||||
|
moduleRoot = getModuleRoot()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get the module root (/lib/modules/$(uname -r)/)
|
||||||
|
func getModuleRoot() string {
|
||||||
|
uname := unix.Utsname{}
|
||||||
|
if err := unix.Uname(&uname); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
for ; uname.Release[i] != 0; i++ {
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.Join(
|
||||||
|
"/lib/modules",
|
||||||
|
string(uname.Release[:i]),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name will, given a file descriptor to a Kernel Module (.ko file), parse the
|
||||||
|
// binary to get the module name. For instance, given a handle to the file at
|
||||||
|
// `kernel/drivers/usb/gadget/legacy/g_ether.ko`, return `g_ether`.
|
||||||
|
func Name(file *os.File) (string, error) {
|
||||||
|
f, err := elf.NewFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
syms, err := f.Symbols()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, sym := range syms {
|
||||||
|
if strings.Compare(sym.Name, "__this_module") == 0 {
|
||||||
|
section := f.Sections[sym.Section]
|
||||||
|
data, err := section.Data()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data) < 25 {
|
||||||
|
return "", fmt.Errorf("modprobe: data is short, __this_module is '%s'", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
data = data[24:]
|
||||||
|
i := 0
|
||||||
|
for ; data[i] != 0x00; i++ {
|
||||||
|
}
|
||||||
|
return string(data[:i]), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("No name found. Is this a .ko or just an ELF?")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open every single kernel module under the root, and parse the ELF headers to
|
||||||
|
// extract the module name.
|
||||||
|
func elfMap(root string) (map[string]string, error) {
|
||||||
|
ret := map[string]string{}
|
||||||
|
|
||||||
|
err := filepath.Walk(
|
||||||
|
root,
|
||||||
|
func(path string, info os.FileInfo, err error) error {
|
||||||
|
if !info.Mode().IsRegular() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fd, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fd.Close()
|
||||||
|
name, err := Name(fd)
|
||||||
|
if err != nil {
|
||||||
|
/* For now, let's just ignore that and avoid adding to it */
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[name] = path
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open every single kernel module under the kernel module directory
|
||||||
|
// (/lib/modules/$(uname -r)/), and parse the ELF headers to extract the
|
||||||
|
// module name.
|
||||||
|
func generateMap() (map[string]string, error) {
|
||||||
|
return elfMap(moduleRoot)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WireguardModExists returns true if Wireguard kernel module exists.
|
||||||
|
func WireguardModExists() bool {
|
||||||
|
_, err := resolveModName("wireguard")
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolveModName will, given a module name (such as `wireguard`) return an absolute
|
||||||
|
// path to the .ko that provides that module.
|
||||||
|
func resolveModName(name string) (string, error) {
|
||||||
|
paths, err := generateMap()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
fsPath := paths[name]
|
||||||
|
if !strings.HasPrefix(fsPath, moduleRoot) {
|
||||||
|
return "", fmt.Errorf("module isn't in the module directory")
|
||||||
|
}
|
||||||
|
|
||||||
|
return fsPath, nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user