From 32c6e7b534f529e651eedfa72e34a0788b2e6ce7 Mon Sep 17 00:00:00 2001 From: starainrt Date: Tue, 31 Dec 2024 10:21:15 +0800 Subject: [PATCH] update image and tcp --- go.mod | 4 +- go.sum | 13 +- image/image.go | 190 +++++++++++++++++++++++++- mget/cmd.go | 8 +- mget/redo.go | 7 +- mget/wget.go | 27 +++- tcm/cmd_unix.go | 7 +- tcm/cmd_windows.go | 2 + tcm/tcpmonitor_unix.go | 277 +++++++++++++++++++++++++++++++------- tcm/tcpmonitor_windows.go | 158 +++++++++++++++++++--- version/version.go | 2 +- 11 files changed, 601 insertions(+), 94 deletions(-) diff --git a/go.mod b/go.mod index f553e5b..c7351c3 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,12 @@ go 1.20 require ( b612.me/bcap v0.0.4 - b612.me/notify v1.2.6 + b612.me/notify v0.0.0-20240818092352-85803f75dfa0 b612.me/sdk/whois v0.0.0-20240816133027-129514a15991 b612.me/starcrypto v0.0.5 b612.me/stario v0.0.10 b612.me/starlog v1.3.4 - b612.me/starmap v1.2.4 + b612.me/starmap v0.0.0-20240818092703-ae61140c5062 b612.me/starnet v0.2.1 b612.me/staros v1.1.8 b612.me/starssh v0.0.2 diff --git a/go.sum b/go.sum index 518664c..63c47a6 100644 --- a/go.sum +++ b/go.sum @@ -1,21 +1,18 @@ b612.me/bcap v0.0.4 h1:iY2Oz+uyG/mue6a/dJiU82ci5Xwkj4xHhre/q0O8G60= b612.me/bcap v0.0.4/go.mod h1:tpus+4iMpsnxb98Pck70s87Zt4sIWuRZjK23MmmzmoY= -b612.me/notify v1.2.5/go.mod h1:GTnAdC6v9krGxtC8Gkn8TcyUsYnHSiHjRAXsONPiLpI= -b612.me/notify v1.2.6 h1:fY+0ccP6cJCDvnfRilmPlDK+J8xTYBpYNwf7jaC2IIE= -b612.me/notify v1.2.6/go.mod h1:awcFq3bvbkf3hdviUtOW16Io0IEJXkNPgno7IRe7B9g= +b612.me/notify v0.0.0-20240818092352-85803f75dfa0 h1:PaLuNLMM0HBM7qPdk4igtNvqT2CDgdm52sL+KA9I3so= +b612.me/notify v0.0.0-20240818092352-85803f75dfa0/go.mod h1:YyaYF4jj5ygIC/QbCMyhBWnsmmTL8kVs6UlHMGVKiY8= b612.me/sdk/whois v0.0.0-20240816133027-129514a15991 h1:+eXeVqkoi4s9sNoY9eGt4ieSbr1+Deos8fC8wMfOCNI= b612.me/sdk/whois v0.0.0-20240816133027-129514a15991/go.mod h1:PB9QpUoQEip0MB3st8H5hmnDTcDsR0RGV0BfpUr5XDg= -b612.me/starcrypto v0.0.3/go.mod h1:pF5A16p8r/h1G0x7ZNmmAF6K1sdIMpbCUxn2WGC8gZ0= b612.me/starcrypto v0.0.5 h1:Aa4pRDO2lBH2Aw+vz8NuUtRb73J8z5aOa9SImBY5sq4= b612.me/starcrypto v0.0.5/go.mod h1:pF5A16p8r/h1G0x7ZNmmAF6K1sdIMpbCUxn2WGC8gZ0= -b612.me/stario v0.0.9/go.mod h1:x4D/x8zA5SC0pj/uJAi4FyG5p4j5UZoMEZfvuRR6VNw= +b612.me/stario v0.0.0-20240818091810-d528a583f4b2/go.mod h1:1Owmu9jzKWgs4VsmeI8YWlGwLrCwPNM/bYpxkyn+MMk= b612.me/stario v0.0.10 h1:+cIyiDCBCjUfodMJDp4FLs+2E1jo7YENkN+sMEe6550= b612.me/stario v0.0.10/go.mod h1:1Owmu9jzKWgs4VsmeI8YWlGwLrCwPNM/bYpxkyn+MMk= b612.me/starlog v1.3.4 h1:XuVYo6NCij8F4TGSgtEuMhs1WkZ7HZNnYUgQ3nLTt84= b612.me/starlog v1.3.4/go.mod h1:37GMgkWQMOAjzKs49Hf2i8bLwdXbd9QF4zKhUxFDoSk= -b612.me/starmap v1.2.4 h1:gfAyBtzW3KKCIyI14I2pEqGsR/u2E+3tkH0xRqtWb4E= -b612.me/starmap v1.2.4/go.mod h1:EhOUzkItc5IcyBmr1C7/vmZBbW3GgCWs63hGn7WhuMc= -b612.me/starnet v0.1.8/go.mod h1:k862Kf8DiVWTqdX6PHTFb6NoT+3G3Y74n8NCyNhuP0Y= +b612.me/starmap v0.0.0-20240818092703-ae61140c5062 h1:ImKEWAxzBYsS/YbqdVOPdUdv6b+i/lSGpipUGueXk7w= +b612.me/starmap v0.0.0-20240818092703-ae61140c5062/go.mod h1:PhtO9wFrwPIHpry2CEdnVNZkrNOgfv77xrE0ZKQDkLM= b612.me/starnet v0.2.1 h1:17n3wa2QgBYbO1rqDLAhyc2DfvbBc23GSp1v42Pvmiw= b612.me/starnet v0.2.1/go.mod h1:6q+AXhYeXsIiKV+hZZmqAMn8S48QcdonURJyH66rbzI= b612.me/staros v1.1.8 h1:5Bpuf9q2nH75S2ekmieJuH3Y8LTqg/voxXCOiMAC3kk= diff --git a/image/image.go b/image/image.go index ab1aca0..cc20399 100644 --- a/image/image.go +++ b/image/image.go @@ -1,15 +1,31 @@ package image import ( + "encoding/hex" "fmt" "image" + "image/color" + "sort" "b612.me/starlog" "github.com/spf13/cobra" ) +var useHex bool +var useAlpha bool +var useCount int +var ckt uint8 +var fromRgb string +var toRgb string + func init() { - Cmd.AddCommand(imgMirrorCmd) + Cmd.AddCommand(imgMirrorCmd, imgRgbCountCmd, imgReplaceCmd, imgReverseCmd) + imgRgbCountCmd.Flags().BoolVarP(&useHex, "hex", "x", false, "使用十六进制表示") + imgRgbCountCmd.Flags().BoolVarP(&useAlpha, "alpha", "a", false, "统计alpha通道") + imgRgbCountCmd.Flags().IntVarP(&useCount, "count", "c", 10, "显示数量") + imgReplaceCmd.Flags().Uint8VarP(&ckt, "ckt", "k", 30, "颜色比较阈值") + imgReplaceCmd.Flags().StringVarP(&fromRgb, "from", "f", "dfdfdf", "需要替换的颜色") + imgReplaceCmd.Flags().StringVarP(&toRgb, "to", "t", "ffffff", "替换为的颜色") } var Cmd = &cobra.Command{ @@ -80,3 +96,175 @@ var imgAlpha = &cobra.Command{ fmt.Println("任务完成!") }, } + +var imgRgbCountCmd = &cobra.Command{ + Use: "rgbcount", + Short: "统计最多的rgb值", + Long: "统计最多的RGB值", + Run: func(this *cobra.Command, args []string) { + if len(args) == 0 { + starlog.Errorln("请指定需要统计的图像!") + return + } + for _, v := range args { + img, err := OpenImage(v) + if err != nil { + starlog.Errorln(err, v) + continue + } + size := img.Bounds() + colorMap := make(map[string]int) + for x := 0; x < size.Dx(); x++ { + for y := 0; y < size.Dy(); y++ { + color := img.At(x, y) + r, g, b, a := color.RGBA() + var key string + if useAlpha { + if !useHex { + key = fmt.Sprintf("%d,%d,%d,%d", uint8(r>>8), uint8(g>>8), uint8(b>>8), uint8(a>>8)) + } else { + key = fmt.Sprintf("%x%x%x%x", uint8(r>>8), uint8(g>>8), uint8(b>>8), uint8(a>>8)) + } + } else { + if !useHex { + key = fmt.Sprintf("%d,%d,%d", uint8(r>>8), uint8(g>>8), uint8(b>>8)) + } else { + key = fmt.Sprintf("%x%x%x", uint8(r>>8), uint8(g>>8), uint8(b>>8)) + } + } + if _, ok := colorMap[key]; ok { + colorMap[key]++ + } else { + colorMap[key] = 1 + } + } + } + colorSlice := make([]struct { + string + int + }, 0, len(colorMap)) + for k, v := range colorMap { + colorSlice = append(colorSlice, struct { + string + int + }{k, v}) + } + sort.Slice(colorSlice, func(i, j int) bool { + return colorSlice[i].int > colorSlice[j].int + }) + fmt.Println(v) + for i := 0; i < useCount && i < len(colorSlice); i++ { + fmt.Printf("%d. %s: %d\n", i+1, colorSlice[i].string, colorSlice[i].int) + } + fmt.Println("----------------") + } + fmt.Println("任务完成!") + }, +} + +var imgReplaceCmd = &cobra.Command{ + Use: "replace", + Short: "图像RGB替换", + Long: "图像RGB替换", + Run: func(this *cobra.Command, args []string) { + if len(args) == 0 { + starlog.Errorln("请指定需要转换的图像!") + return + } + r, g, b, err := HexToRGB(fromRgb) + if err != nil { + starlog.Errorln(err) + return + } + nr, ng, nb, err := HexToRGB(toRgb) + if err != nil { + starlog.Errorln(err) + return + } + for _, v := range args { + img, err := OpenImage(v) + if err != nil { + starlog.Errorln(err, v) + continue + } + size := img.Bounds() + nimg := image.NewRGBA(size) + for x := 0; x < size.Dx(); x++ { + for y := 0; y < size.Dy(); y++ { + mR, mG, mB, ma := img.At(x, y).RGBA() + mr, mg, mb := uint8(mR>>8), uint8(mG>>8), uint8(mB>>8) + nimg.Set(x, y, img.At(x, y)) + if mr-r < ckt || r-mr < ckt { + if mg-g < ckt || g-mg < ckt { + if mb-b < ckt || b-mb < ckt { + nimg.Set(x, y, color.NRGBA{nr, ng, nb, uint8(ma >> 8)}) + } + } + } + } + } + if err := SavePhoto("new-"+v, nimg); err != nil { + starlog.Errorln(err, v) + continue + } else { + fmt.Println(v, "转换已完成!") + } + } + fmt.Println("任务完成!") + }, +} + +func HexToRGB(hexStr string) (uint8, uint8, uint8, error) { + // 检查输入长度是否为6 + if len(hexStr) != 6 { + return 0, 0, 0, fmt.Errorf("invalid hex color string: %s", hexStr) + } + + // 将16进制字符串解码为字节数组 + decoded, err := hex.DecodeString(hexStr) + if err != nil { + return 0, 0, 0, fmt.Errorf("failed to decode hex string: %v", err) + } + + // 解码结果应该有3个字节 + if len(decoded) != 3 { + return 0, 0, 0, fmt.Errorf("invalid hex color format: %s", hexStr) + } + + // 返回三个通道值 + return decoded[0], decoded[1], decoded[2], nil +} + +var imgReverseCmd = &cobra.Command{ + Use: "reverse", + Short: "图像反色", + Long: "图像反色", + Run: func(this *cobra.Command, args []string) { + if len(args) == 0 { + starlog.Errorln("请指定需要转换的图像!") + return + } + for _, v := range args { + img, err := OpenImage(v) + if err != nil { + starlog.Errorln(err, v) + continue + } + size := img.Bounds() + nimg := image.NewRGBA(size) + for x := 0; x < size.Dx(); x++ { + for y := 0; y < size.Dy(); y++ { + r, g, b, a := img.At(x, y).RGBA() + nimg.Set(x, y, color.NRGBA{uint8(255 - r>>8), uint8(255 - g>>8), uint8(255 - b>>8), uint8(a >> 8)}) + } + } + if err := SavePhoto("reverse-"+v, nimg); err != nil { + starlog.Errorln(err, v) + continue + } else { + fmt.Println(v, "转换已完成!") + } + } + fmt.Println("任务完成!") + }, +} diff --git a/mget/cmd.go b/mget/cmd.go index 045ea22..c9e1f07 100644 --- a/mget/cmd.go +++ b/mget/cmd.go @@ -34,7 +34,9 @@ func init() { Cmd.Flags().StringVarP(&mg.Tareget, "output", "o", "", "输出文件名") Cmd.Flags().IntVarP(&mg.BufferSize, "buffer", "b", 8192, "缓冲区大小") Cmd.Flags().IntVarP(&mg.Thread, "thread", "t", 8, "线程数") - Cmd.Flags().IntVarP(&mg.RedoRPO, "safe", "s", 1048576, "安全校验点") + Cmd.Flags().BoolVarP(&mg.NoWriteRedo, "no-redo", "N", false, "不写入redo文件") + Cmd.Flags().IntVarP(&mg.RedoRPO, "safe", "s", 0, "安全校验点,0意味自动调整") + Cmd.Flags().IntVarP(&mg.RedoMinSaveSec, "redo-min-sec", "m", 2, "redo文件最短写入间隔(秒)") Cmd.Flags().StringSliceVarP(&headers, "header", "H", []string{}, "自定义请求头,格式: key=value") Cmd.Flags().StringVarP(&proxy, "proxy", "P", "", "代理地址") Cmd.Flags().StringVarP(&ua, "user-agent", "U", "", "自定义User-Agent") @@ -140,7 +142,9 @@ func Run(cmd *cobra.Command, args []string) { starlog.Infoln("User Interrupted") mg.fn() time.Sleep(time.Second) - mg.Redo.Save() + if !mg.NoWriteRedo { + mg.Redo.Save() + } os.Exit(3) } } diff --git a/mget/redo.go b/mget/redo.go index b5b35dc..053a05a 100644 --- a/mget/redo.go +++ b/mget/redo.go @@ -26,6 +26,7 @@ type Redo struct { avgSpeed float64 total uint64 isRedo bool + lastCallSave time.Time sync.RWMutex } @@ -128,18 +129,20 @@ func (r *Redo) AverageSpeed() float64 { } func (r *Redo) Save() error { + //defer recover() var err error err = r.reform() if err != nil { return err } + r.Lock() + defer r.Unlock() + r.lastCallSave = time.Now() if r.Filename != "" { data, err := json.Marshal(r) if err != nil { return err } - r.Lock() - defer r.Unlock() return os.WriteFile(r.Filename+".bgrd", data, 0644) } return nil diff --git a/mget/wget.go b/mget/wget.go index d710ff9..072b6c9 100644 --- a/mget/wget.go +++ b/mget/wget.go @@ -23,7 +23,10 @@ type Mget struct { //本地文件大小 TargetSize int64 //redo文件最大丢数据量 - RedoRPO int + RedoRPO int + NoWriteRedo bool + RedoAutoRpo bool + RedoMinSaveSec int //单个buffer大小 BufferSize int //并发下载线程数 @@ -231,7 +234,9 @@ func (w *Mget) Run() error { continue } if w.writeError != nil { - err = w.Redo.Save() + if !w.NoWriteRedo { + err = w.Redo.Save() + } return fmt.Errorf("write error: %w %v", w.writeError, err) } break @@ -252,10 +257,13 @@ func (w *Mget) Run() error { if err != nil { return err } - if len(r) == 0 { - return os.Remove(w.Tareget + ".bgrd") + if !w.NoWriteRedo { + if len(r) == 0 { + return os.Remove(w.Tareget + ".bgrd") + } + return w.Redo.Save() } - return w.Redo.Save() + return nil } func (w *Mget) dispatch(idx int) error { @@ -393,6 +401,10 @@ func (w *Mget) WriteServer() error { } } } + if w.RedoRPO == 0 { + w.RedoAutoRpo = true + w.RedoRPO = 1024 * 1024 * 1024 + } for { select { case <-w.ctx.Done(): @@ -413,9 +425,12 @@ func (w *Mget) WriteServer() error { if err != nil { return err } - if currentRange-lastUpdateRange >= w.RedoRPO { + if !w.NoWriteRedo && currentRange-lastUpdateRange >= w.RedoRPO && time.Now().After(w.Redo.lastCallSave.Add(time.Second*time.Duration(w.RedoMinSaveSec))) { w.tf.Sync() go w.Redo.Save() + if w.RedoAutoRpo { + w.RedoRPO = int(w.Redo.Speed()) * 2 + } lastUpdateRange = currentRange } } diff --git a/tcm/cmd_unix.go b/tcm/cmd_unix.go index e2dfe3c..3dbd73f 100644 --- a/tcm/cmd_unix.go +++ b/tcm/cmd_unix.go @@ -31,8 +31,11 @@ func init() { Cmd.Flags().IntVarP(&nf.packetDelay, "packet-delay-num", "n", 0, "触发封禁关键词后,延迟n个包再封禁") Cmd.Flags().BoolVarP(&nf.useRST, "rst", "r", false, "触发封禁关键词后,同步发送RST报文") Cmd.Flags().StringVarP(&nf.rstMode, "rstmode", "R", "reverse", "RST报文发送模式,可选值:both,target,reverse") - Cmd.Flags().BoolVarP(&nf.fastMode, "fastmode", "f", false, "快速模式,仅在模拟延迟或丢包时使用") + Cmd.Flags().BoolVarP(&nf.fastMode, "fastmode", "F", false, "快速模式,仅在模拟延迟或丢包时使用") Cmd.Flags().IntVarP(&nf.NFQNums, "nfqueue-num", "q", 2, "nfqueue队列号") Cmd.Flags().BoolVarP(&nf.allowRandomAck, "random-ack", "A", false, "允许并行乱序处理报文,如果需要模拟延迟,此选项需开启,但封禁功能可能受到乱序影响") - Cmd.Flags().BoolVarP(&nf.onlyDropblackwordPacket, "only-drop-blackword-packet", "o", false, "只封禁包含关键词的报文,此模式下,packetDelay会失效") + Cmd.Flags().BoolVarP(&nf.singlePacketMode, "signle-packet", "o", false, "仅对匹配到的单报文操作,此模式下,packetDelay会失效") + Cmd.Flags().StringSliceVarP(&nf.cuePktMethod, "cue-pkt-method", "O", []string{}, "单报文匹配下,执行的报文操作,可选值:drop,delay ms,allow,reset") + Cmd.Flags().StringSliceVarP(&nf.Flags, "flags", "f", nil, "tcp flags匹配,如:SYN,ACK") + Cmd.Flags().IntVarP(&nf.CapFileCacheNum, "write-cache", "W", 0, "命中匹配写入文件报文缓存,如果为0 ,则忽略匹配条件") } diff --git a/tcm/cmd_windows.go b/tcm/cmd_windows.go index d33bb5f..5840793 100644 --- a/tcm/cmd_windows.go +++ b/tcm/cmd_windows.go @@ -29,5 +29,7 @@ func init() { Cmd.Flags().StringVarP(&nf.eth, "eth", "e", "", "监听网卡名,如eth0") Cmd.Flags().StringVarP(&nf.bpf, "bpf", "b", "tcp", "BPF过滤,如tcp port 80") Cmd.Flags().StringVarP(&nf.host, "host", "i", "", "监听主机名,如127.0.0.1") + Cmd.Flags().StringSliceVarP(&nf.Flags, "flags", "f", nil, "tcp flags匹配,如:SYN,ACK") + Cmd.Flags().IntVarP(&nf.CapFileCacheNum, "write-cache", "W", 0, "命中匹配写入文件报文缓存,如果为0 ,则忽略匹配条件") } diff --git a/tcm/tcpmonitor_unix.go b/tcm/tcpmonitor_unix.go index 1ed9be7..50ff6ef 100644 --- a/tcm/tcpmonitor_unix.go +++ b/tcm/tcpmonitor_unix.go @@ -7,6 +7,7 @@ import ( "b612.me/bcap/nfq" "b612.me/stario" "b612.me/starlog" + "b612.me/starmap" "context" "encoding/hex" "fmt" @@ -63,18 +64,21 @@ type NfCap struct { // 触发封禁词后,使用RST重置链路 useRST bool // RST模式,target=目标端单向RST,reverse=对端反向RST,both=双向RST - rstMode string - fastMode bool //自探测 - printColor []*starlog.Color - logCache chan loged - monitorPort int - cache []string - NFQNums int - ctx context.Context - fn context.CancelFunc - requests chan *handler - allowRandomAck bool - onlyDropblackwordPacket bool + rstMode string + fastMode bool //自探测 + printColor []*starlog.Color + logCache chan loged + monitorPort int + cache []string + NFQNums int + ctx context.Context + fn context.CancelFunc + requests chan *handler + allowRandomAck bool + singlePacketMode bool + cuePktMethod []string + CapFileCacheNum int + Flags []string } type loged struct { @@ -205,7 +209,7 @@ func (t *NfCap) Run() error { func NewNfCap() *NfCap { var nf = new(NfCap) - nf.packetCache = make(chan gopacket.Packet, 2048) + nf.packetCache = make(chan gopacket.Packet, 8192) nf.logCache = make(chan loged, 2048) nf.printColor = []*starlog.Color{ starlog.NewColor(starlog.FgWhite), //0=unknown @@ -233,7 +237,7 @@ func NewNfCap() *NfCap { } nf.cap = bcap.NewPackets() nf.ctx, nf.fn = context.WithCancel(context.Background()) - nf.requests = make(chan *handler, 2048) + nf.requests = make(chan *handler, 8192) return nf } func (t *NfCap) handleNfResult() { @@ -246,8 +250,10 @@ func (t *NfCap) handleNfResult() { continue } if t.allowRandomAck { - go info.p.SetVerdict(info.id, <-info.fin) - continue + go func() { + info.p.SetVerdict(info.id, <-info.fin) + }() + break } info.p.SetVerdict(info.id, <-info.fin) } @@ -344,6 +350,21 @@ func (n *NfCap) strInRange(str string) bool { return false } +func (n *NfCap) strInRangeIdx(str string) int { + if len(n.targetCmd) == 0 { + return -1 + } + for k, v := range n.targetCmd { + if v == "" { + continue + } + if strings.Contains(str, v) { + return k + } + } + return -1 +} + func (n *NfCap) handlePacket(info bcap.PacketInfo, nfp nfq.Packet) int { p := nfp.Packet n.count++ @@ -427,6 +448,9 @@ func (n *NfCap) handlePacket(info bcap.PacketInfo, nfp nfq.Packet) int { case 14: dec = "TCP Keepalive" } + if len(n.Flags) > 0 && !n.writerMatch(p, true) { + return nfqueue.NfAccept + } if n.showAll || n.ipInRange(info.SrcIP) || n.ipInRange(info.DstIP) { n.logCache <- loged{ str: fmt.Sprintf("%s %v:%v -> %v:%v %s seq=%v ack=%v win=%v len=%v\n", time.Now().Format("2006-01-02 15:04:05.000000"), info.SrcIP, info.SrcPort, @@ -451,6 +475,21 @@ func (n *NfCap) handlePacket(info bcap.PacketInfo, nfp nfq.Packet) int { } } } + if res := n.cuePacket(info, layer); res != -1 { + return res + } + if shouldDisallow { + n.logCache <- loged{ + str: fmt.Sprintf("Block(loss) TCP %v:%v -> %v:%v,LEN=%d\n", info.SrcIP, info.SrcPort, info.DstIP, info.DstPort, info.TcpPayloads()), + stateLevel: 0, + logLevel: "warning", + } + return nfqueue.NfDrop + } + return nfqueue.NfAccept +} + +func (n *NfCap) cuePacket(info bcap.PacketInfo, layer gopacket.Layer) int { if info.Comment() != "" || n.cap.Key(info.ReverseKey).Comment() != "" { tmp := info.Comment() if tmp == "" { @@ -478,39 +517,32 @@ func (n *NfCap) handlePacket(info bcap.PacketInfo, nfp nfq.Packet) int { n.cap.SetComment(info.ReverseKey, strconv.Itoa(pkg-1)) } } - if len(n.targetCmd) > 0 && (n.ipInRange(info.SrcIP) || n.ipInRange(info.DstIP)) && n.strInRange(string(layer.LayerPayload())) { - n.logCache <- loged{ - str: fmt.Sprintf("%s:%s -> %s:%s !!Match Keyword,will block!!\n", info.SrcIP, info.SrcPort, - info.DstIP, info.DstPort), - stateLevel: 0, - logLevel: "warning", - } - if n.onlyDropblackwordPacket { - if n.useRST && info.StateDescript() == 13 { - return nfqueue.NfAccept - } + if len(n.targetCmd) > 0 && (n.ipInRange(info.SrcIP) || n.ipInRange(info.DstIP)) { + if idx := n.strInRangeIdx(string(layer.LayerPayload())); idx >= 0 { n.logCache <- loged{ - str: fmt.Sprintf("Block TCP %v:%v -> %v:%v,LEN=%d\n", info.SrcIP, info.SrcPort, info.DstIP, info.DstPort, info.TcpPayloads()), + str: fmt.Sprintf("%s:%s -> %s:%s !!Match Keyword,will block!!\n", info.SrcIP, info.SrcPort, + info.DstIP, info.DstPort), stateLevel: 0, logLevel: "warning", } - return nfqueue.NfDrop - } - if n.packetDelay > 0 && info.Comment() == "" { - n.cap.SetComment(info.Key, strconv.Itoa(n.packetDelay)) - n.cap.SetComment(info.ReverseKey, strconv.Itoa(n.packetDelay)) - } else { - if n.useRST { - RealSendRST(info, n.rstMode, 3) + if n.singlePacketMode { + return n.singlePacket(info, idx) } - if n.ipInRange(info.SrcIP) { - n.blockMap.Store(info.SrcIP, true) + if n.packetDelay > 0 && info.Comment() == "" { + n.cap.SetComment(info.Key, strconv.Itoa(n.packetDelay)) + n.cap.SetComment(info.ReverseKey, strconv.Itoa(n.packetDelay)) } else { - n.blockMap.Store(info.DstIP, true) + if n.useRST { + RealSendRST(info, n.rstMode, 3) + } + if n.ipInRange(info.SrcIP) { + n.blockMap.Store(info.SrcIP, true) + } else { + n.blockMap.Store(info.DstIP, true) + } } } } - _, ok1 := n.blockMap.Load(info.DstIP) _, ok2 := n.blockMap.Load(info.SrcIP) if ok1 || ok2 { @@ -524,35 +556,176 @@ func (n *NfCap) handlePacket(info bcap.PacketInfo, nfp nfq.Packet) int { } return nfqueue.NfDrop } - if shouldDisallow { - n.logCache <- loged{ - str: fmt.Sprintf("Block(loss) TCP %v:%v -> %v:%v,LEN=%d\n", info.SrcIP, info.SrcPort, info.DstIP, info.DstPort, info.TcpPayloads()), - stateLevel: 0, - logLevel: "warning", - } + return -1 +} + +func (n *NfCap) singlePacket(info bcap.PacketInfo, idx int) int { + n.logCache <- loged{ + str: fmt.Sprintf("Handle TCP %v:%v -> %v:%v,LEN=%d\n", info.SrcIP, info.SrcPort, info.DstIP, info.DstPort, info.TcpPayloads()), + stateLevel: 0, + logLevel: "warning", + } + if len(n.cuePktMethod) == 0 { return nfqueue.NfDrop } + task := n.cuePktMethod[idx] + for _, v := range strings.Split(task, ";") { + v = strings.TrimSpace(v) + tasks := strings.Fields(v) + switch strings.ToLower(tasks[0]) { + case "delay": + if len(tasks) < 2 { + continue + } + tmp, err := strconv.Atoi(tasks[1]) + if err != nil { + fmt.Printf("输入延迟无效:%v\n", err) + continue + } + time.Sleep(time.Millisecond * time.Duration(tmp)) + case "drop": + return nfqueue.NfDrop + case "allow": + return nfqueue.NfAccept + case "reset": + RealSendRST(info, n.rstMode, 3) + default: + starlog.Warningf("未知命令:%s\n", v) + } + } return nfqueue.NfAccept } func (n *NfCap) pcapWriter(stopCtx context.Context, fp *os.File) error { w := pcapgo.NewWriter(fp) - err := w.WriteFileHeader(65535, layers.LinkTypeRaw) + err := w.WriteFileHeader(65535, layers.LinkTypeEthernet) if err != nil { return err } + buf := starmap.NewStarChanStack(uint64(n.CapFileCacheNum)) + avail := 0 for { select { case <-stopCtx.Done(): return nil case p := <-n.packetCache: - w.WritePacket(gopacket.CaptureInfo{ - Timestamp: time.Now(), - CaptureLength: len(p.Data()), - Length: len(p.Data()), - }, p.Data()) + if n.CapFileCacheNum == 0 { + w.WritePacket(p.Metadata().CaptureInfo, p.Data()) + continue + } + if avail > 0 { + avail-- + if n.writerMatch(p, false) { + avail = n.CapFileCacheNum + } + w.WritePacket(p.Metadata().CaptureInfo, p.Data()) + continue + } + if buf.Free() == 0 { + buf.Pop() + } + if !n.writerMatch(p, false) { + buf.Push(p) + continue + } + for buf.Len() > 0 { + hp, err := buf.Pop() + if err == nil { + w.WritePacket(hp.(gopacket.Packet).Metadata().CaptureInfo, hp.(gopacket.Packet).Data()) + } + } + w.WritePacket(p.Metadata().CaptureInfo, p.Data()) + avail = n.CapFileCacheNum + } + } +} + +func (n *NfCap) writerMatch(pkt gopacket.Packet, onlyFlags bool) bool { + tcpLayer := pkt.Layer(layers.LayerTypeTCP) + if !onlyFlags { + var src, dst string + if nw := pkt.NetworkLayer(); nw != nil { + srcp, dstp := nw.NetworkFlow().Endpoints() + src = srcp.String() + dst = dstp.String() + } + if !(n.ipInRange(src) || n.ipInRange(dst)) { + return false + } + if tcpLayer == nil { + if len(n.targetCmd) != 0 && !n.strInRange(string(pkt.TransportLayer().LayerPayload())) { + return false + } + return true + } + if len(n.targetCmd) != 0 && !n.strInRange(string(tcpLayer.LayerPayload())) { + return false + } + } + if len(n.Flags) == 0 { + return true + } + if tcpLayer == nil { + return false + } + tl := tcpLayer.(*layers.TCP) + for _, seq := range n.Flags { + notMatch := false + bkfor: + for _, v := range strings.Split(strings.ToUpper(seq), ",") { + switch strings.TrimSpace(v) { + case "SYN": + if !tl.SYN { + notMatch = true + break bkfor + } + case "ACK": + if !tl.ACK { + notMatch = true + break bkfor + } + case "FIN": + if !tl.FIN { + notMatch = true + break bkfor + } + case "RST": + if !tl.RST { + notMatch = true + break bkfor + } + case "CWR": + if !tl.CWR { + notMatch = true + break bkfor + } + case "ECE": + if !tl.ECE { + notMatch = true + break bkfor + } + case "NS": + if !tl.NS { + notMatch = true + break bkfor + } + case "PSH": + if !tl.PSH { + notMatch = true + break bkfor + } + case "URG": + if !tl.URG { + notMatch = true + break bkfor + } + } + } + if !notMatch { + return true } } + return false } func RealSendRST(info bcap.PacketInfo, target string, number int) { diff --git a/tcm/tcpmonitor_windows.go b/tcm/tcpmonitor_windows.go index 1f91402..ecb8497 100644 --- a/tcm/tcpmonitor_windows.go +++ b/tcm/tcpmonitor_windows.go @@ -6,6 +6,7 @@ import ( "b612.me/bcap" "b612.me/bcap/libpcap" "b612.me/starlog" + "b612.me/starmap" "context" "encoding/hex" "fmt" @@ -52,16 +53,18 @@ type Libpcap struct { // 触发封禁词后,使用RST重置链路 useRST bool // RST模式,target=目标端单向RST,reverse=对端反向RST,both=双向RST - rstMode string - printColor []*starlog.Color - logCache chan loged - ctx context.Context - fn context.CancelFunc - bpf string - eth string - host string - handle *libpcap.NetCatch - blockMap sync.Map + rstMode string + printColor []*starlog.Color + logCache chan loged + ctx context.Context + fn context.CancelFunc + bpf string + eth string + host string + handle *libpcap.NetCatch + blockMap sync.Map + CapFileCacheNum int + Flags []string } type loged struct { @@ -297,6 +300,9 @@ func (n *Libpcap) handlePacket(p gopacket.Packet) { if !n.showAll && !n.ipInRange(info.SrcIP) && !n.ipInRange(info.DstIP) { return } + if len(n.Flags) > 0 && !n.writerMatch(p, true) { + return + } n.logCache <- loged{ str: fmt.Sprintf("%s %v:%v -> %v:%v %s seq=%v ack=%v win=%v len=%v\n", time.Now().Format("2006-01-02 15:04:05.000000"), info.SrcIP, info.SrcPort, info.DstIP, info.DstPort, dec, info.TcpSeq(), info.TcpAck(), info.TcpWindow(), info.TcpPayloads()), @@ -330,33 +336,149 @@ func (n *Libpcap) handlePacket(p gopacket.Packet) { } } +func RealSendRST(p *pcap.Handle, info bcap.PacketInfo, target string, number int) { + for i := 0; i < number; i++ { + if target == "both" || target == "target" { + SendRST(p, info.SrcMac, info.DstMac, info.SrcIP, info.SrcPort, info.DstIP, info.DstPort, info.TcpSeq()+(uint32(i)*uint32(info.TcpWindow()))) + //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 (n *Libpcap) pcapWriter(stopCtx context.Context, fp *os.File) error { w := pcapgo.NewWriter(fp) err := w.WriteFileHeader(65535, layers.LinkTypeEthernet) if err != nil { return err } + buf := starmap.NewStarChanStack(uint64(n.CapFileCacheNum)) + avail := 0 for { select { case <-stopCtx.Done(): return nil case p := <-n.packetCache: + if n.CapFileCacheNum == 0 { + w.WritePacket(p.Metadata().CaptureInfo, p.Data()) + continue + } + if avail > 0 { + avail-- + if n.writerMatch(p, false) { + avail = n.CapFileCacheNum + } + w.WritePacket(p.Metadata().CaptureInfo, p.Data()) + continue + } + if buf.Free() == 0 { + buf.Pop() + } + if !n.writerMatch(p, false) { + buf.Push(p) + continue + } + for buf.Len() > 0 { + hp, err := buf.Pop() + if err == nil { + w.WritePacket(hp.(gopacket.Packet).Metadata().CaptureInfo, hp.(gopacket.Packet).Data()) + } + } w.WritePacket(p.Metadata().CaptureInfo, p.Data()) + avail = n.CapFileCacheNum } } } -func RealSendRST(p *pcap.Handle, info bcap.PacketInfo, target string, number int) { - for i := 0; i < number; i++ { - if target == "both" || target == "target" { - SendRST(p, info.SrcMac, info.DstMac, info.SrcIP, info.SrcPort, info.DstIP, info.DstPort, info.TcpSeq()+(uint32(i)*uint32(info.TcpWindow()))) - //SendRST(p, info.DstMac, info.SrcMac, info.SrcIP, info.SrcPort, info.DstIP, info.DstPort, info.TcpSeq()+(uint32(i)*uint32(info.TcpWindow()))) +func (n *Libpcap) writerMatch(pkt gopacket.Packet, onlyFlags bool) bool { + tcpLayer := pkt.Layer(layers.LayerTypeTCP) + if !onlyFlags { + var src, dst string + if nw := pkt.NetworkLayer(); nw != nil { + srcp, dstp := nw.NetworkFlow().Endpoints() + src = srcp.String() + dst = dstp.String() } - 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()))) + if !(n.ipInRange(src) || n.ipInRange(dst)) { + return false + } + if tcpLayer == nil { + if len(n.targetCmd) != 0 && !n.strInRange(string(pkt.TransportLayer().LayerPayload())) { + return false + } + return true + } + if len(n.targetCmd) != 0 && !n.strInRange(string(tcpLayer.LayerPayload())) { + return false } } + if len(n.Flags) == 0 { + return true + } + if tcpLayer == nil { + return false + } + tl := tcpLayer.(*layers.TCP) + for _, seq := range n.Flags { + notMatch := false + bkfor: + for _, v := range strings.Split(strings.ToUpper(seq), ",") { + switch strings.TrimSpace(v) { + case "SYN": + if !tl.SYN { + notMatch = true + break bkfor + } + case "ACK": + if !tl.ACK { + notMatch = true + break bkfor + } + case "FIN": + if !tl.FIN { + notMatch = true + break bkfor + } + case "RST": + if !tl.RST { + notMatch = true + break bkfor + } + case "CWR": + if !tl.CWR { + notMatch = true + break bkfor + } + case "ECE": + if !tl.ECE { + notMatch = true + break bkfor + } + case "NS": + if !tl.NS { + notMatch = true + break bkfor + } + case "PSH": + if !tl.PSH { + notMatch = true + break bkfor + } + case "URG": + if !tl.URG { + notMatch = true + break bkfor + } + } + } + if !notMatch { + return true + } + } + return false } func SendRST(p *pcap.Handle, srcMac, dstMac []byte, srcIP, srcPort, dstIP, dstPort string, seq uint32) error { diff --git a/version/version.go b/version/version.go index 2a0ffce..907f54c 100644 --- a/version/version.go +++ b/version/version.go @@ -1,3 +1,3 @@ package version -var Version = "2.1.0.beta.15" +var Version = "2.1.0.beta.16"