Last active
June 18, 2020 05:51
-
-
Save comzyh/f8972fa97ca8efbe158afcf4cf038927 to your computer and use it in GitHub Desktop.
Demo intergate songgao/water with google/netstack for Tun
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"log" | |
"os" | |
"strings" | |
"github.com/google/netstack/tcpip" | |
"github.com/google/netstack/tcpip/adapters/gonet" | |
"github.com/google/netstack/tcpip/buffer" | |
"github.com/google/netstack/tcpip/header" | |
"github.com/google/netstack/tcpip/link/channel" | |
"github.com/google/netstack/tcpip/network/ipv4" | |
"github.com/google/netstack/tcpip/network/ipv6" | |
"github.com/google/netstack/tcpip/stack" | |
"github.com/google/netstack/tcpip/transport/icmp" | |
"github.com/google/netstack/tcpip/transport/tcp" | |
"github.com/google/netstack/tcpip/transport/udp" | |
"github.com/songgao/water" | |
"github.com/google/netstack/waiter" | |
) | |
var ( | |
ipstack *stack.Stack | |
) | |
func echo(c *gonet.Conn) { | |
defer c.Close() | |
buf := make([]byte, 1500) | |
for { | |
n, err := c.Read(buf) | |
if err != nil { | |
log.Printf("Err: %v", err) | |
break | |
} | |
c.Write(buf[:n]) | |
} | |
log.Print("Connection closed") | |
} | |
func main() { | |
name := "tun0" | |
var mtu uint32 = 1500 | |
var err error | |
// create tun by water | |
ifce, err := water.New(water.Config{ | |
DeviceType: water.TUN, | |
PlatformSpecificParams: water.PlatformSpecificParams{ | |
Name: name, | |
}, | |
}) | |
if err != nil { | |
log.Fatal(err) | |
} | |
// create tcpip stack | |
ipstack = stack.New(stack.Options{ | |
NetworkProtocols: []stack.NetworkProtocol{ipv4.NewProtocol(), ipv6.NewProtocol()}, | |
TransportProtocols: []stack.TransportProtocol{tcp.NewProtocol(), udp.NewProtocol(), icmp.NewProtocol4()}, | |
}) | |
// create Link endpoint. 512 is the size of internal go channel | |
linkEP := channel.New(512, mtu, "") | |
// 1 is the NIC id, you can use any number you like | |
var nicID tcpip.NICID = 1 | |
// create virtual NIC. | |
if err := ipstack.CreateNIC(nicID, linkEP); err != nil { | |
log.Fatal(err) | |
} | |
// IPv4 0.0.0.0/0 | |
subnet, _ := tcpip.NewSubnet(tcpip.Address(strings.Repeat("\x00", 4)), tcpip.AddressMask(strings.Repeat("\x00", 4))) | |
ipstack.AddAddressRange(nicID, ipv4.ProtocolNumber, subnet) | |
// IPv6 [::]/0 | |
subnet, _ = tcpip.NewSubnet(tcpip.Address(strings.Repeat("\x00", 16)), tcpip.AddressMask(strings.Repeat("\x00", 16))) | |
ipstack.AddAddressRange(nicID, ipv6.ProtocolNumber, subnet) | |
if err != nil { | |
log.Fatal(err) | |
} | |
// use Forwarder to accept any connection from stack | |
fwd := tcp.NewForwarder(ipstack, 0, 16, func(r *tcp.ForwarderRequest) { | |
fmt.Printf("ForwarderRequest: %v\n", r) | |
var wq waiter.Queue | |
ep, err := r.CreateEndpoint(&wq) | |
if err != nil { | |
log.Fatalf("r.CreateEndpoint() = %v", err) | |
} | |
r.Complete(false) | |
c := gonet.NewConn(&wq, ep) | |
log.Printf("endpoint: %v", ep.Info().(*tcp.EndpointInfo).ID) | |
// TCP echo | |
go echo(c) | |
}) | |
ipstack.SetTransportProtocolHandler(tcp.ProtocolNumber, fwd.HandlePacket) | |
// start Read loop. read ip packet from tun and write it to ipstack | |
go func() { | |
packet := make([]byte, 2000) | |
for { | |
n, err := ifce.Read(packet) | |
if err != nil { | |
log.Fatal(err) | |
} | |
log.Printf("Packet Received: % x\n", packet[:n]) | |
var p tcpip.NetworkProtocolNumber | |
switch header.IPVersion(packet) { | |
case header.IPv4Version: | |
p = header.IPv4ProtocolNumber | |
case header.IPv6Version: | |
p = header.IPv6ProtocolNumber | |
} | |
linkEP.Inject(p, buffer.View(packet[:n]).ToVectorisedView()) | |
} | |
}() | |
// start write loop. read ip packet from ipstack and write it to tun | |
go func() { | |
for { | |
packet := <-linkEP.C | |
log.Printf("Packet Write out: % x % x\n", packet.Header, packet.Payload) | |
ifce.Write(buffer.NewVectorisedView(len(packet.Header)+len(packet.Payload), []buffer.View{packet.Header, packet.Payload}).ToView()) | |
} | |
}() | |
exitCh := make(chan os.Signal, 1) | |
log.Print("Waiting....") | |
<-exitCh | |
os.Exit(0) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment