Golang中Wireguard-go可以写入但无法读取的问题

Golang中Wireguard-go可以写入但无法读取的问题 不确定这里是否是询问 wireguard-go 问题的合适地方,有人能帮忙解释为什么读取不工作但写入正常吗?谢谢

package wireguard

import (
	"fmt"
	"syscall"
	"unsafe"

	"net/netip"

	"golang.zx2c4.com/wireguard/conn"
	"golang.zx2c4.com/wireguard/device"
	"golang.zx2c4.com/wireguard/tun"
	"golang.zx2c4.com/wireguard/tun/netstack"
)

func NewUDP(localAddr, remoteAddr, privateKey, publicKey string,
	mtu, localPort, remotePort int) (tun.Device, error) {
	tun, _, err := netstack.CreateNetTUN(
		[]netip.Addr{netip.MustParseAddr(localAddr)},
		[]netip.Addr{netip.MustParseAddr("8.8.8.8")},
		mtu,
	)
	if err != nil {
		return nil, err
	}

	dev := device.NewDevice(tun, conn.NewDefaultBind(),
		device.NewLogger(device.LogLevelVerbose, fmt.Sprint(localPort, ">")))
	err = dev.IpcSet(fmt.Sprintf(`private_key=%s
listen_port=%d
public_key=%s
allowed_ip=0.0.0.0/0
endpoint=127.0.0.1:%d
`, privateKey, localPort, publicKey, remotePort))
	if err != nil {
		return nil, err
	}
	err = dev.Up()
	if err != nil {
		return nil, err
	}

	return tun, nil
}
package wireguard

import (
	"errors"
	"fmt"
	"net"
	"testing"
	"time"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
)

func TestUDP(t *testing.T) {
	exit := make(chan struct{})
	msgCh := make(chan string, 2)
	errCh := make(chan error, 2)
	localAddr := "127.0.0.1"
	serverAddr := "192.168.4.29"
	serverPort := 58120
	clientAddr := "192.168.4.28"
	clientPort := 58122
	mtu := 1200

	go func() {
		var (
			privateKey = "003ed5d73b55806c30de3f8a7bdab38af13539220533055e635690b8b87ad641"
			publicKey  = "f928d4f6c1b86c12f2562c10b07c555c5c57fd00f59e90c8d8d88767271cbf7c"
		)
		conn, err := NewUDP(serverAddr, clientAddr, privateKey, publicKey, mtu, serverPort, clientPort)
		if err != nil {
			errCh <- err
			return
		}

		data, err := ConstructUDP(localAddr, serverPort, localAddr, clientPort, []byte("Hello UDP Client"))
		if err != nil {
			errCh <- err
			return
		}

		time.Sleep(2 * time.Second)

		for {
			select {
			case <-exit:
				return
			default:
			}
			fmt.Println("++++server++++0")
			n, err := conn.Write(data, 0)
			if err != nil {
				errCh <- err
				return
			}
			if n == 0 {
				errCh <- errors.New("server write 0")
				return
			}
			fmt.Println("++++server++++1++", n)
			conn.Flush()

			var buf [2048]byte
			_, err = conn.Read(buf[0:], 0)
			if err != nil {
				errCh <- err
				return
			}
			fmt.Println("++++server++++2")
			msgCh <- fmt.Sprint("server> ", string(buf[0:]))

		}
	}()

	go func() {
		var (
			privateKey = "087ec6e14bbed210e7215cdc73468dfa23f080a1bfb8665b2fd809bd99d28379"
			publicKey  = "c4c8e984c5322c8184c72265b92b250fdb63688705f504ba003c88f03393cf28"
		)
		conn, err := NewUDP(clientAddr, serverAddr, privateKey, publicKey, mtu, clientPort, serverPort)
		if err != nil {
			errCh <- err
			return
		}

		data, err := ConstructUDP(localAddr, clientPort, localAddr, serverPort, []byte("Hello UDP Server"))
		if err != nil {
			errCh <- err
			return
		}

		time.Sleep(2 * time.Second)

		for {
			select {
			case <-exit:
				return
			default:
			}
			fmt.Println("++++client++++0")
			n, err := conn.Write(data, 0)
			if err != nil {
				errCh <- err
				return
			}
			if n == 0 {
				errCh <- errors.New("client write 0")
				return
			}
			fmt.Println("++++client++++1++", n)
			conn.Flush()

			var buf [2048]byte
			_, err = conn.Read(buf[0:], 0)
			if err != nil {
				errCh <- err
				return
			}
			fmt.Println("++++client++++2")
			msgCh <- fmt.Sprint("client> ", string(buf[0:]))

			time.Sleep(5 * time.Second)
			close(exit)
		}
	}()

	select {
	case msg := <-msgCh:
		t.Log(msg)
	case err := <-errCh:
		close(exit)
		t.Fatal(err)
	case <-exit:
	}

}

func ConstructUDP(srcIP string, srcPort int, dstIP string, dstPort int, data []byte) ([]byte, error) {
	sIP := net.ParseIP(srcIP)
	if sIP == nil {
		return nil, fmt.Errorf("non-ip target: %q", srcIP)
	}
	sIP = sIP.To4()
	if sIP == nil {
		return nil, fmt.Errorf("non-ipv4 target: %q", srcIP)
	}

	dIP := net.ParseIP(dstIP)
	if dIP == nil {
		return nil, fmt.Errorf("non-ip target: %q", dstIP)
	}
	dIP = dIP.To4()
	if dIP == nil {
		return nil, fmt.Errorf("non-ipv4 target: %q", dstIP)
	}

	ip := layers.IPv4{
		SrcIP:    sIP,
		DstIP:    dIP,
		Version:  4,
		TTL:      64,
		Protocol: layers.IPProtocolTCP,
	}

	sport := layers.TCPPort(srcPort)
	dport := layers.TCPPort(dstPort)
	tcp := layers.TCP{
		SrcPort: sport,
		DstPort: dport,
		Window:  1505,
		Urgent:  0,
		Seq:     11050,
		Ack:     0,
	}
	opts := gopacket.SerializeOptions{
		FixLengths:       true,
		ComputeChecksums: true,
	}

	tcp.SetNetworkLayerForChecksum(&ip)

	tcpPayloadBuf := gopacket.NewSerializeBuffer()
	payload := gopacket.Payload(data)
	if err := gopacket.SerializeLayers(tcpPayloadBuf, opts, &tcp, payload); err != nil {
		return nil, fmt.Errorf("failed to serialize: %v", err)
	}

	return tcpPayloadBuf.Bytes(), nil
}

更多关于Golang中Wireguard-go可以写入但无法读取的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中Wireguard-go可以写入但无法读取的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


问题在于你的ConstructUDP函数实际上构造的是TCP数据包,而不是UDP数据包。WireGuard使用UDP协议,但你的代码中错误地使用了layers.TCPlayers.IPProtocolTCP

以下是修正后的ConstructUDP函数:

func ConstructUDP(srcIP string, srcPort int, dstIP string, dstPort int, data []byte) ([]byte, error) {
    sIP := net.ParseIP(srcIP)
    if sIP == nil {
        return nil, fmt.Errorf("non-ip target: %q", srcIP)
    }
    sIP = sIP.To4()
    if sIP == nil {
        return nil, fmt.Errorf("non-ipv4 target: %q", srcIP)
    }

    dIP := net.ParseIP(dstIP)
    if dIP == nil {
        return nil, fmt.Errorf("non-ip target: %q", dstIP)
    }
    dIP = dIP.To4()
    if dIP == nil {
        return nil, fmt.Errorf("non-ipv4 target: %q", dstIP)
    }

    ip := layers.IPv4{
        SrcIP:    sIP,
        DstIP:    dIP,
        Version:  4,
        TTL:      64,
        Protocol: layers.IPProtocolUDP, // 改为UDP协议
    }

    sport := layers.UDPPort(srcPort)
    dport := layers.UDPPort(dstPort)
    udp := layers.UDP{ // 使用UDP层而不是TCP
        SrcPort: sport,
        DstPort: dport,
    }
    opts := gopacket.SerializeOptions{
        FixLengths:       true,
        ComputeChecksums: true,
    }

    udp.SetNetworkLayerForChecksum(&ip)

    udpPayloadBuf := gopacket.NewSerializeBuffer()
    payload := gopacket.Payload(data)
    if err := gopacket.SerializeLayers(udpPayloadBuf, opts, &udp, payload); err != nil {
        return nil, fmt.Errorf("failed to serialize: %v", err)
    }

    return udpPayloadBuf.Bytes(), nil
}

另外,你的测试代码中还有几个问题需要修正:

  1. NewUDP函数中,DNS服务器地址硬编码为8.8.8.8,这可能导致网络问题:
func NewUDP(localAddr, remoteAddr, privateKey, publicKey string,
    mtu, localPort, remotePort int) (tun.Device, error) {
    tun, _, err := netstack.CreateNetTUN(
        []netip.Addr{netip.MustParseAddr(localAddr)},
        []netip.Addr{}, // 可以留空或使用合适的DNS
        mtu,
    )
    if err != nil {
        return nil, err
    }
    // ... 其余代码不变
}
  1. 测试中的无限循环可能导致goroutine泄漏,建议添加超时控制:
func TestUDP(t *testing.T) {
    timeout := time.After(10 * time.Second)
    done := make(chan bool)
    
    // ... 原有代码
    
    select {
    case msg := <-msgCh:
        t.Log(msg)
    case err := <-errCh:
        t.Fatal(err)
    case <-timeout:
        t.Fatal("test timeout")
    case <-done:
        t.Log("test completed")
    }
}
  1. 确保WireGuard设备正确配置了路由。在dev.IpcSet中添加路由配置:
err = dev.IpcSet(fmt.Sprintf(`private_key=%s
listen_port=%d
public_key=%s
allowed_ip=0.0.0.0/0
endpoint=127.0.0.1:%d
persistent_keepalive_interval=25
`, privateKey, localPort, publicKey, remotePort))

读取不工作的根本原因是协议不匹配。WireGuard期望接收UDP数据包,但你的代码发送的是TCP数据包,导致WireGuard无法正确解析和处理这些数据包。修正协议类型后,读取功能应该能正常工作。

回到顶部