1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
package virtualnetwork
import (
"math"
"net"
"net/http"
"os"
"github.com/containers/gvisor-tap-vsock/pkg/tap"
"github.com/containers/gvisor-tap-vsock/pkg/types"
"github.com/pkg/errors"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/link/sniffer"
"gvisor.dev/gvisor/pkg/tcpip/network/arp"
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
"gvisor.dev/gvisor/pkg/tcpip/stack"
"gvisor.dev/gvisor/pkg/tcpip/transport/icmp"
"gvisor.dev/gvisor/pkg/tcpip/transport/tcp"
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
)
type VirtualNetwork struct {
configuration *types.Configuration
stack *stack.Stack
networkSwitch *tap.Switch
servicesMux http.Handler
ipPool *tap.IPPool
}
func New(configuration *types.Configuration) (*VirtualNetwork, error) {
_, subnet, err := net.ParseCIDR(configuration.Subnet)
if err != nil {
return nil, errors.Wrap(err, "cannot parse subnet cidr")
}
var endpoint stack.LinkEndpoint
ipPool := tap.NewIPPool(subnet)
ipPool.Reserve(net.ParseIP(configuration.GatewayIP), configuration.GatewayMacAddress)
for ip, mac := range configuration.DHCPStaticLeases {
ipPool.Reserve(net.ParseIP(ip), mac)
}
tapEndpoint, err := tap.NewLinkEndpoint(configuration.Debug, configuration.MTU, configuration.GatewayMacAddress, configuration.GatewayIP, configuration.GatewayVirtualIPs)
if err != nil {
return nil, errors.Wrap(err, "cannot create tap endpoint")
}
networkSwitch := tap.NewSwitch(configuration.Debug, configuration.MTU)
tapEndpoint.Connect(networkSwitch)
networkSwitch.Connect(tapEndpoint)
if configuration.CaptureFile != "" {
_ = os.Remove(configuration.CaptureFile)
fd, err := os.Create(configuration.CaptureFile)
if err != nil {
return nil, errors.Wrap(err, "cannot create capture file")
}
endpoint, err = sniffer.NewWithWriter(tapEndpoint, fd, math.MaxUint32)
if err != nil {
return nil, errors.Wrap(err, "cannot create sniffer")
}
} else {
endpoint = tapEndpoint
}
stack, err := createStack(configuration, endpoint)
if err != nil {
return nil, errors.Wrap(err, "cannot create network stack")
}
mux, err := addServices(configuration, stack, ipPool)
if err != nil {
return nil, errors.Wrap(err, "cannot add network services")
}
return &VirtualNetwork{
configuration: configuration,
stack: stack,
networkSwitch: networkSwitch,
servicesMux: mux,
ipPool: ipPool,
}, nil
}
func (n *VirtualNetwork) BytesSent() uint64 {
if n.networkSwitch == nil {
return 0
}
return n.networkSwitch.Sent
}
func (n *VirtualNetwork) BytesReceived() uint64 {
if n.networkSwitch == nil {
return 0
}
return n.networkSwitch.Received
}
func createStack(configuration *types.Configuration, endpoint stack.LinkEndpoint) (*stack.Stack, error) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{
ipv4.NewProtocol,
arp.NewProtocol,
},
TransportProtocols: []stack.TransportProtocolFactory{
tcp.NewProtocol,
udp.NewProtocol,
icmp.NewProtocol4,
},
})
if err := s.CreateNIC(1, endpoint); err != nil {
return nil, errors.New(err.String())
}
if err := s.AddProtocolAddress(1, tcpip.ProtocolAddress{
Protocol: ipv4.ProtocolNumber,
AddressWithPrefix: tcpip.AddrFrom4Slice(net.ParseIP(configuration.GatewayIP).To4()).WithPrefix(),
}, stack.AddressProperties{}); err != nil {
return nil, errors.New(err.String())
}
s.SetSpoofing(1, true)
s.SetPromiscuousMode(1, true)
_, parsedSubnet, err := net.ParseCIDR(configuration.Subnet)
if err != nil {
return nil, errors.Wrap(err, "cannot parse cidr")
}
subnet, err := tcpip.NewSubnet(tcpip.AddrFromSlice(parsedSubnet.IP), tcpip.MaskFromBytes(parsedSubnet.Mask))
if err != nil {
return nil, errors.Wrap(err, "cannot parse subnet")
}
s.SetRouteTable([]tcpip.Route{
{
Destination: subnet,
Gateway: tcpip.Address{},
NIC: 1,
},
})
return s, nil
}
|