anylink/handler/link_tap.go

273 lines
6.1 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"
"log"
"net"
"github.com/bjdgyc/anylink/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"
func checkTap() {
brFace, err := net.InterfaceByName(bridgeName)
if err != nil {
log.Fatal("testTap err: ", err)
}
bridgeHw := brFace.HardwareAddr
var bridgeIp net.IP
addrs, err := brFace.Addrs()
for _, addr := range addrs {
ip, _, err := net.ParseCIDR(addr.String())
if err != nil || ip.To4() == nil {
continue
}
bridgeIp = ip
}
if bridgeIp == nil && bridgeHw == nil {
log.Fatalln("bridgeIp is err")
}
if !sessdata.IpPool.Ipv4IPNet.Contains(bridgeIp) {
log.Fatalln("bridgeIp or Ip network err")
}
// 设置本机ip arp为静态
addr := &arpdis.Addr{IP: bridgeIp.To4(), HardwareAddr: bridgeHw, Type: arpdis.TypeStatic}
arpdis.Add(addr)
}
// 创建tap网卡
func LinkTap(sess *sessdata.ConnSession) {
defer func() {
log.Println("LinkTap return")
sess.Close()
}()
cfg := water.Config{
DeviceType: water.TAP,
}
ifce, err := water.New(cfg)
if err != nil {
log.Println(err)
return
}
sess.TunName = ifce.Name()
defer ifce.Close()
// arp on
cmdstr1 := fmt.Sprintf("ip link set dev %s up mtu %d multicast on", ifce.Name(), sess.Mtu)
cmdstr2 := fmt.Sprintf("sysctl -w net.ipv6.conf.%s.disable_ipv6=1", ifce.Name())
cmdstr3 := fmt.Sprintf("ip link set dev %s master %s", ifce.Name(), bridgeName)
cmdStrs := []string{cmdstr1, cmdstr2, cmdstr3}
err = execCmd(cmdStrs)
if err != nil {
return
}
// TODO 测试
// sess.MacHw, _ = net.ParseMAC("3c:8c:40:a0:6a:3d")
go loopArp(sess)
go tapRead(ifce, sess)
var (
payload *sessdata.Payload
)
for {
select {
case payload = <-sess.PayloadIn:
case <-sess.CloseChan:
return
}
var frame ethernet.Frame
switch payload.LType {
default:
log.Println(payload)
case sessdata.LTypeEthernet:
frame = payload.Data
case sessdata.LTypeIPData: // 需要转换成 Ethernet 数据
data := payload.Data
ip_src := waterutil.IPv4Source(data)
if waterutil.IsIPv6(data) || !ip_src.Equal(sess.Ip) {
// 过滤掉IPv6的数据
// 非分配给客户端ip直接丢弃
continue
}
ip_dst := waterutil.IPv4Destination(data)
// fmt.Println("get:", ip_src, ip_dst)
var dstAddr *arpdis.Addr
if !sessdata.IpPool.Ipv4IPNet.Contains(ip_dst) || ip_dst.Equal(sessdata.IpPool.Ipv4Gateway) {
// 不是同一网段使用网关mac地址
ip_dst = sessdata.IpPool.Ipv4Gateway
dstAddr = arpdis.Lookup(ip_dst, false)
if dstAddr == nil {
log.Println("Ipv4Gateway mac err", ip_dst)
return
}
// fmt.Println("Gateway", ip_dst, dstAddr.HardwareAddr)
} else {
// 同一网段内的其他主机
dstAddr = arpdis.Lookup(ip_dst, true)
// fmt.Println("other", ip_src, ip_dst, dstAddr)
if dstAddr == nil || dstAddr.Type == arpdis.TypeUnreachable {
// 异步检测发送数据包
select {
case sess.PayloadArp <- payload:
case <-sess.CloseChan:
return
default:
// PayloadArp 容量已经满了
log.Println("PayloadArp is full", sess.Ip, ip_dst)
}
continue
}
}
frame.Prepare(dstAddr.HardwareAddr, sess.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 {
log.Println("tap Write err", err)
return
}
}
}
// 异步处理获取ip对应的mac地址的数据
func loopArp(sess *sessdata.ConnSession) {
defer func() {
log.Println("loopArp return")
}()
var (
payload *sessdata.Payload
dstAddr *arpdis.Addr
ip_dst net.IP
)
for {
select {
case payload = <-sess.PayloadArp:
case <-sess.CloseChan:
return
}
ip_dst = waterutil.IPv4Destination(payload.Data)
dstAddr = arpdis.Lookup(ip_dst, false)
// 不可达数据包
if dstAddr == nil || dstAddr.Type == arpdis.TypeUnreachable {
// 直接丢弃数据
// fmt.Println("Lookup", ip_dst)
continue
}
// 正常获取mac地址
if payloadInData(sess, payload) {
return
}
}
}
func tapRead(ifce *water.Interface, sess *sessdata.ConnSession) {
defer func() {
log.Println("tapRead return")
ifce.Close()
}()
var (
err error
n int
buf []byte
)
fmt.Println(sess.MacHw)
for {
var frame ethernet.Frame
frame.Resize(BufferSize)
n, err = ifce.Read(frame)
if err != nil {
log.Println("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(sess.Ip) {
// 过滤非本机地址
// log.Println(ip_dst, sess.Ip)
continue
}
if payloadOut(sess, sessdata.LTypeIPData, 0x00, data) {
return
}
case ethernet.ARP:
// 暂时仅实现了ARP协议
packet := gopacket.NewPacket(frame, layers.LayerTypeEthernet, gopacket.NoCopy)
layer := packet.Layer(layers.LayerTypeARP)
arpReq := layer.(*layers.ARP)
// fmt.Println("arp", net.IP(arpReq.SourceProtAddress), sess.Ip)
if !sess.Ip.Equal(arpReq.DstProtAddress) {
// 过滤非本机地址
continue
}
// fmt.Println("arp", arpReq.SourceProtAddress, sess.Ip)
// fmt.Println(packet)
// 返回ARP数据
src := &arpdis.Addr{IP: sess.Ip, HardwareAddr: sess.MacHw}
dst := &arpdis.Addr{IP: arpReq.SourceProtAddress, HardwareAddr: frame.Source()}
buf, err = arpdis.NewARPReply(src, dst)
if err != nil {
log.Println(err)
return
}
// 从接受的arp信息添加arp地址
addr := &arpdis.Addr{}
copy(addr.IP, arpReq.SourceProtAddress)
copy(addr.HardwareAddr, frame.Source())
arpdis.Add(addr)
if payloadIn(sess, sessdata.LTypeEthernet, 0x00, buf) {
return
}
}
}
}