feature: setup veth and allow routing to an external interface
This commit is contained in:
parent
f63f74284d
commit
fdb4db7dba
@ -33,14 +33,14 @@ func setupEnv() int {
|
||||
}
|
||||
}(newNs)
|
||||
|
||||
vethPair, err := netlink.NewVethPair(newNs)
|
||||
vethPair, err := netlink.NewVirtualPairing(newNs, "wlp3s0")
|
||||
if err != nil {
|
||||
fmt.Println("new Veth error", err)
|
||||
return 1
|
||||
}
|
||||
|
||||
defer func(veth *netlink.PairLink) {
|
||||
err = veth.DeleteLink()
|
||||
err = veth.DeleteVirtualPairing()
|
||||
if err != nil {
|
||||
fmt.Println("delete vethPair error", err)
|
||||
}
|
||||
|
5
go.mod
5
go.mod
@ -9,4 +9,7 @@ require (
|
||||
golang.org/x/sys v0.15.0
|
||||
)
|
||||
|
||||
require github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae // indirect
|
||||
require (
|
||||
github.com/coreos/go-iptables v0.7.0 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae // indirect
|
||||
)
|
||||
|
2
go.sum
2
go.sum
@ -1,3 +1,5 @@
|
||||
github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8=
|
||||
github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
|
||||
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||
|
@ -2,9 +2,12 @@ package netlink
|
||||
|
||||
import (
|
||||
"antoine-roux.tk/projects/go/firecracker-netns/internal/netns"
|
||||
"antoine-roux.tk/projects/go/firecracker-netns/internal/sysctl"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"github.com/coreos/go-iptables/iptables"
|
||||
"github.com/vishvananda/netlink"
|
||||
"net"
|
||||
)
|
||||
|
||||
// inspired by https://github.com/containernetworking/plugins/blob/main/pkg/ip/link_linux.go#L57
|
||||
@ -12,14 +15,16 @@ import (
|
||||
type Peer struct {
|
||||
link netlink.Link
|
||||
netNs netns.NsHandle
|
||||
ip net.IPNet
|
||||
}
|
||||
|
||||
type PairLink struct {
|
||||
host Peer
|
||||
guest Peer
|
||||
host Peer
|
||||
guest Peer
|
||||
wanLinkName string
|
||||
}
|
||||
|
||||
func NewVethPair(ns netns.NsHandle) (pair *PairLink, error error) {
|
||||
func NewVirtualPairing(ns netns.NsHandle, wanLinkName string) (pair *PairLink, error error) {
|
||||
|
||||
origins, err := netns.Get()
|
||||
if err != nil {
|
||||
@ -61,6 +66,35 @@ func NewVethPair(ns netns.NsHandle) (pair *PairLink, error error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = netlink.LinkSetUp(veth2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
veth2IP := &netlink.Addr{
|
||||
IPNet: &net.IPNet{
|
||||
IP: net.IPv4(192, 168, 0, 3),
|
||||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
}
|
||||
|
||||
// ip addr add 192.168.0.3/24 dev veth527f8d3e
|
||||
err = netlink.AddrAdd(veth2, veth2IP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ip route add default via veth527f8d3e
|
||||
_, defaultDst, _ := net.ParseCIDR("0.0.0.0/0")
|
||||
defaultRoute := &netlink.Route{
|
||||
LinkIndex: veth2.Attrs().Index,
|
||||
Dst: defaultDst,
|
||||
}
|
||||
err = netlink.RouteAdd(defaultRoute)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = netns.Set(origins)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -73,11 +107,62 @@ func NewVethPair(ns netns.NsHandle) (pair *PairLink, error error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PairLink{host: Peer{veth1, origins}, guest: Peer{veth2, ns}}, nil
|
||||
err = netlink.LinkSetUp(veth1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
veth1IP := &netlink.Addr{
|
||||
IPNet: &net.IPNet{
|
||||
IP: net.IPv4(192, 168, 0, 4),
|
||||
Mask: net.CIDRMask(24, 32),
|
||||
},
|
||||
}
|
||||
|
||||
// ip addr add 192.168.0.4/24 dev vethda43d466
|
||||
err = netlink.AddrAdd(veth1, veth1IP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// bash -c 'echo 1 > /proc/sys/net/ipv4/conf/veth4bbc9fef/proxy_arp'
|
||||
err = sysctl.Set(fmt.Sprintf("net.ipv4.conf.%s.proxy_arp", veth1.Attrs().Name), "1")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ipt, err := iptables.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// sudo iptables -t nat -I POSTROUTING 1 -o wlp3s0 -j MASQUERADE --source 192.168.0.3/24
|
||||
err = ipt.InsertUnique("nat", "POSTROUTING", 1, "-o", wanLinkName, "-j", "MASQUERADE", "--source", veth2IP.IPNet.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// sudo iptables -I FORWARD 1 -o vethee574a50 -i wlp3s0 -j ACCEPT
|
||||
err = ipt.InsertUnique("filter", "FORWARD", 1, "-o", veth1.Attrs().Name, "-i", wanLinkName, "-j", "ACCEPT")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// sudo iptables -I FORWARD 1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
err = ipt.InsertUnique("filter", "FORWARD", 1, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PairLink{
|
||||
host: Peer{veth1, origins, *veth1IP.IPNet},
|
||||
guest: Peer{veth2, ns, *veth2IP.IPNet},
|
||||
wanLinkName: wanLinkName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DeleteLink removes an interface link.
|
||||
func (p *PairLink) DeleteLink() error {
|
||||
// DeleteVirtualPairing removes an interface link.
|
||||
func (p *PairLink) DeleteVirtualPairing() error {
|
||||
err := netns.Set(p.host.netNs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("set original Ns for deleting veth %q: %v", p.host.link.Attrs().Name, err)
|
||||
@ -87,6 +172,29 @@ func (p *PairLink) DeleteLink() error {
|
||||
return fmt.Errorf("failed to delete %q: %v", p.host.link.Attrs().Name, err)
|
||||
}
|
||||
|
||||
ipt, err := iptables.New()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// sudo iptables -t nat -I POSTROUTING 1 -o wlp3s0 -j MASQUERADE --source 192.168.0.3/24
|
||||
err = ipt.DeleteIfExists("nat", "POSTROUTING", "-o", p.wanLinkName, "-j", "MASQUERADE", "--source", p.guest.ip.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// sudo iptables -I FORWARD 1 -o vethee574a50 -i wlp3s0 -j ACCEPT
|
||||
err = ipt.DeleteIfExists("filter", "FORWARD", "-o", p.host.link.Attrs().Name, "-i", p.wanLinkName, "-j", "ACCEPT")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// sudo iptables -I FORWARD 1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
err = ipt.DeleteIfExists("filter", "FORWARD", "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
37
internal/sysctl/sysctl.go
Normal file
37
internal/sysctl/sysctl.go
Normal file
@ -0,0 +1,37 @@
|
||||
package sysctl
|
||||
|
||||
// inspired from https://github.com/lorenzosaino/go-sysctl/blob/main/sysctl.go
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const defaultPath = "/proc/sys/"
|
||||
|
||||
// Get returns a sysctl from a given key.
|
||||
func Get(key string) (string, error) {
|
||||
return readFile(pathFromKey(key))
|
||||
}
|
||||
|
||||
// Set updates the value of a sysctl.
|
||||
func Set(key, value string) error {
|
||||
return writeFile(pathFromKey(key), value)
|
||||
}
|
||||
|
||||
func pathFromKey(key string) string {
|
||||
return filepath.Join(defaultPath, strings.Replace(key, ".", "/", -1))
|
||||
}
|
||||
|
||||
func readFile(path string) (string, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return strings.TrimSpace(string(data)), nil
|
||||
}
|
||||
|
||||
func writeFile(path, value string) error {
|
||||
return os.WriteFile(path, []byte(value), 0o644)
|
||||
}
|
Loading…
Reference in New Issue
Block a user