dockerfiles/anylink/server/handler/link_tap.go

266 lines
6.0 KiB
Go
Raw Normal View History

2021-06-08 20:45:26 +08:00
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)
2021-08-02 20:41:35 +08:00
cmdstr2 := fmt.Sprintf("ip link set dev %s master %s", ifce.Name(), bridgeName)
err = execCmd([]string{cmdstr1, cmdstr2})
2021-06-08 20:45:26 +08:00
if err != nil {
base.Error(err)
_ = ifce.Close()
return err
}
2021-08-02 20:41:35 +08:00
cmdstr3 := fmt.Sprintf("sysctl -w net.ipv6.conf.%s.disable_ipv6=1", ifce.Name())
execCmd([]string{cmdstr3})
2021-06-08 20:45:26 +08:00
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 (
2021-08-02 20:41:35 +08:00
err error
pl *sessdata.Payload
frame ethernet.Frame
2021-06-08 20:45:26 +08:00
)
for {
select {
2021-08-02 20:41:35 +08:00
case pl = <-cSess.PayloadIn:
2021-06-08 20:45:26 +08:00
case <-cSess.CloseChan:
return
}
// var frame ethernet.Frame
2021-08-02 20:41:35 +08:00
fb := getByteFull()
frame = *fb
switch pl.LType {
2021-06-08 20:45:26 +08:00
default:
// log.Println(payload)
case sessdata.LTypeEthernet:
2021-08-02 20:41:35 +08:00
copy(frame, pl.Data)
frame = frame[:len(pl.Data)]
2021-06-08 20:45:26 +08:00
case sessdata.LTypeIPData: // 需要转换成 Ethernet 数据
2021-08-02 20:41:35 +08:00
ip_src := waterutil.IPv4Source(pl.Data)
if waterutil.IsIPv6(pl.Data) || !ip_src.Equal(cSess.IpAddr) {
2021-06-08 20:45:26 +08:00
// 过滤掉IPv6的数据
// 非分配给客户端ip直接丢弃
continue
}
// packet := gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.Default)
// fmt.Println("get:", packet)
2021-08-02 20:41:35 +08:00
ip_dst := waterutil.IPv4Destination(pl.Data)
2021-06-08 20:45:26 +08:00
// 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)
2021-08-02 20:41:35 +08:00
frame.Prepare(dstHw, cSess.MacHw, ethernet.NotTagged, ethernet.IPv4, len(pl.Data))
copy(frame[12+2:], pl.Data)
2021-06-08 20:45:26 +08:00
}
// 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
}
2021-08-02 20:41:35 +08:00
putByte(fb)
putPayload(pl)
2021-06-08 20:45:26 +08:00
}
}
func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
defer func() {
base.Debug("tapRead return", cSess.IpAddr)
_ = ifce.Close()
}()
var (
err error
n int
2021-08-02 20:41:35 +08:00
data []byte
2021-06-08 20:45:26 +08:00
frame ethernet.Frame
)
for {
// var frame ethernet.Frame
// frame.Resize(BufferSize)
2021-08-02 20:41:35 +08:00
fb := getByteFull()
frame = *fb
2021-06-08 20:45:26 +08:00
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数据
2021-08-02 20:41:35 +08:00
data = frame.Payload()
2021-06-08 20:45:26 +08:00
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)
2021-08-02 20:41:35 +08:00
pl := getPayload()
// 拷贝数据到pl
copy(pl.Data, data)
// 更新切片长度
pl.Data = pl.Data[:len(data)]
if payloadOut(cSess, pl) {
2021-06-08 20:45:26 +08:00
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()}
2021-08-02 20:41:35 +08:00
data, err = arpdis.NewARPReply(src, dst)
2021-06-08 20:45:26 +08:00
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)
2021-08-02 20:41:35 +08:00
pl := getPayload()
// 设置为二层数据类型
pl.LType = sessdata.LTypeEthernet
// 拷贝数据到pl
copy(pl.Data, data)
// 更新切片长度
pl.Data = pl.Data[:len(data)]
if payloadIn(cSess, pl) {
2021-06-08 20:45:26 +08:00
return
}
}
2021-08-02 20:41:35 +08:00
putByte(fb)
2021-06-08 20:45:26 +08:00
}
}