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") + } }