mirror of https://github.com/bjdgyc/anylink.git
278 lines
6.0 KiB
Go
278 lines
6.0 KiB
Go
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
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|