mirror of
https://github.com/h44z/wg-portal
synced 2025-02-26 05:49:14 +00:00
100 lines
2.7 KiB
Go
100 lines
2.7 KiB
Go
|
package adapters
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"github.com/h44z/wg-portal/internal"
|
||
|
"github.com/h44z/wg-portal/internal/domain"
|
||
|
"github.com/sirupsen/logrus"
|
||
|
"os/exec"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// WgQuickRepo implements higher level wg-quick like interactions like setting DNS, routing tables or interface hooks.
|
||
|
type WgQuickRepo struct {
|
||
|
shellCmd string
|
||
|
resolvConfIfacePrefix string
|
||
|
}
|
||
|
|
||
|
func NewWgQuickRepo() *WgQuickRepo {
|
||
|
return &WgQuickRepo{
|
||
|
shellCmd: "bash",
|
||
|
resolvConfIfacePrefix: "tun.",
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (r *WgQuickRepo) ExecuteInterfaceHook(id domain.InterfaceIdentifier, hookCmd string) error {
|
||
|
if hookCmd == "" {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
err := r.exec(hookCmd, id)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to exec hook: %w", err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (r *WgQuickRepo) SetDNS(id domain.InterfaceIdentifier, dnsStr, dnsSearchStr string) error {
|
||
|
if dnsStr == "" && dnsSearchStr == "" {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
dnsServers := internal.SliceString(dnsStr)
|
||
|
dnsSearchDomains := internal.SliceString(dnsSearchStr)
|
||
|
|
||
|
dnsCommand := "resolvconf -a %resPref%i -m 0 -x"
|
||
|
dnsCommandInput := make([]string, 0, len(dnsServers)+len(dnsSearchDomains))
|
||
|
|
||
|
for _, dnsServer := range dnsServers {
|
||
|
dnsCommandInput = append(dnsCommandInput, fmt.Sprintf("nameserver %s", dnsServer))
|
||
|
}
|
||
|
for _, searchDomain := range dnsSearchDomains {
|
||
|
dnsCommandInput = append(dnsCommandInput, fmt.Sprintf("search %s", searchDomain))
|
||
|
}
|
||
|
|
||
|
err := r.exec(dnsCommand, id, dnsCommandInput...)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to set dns settings: %w", err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (r *WgQuickRepo) UnsetDNS(id domain.InterfaceIdentifier) error {
|
||
|
dnsCommand := "resolvconf -d %resPref%i -f"
|
||
|
|
||
|
err := r.exec(dnsCommand, id)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to unset dns settings: %w", err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (r *WgQuickRepo) replaceCommandPlaceHolders(command string, interfaceId domain.InterfaceIdentifier) string {
|
||
|
command = strings.ReplaceAll(command, "%resPref", r.resolvConfIfacePrefix)
|
||
|
return strings.ReplaceAll(command, "%i", string(interfaceId))
|
||
|
}
|
||
|
|
||
|
func (r *WgQuickRepo) exec(command string, interfaceId domain.InterfaceIdentifier, stdin ...string) error {
|
||
|
commandWithInterfaceName := r.replaceCommandPlaceHolders(command, interfaceId)
|
||
|
cmd := exec.Command(r.shellCmd, "-ce", commandWithInterfaceName)
|
||
|
if len(stdin) > 0 {
|
||
|
b := &bytes.Buffer{}
|
||
|
for _, ln := range stdin {
|
||
|
if _, err := fmt.Fprint(b, ln); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
cmd.Stdin = b
|
||
|
}
|
||
|
out, err := cmd.CombinedOutput() // execute and wait for output
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to exexute shell command %s: %w", commandWithInterfaceName, err)
|
||
|
}
|
||
|
logrus.Tracef("executed shell command %s, with output: %s", commandWithInterfaceName, string(out))
|
||
|
return nil
|
||
|
}
|