1.add tcp kill/mon functions 2.support win 7 again 3.fix tcp keepalive period too fast on windows 4.other bug fix
parent
8845d35339
commit
5b0b3834bb
@ -0,0 +1,16 @@
|
||||
//go:build windows && arm64
|
||||
|
||||
package tcm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var Cmd = &cobra.Command{
|
||||
Use: "tcm",
|
||||
Short: "TCP连接监视工具",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("windows on arm is not supported yet")
|
||||
},
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
//go:build windows && arm64
|
||||
|
||||
package tcpkill
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var Cmd = &cobra.Command{
|
||||
Use: "tcpkill",
|
||||
Short: "杀掉那个TCP连接",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("windows on arm is not supported yet")
|
||||
},
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
//go:build !(windows && arm64)
|
||||
|
||||
package tcpkill
|
||||
|
||||
import (
|
||||
"b612.me/bcap"
|
||||
"b612.me/starlog"
|
||||
"context"
|
||||
"fmt"
|
||||
netm "github.com/shirou/gopsutil/v4/net"
|
||||
"net"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func (t *TCPKill) PreRun() error {
|
||||
if t.cap == nil {
|
||||
t.cap = bcap.NewPackets()
|
||||
t.ctx, t.stopFn = context.WithCancel(context.Background())
|
||||
}
|
||||
t.requests = make(chan *handler, 1024)
|
||||
if t.KillType == "" {
|
||||
t.KillType = "both"
|
||||
}
|
||||
conns, err := netm.Connections("tcp")
|
||||
if err != nil {
|
||||
starlog.Errorf("Failed to get system connections:%v\n", err)
|
||||
return err
|
||||
}
|
||||
starlog.Infof("Got %d connections\n", len(conns))
|
||||
for _, conn := range conns {
|
||||
//fmt.Printf("Connection: %v => %v PID=%v Status=%v\n", conn.Laddr, conn.Raddr, conn.Pid, conn.Status)
|
||||
if t.Match(conn) {
|
||||
fmt.Printf("Matched connection: %v:%v => %v:%v PID=%v Status=%v\n", conn.Laddr.IP, conn.Laddr.Port, conn.Raddr.IP, conn.Raddr.Port, conn.Pid, conn.Status)
|
||||
t.matchConns.Store(key(conn), conn)
|
||||
t.matchCount++
|
||||
}
|
||||
}
|
||||
if t.matchCount == 0 && !t.WaitMode {
|
||||
starlog.Warningln("No matched connection")
|
||||
return fmt.Errorf("No matched connection")
|
||||
}
|
||||
starlog.Infof("Matched %d connections\n", t.matchCount)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TCPKill) Match(info netm.ConnectionStat) bool {
|
||||
if info.Status != "PCAP" {
|
||||
if t.Status != "" && t.Status != info.Status {
|
||||
return false
|
||||
}
|
||||
if info.Status == "DELETE" || info.Status == "CLOSED" || info.Status == "LISTEN" {
|
||||
return false
|
||||
}
|
||||
if runtime.GOOS == "windows" && info.Status == "TIME_WAIT" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if _, ok := t.matchConns.Load(key(info)); ok {
|
||||
return true
|
||||
}
|
||||
if t.SrcIP == "" && t.SrcPort == 0 && t.DstIP == "" && t.DstPort == 0 {
|
||||
if t.Status != "" && info.Status != "PCAP" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
innerCheck := func(srcIP string, srcPort int, conns netm.Addr) bool {
|
||||
sIp := net.ParseIP(srcIP)
|
||||
if sIp == nil {
|
||||
return false
|
||||
}
|
||||
lAddr := net.ParseIP(conns.IP)
|
||||
if lAddr != nil {
|
||||
if sIp.To16() != nil && lAddr.To16() != nil && !lAddr.To16().Equal(sIp.To16()) {
|
||||
return false
|
||||
}
|
||||
if sIp.To4() != nil && lAddr.To4() != nil && !lAddr.To4().Equal(sIp.To4()) {
|
||||
return false
|
||||
}
|
||||
if (sIp.To4() != nil && lAddr.To4() == nil) || (sIp.To4() == nil && lAddr.To4() != nil) {
|
||||
return false
|
||||
}
|
||||
if srcPort != 0 && uint32(srcPort) != conns.Port {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
if t.SrcIP != "" {
|
||||
if !innerCheck(t.SrcIP, t.SrcPort, info.Laddr) {
|
||||
return false
|
||||
}
|
||||
} else if t.SrcPort != 0 && t.SrcPort != int(info.Laddr.Port) {
|
||||
return false
|
||||
}
|
||||
if t.DstIP != "" {
|
||||
if !innerCheck(t.DstIP, t.DstPort, info.Raddr) {
|
||||
return false
|
||||
}
|
||||
} else if t.DstPort != 0 && t.DstPort != int(info.Raddr.Port) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func key(i netm.ConnectionStat) string {
|
||||
return fmt.Sprintf("tcp://%v:%v-%v:%v", i.Laddr.IP, i.Laddr.Port, i.Raddr.IP, i.Raddr.Port)
|
||||
}
|
@ -0,0 +1,372 @@
|
||||
//go:build !windows
|
||||
|
||||
package tcpkill
|
||||
|
||||
import (
|
||||
"b612.me/bcap"
|
||||
"b612.me/bcap/nfq"
|
||||
"b612.me/starlog"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/florianl/go-nfqueue/v2"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
netm "github.com/shirou/gopsutil/v4/net"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TCPKill struct {
|
||||
NFQNums int
|
||||
AutoIptables bool
|
||||
SrcIP string
|
||||
SrcPort int
|
||||
DstIP string
|
||||
DstPort int
|
||||
Status string
|
||||
KillType string
|
||||
RstNumbers int
|
||||
WaitMode bool
|
||||
matchConns sync.Map
|
||||
matchCount uint
|
||||
sync.Mutex
|
||||
cache []string
|
||||
cap *bcap.Packets
|
||||
ctx context.Context
|
||||
stopFn context.CancelFunc
|
||||
requests chan *handler
|
||||
BPF string
|
||||
Eth string
|
||||
Host string
|
||||
}
|
||||
|
||||
func (t *TCPKill) doIptables() error {
|
||||
if t.SrcPort != 0 {
|
||||
if _, err := exec.Command("iptables", "-t", "raw", "-A", "PREROUTING", "-p", "tcp", "--dport", strconv.Itoa(t.SrcPort), "-j", "NFQUEUE", "--queue-num", strconv.Itoa(t.NFQNums)).CombinedOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
t.cache = append(t.cache, "-t raw -D PREROUTING -p tcp --dport "+strconv.Itoa(t.SrcPort)+" -j NFQUEUE --queue-num "+strconv.Itoa(t.NFQNums))
|
||||
if _, err := exec.Command("iptables", "-t", "raw", "-A", "OUTPUT", "-p", "tcp", "--sport", strconv.Itoa(t.SrcPort), "-j", "NFQUEUE", "--queue-num", strconv.Itoa(t.NFQNums)).CombinedOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
t.cache = append(t.cache, "-t raw -D OUTPUT -p tcp --sport "+strconv.Itoa(t.SrcPort)+" -j NFQUEUE --queue-num "+strconv.Itoa(t.NFQNums))
|
||||
return nil
|
||||
}
|
||||
if t.DstPort != 0 {
|
||||
if _, err := exec.Command("iptables", "-t", "raw", "-A", "PREROUTING", "-p", "tcp", "--sport", strconv.Itoa(t.DstPort), "-j", "NFQUEUE", "--queue-num", strconv.Itoa(t.NFQNums)).CombinedOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
t.cache = append(t.cache, "-t raw -D PREROUTING -p tcp --sport "+strconv.Itoa(t.DstPort)+" -j NFQUEUE --queue-num "+strconv.Itoa(t.NFQNums))
|
||||
if _, err := exec.Command("iptables", "-t", "raw", "-A", "OUTPUT", "-p", "tcp", "--dport", strconv.Itoa(t.DstPort), "-j", "NFQUEUE", "--queue-num", strconv.Itoa(t.NFQNums)).CombinedOutput(); err != nil {
|
||||
return err
|
||||
}
|
||||
t.cache = append(t.cache, "-t raw -D OUTPUT -p tcp --dport "+strconv.Itoa(t.DstPort)+" -j NFQUEUE --queue-num "+strconv.Itoa(t.NFQNums))
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("No src or dst port detect,it is too dangerous to set iptables automatically without port,please operate manually")
|
||||
}
|
||||
|
||||
func (t *TCPKill) undoIptables() {
|
||||
for _, cmd := range t.cache {
|
||||
exec.Command("iptables", strings.Fields(cmd)...).CombinedOutput()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TCPKill) Run() error {
|
||||
if err := t.PreRun(); err != nil {
|
||||
return err
|
||||
}
|
||||
stopSignal := make(chan os.Signal)
|
||||
starlog.Noticef("Starting nfqueue capture\n")
|
||||
nf := nfq.NewNfQueue(t.ctx, uint16(t.NFQNums), 65535)
|
||||
nf.SetRecall(t.handleRoute)
|
||||
go func() {
|
||||
if err := nf.Run(); err != nil {
|
||||
starlog.Errorln(err)
|
||||
stopSignal <- syscall.SIGKILL
|
||||
}
|
||||
}()
|
||||
if t.AutoIptables {
|
||||
if _, err := exec.Command("iptables", "-V").CombinedOutput(); err != nil {
|
||||
starlog.Warningln("iptables not found, cannot auto set iptables")
|
||||
return fmt.Errorf("iptables not found")
|
||||
}
|
||||
defer t.undoIptables()
|
||||
if err := t.doIptables(); err != nil {
|
||||
starlog.Errorf("Failed to set iptables:%v\n", err)
|
||||
return err
|
||||
}
|
||||
starlog.Infof("Set iptables success\n")
|
||||
}
|
||||
signal.Notify(stopSignal, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
|
||||
go t.SynSent()
|
||||
go t.handleNfResult()
|
||||
select {
|
||||
//todo need nf.Stop()
|
||||
case <-stopSignal:
|
||||
starlog.Warningf("Received stop signal\n")
|
||||
|
||||
case <-t.ctx.Done():
|
||||
starlog.Infoln("TCPKILL Task Finished")
|
||||
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (t *TCPKill) handleNfResult() {
|
||||
for {
|
||||
select {
|
||||
case <-t.ctx.Done():
|
||||
return
|
||||
case info := <-t.requests:
|
||||
if info == nil {
|
||||
continue
|
||||
}
|
||||
info.p.SetVerdict(info.id, <-info.fin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TCPKill) handleRoute(id uint32, q *nfqueue.Nfqueue, p nfq.Packet) {
|
||||
if t.requests == nil {
|
||||
q.SetVerdict(id, nfqueue.NfAccept)
|
||||
return
|
||||
}
|
||||
info, err := t.cap.ParsePacket(p.Packet)
|
||||
if err != nil {
|
||||
q.SetVerdict(id, nfqueue.NfAccept)
|
||||
return
|
||||
}
|
||||
fin := make(chan int)
|
||||
t.requests <- &handler{
|
||||
id: id,
|
||||
p: q,
|
||||
packet: p.Packet,
|
||||
attr: p.Attr,
|
||||
fin: fin,
|
||||
}
|
||||
go func() {
|
||||
fin <- t.handlePacket(info, p)
|
||||
}()
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
id uint32
|
||||
p *nfqueue.Nfqueue
|
||||
packet gopacket.Packet
|
||||
attr nfqueue.Attribute
|
||||
fin chan int
|
||||
}
|
||||
|
||||
func (t *TCPKill) handlePacket(info bcap.PacketInfo, p nfq.Packet) int {
|
||||
if p.Packet == nil {
|
||||
return nfqueue.NfAccept
|
||||
}
|
||||
tcpLayer := p.Packet.Layer(layers.LayerTypeTCP)
|
||||
if tcpLayer == nil {
|
||||
return nfqueue.NfAccept
|
||||
}
|
||||
tcp := tcpLayer.(*layers.TCP)
|
||||
if tcp.SYN && !tcp.ACK {
|
||||
//starlog.Debugf("SYN packet:%v\n", p.Packet)
|
||||
return nfqueue.NfAccept
|
||||
}
|
||||
if tcp.RST {
|
||||
starlog.Warningf("RST packet:%v <==> %v\n", info.SrcIP+":"+info.SrcPort, info.DstIP+":"+info.DstPort)
|
||||
return nfqueue.NfAccept
|
||||
}
|
||||
if !t.Match(netm.ConnectionStat{
|
||||
Status: "PCAP",
|
||||
Laddr: netm.Addr{
|
||||
IP: info.SrcIP,
|
||||
Port: uint32(tcp.SrcPort),
|
||||
},
|
||||
Raddr: netm.Addr{
|
||||
IP: info.DstIP,
|
||||
Port: uint32(tcp.DstPort),
|
||||
},
|
||||
}) && !t.Match(netm.ConnectionStat{
|
||||
Status: "PCAP",
|
||||
Raddr: netm.Addr{
|
||||
IP: info.SrcIP,
|
||||
Port: uint32(tcp.SrcPort),
|
||||
},
|
||||
Laddr: netm.Addr{
|
||||
IP: info.DstIP,
|
||||
Port: uint32(tcp.DstPort),
|
||||
},
|
||||
}) {
|
||||
return nfqueue.NfAccept
|
||||
}
|
||||
RealSendRST(info, t.KillType, t.RstNumbers)
|
||||
return nfqueue.NfAccept
|
||||
}
|
||||
|
||||
func (t *TCPKill) SynSent() {
|
||||
for {
|
||||
time.Sleep(time.Millisecond * 2500)
|
||||
realConns, err := netm.Connections("tcp")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
t.matchConns.Range(func(key, value any) bool {
|
||||
t.matchConns.Delete(key)
|
||||
t.matchCount--
|
||||
return true
|
||||
})
|
||||
for _, conn := range realConns {
|
||||
if t.Match(conn) {
|
||||
t.matchConns.Store(key(conn), conn)
|
||||
t.matchCount++
|
||||
}
|
||||
}
|
||||
if t.matchCount == 0 && !t.WaitMode {
|
||||
starlog.Warningln("No matched connection anymore")
|
||||
t.stopFn()
|
||||
return
|
||||
}
|
||||
t.matchConns.Range(func(k, v any) bool {
|
||||
conn := v.(netm.ConnectionStat)
|
||||
if err := SendSYN(conn.Laddr.IP, strconv.Itoa(int(conn.Laddr.Port)), conn.Raddr.IP, strconv.Itoa(int(conn.Raddr.Port)), 1127); err != nil {
|
||||
starlog.Errorf("Failed to send SYN:%v\n", err)
|
||||
}
|
||||
if err := SendSYN(conn.Raddr.IP, strconv.Itoa(int(conn.Raddr.Port)), conn.Laddr.IP, strconv.Itoa(int(conn.Laddr.Port)), 1127); err != nil {
|
||||
starlog.Errorf("Failed to send SYN:%v\n", err)
|
||||
}
|
||||
starlog.Infof("Send SYN to %v <==> %v\n", conn.Laddr.String(), conn.Raddr.String())
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func RealSendRST(info bcap.PacketInfo, target string, number int) {
|
||||
for i := 0; i < number; i++ {
|
||||
if target == "both" || target == "target" {
|
||||
seq := uint32(info.TcpPayloads()) + info.TcpSeq() + (uint32(i) * uint32(info.TcpWindow()))
|
||||
SendRST(info.SrcIP, info.SrcPort, info.DstIP, info.DstPort, seq)
|
||||
}
|
||||
if target == "both" || target == "reverse" {
|
||||
SendRST(info.DstIP, info.DstPort, info.SrcIP, info.SrcPort, info.TcpAck()+(uint32(i)*uint32(info.TcpWindow())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SendRST(srcIP, srcPort, dstIP, dstPort string, seq uint32) error {
|
||||
if net.ParseIP(dstIP).To4() != nil {
|
||||
return sendIPv4(srcIP, srcPort, dstIP, dstPort, seq, false)
|
||||
}
|
||||
return sendIPv6(srcIP, srcPort, dstIP, dstPort, seq, false)
|
||||
}
|
||||
|
||||
func SendSYN(srcIP, srcPort, dstIP, dstPort string, seq uint32) error {
|
||||
if net.ParseIP(dstIP).To4() != nil {
|
||||
return sendIPv4(srcIP, srcPort, dstIP, dstPort, seq, true)
|
||||
}
|
||||
return sendIPv6(srcIP, srcPort, dstIP, dstPort, seq, true)
|
||||
}
|
||||
|
||||
func sendIPv4(srcIP, srcPort, dstIP, dstPort string, seq uint32, isSyn bool) error {
|
||||
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.Close(fd)
|
||||
|
||||
dstNetIP := net.ParseIP(dstIP)
|
||||
iPv4 := layers.IPv4{
|
||||
SrcIP: net.ParseIP(srcIP),
|
||||
DstIP: dstNetIP,
|
||||
Version: 4,
|
||||
TTL: 64,
|
||||
Protocol: layers.IPProtocolTCP,
|
||||
}
|
||||
sPort, err := strconv.Atoi(srcPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dPort, err := strconv.Atoi(dstPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tcp := layers.TCP{
|
||||
SrcPort: layers.TCPPort(sPort),
|
||||
DstPort: layers.TCPPort(dPort),
|
||||
Seq: seq,
|
||||
RST: !isSyn,
|
||||
SYN: isSyn,
|
||||
}
|
||||
|
||||
if err = tcp.SetNetworkLayerForChecksum(&iPv4); err != nil {
|
||||
return err
|
||||
}
|
||||
buffer := gopacket.NewSerializeBuffer()
|
||||
options := gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
if err = gopacket.SerializeLayers(buffer, options, &iPv4, &tcp); err != nil {
|
||||
return err
|
||||
}
|
||||
addr := syscall.SockaddrInet4{
|
||||
Port: dPort,
|
||||
Addr: [4]byte{dstNetIP.To4()[0], dstNetIP.To4()[1], dstNetIP.To4()[2], dstNetIP.To4()[3]},
|
||||
}
|
||||
return syscall.Sendto(fd, buffer.Bytes(), 0, &addr)
|
||||
}
|
||||
|
||||
func sendIPv6(srcIP, srcPort, dstIP, dstPort string, seq uint32, isSyn bool) error {
|
||||
fd, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer syscall.Close(fd)
|
||||
|
||||
dstNetIP := net.ParseIP(dstIP)
|
||||
iPv6 := layers.IPv6{
|
||||
SrcIP: net.ParseIP(srcIP),
|
||||
DstIP: dstNetIP,
|
||||
Version: 6,
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
HopLimit: 64,
|
||||
}
|
||||
sPort, err := strconv.Atoi(srcPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dPort, err := strconv.Atoi(dstPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tcp := layers.TCP{
|
||||
SrcPort: layers.TCPPort(sPort),
|
||||
DstPort: layers.TCPPort(dPort),
|
||||
Seq: seq,
|
||||
RST: !isSyn,
|
||||
SYN: isSyn,
|
||||
}
|
||||
|
||||
if err := tcp.SetNetworkLayerForChecksum(&iPv6); err != nil {
|
||||
return err
|
||||
}
|
||||
buffer := gopacket.NewSerializeBuffer()
|
||||
options := gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
if err = gopacket.SerializeLayers(buffer, options, &iPv6, &tcp); err != nil {
|
||||
return err
|
||||
}
|
||||
addr := syscall.SockaddrInet6{
|
||||
Port: dPort,
|
||||
Addr: [16]byte(dstNetIP.To16()),
|
||||
}
|
||||
return syscall.Sendto(fd, buffer.Bytes(), 0, &addr)
|
||||
}
|
@ -0,0 +1,390 @@
|
||||
//go:build windows && (amd64 || 386)
|
||||
|
||||
package tcpkill
|
||||
|
||||
import (
|
||||
"b612.me/bcap"
|
||||
"b612.me/bcap/libpcap"
|
||||
"b612.me/starlog"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/google/gopacket/pcap"
|
||||
netm "github.com/shirou/gopsutil/v4/net"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TCPKill struct {
|
||||
NFQNums int
|
||||
AutoIptables bool
|
||||
BPF string
|
||||
Eth string
|
||||
Host string
|
||||
SrcIP string
|
||||
SrcPort int
|
||||
DstIP string
|
||||
DstPort int
|
||||
KillType string
|
||||
RstNumbers int
|
||||
WaitMode bool
|
||||
Status string
|
||||
matchConns sync.Map
|
||||
matchCount uint
|
||||
sync.Mutex
|
||||
cache []string
|
||||
cap *bcap.Packets
|
||||
ctx context.Context
|
||||
stopFn context.CancelFunc
|
||||
requests chan *handler
|
||||
pc *libpcap.NetCatch
|
||||
macCache map[string]net.HardwareAddr
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
}
|
||||
|
||||
func (t *TCPKill) presetWindows() {
|
||||
t.macCache = make(map[string]net.HardwareAddr)
|
||||
if t.BPF == "" {
|
||||
if t.DstIP != "" {
|
||||
t.BPF = fmt.Sprintf("tcp and host %s", t.DstIP)
|
||||
} else if t.SrcIP != "" {
|
||||
t.BPF = fmt.Sprintf("tcp and host %s", t.SrcIP)
|
||||
} else if t.SrcPort != 0 {
|
||||
t.BPF = fmt.Sprintf("tcp and port %d", t.SrcPort)
|
||||
} else if t.DstPort != 0 {
|
||||
t.BPF = fmt.Sprintf("tcp and port %d", t.DstPort)
|
||||
} else {
|
||||
t.BPF = "tcp"
|
||||
}
|
||||
}
|
||||
if t.Eth == "" && t.Host == "" {
|
||||
allDevice, err := pcap.FindAllDevs()
|
||||
if err != nil {
|
||||
starlog.Errorf("get pcap devices failed:%v\n", err)
|
||||
return
|
||||
}
|
||||
if t.SrcIP == "" {
|
||||
defer func() {
|
||||
t.SrcIP = ""
|
||||
}()
|
||||
ip := t.DstIP
|
||||
if ip == "" {
|
||||
ip = "223.6.6.6"
|
||||
}
|
||||
if strings.Contains(ip, ":") {
|
||||
ip = "[" + ip + "]"
|
||||
}
|
||||
l, err := net.Dial("udp", ip+":53")
|
||||
if err == nil {
|
||||
t.SrcIP = l.LocalAddr().(*net.UDPAddr).IP.String()
|
||||
starlog.Infof("No eth or ip detected,use %s as source ip\n", t.SrcIP)
|
||||
l.Close()
|
||||
} else {
|
||||
starlog.Errorf("Failed to get source ip:%v\n", err)
|
||||
}
|
||||
}
|
||||
for _, v := range allDevice {
|
||||
if t.SrcIP == "127.0.0.1" && v.Name == "\\Device\\NPF_Loopback" {
|
||||
t.Eth = v.Name
|
||||
return
|
||||
}
|
||||
for _, addr := range v.Addresses {
|
||||
if addr.IP.String() == t.SrcIP {
|
||||
t.Eth = v.Name
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TCPKill) Run() error {
|
||||
var err error
|
||||
if err = t.PreRun(); err != nil {
|
||||
return err
|
||||
}
|
||||
t.presetWindows()
|
||||
stopSignal := make(chan os.Signal)
|
||||
starlog.Noticef("Starting capture\n")
|
||||
signal.Notify(stopSignal, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL)
|
||||
if t.Eth != "" {
|
||||
t.pc, err = libpcap.NewCatchEth(t.Eth, t.BPF)
|
||||
if err != nil {
|
||||
starlog.Errorf("Failed to create pcap handle:%v\n", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if t.Host != "" {
|
||||
t.pc, err = libpcap.NewCatch(t.Host, t.BPF)
|
||||
if err != nil {
|
||||
starlog.Errorf("Failed to create pcap handle:%v\n", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if t.pc == nil {
|
||||
starlog.Errorf("No pcap handle\n")
|
||||
return fmt.Errorf("No pcap handle")
|
||||
}
|
||||
t.pc.SetRecall(t.handlePacket)
|
||||
go func() {
|
||||
if err := t.pc.Run(); err != nil {
|
||||
starlog.Errorln(err)
|
||||
stopSignal <- syscall.SIGKILL
|
||||
}
|
||||
}()
|
||||
go t.SynSent()
|
||||
select {
|
||||
//todo need nf.Stop()
|
||||
case <-stopSignal:
|
||||
starlog.Warningf("Received stop signal\n")
|
||||
|
||||
case <-t.ctx.Done():
|
||||
starlog.Infoln("TCPKILL Task Finished")
|
||||
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (t *TCPKill) SynSent() {
|
||||
for {
|
||||
time.Sleep(time.Millisecond * 2500)
|
||||
realConns, err := netm.Connections("tcp")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
t.matchConns.Range(func(key, value any) bool {
|
||||
t.matchConns.Delete(key)
|
||||
t.matchCount--
|
||||
return true
|
||||
})
|
||||
for _, conn := range realConns {
|
||||
if t.Match(conn) {
|
||||
t.matchConns.Store(key(conn), conn)
|
||||
t.matchCount++
|
||||
}
|
||||
}
|
||||
if t.matchCount == 0 && !t.WaitMode {
|
||||
starlog.Warningln("No matched connection anymore")
|
||||
t.stopFn()
|
||||
return
|
||||
}
|
||||
t.matchConns.Range(func(k, v any) bool {
|
||||
conn := v.(netm.ConnectionStat)
|
||||
if t.macCache[conn.Laddr.IP] == nil || t.macCache[conn.Raddr.IP] == nil {
|
||||
target := conn.Raddr.IP + ":" + strconv.Itoa(int(conn.Raddr.Port))
|
||||
if strings.Contains(conn.Raddr.IP, ":") {
|
||||
target = "[" + conn.Raddr.IP + "]:" + strconv.Itoa(int(conn.Raddr.Port))
|
||||
}
|
||||
starlog.Warningf("No mac address for %v or %v,try send syn to %v\n", conn.Laddr.IP, conn.Raddr.IP, target)
|
||||
tcpConn, err := net.DialTimeout("tcp", target, time.Millisecond*800)
|
||||
if err == nil {
|
||||
tcpConn.(*net.TCPConn).SetLinger(0)
|
||||
tcpConn.Close()
|
||||
}
|
||||
time.Sleep(time.Millisecond * 600)
|
||||
}
|
||||
t.Lock()
|
||||
if err := SendSYN(t.pc.Handle, t.macCache[conn.Laddr.IP], t.macCache[conn.Raddr.IP], conn.Laddr.IP, strconv.Itoa(int(conn.Laddr.Port)), conn.Raddr.IP, strconv.Itoa(int(conn.Raddr.Port)), 1127); err != nil {
|
||||
starlog.Errorf("Failed to send SYN:%v\n", err)
|
||||
}
|
||||
if err := SendSYN(t.pc.Handle, t.macCache[conn.Raddr.IP], t.macCache[conn.Laddr.IP], conn.Raddr.IP, strconv.Itoa(int(conn.Raddr.Port)), conn.Laddr.IP, strconv.Itoa(int(conn.Laddr.Port)), 1127); err != nil {
|
||||
starlog.Errorf("Failed to send SYN:%v\n", err)
|
||||
}
|
||||
t.Unlock()
|
||||
starlog.Infof("Send SYN to %v <==> %v\n", conn.Laddr.String(), conn.Raddr.String())
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TCPKill) handlePacket(p gopacket.Packet) {
|
||||
t.Lock()
|
||||
info, err := t.cap.ParsePacket(p)
|
||||
t.Unlock()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tcpLayer := p.Layer(layers.LayerTypeTCP)
|
||||
if tcpLayer == nil {
|
||||
return
|
||||
}
|
||||
tcp := tcpLayer.(*layers.TCP)
|
||||
if tcp.SYN && !tcp.ACK {
|
||||
return
|
||||
}
|
||||
t.Lock()
|
||||
//fmt.Println(info.SrcIP, hex.EncodeToString(info.SrcMac), info.DstIP, hex.EncodeToString(info.DstMac))
|
||||
t.macCache[info.SrcIP] = info.SrcMac
|
||||
t.macCache[info.DstIP] = info.DstMac
|
||||
t.Unlock()
|
||||
if tcp.RST {
|
||||
starlog.Warningf("RST packet:%v <==> %v\n", info.SrcIP+":"+info.SrcPort, info.DstIP+":"+info.DstPort)
|
||||
return
|
||||
}
|
||||
//starlog.Debugf("packet:%v <==> %v\n", info.SrcIP+":"+info.SrcPort, info.DstIP+":"+info.DstPort)
|
||||
if !t.Match(netm.ConnectionStat{
|
||||
Status: "PCAP",
|
||||
Laddr: netm.Addr{
|
||||
IP: info.SrcIP,
|
||||
Port: uint32(tcp.SrcPort),
|
||||
},
|
||||
Raddr: netm.Addr{
|
||||
IP: info.DstIP,
|
||||
Port: uint32(tcp.DstPort),
|
||||
},
|
||||
}) && !t.Match(netm.ConnectionStat{
|
||||
Status: "PCAP",
|
||||
Raddr: netm.Addr{
|
||||
IP: info.SrcIP,
|
||||
Port: uint32(tcp.SrcPort),
|
||||
},
|
||||
Laddr: netm.Addr{
|
||||
IP: info.DstIP,
|
||||
Port: uint32(tcp.DstPort),
|
||||
},
|
||||
}) {
|
||||
return
|
||||
}
|
||||
starlog.Noticef("Sending RST... %v:%v <==> %v:%v SEQ=%d ACK=%d\n", info.SrcIP, info.SrcPort, info.DstIP, info.DstPort, info.TcpSeq(), info.TcpAck())
|
||||
RealSendRST(t.pc.Handle, info, t.KillType, t.RstNumbers)
|
||||
}
|
||||
|
||||
func RealSendRST(p *pcap.Handle, info bcap.PacketInfo, target string, number int) {
|
||||
for i := 0; i < number; i++ {
|
||||
if target == "both" || target == "target" {
|
||||
seq := uint32(info.TcpPayloads()) + info.TcpSeq() + (uint32(i) * uint32(info.TcpWindow()))
|
||||
SendRST(p, info.SrcMac, info.DstMac, info.SrcIP, info.SrcPort, info.DstIP, info.DstPort, seq)
|
||||
//SendRST(p, info.DstMac, info.SrcMac, info.SrcIP, info.SrcPort, info.DstIP, info.DstPort, info.TcpSeq()+(uint32(i)*uint32(info.TcpWindow())))
|
||||
|
||||
}
|
||||
if target == "both" || target == "reverse" {
|
||||
SendRST(p, info.DstMac, info.SrcMac, info.DstIP, info.DstPort, info.SrcIP, info.SrcPort, info.TcpAck()+(uint32(i)*uint32(info.TcpWindow())))
|
||||
//SendRST(p, info.SrcMac, info.DstMac, info.DstIP, info.DstPort, info.SrcIP, info.SrcPort, info.TcpAck()+(uint32(i)*uint32(info.TcpWindow())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SendRST(p *pcap.Handle, srcMac, dstMac []byte, srcIP, srcPort, dstIP, dstPort string, seq uint32) error {
|
||||
if net.ParseIP(dstIP).To4() != nil {
|
||||
return sendIPv4(p, srcMac, dstMac, srcIP, srcPort, dstIP, dstPort, seq, false)
|
||||
}
|
||||
return sendIPv6(p, srcMac, dstMac, srcIP, srcPort, dstIP, dstPort, seq, false)
|
||||
}
|
||||
|
||||
func SendSYN(p *pcap.Handle, srcMac, dstMac []byte, srcIP, srcPort, dstIP, dstPort string, seq uint32) error {
|
||||
if net.ParseIP(dstIP).To4() != nil {
|
||||
return sendIPv4(p, srcMac, dstMac, srcIP, srcPort, dstIP, dstPort, seq, true)
|
||||
}
|
||||
return sendIPv6(p, srcMac, dstMac, srcIP, srcPort, dstIP, dstPort, seq, true)
|
||||
}
|
||||
|
||||
func sendIPv4(p *pcap.Handle, srcMac, dstMac []byte, srcIP, srcPort, dstIP, dstPort string, seq uint32, isSyn bool) error {
|
||||
|
||||
dstNetIP := net.ParseIP(dstIP)
|
||||
eth := layers.Ethernet{
|
||||
SrcMAC: srcMac,
|
||||
DstMAC: dstMac,
|
||||
EthernetType: layers.EthernetTypeIPv4,
|
||||
}
|
||||
iPv4 := layers.IPv4{
|
||||
SrcIP: net.ParseIP(srcIP),
|
||||
DstIP: dstNetIP,
|
||||
Version: 4,
|
||||
TTL: 64,
|
||||
Protocol: layers.IPProtocolTCP,
|
||||
}
|
||||
sPort, err := strconv.Atoi(srcPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dPort, err := strconv.Atoi(dstPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tcp := layers.TCP{
|
||||
SrcPort: layers.TCPPort(sPort),
|
||||
DstPort: layers.TCPPort(dPort),
|
||||
Seq: seq,
|
||||
RST: !isSyn,
|
||||
SYN: isSyn,
|
||||
}
|
||||
|
||||
if err = tcp.SetNetworkLayerForChecksum(&iPv4); err != nil {
|
||||
return err
|
||||
}
|
||||
buffer := gopacket.NewSerializeBuffer()
|
||||
options := gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
if srcMac == nil && dstMac == nil {
|
||||
if err = gopacket.SerializeLayers(buffer, options, &iPv4, &tcp); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err = gopacket.SerializeLayers(buffer, options, ð, &iPv4, &tcp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return p.WritePacketData(buffer.Bytes())
|
||||
}
|
||||
|
||||
func sendIPv6(p *pcap.Handle, srcMac, dstMac []byte, srcIP, srcPort, dstIP, dstPort string, seq uint32, isSyn bool) error {
|
||||
dstNetIP := net.ParseIP(dstIP)
|
||||
eth := layers.Ethernet{
|
||||
SrcMAC: srcMac,
|
||||
DstMAC: dstMac,
|
||||
EthernetType: layers.EthernetTypeIPv6,
|
||||
}
|
||||
iPv6 := layers.IPv6{
|
||||
SrcIP: net.ParseIP(srcIP),
|
||||
DstIP: dstNetIP,
|
||||
Version: 6,
|
||||
NextHeader: layers.IPProtocolTCP,
|
||||
HopLimit: 64,
|
||||
}
|
||||
sPort, err := strconv.Atoi(srcPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dPort, err := strconv.Atoi(dstPort)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tcp := layers.TCP{
|
||||
SrcPort: layers.TCPPort(sPort),
|
||||
DstPort: layers.TCPPort(dPort),
|
||||
Seq: seq,
|
||||
RST: !isSyn,
|
||||
SYN: isSyn,
|
||||
}
|
||||
if err := tcp.SetNetworkLayerForChecksum(&iPv6); err != nil {
|
||||
return err
|
||||
}
|
||||
buffer := gopacket.NewSerializeBuffer()
|
||||
options := gopacket.SerializeOptions{
|
||||
FixLengths: true,
|
||||
ComputeChecksums: true,
|
||||
}
|
||||
if srcMac == nil && dstMac == nil {
|
||||
if err = gopacket.SerializeLayers(buffer, options, &iPv6, &tcp); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err = gopacket.SerializeLayers(buffer, options, ð, &iPv6, &tcp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return p.WritePacketData(buffer.Bytes())
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
package version
|
||||
|
||||
var Version = "2.1.0.beta.15"
|
Loading…
Reference in New Issue