mirror of
https://github.com/netbirdio/netbird.git
synced 2025-04-11 04:58:38 +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/netns v0.0.0-20191106174202-0a2b9b5464df
|
||||
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/wgctrl v0.0.0-20210506160403-92e472f520a5
|
||||
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