Skip to content

Instantly share code, notes, and snippets.

@warriorpaw
Last active October 30, 2022 10:12
Show Gist options
  • Save warriorpaw/6858526fad5d2fe25a016fda141806a1 to your computer and use it in GitHub Desktop.
Save warriorpaw/6858526fad5d2fe25a016fda141806a1 to your computer and use it in GitHub Desktop.
vxlan package mix up to fool some distributed deep packet inspection ;; Just for fun
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"encoding/binary"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
pseudoRand "math/rand"
"net"
"os"
"os/exec"
"os/signal"
"runtime"
"strconv"
"sync"
"syscall"
"time"
"unsafe"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/songgao/water"
"golang.org/x/net/bpf"
"golang.org/x/net/ipv4"
)
/*
config example
{
"tunnels":[
{
"type":"udp",
"config":"{\"port\":111,\"peer\":{\"ip\":\"1.1.1.1\",\"port\":23}}",
"vxlanId":1,
"remoteId":0
},
{
"type":"tap",
"config":"{\"name\":\"vxlan111\",\"ip\":\"1.1.1.1/24\"}",
"vxlanId":2,
"remoteId":0
},
{
"type":"tun",
"config":"{\"name\":\"vxlan111\",\"ip\":\"1.1.1.1/24\",\"p2p\":\"2.2.2.2/24\"}",
"vxlanId":3,
"remoteId":0
}
],
"transporter":{
"remotes":[
{
"RemoteId":0,
"ipPorts":[
{
"ip":"",
"port":0
},
{
"ip":"",
"port":0
}
]
},
{
"RemoteId":0,
"ipPorts":[
{
"ip":"",
"port":0
},
{
"ip":"",
"port":0
}
]
}
],
"tba-interval": 120,
"port":0,
"listen-ip":"0.0.0.0",
"send-ip":"0,0,0,0",
"send-port-start": 10000,
"send-port-end": 60000,
"key":"",
"outMtu":1450
}
}
*/
func errorPanic(err error, format string, a ...interface{}) {
if err != nil {
fmt.Printf("Panic : "+format, a...)
panic(err)
}
}
func errorPrint(format string, a ...interface{}) {
if a != nil && len(a) > 0 {
fmt.Printf("Error : "+format, a...)
} else {
fmt.Printf("Error : " + format)
}
}
type vxlanHeader struct {
flags uint16
group uint16
vxlanId uint32
}
type IpPort struct {
Ip string `json:"ip"`
Port int `json:"port"`
}
type TunnelConfig struct {
TunnelPeerType string `json:"type"`
TunnelPeerConfig string `json:"config"`
VxlanId uint8 `json:"vxlanId"`
RemoteId int `json:"remoteId"`
}
type RemoteIpPorts struct {
RemoteId int `json:id`
IpPorts []IpPort `json:"ipPorts"`
}
type TransporterConfig struct {
Remotes []RemoteIpPorts `json:"remotes"`
ReceivingPort int `json:"port"`
ListenIp string `json:"listen-ip"`
SendIp string `json:"send-ip"`
SendPortStart uint16 `json:"send-port-start"`
SendPortEnd uint16 `json:"send-port-end"`
Key string `json:"key"`
OutMtu int `json:"outMtu"`
TbaInterval int64 `json:"tba-interval"`
}
type Config struct {
Tunnels []TunnelConfig `json:"tunnels"`
Transporter TransporterConfig `json:"transporter"`
}
func (c *Config) load(f string) {
jsonBytes, err := ioutil.ReadFile(f)
errorPanic(err, "open file %s error %+v \n", f, err)
err = json.Unmarshal(jsonBytes, c)
errorPanic(err, "Unmarshal file %s error %+v \n", f, err)
// no input legality check, just panic in New if config is miss some value.
}
const nonceSize int = 12
const overHeadSize int = 16
const udpIpHeader int = 28
const saltOne string = "YourFirstSalt"
const saltTwo string = "YourSecondSalt"
type TimeBasedAeadCipher struct {
memPool *sync.Pool
hashedKey []byte
interval int64
stopChan chan interface{}
sync.RWMutex
current cipher.AEAD
toleration cipher.AEAD
}
func CountToKey(TOTCount int64, k []byte) []byte {
sig := hmac.New(sha256.New, k)
sig.Write([]byte(strconv.FormatInt(TOTCount, 16)))
salter := sha256.New()
salter.Write(sig.Sum(nil))
salter.Write([]byte(saltTwo))
return salter.Sum(nil)
}
func (c *TimeBasedAeadCipher) getTOTEncryptKey(TOTCount int64) (current []byte, toleration []byte) {
if TOTCount%2 == 0 {
// tolerate delay package
current = CountToKey(TOTCount, c.hashedKey)
toleration = CountToKey(TOTCount-2, c.hashedKey)
} else {
// tolerate future package
current = CountToKey(TOTCount-1, c.hashedKey)
toleration = CountToKey(TOTCount+1, c.hashedKey)
}
return
}
func newAesGcm(key []byte) (ret cipher.AEAD, err error) {
block, err := aes.NewCipher(key)
if err != nil {
return
}
ret, err = cipher.NewGCM(block)
return
}
func (c *TimeBasedAeadCipher) updateCipher(now int64) {
cKey, tKey := c.getTOTEncryptKey(now / c.interval)
cAead, err := newAesGcm(cKey)
errorPanic(err, "newAesGcm error")
tAead, err := newAesGcm(tKey)
errorPanic(err, "newAesGcm error")
c.Lock()
defer c.Unlock()
c.current = cAead
c.toleration = tAead
}
func (c *TimeBasedAeadCipher) nextDuration() (ret time.Duration) {
now := time.Now()
nowSec := now.Unix()
nextTimer := time.Unix(nowSec+c.interval-nowSec%c.interval, 0)
ret = nextTimer.Sub(now)
return
}
func (c *TimeBasedAeadCipher) updateCipherTimer() {
stopChan := c.stopChan
t := time.NewTimer(c.nextDuration())
for {
select {
case <-t.C:
c.updateCipher(time.Now().Unix())
t.Reset(c.nextDuration())
case <-stopChan:
return
}
}
}
func newTimeBasedAead(k string, interval int64, stopChan chan interface{}, p *sync.Pool) *TimeBasedAeadCipher {
ret := TimeBasedAeadCipher{}
ret.memPool = p
ret.stopChan = stopChan
ret.interval = interval / 2
salter := sha256.New()
salter.Write([]byte(k))
salter.Write([]byte(saltOne))
ret.hashedKey = salter.Sum(nil)
ret.updateCipher(time.Now().Unix())
go ret.updateCipherTimer()
return &ret
}
func getNonce(nonce []byte) (err error) {
// TODO: reduce nonce size. since we use TBKey
_, err = io.ReadFull(rand.Reader, nonce)
return
}
func (c *TimeBasedAeadCipher) Encrypt(udpPackage []byte) ([]byte, error) {
// TODO: make nonceSize transparent to the upper layer
plainData := udpPackage[nonceSize:]
if cap(plainData) < len(plainData)+overHeadSize {
errorPrint("udpPackage has no enough cap")
return udpPackage, fmt.Errorf("udpPackage has no enough cap")
}
cipherPackage := c.memPool.Get().([]byte)
cipherData := cipherPackage[nonceSize:]
nonce := cipherPackage[:nonceSize]
getNonce(nonce)
c.RLock()
currentAead := c.current
c.RUnlock()
cipherData = currentAead.Seal(cipherData[:0], nonce, plainData, nil)
c.memPool.Put(udpPackage)
return cipherPackage[:len(cipherData)+nonceSize], nil
}
func (c *TimeBasedAeadCipher) Decrypt(udpPackage []byte) ([]byte, error) {
cipherData := udpPackage[nonceSize:]
nonce := udpPackage[:nonceSize]
decryptedPackage := c.memPool.Get().([]byte)
plainData := decryptedPackage[nonceSize:]
c.RLock()
currentAead := c.current
tolerationAead := c.toleration
c.RUnlock()
var data []byte
var err error
if data, err = currentAead.Open(plainData[:0], nonce, cipherData, nil); err != nil {
if data, err = tolerationAead.Open(plainData[:0], nonce, cipherData, nil); err != nil {
errorPrint("[%s] Decrypt msg error: %v, drop package", time.Now().String(), err)
return udpPackage, err
}
}
c.memPool.Put(udpPackage)
// TODO: make nonceSize transparent to the upper layer
return decryptedPackage[:len(data)+nonceSize], nil
}
type RawUdpConn struct {
c net.PacketConn
srcIp net.IP
}
func NewRawUdpConn(srcIp string, bufferSize int, sendOnly bool) (ret *RawUdpConn, err error) {
conn, err := net.ListenPacket("ip4:udp", srcIp)
if err != nil {
return
}
ipConn := conn.(*net.IPConn)
if sendOnly {
ipConn.SetReadBuffer(0)
} else {
ipConn.SetReadBuffer(bufferSize)
}
ipConn.SetWriteBuffer(bufferSize)
if sendOnly {
filter := []bpf.Instruction{
bpf.RetConstant{Val: 0x0},
}
var assembled []bpf.RawInstruction
if assembled, err = bpf.Assemble(filter); err != nil {
return
}
ipv4.NewPacketConn(conn).SetBPF(assembled)
}
ret = &RawUdpConn{}
ret.c = conn
ret.srcIp = net.ParseIP(srcIp)
return
}
func (r *RawUdpConn) Close() {
if r.c != nil {
r.c.Close()
}
}
func (r *RawUdpConn) Read(buffer []byte) (n int, err error) {
n, _, err = r.c.ReadFrom(buffer)
return
}
func (r *RawUdpConn) Write(srcPort uint16, dstIp net.IP, dstPort uint16, payload []byte) (n int, err error) {
ip := &layers.IPv4{
Version: 4,
TTL: 64,
SrcIP: r.srcIp,
DstIP: dstIp,
Protocol: layers.IPProtocolUDP,
}
udp := &layers.UDP{
SrcPort: layers.UDPPort(srcPort),
DstPort: layers.UDPPort(dstPort),
}
udp.SetNetworkLayerForChecksum(ip)
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
ComputeChecksums: true,
FixLengths: true,
}
err = gopacket.SerializeLayers(buf, opts, udp, gopacket.Payload(payload))
if err != nil {
return
}
n, err = r.c.WriteTo(buf.Bytes(), &net.IPAddr{IP: dstIp, Zone: ""})
return
}
type SendData struct {
data []byte
remoteId int
}
type TunnelChan struct {
recvChan chan []byte
sendChan chan []byte
remoteId int
}
type Transporter struct {
memPool *sync.Pool
sendConn *RawUdpConn
recvConn *net.UDPConn
upRemotes map[int][]*net.UDPAddr
tbAead *TimeBasedAeadCipher
conf *TransporterConfig
TunnelChans []TunnelChan
sendCipherChan chan SendData
sendPlainChan chan SendData
recvCipherChan chan []byte
stopChan chan interface{}
outMtu int
}
func getUdpConn(port int, ip net.IP) (ret *net.UDPConn, err error) {
ret, err = net.ListenUDP("udp", &net.UDPAddr{IP: ip, Port: port})
return
}
func newTransporter(c *Config) *Transporter {
var err error = nil
ret := &Transporter{}
ret.conf = &c.Transporter
ret.memPool = &sync.Pool{New: func() interface{} { return make([]byte, c.Transporter.OutMtu-udpIpHeader) }}
ret.upRemotes = make(map[int][]*net.UDPAddr)
for _, r := range ret.conf.Remotes {
ret.upRemotes[r.RemoteId] = make([]*net.UDPAddr, len(r.IpPorts))
for pos, ipPort := range r.IpPorts {
ret.upRemotes[r.RemoteId][pos] = &net.UDPAddr{IP: net.ParseIP(ipPort.Ip), Port: ipPort.Port}
}
}
ret.recvConn, err = getUdpConn(ret.conf.ReceivingPort, net.ParseIP(ret.conf.ListenIp))
errorPanic(err, "creat Transporter recvConn error \n")
ret.sendConn, err = NewRawUdpConn(ret.conf.SendIp, 20*1024*1024, true)
errorPanic(err, "NewRawUdpConn error \n")
ret.stopChan = make(chan interface{}, 2)
ret.tbAead = newTimeBasedAead(ret.conf.Key, ret.conf.TbaInterval, ret.stopChan, ret.getMemPool())
ret.sendCipherChan = make(chan SendData, 5000)
ret.sendPlainChan = make(chan SendData, 5000)
ret.recvCipherChan = make(chan []byte, 5000)
ret.TunnelChans = make([]TunnelChan, 256)
ret.outMtu = ret.conf.OutMtu
for pos := range c.Tunnels {
vxlanId := c.Tunnels[pos].VxlanId
ret.TunnelChans[vxlanId].recvChan = make(chan []byte, 5000)
ret.TunnelChans[vxlanId].sendChan = make(chan []byte, 5000)
ret.TunnelChans[vxlanId].remoteId = c.Tunnels[pos].RemoteId
if _, ok := ret.upRemotes[c.Tunnels[pos].RemoteId]; !ok {
errorPanic(fmt.Errorf("remote id error"), "remote id error")
}
go ret.handleTunnelChan(vxlanId)
}
go ret.handleSend()
for i := 0; i < runtime.NumCPU(); i++ {
go ret.handleEncrypt()
}
for i := 0; i < runtime.NumCPU(); i++ {
go ret.handleDecrypt()
}
go ret.handleRecv()
return ret
}
func (s *Transporter) handleTunnelChan(vxlanId uint8) {
sendChan := s.TunnelChans[vxlanId].sendChan
stopChan := s.stopChan
sendData := SendData{}
sendData.remoteId = s.TunnelChans[vxlanId].remoteId
sendPlainChan := s.sendPlainChan
outMtu := s.outMtu
for {
select {
case udpPackage, ok := <-sendChan:
if ok == false {
errorPrint("Transporter TunnelChans broken, exit\n")
return
}
n := len(udpPackage)
if (n + overHeadSize + 1) > (outMtu - udpIpHeader) {
errorPrint("package is too large, pls reduce your vxlan mtu\n")
continue
}
if n < (20 + nonceSize) {
errorPrint("package is too small\n")
continue
}
udpPackage = udpPackage[:n+1]
udpPackage[n] = vxlanId
sendData.data = udpPackage
sendPlainChan <- sendData
case <-stopChan:
return
}
}
}
func (s *Transporter) handleSend() {
cipherChan := s.sendCipherChan
portStart := s.conf.SendPortStart
portLen := int(s.conf.SendPortEnd - s.conf.SendPortStart)
remotes := s.upRemotes
stopChan := s.stopChan
sendConn := s.sendConn
for {
select {
case udpPackage, ok := <-cipherChan:
if ok == false {
errorPrint("upLink cipherChan broken, exit\n")
return
}
remote := remotes[udpPackage.remoteId]
srcPort := uint16(pseudoRand.Intn(portLen)) + portStart
remoteAddr := remote[pseudoRand.Intn(len(remote))]
if _, err := sendConn.Write(srcPort, remoteAddr.IP, uint16(remoteAddr.Port), udpPackage.data); err != nil {
errorPrint("up link sendConn.Write error %+v \n", err)
}
s.memPool.Put(udpPackage.data)
case <-stopChan:
return
}
}
}
func (s *Transporter) handleEncrypt() {
plainChan := s.sendPlainChan
cipherChan := s.sendCipherChan
aead := s.tbAead
stopChan := s.stopChan
for {
select {
case udpPackage, ok := <-plainChan:
if ok == false {
errorPrint("upLink plainChan broken, exit\n")
return
}
if cipherData, err := aead.Encrypt(udpPackage.data); err != nil {
errorPrint("Encrypt error, drop package \n")
} else {
udpPackage.data = cipherData
cipherChan <- udpPackage
}
case <-stopChan:
return
}
}
}
func (s *Transporter) handleRecv() {
listenConn := s.recvConn
cipherChan := s.recvCipherChan
outMtu := s.outMtu
for {
data := s.memPool.Get().([]byte)
data = data[:outMtu-udpIpHeader]
n, _, err := listenConn.ReadFromUDP(data)
if err != nil {
errorPrint("error in downLink listenConn.ReadFromUDP %+v \n", err)
return
}
if n < nonceSize+overHeadSize+20+1 {
errorPrint("size error, drop package \n")
continue
}
cipherChan <- data[:n]
}
}
func (s *Transporter) handleDecrypt() {
cipherChan := s.recvCipherChan
aead := s.tbAead
stopChan := s.stopChan
for {
select {
case udpPackage, ok := <-cipherChan:
if ok == false {
errorPrint("upLink plainChan broken\n")
return
}
if plainPackage, err := aead.Decrypt(udpPackage); err != nil {
errorPrint("Encrypt error, drop package \n")
} else {
packageLen := len(plainPackage)
vxlanId := plainPackage[packageLen-1]
if s.TunnelChans[vxlanId].recvChan == nil {
errorPrint("vxlanId is error \n")
} else {
s.TunnelChans[vxlanId].recvChan <- plainPackage[:packageLen-1]
}
}
case <-stopChan:
return
}
}
}
func (s *Transporter) getTunnelChan(vxlanId uint8) *TunnelChan {
return &s.TunnelChans[vxlanId]
}
func (s *Transporter) getMemPool() *sync.Pool {
return s.memPool
}
func (s *Transporter) stop() {
close(s.stopChan)
close(s.sendCipherChan)
close(s.sendPlainChan)
close(s.recvCipherChan)
s.recvConn.Close()
s.sendConn.Close()
for _, c := range s.TunnelChans {
if c.sendChan != nil {
close(c.recvChan)
close(c.sendChan)
}
}
}
type TunnelPeer interface {
recvFrom([]byte) (int, error)
sendTo([]byte) (int, error)
close()
}
type UdpPeerConfig struct {
ListenPort int `json:"port"`
Peer IpPort `json:"peer"`
}
type UdpPeer struct {
listenConn *net.UDPConn
peerAddr *net.UDPAddr
vxlanHeader []byte
config UdpPeerConfig
}
func newUdpPeer(confStr string, vxlanId uint8) TunnelPeer {
ret := &UdpPeer{}
err := json.Unmarshal([]byte(confStr), &ret.config)
errorPanic(err, "Unmarshal newUdpPeer confStr %s error %+v \n", confStr, err)
// make vxlan header
h := &vxlanHeader{flags: 0x0800, group: 0, vxlanId: uint32(vxlanId) * 256}
buf := new(bytes.Buffer)
err = binary.Write(buf, binary.BigEndian, h)
errorPanic(err, "binary.Write error \n")
ret.vxlanHeader = buf.Bytes()
// get port
ret.listenConn, err = getUdpConn(ret.config.ListenPort, net.ParseIP("0.0.0.0"))
errorPanic(err, "creat Tunnel listenConn error \n")
ret.peerAddr = &net.UDPAddr{IP: net.ParseIP(ret.config.Peer.Ip), Port: ret.config.Peer.Port}
return ret
}
func (udp *UdpPeer) recvFrom(data []byte) (int, error) {
n, _, err := udp.listenConn.ReadFromUDP(data)
return n, err
}
func (udp *UdpPeer) sendTo(data []byte) (int, error) {
copy(data[nonceSize-8:nonceSize], udp.vxlanHeader)
return udp.listenConn.WriteToUDP(data[nonceSize-8:], udp.peerAddr)
}
func (udp *UdpPeer) close() {
udp.listenConn.Close()
}
type TapPeerConfig struct {
TapName string `json:"name"`
TapIp string `json:"ip"`
P2PIp string `json:"p2p"`
}
type TapPeer struct {
tapIF *water.Interface
config TapPeerConfig
}
type ifReqMtu struct {
Name [0x10]byte
Mtu int32
pad [0x28 - 0x10 - 4]byte
}
func newTapPeer(confStr string, outMtu int, isTap bool) TunnelPeer {
ret := &TapPeer{}
err := json.Unmarshal([]byte(confStr), &ret.config)
errorPanic(err, "Unmarshal newTapPeer confStr %s error %+v \n", confStr, err)
// new tap
tapConfig := water.Config{}
mtuReduce := 0
if !isTap {
tapConfig.DeviceType = water.TUN
mtuReduce = udpIpHeader + nonceSize + overHeadSize + 1
} else {
tapConfig.DeviceType = water.TAP
mtuReduce = udpIpHeader + 14 + nonceSize + overHeadSize + 1
}
tapConfig.Name = ret.config.TapName
ret.tapIF, err = water.New(tapConfig)
errorPanic(err, "water.New if error")
// set mtu
var req ifReqMtu
req.Mtu = int32(outMtu - mtuReduce)
copy(req.Name[:], []byte(ret.config.TapName))
tmpUdp, err := getUdpConn(0, net.ParseIP("0.0.0.0"))
errorPanic(err, "error in get udp")
defer tmpUdp.Close()
fileUdp, _ := tmpUdp.File()
fd := fileUdp.Fd()
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.SIOCSIFMTU), uintptr(unsafe.Pointer(&req)))
if errno != 0 {
fmt.Printf("SIOCSIFMTU syscall return %d\n", errno)
panic(fmt.Errorf("SIOCSIFMTU syscall return %d\n", errno))
}
// set ip on tap
cmd := exec.Command("ip", "addr", "add", ret.config.TapIp, "dev", ret.config.TapName)
err = cmd.Run()
errorPanic(err, "set ip error %+v \n", err)
if !isTap {
// set p2p ip
if len(ret.config.P2PIp) == 0 {
errorPanic(fmt.Errorf("tun dev need p2p ip"), "tun dev need p2p ip")
}
cmd := exec.Command("ifconfig", ret.config.TapName, "pointopoint", ret.config.P2PIp)
err = cmd.Run()
errorPanic(err, "set p2p ip error %+v \n", err)
}
// set tap up
cmd = exec.Command("ip", "link", "set", ret.config.TapName, "up")
err = cmd.Run()
errorPanic(err, "set link up error %+v \n", err)
return ret
}
func (tap *TapPeer) recvFrom(data []byte) (int, error) {
n, err := tap.tapIF.Read(data[nonceSize:])
if err != nil {
errorPrint("error in handleSend tapIF.Read %+v \n", err)
return n, err
}
return n + nonceSize, err
}
func (tap *TapPeer) sendTo(data []byte) (int, error) {
n := len(data)
sendBytes, err := tap.tapIF.Write(data[nonceSize:])
if sendBytes != (n-nonceSize) || err != nil {
errorPrint("tapIF.Write err %d -> %d, %+v \n", n, sendBytes, err)
return sendBytes, err
}
return n, err
}
func (tap *TapPeer) close() {
tap.tapIF.Close()
}
type Tunnel struct {
memPool *sync.Pool
peer TunnelPeer
tunnelChan *TunnelChan
conf *TunnelConfig
outMtu int
stopChan chan interface{}
}
func newTunnel(c *TunnelConfig, tunnelChan *TunnelChan, p *sync.Pool, outMtu int) *Tunnel {
ret := &Tunnel{}
ret.tunnelChan = tunnelChan
ret.conf = c
ret.memPool = p
ret.outMtu = outMtu
switch c.TunnelPeerType {
case "udp":
ret.peer = newUdpPeer(c.TunnelPeerConfig, c.VxlanId)
case "tap":
ret.peer = newTapPeer(c.TunnelPeerConfig, outMtu, true)
case "tun":
ret.peer = newTapPeer(c.TunnelPeerConfig, outMtu, false)
default:
panic(fmt.Errorf("newTunnel unknow type %s\n", c.TunnelPeerType))
}
ret.stopChan = make(chan interface{}, 2)
go ret.handleSendToPeer()
go ret.handleListen()
return ret
}
func (s *Tunnel) handleSendToPeer() {
plainChan := s.tunnelChan.recvChan
stopChan := s.stopChan
peer := s.peer
for {
select {
case udpPackage, ok := <-plainChan:
if ok == false {
errorPrint("Tunnel plainChan broken \n")
return
}
if _, err := peer.sendTo(udpPackage); err != nil {
errorPrint("Tunnel peer.sendTo error %+v \n", err)
}
s.memPool.Put(udpPackage)
case <-stopChan:
return
}
}
}
func (s *Tunnel) handleListen() {
peer := s.peer
sendChan := s.tunnelChan.sendChan
outMtu := s.outMtu
for {
data := s.memPool.Get().([]byte)
data = data[:outMtu-udpIpHeader]
n, err := peer.recvFrom(data)
if err != nil {
errorPrint("error in Tunnel peer.recvFrom %+v \n", err)
return
}
sendChan <- data[:n]
}
}
func (s *Tunnel) stop() {
close(s.stopChan)
s.peer.close()
}
func main() {
configPath := ""
flag.StringVar(&configPath, "c", "./conf.json", "config file path")
flag.Parse()
pseudoRand.Seed(time.Now().Unix())
c := &Config{}
c.load(configPath)
transporter := newTransporter(c)
tunnels := make([]*Tunnel, len(c.Tunnels))
for pos := range c.Tunnels {
tunnels[pos] = newTunnel(&c.Tunnels[pos], transporter.getTunnelChan(c.Tunnels[pos].VxlanId), transporter.getMemPool(), c.Transporter.OutMtu)
}
signalChan := make(chan os.Signal, 2)
signal.Notify(signalChan, os.Interrupt)
<-signalChan
transporter.stop()
for _, tunnel := range tunnels {
tunnel.stop()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment