2019-04-29 21:25:05 +00:00
|
|
|
// Copyright 2018 The gVisor Authors.
|
2018-07-09 21:03:03 +00:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2018-04-27 17:37:02 +00:00
|
|
|
|
2018-08-22 20:29:57 +00:00
|
|
|
// +build linux
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// This sample creates a stack with TCP and IPv4 protocols on top of a TUN
|
|
|
|
// device, and listens on a port. Data received by the server in the accepted
|
|
|
|
// connections is echoed back to the clients.
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"flag"
|
|
|
|
"log"
|
|
|
|
"math/rand"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2019-06-13 23:49:09 +00:00
|
|
|
"gvisor.dev/gvisor/pkg/tcpip"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/link/fdbased"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/link/rawfile"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/link/tun"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/network/arp"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
|
|
|
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
|
|
|
|
"gvisor.dev/gvisor/pkg/waiter"
|
2018-04-27 17:37:02 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var tap = flag.Bool("tap", false, "use tap istead of tun")
|
|
|
|
var mac = flag.String("mac", "aa:00:01:01:01:01", "mac address to use in tap device")
|
|
|
|
|
|
|
|
func echo(wq *waiter.Queue, ep tcpip.Endpoint) {
|
|
|
|
defer ep.Close()
|
|
|
|
|
|
|
|
// Create wait queue entry that notifies a channel.
|
|
|
|
waitEntry, notifyCh := waiter.NewChannelEntry(nil)
|
|
|
|
|
|
|
|
wq.EventRegister(&waitEntry, waiter.EventIn)
|
|
|
|
defer wq.EventUnregister(&waitEntry)
|
|
|
|
|
|
|
|
for {
|
2018-05-02 05:11:07 +00:00
|
|
|
v, _, err := ep.Read(nil)
|
2018-04-27 17:37:02 +00:00
|
|
|
if err != nil {
|
|
|
|
if err == tcpip.ErrWouldBlock {
|
|
|
|
<-notifyCh
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ep.Write(tcpip.SlicePayload(v), tcpip.WriteOptions{})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
flag.Parse()
|
|
|
|
if len(flag.Args()) != 3 {
|
|
|
|
log.Fatal("Usage: ", os.Args[0], " <tun-device> <local-address> <local-port>")
|
|
|
|
}
|
|
|
|
|
|
|
|
tunName := flag.Arg(0)
|
|
|
|
addrName := flag.Arg(1)
|
|
|
|
portName := flag.Arg(2)
|
|
|
|
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
|
|
|
|
// Parse the mac address.
|
|
|
|
maddr, err := net.ParseMAC(*mac)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Bad MAC address: %v", *mac)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the IP address. Support both ipv4 and ipv6.
|
|
|
|
parsedAddr := net.ParseIP(addrName)
|
|
|
|
if parsedAddr == nil {
|
|
|
|
log.Fatalf("Bad IP address: %v", addrName)
|
|
|
|
}
|
|
|
|
|
|
|
|
var addr tcpip.Address
|
|
|
|
var proto tcpip.NetworkProtocolNumber
|
|
|
|
if parsedAddr.To4() != nil {
|
|
|
|
addr = tcpip.Address(parsedAddr.To4())
|
|
|
|
proto = ipv4.ProtocolNumber
|
|
|
|
} else if parsedAddr.To16() != nil {
|
|
|
|
addr = tcpip.Address(parsedAddr.To16())
|
|
|
|
proto = ipv6.ProtocolNumber
|
|
|
|
} else {
|
|
|
|
log.Fatalf("Unknown IP type: %v", addrName)
|
|
|
|
}
|
|
|
|
|
|
|
|
localPort, err := strconv.Atoi(portName)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Unable to convert port %v: %v", portName, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the stack with ip and tcp protocols, then add a tun-based
|
|
|
|
// NIC and address.
|
2019-09-25 19:56:00 +00:00
|
|
|
s := stack.New(stack.Options{
|
|
|
|
NetworkProtocols: []stack.NetworkProtocol{ipv4.NewProtocol(), ipv6.NewProtocol(), arp.NewProtocol()},
|
|
|
|
TransportProtocols: []stack.TransportProtocol{tcp.NewProtocol()},
|
|
|
|
})
|
2018-04-27 17:37:02 +00:00
|
|
|
|
|
|
|
mtu, err := rawfile.GetMTU(tunName)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var fd int
|
|
|
|
if *tap {
|
|
|
|
fd, err = tun.OpenTAP(tunName)
|
|
|
|
} else {
|
|
|
|
fd, err = tun.Open(tunName)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2019-09-17 18:29:03 +00:00
|
|
|
linkEP, err := fdbased.New(&fdbased.Options{
|
2019-06-06 15:05:46 +00:00
|
|
|
FDs: []int{fd},
|
2018-04-27 17:37:02 +00:00
|
|
|
MTU: mtu,
|
|
|
|
EthernetHeader: *tap,
|
|
|
|
Address: tcpip.LinkAddress(maddr),
|
|
|
|
})
|
2019-04-17 18:14:24 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
2019-09-17 18:29:03 +00:00
|
|
|
if err := s.CreateNIC(1, linkEP); err != nil {
|
2018-04-27 17:37:02 +00:00
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := s.AddAddress(1, proto, addr); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := s.AddAddress(1, arp.ProtocolNumber, arp.ProtocolAddress); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2019-08-21 22:30:13 +00:00
|
|
|
subnet, err := tcpip.NewSubnet(tcpip.Address(strings.Repeat("\x00", len(addr))), tcpip.AddressMask(strings.Repeat("\x00", len(addr))))
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// Add default route.
|
|
|
|
s.SetRouteTable([]tcpip.Route{
|
|
|
|
{
|
2019-08-21 22:30:13 +00:00
|
|
|
Destination: subnet,
|
2018-04-27 17:37:02 +00:00
|
|
|
NIC: 1,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
// Create TCP endpoint, bind it, then start listening.
|
|
|
|
var wq waiter.Queue
|
|
|
|
ep, e := s.NewEndpoint(tcp.ProtocolNumber, proto, &wq)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(e)
|
|
|
|
}
|
|
|
|
|
|
|
|
defer ep.Close()
|
|
|
|
|
2019-03-05 22:52:35 +00:00
|
|
|
if err := ep.Bind(tcpip.FullAddress{0, "", uint16(localPort)}); err != nil {
|
2018-04-27 17:37:02 +00:00
|
|
|
log.Fatal("Bind failed: ", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := ep.Listen(10); err != nil {
|
|
|
|
log.Fatal("Listen failed: ", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for connections to appear.
|
|
|
|
waitEntry, notifyCh := waiter.NewChannelEntry(nil)
|
|
|
|
wq.EventRegister(&waitEntry, waiter.EventIn)
|
|
|
|
defer wq.EventUnregister(&waitEntry)
|
|
|
|
|
|
|
|
for {
|
|
|
|
n, wq, err := ep.Accept()
|
|
|
|
if err != nil {
|
|
|
|
if err == tcpip.ErrWouldBlock {
|
|
|
|
<-notifyCh
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Fatal("Accept() failed:", err)
|
|
|
|
}
|
|
|
|
|
2018-07-17 17:13:57 +00:00
|
|
|
go echo(wq, n) // S/R-SAFE: sample code.
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
}
|