mirror of
https://github.com/bjdgyc/anylink.git
synced 2025-08-08 11:44:11 +08:00
增加 macvtap 模式支持
This commit is contained in:
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
|
@@ -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",
|
||||
|
@@ -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
137
server/handler/link_vtap.go
Normal 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})
|
||||
}
|
||||
}
|
||||
}
|
@@ -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()
|
||||
}
|
||||
|
Reference in New Issue
Block a user