dockerfiles/anylink/server/handler/link_tap.go

266 lines
6.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handler
import (
"fmt"
"net"
"github.com/bjdgyc/anylink/base"
"github.com/bjdgyc/anylink/pkg/arpdis"
"github.com/bjdgyc/anylink/sessdata"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/songgao/packets/ethernet"
"github.com/songgao/water"
"github.com/songgao/water/waterutil"
)
const bridgeName = "anylink0"
var (
bridgeIp net.IP
bridgeHw net.HardwareAddr
)
func checkTap() {
brFace, err := net.InterfaceByName(bridgeName)
if err != nil {
base.Fatal("testTap err: ", err)
}
bridgeHw = brFace.HardwareAddr
addrs, err := brFace.Addrs()
if err != nil {
base.Fatal("testTap err: ", err)
}
for _, addr := range addrs {
ip, _, err := net.ParseCIDR(addr.String())
if err != nil || ip.To4() == nil {
continue
}
bridgeIp = ip
}
if bridgeIp == nil && bridgeHw == nil {
base.Fatal("bridgeIp is err")
}
if !sessdata.IpPool.Ipv4IPNet.Contains(bridgeIp) {
base.Fatal("bridgeIp or Ip network err")
}
}
// 创建tap网卡
func LinkTap(cSess *sessdata.ConnSession) error {
cfg := water.Config{
DeviceType: water.TAP,
}
ifce, err := water.New(cfg)
if err != nil {
base.Error(err)
return err
}
cSess.TunName = 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})
if err != nil {
base.Error(err)
_ = ifce.Close()
return err
}
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)
return nil
}
func tapWrite(ifce *water.Interface, cSess *sessdata.ConnSession) {
defer func() {
base.Debug("LinkTap return", cSess.IpAddr)
cSess.Close()
_ = ifce.Close()
}()
var (
err error
pl *sessdata.Payload
frame ethernet.Frame
)
for {
select {
case pl = <-cSess.PayloadIn:
case <-cSess.CloseChan:
return
}
// 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)]
case sessdata.LTypeIPData: // 需要转换成 Ethernet 数据
ip_src := waterutil.IPv4Source(pl.Data)
if waterutil.IsIPv6(pl.Data) || !ip_src.Equal(cSess.IpAddr) {
// 过滤掉IPv6的数据
// 非分配给客户端ip直接丢弃
continue
}
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
// fmt.Println("get:", packet)
ip_dst := waterutil.IPv4Destination(pl.Data)
// fmt.Println("get:", ip_src, ip_dst)
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)
// fmt.Println("dstAddr", dstAddr)
if dstAddr != nil {
dstHw = dstAddr.HardwareAddr
} else {
dstHw = bridgeHw
}
}
// fmt.Println("Gateway", ip_dst, dstAddr.HardwareAddr)
frame.Prepare(dstHw, cSess.MacHw, ethernet.NotTagged, ethernet.IPv4, len(pl.Data))
copy(frame[12+2:], pl.Data)
}
// packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default)
// fmt.Println("write:", packet)
_, err = ifce.Write(frame)
if err != nil {
base.Error("tap Write err", err)
return
}
putByte(fb)
putPayload(pl)
}
}
func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
defer func() {
base.Debug("tapRead return", cSess.IpAddr)
_ = ifce.Close()
}()
var (
err error
n int
data []byte
frame ethernet.Frame
)
for {
// var frame ethernet.Frame
// frame.Resize(BufferSize)
fb := getByteFull()
frame = *fb
n, err = ifce.Read(frame)
if err != nil {
base.Error("tap Read err", n, err)
return
}
frame = frame[:n]
switch frame.Ethertype() {
default:
// packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default)
// fmt.Println(packet)
continue
case ethernet.IPv6:
continue
case ethernet.IPv4:
// 发送IP数据
data = frame.Payload()
ip_dst := waterutil.IPv4Destination(data)
if !ip_dst.Equal(cSess.IpAddr) {
// 过滤非本机地址
// log.Println(ip_dst, sess.Ip)
continue
}
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
// fmt.Println("put:", packet)
pl := getPayload()
// 拷贝数据到pl
copy(pl.Data, data)
// 更新切片长度
pl.Data = pl.Data[:len(data)]
if payloadOut(cSess, pl) {
return
}
case ethernet.ARP:
// 暂时仅实现了ARP协议
packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.Default)
layer := packet.Layer(layers.LayerTypeARP)
arpReq := layer.(*layers.ARP)
if !cSess.IpAddr.Equal(arpReq.DstProtAddress) {
// 过滤非本机地址
continue
}
// fmt.Println("arp", net.IP(arpReq.SourceProtAddress), sess.Ip)
// fmt.Println(packet)
// 返回ARP数据
src := &arpdis.Addr{IP: cSess.IpAddr, HardwareAddr: cSess.MacHw}
dst := &arpdis.Addr{IP: arpReq.SourceProtAddress, HardwareAddr: frame.Source()}
data, err = arpdis.NewARPReply(src, dst)
if err != nil {
base.Error(err)
return
}
// 从接受的arp信息添加arp地址
addr := &arpdis.Addr{
IP: make([]byte, len(arpReq.SourceProtAddress)),
HardwareAddr: make([]byte, len(frame.Source())),
}
// addr.IP = arpReq.SourceProtAddress
// addr.HardwareAddr = frame.Source()
copy(addr.IP, arpReq.SourceProtAddress)
copy(addr.HardwareAddr, frame.Source())
arpdis.Add(addr)
pl := getPayload()
// 设置为二层数据类型
pl.LType = sessdata.LTypeEthernet
// 拷贝数据到pl
copy(pl.Data, data)
// 更新切片长度
pl.Data = pl.Data[:len(data)]
if payloadIn(cSess, pl) {
return
}
}
putByte(fb)
}
}