dockerfiles/anylink/server/handler/link_tap.go

278 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"
"io"
"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 (
// 网关mac地址
gatewayHw net.HardwareAddr
)
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)
}
var ifIp net.IP
addrs, err := iFace.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
}
ifIp = ip
}
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{
DeviceType: water.TAP,
}
ifce, err := water.New(cfg)
if err != nil {
base.Error(err)
return err
}
cSess.SetIfName(ifce.Name())
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 allTapRead(ifce, cSess)
go allTapWrite(ifce, cSess)
return nil
}
// ========================通用代码===========================
func allTapWrite(ifce LinkDriver, cSess *sessdata.ConnSession) {
defer func() {
base.Debug("LinkTap return", cSess.IpAddr)
cSess.Close()
ifce.Close()
}()
var (
err error
dstHw net.HardwareAddr
pl *sessdata.Payload
frame = make(ethernet.Frame, BufferSize)
ipDst = net.IPv4(1, 2, 3, 4)
)
for {
frame.Resize(BufferSize)
select {
case pl = <-cSess.PayloadIn:
case <-cSess.CloseChan:
return
}
// var frame ethernet.Frame
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 数据
ipSrc := waterutil.IPv4Source(pl.Data)
if !ipSrc.Equal(cSess.IpAddr) {
// 非分配给客户端ip直接丢弃
continue
}
if waterutil.IsIPv6(pl.Data) {
// 过滤掉IPv6的数据
continue
}
// packet := gopacket.NewPacket(pl.Data, layers.LayerTypeIPv4, gopacket.Default)
// fmt.Println("get:", packet)
// 手动设置ipv4地址
ipDst[12] = pl.Data[16]
ipDst[13] = pl.Data[17]
ipDst[14] = pl.Data[18]
ipDst[15] = pl.Data[19]
dstHw = gatewayHw
if sessdata.IpPool.Ipv4IPNet.Contains(ipDst) {
dstAddr := arpdis.Lookup(ipDst, true)
// fmt.Println("dstAddr", dstAddr)
if dstAddr != nil {
dstHw = 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)
}
// 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
}
putPayloadInBefore(cSess, pl)
}
}
func allTapRead(ifce LinkDriver, cSess *sessdata.ConnSession) {
defer func() {
base.Debug("tapRead return", cSess.IpAddr)
ifce.Close()
}()
var (
err error
n int
data []byte
frame = make(ethernet.Frame, BufferSize)
)
for {
frame.Resize(BufferSize)
n, err = ifce.Read(frame)
if err != nil {
base.Error("tap Read err", n, err)
return
}
frame = frame[:n]
switch frame.Ethertype() {
default:
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.NoCopy)
layer := packet.Layer(layers.LayerTypeARP)
arpReq := layer.(*layers.ARP)
if !cSess.IpAddr.Equal(arpReq.DstProtAddress) {
// 过滤非本机地址
continue
}
// 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: arpReq.SourceHwAddress}
data, err = arpdis.NewARPReply(src, dst)
if err != nil {
base.Error(err)
return
}
// 从接受的arp信息添加arp地址
addr := &arpdis.Addr{
IP: append([]byte{}, dst.IP...),
HardwareAddr: append([]byte{}, dst.HardwareAddr...),
}
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
}
}
}
}