增加 macvtap 模式支持

This commit is contained in:
bjdgyc
2021-08-12 18:17:20 +08:00
parent 5010d2ecbd
commit 903554533b
19 changed files with 295 additions and 125 deletions

View File

@@ -7,6 +7,7 @@ import (
"time"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/pkg/utils"
"github.com/bjdgyc/anylink/sessdata"
)
@@ -29,7 +30,7 @@ func LinkCstp(conn net.Conn, bufRW *bufio.ReadWriter, cSess *sessdata.ConnSessio
for {
// 设置超时限制
err = conn.SetReadDeadline(time.Now().Add(dead))
err = conn.SetReadDeadline(utils.NowSec().Add(dead))
if err != nil {
base.Error("SetDeadline: ", err)
return

View File

@@ -5,6 +5,7 @@ import (
"time"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/pkg/utils"
"github.com/bjdgyc/anylink/sessdata"
)
@@ -32,7 +33,7 @@ func LinkDtls(conn net.Conn, cSess *sessdata.ConnSession) {
go dtlsWrite(conn, dSess, cSess)
for {
err = conn.SetReadDeadline(time.Now().Add(dead))
err = conn.SetReadDeadline(utils.NowSec().Add(dead))
if err != nil {
base.Error("SetDeadline: ", err)
return

View File

@@ -2,6 +2,7 @@ package handler
import (
"fmt"
"io"
"net"
"github.com/bjdgyc/anylink/base"
@@ -17,18 +18,32 @@ import (
const bridgeName = "anylink0"
var (
bridgeIp net.IP
bridgeHw net.HardwareAddr
// 网关mac地址
gatewayHw net.HardwareAddr
)
func checkTap() {
brFace, err := net.InterfaceByName(bridgeName)
type LinkDriver interface {
io.ReadWriteCloser
Name() string
}
func _setGateway() {
dstAddr := arpdis.Lookup(sessdata.IpPool.Ipv4Gateway, false)
gatewayHw = dstAddr.HardwareAddr
// 设置为静态地址映射
dstAddr.Type = arpdis.TypeStatic
arpdis.Add(dstAddr)
}
func _checkTapIp(ifName string) {
iFace, err := net.InterfaceByName(ifName)
if err != nil {
base.Fatal("testTap err: ", err)
}
bridgeHw = brFace.HardwareAddr
addrs, err := brFace.Addrs()
var ifIp net.IP
addrs, err := iFace.Addrs()
if err != nil {
base.Fatal("testTap err: ", err)
}
@@ -37,17 +52,19 @@ func checkTap() {
if err != nil || ip.To4() == nil {
continue
}
bridgeIp = ip
}
if bridgeIp == nil && bridgeHw == nil {
base.Fatal("bridgeIp is err")
ifIp = ip
}
if !sessdata.IpPool.Ipv4IPNet.Contains(bridgeIp) {
base.Fatal("bridgeIp or Ip network err")
if !sessdata.IpPool.Ipv4IPNet.Contains(ifIp) {
base.Fatal("tapIp or Ip network err")
}
}
func checkTap() {
_setGateway()
_checkTapIp(bridgeName)
}
// 创建tap网卡
func LinkTap(cSess *sessdata.ConnSession) error {
cfg := water.Config{
@@ -60,9 +77,8 @@ func LinkTap(cSess *sessdata.ConnSession) error {
return err
}
cSess.TunName = ifce.Name()
cSess.SetIfName(ifce.Name())
// arp on
cmdstr1 := fmt.Sprintf("ip link set dev %s up mtu %d multicast on", ifce.Name(), cSess.Mtu)
cmdstr2 := fmt.Sprintf("ip link set dev %s master %s", ifce.Name(), bridgeName)
err = execCmd([]string{cmdstr1, cmdstr2})
@@ -75,25 +91,31 @@ func LinkTap(cSess *sessdata.ConnSession) error {
cmdstr3 := fmt.Sprintf("sysctl -w net.ipv6.conf.%s.disable_ipv6=1", ifce.Name())
execCmd([]string{cmdstr3})
go tapRead(ifce, cSess)
go tapWrite(ifce, cSess)
go allTapRead(ifce, cSess)
go allTapWrite(ifce, cSess)
return nil
}
func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
// ========================通用代码===========================
func allTapWrite(ifce LinkDriver, cSess *sessdata.ConnSession) {
defer func() {
base.Debug("LinkTap return", cSess.IpAddr)
cSess.Close()
_ = ifce.Close()
ifce.Close()
}()
var (
err error
dstHw net.HardwareAddr
pl *sessdata.Payload
frame ethernet.Frame
frame = make(ethernet.Frame, BufferSize)
ipDst = net.IPv4(1, 2, 3, 4)
)
for {
frame.Resize(BufferSize)
select {
case pl = <-cSess.PayloadIn:
case <-cSess.CloseChan:
@@ -101,45 +123,46 @@ func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
}
// var frame ethernet.Frame
fb := getByteFull()
frame = *fb
switch pl.LType {
default:
// log.Println(payload)
case sessdata.LTypeEthernet:
copy(frame, pl.Data)
frame = frame[:len(pl.Data)]
// packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default)
// fmt.Println("wirteArp:", packet)
case sessdata.LTypeIPData: // 需要转换成 Ethernet 数据
ip_src := waterutil.IPv4Source(pl.Data)
if waterutil.IsIPv6(pl.Data) || !ip_src.Equal(cSess.IpAddr) {
// 过滤掉IPv6的数据
ipSrc := waterutil.IPv4Source(pl.Data)
if !ipSrc.Equal(cSess.IpAddr) {
// 非分配给客户端ip直接丢弃
continue
}
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
if waterutil.IsIPv6(pl.Data) {
// 过滤掉IPv6的数据
continue
}
// packet := gopacket.NewPacket(pl.Data, layers.LayerTypeIPv4, gopacket.Default)
// fmt.Println("get:", packet)
ip_dst := waterutil.IPv4Destination(pl.Data)
// fmt.Println("get:", ip_src, ip_dst)
// 手动设置ipv4地址
ipDst[12] = pl.Data[16]
ipDst[13] = pl.Data[17]
ipDst[14] = pl.Data[18]
ipDst[15] = pl.Data[19]
var dstHw net.HardwareAddr
if !sessdata.IpPool.Ipv4IPNet.Contains(ip_dst) || ip_dst.Equal(sessdata.IpPool.Ipv4Gateway) {
// 不是同一网段使用网关mac地址
dstAddr := arpdis.Lookup(sessdata.IpPool.Ipv4Gateway, false)
dstHw = dstAddr.HardwareAddr
} else {
dstAddr := arpdis.Lookup(ip_dst, true)
dstHw = gatewayHw
if sessdata.IpPool.Ipv4IPNet.Contains(ipDst) {
dstAddr := arpdis.Lookup(ipDst, true)
// fmt.Println("dstAddr", dstAddr)
if dstAddr != nil {
dstHw = dstAddr.HardwareAddr
} else {
dstHw = bridgeHw
}
}
// fmt.Println("Gateway", ip_dst, dstAddr.HardwareAddr)
// fmt.Println("Gateway", ipSrc, ipDst, dstHw)
frame.Prepare(dstHw, cSess.MacHw, ethernet.NotTagged, ethernet.IPv4, len(pl.Data))
copy(frame[12+2:], pl.Data)
}
@@ -152,29 +175,26 @@ func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
return
}
putByte(fb)
putPayload(pl)
}
}
func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
func allTapRead(ifce LinkDriver, cSess *sessdata.ConnSession) {
defer func() {
base.Debug("tapRead return", cSess.IpAddr)
_ = ifce.Close()
ifce.Close()
}()
var (
err error
n int
data []byte
frame ethernet.Frame
frame = make(ethernet.Frame, BufferSize)
)
for {
// var frame ethernet.Frame
// frame.Resize(BufferSize)
fb := getByteFull()
frame = *fb
frame.Resize(BufferSize)
n, err = ifce.Read(frame)
if err != nil {
base.Error("tap Read err", n, err)
@@ -184,8 +204,6 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
switch frame.Ethertype() {
default:
// packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default)
// fmt.Println(packet)
continue
case ethernet.IPv6:
continue
@@ -214,7 +232,7 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
case ethernet.ARP:
// 暂时仅实现了ARP协议
packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default)
packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.NoCopy)
layer := packet.Layer(layers.LayerTypeARP)
arpReq := layer.(*layers.ARP)
@@ -223,12 +241,12 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
continue
}
// fmt.Println("arp", net.IP(arpReq.SourceProtAddress), sess.Ip)
// fmt.Println("arp", time.Now(), net.IP(arpReq.SourceProtAddress), cSess.IpAddr)
// fmt.Println(packet)
// 返回ARP数据
src := &arpdis.Addr{IP: cSess.IpAddr, HardwareAddr: cSess.MacHw}
dst := &arpdis.Addr{IP: arpReq.SourceProtAddress, HardwareAddr: frame.Source()}
dst := &arpdis.Addr{IP: arpReq.SourceProtAddress, HardwareAddr: arpReq.SourceHwAddress}
data, err = arpdis.NewARPReply(src, dst)
if err != nil {
base.Error(err)
@@ -237,13 +255,9 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
// 从接受的arp信息添加arp地址
addr := &arpdis.Addr{
IP: make([]byte, len(arpReq.SourceProtAddress)),
HardwareAddr: make([]byte, len(frame.Source())),
IP: append([]byte{}, dst.IP...),
HardwareAddr: append([]byte{}, dst.HardwareAddr...),
}
// addr.IP = arpReq.SourceProtAddress
// addr.HardwareAddr = frame.Source()
copy(addr.IP, arpReq.SourceProtAddress)
copy(addr.HardwareAddr, frame.Source())
arpdis.Add(addr)
pl := getPayload()
@@ -259,7 +273,5 @@ func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
}
}
putByte(fb)
}
}

View File

@@ -40,8 +40,7 @@ func LinkTun(cSess *sessdata.ConnSession) error {
return err
}
// log.Printf("Interface Name: %s\n", ifce.Name())
cSess.SetTunName(ifce.Name())
// cSess.TunName = ifce.Name()
cSess.SetIfName(ifce.Name())
cmdstr1 := fmt.Sprintf("ip link set dev %s up mtu %d multicast off", ifce.Name(), cSess.Mtu)
cmdstr2 := fmt.Sprintf("ip addr add dev %s local %s peer %s/32",

View File

@@ -160,9 +160,12 @@ func LinkTunnel(w http.ResponseWriter, r *http.Request) {
err = LinkTun(cSess)
case base.LinkModeTAP:
err = LinkTap(cSess)
case base.LinkModeMacvtap:
err = LinkMacvtap(cSess)
}
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
conn.Close()
base.Error(err)
return
}

137
server/handler/link_vtap.go Normal file
View File

@@ -0,0 +1,137 @@
package handler
import (
"fmt"
"net"
"os"
"strings"
"syscall"
"unsafe"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/pkg/utils"
"github.com/bjdgyc/anylink/sessdata"
)
// link vtap
const vTapPrefix = "lvtap"
type Vtap struct {
*os.File
ifName string
}
func (v *Vtap) Close() error {
v.File.Close()
cmdstr := fmt.Sprintf("ip link del %s", v.ifName)
return execCmd([]string{cmdstr})
}
func checkMacvtap() {
_setGateway()
_checkTapIp(base.Cfg.Ipv4Master)
ifName := "anylinkMacvtap"
// 加载 macvtap
cmdstr0 := fmt.Sprintf("modprobe -i macvtap")
// 开启主网卡混杂模式
cmdstr1 := fmt.Sprintf("ip link set dev %s promisc on", base.Cfg.Ipv4Master)
// 测试 macvtap 功能
cmdstr2 := fmt.Sprintf("ip link add link %s name %s type macvtap mode bridge", base.Cfg.Ipv4Master, ifName)
cmdstr3 := fmt.Sprintf("ip link del %s", ifName)
err := execCmd([]string{cmdstr0, cmdstr1, cmdstr2, cmdstr3})
if err != nil {
base.Fatal(err)
}
}
// 创建 Macvtap 网卡
func LinkMacvtap(cSess *sessdata.ConnSession) error {
capL := sessdata.IpPool.IpLongMax - sessdata.IpPool.IpLongMin
ipN := utils.Ip2long(cSess.IpAddr) % capL
ifName := fmt.Sprintf("%s%d", vTapPrefix, ipN)
cSess.SetIfName(ifName)
cmdstr1 := fmt.Sprintf("ip link add link %s name %s type macvtap mode bridge", base.Cfg.Ipv4Master, ifName)
cmdstr2 := fmt.Sprintf("ip link set dev %s up mtu %d address %s", ifName, cSess.Mtu, cSess.MacHw)
err := execCmd([]string{cmdstr1, cmdstr2})
if err != nil {
base.Error(err)
return err
}
cmdstr3 := fmt.Sprintf("sysctl -w net.ipv6.conf.%s.disable_ipv6=1", ifName)
execCmd([]string{cmdstr3})
return createVtap(cSess, ifName)
}
func checkIpvtap() {
}
// 创建 Ipvtap 网卡
func LinkIpvtap(cSess *sessdata.ConnSession) error {
return nil
}
type ifReq struct {
Name [0x10]byte
Flags uint16
pad [0x28 - 0x10 - 2]byte
}
func createVtap(cSess *sessdata.ConnSession, ifName string) error {
// 初始化 ifName
inf, err := net.InterfaceByName(ifName)
if err != nil {
base.Error(err)
return err
}
tName := fmt.Sprintf("/dev/tap%d", inf.Index)
var fdInt int
fdInt, err = syscall.Open(tName, os.O_RDWR|syscall.O_NONBLOCK, 0)
if err != nil {
return err
}
var flags uint16 = syscall.IFF_TAP | syscall.IFF_NO_PI
var req ifReq
req.Flags = flags
_, _, errno := syscall.Syscall(
syscall.SYS_IOCTL,
uintptr(fdInt),
uintptr(syscall.TUNSETIFF),
uintptr(unsafe.Pointer(&req)),
)
if errno != 0 {
return os.NewSyscallError("ioctl", errno)
}
file := os.NewFile(uintptr(fdInt), tName)
ifce := &Vtap{file, ifName}
go allTapRead(ifce, cSess)
go allTapWrite(ifce, cSess)
return nil
}
// 销毁未关闭的vtap
func destroyVtap() {
its, err := net.Interfaces()
if err != nil {
base.Error(err)
return
}
for _, v := range its {
if strings.HasPrefix(v.Name, vTapPrefix) {
// 删除原来的网卡
cmdstr := fmt.Sprintf("ip link del %s", v.Name)
execCmd([]string{cmdstr})
}
}
}

View File

@@ -11,10 +11,17 @@ func Start() {
dbdata.Start()
sessdata.Start()
checkTun()
if base.Cfg.LinkMode == base.LinkModeTAP {
switch base.Cfg.LinkMode {
case base.LinkModeTUN:
checkTun()
case base.LinkModeTAP:
checkTap()
case base.LinkModeMacvtap:
checkMacvtap()
default:
base.Fatal("LinkMode is err")
}
go admin.StartAdmin()
go startTls()
go startDtls()
@@ -22,4 +29,5 @@ func Start() {
func Stop() {
_ = dbdata.Stop()
destroyVtap()
}