mirror of https://github.com/bjdgyc/anylink.git
255 lines
5.8 KiB
Go
255 lines
5.8 KiB
Go
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
|
||
payload *sessdata.Payload
|
||
frame ethernet.Frame
|
||
)
|
||
|
||
for {
|
||
select {
|
||
case payload = <-cSess.PayloadIn:
|
||
case <-cSess.CloseChan:
|
||
return
|
||
}
|
||
|
||
// var frame ethernet.Frame
|
||
fb := getByteFull()
|
||
frame = *fb
|
||
switch payload.LType {
|
||
default:
|
||
// log.Println(payload)
|
||
case sessdata.LTypeEthernet:
|
||
copy(frame, payload.Data)
|
||
frame = frame[:len(payload.Data)]
|
||
case sessdata.LTypeIPData: // 需要转换成 Ethernet 数据
|
||
data := payload.Data
|
||
|
||
ip_src := waterutil.IPv4Source(data)
|
||
if waterutil.IsIPv6(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(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(data))
|
||
copy(frame[12+2:], 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(payload)
|
||
}
|
||
}
|
||
|
||
func tapRead(ifce *water.Interface, cSess *sessdata.ConnSession) {
|
||
defer func() {
|
||
base.Debug("tapRead return", cSess.IpAddr)
|
||
_ = ifce.Close()
|
||
}()
|
||
|
||
var (
|
||
err error
|
||
n int
|
||
buf []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)
|
||
|
||
if payloadOut(cSess, sessdata.LTypeIPData, 0x00, data) {
|
||
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()}
|
||
buf, 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)
|
||
|
||
if payloadIn(cSess, sessdata.LTypeEthernet, 0x00, buf) {
|
||
return
|
||
}
|
||
|
||
}
|
||
|
||
putByte(fb)
|
||
}
|
||
}
|