Closed anjmao closed 3 years ago
WireGuard native macOS app creates such network interface
utun6: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1420
options=6403<RXCSUM,TXCSUM,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
inet 10.0.44.2 --> 10.0.44.2 netmask 0xffffffff
Our node creates such interface
utun6: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1420
inet 10.182.0.2 --> 10.182.0.1 netmask 0xffffff00
It could be that we are missing whose extra options. @zolia What do you think?
I also checked ProtonVPN app and on connection it adds these options too.
ipsec0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1400
options=6403<RXCSUM,TXCSUM,CHANNEL_IO,PARTIAL_CSUM,ZEROINVERT_CSUM>
inet 10.1.6.89 --> 10.1.6.89 netmask 0xffff0000
Had the same problem (same error "assertion failed: ifp->if_sndbyte_total >= len") for a while https://github.com/mysteriumnetwork/node/issues/2174
But then it disappeared. If it reappeared, perhaps would be easier to see what changed a) before May 5th, after this was fixed (May 21st).
Tried standalone wg connection by running provider on linux and consumer on macOS. The idea was to randomly destroy wg interfaces on both ends, but wasn't able to reproduce :(
package main
import (
"flag"
"fmt"
"io/ioutil"
"log"
"math/rand"
"net"
"net/http"
"os"
"os/exec"
"os/signal"
"syscall"
"time"
"github.com/mysteriumnetwork/node/core/port"
"github.com/mysteriumnetwork/node/services/wireguard/endpoint"
"github.com/mysteriumnetwork/node/services/wireguard/endpoint/kernelspace"
"github.com/mysteriumnetwork/node/services/wireguard/endpoint/userspace"
"github.com/mysteriumnetwork/node/services/wireguard/key"
"github.com/mysteriumnetwork/node/services/wireguard/resources"
"github.com/mysteriumnetwork/node/services/wireguard/wgcfg"
"github.com/mysteriumnetwork/node/utils/netutil"
"golang.zx2c4.com/wireguard/ipc"
)
var (
consumerMode = flag.Bool("consumer", false, "Run as consumer")
)
const (
providerPrivateKey = "AJ6U91UROIh/alezabeGVDO24ImWXLBJwrR33LSp+30="
providerPublicIP = "82.196.6.69"
consumerPrivateKey = "aDAyenbk7Cd2/HuDGueSkCSOOWjnjQdm+ehUq1PEEWA="
)
func main() {
flag.Parse()
rand.Seed(time.Now().UnixNano())
if *consumerMode {
c := consumer{}
go func() {
for {
if err := c.start(); err != nil {
log.Fatal(err)
}
ts := time.Duration(rand.Intn(10)) * time.Second
log.Printf("Will reopen consumer in %s\n", ts)
time.Sleep(ts)
c.stop()
time.Sleep(time.Second)
}
}()
done := make(chan os.Signal, 1)
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
<-done
c.stop()
return
}
p := provider{}
go func() {
for {
if err := p.start(); err != nil {
log.Fatal(err)
}
ts := time.Duration(rand.Intn(10)) * time.Second
log.Printf("Will reopen provider in %s\n", ts)
time.Sleep(ts)
p.stop()
time.Sleep(time.Second)
}
}()
done := make(chan os.Signal, 1)
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
<-done
p.stop()
}
type provider struct {
wg endpoint.WgClient
done chan struct{}
}
func (p *provider) start() error {
p.done = make(chan struct{}, 1)
log.Println("Running provider mode")
wg, err := kernelspace.NewWireguardClient()
if err != nil {
return fmt.Errorf("could not create wireguard client: %w", err)
}
p.wg = wg
alloc := resources.NewAllocator(port.NewPool(), defaultSubnet())
iface, err := alloc.AllocateInterface()
if err != nil {
return fmt.Errorf("could not allocate interface: %w", err)
}
peerPubKey, err := key.PrivateKeyToPublicKey(consumerPrivateKey)
if err != nil {
return err
}
subnet := defaultSubnet()
subnet.IP = netutil.FirstIP(subnet)
cfg := wgcfg.DeviceConfig{
IfaceName: iface,
Subnet: subnet,
PrivateKey: providerPrivateKey,
ListenPort: 51820,
DNS: nil,
DNSScriptDir: "",
Peer: wgcfg.Peer{
PublicKey: peerPubKey,
Endpoint: nil,
AllowedIPs: []string{"0.0.0.0/0", "::/0"},
KeepAlivePeriodSeconds: 18,
},
}
errc := make(chan error, 1)
go func() {
log.Println("Configure device")
errc <- wg.ConfigureDevice(cfg)
for {
select {
case <-p.done:
return
case <-time.After(3 * time.Second):
stats, _ := wg.PeerStats(iface)
log.Printf("%+v", stats)
}
}
}()
if err := <-errc; err != nil {
return fmt.Errorf("could not configure device: %w", err)
}
// Setup firewall.
cmd("iptables", "-A", "POSTROUTING", "--source", "10.182.0.2/24", "!", "--destination", "10.182.0.2/24", "--jump", "SNAT", "--to", providerPublicIP, "--table", "nat")
return nil
}
func (p *provider) stop() {
log.Println("Stopping provider mode")
close(p.done)
if err := p.wg.Close(); err != nil {
log.Fatalf("could not destroy device: %v", err)
}
}
type consumer struct {
wg endpoint.WgClient
uapi net.Listener
done chan struct{}
}
func (c *consumer) start() error {
c.done = make(chan struct{}, 1)
log.Println("Running consumer mode")
wg, err := userspace.NewWireguardClient()
if err != nil {
return fmt.Errorf("could not create wireguard client: %w", err)
}
c.wg = wg
ports := port.NewPool()
alloc := resources.NewAllocator(ports, defaultSubnet())
iface, err := alloc.AllocateInterface()
if err != nil {
return fmt.Errorf("could not allocate interface: %w", err)
}
fileUAPI, err := ipc.UAPIOpen(iface)
if err != nil {
return fmt.Errorf("UAPI listen error: %w", err)
}
uapi, err := ipc.UAPIListen(iface, fileUAPI)
if err != nil {
return fmt.Errorf("failed to listen on UAPI socket: %w", err)
}
c.uapi = uapi
go func() {
for {
conn, err := uapi.Accept()
if err != nil {
log.Println(err)
return
}
go wg.Device().IpcHandle(conn)
}
}()
peerPubKey, err := key.PrivateKeyToPublicKey(providerPrivateKey)
if err != nil {
return err
}
subnet := defaultSubnet()
subnet.IP = consumerIP(subnet)
cfg := wgcfg.DeviceConfig{
IfaceName: iface,
Subnet: subnet,
PrivateKey: consumerPrivateKey,
ListenPort: 51820,
DNS: nil,
DNSScriptDir: "",
Peer: wgcfg.Peer{
PublicKey: peerPubKey,
Endpoint: &net.UDPAddr{IP: net.ParseIP(providerPublicIP), Port: 51820},
AllowedIPs: []string{"0.0.0.0/0", "::/0"},
KeepAlivePeriodSeconds: 18,
},
}
go c.checkIPLoop()
errc := make(chan error, 1)
go func() {
log.Println("Configure device")
errc <- wg.ConfigureDevice(cfg)
for {
select {
case <-c.done:
return
case <-time.After(3 * time.Second):
stats, _ := wg.PeerStats(iface)
log.Printf("%+v", stats)
}
}
}()
if err := <-errc; err != nil {
return fmt.Errorf("could not configure device: %w", err)
}
return nil
}
func (c *consumer) stop() {
close(c.done)
log.Println("Stopping consumer mode")
_ = c.uapi.Close()
if err := c.wg.Close(); err != nil {
log.Fatalf("could not destroy device: %v", err)
}
}
func (c *consumer) checkIPLoop() {
for {
select {
case <-c.done:
return
case <-time.After(time.Duration(rand.Intn(7)) * time.Second):
httpc := http.Client{Timeout: 10 * time.Second}
resp, err := httpc.Get("https://api.ipify.org")
if err != nil {
log.Printf("ip fetch err: %v", err)
time.Sleep(1 * time.Second)
continue
}
defer resp.Body.Close()
result, _ := ioutil.ReadAll(resp.Body)
fmt.Printf("IP: %s\n", string(result))
}
}
}
func defaultSubnet() net.IPNet {
return net.IPNet{
IP: net.ParseIP("10.182.0.0").To4(),
Mask: net.IPv4Mask(255, 255, 0, 0),
}
}
func consumerIP(subnet net.IPNet) net.IP {
subnet.IP[len(subnet.IP)-1] = byte(2)
return subnet.IP
}
func cmd(args ...string) {
out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
if err != nil {
log.Fatalf("could not exec command: %s:%v", string(out), err)
}
}
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been automatically closed because it has not had activity for a long time. If this issue is still valid, please ping a maintainer and ask them to label it as "pinned". Thank you for your contributions.
I connected to WireGuard provider (hosted on Digital Ocean data center). Connection worked fine. When I pressed ctrl+C to kill myst process gracefully and mac crashed.
I was able to reproduce it most of the time following these steps:
Crash log