From b6c51a357c7ae6ab62780e491c8c9479bc60b1bf Mon Sep 17 00:00:00 2001 From: lucheng Date: Mon, 5 Aug 2024 13:46:49 +0800 Subject: [PATCH] Add demo for use tun For MacOS, it only support tun. If use tun than tap, server should recode ip of each endpoint. And parse ipv4 header from net connection, and forword packet according to ipv4 header dst ip. If dst ip included by vpn cidr cheack the endpoint and forward to it. If dst ip included by vpn cidr but no recode of endpoint, drop it do nothing. If dst ip not included by vpn cidr, send it to server tun interface, it will forword by server according to routes and iptables rules. --- demo/tun/main.go | 198 +++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 2 +- 2 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 demo/tun/main.go diff --git a/demo/tun/main.go b/demo/tun/main.go new file mode 100644 index 0000000..a3adfe2 --- /dev/null +++ b/demo/tun/main.go @@ -0,0 +1,198 @@ +package main + +import ( + "fmt" + "io" + "net" + "os" + + "github.com/songgao/water" + "github.com/urfave/cli/v2" + "github.com/vishvananda/netlink" + "golang.org/x/net/ipv4" +) + +const ( + PORT = 8000 + ADDR = "10.67.0.254" + SIP = "10.69.0.254/24" + MAX_PKT_SIZE = 4096 +) + +var EP map[string]net.Conn +var idx = 1 + +func init() { + EP = make(map[string]net.Conn) +} + +func handleConn(conn net.Conn, iface *water.Interface) { + EP[fmt.Sprintf("10.69.0.%d", idx)] = conn + idx += 1 + + go func() { + for { + buf := make([]byte, MAX_PKT_SIZE) + n, err := iface.Read(buf) + if err != nil { + fmt.Println(err) + continue + } + + h, err := ipv4.ParseHeader(buf[:n]) + if err != nil { + fmt.Println(err) + continue + } + dst := h.Dst.String() + fmt.Printf("iface dst %s\n", dst) + p, ok := EP[dst] + if !ok { + fmt.Printf("pkt from server dst %s no route\n", dst) + continue + } + + _, err = p.Write(buf[:n]) + if err != nil { + fmt.Println(err) + continue + } + } + }() + + for { + buf := make([]byte, MAX_PKT_SIZE) + n, err := conn.Read(buf) + if err != nil { + fmt.Println(err) + continue + } + + h, err := ipv4.ParseHeader(buf[:n]) + if err != nil { + fmt.Println(err) + continue + } + dst := h.Dst.String() + fmt.Printf("conn dst %s\n", dst) + + p, ok := EP[dst] + if !ok { + fmt.Printf("pkt from client dst %s send to loacal", dst) + _, err = iface.Write(buf[:n]) + if err != nil { + fmt.Println(err) + continue + } + } else { + _, err = p.Write(buf[:n]) + if err != nil { + fmt.Println(err) + continue + } + } + } +} + +func setupTun(addr string) (*water.Interface, error) { + tname := "tun0" + config := water.Config{ + DeviceType: water.TUN, + } + config.Name = tname + + iface, err := water.New(config) + if err != nil { + return nil, err + } + + link, err := netlink.LinkByName(tname) + if err != nil { + return nil, err + } + + a, err := netlink.ParseAddr(addr) + if err != nil { + return nil, err + } + + err = netlink.AddrAdd(link, a) + if err != nil { + return nil, err + } + + err = netlink.LinkSetUp(link) + if err != nil { + return nil, err + } + + return iface, nil +} + +func sRun(cCtx *cli.Context) error { + ln, err := net.Listen("tcp4", fmt.Sprintf(":%d", PORT)) + if err != nil { + return err + } + fmt.Println("server listen on port 8000") + + iface, err := setupTun(SIP) + if err != nil { + return err + } + fmt.Printf("create tun %s\n", iface.Name()) + + for { + conn, err := ln.Accept() + if err != nil { + return err + } + + go handleConn(conn, iface) + } +} + +func cRun(cCtx *cli.Context) error { + conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", ADDR, PORT)) + if err != nil { + return err + } + fmt.Println("client dial 8000") + + iface, err := setupTun(cCtx.String("addr")) + if err != nil { + return err + } + + for { + go io.Copy(iface, conn) + io.Copy(conn, iface) + } +} + +func main() { + app := &cli.App{ + Commands: []*cli.Command{ + { + Name: "server", + Action: sRun, + }, + { + Name: "client", + Action: cRun, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "addr", + Aliases: []string{"a"}, + Required: true, + }, + }, + }, + }, + } + + if err := app.Run(os.Args); err != nil { + fmt.Println(err) + os.Exit(1) + } +} diff --git a/go.mod b/go.mod index db61da2..552cdcc 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 github.com/urfave/cli/v2 v2.27.1 github.com/vishvananda/netlink v1.1.0 + golang.org/x/net v0.10.0 golang.org/x/sync v0.7.0 golang.org/x/sys v0.19.0 golang.org/x/term v0.19.0 @@ -41,7 +42,6 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/crypto v0.9.0 // indirect - golang.org/x/net v0.10.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.30.0 // indirect )