Files
netstack/cmd/netstack/main.go

200 lines
4.6 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 main
import (
"flag"
"fmt"
"log"
"net"
"netstack/logger"
"netstack/tcpip"
"netstack/tcpip/header"
"netstack/tcpip/link/fdbased"
"netstack/tcpip/link/loopback"
"netstack/tcpip/link/tuntap"
"netstack/tcpip/network/arp"
"netstack/tcpip/network/ipv4"
"netstack/tcpip/network/ipv6"
"netstack/tcpip/stack"
"netstack/tcpip/transport/tcp"
"netstack/tcpip/transport/udp"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
)
var mac = flag.String("mac", "aa:00:01:01:01:01", "mac address to use in tap device")
func main() {
flag.Parse()
if len(flag.Args()) != 4 {
log.Fatal("Usage: ", os.Args[0], " <tap-device> <local-address/mask> <ip-address> <local-port>")
}
logger.SetFlags(logger.HANDSHAKE)
log.SetFlags(log.Lshortfile | log.LstdFlags)
tapName := flag.Arg(0)
cidrName := flag.Arg(1)
addrName := flag.Arg(2)
portName := flag.Arg(3)
log.Printf("tap: %v, addr: %v, port: %v", tapName, addrName, portName)
maddr, err := net.ParseMAC(*mac)
if err != nil {
log.Fatalf("Bad MAC address: %v", *mac)
}
parsedAddr := net.ParseIP(addrName)
if err != nil {
log.Fatalf("Bad addrress: %v", addrName)
}
// 解析地址ip地址ipv4或者ipv6地址都支持
var addr tcpip.Address
var proto tcpip.NetworkProtocolNumber
if parsedAddr.To4() != nil {
addr = tcpip.Address(parsedAddr.To4())
proto = ipv4.ProtocolNumber
} else if parsedAddr.To16() != nil {
addr = tcpip.Address(parsedAddr.To16())
proto = ipv6.ProtocolNumber
} else {
log.Fatalf("Unknown IP type: %v", parsedAddr)
}
localPort, err := strconv.Atoi(portName)
if err != nil {
log.Fatalf("Unable to convert port %v: %v", portName, err)
}
// 虚拟网卡配置
conf := &tuntap.Config{
Name: tapName,
Mode: tuntap.TAP,
}
var fd int
// 新建虚拟网卡
fd, err = tuntap.NewNetDev(conf)
if err != nil {
log.Fatal(err)
}
// 启动tap网卡
_ = tuntap.SetLinkUp(tapName)
// 设置路由
_ = tuntap.SetRoute(tapName, cidrName)
// 抽象的文件接口
linkID := fdbased.New(&fdbased.Options{
FD: fd,
MTU: 1500,
Address: tcpip.LinkAddress(maddr),
ResolutionRequired: true,
})
_ = linkID
loopbackLinkID := loopback.New()
// 新建相关协议的协议栈
s := stack.New([]string{ipv4.ProtocolName, arp.ProtocolName},
[]string{tcp.ProtocolName, udp.ProtocolName}, stack.Options{})
// 新建抽象的网卡
if err := s.CreateNamedNIC(1, "vnic1", loopbackLinkID); err != nil {
log.Fatal(err)
}
// 在该协议栈上添加和注册相应的网络层
if err := s.AddAddress(1, proto, addr); err != nil {
log.Fatal(err)
}
// 在该协议栈上添加和注册ARP协议
if err := s.AddAddress(1, arp.ProtocolNumber, arp.ProtocolAddress); err != nil {
log.Fatal(err)
}
// 添加默认路由
s.SetRouteTable([]tcpip.Route{
{
Destination: tcpip.Address(strings.Repeat("\x00", len(addr))),
Mask: tcpip.AddressMask(strings.Repeat("\x00", len(addr))),
Gateway: "",
NIC: 1,
},
})
done := make(chan struct{}, 2)
//logger.SetFlags(logger.TCP)
go func() { // echo server
listener := tcpListen(s, proto, addr, localPort)
done <- struct{}{}
for {
conn, err := listener.Accept()
if err != nil {
log.Println(err)
}
log.Println("服务端 建立连接")
go func() {
time.Sleep(3 * time.Second)
for {
time.Sleep(50 * time.Millisecond)
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
log.Println(err)
break
}
fmt.Println("data: ", n, len(buf), string(buf))
// conn.Write([]byte("Server echo"))
//}
}
}()
}
}()
<-done
go func() {
port := localPort
conn, err := Dial(s, header.IPv4ProtocolNumber, addr, port)
if err != nil {
log.Fatal(err)
}
log.Printf("客户端 建立连接\n")
conn.SetSockOpt(tcpip.KeepaliveEnabledOption(1))
conn.SetSockOpt(tcpip.KeepaliveIntervalOption(75 * time.Second))
conn.SetSockOpt(tcpip.KeepaliveIdleOption(30 * time.Second)) // 30s的探活心跳
conn.SetSockOpt(tcpip.KeepaliveCountOption(9))
time.Sleep(time.Second)
log.Printf("\n\n客户端 写入数据")
buf := make([]byte, 1<<20)
conn.Write(buf)
time.Sleep(5 * time.Second)
buf = make([]byte, 1<<22)
conn.Write(buf)
time.Sleep(500 * time.Minute)
conn.Close()
}()
close(done)
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGUSR1, syscall.SIGUSR2)
<-c
}