This commit is contained in:
兔子 2025-03-25 10:00:26 +08:00
parent 98f50488ca
commit 1879810c9e
23 changed files with 1381 additions and 182 deletions

View File

@ -7,6 +7,7 @@ import (
)
var isFormat bool
var jieqi string
func init() {
Cmd.PersistentFlags().Float64Var(&lon, "lon", -273, "经度,WGS84坐标系")
@ -168,6 +169,61 @@ var CmdStar = &cobra.Command{
},
}
var CmdJieqi = &cobra.Command{
Use: "jq",
Short: "节气计算",
Run: func(cmd *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Println("请输入年份或节气")
return
}
year := args[0]
if year == "" {
year = time.Now().Format("2006")
}
year = year[:4]
fmt.Println("年份: ", year)
/*
var jqname = map[string]int{
"春分": 0,
"清明": 15,
"谷雨": 30,
"立夏": 45,
"小满": 60,
"芒种": 75,
"夏至": 90,
"小暑": 105,
"大暑": 120,
"立秋": 135,
"处暑": 150,
"白露": 165,
"秋分": 180,
"寒露": 195,
"霜降": 210,
"立冬": 225,
"小雪": 240,
"大雪": 255,
"冬至": 270,
"小寒": 285,
"大寒": 300,
"立春": 315,
"雨水": 330,
"惊蛰": 345,
}
if jieqi != "" {
if v, ok := jqname[jieqi]; !ok {
fmt.Println("节气名错误")
return
} else {
fmt.Println("节气名: ", jieqi)
fmt.Println("时间: ", calendar.JieQi(year, v))
}
}
*/
},
}
func CliLoadLonLatHeight() bool {
if city != "" {
if !GetFromCity(city) {

1
astro/jieqi.go Normal file
View File

@ -0,0 +1 @@
package astro

View File

@ -105,9 +105,9 @@ func ParseCert(data []byte, pwd string) {
switch n := priv.(type) {
case *rsa.PrivateKey:
starlog.Green("这是一个RSA私钥\n")
starlog.Green("钥位数:%d\n", n.Size())
starlog.Green("钥长度:%d\n", n.N.BitLen())
starlog.Green("钥指数:%d\n", n.E)
starlog.Green("钥位数:%d\n", n.Size())
starlog.Green("钥长度:%d\n", n.N.BitLen())
starlog.Green("钥指数:%d\n", n.E)
starlog.Green("私钥系数:%d\n", n.D)
starlog.Green("私钥质数p%d\n", n.Primes[0])
starlog.Green("私钥质数q%d\n", n.Primes[1])
@ -116,8 +116,8 @@ func ParseCert(data []byte, pwd string) {
starlog.Green("私钥系数qInv%d\n", n.Precomputed.Qinv)
case *ecdsa.PrivateKey:
starlog.Green("这是一个ECDSA私钥\n")
starlog.Green("钥位数:%d\n", n.Curve.Params().BitSize)
starlog.Green("钥曲线:%s\n", n.Curve.Params().Name)
starlog.Green("钥位数:%d\n", n.Curve.Params().BitSize)
starlog.Green("钥曲线:%s\n", n.Curve.Params().Name)
starlog.Green("私钥长度:%d\n", n.Params().BitSize)
starlog.Green("私钥系数:%d\n", n.D)
starlog.Green("私钥公钥X%d\n", n.PublicKey.X)
@ -237,9 +237,9 @@ func ParseCert(data []byte, pwd string) {
switch n := priv.(type) {
case *rsa.PrivateKey:
starlog.Green("这是一个RSA私钥\n")
starlog.Green("钥位数:%d\n", n.Size())
starlog.Green("钥长度:%d\n", n.N.BitLen())
starlog.Green("钥指数:%d\n", n.E)
starlog.Green("钥位数:%d\n", n.Size())
starlog.Green("钥长度:%d\n", n.N.BitLen())
starlog.Green("钥指数:%d\n", n.E)
starlog.Green("私钥系数:%d\n", n.D)
starlog.Green("私钥质数p%d\n", n.Primes[0])
starlog.Green("私钥质数q%d\n", n.Primes[1])
@ -378,9 +378,9 @@ func ParseCert(data []byte, pwd string) {
switch n := priv.(type) {
case *rsa.PrivateKey:
starlog.Green("这是一个RSA私钥\n")
starlog.Green("钥位数:%d\n", n.Size())
starlog.Green("钥长度:%d\n", n.N.BitLen())
starlog.Green("钥指数:%d\n", n.E)
starlog.Green("钥位数:%d\n", n.Size())
starlog.Green("钥长度:%d\n", n.N.BitLen())
starlog.Green("钥指数:%d\n", n.E)
starlog.Green("私钥系数:%d\n", n.D)
starlog.Green("私钥质数p%d\n", n.Primes[0])
starlog.Green("私钥质数q%d\n", n.Primes[1])
@ -640,7 +640,7 @@ func GetCert(data []byte, pwd string) ([]any, []x509.Certificate, error) {
switch n := priv.(type) {
case *rsa.PrivateKey:
starlog.Green("这是一个RSA私钥\n")
starlog.Green("钥位数:%d\n", n.Size())
starlog.Green("钥位数:%d\n", n.Size())
case *ecdsa.PrivateKey:
starlog.Green("这是一个ECDSA私钥\n")
starlog.Green("私钥位数:%d\n", n.Curve.Params().BitSize)
@ -760,8 +760,8 @@ func GetCert(data []byte, pwd string) ([]any, []x509.Certificate, error) {
case *rsa.PrivateKey:
common = append(common, n)
starlog.Green("这是一个RSA私钥\n")
starlog.Green("钥位数:%d\n", n.Size())
starlog.Green("钥长度:%d\n", n.N.BitLen())
starlog.Green("钥位数:%d\n", n.Size())
starlog.Green("钥长度:%d\n", n.N.BitLen())
case *ecdsa.PrivateKey:
common = append(common, n)
starlog.Green("这是一个ECDSA私钥\n")

4
go.mod
View File

@ -20,6 +20,7 @@ require (
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2
github.com/emersion/go-smtp v0.20.2
github.com/florianl/go-nfqueue/v2 v2.0.0
github.com/gdamore/tcell/v2 v2.7.1
github.com/go-acme/lego/v4 v4.16.1
github.com/goftp/file-driver v0.0.0-20180502053751-5d604a0fc0c9
github.com/goftp/server v0.0.0-20200708154336-f64f7c2d8a42
@ -29,6 +30,7 @@ require (
github.com/inconshreveable/mousetrap v1.1.0
github.com/miekg/dns v1.1.58
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/rivo/tview v0.0.0-20241227133733-17b7edb88c57
github.com/shirou/gopsutil/v4 v4.24.10
github.com/spf13/cobra v1.8.0
github.com/things-go/go-socks5 v0.0.5
@ -56,6 +58,7 @@ require (
github.com/cpu/goacmedns v0.1.1 // indirect
github.com/ebitengine/purego v0.8.1 // indirect
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect
github.com/gdamore/encoding v1.0.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/goccy/go-json v0.10.2 // indirect
@ -71,6 +74,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mdlayher/netlink v1.7.2 // indirect

10
go.sum
View File

@ -72,6 +72,10 @@ github.com/emersion/go-smtp v0.20.2/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVR
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/florianl/go-nfqueue/v2 v2.0.0 h1:NTCxS9b0GSbHkWv1a7oOvZn679fsyDkaSkRvOYpQ9Oo=
github.com/florianl/go-nfqueue/v2 v2.0.0/go.mod h1:M2tBLIj62QpwqjwV0qfcjqGOqP3qiTuXr2uSRBXH9Qk=
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.7.1 h1:TiCcmpWHiAU7F0rA2I3S2Y4mmLmO9KHxJ7E1QhYzQbc=
github.com/gdamore/tcell/v2 v2.7.1/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
github.com/go-acme/lego/v4 v4.16.1 h1:JxZ93s4KG0jL27rZ30UsIgxap6VGzKuREsSkkyzeoCQ=
github.com/go-acme/lego/v4 v4.16.1/go.mod h1:AVvwdPned/IWpD/ihHhMsKnveF7HHYAz/CmtXi7OZoE=
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
@ -131,10 +135,13 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
@ -159,7 +166,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/rivo/tview v0.0.0-20241227133733-17b7edb88c57 h1:LmsF7Fk5jyEDhJk0fYIqdWNuTxSyid2W42A0L2YWjGE=
github.com/rivo/tview v0.0.0-20241227133733-17b7edb88c57/go.mod h1:02iFIz7K/A9jGCvrizLPvoqr4cEIx7q54RH5Qudkrss=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=

View File

@ -29,7 +29,7 @@ var Cmd = &cobra.Command{
var cumethod, method []string
var result = make(map[string]string)
var err error
cumethod = []string{"md5", "crc32", "sha512", "sha384", "sha256", "sha224", "sha1", "md4", "ripemd160", "hmacmd5", "hmacmd4", "hmacsha1", "hmacsha224", "hmacsha256", "hmacsha384", "hmacsha512"}
cumethod = []string{"md5", "crc32a", "crc32", "sha512", "sha384", "sha256", "sha224", "sha1", "md4", "ripemd160", "hmacmd5", "hmacmd4", "hmacsha1", "hmacsha224", "hmacsha256", "hmacsha384", "hmacsha512"}
if ok, _ := this.Flags().GetBool("all"); ok {
method = cumethod
} else {
@ -79,6 +79,7 @@ func init() {
Cmd.Flags().BoolP("file", "f", false, "对指定文件进行校验")
Cmd.Flags().BoolP("md5", "m", false, "进行MD5校验默认")
Cmd.Flags().BoolP("crc32", "c", false, "进行CRC32校验")
Cmd.Flags().Bool("crc32a", false, "进行CRC32A校验")
Cmd.Flags().BoolP("sha512", "s", false, "进行SHA512校验")
Cmd.Flags().Bool("sha384", false, "进行SHA384校验")
Cmd.Flags().Bool("sha256", false, "进行SHA256校验")
@ -98,10 +99,9 @@ func init() {
func FileSumAll(filepath string, key string, method []string, shell func(float64)) (map[string]string, error) {
result := make(map[string]string)
methods := make(map[string]hash.Hash)
var iscrc bool
if len(method) == 0 {
method = []string{"sha512", "sha256", "sha384", "sha224", "sha1", "crc32", "md5", "md4", "ripemd160", "hmacmd5", "hmacmd4", "hmacsha1", "hmacsha224", "hmacsha256", "hmacsha384", "hmacsha512"}
method = []string{"sha512", "sha256", "sha384", "sha224", "sha1", "crc32a", "crc32", "md5", "md4", "ripemd160", "hmacmd5", "hmacmd4", "hmacsha1", "hmacsha224", "hmacsha256", "hmacsha384", "hmacsha512"}
}
fp, err := os.Open(filepath)
defer fp.Close()
@ -115,6 +115,7 @@ func FileSumAll(filepath string, key string, method []string, shell func(float64
sum256 := sha256.New()
sum224 := sha256.New224()
sum1 := sha1.New()
crc32a := crc32.New(crc32.MakeTable(0x04C11DB7))
crcsum := crc32.NewIEEE()
md5sum := md5.New()
md4sum := md4.New()
@ -130,8 +131,10 @@ func FileSumAll(filepath string, key string, method []string, shell func(float64
switch v {
case "md5":
methods["md5"] = md5sum
case "crc32a":
methods["crc32a"] = crc32a
case "crc32":
iscrc = true
methods["crc32"] = crcsum
case "sha1":
methods["sha1"] = sum1
case "sha224":
@ -179,31 +182,25 @@ func FileSumAll(filepath string, key string, method []string, shell func(float64
for _, v := range methods {
v.Write(buf[0:n])
}
if iscrc {
crcsum.Write(buf[0:n])
}
}
for k, v := range methods {
result[k] = hex.EncodeToString(v.Sum(nil))
}
if iscrc {
result["crc32"] = hex.EncodeToString(crcsum.Sum(nil))
}
return result, nil
}
func SumAll(data []byte, key string, method []string) (map[string][]byte, error) {
result := make(map[string][]byte)
methods := make(map[string]hash.Hash)
var iscrc bool
if len(method) == 0 {
method = []string{"sha512", "sha256", "sha384", "sha224", "sha1", "crc32", "md5", "md4", "ripemd160", "hmacmd5", "hmacmd4", "hmacsha1", "hmacsha224", "hmacsha256", "hmacsha384", "hmacsha512"}
method = []string{"sha512", "sha256", "sha384", "sha224", "sha1", "crc32a", "crc32", "md5", "md4", "ripemd160", "hmacmd5", "hmacmd4", "hmacsha1", "hmacsha224", "hmacsha256", "hmacsha384", "hmacsha512"}
}
sum512 := sha512.New()
sum384 := sha512.New384()
sum256 := sha256.New()
sum224 := sha256.New224()
sum1 := sha1.New()
crc32a := crc32.New(crc32.MakeTable(0x04C11DB7))
crcsum := crc32.NewIEEE()
md5sum := md5.New()
md4sum := md4.New()
@ -219,8 +216,10 @@ func SumAll(data []byte, key string, method []string) (map[string][]byte, error)
switch v {
case "md5":
methods["md5"] = md5sum
case "crc32a":
methods["crc32a"] = crc32a
case "crc32":
iscrc = true
methods["crc32"] = crcsum
case "sha1":
methods["sha1"] = sum1
case "sha224":
@ -254,15 +253,8 @@ func SumAll(data []byte, key string, method []string) (map[string][]byte, error)
for _, v := range methods {
v.Write(data)
}
if iscrc {
crcsum.Write(data)
}
for k, v := range methods {
result[k] = v.Sum(nil)
}
if iscrc {
result["crc32"] = crcsum.Sum(nil)
}
return result, nil
}

View File

@ -4,6 +4,7 @@ import (
"b612.me/starcrypto"
"b612.me/staros"
"crypto"
"crypto/ecdh"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
@ -67,7 +68,7 @@ func (k *KeyGen) Gen() error {
if err != nil {
return err
}
case "ecdsa", "ecdh":
case "ecdsa":
var cr elliptic.Curve
switch k.Bits {
case 224:
@ -90,6 +91,33 @@ func (k *KeyGen) Gen() error {
if err != nil {
return err
}
case "x25519":
priv, err = ecdh.X25519().GenerateKey(rand.Reader)
if err != nil {
return err
}
pub = priv.(*ecdh.PrivateKey).Public()
case "ecdh":
switch k.Bits {
case 256:
priv, err = ecdh.P256().GenerateKey(rand.Reader)
if err != nil {
return err
}
pub = priv.(*ecdh.PrivateKey).Public()
case 384:
priv, err = ecdh.P384().GenerateKey(rand.Reader)
if err != nil {
return err
}
pub = priv.(*ecdh.PrivateKey).Public()
case 521:
priv, err = ecdh.P521().GenerateKey(rand.Reader)
if err != nil {
return err
}
pub = priv.(*ecdh.PrivateKey).Public()
}
default:
return errors.New("invalid key type,only support rsa,ecdsa")
}

View File

@ -24,6 +24,7 @@ import (
"b612.me/apps/b612/merge"
"b612.me/apps/b612/mget"
"b612.me/apps/b612/net"
"b612.me/apps/b612/nmon"
"b612.me/apps/b612/rmt"
"b612.me/apps/b612/search"
"b612.me/apps/b612/smtpclient"
@ -55,7 +56,7 @@ func init() {
base64.Cmd, base85.Cmd, base91.Cmd, attach.Cmd, detach.Cmd, df.Cmd, dfinder.Cmd,
ftp.Cmd, generate.Cmd, hash.Cmd, image.Cmd, merge.Cmd, search.Cmd, split.Cmd, vic.Cmd,
calc.Cmd, net.Cmd, rmt.Cmds, rmt.Cmdc, keygen.Cmd, dns.Cmd, whois.Cmd, socks5.Cmd, httproxy.Cmd, smtpserver.Cmd, smtpclient.Cmd,
cert.Cmd, aes.Cmd, tls.Cmd, mget.Cmd, tcpkill.Cmd, tcm.Cmd, astro.CmdCal, astro.Cmd)
cert.Cmd, aes.Cmd, tls.Cmd, mget.Cmd, tcpkill.Cmd, tcm.Cmd, astro.CmdCal, astro.Cmd, nmon.Cmd)
}
func main() {

View File

@ -259,7 +259,10 @@ func (w *Mget) Run() error {
}
if !w.NoWriteRedo {
if len(r) == 0 {
return os.Remove(w.Tareget + ".bgrd")
if staros.Exists(w.Tareget + ".bgrd") {
return os.Remove(w.Tareget + ".bgrd")
}
return nil
}
return w.Redo.Save()
}

View File

@ -8,6 +8,8 @@ import (
"b612.me/starlog"
"fmt"
"github.com/spf13/cobra"
"os"
"os/signal"
"time"
)
@ -36,6 +38,7 @@ var natt NatThroughs
var scanip ScanIP
var scanport ScanPort
var monitorip Monitor
func init() {
CmdNatPClient.Flags().StringVarP(&natc.ServiceTarget, "target", "t", "", "forward server target address")
@ -60,7 +63,7 @@ func init() {
CmdNetTrace.Flags().IntVarP(&timeout, "timeout", "t", 800, "超时时间,单位毫秒")
CmdNetTrace.Flags().IntVarP(&maxHop, "max-hop", "m", 32, "最大跳数")
CmdNetTrace.Flags().BoolVarP(&disableIpInfo, "disable-ipinfo", "D", false, "禁用ip信息查询")
CmdNetTrace.Flags().StringVarP(&bindAddr, "bind", "b", "0.0.0.0", "绑定地址")
CmdNetTrace.Flags().StringVarP(&bindAddr, "bind", "b", "", "绑定地址")
CmdNetTrace.Flags().BoolVarP(&hideIncorrect, "hide-incorrect", "H", false, "隐藏错误节点")
Cmd.AddCommand(CmdNetTrace, cmdSSHJar)
@ -106,6 +109,17 @@ func init() {
CmdScanPort.Flags().IntVarP(&scanport.Retry, "retry", "r", 2, "重试次数")
Cmd.AddCommand(CmdScanPort)
CmdMonitorIP.Flags().StringSliceVarP(&monitorip.IPs, "ip", "i", []string{}, "扫描IP地址列表")
CmdMonitorIP.Flags().IntVarP(&monitorip.Port, "port", "p", 80, "TCP模式扫描端口")
CmdMonitorIP.Flags().IntVarP(&monitorip.Timeout, "timeout", "t", 1200, "超时时间,毫秒")
CmdMonitorIP.Flags().IntVarP(&monitorip.Interval, "interval", "I", 1, "扫描间隔,秒")
CmdMonitorIP.Flags().IntVarP(&monitorip.Threads, "threads", "m", 100, "最大线程数")
CmdMonitorIP.Flags().StringVarP(&monitorip.Log, "log", "l", "", "日志文件地址")
CmdMonitorIP.Flags().StringVarP(&monitorip.ScanType, "type", "T", "icmp", "扫描类型")
CmdMonitorIP.Flags().IntVarP(&monitorip.Retry, "retry", "r", 1, "重试次数")
CmdMonitorIP.Flags().BoolVarP(&monitorip.WithHostname, "with-hostname", "H", false, "显示主机名")
Cmd.AddCommand(CmdMonitorIP)
Cmd.AddCommand(tcpkill.Cmd, tcping.Cmd, tcm.Cmd)
}
@ -221,6 +235,30 @@ var CmdScanIP = &cobra.Command{
},
}
var CmdMonitorIP = &cobra.Command{
Use: "monitorip",
Short: "监控IP",
Run: func(cmd *cobra.Command, args []string) {
if len(monitorip.IPs) == 0 {
cmd.Help()
return
}
monitorip.status = make(map[string]bool)
monitorip.stopChan = make(chan struct{})
sig := make(chan os.Signal)
signal.Notify(sig, os.Interrupt, os.Kill)
go func() {
err := monitorip.Start()
if err != nil {
starlog.Errorln(err)
os.Exit(1)
}
}()
<-sig
monitorip.Stop()
},
}
var CmdScanPort = &cobra.Command{
Use: "scanport",
Short: "扫描端口",

183
net/icmp.go Normal file
View File

@ -0,0 +1,183 @@
package net
import (
"fmt"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
"net"
"sync"
"sync/atomic"
"time"
)
const (
readBufferSize = 1500
maxSeq = 0xffff
)
type Pinger struct {
icmpID int
conn4 *icmp.PacketConn
conn6 *icmp.PacketConn
connOnce4 sync.Once
connOnce6 sync.Once
connErr4 error
connErr6 error
sequenceNum4 uint32
sequenceNum6 uint32
pending sync.Map
closed chan struct{}
}
type pendingKey struct {
proto string
seq int
}
func NewPinger(icmpID int) *Pinger {
return &Pinger{
icmpID: icmpID & 0xffff,
closed: make(chan struct{}),
}
}
func (p *Pinger) Close() error {
close(p.closed)
var err error
if p.conn4 != nil {
if e := p.conn4.Close(); e != nil {
err = e
}
}
if p.conn6 != nil {
if e := p.conn6.Close(); e != nil {
err = e
}
}
return err
}
func (p *Pinger) Ping(ip string, timeout time.Duration) error {
var conn *icmp.PacketConn
var proto string
var sequence *uint32
dest, err := net.ResolveIPAddr("ip", ip)
if err != nil {
return fmt.Errorf("resolve IP address error: %w", err)
}
if dest.IP.To4() != nil {
// IPv4处理
p.connOnce4.Do(func() {
p.conn4, p.connErr4 = icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if p.connErr4 == nil {
go p.receiveLoop(p.conn4, "ip4")
}
})
if p.connErr4 != nil {
return fmt.Errorf("ICMPv4 connection error: %w", p.connErr4)
}
conn = p.conn4
proto = "ip4"
sequence = &p.sequenceNum4
} else {
// IPv6处理
p.connOnce6.Do(func() {
p.conn6, p.connErr6 = icmp.ListenPacket("ip6:ipv6-icmp", "::")
if p.connErr6 == nil {
go p.receiveLoop(p.conn6, "ip6")
}
})
if p.connErr6 != nil {
return fmt.Errorf("ICMPv6 connection error: %w", p.connErr6)
}
conn = p.conn6
proto = "ip6"
sequence = &p.sequenceNum6
}
seq := int(atomic.AddUint32(sequence, 1) & maxSeq)
key := pendingKey{proto, seq}
resultChan := make(chan struct{})
p.pending.Store(key, resultChan)
defer p.pending.Delete(key)
var msgType icmp.Type
if proto == "ip4" {
msgType = ipv4.ICMPTypeEcho
} else {
msgType = ipv6.ICMPTypeEchoRequest
}
msg := &icmp.Message{
Type: msgType,
Code: 0,
Body: &icmp.Echo{
ID: p.icmpID,
Seq: seq,
Data: []byte("HELLO-PING"),
},
}
packet, err := msg.Marshal(nil)
if err != nil {
return fmt.Errorf("marshal error: %w", err)
}
if _, err := conn.WriteTo(packet, dest); err != nil {
return fmt.Errorf("write error: %w", err)
}
select {
case <-resultChan:
return nil
case <-time.After(timeout):
return fmt.Errorf("timeout")
case <-p.closed:
return fmt.Errorf("pinger closed")
}
}
func (p *Pinger) receiveLoop(conn *icmp.PacketConn, proto string) {
buffer := make([]byte, readBufferSize)
for {
select {
case <-p.closed:
return
default:
n, _, err := conn.ReadFrom(buffer)
if err != nil {
continue
}
var expectedType icmp.Type
var protocol int
if proto == "ip4" {
expectedType = ipv4.ICMPTypeEchoReply
protocol = 1 // ICMPv4协议号
} else {
expectedType = ipv6.ICMPTypeEchoReply
protocol = 58 // ICMPv6协议号
}
msg, err := icmp.ParseMessage(protocol, buffer[:n])
if err != nil {
continue
}
if msg.Type != expectedType {
continue
}
echo, ok := msg.Body.(*icmp.Echo)
if !ok || echo.ID != p.icmpID {
continue
}
key := pendingKey{proto, echo.Seq}
if ch, exists := p.pending.LoadAndDelete(key); exists {
close(ch.(chan struct{}))
}
}
}
}

193
net/monitorip.go Normal file
View File

@ -0,0 +1,193 @@
package net
import (
"b612.me/apps/b612/netforward"
"b612.me/starlog"
"fmt"
"net"
"sync"
"time"
)
type Monitor struct {
IPs []string
Port int
ScanType string
Timeout int
Interval int
Log string
Retry int
Threads int
WithHostname bool
pinger *Pinger
status map[string]bool
statusLock sync.RWMutex
stopChan chan struct{}
}
func NewMonitor(ips []string, scanType string) *Monitor {
return &Monitor{
IPs: ips,
ScanType: scanType,
status: make(map[string]bool),
stopChan: make(chan struct{}),
Timeout: 1000,
Interval: 1,
Retry: 1,
Threads: 50,
}
}
func (m *Monitor) Start() error {
if m.Log != "" {
starlog.SetLogFile(m.Log, starlog.Std, true)
}
m.pinger = NewPinger(1127)
// Initialize status
m.statusLock.Lock()
for _, ip := range m.IPs {
m.status[ip] = false // Initial state as down
}
m.statusLock.Unlock()
ticker := time.NewTicker(time.Duration(m.Interval) * time.Second)
defer ticker.Stop()
m.checkAllIPs()
m.displayStatus()
for {
select {
case <-ticker.C:
m.checkAllIPs()
m.displayStatus()
case <-m.stopChan:
return nil
}
}
}
func (m *Monitor) Stop() {
close(m.stopChan)
}
func (m *Monitor) checkAllIPs() {
var wg sync.WaitGroup
sem := make(chan struct{}, m.Threads)
for _, ip := range m.IPs {
wg.Add(1)
sem <- struct{}{}
go func(ip string) {
defer func() {
<-sem
wg.Done()
}()
currentStatus := m.checkIP(ip)
m.updateStatus(ip, currentStatus)
}(ip)
}
wg.Wait()
}
func (m *Monitor) checkIP(ip string) bool {
for i := 0; i < m.Retry+1; i++ {
var success bool
var err error
switch m.ScanType {
case "icmp":
err = m.pinger.Ping(ip, time.Duration(m.Timeout)*time.Millisecond)
success = err == nil
case "tcp":
dialer := net.Dialer{
Timeout: time.Duration(m.Timeout) * time.Millisecond,
Control: netforward.ControlSetReUseAddr,
}
conn, err := dialer.Dial("tcp", fmt.Sprintf("%s:%d", ip, m.Port))
if err == nil {
conn.Close()
success = true
}
}
if success {
return true
}
if i < m.Retry {
time.Sleep(time.Duration(m.Timeout) * time.Millisecond / 2)
}
}
return false
}
func (m *Monitor) updateStatus(ip string, current bool) {
m.statusLock.Lock()
defer m.statusLock.Unlock()
previous := m.status[ip]
if current != previous {
m.logStatusChange(ip, previous, current)
m.status[ip] = current
}
}
func (m *Monitor) logStatusChange(ip string, from, to bool) {
statusToStr := func(s bool) string {
if s {
return "UP"
}
return "DOWN"
}
var hostname string
if m.WithHostname {
names, err := net.LookupAddr(ip)
if err == nil && len(names) > 0 {
hostname = names[0]
}
}
starlog.Infof("[Status Change] %s (%s): %s → %s\n",
ip,
hostname,
statusToStr(from),
statusToStr(to),
)
}
func (m *Monitor) displayStatus() {
fmt.Print("\033[H\033[2J") // Clear screen
fmt.Printf("Monitoring Status (%s)\n", time.Now().Format("2006-01-02 15:04:05"))
fmt.Println("======================================")
m.statusLock.RLock()
defer m.statusLock.RUnlock()
for _, ip := range m.IPs {
status := m.status[ip]
statusStr := "DOWN"
if status {
statusStr = "UP"
}
var hostname string
if m.WithHostname {
names, err := net.LookupAddr(ip)
if err == nil && len(names) > 0 {
hostname = names[0]
}
}
fmt.Printf("%-15s", ip)
if m.WithHostname {
fmt.Printf(" (%s)", hostname)
}
if statusStr == "UP" {
starlog.Green(": [%s]\n", statusStr)
} else {
starlog.Red(": [%s]\n", statusStr)
}
}
}

View File

@ -4,7 +4,6 @@ import (
"b612.me/apps/b612/netforward"
"b612.me/stario"
"b612.me/starlog"
"b612.me/starnet"
"fmt"
"math"
"net"
@ -153,6 +152,7 @@ func (s *ScanIP) ICMP() error {
}
}()
idx := 0
pinger := NewPinger(1127)
for {
ip := firstIP.String()
if ip == lastIP.String() {
@ -166,7 +166,7 @@ func (s *ScanIP) ICMP() error {
}()
defer wg.Done()
for i := 0; i < s.Retry+1; i++ {
_, err := starnet.Ping(ip, idx, time.Duration(s.Timeout)*time.Millisecond)
err := pinger.Ping(ip, time.Duration(s.Timeout)*time.Millisecond)
if err == nil {
atomic.AddInt32(&count, 1)
if s.WithHostname {

View File

@ -9,6 +9,8 @@ import (
"fmt"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal"
"math/rand"
"net"
"os"
"strings"
@ -23,6 +25,9 @@ var (
curlUrl string
serverVersion string
curlArg []string
passwds []string
allowAny bool
logPath string
)
func init() {
@ -31,6 +36,10 @@ func init() {
cmdSSHJar.Flags().StringVarP(&KeyPasswd, "passwd", "p", "", "私钥密码")
cmdSSHJar.Flags().StringVarP(&outpath, "output", "o", "", "输出文件")
cmdSSHJar.Flags().StringVarP(&serverVersion, "version", "v", "SSH-2.0-OpenSSH_8.0", "SSH版本")
cmdSSHJar.Flags().StringVarP(&curlUrl, "curl", "c", "", "Curl URL")
cmdSSHJar.Flags().StringSliceVarP(&passwds, "allow-passwds", "P", nil, "密码列表,格式:[用户名]:[密码]")
cmdSSHJar.Flags().BoolVarP(&allowAny, "allow-any", "A", false, "允许任意密码登录")
cmdSSHJar.Flags().StringVarP(&logPath, "log", "L", "", "日志文件")
}
var cmdSSHJar = &cobra.Command{
@ -38,11 +47,41 @@ var cmdSSHJar = &cobra.Command{
Short: "SSH蜜罐",
Long: "SSH蜜罐",
Run: func(cmd *cobra.Command, args []string) {
runSSHHoneyJar(listenAddr, keyFile, KeyPasswd, outpath, serverVersion)
var mypwds [][]string
for _, v := range passwds {
args := strings.SplitN(v, ":", 2)
if len(args) == 2 {
mypwds = append(mypwds, args)
}
}
runSSHHoneyJar(SSHJar{
listenAddr: listenAddr,
keyFile: keyFile,
keyPasswd: KeyPasswd,
outpath: outpath,
logpath: logPath,
version: serverVersion,
passwds: mypwds,
allowAny: allowAny,
})
},
}
func runSSHHoneyJar(listenAddr, keyFile, KeyPasswd, outpath, version string) {
type SSHJar struct {
listenAddr string
keyFile string
keyPasswd string
outpath string
logpath string
version string
passwds [][]string
allowAny bool
}
func runSSHHoneyJar(jar SSHJar) {
if jar.logpath != "" {
starlog.SetLogFile(jar.logpath, starlog.Std, true)
}
var f *os.File
var err error
if outpath != "" {
@ -56,10 +95,10 @@ func runSSHHoneyJar(listenAddr, keyFile, KeyPasswd, outpath, version string) {
defer f.Close()
defer conn.Flush()
config := &ssh.ServerConfig{
ServerVersion: version,
ServerVersion: jar.version,
// 密码验证回调函数
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
starlog.Infof("Login attempt from %s with %s %s\n", c.RemoteAddr(), c.User(), string(pass))
starlog.Infof("Login attempt from %s with %s by %s\n", c.RemoteAddr(), c.User(), string(pass))
data := []string{time.Now().Format("2006-01-02 15:04:05"), c.RemoteAddr().String(), c.User(), string(pass)}
if f != nil {
conn.Write(data)
@ -83,9 +122,30 @@ func runSSHHoneyJar(listenAddr, keyFile, KeyPasswd, outpath, version string) {
}
}()
}
perm := &ssh.Permissions{
Extensions: map[string]string{
"user": c.User(),
"passwd": string(pass),
},
}
if jar.allowAny {
return perm, nil
}
for _, v := range jar.passwds {
if c.User() == v[0] && string(pass) == v[1] {
return perm, nil
}
}
return nil, fmt.Errorf("password rejected for %q", c.User())
},
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
if jar.allowAny {
return &ssh.Permissions{
Extensions: map[string]string{
"user": conn.User(),
},
}, nil
}
return nil, fmt.Errorf("public key rejected for %q", conn.User())
},
}
@ -132,9 +192,179 @@ func runSSHHoneyJar(listenAddr, keyFile, KeyPasswd, outpath, version string) {
}
starlog.Infof("New connection from %s\n", conn.RemoteAddr())
go func(conn net.Conn) {
ssh.NewServerConn(conn, config)
conn.Close()
sConn, chans, reqs, err := ssh.NewServerConn(conn, config)
if err != nil {
starlog.Errorf("SSH handshake failed: %v\n", err)
return
}
defer sConn.Close()
defer starlog.Noticef("Connection from %s closed\n", sConn.RemoteAddr())
go ssh.DiscardRequests(reqs)
for newChannel := range chans {
if newChannel.ChannelType() != "session" {
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
continue
}
channel, requests, err := newChannel.Accept()
if err != nil {
starlog.Errorf("Failed to accept channel: %v", err)
continue
}
go handleSession(channel, requests, sConn)
}
}(conn)
}
}
func handleSession(channel ssh.Channel, requests <-chan *ssh.Request, conn *ssh.ServerConn) {
defer channel.Close()
term := terminal.NewTerminal(channel, "$ ") // 设置 shell 提示符
term.AutoCompleteCallback = nil // 禁用自动补全
for req := range requests {
switch req.Type {
case "pty-req":
// 接受伪终端请求(攻击者希望获得交互式体验)
req.Reply(true, nil)
term.SetSize( // 简单设置终端尺寸
24, // 行
80, // 列
)
case "shell":
req.Reply(true, nil)
go func() {
for {
line, err := term.ReadLine()
if err != nil {
break
}
starlog.Infof("[%s %s] Command: %s\n", conn.RemoteAddr(), conn.Permissions.Extensions["user"], line)
time.Sleep(time.Millisecond * 200)
term.Write([]byte(FakeCommand(line)))
}
}()
case "exec":
// 处理非交互式命令(如 ssh user@host 'ls -l'
var payload struct{ Command string }
ssh.Unmarshal(req.Payload, &payload)
req.Reply(true, nil)
// 记录并返回假输出
starlog.Infof("[%s %s] Exec: %s\n", conn.RemoteAddr(), conn.Permissions.Extensions["user"], payload.Command)
term.Write([]byte(FakeCommand(payload.Command)))
channel.Close()
default:
req.Reply(false, nil)
}
}
}
func FakeCommand(cmd string) string {
// 按命令类型分级模拟
switch {
//---------------- 系统信息探测类 ----------------
case strings.Contains(cmd, "uname -a"):
return "Linux core 6.1.0-21-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.90-1 (2024-05-03) x86_64 GNU/Linux\n\n"
case strings.Contains(cmd, "cat /etc/os-release"):
return `PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
`
case strings.Contains(cmd, "free -h"):
return ` total used free shared buff/cache available
Mem: 1022Gi 12Gi 3.0Gi 1.0Gi 47Gi 480Gi
Swap: 0B 0B 0B
`
//---------------- 敏感文件诱导类 ----------------
case strings.Contains(cmd, "ls /home"):
return "admin backup devops secret\n"
case strings.Contains(cmd, "ls /var/log"):
return `auth.log apache2 payment_system.log database_backup.log
`
case strings.Contains(cmd, "ls"):
return "password.txt\n"
case strings.Contains(cmd, "cat /etc/passwd"):
return `root:x:0:0:root:/root:/bin/bash
admin:x:1000:1000:,,,:/home/admin:/bin/bash
mysql:x:106:113:MySQL Server,,,:/nonexistent:/bin/false
core:x:0:0:,,,:/root:/bin/bash
`
//---------------- 网络配置诱导类 ----------------
case strings.Contains(cmd, "ifconfig") || strings.Contains(cmd, "ip addr"):
return `eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.105 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::250:56ff:fec0:8888 prefixlen 64 scopeid 0x20<link>
ether 00:50:56:c0:88:88 txqueuelen 1000 (Ethernet)
RX packets 123456 bytes 123456789 (117.7 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 98765 bytes 9876543 (9.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1000 (Local Loopback)
`
case strings.Contains(cmd, "netstat -antp"):
return `Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1234/sshd
tcp 0 0 192.168.1.105:5432 203.0.113.5:43892 ESTABLISHED 5678/postgres
tcp6 0 0 :::8080 :::* LISTEN 91011/java
`
//---------------- 凭证钓鱼类 ----------------
case strings.Contains(cmd, "mysql -u root -p"):
return "ERROR 1045 (28000): Access denied\n"
case strings.Contains(cmd, "sudo -l"):
return `Matching Defaults entries for admin on this host:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User admin may run the following commands on honeypot:
(ALL) NOPASSWD: /usr/bin/vim /etc/shadow
`
//---------------- 进程服务类 ----------------
case strings.Contains(cmd, "ps aux"):
return `USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 169020 13184 ? Ss May01 0:12 /sbin/init
admin 1234 0.3 2.1 1123456 178912 ? Sl May01 12:34 /opt/payment_system/payment_processor --debug
`
//---------------- 定制化陷阱 ----------------
case strings.Contains(cmd, "find / -name *.db"):
return `/var/lib/mysql/transactions.db
/home/backup/internal_users.db
`
case strings.Contains(cmd, "curl"):
return `<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>
`
default:
// 模糊响应增加真实感
if rand.Intn(100) > 70 { // 30%概率返回"command not found"
return "sh: command not found: " + strings.Fields(cmd)[0] + "\n"
}
return "\n"
}
}

View File

@ -3,5 +3,5 @@ package net
import "testing"
func TestSSHJar(t *testing.T) {
runSSHHoneyJar("127.0.0.1:22", "", "", "./test.csv", "")
//runSSHHoneyJar("127.0.0.1:22", "", "", "./test.csv", "")
}

View File

@ -52,6 +52,7 @@ func Traceroute(address string, bindaddr string, dns string, maxHops int, timeou
}
traceroute(address, bindaddr, maxHops, timeout, ipinfoAddr, hideIncorrect)
}
func traceroute(address string, bindaddr string, maxHops int, timeout time.Duration, ipinfoAddr string, hideIncorrect bool) {
ipinfo := net.ParseIP(address)
if ipinfo == nil {
@ -59,26 +60,46 @@ func traceroute(address string, bindaddr string, maxHops int, timeout time.Durat
return
}
var echoType icmp.Type = ipv4.ICMPTypeEcho
var exceededType icmp.Type = ipv4.ICMPTypeTimeExceeded
var replyType icmp.Type = ipv4.ICMPTypeEchoReply
var proto = 1
var network = "ip4:icmp"
var resolveIP = "ip4"
if ipinfo.To4() == nil {
network = "ip6:ipv6-icmp"
resolveIP = "ip6"
var (
echoType icmp.Type
exceededType icmp.Type
replyType icmp.Type
unreachType icmp.Type
proto int
network string
resolveIP string
isIPv4 bool
)
if ipinfo.To4() != nil {
echoType = ipv4.ICMPTypeEcho
exceededType = ipv4.ICMPTypeTimeExceeded
replyType = ipv4.ICMPTypeEchoReply
unreachType = ipv4.ICMPTypeDestinationUnreachable
proto = 1
network = "ip4:icmp"
resolveIP = "ip4"
isIPv4 = true
} else {
echoType = ipv6.ICMPTypeEchoRequest
exceededType = ipv6.ICMPTypeTimeExceeded
replyType = ipv6.ICMPTypeEchoReply
unreachType = ipv6.ICMPTypeDestinationUnreachable
proto = 58
network = "ip6:ipv6-icmp"
resolveIP = "ip6"
isIPv4 = false
}
if bindaddr == "" {
bindaddr = "0.0.0.0"
if !isIPv4 {
bindaddr = "::"
}
}
c, err := icmp.ListenPacket(network, bindaddr)
if err != nil {
fmt.Println(err)
starlog.Errorln("监听失败:", err)
return
}
defer c.Close()
@ -90,121 +111,179 @@ func traceroute(address string, bindaddr string, maxHops int, timeout time.Durat
if timeout == 0 {
timeout = time.Second * 3
}
exitfor:
for i := 1; i <= maxHops; i++ {
retry := 0
doRetry:
for ttl := 1; ttl <= maxHops; ttl++ {
if atomic.LoadInt32(&firstTargetHop) <= int32(ttl) {
return
}
dst, err := net.ResolveIPAddr(resolveIP, address)
if err != nil {
starlog.Errorln("IP地址解析失败", address, err)
starlog.Errorln("解析失败:", address, err)
return
}
if atomic.LoadInt32(&firstTargetHop) <= int32(i) {
return
}
m := icmp.Message{
// 构造ICMP报文
msg := icmp.Message{
Type: echoType, Code: 0,
Body: &icmp.Echo{
ID: i, Seq: i,
ID: ttl, // 使用TTL作为ID
Seq: ttl, // 使用TTL作为序列号
Data: []byte("B612.ME-ROUTER-TRACE"),
},
}
b, err := m.Marshal(nil)
msgBytes, err := msg.Marshal(nil)
if err != nil {
fmt.Printf("%d\tMarshal error: %v\n", i, err)
starlog.Warningf("%d\t封包失败: %v\n", ttl, err)
continue
}
// 设置TTL/HopLimit
if network == "ip4:icmp" {
if err := c.IPv4PacketConn().SetTTL(i); err != nil {
fmt.Printf("%d\tSetTTL error: %v\n", i, err)
if err := c.IPv4PacketConn().SetTTL(ttl); err != nil {
starlog.Warningf("%d\t设置TTL失败: %v\n", ttl, err)
continue
}
} else {
if err := c.IPv6PacketConn().SetHopLimit(i); err != nil {
fmt.Printf("%d\tSetHopLimit error: %v\n", i, err)
if err := c.IPv6PacketConn().SetHopLimit(ttl); err != nil {
starlog.Warningf("%d\t设置HopLimit失败: %v\n", ttl, err)
continue
}
}
start := time.Now()
n, err := c.WriteTo(b, dst)
if err != nil {
fmt.Printf("%d\tWriteTo error: %v\n", i, err)
continue
} else if n != len(b) {
fmt.Printf("%d\tWrite Short: %v Expected: %v\n", i, n, len(b))
startTime := time.Now()
if _, err := c.WriteTo(msgBytes, dst); err != nil {
starlog.Warningf("%d\t发送失败: %v\n", ttl, err)
continue
}
now := time.Now()
exitrecheck:
for {
reply := make([]byte, 1500)
err = c.SetReadDeadline(time.Now().Add(timeout))
if err != nil {
fmt.Printf("%d\tSetReadDeadline error: %v\n", i, err)
break
}
n, peer, err := c.ReadFrom(reply)
if err != nil {
fmt.Printf("%d\tReadFrom error: %v\n", i, err)
break
}
duration := time.Since(start)
// 接收响应处理
timeoutCh := time.After(timeout)
responsesReceived := 0
rm, err := icmp.ParseMessage(proto, reply[:n])
if err != nil {
fmt.Printf("%d\tParseMessage error: %v\n", i, err)
break
}
switch rm.Type {
case exceededType:
fmt.Printf("%d\thops away:\t%s\t(%s) %s\n", i, peer, duration, GetIPInfo(peer.String(), ipinfoAddr))
break exitrecheck
case replyType:
fmt.Printf("%d\thops away:\t%s\t(%s) %s\n", i, peer, duration, GetIPInfo(peer.String(), ipinfoAddr))
if peer.String() == dst.String() {
break exitfor
}
case ipv4.ICMPTypeEcho, ipv6.ICMPTypeEchoRequest:
if time.Now().Sub(now).Seconds() > timeout.Seconds() {
if retry < 1 {
retry++
goto doRetry
}
if !hideIncorrect {
fmt.Printf("%d\tInvalid Echo Request:%s (%s) %s\n", i, peer, duration, GetIPInfo(peer.String(), ipinfoAddr))
}
break exitrecheck
}
case ipv4.ICMPTypeDestinationUnreachable, ipv6.ICMPTypeDestinationUnreachable:
if time.Now().Sub(now).Seconds() > timeout.Seconds() {
if retry < 1 {
retry++
goto doRetry
}
if !hideIncorrect {
fmt.Printf("%d\tInvalid DstInv Request:%s (%s) %s\n", i, peer, duration, GetIPInfo(peer.String(), ipinfoAddr))
}
break exitrecheck
recvLoop:
for responsesReceived < 3 {
select {
case <-timeoutCh:
if responsesReceived == 0 {
fmt.Printf("%d\t*\n", ttl)
}
break recvLoop
default:
if time.Now().Sub(now).Seconds() > timeout.Seconds() {
if retry < 1 {
retry++
goto doRetry
reply := make([]byte, 1500)
if err := c.SetReadDeadline(time.Now().Add(50 * time.Millisecond)); err != nil {
break recvLoop
}
n, peer, err := c.ReadFrom(reply)
if err != nil {
if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
continue
}
if !hideIncorrect {
fmt.Printf("%d\tgot %+v from %v (%s) %s\n", i, rm.Type, peer, duration, GetIPInfo(peer.String(), ipinfoAddr))
starlog.Debugf("%d\t接收错误: %v", ttl, err)
continue
}
// 解析响应
rm, err := icmp.ParseMessage(proto, reply[:n])
if err != nil {
starlog.Debugf("%d\t解析错误: %v", ttl, err)
continue
}
// 验证响应匹配
if match := checkResponseMatch(rm, ttl, peer.String() == dst.String(), isIPv4, exceededType, replyType, unreachType); match {
duration := time.Since(startTime)
fmt.Printf("%d\t%s\t%s\t%s\n",
ttl,
peer,
duration.Round(time.Millisecond),
GetIPInfo(peer.String(), ipinfoAddr),
)
responsesReceived++
if peer.String() == dst.String() {
atomic.StoreInt32(&firstTargetHop, int32(ttl))
break exitfor
}
break exitrecheck
}
}
}
}
}
func checkResponseMatch(rm *icmp.Message, ttl int, isFinal bool, isIPv4 bool,
exceededType, replyType, unreachType icmp.Type) bool {
switch {
case rm.Type == exceededType:
if body, ok := rm.Body.(*icmp.TimeExceeded); ok {
return validateOriginalPacket(body.Data, ttl, isIPv4)
}
case rm.Type == replyType:
if isFinal {
if body, ok := rm.Body.(*icmp.Echo); ok {
return body.ID == ttl && body.Seq == ttl
}
}
return false
case rm.Type == unreachType:
if body, ok := rm.Body.(*icmp.DstUnreach); ok {
return validateOriginalPacket(body.Data, ttl, isIPv4)
}
}
return false
}
func validateOriginalPacket(data []byte, ttl int, isIPv4 bool) bool {
var (
proto byte
header []byte
)
if isIPv4 {
if len(data) < 20+8 {
return false
}
ihl := data[0] & 0x0F
if ihl < 5 {
return false
}
proto = data[9]
header = data[:ihl*4]
} else {
if len(data) < 40+8 {
return false
}
proto = data[6]
header = data[:40]
}
if proto != 1 && proto != 58 {
return false
}
payload := data[len(header):]
if len(payload) < 8 {
return false
}
if isIPv4 {
return payload[0] == 8 && // ICMP Echo Request
payload[4] == byte(ttl>>8) &&
payload[5] == byte(ttl) &&
payload[6] == byte(ttl>>8) &&
payload[7] == byte(ttl)
} else {
return payload[0] == 128 && // ICMPv6 Echo Request
payload[4] == byte(ttl>>8) &&
payload[5] == byte(ttl) &&
payload[6] == byte(ttl>>8) &&
payload[7] == byte(ttl)
}
}
@ -213,16 +292,23 @@ func GetIPInfo(ip string, addr string) string {
return ""
}
uri := strings.ReplaceAll(addr, "{ip}", ip)
res, err := starnet.Curl(starnet.NewSimpleRequest(uri, "GET", starnet.WithTimeout(time.Second*2), starnet.WithDialTimeout(time.Second*3)))
res, err := starnet.Curl(starnet.NewSimpleRequest(uri, "GET",
starnet.WithTimeout(time.Second*2),
starnet.WithDialTimeout(time.Second*3)))
if err != nil {
return "获取IP信息失败" + err.Error()
return "IP信息获取失败"
}
var ipinfo IPInfo
err = res.Body().Unmarshal(&ipinfo)
if err != nil {
return "解析IP信息失败" + err.Error()
if err := res.Body().Unmarshal(&ipinfo); err != nil {
return "IP信息解析失败"
}
return fmt.Sprintf("%s %s %s %s %s", ipinfo.CountryName, ipinfo.RegionName, ipinfo.CityName, ipinfo.OwnerDomain, ipinfo.ISP)
return fmt.Sprintf("%s %s %s",
ipinfo.CountryName,
ipinfo.RegionName,
ipinfo.ISP)
}
type IPInfo struct {

View File

@ -1,28 +0,0 @@
package nmon
import (
"fmt"
"github.com/shirou/gopsutil/v4/cpu"
"time"
)
func Cpu() {
go func() {
flat, err := cpu.Percent(time.Second, false)
if err != nil {
return
}
fmt.Println(flat)
}()
flat, err := cpu.Percent(time.Second, true)
if err != nil {
return
}
c := 0.0000
for _, v := range flat {
c += v
}
fmt.Println(flat)
fmt.Println(c / float64(len(flat)))
time.Sleep(time.Millisecond * 200)
}

View File

@ -1,7 +0,0 @@
package nmon
import "testing"
func TestCpu(t *testing.T) {
Cpu()
}

409
nmon/mon.go Normal file
View File

@ -0,0 +1,409 @@
package nmon
import (
"fmt"
"os"
"sync"
"time"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
"github.com/shirou/gopsutil/v4/cpu"
"github.com/shirou/gopsutil/v4/disk"
"github.com/shirou/gopsutil/v4/load"
"github.com/shirou/gopsutil/v4/mem"
"github.com/shirou/gopsutil/v4/net"
"github.com/spf13/cobra"
)
var (
refreshInterval time.Duration
savePath string
app *tview.Application
showCores bool
noTUI bool
diskIOHistory = make(map[string]disk.IOCountersStat)
netStats = make(map[string]*NetStat)
fileMutex sync.Mutex
)
type NetStat struct {
LastBytesSent uint64
LastBytesRecv uint64
LastTime time.Time
CurrentSentRate float64
CurrentRecvRate float64
}
var Cmd = &cobra.Command{
Use: "nmon",
Short: "System Monitoring Tool",
Run: func(cmd *cobra.Command, args []string) {
if noTUI {
runTextMode()
return
}
startTUI()
},
}
func init() {
Cmd.Flags().BoolVarP(&noTUI, "no-tui", "t", false, "Run in text mode")
Cmd.Flags().BoolVarP(&showCores, "cores", "c", false, "Show per-core CPU usage")
Cmd.Flags().DurationVarP(&refreshInterval, "interval", "i", time.Second, "Refresh interval")
Cmd.Flags().StringVarP(&savePath, "save", "s", "", "Save monitoring data to file (nmon format)")
}
func main() {
if err := Cmd.Execute(); err != nil {
fmt.Println(err)
}
}
func createClickableTextView(title string) *tview.TextView {
view := tview.NewTextView().SetDynamicColors(true)
view.SetBorder(true).SetTitle(title)
return view
}
func startTUI() {
app = tview.NewApplication()
flex := tview.NewFlex().SetDirection(tview.FlexRow)
cpuView := tview.NewTextView().SetDynamicColors(true)
memView := tview.NewTextView().SetDynamicColors(true)
netView := tview.NewTextView().SetDynamicColors(true)
diskView := tview.NewTextView().SetDynamicColors(true)
// 动态布局更新函数
ioStats, _ := disk.IOCounters()
updateLayout := func() {
flex.Clear()
cpuLines := 2 // 固定基础2行CPU Load + Load Avg
if showCores {
perCPU, _ := cpu.Percent(0, true)
cpuLines = 2 + len(perCPU)
}
flex.AddItem(cpuView, cpuLines, 1, false)
flex.AddItem(memView, 3, 1, false)
flex.AddItem(diskView, len(ioStats), 1, false)
flex.AddItem(netView, 3, 1, false)
}
// 初始化数据
updateLayout()
app.SetMouseCapture(func(event *tcell.EventMouse, action tview.MouseAction) (*tcell.EventMouse, tview.MouseAction) {
// 示例:打印点击坐标
if action == tview.MouseLeftClick {
showCores = !showCores
app.QueueUpdateDraw(updateLayout)
}
return event, action
})
go updateLoop(cpuView, memView, netView, diskView)
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
if event.Key() == tcell.KeyCtrlC {
app.Stop()
}
return event
})
if err := app.SetRoot(flex, true).Run(); err != nil {
panic(err)
}
}
func updateLoop(cpuView, memView, netView, diskView *tview.TextView) {
var lastSave time.Time
for {
app.QueueUpdateDraw(func() {
updateCPU(cpuView)
updateMemory(memView)
updateNetwork(netView)
updateDiskIO(diskView)
})
if savePath != "" && time.Since(lastSave) > time.Minute {
go saveNMONData()
lastSave = time.Now()
}
time.Sleep(refreshInterval)
}
}
func updateCPU(view *tview.TextView) {
percent, _ := cpu.Percent(time.Second, false)
loadAvg, _ := load.Avg()
text := fmt.Sprintf("[red]CPU Load: [white]%.2f%%\n[red]Load Avg: [white]%.2f, %.2f, %.2f",
percent[0],
loadAvg.Load1,
loadAvg.Load5,
loadAvg.Load15)
if showCores {
perCPU, _ := cpu.Percent(time.Second, true)
for i, p := range perCPU {
text += fmt.Sprintf("\nCore %d: [green]%s[white] %.2f%%",
i+1,
progressBar(p, 20),
p)
}
}
view.SetText(text)
}
func updateMemory(view *tview.TextView) {
memStat, _ := mem.VirtualMemory()
text := fmt.Sprintf("[red]Memory: [white]%.2f%% Used (%.2f GB / %.2f GB)",
memStat.UsedPercent,
float64(memStat.Used)/1024/1024/1024,
float64(memStat.Total)/1024/1024/1024)
view.SetText(text + "\n" + progressBar(memStat.UsedPercent, 50))
}
func updateNetwork(view *tview.TextView) {
interfaces, _ := net.IOCounters(true)
now := time.Now()
var totalSent, totalRecv float64
for _, iface := range interfaces {
if iface.Name == "lo" {
continue
}
stat, exists := netStats[iface.Name]
if !exists {
stat = &NetStat{
LastBytesSent: iface.BytesSent,
LastBytesRecv: iface.BytesRecv,
LastTime: now,
}
netStats[iface.Name] = stat
continue
}
timeDiff := now.Sub(stat.LastTime).Seconds()
sentDiff := float64(iface.BytesSent - stat.LastBytesSent)
recvDiff := float64(iface.BytesRecv - stat.LastBytesRecv)
stat.CurrentSentRate = sentDiff / timeDiff
stat.CurrentRecvRate = recvDiff / timeDiff
stat.LastBytesSent = iface.BytesSent
stat.LastBytesRecv = iface.BytesRecv
stat.LastTime = now
totalSent += stat.CurrentSentRate
totalRecv += stat.CurrentRecvRate
}
view.SetText(fmt.Sprintf("[red]Network: [white]↑%s ↓%s",
formatSpeed(totalSent),
formatSpeed(totalRecv)))
}
func updateDiskIO(view *tview.TextView) {
ioStats, _ := disk.IOCounters()
text := "[red]Disk I/O:\n"
for name, io := range ioStats {
last, exists := diskIOHistory[name]
if exists {
interval := float64(refreshInterval.Seconds())
readSpeed := float64(io.ReadBytes-last.ReadBytes) / interval
writeSpeed := float64(io.WriteBytes-last.WriteBytes) / interval
text += fmt.Sprintf(" %-8s R:%s W:%s\n",
name,
formatSpeed(readSpeed),
formatSpeed(writeSpeed))
}
diskIOHistory[name] = io
}
view.SetText(text)
}
func progressBar(percent float64, width int) string {
filled := int(percent / 100 * float64(width))
bar := "[green]"
for i := 0; i < width; i++ {
if i < filled {
bar += "■"
} else {
bar += "□"
}
}
return bar + "[white]"
}
func formatSpeed(speed float64) string {
const (
KB = 1024
MB = KB * 1024
)
switch {
case speed >= MB:
return fmt.Sprintf("%7.3f MB/s", speed/MB)
case speed >= KB:
return fmt.Sprintf("%7.3f KB/s", speed/KB)
default:
return fmt.Sprintf("%7.3f B/s", speed)
}
}
func saveNMONData() {
fileMutex.Lock()
defer fileMutex.Unlock()
f, err := os.OpenFile(savePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return
}
defer f.Close()
now := time.Now().Format("2006-01-02 15:04:05")
cpuPercent, _ := cpu.Percent(0, false)
memStat, _ := mem.VirtualMemory()
ioStats, _ := disk.IOCounters()
fmt.Fprintf(f, "%s,CPU_ALL,%.2f\n", now, cpuPercent[0])
fmt.Fprintf(f, "%s,MEM,%.2f,%.2f\n", now, memStat.UsedPercent, memStat.Available)
for name, io := range ioStats {
fmt.Fprintf(f, "%s,DISKIO,%s,%d,%d\n",
now, name, io.ReadBytes, io.WriteBytes)
}
}
// 文本模式相关函数
func runTextMode() {
ticker := time.NewTicker(refreshInterval)
defer ticker.Stop()
for {
fmt.Println(getCPUInfo())
fmt.Println(getMemoryInfo())
fmt.Println(getNetworkInfo())
fmt.Println(getDiskIOInfo())
if savePath != "" {
go saveNMONData()
}
<-ticker.C
}
}
// 数据获取函数
func getCPUInfo() string {
percent, _ := cpu.Percent(time.Second, false)
loadAvg, _ := load.Avg()
fmt.Print("\033[H\033[2J")
fmt.Println("=== System Monitor ===")
text := fmt.Sprintf("[CPU]\nLoad: %.2f%% Avg: %.2f, %.2f, %.2f",
percent[0],
loadAvg.Load1,
loadAvg.Load5,
loadAvg.Load15)
if showCores {
perCPU, _ := cpu.Percent(time.Second, true)
for i, p := range perCPU {
text += fmt.Sprintf("\nCore %d: %s %.2f%%",
i+1,
textProgressBar(p, 20),
p)
}
}
return text
}
func getMemoryInfo() string {
memStat, _ := mem.VirtualMemory()
return fmt.Sprintf("[Memory]\nUsed: %.2f%% (%.2fG/%.2fG)\n%s",
memStat.UsedPercent,
float64(memStat.Used)/1024/1024/1024,
float64(memStat.Total)/1024/1024/1024,
textProgressBar(memStat.UsedPercent, 50))
}
func getNetworkInfo() string {
interfaces, _ := net.IOCounters(true)
now := time.Now()
var sent, recv float64
for _, iface := range interfaces {
if iface.Name == "lo" {
continue
}
stat, exists := netStats[iface.Name]
if !exists {
stat = &NetStat{
LastBytesSent: iface.BytesSent,
LastBytesRecv: iface.BytesRecv,
LastTime: now,
}
netStats[iface.Name] = stat
continue
}
timeDiff := now.Sub(stat.LastTime).Seconds()
sentDiff := float64(iface.BytesSent - stat.LastBytesSent)
recvDiff := float64(iface.BytesRecv - stat.LastBytesRecv)
stat.CurrentSentRate = sentDiff / timeDiff
stat.CurrentRecvRate = recvDiff / timeDiff
stat.LastBytesSent = iface.BytesSent
stat.LastBytesRecv = iface.BytesRecv
stat.LastTime = now
sent += stat.CurrentSentRate
recv += stat.CurrentRecvRate
}
return fmt.Sprintf("[Network]\nUpload: %s\nDownload: %s",
formatSpeed(sent),
formatSpeed(recv))
}
func getDiskIOInfo() string {
ioStats, _ := disk.IOCounters()
text := "[Disk I/O]"
for name, io := range ioStats {
last, exists := diskIOHistory[name]
if exists {
interval := float64(refreshInterval.Seconds())
read := float64(io.ReadBytes-last.ReadBytes) / interval
write := float64(io.WriteBytes-last.WriteBytes) / interval
text += fmt.Sprintf("\n%-8s Read: %s Write: %s",
name,
formatSpeed(read),
formatSpeed(write))
}
diskIOHistory[name] = io
}
return text
}
func textProgressBar(percent float64, width int) string {
filled := int(percent / 100 * float64(width))
bar := ""
for i := 0; i < width; i++ {
if i < filled {
bar += "■"
} else {
bar += "□"
}
}
return bar
}

View File

@ -845,7 +845,7 @@ func sendIPv6(srcIP, srcPort, dstIP, dstPort string, seq uint32, isSyn bool) err
return err
}
addr := syscall.SockaddrInet6{
Port: dPort,
Port: 0,
Addr: [16]byte(dstNetIP.To16()),
}
return syscall.Sendto(fd, buffer.Bytes(), 0, &addr)

View File

@ -365,7 +365,7 @@ func sendIPv6(srcIP, srcPort, dstIP, dstPort string, seq uint32, isSyn bool) err
return err
}
addr := syscall.SockaddrInet6{
Port: dPort,
Port: 0,
Addr: [16]byte(dstNetIP.To16()),
}
return syscall.Sendto(fd, buffer.Bytes(), 0, &addr)

View File

@ -3,5 +3,5 @@ package tls
import "testing"
func TestCert(t *testing.T) {
showTls("139.199.163.65:443", true, "")
//showTls("139.199.163.65:443", true, "")
}

View File

@ -1,3 +1,3 @@
package version
var Version = "2.1.0.beta.16"
var Version = "2.1.0.beta.17"