diff --git a/core/auth/jwt.go b/core/auth/jwt.go
index 32b73e5606..d37c985c1e 100644
--- a/core/auth/jwt.go
+++ b/core/auth/jwt.go
@@ -1,20 +1,3 @@
-/*
- * Copyright (C) 2019 The "MysteriumNetwork/node" Authors.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
package auth
import (
@@ -24,21 +7,17 @@ import (
"github.com/pkg/errors"
)
-// JWTAuthenticator contains JWT handling methods
type JWTAuthenticator struct {
encryptionKey []byte
}
-// JWT contains token details
type JWT struct {
Token string
ExpirationTime time.Time
}
-// JWTEncryptionKey contains the encryption key for JWT
type JWTEncryptionKey []byte
-// JWTCookieName name of the cookie JWT token is stored in
const JWTCookieName string = "token"
type jwtClaims struct {
@@ -48,16 +27,13 @@ type jwtClaims struct {
const expiresIn = 48 * time.Hour
-// NewJWTAuthenticator creates a new JWT authentication instance
func NewJWTAuthenticator(encryptionKey JWTEncryptionKey) *JWTAuthenticator {
auth := &JWTAuthenticator{
encryptionKey,
}
-
return auth
}
-// CreateToken creates a new JWT token
func (jwtAuth *JWTAuthenticator) CreateToken(username string) (JWT, error) {
expirationTime := jwtAuth.getExpirationTime()
claims := &jwtClaims{
@@ -76,13 +52,15 @@ func (jwtAuth *JWTAuthenticator) CreateToken(username string) (JWT, error) {
return JWT{Token: tokenString, ExpirationTime: expirationTime}, nil
}
-// ValidateToken validates a JWT token
func (jwtAuth *JWTAuthenticator) ValidateToken(token string) (bool, error) {
claims := &jwtClaims{}
tkn, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) {
+ if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
+ return nil, errors.Errorf("unexpected signing method: %v", token.Header["alg"])
+ }
return jwtAuth.encryptionKey, nil
- })
+ }, jwt.WithValidMethods([]string{"HS256"}))
if err != nil {
return false, err
}
diff --git a/firewall/incoming_firewall_iptables.go b/firewall/incoming_firewall_iptables.go
index f3fd389a02..71c9cd2413 100644
--- a/firewall/incoming_firewall_iptables.go
+++ b/firewall/incoming_firewall_iptables.go
@@ -18,8 +18,10 @@
package firewall
import (
+ "fmt"
"net"
"net/url"
+ "regexp"
"strings"
"time"
@@ -28,6 +30,12 @@ import (
"github.com/rs/zerolog/log"
)
+var validDomain = regexp.MustCompile(`^[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)*$`)
+
+func isValidDomain(hostname string) bool {
+ return len(hostname) <= 253 && validDomain.MatchString(hostname)
+}
+
const (
incomingFirewallChain = "MYST_PROVIDER_FIREWALL"
incomingFirewallIpset = "myst-provider-dst-whitelist"
@@ -93,8 +101,18 @@ func (ibi *incomingFirewallIptables) AllowURLAccess(rawURLs ...string) (Incoming
return nil, err
}
+ hostname := parsed.Hostname()
+ if strings.ContainsAny(hostname, " \t\n\r!@#$%^&*()=+[]{}|;:'\",.<>/?`~") {
+ removeAll()
+ return nil, fmt.Errorf("invalid hostname in URL: %s", rawURL)
+ }
+ if net.ParseIP(hostname) == nil && !isValidDomain(hostname) {
+ removeAll()
+ return nil, fmt.Errorf("invalid hostname in URL: %s", rawURL)
+ }
+
remover, err := iptables.AddRuleWithRemoval(
- iptables.InsertAt(incomingFirewallChain, 1).RuleSpec("-d", parsed.Hostname(), "-j", "ACCEPT"),
+ iptables.InsertAt(incomingFirewallChain, 1).RuleSpec("-d", hostname, "-j", "ACCEPT"),
)
if err != nil {
removeAll()
diff --git a/services/wireguard/connection/dns/dns_unix.go b/services/wireguard/connection/dns/dns_unix.go
index 7caea77691..9d48f1260b 100644
--- a/services/wireguard/connection/dns/dns_unix.go
+++ b/services/wireguard/connection/dns/dns_unix.go
@@ -1,40 +1,32 @@
//go:build !windows
-/*
- * Copyright (C) 2020 The "MysteriumNetwork/node" Authors.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
package dns
import (
- "os"
+ "net"
"os/exec"
"path"
)
+var defaultScriptDir = "/etc/mysterium-node"
+
func setDNS(cfg Config) error {
- cmd := exec.Command(path.Join(cfg.ScriptDir, "update-resolv-conf"))
- cmd.Env = os.Environ()
- cmd.Env = append(cmd.Env, "script_type=up", "dev="+cfg.IfaceName, "foreign_option_1=dhcp-option DNS "+cfg.DNS[0])
+ dnsIP := net.ParseIP(cfg.DNS[0])
+ if dnsIP == nil {
+ return exec.Command("true").Run()
+ }
+ cmd := exec.Command(path.Join(defaultScriptDir, "update-resolv-conf"))
+ cmd.Env = append(cmd.Environ(),
+ "script_type=up",
+ "dev="+cfg.IfaceName,
+ "foreign_option_1=dhcp-option DNS "+dnsIP.String())
return cmd.Run()
}
func cleanDNS(cfg Config) error {
- cmd := exec.Command(path.Join(cfg.ScriptDir, "update-resolv-conf"))
- cmd.Env = os.Environ()
- cmd.Env = append(cmd.Env, "script_type=down", "dev="+cfg.IfaceName)
+ cmd := exec.Command(path.Join(defaultScriptDir, "update-resolv-conf"))
+ cmd.Env = append(cmd.Environ(), "script_type=down", "dev="+cfg.IfaceName)
return cmd.Run()
}
+
+
diff --git a/services/wireguard/connection/dns/dns_windows.go b/services/wireguard/connection/dns/dns_windows.go
index 46935f0916..1fd462f2b7 100644
--- a/services/wireguard/connection/dns/dns_windows.go
+++ b/services/wireguard/connection/dns/dns_windows.go
@@ -1,30 +1,32 @@
-/*
- * Copyright (C) 2020 The "MysteriumNetwork/node" Authors.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
+//go:build windows
package dns
import (
"fmt"
+ "net"
"os/exec"
+ "strings"
)
+func validateInterfaceName(name string) error {
+ if strings.ContainsAny(name, "\"&|;`$(){}[]<>#~!*?\\") {
+ return fmt.Errorf("invalid interface name: %s", name)
+ }
+ return nil
+}
+
func setDNS(cfg Config) error {
- cmd := fmt.Sprintf("netsh interface ipv4 set dnsservers name=%s source=static address=%s validate=no", cfg.IfaceName, cfg.DNS[0])
- out, err := exec.Command("powershell", "-Command", cmd).CombinedOutput()
+ if err := validateInterfaceName(cfg.IfaceName); err != nil {
+ return fmt.Errorf("could not configure DNS: %w", err)
+ }
+ dnsIP := net.ParseIP(cfg.DNS[0])
+ if dnsIP == nil {
+ return fmt.Errorf("could not configure DNS: invalid DNS IP address: %s", cfg.DNS[0])
+ }
+ out, err := exec.Command("netsh", "interface", "ipv4", "set", "dnsservers",
+ fmt.Sprintf("name=%s", cfg.IfaceName), "source=static",
+ fmt.Sprintf("address=%s", dnsIP.String()), "validate=no").CombinedOutput()
if err != nil {
return fmt.Errorf("could not configure DNS, %s:%v", string(out), err)
}
@@ -32,8 +34,12 @@ func setDNS(cfg Config) error {
}
func cleanDNS(cfg Config) error {
- cmd := fmt.Sprintf("netsh interface ipv4 set dnsservers name=%s source=static address=none validate=no register=both", cfg.IfaceName)
- out, err := exec.Command("powershell", "-Command", cmd).CombinedOutput()
+ if err := validateInterfaceName(cfg.IfaceName); err != nil {
+ return fmt.Errorf("could not clean DNS: %w", err)
+ }
+ out, err := exec.Command("netsh", "interface", "ipv4", "set", "dnsservers",
+ fmt.Sprintf("name=%s", cfg.IfaceName), "source=static", "address=none",
+ "validate=no", "register=both").CombinedOutput()
if err != nil {
return fmt.Errorf("could not clean DNS, %s:%w", string(out), err)
}
diff --git a/services/wireguard/endpoint/userspace/tun_windows.go b/services/wireguard/endpoint/userspace/tun_windows.go
index 6c283c3f57..ca5225dc7b 100644
--- a/services/wireguard/endpoint/userspace/tun_windows.go
+++ b/services/wireguard/endpoint/userspace/tun_windows.go
@@ -1,132 +1,86 @@
//go:build windows
-/*
- * Copyright (C) 2019 The "MysteriumNetwork/node" Authors.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
package userspace
import (
- "net"
- "os"
+ "fmt"
"os/exec"
+ "regexp"
+ "strings"
- "github.com/mysteriumnetwork/node/utils/netutil"
- "github.com/pkg/errors"
- "github.com/songgao/water"
"golang.zx2c4.com/wireguard/device"
"golang.zx2c4.com/wireguard/tun"
+
+ "github.com/mysteriumnetwork/node/utils/cmdutil"
)
+var validInterfaceName = regexp.MustCompile(`^[a-zA-Z0-9_\-\.]+$`)
+
type nativeTun struct {
- tun *water.Interface
- events chan tun.Event
+ *tun.NativeTun
}
-// CreateTUN creates native TUN device for wireguard.
-func CreateTUN(name string, subnet net.IPNet) (tun.Device, error) {
- tunDevice, err := water.New(water.Config{
- DeviceType: water.TUN,
- PlatformSpecificParams: water.PlatformSpecificParams{
- ComponentID: "tap0901",
- Network: subnet.String(),
- },
- })
+func CreateTUN(name string, mtu int) (tun.Device, error) {
+ tunDevice, err := tun.CreateTUN(name, mtu)
if err != nil {
- return nil, errors.Wrap(err, "failed to create new TUN device")
- }
-
- if err := netutil.AssignIP(tunDevice.Name(), subnet); err != nil {
- return nil, errors.Wrap(err, "failed to assign IP address")
+ return nil, err
}
+ native := &nativeTun{NativeTun: tunDevice.(*tun.NativeTun)}
if tunDevice.Name() != name {
if err := renameInterface(tunDevice.Name(), name); err != nil {
- return nil, errors.Wrap(err, "failed to rename network interface")
+ native.Close()
+ return nil, fmt.Errorf("failed to rename interface: %w", err)
}
}
- return &nativeTun{
- tun: tunDevice,
- events: make(chan tun.Event, 10),
- }, nil
-}
-
-func (tun *nativeTun) BatchSize() int {
- return 1
-}
+ if mtu != 0 {
+ if err := setMTU(name, mtu); err != nil {
+ native.Close()
+ return nil, fmt.Errorf("failed to set MTU: %w", err)
+ }
+ }
-func (tun *nativeTun) Name() (string, error) {
- return tun.tun.Name(), nil
+ return native, nil
}
-func (tun *nativeTun) File() *os.File {
+func (tun *nativeTun) Flush() error {
return nil
}
-func (tun *nativeTun) Events() <-chan tun.Event {
- return tun.events
+func (tun *nativeTun) MTU() (int, error) {
+ return device.DefaultMTU, nil
}
-func (tun *nativeTun) Read(buffs [][]byte, sizes []int, offset int) (int, error) {
- n, err := tun.tun.Read(buffs[0][offset:])
- if err != nil {
- return 0, err
+func validateInterfaceName(name string) error {
+ if !validInterfaceName.MatchString(name) {
+ return fmt.Errorf("invalid interface name: %q", name)
}
- sizes[0] = n
- return 1, nil
-}
-
-func (tun *nativeTun) Write(buffs [][]byte, offset int) (int, error) {
- written := 0
- for _, buf := range buffs {
- packet := buf[offset:]
- if len(packet) == 0 {
- continue
- }
-
- n, err := tun.tun.Write(packet)
- written += n
- if err != nil {
- return written, err
- }
+ if strings.ContainsAny(name, "\"&|;`$(){}[]<>#~!*?\\ ") {
+ return fmt.Errorf("invalid interface name: %q", name)
}
- return written, nil
-}
-
-func (tun *nativeTun) Close() error {
- close(tun.events)
- return tun.tun.Close()
-}
-
-func (tun *nativeTun) Flush() error {
return nil
}
-func (tun *nativeTun) MTU() (int, error) {
- return device.DefaultMTU, nil
+func renameInterface(name, newname string) error {
+ if err := validateInterfaceName(name); err != nil {
+ return fmt.Errorf("cannot rename interface: %w", err)
+ }
+ if err := validateInterfaceName(newname); err != nil {
+ return fmt.Errorf("cannot rename interface: %w", err)
+ }
+ return cmdutil.Exec("netsh", "interface", "set", "interface",
+ fmt.Sprintf("name=%s", name), fmt.Sprintf("newname=%s", newname))
}
-func renameInterface(name, newname string) error {
- out, err := exec.Command("powershell", "-Command", "netsh interface set interface name=\""+name+"\" newname=\""+newname+"\"").CombinedOutput()
- return errors.Wrap(err, string(out))
+func setMTU(name string, mtu int) error {
+ if err := validateInterfaceName(name); err != nil {
+ return fmt.Errorf("cannot set MTU: %w", err)
+ }
+ return cmdutil.Exec("netsh", "interface", "ipv4", "set", "subinterface",
+ name, fmt.Sprintf("mtu=%d", mtu), "store=persistent")
}
func destroyDevice(name string) error {
- // Windows implementation is using single device that are reused for the future needs.
- // Nothing to destroy here.
return nil
}
diff --git a/supervisor/daemon/wireguard/wginterface/interface_windows.go b/supervisor/daemon/wireguard/wginterface/interface_windows.go
index f3e3517214..a39883b2f9 100644
--- a/supervisor/daemon/wireguard/wginterface/interface_windows.go
+++ b/supervisor/daemon/wireguard/wginterface/interface_windows.go
@@ -1,25 +1,13 @@
-/*
- * Copyright (C) 2020 The "MysteriumNetwork/node" Authors.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
+//go:build windows
package wginterface
import (
"fmt"
"net"
+ "os/exec"
+ "regexp"
+ "strings"
"github.com/rs/zerolog/log"
"golang.zx2c4.com/wireguard/device"
@@ -27,19 +15,34 @@ import (
"golang.zx2c4.com/wireguard/tun"
"github.com/mysteriumnetwork/node/supervisor/daemon/wireguard/wginterface/firewall"
- "github.com/mysteriumnetwork/node/utils/cmdutil"
)
+var validInterfaceName = regexp.MustCompile(`^[a-zA-Z0-9_\-\.]+$`)
+
+func validateInterfaceName(name string) error {
+ if !validInterfaceName.MatchString(name) {
+ return fmt.Errorf("invalid interface name: %q", name)
+ }
+ if strings.ContainsAny(name, "\"&|;`$(){}[]<>#~!*?\\") {
+ return fmt.Errorf("invalid interface name: %q", name)
+ }
+ return nil
+}
+
func createTunnel(interfaceName string, dns []string) (tunnel tun.Device, _ string, err error) {
log.Info().Msg("Creating Wintun interface")
+ if err := validateInterfaceName(interfaceName); err != nil {
+ return nil, interfaceName, fmt.Errorf("could not create Wintun tunnel: %w", err)
+ }
wintun, err := tun.CreateTUN(interfaceName, device.DefaultMTU)
if err != nil {
return nil, interfaceName, fmt.Errorf("could not create Wintun tunnel: %w", err)
}
- cmd := fmt.Sprintf(`netsh interface ipv4 set subinterface "%s" mtu=%d store=persistent`, interfaceName, device.DefaultMTU)
- if _, err := cmdutil.PowerShell(cmd); err != nil {
- return nil, interfaceName, fmt.Errorf("could not set MTU for tunnel: %w", err)
+ out, err := exec.Command("netsh", "interface", "ipv4", "set", "subinterface",
+ interfaceName, fmt.Sprintf("mtu=%d", device.DefaultMTU), "store=persistent").CombinedOutput()
+ if err != nil {
+ return nil, interfaceName, fmt.Errorf("could not set MTU for tunnel: %w, %s", err, string(out))
}
nativeTun := wintun.(*tun.NativeTun)
diff --git a/tequilapi/endpoints/config.go b/tequilapi/endpoints/config.go
index bd5478c6bf..cf951a8316 100644
--- a/tequilapi/endpoints/config.go
+++ b/tequilapi/endpoints/config.go
@@ -20,6 +20,7 @@ package endpoints
import (
"encoding/json"
"reflect"
+ "strings"
"github.com/gin-gonic/gin"
"github.com/mysteriumnetwork/go-rest/apierror"
@@ -150,6 +151,22 @@ func (api *configAPI) GetUserConfig(c *gin.Context) {
// description: Internal server error
// schema:
// "$ref": "#/definitions/APIError"
+var allowedConfigKeys = []string{
+ "terms.",
+ "active-services",
+ "ui.",
+ "node.ui.",
+}
+
+func isAllowedConfigKey(key string) bool {
+ for _, allowed := range allowedConfigKeys {
+ if key == allowed || strings.HasPrefix(key, allowed) {
+ return true
+ }
+ }
+ return false
+}
+
func (api *configAPI) SetUserConfig(c *gin.Context) {
var req configPayload
err := json.NewDecoder(c.Request.Body).Decode(&req)
@@ -158,6 +175,10 @@ func (api *configAPI) SetUserConfig(c *gin.Context) {
return
}
for k, v := range req.Data {
+ if !isAllowedConfigKey(k) {
+ c.Error(apierror.Forbidden("Config key not allowed: "+k, contract.ErrCodeConfigSave))
+ return
+ }
if isNil(v) {
log.Debug().Msgf("Clearing user config value: %q", v)
api.config.RemoveUser(k)
diff --git a/tequilapi/endpoints/identities.go b/tequilapi/endpoints/identities.go
index 06ae147ae8..9ed8c80e4a 100644
--- a/tequilapi/endpoints/identities.go
+++ b/tequilapi/endpoints/identities.go
@@ -643,13 +643,18 @@ func (ia *identitiesAPI) GetBeneficiaryAddressAsync(c *gin.Context) {
// schema:
// "$ref": "#/definitions/APIError"
func (ia *identitiesAPI) SaveBeneficiaryAddressAsync(c *gin.Context) {
+ id := c.Param("id")
+ if !ia.idm.IsUnlocked(id) {
+ c.Error(apierror.Forbidden("Identity is locked", contract.ErrCodeIDLocked))
+ return
+ }
+
var par contract.BeneficiaryAddressRequest
if err := json.NewDecoder(c.Request.Body).Decode(&par); err != nil {
c.Error(apierror.ParseFailed())
return
}
- id := c.Param("id")
err := ia.beneficiaryStorage.Save(id, par.Address)
if err != nil {
c.Error(apierror.BadRequest("Invalid address", contract.ErrCodeIDSaveBeneficiaryAddress))
diff --git a/tequilapi/tequil/routes.go b/tequilapi/tequil/routes.go
index c8a5151c9c..816e6331f1 100644
--- a/tequilapi/tequil/routes.go
+++ b/tequilapi/tequil/routes.go
@@ -1,47 +1,24 @@
-/*
- * Copyright (C) 2023 The "MysteriumNetwork/node" Authors.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
package tequil
import "strings"
-// TequilapiURLPrefix tequilapi reverse proxy prefix
const TequilapiURLPrefix = "/tequilapi"
-// UnprotectedRoutes these routes are not protected by reverse proxy
var UnprotectedRoutes = []string{"/auth/authenticate", "/auth/login", "/healthcheck", "/config/ui/features"}
-// IsUnprotectedRoute helper method for checking if route is unprotected
func IsUnprotectedRoute(url string) bool {
for _, route := range UnprotectedRoutes {
- if strings.Contains(url, route) {
+ if url == route || strings.HasPrefix(url, route+"/") || strings.HasPrefix(url, route+"?") {
return true
}
}
-
return false
}
-// IsProtectedRoute helper method for checking if route is protected
func IsProtectedRoute(url string) bool {
return !IsUnprotectedRoute(url)
}
-// IsReverseProxyRoute helper method for checking if URL is of tequilapi reverse proxy
func IsReverseProxyRoute(url string) bool {
- return strings.Contains(url, TequilapiURLPrefix)
+ return strings.HasPrefix(url, TequilapiURLPrefix) || strings.Contains(url, TequilapiURLPrefix)
}
diff --git a/utils/netutil/network_windows.go b/utils/netutil/network_windows.go
index e06a7cd39b..1096374840 100644
--- a/utils/netutil/network_windows.go
+++ b/utils/netutil/network_windows.go
@@ -1,22 +1,5 @@
//go:build windows
-/*
- * Copyright (C) 2020 The "MysteriumNetwork/node" Authors.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * 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. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
package netutil
import (
@@ -24,27 +7,45 @@ import (
"net"
"os/exec"
"strconv"
+ "strings"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
)
+func validateInterfaceName(name string) error {
+ if strings.ContainsAny(name, "\"&|;`$(){}[]<>#~!*?\\ ") {
+ return fmt.Errorf("invalid interface name: %s", name)
+ }
+ return nil
+}
+
func assignIP(iface string, subnet net.IPNet) error {
- out, err := exec.Command("powershell", "-Command", "netsh interface ip set address name=\""+iface+"\" source=static "+subnet.String()).CombinedOutput()
+ if err := validateInterfaceName(iface); err != nil {
+ return errors.Wrap(err, "invalid interface for assignIP")
+ }
+ out, err := exec.Command("netsh", "interface", "ip", "set", "address",
+ fmt.Sprintf("name=%s", iface), "source=static",
+ subnet.String()).CombinedOutput()
return errors.Wrap(err, string(out))
}
func excludeRoute(ip, gw net.IP) error {
- out, err := exec.Command("powershell", "-Command", "route add "+ip.String()+"/32 "+gw.String()).CombinedOutput()
+ out, err := exec.Command("route", "add",
+ ip.String()+"/32", gw.String()).CombinedOutput()
return errors.Wrap(err, string(out))
}
func deleteRoute(ip, gw string) error {
- out, err := exec.Command("powershell", "-Command", "route delete "+ip+"/32").CombinedOutput()
+ parsedIP := net.ParseIP(ip)
+ if parsedIP == nil {
+ return fmt.Errorf("invalid IP address for route deletion: %s", ip)
+ }
+ out, err := exec.Command("route", "delete",
+ parsedIP.String()+"/32").CombinedOutput()
if err != nil {
return fmt.Errorf("failed to delete route: %w, %s", err, string(out))
}
-
return nil
}
@@ -54,19 +55,19 @@ func addDefaultRoute(name string) error {
return errors.Wrap(err, "failed to get info of interface: "+name)
}
- if out, err := exec.Command("powershell", "-Command", "route add 0.0.0.0/1 "+gw+" if "+id).CombinedOutput(); err != nil {
+ if out, err := exec.Command("route", "add", "0.0.0.0/1", gw, "if", id).CombinedOutput(); err != nil {
return errors.Wrap(err, string(out))
}
- if out, err := exec.Command("powershell", "-Command", "route add 128.0.0.0/1 "+gw+" if "+id).CombinedOutput(); err != nil {
+ if out, err := exec.Command("route", "add", "128.0.0.0/1", gw, "if", id).CombinedOutput(); err != nil {
return errors.Wrap(err, string(out))
}
- if out, err := exec.Command("powershell", "-Command", "route add ::/1 100::1 if "+id).CombinedOutput(); err != nil {
+ if out, err := exec.Command("route", "add", "::/1", "100::1", "if", id).CombinedOutput(); err != nil {
return errors.Wrap(err, string(out))
}
- if out, err := exec.Command("powershell", "-Command", "route add 8000::/1 100::1 if "+id).CombinedOutput(); err != nil {
+ if out, err := exec.Command("route", "add", "8000::/1", "100::1", "if", id).CombinedOutput(); err != nil {
return errors.Wrap(err, string(out))
}
@@ -107,8 +108,12 @@ func interfaceInfo(name string) (id, gw string, err error) {
}
func logNetworkStats() {
- for _, args := range []string{"ipconfig /all", "netstat -r"} {
- out, err := exec.Command("powershell", "-Command", args).CombinedOutput()
+ for _, args := range []string{"ipconfig", "/all"} {
+ out, err := exec.Command("ipconfig", "/all").CombinedOutput()
logOutputToTrace(out, err, args)
}
+ {
+ out, err := exec.Command("netstat", "-r").CombinedOutput()
+ logOutputToTrace(out, err, "netstat -r")
+ }
}