init
commit
1ea024e28f
@ -0,0 +1,2 @@
|
|||||||
|
bin
|
||||||
|
.idea
|
@ -0,0 +1,20 @@
|
|||||||
|
package aes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"b612.me/starcrypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_EncodeStr(t *testing.T) {
|
||||||
|
//fmt.Println(EncodeStr("我喜欢你", "sakurasaiteruyogugugug"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_DecodeStr(t *testing.T) {
|
||||||
|
//fmt.Println(DecodeStr("Z_8aILbog@Kjm$P", "sakurasaiteruyogugugug"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Base91(t *testing.T) {
|
||||||
|
fmt.Println(starcrypto.Base91EncodeToString([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}))
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package base91
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"b612.me/starcrypto"
|
||||||
|
"b612.me/starlog"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Cmd = &cobra.Command{
|
||||||
|
Use: "base91",
|
||||||
|
Short: "使用base91处理文件或字符串",
|
||||||
|
Long: "使用base91处理文件或字符串",
|
||||||
|
Run: func(this *cobra.Command, args []string) {
|
||||||
|
de, _ := this.Flags().GetBool("decode")
|
||||||
|
if len(args) != 1 {
|
||||||
|
starlog.Criticalln("参数不足,请输入文件地址或字符串")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !de {
|
||||||
|
data := starcrypto.Base91EncodeToString([]byte(args[0]))
|
||||||
|
fmt.Println(data)
|
||||||
|
} else {
|
||||||
|
var data []byte
|
||||||
|
data = starcrypto.Base91DecodeString(args[0])
|
||||||
|
fmt.Println(string(data))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Cmd.Flags().StringP("out", "o", "", "指定加解码输出地址")
|
||||||
|
Cmd.Flags().BoolP("decode", "d", false, "base91解码")
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
mkdir bin
|
||||||
|
set GOOS=windows
|
||||||
|
set GOARCH=amd64
|
||||||
|
go build -o .\bin\b612_x86_64.exe -ldflags "-w -s" .
|
||||||
|
upx -9 .\bin\b612_x86_64.exe
|
||||||
|
set GOARCH=386
|
||||||
|
go build -o .\bin\b612_x86.exe -ldflags "-w -s" .
|
||||||
|
upx -9 .\bin\b612_x86.exe
|
||||||
|
set GOARCH=arm64
|
||||||
|
go build -o .\bin\b612_arm64.exe -ldflags "-w -s" .
|
||||||
|
upx -9 .\bin\b612_arm64.exe
|
||||||
|
set GOOS=linux
|
||||||
|
set GOARCH=amd64
|
||||||
|
go build -o .\bin\b612_x86_64 -ldflags "-w -s" .
|
||||||
|
upx -9 .\bin\b612_x86_64
|
||||||
|
set GOARCH=386
|
||||||
|
go build -o .\bin\b612_x86 -ldflags "-w -s" .
|
||||||
|
upx -9 .\bin\b612_x86
|
||||||
|
set GOARCH=arm64
|
||||||
|
go build -o .\bin\b612_arm64 -ldflags "-w -s" .
|
||||||
|
upx -9 .\bin\b612_arm64
|
||||||
|
set GOARCH=mips
|
||||||
|
go build -o .\bin\b612_mips -ldflags "-w -s" .
|
||||||
|
set GOARCH=mipsle
|
||||||
|
go build -o .\bin\b612_mipsle -ldflags "-w -s" .
|
||||||
|
set GOARCH=mips64
|
||||||
|
go build -o .\bin\b612_mips64 -ldflags "-w -s" .
|
||||||
|
set GOARCH=mips64le
|
||||||
|
go build -o .\bin\b612_mips64le -ldflags "-w -s" .
|
||||||
|
set GOOS=darwin
|
||||||
|
set GOARCH=amd64
|
||||||
|
go build -o .\bin\b612_darwin_x64 -ldflags "-w -s" .
|
||||||
|
upx -9 .\bin\b612_darwin_x64
|
||||||
|
set GOARCH=arm64
|
||||||
|
go build -o .\bin\b612_darwin_arm64 -ldflags "-w -s" .
|
||||||
|
upx -9 .\bin\b612_darwin_arm64
|
||||||
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
|||||||
|
package detach
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/starcrypto"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"b612.me/starlog"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Cmd = &cobra.Command{
|
||||||
|
Use: "detach",
|
||||||
|
Short: "分离两个文件",
|
||||||
|
Long: "分离两个文件",
|
||||||
|
Run: func(this *cobra.Command, args []string) {
|
||||||
|
var src, dst, out string
|
||||||
|
if len(args) == 3 {
|
||||||
|
src = args[0]
|
||||||
|
dst = args[1]
|
||||||
|
out = args[2]
|
||||||
|
} else {
|
||||||
|
src, _ = this.Flags().GetString("src")
|
||||||
|
dst, _ = this.Flags().GetString("dst")
|
||||||
|
out, _ = this.Flags().GetString("out")
|
||||||
|
}
|
||||||
|
num, _ := this.Flags().GetInt("num")
|
||||||
|
if src == "" || dst == "" {
|
||||||
|
starlog.Criticalln("ERROR PATH")
|
||||||
|
this.Help()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := starcrypto.Detach(src, num, dst, out)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Criticalln(err.Error)
|
||||||
|
} else {
|
||||||
|
fmt.Println("完成")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Cmd.Flags().StringP("src", "s", "", "源文件路径")
|
||||||
|
Cmd.Flags().StringP("dst", "d", "", "目标文件路径1")
|
||||||
|
Cmd.Flags().StringP("out", "o", "", "目标文件路径2")
|
||||||
|
Cmd.Flags().IntP("num", "n", 0, "分割开始字节")
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
package df
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/starlog"
|
||||||
|
"b612.me/staros"
|
||||||
|
"b612.me/wincmd/ntfs/mft"
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Cmd = &cobra.Command{
|
||||||
|
Use: "df",
|
||||||
|
Short: "分析nfts磁盘文件占用",
|
||||||
|
Long: "分析nfts磁盘文件占用",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
os.Exit(folderSize("./"))
|
||||||
|
}
|
||||||
|
os.Exit(folderSize(args[0]))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func folderSize(path string) int {
|
||||||
|
fullPath, err := filepath.Abs(path)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Criticalln("filepath not a vaild path", path, err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
vol := filepath.VolumeName(fullPath) + `\`
|
||||||
|
fmt.Println(vol)
|
||||||
|
if staros.IsFile(fullPath) {
|
||||||
|
fullPath = filepath.Dir(fullPath)
|
||||||
|
}
|
||||||
|
fmt.Println("consider folder is", fullPath)
|
||||||
|
folderLists, err := ioutil.ReadDir(fullPath)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Criticalln("read folder failed", err)
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
targetFolders := make(map[string]uint64)
|
||||||
|
for _, v := range folderLists {
|
||||||
|
if v.IsDir() {
|
||||||
|
//fmt.Println(filepath.Join(fullPath, v.Name()))
|
||||||
|
targetFolders[filepath.Join(fullPath, v.Name())] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileLists, err := mft.GetFileListsByMft(vol)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("read mft failed", err)
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
var totalSize uint64
|
||||||
|
var fc1, fc2 int
|
||||||
|
for _, v := range fileLists {
|
||||||
|
if strings.Contains(v.Path, fullPath) {
|
||||||
|
if v.IsDir {
|
||||||
|
fc2++
|
||||||
|
} else {
|
||||||
|
fc1++
|
||||||
|
}
|
||||||
|
totalSize += v.Aszie
|
||||||
|
}
|
||||||
|
for k, _ := range targetFolders {
|
||||||
|
if strings.Contains(v.Path, k) {
|
||||||
|
targetFolders[k] += v.Aszie
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getSize := func(size uint64) string {
|
||||||
|
floatSize := float64(size)
|
||||||
|
var sizeC = []string{"byte", "KB", "MB", "GB", "TB"}
|
||||||
|
if floatSize < 1024 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
if floatSize/math.Pow(1024, float64(i+1)) < 1024 {
|
||||||
|
return fmt.Sprintf("%.4f%s", floatSize/math.Pow(1024, float64(i+1)), sizeC[i+1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
target := sortMapByValue(targetFolders)
|
||||||
|
for _, v := range target {
|
||||||
|
fmt.Printf("%-20s %-10d %s\n", v.Key, v.Value, getSize(v.Value))
|
||||||
|
}
|
||||||
|
fmt.Printf("%-20s %-10d %s\n", fullPath, totalSize, getSize(totalSize))
|
||||||
|
fmt.Println("file count:", fc1, "folder count:", fc2)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pair struct {
|
||||||
|
Key string
|
||||||
|
Value uint64
|
||||||
|
}
|
||||||
|
type PairList []Pair
|
||||||
|
|
||||||
|
func (p PairList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||||
|
func (p PairList) Len() int { return len(p) }
|
||||||
|
func (p PairList) Less(i, j int) bool { return p[i].Value < p[j].Value }
|
||||||
|
|
||||||
|
func sortMapByValue(m map[string]uint64) PairList {
|
||||||
|
p := make(PairList, len(m))
|
||||||
|
i := 0
|
||||||
|
for k, v := range m {
|
||||||
|
p[i] = Pair{k, v}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
sort.Sort(p)
|
||||||
|
return p
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
package dfinder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/starlog"
|
||||||
|
"b612.me/staros"
|
||||||
|
"b612.me/wincmd/ntfs/mft"
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dfpath, dfreg, dfoutpath string
|
||||||
|
var dfonlyname, dfshow bool
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Cmd.Flags().StringVarP(&dfoutpath, "outpath", "o", "", "outpath")
|
||||||
|
Cmd.Flags().StringVarP(&dfpath, "path", "p", "./", "path you want to search")
|
||||||
|
Cmd.Flags().StringVarP(&dfreg, "regexp", "r", ".*", "search regexp")
|
||||||
|
Cmd.Flags().BoolVarP(&dfonlyname, "only-filter-name", "f", false, "only regexp for name not path")
|
||||||
|
Cmd.Flags().BoolVarP(&dfshow, "show", "s", true, "show on the stdout")
|
||||||
|
}
|
||||||
|
|
||||||
|
var Cmd = &cobra.Command{
|
||||||
|
Use: "dfinder",
|
||||||
|
Short: "查找nfts磁盘文件",
|
||||||
|
Long: "查找nfts磁盘文件",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
os.Exit(fileFinder(dfpath, dfreg, dfonlyname, dfoutpath, dfshow))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileFinder(path string, reg string, onlyFilterName bool, outpath string, show bool) int {
|
||||||
|
fullPath, err := filepath.Abs(path)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Criticalln("filepath not a vaild path", path, err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
vol := filepath.VolumeName(fullPath) + `\`
|
||||||
|
fmt.Println(vol)
|
||||||
|
if staros.IsFile(fullPath) {
|
||||||
|
fullPath = filepath.Dir(fullPath)
|
||||||
|
}
|
||||||
|
fmt.Println("consider folder is", fullPath)
|
||||||
|
|
||||||
|
fileLists, err := mft.GetFileListsByMftFn(vol, func(name string, isFolder bool) bool {
|
||||||
|
if isFolder {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if onlyFilterName {
|
||||||
|
if matched, _ := regexp.MatchString(reg, name); matched {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("read mft failed", err)
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
getSize := func(size uint64) string {
|
||||||
|
floatSize := float64(size)
|
||||||
|
var sizeC = []string{"byte", "KB", "MB", "GB", "TB"}
|
||||||
|
if floatSize < 1024 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
if floatSize/math.Pow(1024, float64(i+1)) < 1024 {
|
||||||
|
return fmt.Sprintf("%.4f%s", floatSize/math.Pow(1024, float64(i+1)), sizeC[i+1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
fp := new(os.File)
|
||||||
|
if outpath != "" {
|
||||||
|
fp, err = os.Create(outpath)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Criticalln(err)
|
||||||
|
} else {
|
||||||
|
defer fp.Close()
|
||||||
|
fp.WriteString(`名称,路径,大小,大小(格式化),修改时间,是否是文件夹` + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newReg := regexp.MustCompile(reg)
|
||||||
|
for _, v := range fileLists {
|
||||||
|
if !strings.Contains(v.Path, fullPath) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if onlyFilterName {
|
||||||
|
if show {
|
||||||
|
fmt.Printf("name:%-10s path:%-20s size:%-10s modTime:%v\n", v.Name, v.Path, getSize(v.Size), v.ModTime)
|
||||||
|
}
|
||||||
|
if fp != nil {
|
||||||
|
fp.WriteString(fmt.Sprintf("%s,%s,%v,%s,%v,%v\n", v.Name, v.Path, v.Size, getSize(v.Size), v.ModTime, v.IsDir))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if newReg.MatchString(v.Path) {
|
||||||
|
if show {
|
||||||
|
fmt.Printf("name:%-10s path:%-20s size:%-10s modTime:%v\n", v.Name, v.Path, getSize(v.Size), v.ModTime)
|
||||||
|
}
|
||||||
|
if fp != nil {
|
||||||
|
fp.WriteString(fmt.Sprintf("%s,%s,%v,%s,%v,%v\n", v.Name, v.Path, v.Size, getSize(v.Size), v.ModTime, v.IsDir))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
module b612.me/apps/b612
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require (
|
||||||
|
b612.me/notify v1.2.4
|
||||||
|
b612.me/starcrypto v0.0.2
|
||||||
|
b612.me/stario v0.0.8
|
||||||
|
b612.me/starlog v1.3.2
|
||||||
|
b612.me/staros v1.1.6
|
||||||
|
b612.me/starssh v0.0.2
|
||||||
|
b612.me/startext v0.0.0-20220314043758-22c6d5e5b1cd
|
||||||
|
b612.me/wincmd v0.0.2
|
||||||
|
github.com/goftp/file-driver v0.0.0-20180502053751-5d604a0fc0c9
|
||||||
|
github.com/goftp/server v0.0.0-20200708154336-f64f7c2d8a42
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||||
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||||
|
github.com/spf13/cobra v1.6.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
b612.me/starmap v1.2.3 // indirect
|
||||||
|
b612.me/starnet v0.1.7 // indirect
|
||||||
|
b612.me/win32api v0.0.1 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||||
|
github.com/jlaffaye/ftp v0.1.0 // indirect
|
||||||
|
github.com/kr/fs v0.1.0 // indirect
|
||||||
|
github.com/pkg/sftp v1.13.4 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/stretchr/testify v1.8.0 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 // indirect
|
||||||
|
golang.org/x/image v0.6.0 // indirect
|
||||||
|
golang.org/x/sys v0.5.0 // indirect
|
||||||
|
golang.org/x/term v0.5.0 // indirect
|
||||||
|
golang.org/x/text v0.8.0 // indirect
|
||||||
|
)
|
@ -0,0 +1,108 @@
|
|||||||
|
b612.me/notify v1.2.4 h1:cjP80V9FeM+ib1DztZdykusakcbjNI4dAB1pXE8U6bo=
|
||||||
|
b612.me/notify v1.2.4/go.mod h1:SlCrG1kPRVhYUrIkwY/j0zAwCU4VeTHubcZoQXW8Anw=
|
||||||
|
b612.me/starcrypto v0.0.2 h1:aRf1HcqK8GqHYxLAhWfFC4W/EqQLEFNEmxsBu3wG30o=
|
||||||
|
b612.me/starcrypto v0.0.2/go.mod h1:hz0xRnfWNpYOlVrIPoGrQOWPibq4YiUZ7qN5tsQbzPo=
|
||||||
|
b612.me/stario v0.0.7/go.mod h1:or4ssWcxQSjMeu+hRKEgtp0X517b3zdlEOAms8Qscvw=
|
||||||
|
b612.me/stario v0.0.8 h1:kaA4pszAKLZJm2D9JmiuYSpgjTeE3VaO74vm+H0vBGM=
|
||||||
|
b612.me/stario v0.0.8/go.mod h1:or4ssWcxQSjMeu+hRKEgtp0X517b3zdlEOAms8Qscvw=
|
||||||
|
b612.me/starlog v1.3.2 h1:bFUJyZEpcOcBwPlzlhPBwlYxq7aDcR8pJNoaDk+SUNE=
|
||||||
|
b612.me/starlog v1.3.2/go.mod h1:bxSvBSzlJoLfrZJ5b9CJFuQaXjFi8PYUbGWitNO1FYA=
|
||||||
|
b612.me/starmap v1.2.3 h1:+ao++KgbSGMA4UzcHm/EXJoukbUudk8t5ac7rjwV9KA=
|
||||||
|
b612.me/starmap v1.2.3/go.mod h1:K+exTSWg8i/taoUyGR6DPW6Ja0k6aIdpcniqByOf4O0=
|
||||||
|
b612.me/starnet v0.1.7 h1:k3CUfYNRolC/xw5Ekus2NVWHlqeykSyAH8USGTPKA5o=
|
||||||
|
b612.me/starnet v0.1.7/go.mod h1:DNC4i/ezgVLlmxnquf8AeljsL4mQ5vAyxh8vGPQqsys=
|
||||||
|
b612.me/staros v1.1.6 h1:m3QaEmPyvPcJVomjWs8cDeauDYFNKv7cLHTiOHClKqM=
|
||||||
|
b612.me/staros v1.1.6/go.mod h1:O657LC3qag4VSsHNmt5RM8gKJvzoEGq8IF8WegcRgq0=
|
||||||
|
b612.me/starssh v0.0.2 h1:cYlrXjd7ZTesdZG+7XcoLsEEMROaeWMTYonScBLnvyY=
|
||||||
|
b612.me/starssh v0.0.2/go.mod h1:1gvG/GT5Y5EvOx9ZKnLFUa+wOX20HaqS1IuTnU7BOlk=
|
||||||
|
b612.me/startext v0.0.0-20220314043758-22c6d5e5b1cd h1:EsmnczYZhOV8JTxD/m0N0qBjfZN8JuLNrTJ6z3S8YqA=
|
||||||
|
b612.me/startext v0.0.0-20220314043758-22c6d5e5b1cd/go.mod h1:yKdeLQHZ3scqyjw1ZODCoL+hLmkOp2eu5riP4agraz8=
|
||||||
|
b612.me/win32api v0.0.1 h1:vLFB1xhO6pd9+zB2EyaapKB459Urv3v+C1YwgwOFEWo=
|
||||||
|
b612.me/win32api v0.0.1/go.mod h1:MHu0JBQjzxQ2yxpZPUBbn5un45o67eF5iWKa4Q9e0yE=
|
||||||
|
b612.me/wincmd v0.0.2 h1:Ub1WtelVT6a3vD4B6zDYo3UPO/t9ymnI3x1dQPJcrGw=
|
||||||
|
b612.me/wincmd v0.0.2/go.mod h1:bwpyCKfSDY8scSMo3Lrd0Qnqvpz7/CILL7oodfG0wgo=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/goftp/file-driver v0.0.0-20180502053751-5d604a0fc0c9 h1:cC0Hbb+18DJ4i6ybqDybvj4wdIDS4vnD0QEci98PgM8=
|
||||||
|
github.com/goftp/file-driver v0.0.0-20180502053751-5d604a0fc0c9/go.mod h1:GpOj6zuVBG3Inr9qjEnuVTgBlk2lZ1S9DcoFiXWyKss=
|
||||||
|
github.com/goftp/server v0.0.0-20200708154336-f64f7c2d8a42 h1:JdOp2qR5PF4O75tzHeqrwnDDv8oHDptWyTbyYS4fD8E=
|
||||||
|
github.com/goftp/server v0.0.0-20200708154336-f64f7c2d8a42/go.mod h1:k/SS6VWkxY7dHPhoMQ8IdRu8L4lQtmGbhyXGg+vCnXE=
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
|
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||||
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/jlaffaye/ftp v0.1.0 h1:DLGExl5nBoSFoNshAUHwXAezXwXBvFdx7/qwhucWNSE=
|
||||||
|
github.com/jlaffaye/ftp v0.1.0/go.mod h1:hhq4G4crv+nW2qXtNYcuzLeOudG92Ps37HEKeg2e3lE=
|
||||||
|
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
|
||||||
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||||
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||||
|
github.com/pkg/sftp v1.13.4 h1:Lb0RYJCmgUcBgZosfoi9Y9sbl6+LJgOIgk/2Y4YjMFg=
|
||||||
|
github.com/pkg/sftp v1.13.4/go.mod h1:LzqnAvaD5TWeNBsZpfKxSYn1MbjWwOsCIAFFJbpIsK8=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
||||||
|
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s=
|
||||||
|
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
|
golang.org/x/image v0.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4=
|
||||||
|
golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||||
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
@ -0,0 +1,15 @@
|
|||||||
|
[web1]
|
||||||
|
addr=0.0.0.0
|
||||||
|
port=9999
|
||||||
|
key=C:\\tech\b612.me.key
|
||||||
|
cert=C:\\tech\b612.me.cer
|
||||||
|
enablessl=true
|
||||||
|
reverse=/::https://www.b612.me
|
||||||
|
replace=www.b612.me::127.0.0.1:9999
|
||||||
|
inheader=Accept-Encoding::none
|
||||||
|
host=b612.me
|
||||||
|
authuser=b612
|
||||||
|
authpasswd=b612
|
||||||
|
whiteip=
|
||||||
|
blackip=
|
||||||
|
wanringpage=
|
@ -0,0 +1,92 @@
|
|||||||
|
package httpreverse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/starlog"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
)
|
||||||
|
|
||||||
|
var remote, config string
|
||||||
|
var addr, key, cert, log string
|
||||||
|
var port int
|
||||||
|
var enablessl bool
|
||||||
|
var host string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Cmd.Flags().StringVarP(&host, "host", "H", "", "host字段")
|
||||||
|
Cmd.Flags().StringVarP(&remote, "remote", "r", "", "反向代理地址")
|
||||||
|
Cmd.Flags().StringVarP(&config, "config", "C", "", "配置文件地址")
|
||||||
|
Cmd.Flags().StringVarP(&addr, "addr", "a", "0.0.0.0", "监听地址")
|
||||||
|
Cmd.Flags().StringVarP(&key, "key", "k", "", "ssl key地址")
|
||||||
|
Cmd.Flags().StringVarP(&cert, "cert", "c", "", "ssl 证书地址")
|
||||||
|
Cmd.Flags().StringVarP(&log, "log", "l", "", "log日志地址")
|
||||||
|
Cmd.Flags().BoolVarP(&enablessl, "enable-ssl", "s", false, "启用ssl")
|
||||||
|
Cmd.Flags().IntVarP(&port, "port", "p", 8080, "监听端口")
|
||||||
|
}
|
||||||
|
|
||||||
|
var Cmd = &cobra.Command{
|
||||||
|
Use: "hproxy",
|
||||||
|
Short: "Http Reverse Proxy(Http反向代理)",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if log != "" {
|
||||||
|
starlog.SetLogFile(log, starlog.Std, true)
|
||||||
|
}
|
||||||
|
if config != "" {
|
||||||
|
r, err := Parse(config)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
sig := make(chan os.Signal)
|
||||||
|
signal.Notify(sig, os.Kill, os.Interrupt)
|
||||||
|
starlog.Noticeln("Stop Due to Recv Siganl", <-sig)
|
||||||
|
r.Close()
|
||||||
|
}()
|
||||||
|
err = r.Run()
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("Http Reverse Proxy Exit Error", err)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
starlog.Infoln("Http Reverse Proxy Exit Normally")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if remote == "" {
|
||||||
|
starlog.Errorln("please enter the reverse url")
|
||||||
|
os.Exit(4)
|
||||||
|
}
|
||||||
|
u, err := url.Parse(remote)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln(err)
|
||||||
|
os.Exit(3)
|
||||||
|
}
|
||||||
|
reverse := ReverseConfig{
|
||||||
|
Name: "web",
|
||||||
|
Addr: addr,
|
||||||
|
Host: host,
|
||||||
|
ReverseURL: map[string]*url.URL{
|
||||||
|
"/": u,
|
||||||
|
},
|
||||||
|
Port: port,
|
||||||
|
UsingSSL: enablessl,
|
||||||
|
Key: key,
|
||||||
|
Cert: cert,
|
||||||
|
XForwardMode: 1,
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
sig := make(chan os.Signal)
|
||||||
|
signal.Notify(sig, os.Kill, os.Interrupt)
|
||||||
|
starlog.Noticeln("Stop Due to Recv Siganl", <-sig)
|
||||||
|
reverse.Close()
|
||||||
|
}()
|
||||||
|
err = reverse.Run()
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("Http Reverse Proxy Exit Error", err)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
starlog.Infoln("Http Reverse Proxy Exit Normally")
|
||||||
|
return
|
||||||
|
},
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
package httpreverse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IPCIDR(ip string) (string, int, error) {
|
||||||
|
if !strings.Contains(ip, "/") {
|
||||||
|
return ip, 32, nil
|
||||||
|
}
|
||||||
|
tmp := strings.Split(ip, "/")
|
||||||
|
cidr, err := strconv.Atoi(tmp[1])
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, err
|
||||||
|
}
|
||||||
|
intIp, err := IP2Int(tmp[0])
|
||||||
|
if err != nil {
|
||||||
|
return "", 0, err
|
||||||
|
}
|
||||||
|
ip, err = Int2IP(int((uint32(intIp) >> (32 - cidr)) << (32 - cidr)))
|
||||||
|
return ip, cidr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func IPEnd(ip string, cidr int) (string, error) {
|
||||||
|
intIp, err := IP2Int(ip)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
ip, err = Int2IP(int(uint32(intIp) | ((uint32(4294967295) << cidr) >> cidr)))
|
||||||
|
return ip, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func IPStart(ip string, cidr int) (string, error) {
|
||||||
|
intIp, err := IP2Int(ip)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
ip, err = Int2IP(int((uint32(intIp) >> (32 - cidr)) << (32 - cidr)))
|
||||||
|
return ip, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func IPInRange(cidrip, ip string) (bool, error) {
|
||||||
|
w, c, err := IPCIDR(cidrip)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
f, _, err := IPCIDR(ip + "/" + strconv.Itoa(c))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return w == f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func IPinRange2(startIP string, cidr int, ip string) (bool, error) {
|
||||||
|
f, _, err := IPCIDR(ip + "/" + strconv.Itoa(cidr))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return startIP == f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func IP2Int(ipAddr string) (int, error) {
|
||||||
|
var ipNum uint32 = 0
|
||||||
|
ipFilter := strings.Split(ipAddr, ".")
|
||||||
|
for i := 0; i < len(ipFilter); i++ {
|
||||||
|
num, err := strconv.ParseUint(ipFilter[len(ipFilter)-1-i], 10, 32)
|
||||||
|
ipNum |= (uint32(num) << (8 * uint32(i)))
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return int(ipNum), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Int2IP(intIP int) (string, error) {
|
||||||
|
var result string
|
||||||
|
var ip uint32
|
||||||
|
ip = uint32(intIP)
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
result += strconv.FormatUint(uint64(uint8(ip>>uint8((3-i)*8))), 10) + "."
|
||||||
|
}
|
||||||
|
return result[0 : len(result)-1], nil
|
||||||
|
}
|
@ -0,0 +1,174 @@
|
|||||||
|
package httpreverse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/staros/sysconf"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ReverseConfig struct {
|
||||||
|
Name string
|
||||||
|
Addr string
|
||||||
|
ReverseURL map[string]*url.URL
|
||||||
|
Port int
|
||||||
|
UsingSSL bool
|
||||||
|
Key string
|
||||||
|
Cert string
|
||||||
|
Host string
|
||||||
|
InHeader [][2]string
|
||||||
|
OutHeader [][2]string
|
||||||
|
Cookie [][3]string //[3]string should contains path::key::value
|
||||||
|
ReplaceList [][2]string
|
||||||
|
ReplaceOnce bool
|
||||||
|
proxy map[string]*httputil.ReverseProxy
|
||||||
|
XForwardMode int //0=off 1=useremote 2=add
|
||||||
|
httpmux http.ServeMux
|
||||||
|
httpserver http.Server
|
||||||
|
|
||||||
|
basicAuthUser string
|
||||||
|
basicAuthPwd string
|
||||||
|
protectAuthPage []string
|
||||||
|
blackip map[string]int
|
||||||
|
whiteip map[string]int
|
||||||
|
warningpage string
|
||||||
|
warnpagedata []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type HttpReverseServer struct {
|
||||||
|
Config []*ReverseConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func Parse(path string) (HttpReverseServer, error) {
|
||||||
|
var res HttpReverseServer
|
||||||
|
ini := sysconf.NewIni()
|
||||||
|
err := ini.ParseFromFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
for _, v := range ini.Data {
|
||||||
|
var ins = ReverseConfig{
|
||||||
|
Name: v.Name,
|
||||||
|
Host: v.Get("host"),
|
||||||
|
Addr: v.Get("addr"),
|
||||||
|
Port: v.Int("port"),
|
||||||
|
UsingSSL: v.Bool("enablessl"),
|
||||||
|
Key: v.Get("key"),
|
||||||
|
Cert: v.Get("cert"),
|
||||||
|
ReplaceOnce: v.Bool("replaceonce"),
|
||||||
|
XForwardMode: v.Int("xforwardmode"),
|
||||||
|
basicAuthUser: v.Get("authuser"),
|
||||||
|
basicAuthPwd: v.Get("authpasswd"),
|
||||||
|
warningpage: v.Get("warnpage"),
|
||||||
|
}
|
||||||
|
if ins.warningpage != "" {
|
||||||
|
data, err := ioutil.ReadFile(ins.warningpage)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
ins.warnpagedata = data
|
||||||
|
}
|
||||||
|
ins.proxy = make(map[string]*httputil.ReverseProxy)
|
||||||
|
ins.ReverseURL = make(map[string]*url.URL)
|
||||||
|
for _, reverse := range v.GetAll("reverse") {
|
||||||
|
kv := strings.SplitN(reverse, "::", 2)
|
||||||
|
if len(kv) != 2 {
|
||||||
|
return res, errors.New("reverse settings not correct:" + reverse)
|
||||||
|
}
|
||||||
|
ins.ReverseURL[strings.TrimSpace(kv[0])], err = url.Parse(strings.TrimSpace(kv[1]))
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, header := range v.GetAll("inheader") {
|
||||||
|
kv := strings.SplitN(header, "::", 2)
|
||||||
|
if len(kv) != 2 {
|
||||||
|
return res, errors.New("header settings not correct:" + header)
|
||||||
|
}
|
||||||
|
ins.InHeader = append(ins.InHeader, [2]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1])})
|
||||||
|
}
|
||||||
|
for _, authpage := range v.GetAll("authpage") {
|
||||||
|
ins.protectAuthPage = append(ins.protectAuthPage, authpage)
|
||||||
|
}
|
||||||
|
ins.blackip = make(map[string]int)
|
||||||
|
for _, blackip := range v.GetAll("blackip") {
|
||||||
|
ip, cidr, err := IPCIDR(blackip)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
ins.blackip[ip] = cidr
|
||||||
|
}
|
||||||
|
ins.whiteip = make(map[string]int)
|
||||||
|
for _, whiteip := range v.GetAll("whiteip") {
|
||||||
|
ip, cidr, err := IPCIDR(whiteip)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
ins.whiteip[ip] = cidr
|
||||||
|
}
|
||||||
|
for _, header := range v.GetAll("outheader") {
|
||||||
|
kv := strings.SplitN(header, "::", 2)
|
||||||
|
if len(kv) != 2 {
|
||||||
|
return res, errors.New("header settings not correct:" + header)
|
||||||
|
}
|
||||||
|
ins.OutHeader = append(ins.OutHeader, [2]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1])})
|
||||||
|
}
|
||||||
|
for _, cookie := range v.GetAll("cookie") {
|
||||||
|
kv := strings.SplitN(cookie, "::", 3)
|
||||||
|
if len(kv) != 3 {
|
||||||
|
return res, errors.New("cookie settings not correct:" + cookie)
|
||||||
|
}
|
||||||
|
ins.Cookie = append(ins.Cookie, [3]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]), strings.TrimSpace(kv[2])})
|
||||||
|
}
|
||||||
|
for _, replace := range v.GetAll("replace") {
|
||||||
|
kv := strings.SplitN(replace, "::", 2)
|
||||||
|
if len(kv) != 2 {
|
||||||
|
return res, errors.New("replace settings not correct:" + replace)
|
||||||
|
}
|
||||||
|
ins.ReplaceList = append(ins.ReplaceList, [2]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1])})
|
||||||
|
}
|
||||||
|
res.Config = append(res.Config, &ins)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpReverseServer) Run() error {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
var mu sync.Mutex
|
||||||
|
var haveErr string
|
||||||
|
for _, v := range h.Config {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(v *ReverseConfig) {
|
||||||
|
defer wg.Done()
|
||||||
|
err := v.Run()
|
||||||
|
if err != nil {
|
||||||
|
mu.Lock()
|
||||||
|
haveErr += err.Error() + "\n"
|
||||||
|
mu.Unlock()
|
||||||
|
}
|
||||||
|
}(v)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
if haveErr != "" {
|
||||||
|
return errors.New(haveErr)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpReverseServer) Close() error {
|
||||||
|
var haveErr string
|
||||||
|
for _, v := range h.Config {
|
||||||
|
err := v.Close()
|
||||||
|
if err != nil {
|
||||||
|
haveErr += err.Error() + "\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if haveErr != "" {
|
||||||
|
return errors.New(haveErr)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package httpreverse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReverseParse(t *testing.T) {
|
||||||
|
data, err := Parse("./cfg.ini")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("%+v\n", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReverse(t *testing.T) {
|
||||||
|
data, err := Parse("./cfg.ini")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("%+v\n", data)
|
||||||
|
data.Run()
|
||||||
|
}
|
@ -0,0 +1,262 @@
|
|||||||
|
package httpreverse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/starlog"
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var version = "2.0.1"
|
||||||
|
|
||||||
|
func (h *ReverseConfig) Run() error {
|
||||||
|
err := h.init()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for key, proxy := range h.proxy {
|
||||||
|
h.httpmux.HandleFunc(key, func(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
starlog.Infof("<%s> Req Path:%s Addr:%s UA:%s\n", h.Name, request.URL.Path, request.RemoteAddr, request.Header.Get("User-Agent"))
|
||||||
|
|
||||||
|
if !h.BasicAuth(writer, request) {
|
||||||
|
h.SetResponseHeader(writer)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !h.filter(writer, request) {
|
||||||
|
h.SetResponseHeader(writer)
|
||||||
|
writer.WriteHeader(403)
|
||||||
|
if len(h.warnpagedata) != 0 {
|
||||||
|
writer.Write(h.warnpagedata)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writer.Write([]byte(`
|
||||||
|
<html>
|
||||||
|
<head><title>403 Forbidden</title></head>
|
||||||
|
<body>
|
||||||
|
<center><h1>403 Forbidden</h1></center>
|
||||||
|
<center><h3>You Are Not Allowed to Access This Page</h3></center>
|
||||||
|
<center><h3>Please Contact Site Administrator For Help</h3></center>
|
||||||
|
<hr><center>B612 HTTP REVERSE SERVER</center>
|
||||||
|
</body>
|
||||||
|
</html>`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
proxy.ServeHTTP(writer, request)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
h.httpserver = http.Server{
|
||||||
|
Addr: fmt.Sprintf("%s:%d", h.Addr, h.Port),
|
||||||
|
Handler: &h.httpmux,
|
||||||
|
}
|
||||||
|
starlog.Infoln(h.Name + " Listening on " + h.Addr + ":" + strconv.Itoa(h.Port))
|
||||||
|
if !h.UsingSSL {
|
||||||
|
if err := h.httpserver.ListenAndServe(); err != http.ErrServerClosed {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if h.httpserver.ListenAndServeTLS(h.Cert, h.Key); err != http.ErrServerClosed {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ReverseConfig) Close() error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
return h.httpserver.Shutdown(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ReverseConfig) init() error {
|
||||||
|
h.proxy = make(map[string]*httputil.ReverseProxy)
|
||||||
|
for key, val := range h.ReverseURL {
|
||||||
|
h.proxy[key] = httputil.NewSingleHostReverseProxy(val)
|
||||||
|
h.proxy[key].ModifyResponse = h.ModifyResponse()
|
||||||
|
originalDirector := h.proxy[key].Director
|
||||||
|
h.proxy[key].Director = func(req *http.Request) {
|
||||||
|
originalDirector(req)
|
||||||
|
h.ModifyRequest(req, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ReverseConfig) SetResponseHeader(resp http.ResponseWriter) {
|
||||||
|
resp.Header().Set("X-Powered-By", "B612.ME")
|
||||||
|
resp.Header().Set("Server", "B612/"+version)
|
||||||
|
resp.Header().Set("X-Proxy", "B612 Reverse Proxy")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ReverseConfig) ModifyResponse() func(*http.Response) error {
|
||||||
|
return func(resp *http.Response) error {
|
||||||
|
for _, v := range h.OutHeader {
|
||||||
|
resp.Header.Set(v[0], v[1])
|
||||||
|
}
|
||||||
|
resp.Header.Del("X-Powered-By")
|
||||||
|
resp.Header.Del("Server")
|
||||||
|
resp.Header.Del("X-Proxy")
|
||||||
|
resp.Header.Set("X-Powered-By", "B612.ME")
|
||||||
|
resp.Header.Set("Server", "B612/"+version)
|
||||||
|
resp.Header.Set("X-Proxy", "B612 Reverse Proxy")
|
||||||
|
if len(h.ReplaceList) != 0 && resp.ContentLength <= 20*1024*1024 && strings.Contains(resp.Header.Get("Content-Type"), "text") {
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
strBody := string(body)
|
||||||
|
replaceCount := -1
|
||||||
|
if h.ReplaceOnce {
|
||||||
|
replaceCount = 1
|
||||||
|
}
|
||||||
|
for _, v := range h.ReplaceList {
|
||||||
|
strBody = strings.Replace(strBody, v[0], v[1], replaceCount)
|
||||||
|
}
|
||||||
|
body = []byte(strBody)
|
||||||
|
resp.Body = ioutil.NopCloser(bytes.NewReader(body))
|
||||||
|
resp.ContentLength = int64(len(body))
|
||||||
|
resp.Header.Set("Content-Length", strconv.Itoa(len(body)))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ReverseConfig) ModifyRequest(req *http.Request, remote *url.URL) {
|
||||||
|
if h.XForwardMode == 1 {
|
||||||
|
req.Header.Set("X-Forwarded-For", strings.Split(req.RemoteAddr, ":")[0])
|
||||||
|
} else if h.XForwardMode == 2 {
|
||||||
|
xforward := strings.Split(strings.TrimSpace(req.Header.Get("X-Forwarded-For")), ",")
|
||||||
|
xforward = append(xforward, strings.Split(req.RemoteAddr, ":")[0])
|
||||||
|
req.Header.Set("X-Forwarded-For", strings.Join(xforward, ", "))
|
||||||
|
}
|
||||||
|
for _, v := range h.Cookie {
|
||||||
|
req.AddCookie(&http.Cookie{
|
||||||
|
Name: v[1],
|
||||||
|
Value: v[2],
|
||||||
|
Path: v[0],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
host := h.Host
|
||||||
|
if host == "" {
|
||||||
|
host = remote.Host
|
||||||
|
}
|
||||||
|
targetQuery := remote.RawQuery
|
||||||
|
req.URL.Scheme = remote.Scheme
|
||||||
|
req.URL.Host = remote.Host
|
||||||
|
req.Host = host
|
||||||
|
req.URL.Path, req.URL.RawPath = joinURLPath(remote, req.URL)
|
||||||
|
if targetQuery == "" || req.URL.RawQuery == "" {
|
||||||
|
req.URL.RawQuery = targetQuery + req.URL.RawQuery
|
||||||
|
} else {
|
||||||
|
req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
|
||||||
|
}
|
||||||
|
for _, v := range h.InHeader {
|
||||||
|
req.Header.Set(v[0], v[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ReverseConfig) GiveBasicAuth(w http.ResponseWriter) {
|
||||||
|
w.Header().Set("WWW-Authenticate", ` Basic realm="Please Enter Passwd"`)
|
||||||
|
w.WriteHeader(401)
|
||||||
|
w.Write([]byte(`
|
||||||
|
<html>
|
||||||
|
<head><title>401 Authorization Required</title></head>
|
||||||
|
<body>
|
||||||
|
<center><h1>401 Authorization Required</h1></center>
|
||||||
|
<hr><center>B612 HTTP SERVER</center>
|
||||||
|
</body>
|
||||||
|
</html>`))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ReverseConfig) BasicAuth(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
if h.basicAuthPwd != "" {
|
||||||
|
if len(h.protectAuthPage) != 0 {
|
||||||
|
for _, v := range h.protectAuthPage {
|
||||||
|
if !(strings.Index(r.URL.Path, v) == 0 || strings.Contains(r.URL.RawQuery, v)) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
authHeader := strings.TrimSpace(r.Header.Get("Authorization"))
|
||||||
|
if len(authHeader) == 0 {
|
||||||
|
h.GiveBasicAuth(w)
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
userAuth := base64.StdEncoding.EncodeToString([]byte(h.basicAuthUser + ":" + h.basicAuthPwd))
|
||||||
|
authStr := strings.Split(authHeader, " ")
|
||||||
|
if strings.TrimSpace(authStr[1]) != userAuth || strings.ToLower(strings.TrimSpace(authStr[0])) != "basic" {
|
||||||
|
h.GiveBasicAuth(w)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *ReverseConfig) filter(w http.ResponseWriter, r *http.Request) bool {
|
||||||
|
if len(h.blackip) == 0 && len(h.whiteip) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if len(h.whiteip) != 0 {
|
||||||
|
if _, ok := h.whiteip[strings.Split(r.RemoteAddr, ":")[0]]; ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for k, v := range h.whiteip {
|
||||||
|
if match, _ := IPinRange2(k, v, strings.Split(r.RemoteAddr, ":")[0]); match {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if _, ok := h.blackip[strings.Split(r.RemoteAddr, ":")[0]]; ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for k, v := range h.blackip {
|
||||||
|
if match, _ := IPinRange2(k, v, strings.Split(r.RemoteAddr, ":")[0]); match {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func joinURLPath(a, b *url.URL) (path, rawpath string) {
|
||||||
|
if a.RawPath == "" && b.RawPath == "" {
|
||||||
|
return singleJoiningSlash(a.Path, b.Path), ""
|
||||||
|
}
|
||||||
|
// Same as singleJoiningSlash, but uses EscapedPath to determine
|
||||||
|
// whether a slash should be added
|
||||||
|
apath := a.EscapedPath()
|
||||||
|
bpath := b.EscapedPath()
|
||||||
|
|
||||||
|
aslash := strings.HasSuffix(apath, "/")
|
||||||
|
bslash := strings.HasPrefix(bpath, "/")
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case aslash && bslash:
|
||||||
|
return a.Path + b.Path[1:], apath + bpath[1:]
|
||||||
|
case !aslash && !bslash:
|
||||||
|
return a.Path + "/" + b.Path, apath + "/" + bpath
|
||||||
|
}
|
||||||
|
return a.Path + b.Path, apath + bpath
|
||||||
|
}
|
||||||
|
|
||||||
|
func singleJoiningSlash(a, b string) string {
|
||||||
|
aslash := strings.HasSuffix(a, "/")
|
||||||
|
bslash := strings.HasPrefix(b, "/")
|
||||||
|
switch {
|
||||||
|
case aslash && bslash:
|
||||||
|
return a + b[1:]
|
||||||
|
case !aslash && !bslash:
|
||||||
|
return a + "/" + b
|
||||||
|
}
|
||||||
|
return a + b
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,193 @@
|
|||||||
|
package image
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/staros"
|
||||||
|
"errors"
|
||||||
|
"image"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/golang/freetype"
|
||||||
|
|
||||||
|
"github.com/nfnt/resize"
|
||||||
|
|
||||||
|
"image/color"
|
||||||
|
"image/draw"
|
||||||
|
_ "image/gif"
|
||||||
|
_ "image/jpeg"
|
||||||
|
"image/png"
|
||||||
|
_ "image/png"
|
||||||
|
)
|
||||||
|
|
||||||
|
func OpenImage(name string) (image.Image, error) {
|
||||||
|
if !staros.Exists(name) {
|
||||||
|
return nil, errors.New("File Not Exists")
|
||||||
|
}
|
||||||
|
fso, err := os.Open(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
img, _, err := image.Decode(fso)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return img, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func MergePhoto(big, small image.Image, bigsize, smallsize uint, x, y int) image.Image {
|
||||||
|
big = resize.Resize(bigsize, bigsize, big, resize.Lanczos3)
|
||||||
|
small = resize.Resize(smallsize, smallsize, small, resize.Lanczos3)
|
||||||
|
offset := image.Pt(x, y)
|
||||||
|
b := big.Bounds()
|
||||||
|
nimg := image.NewRGBA(b)
|
||||||
|
draw.Draw(nimg, b, big, image.ZP, draw.Src)
|
||||||
|
draw.Draw(nimg, small.Bounds(), small, offset, draw.Over)
|
||||||
|
return nimg
|
||||||
|
}
|
||||||
|
|
||||||
|
func SavePhoto(path string, img image.Image) error {
|
||||||
|
imgf, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer imgf.Close()
|
||||||
|
return png.Encode(imgf, img)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetAlpha(img image.Image, alpha uint8) image.Image {
|
||||||
|
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()
|
||||||
|
r = r >> 8
|
||||||
|
g = g >> 8
|
||||||
|
b = b >> 8
|
||||||
|
a = a >> 8
|
||||||
|
nimg.Set(x, y, color.NRGBA{uint8(r), uint8(g), uint8(b), alpha})
|
||||||
|
//nimg.Set(x, y, color.Alpha{alpha})
|
||||||
|
//nimg.Set(x, y, img.At(x, y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nimg
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddText(text string, img image.Image, x, y int, dpi, size float64, colors color.RGBA, ttf string) (image.Image, error) {
|
||||||
|
if !staros.Exists(ttf) {
|
||||||
|
return nil, errors.New("File Not Exists")
|
||||||
|
}
|
||||||
|
fontbyte, err := ioutil.ReadFile(ttf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
font, err := freetype.ParseFont(fontbyte)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nimg, ok := img.(draw.Image)
|
||||||
|
if !ok {
|
||||||
|
size := img.Bounds()
|
||||||
|
nimg = image.NewRGBA(img.Bounds())
|
||||||
|
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(r), uint8(g), uint8(b), uint8(a)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f := freetype.NewContext()
|
||||||
|
f.SetDPI(dpi)
|
||||||
|
f.SetFontSize(size)
|
||||||
|
f.SetFont(font)
|
||||||
|
f.SetClip(nimg.Bounds())
|
||||||
|
f.SetDst(nimg)
|
||||||
|
f.SetSrc(image.NewUniform(colors))
|
||||||
|
_, err = f.DrawString(text, freetype.Pt(x, y))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nimg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextImg struct {
|
||||||
|
Text string
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
Dpi float64
|
||||||
|
Size float64
|
||||||
|
Color color.NRGBA
|
||||||
|
}
|
||||||
|
|
||||||
|
type TextList struct {
|
||||||
|
List []TextImg
|
||||||
|
TTF []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddListTests(list TextList, img image.Image) (image.Image, error) {
|
||||||
|
font, err := freetype.ParseFont(list.TTF)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nimg, ok := img.(draw.Image)
|
||||||
|
if !ok {
|
||||||
|
size := img.Bounds()
|
||||||
|
nimg = image.NewRGBA(img.Bounds())
|
||||||
|
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(r), uint8(g), uint8(b), uint8(a)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, v := range list.List {
|
||||||
|
f := freetype.NewContext()
|
||||||
|
f.SetDPI(v.Dpi)
|
||||||
|
f.SetFontSize(v.Size)
|
||||||
|
f.SetFont(font)
|
||||||
|
f.SetClip(nimg.Bounds())
|
||||||
|
f.SetDst(nimg)
|
||||||
|
f.SetSrc(image.NewUniform(v.Color))
|
||||||
|
_, err = f.DrawString(v.Text, freetype.Pt(v.X, v.Y))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nimg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddTexts(text string, img image.Image, x, y int, dpi, size float64, colors color.NRGBA, ttf string) (image.Image, error) {
|
||||||
|
if !staros.Exists(ttf) {
|
||||||
|
return nil, errors.New("File Not Exists")
|
||||||
|
}
|
||||||
|
fontbyte, err := ioutil.ReadFile(ttf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
font, err := freetype.ParseFont(fontbyte)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nimg, ok := img.(draw.Image)
|
||||||
|
if !ok {
|
||||||
|
size := img.Bounds()
|
||||||
|
nimg = image.NewRGBA(img.Bounds())
|
||||||
|
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(r), uint8(g), uint8(b), uint8(a)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f := freetype.NewContext()
|
||||||
|
f.SetDPI(dpi)
|
||||||
|
f.SetFontSize(size)
|
||||||
|
f.SetFont(font)
|
||||||
|
f.SetClip(nimg.Bounds())
|
||||||
|
f.SetDst(nimg)
|
||||||
|
f.SetSrc(image.NewUniform(colors))
|
||||||
|
_, err = f.DrawString(text, freetype.Pt(x, y))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nimg, nil
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package image
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
|
||||||
|
"b612.me/starlog"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Cmd.AddCommand(imgMirrorCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var Cmd = &cobra.Command{
|
||||||
|
Use: "image",
|
||||||
|
Short: "图像处理",
|
||||||
|
Long: "简单的图像处理工具",
|
||||||
|
Run: func(this *cobra.Command, args []string) {
|
||||||
|
this.Help()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var imgMirrorCmd = &cobra.Command{
|
||||||
|
Use: "mirror",
|
||||||
|
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++ {
|
||||||
|
nimg.Set(size.Dx()-x, y, img.At(x, y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := SavePhoto(v, nimg); err != nil {
|
||||||
|
starlog.Errorln(err, v)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
fmt.Println(v, "转换已完成!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("任务完成!")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var imgAlpha = &cobra.Command{
|
||||||
|
Use: "alpha",
|
||||||
|
Short: "设置透明度",
|
||||||
|
Long: "设置alpha通道透明度",
|
||||||
|
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
|
||||||
|
}
|
||||||
|
img = SetAlpha(img, 4)
|
||||||
|
if err := SavePhoto(v, img); err != nil {
|
||||||
|
starlog.Errorln(err, v)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
fmt.Println(v, "转换已完成!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("任务完成!")
|
||||||
|
},
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/apps/b612/attach"
|
||||||
|
"b612.me/apps/b612/base64"
|
||||||
|
"b612.me/apps/b612/base85"
|
||||||
|
"b612.me/apps/b612/base91"
|
||||||
|
"b612.me/apps/b612/detach"
|
||||||
|
"b612.me/apps/b612/df"
|
||||||
|
"b612.me/apps/b612/dfinder"
|
||||||
|
"b612.me/apps/b612/ftp"
|
||||||
|
"b612.me/apps/b612/generate"
|
||||||
|
"b612.me/apps/b612/hash"
|
||||||
|
"b612.me/apps/b612/httpreverse"
|
||||||
|
"b612.me/apps/b612/httpserver"
|
||||||
|
"b612.me/apps/b612/image"
|
||||||
|
"b612.me/apps/b612/merge"
|
||||||
|
"b612.me/apps/b612/search"
|
||||||
|
"b612.me/apps/b612/split"
|
||||||
|
"b612.me/apps/b612/tcping"
|
||||||
|
"b612.me/apps/b612/uac"
|
||||||
|
"b612.me/apps/b612/vic"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cmdRoot = &cobra.Command{
|
||||||
|
Use: "b612",
|
||||||
|
Version: "2.0.1",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cmdRoot.AddCommand(tcping.Cmd, uac.Cmd, httpserver.Cmd, httpreverse.Cmd,
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmdRoot.Execute()
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
package net
|
@ -0,0 +1,213 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/starlog"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NetForward struct {
|
||||||
|
LocalAddr string
|
||||||
|
LocalPort int
|
||||||
|
RemoteURI string
|
||||||
|
EnableTCP bool
|
||||||
|
EnableUDP bool
|
||||||
|
DialTimeout time.Duration
|
||||||
|
UDPTimeout time.Duration
|
||||||
|
stopCtx context.Context
|
||||||
|
stopFn context.CancelFunc
|
||||||
|
running int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetForward) Close() {
|
||||||
|
n.stopFn()
|
||||||
|
}
|
||||||
|
func (n *NetForward) Run() error {
|
||||||
|
if !atomic.CompareAndSwapInt32(&n.running, 0, 1) {
|
||||||
|
return errors.New("already running")
|
||||||
|
}
|
||||||
|
n.stopCtx, n.stopFn = context.WithCancel(context.Background())
|
||||||
|
if n.DialTimeout == 0 {
|
||||||
|
n.DialTimeout = time.Second * 10
|
||||||
|
}
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
if n.EnableTCP {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
n.runTCP()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.EnableUDP {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
n.runUDP()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetForward) runTCP() error {
|
||||||
|
listen, err := net.Listen("tcp", fmt.Sprintf("%s:%d", n.LocalAddr, n.LocalPort))
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("Listening On Tcp Failed:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
<-n.stopCtx.Done()
|
||||||
|
listen.Close()
|
||||||
|
}()
|
||||||
|
starlog.Infof("Listening TCP on %v\n", fmt.Sprintf("%s:%d", n.LocalAddr, n.LocalPort))
|
||||||
|
for {
|
||||||
|
conn, err := listen.Accept()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log := starlog.Std.NewFlag()
|
||||||
|
log.Infof("Accept New TCP Conn from %v\n", conn.RemoteAddr().String())
|
||||||
|
go func(conn net.Conn) {
|
||||||
|
rmt, err := net.DialTimeout("tcp", n.RemoteURI, n.DialTimeout)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Dial Remote %s Failed:%v\n", n.RemoteURI, err)
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Infof("Connect %s <==> %s\n", conn.RemoteAddr().String(), n.RemoteURI)
|
||||||
|
Copy(rmt, conn)
|
||||||
|
log.Noticef("Connection Closed %s <==> %s", conn.RemoteAddr().String(), n.RemoteURI)
|
||||||
|
}(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type UDPConn struct {
|
||||||
|
net.Conn
|
||||||
|
listen *net.UDPConn
|
||||||
|
remoteAddr *net.UDPAddr
|
||||||
|
lastbeat int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UDPConn) Write(p []byte) (n int, err error) {
|
||||||
|
u.lastbeat = time.Now().Unix()
|
||||||
|
return u.Conn.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UDPConn) Read(p []byte) (n int, err error) {
|
||||||
|
u.lastbeat = time.Now().Unix()
|
||||||
|
return u.Conn.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UDPConn) Work() {
|
||||||
|
buf := make([]byte, 8192)
|
||||||
|
for {
|
||||||
|
count, err := u.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
u.Close()
|
||||||
|
u.lastbeat = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = u.listen.Write(buf[0:count])
|
||||||
|
if err != nil {
|
||||||
|
u.lastbeat = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetForward) runUDP() error {
|
||||||
|
var mu sync.RWMutex
|
||||||
|
udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%v", n.LocalAddr, n.LocalPort))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
listen, err := net.ListenUDP("udp", udpAddr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
starlog.Infof("Listening UDP on %v\n", fmt.Sprintf("%s:%d", n.LocalAddr, n.LocalPort))
|
||||||
|
go func() {
|
||||||
|
<-n.stopCtx.Done()
|
||||||
|
listen.Close()
|
||||||
|
}()
|
||||||
|
udpMap := make(map[string]UDPConn)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-n.stopCtx.Done():
|
||||||
|
return
|
||||||
|
case <-time.After(time.Second * 60):
|
||||||
|
mu.Lock()
|
||||||
|
for k, v := range udpMap {
|
||||||
|
if time.Now().Unix() > int64(n.UDPTimeout.Seconds())+v.lastbeat {
|
||||||
|
delete(udpMap, k)
|
||||||
|
starlog.Noticef("Connection Closed %s <==> %s", v.remoteAddr.String(), n.RemoteURI)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mu.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
buf := make([]byte, 8192)
|
||||||
|
for {
|
||||||
|
count, rmt, err := listen.ReadFromUDP(buf)
|
||||||
|
if err != nil || rmt.String() == n.RemoteURI {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go func(data []byte, rmt *net.UDPAddr) {
|
||||||
|
log := starlog.Std.NewFlag()
|
||||||
|
mu.Lock()
|
||||||
|
addr, ok := udpMap[rmt.String()]
|
||||||
|
if !ok {
|
||||||
|
log.Infof("Accept New UDP Conn from %v\n", rmt.String())
|
||||||
|
conn, err := net.Dial("udp", n.RemoteURI)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Dial Remote %s Failed:%v\n", n.RemoteURI, err)
|
||||||
|
mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addr = UDPConn{
|
||||||
|
Conn: conn,
|
||||||
|
remoteAddr: rmt,
|
||||||
|
listen: listen,
|
||||||
|
lastbeat: time.Now().Unix(),
|
||||||
|
}
|
||||||
|
udpMap[rmt.String()] = addr
|
||||||
|
go addr.Work()
|
||||||
|
log.Infof("Connect %s <==> %s\n", rmt.String(), n.RemoteURI)
|
||||||
|
}
|
||||||
|
mu.Unlock()
|
||||||
|
_, err := addr.Write(data)
|
||||||
|
if err != nil {
|
||||||
|
mu.Lock()
|
||||||
|
addr.Close()
|
||||||
|
delete(udpMap, addr.remoteAddr.String())
|
||||||
|
mu.Unlock()
|
||||||
|
log.Noticef("Connection Closed %s <==> %s", rmt.String(), n.RemoteURI)
|
||||||
|
}
|
||||||
|
}(buf[0:count], rmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Copy(dst, src net.Conn) {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(2)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
io.Copy(dst, src)
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
io.Copy(src, dst)
|
||||||
|
}()
|
||||||
|
wg.Wait()
|
||||||
|
dst.Close()
|
||||||
|
src.Close()
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestForward(t *testing.T) {
|
||||||
|
var f = NetForward{
|
||||||
|
LocalAddr: "127.0.0.1",
|
||||||
|
LocalPort: 22232,
|
||||||
|
RemoteURI: "127.0.0.1:1127",
|
||||||
|
EnableTCP: true,
|
||||||
|
EnableUDP: true,
|
||||||
|
DialTimeout: 0,
|
||||||
|
UDPTimeout: 0,
|
||||||
|
}
|
||||||
|
f.Run()
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SimpleNatClient struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
cmdTCPConn net.Conn
|
||||||
|
cmdUDPConn *net.UDPAddr
|
||||||
|
ServiceTarget string
|
||||||
|
CmdTarget string
|
||||||
|
tcpAlived bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleNatClient) tcpCmdConn() net.Conn {
|
||||||
|
s.mu.RLock()
|
||||||
|
defer s.mu.RUnlock()
|
||||||
|
return s.cmdTCPConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleNatClient) tcpCmdConnAlived() bool {
|
||||||
|
s.mu.RLock()
|
||||||
|
defer s.mu.RUnlock()
|
||||||
|
return s.tcpAlived
|
||||||
|
}
|
@ -0,0 +1,138 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/starlog"
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var MSG_CMD_HELLO = []byte{11, 27, 19, 96, 182, 18, 25, 150, 17, 39}
|
||||||
|
var MSG_NEW_CONN = []byte{0, 0, 0, 0, 255, 255, 255, 255, 11, 27}
|
||||||
|
var MSG_NEW_CONN_REQ = []byte{0, 0, 0, 0, 255, 255, 255, 255, 19, 96}
|
||||||
|
var MSG_CLOSE = []byte{255, 255, 0, 0, 255, 0, 0, 255, 255, 27}
|
||||||
|
var MSG_HEARTBEAT = []byte{6, 66, 66, 6, 6, 66, 6, 66, 11, 27}
|
||||||
|
|
||||||
|
type SimpleNatServer struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
cmdTCPConn net.Conn
|
||||||
|
cmdUDPConn *net.UDPAddr
|
||||||
|
listenTcp net.Listener
|
||||||
|
listenUDP *net.UDPConn
|
||||||
|
Addr string
|
||||||
|
Port int
|
||||||
|
lastTCPHeart int64
|
||||||
|
lastUDPHeart int64
|
||||||
|
Passwd string
|
||||||
|
DialTimeout int64
|
||||||
|
UDPTimeout int64
|
||||||
|
running int32
|
||||||
|
|
||||||
|
tcpConnPool chan net.Conn
|
||||||
|
tcpAlived bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleNatServer) getConnfromTCPPool() (net.Conn, error) {
|
||||||
|
select {
|
||||||
|
case conn := <-s.tcpConnPool:
|
||||||
|
return conn, nil
|
||||||
|
case <-time.After(time.Second * 10):
|
||||||
|
return nil, errors.New("no connection got")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleNatServer) tcpCmdConn() net.Conn {
|
||||||
|
s.mu.RLock()
|
||||||
|
defer s.mu.RUnlock()
|
||||||
|
return s.cmdTCPConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleNatServer) tcpCmdConnAlived() bool {
|
||||||
|
s.mu.RLock()
|
||||||
|
defer s.mu.RUnlock()
|
||||||
|
return s.tcpAlived
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleNatServer) listenTCP() error {
|
||||||
|
var err error
|
||||||
|
s.tcpConnPool = make(chan net.Conn, 10)
|
||||||
|
s.listenTcp, err = net.Listen("tcp", fmt.Sprintf("%s:d", s.Addr, s.Port))
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("failed to listen tcp", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
conn, err := s.listenTcp.Accept()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s.tcpCmdConnAlived() {
|
||||||
|
go s.tcpClientServe(conn.(*net.TCPConn))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go s.waitingForTCPCmd(conn.(*net.TCPConn))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleNatServer) tcpClientServe(conn *net.TCPConn) {
|
||||||
|
if !s.tcpCmdConnAlived() {
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Split(conn.RemoteAddr().String(), ":")[0] == strings.Split(s.tcpCmdConn().RemoteAddr().String(), ":")[0] {
|
||||||
|
conn.SetReadDeadline(time.Now().Add(5 * time.Second))
|
||||||
|
cmdBuf := make([]byte, 10)
|
||||||
|
if _, err := io.ReadFull(conn, cmdBuf); err == nil {
|
||||||
|
conn.SetReadDeadline(time.Time{})
|
||||||
|
if bytes.Equal(cmdBuf, MSG_NEW_CONN) {
|
||||||
|
starlog.Noticef("Nat Server Recv New Client Conn From %v\n", conn.RemoteAddr().String())
|
||||||
|
s.tcpConnPool <- conn
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn.SetReadDeadline(time.Time{})
|
||||||
|
}
|
||||||
|
starlog.Noticef("Nat Server Recv New Side Conn From %v\n", conn.RemoteAddr().String())
|
||||||
|
_, err := s.tcpCmdConn().Write(MSG_NEW_CONN_REQ)
|
||||||
|
if err != nil {
|
||||||
|
s.mu.Lock()
|
||||||
|
s.cmdTCPConn.Close()
|
||||||
|
s.tcpAlived = false
|
||||||
|
s.mu.Unlock()
|
||||||
|
starlog.Errorf("Failed to Write CMD To Client:%v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reverse, err := s.getConnfromTCPPool()
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorf("Nat Server Conn to %v Closed %v\n", conn.RemoteAddr(), err)
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
starlog.Infof("Nat Server Conn %v<==>%v Connected\n", conn.RemoteAddr(), reverse.RemoteAddr())
|
||||||
|
Copy(reverse, conn)
|
||||||
|
starlog.Warningf("Nat Server Conn %v<==>%v Closed\n", conn.RemoteAddr(), reverse.RemoteAddr())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SimpleNatServer) waitingForTCPCmd(conn *net.TCPConn) {
|
||||||
|
conn.SetReadDeadline(time.Now().Add(time.Duration(s.DialTimeout) * time.Second))
|
||||||
|
cmdBuf := make([]byte, 10)
|
||||||
|
if _, err := io.ReadFull(conn, cmdBuf); err != nil {
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if bytes.Equal(cmdBuf, MSG_CMD_HELLO) {
|
||||||
|
s.mu.Lock()
|
||||||
|
s.cmdTCPConn = conn
|
||||||
|
s.tcpAlived = true
|
||||||
|
conn.SetKeepAlive(true)
|
||||||
|
conn.SetKeepAlivePeriod(time.Second * 20)
|
||||||
|
s.mu.Unlock()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package rmt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/notify"
|
||||||
|
"b612.me/notify/starnotify"
|
||||||
|
"b612.me/starlog"
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
rmtRmt string
|
||||||
|
rmtCmd RmtCmd
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Cmdc.Flags().StringVarP(&rmtRmt, "remote", "r", "", "Remote Address")
|
||||||
|
Cmdc.Flags().StringVarP(&rmtPol, "protocol", "o", "tcp", "Remote protocol")
|
||||||
|
Cmdc.Flags().StringVarP(&rmtCmd.Cmd, "cmd", "c", "", "command")
|
||||||
|
Cmdc.Flags().StringVarP(&rmtCmd.WorkDir, "workdir", "w", "", "workdir")
|
||||||
|
Cmdc.Flags().StringSliceVarP(&rmtCmd.Env, "env", "e", []string{}, "env")
|
||||||
|
Cmdc.Flags().BoolVarP(&rmtCmd.Daemon, "daemon", "d", false, "daemon")
|
||||||
|
Cmdc.Flags().BoolVarP(&rmtCmd.Stream, "stream", "s", false, "stream")
|
||||||
|
Cmdc.Flags().StringVarP(&rmtListenPort, "port", "p", "5780", "Remote Port")
|
||||||
|
}
|
||||||
|
|
||||||
|
var Cmdc = &cobra.Command{
|
||||||
|
Use: "rmtc",
|
||||||
|
Short: "simple remote shell client",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if rmtRmt == "" {
|
||||||
|
starlog.Errorln("Please Enter Remote Path")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
err := starnotify.NewClient("c").Connect(rmtPol, fmt.Sprintf("%s:%s", rmtRmt, rmtListenPort))
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("Create Remote Failed", err)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
starnotify.C("c").SetLink("stream", RmtSteam)
|
||||||
|
defer starnotify.C("c").Stop()
|
||||||
|
cdata, err := starnotify.C("c").SendWaitObj("cmd", rmtCmd, time.Second*3600)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("Got Answer Failed:", err)
|
||||||
|
os.Exit(3)
|
||||||
|
}
|
||||||
|
data, err := cdata.Value.ToInterface()
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("Decode FAILED:", err)
|
||||||
|
os.Exit(4)
|
||||||
|
}
|
||||||
|
rtnData, ok := data.(RmtCmdBack)
|
||||||
|
if !ok {
|
||||||
|
starlog.Errorln("Decode FAILED2:", err)
|
||||||
|
os.Exit(5)
|
||||||
|
}
|
||||||
|
fmt.Println("Return Pid:", rtnData.RetCode)
|
||||||
|
if !rmtCmd.Stream {
|
||||||
|
fmt.Println("Return OutPut\n", rtnData.OutPut)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func RmtSteam(msg *notify.Message) {
|
||||||
|
fmt.Println(strings.TrimSpace(msg.Value.MustToString()))
|
||||||
|
}
|
@ -0,0 +1,166 @@
|
|||||||
|
package rmt
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/notify"
|
||||||
|
"b612.me/notify/starnotify"
|
||||||
|
"b612.me/starlog"
|
||||||
|
"b612.me/staros"
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RmtCmd struct {
|
||||||
|
Env []string
|
||||||
|
WorkDir string
|
||||||
|
Cmd string
|
||||||
|
Daemon bool
|
||||||
|
Stream bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type RmtCmdBack struct {
|
||||||
|
RetCode int
|
||||||
|
OutPut string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
rmtListenPort string
|
||||||
|
rmtPol string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
notify.RegisterName("remoteback", RmtCmdBack{})
|
||||||
|
notify.RegisterName("remotecmd", RmtCmd{})
|
||||||
|
Cmds.Flags().StringVarP(&rmtListenPort, "port", "p", "5780", "Listen Port")
|
||||||
|
Cmds.Flags().StringVarP(&rmtPol, "protocol", "o", "tcp", "Remote protocol")
|
||||||
|
}
|
||||||
|
|
||||||
|
var Cmds = &cobra.Command{
|
||||||
|
Use: "rmts",
|
||||||
|
Short: "simple remote shell server",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if rmtListenPort == "" {
|
||||||
|
starlog.Errorln("Please Enter Port")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
err := starnotify.NewServer("s").Listen(rmtPol, "0.0.0.0:"+rmtListenPort)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("Create Listener Failed", err)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
starnotify.S("s").SetLink("cmd", ListenAndServe)
|
||||||
|
starlog.Infoln("Service Running")
|
||||||
|
stopSig := make(chan os.Signal)
|
||||||
|
signal.Notify(stopSig, os.Kill, os.Interrupt)
|
||||||
|
<-stopSig
|
||||||
|
starlog.Noticeln("Recv Stop Sig")
|
||||||
|
starnotify.S("s").Stop()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListenAndServe(msg *notify.Message) {
|
||||||
|
data, err := msg.Value.ToInterface()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cmd, ok := data.(RmtCmd)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var sysName, sysArg string = "bash", "-c"
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
sysName = "cmd.exe"
|
||||||
|
sysArg = "/c"
|
||||||
|
}
|
||||||
|
if cmd.Cmd == "" {
|
||||||
|
msg.ReplyObj(RmtCmdBack{
|
||||||
|
RetCode: 255,
|
||||||
|
OutPut: "Please enter the command",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
starlog.Noticef("Recv Command:%+v\n", cmd)
|
||||||
|
var myCmd *staros.StarCmd
|
||||||
|
myCmd, err = staros.Command(sysName, sysArg, cmd.Cmd)
|
||||||
|
if err != nil {
|
||||||
|
msg.ReplyObj(RmtCmdBack{
|
||||||
|
RetCode: 255,
|
||||||
|
OutPut: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cmd.WorkDir != "" {
|
||||||
|
myCmd.CMD.Dir = cmd.WorkDir
|
||||||
|
}
|
||||||
|
if len(cmd.Env) > 0 {
|
||||||
|
myCmd.CMD.Env = cmd.Env
|
||||||
|
}
|
||||||
|
if cmd.Daemon {
|
||||||
|
err := myCmd.Release()
|
||||||
|
if err != nil {
|
||||||
|
msg.ReplyObj(RmtCmdBack{
|
||||||
|
RetCode: 254,
|
||||||
|
OutPut: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pid := myCmd.CMD.Process.Pid
|
||||||
|
msg.ReplyObj(RmtCmdBack{
|
||||||
|
RetCode: 0,
|
||||||
|
OutPut: fmt.Sprintf("Runned,PID is %d", pid),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = myCmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
msg.ReplyObj(RmtCmdBack{
|
||||||
|
RetCode: 254,
|
||||||
|
OutPut: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for myCmd.IsRunning() {
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
if cmd.Stream {
|
||||||
|
std, err := myCmd.NowAllOutput()
|
||||||
|
if err != nil {
|
||||||
|
std += "\n" + err.Error()
|
||||||
|
}
|
||||||
|
std = strings.TrimSpace(std)
|
||||||
|
if len(std) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
msg.ClientConn.Server().SendObj(msg.ClientConn, "stream", std)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 50)
|
||||||
|
if !cmd.Stream {
|
||||||
|
std := myCmd.AllStdOut()
|
||||||
|
if myCmd.AllStdErr() != nil {
|
||||||
|
std += "\n" + myCmd.AllStdErr().Error()
|
||||||
|
}
|
||||||
|
msg.ReplyObj(RmtCmdBack{
|
||||||
|
RetCode: myCmd.ExitCode(),
|
||||||
|
OutPut: std,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
std, err := myCmd.NowAllOutput()
|
||||||
|
if err != nil {
|
||||||
|
std += "\n" + err.Error()
|
||||||
|
}
|
||||||
|
msg.ClientConn.Server().SendObj(msg.ClientConn, "stream", std)
|
||||||
|
time.Sleep(time.Millisecond * 1000)
|
||||||
|
err = msg.ReplyObj(RmtCmdBack{
|
||||||
|
RetCode: myCmd.ExitCode(),
|
||||||
|
OutPut: "",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
starlog.Warningln("Reply failed:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
package search
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/stario"
|
||||||
|
"b612.me/starlog"
|
||||||
|
"b612.me/startext"
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var stFolder string
|
||||||
|
var stNum, stMax, stMin int
|
||||||
|
var stautoGBK bool
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Cmd.Flags().StringVarP(&stFolder, "folder", "f", "./", "搜索的文件夹")
|
||||||
|
Cmd.Flags().IntVarP(&stNum, "thread-num", "n", 5, "并发搜寻协程数")
|
||||||
|
Cmd.Flags().BoolVarP(&stautoGBK, "autogbk", "g", true, "自动GBK识别")
|
||||||
|
Cmd.Flags().IntVar(&stMax, "max", 0, "行最大字数")
|
||||||
|
Cmd.Flags().IntVar(&stMin, "min", 0, "行最小字数")
|
||||||
|
}
|
||||||
|
|
||||||
|
var Cmd = &cobra.Command{
|
||||||
|
Use: "st",
|
||||||
|
Short: "搜索文件中特定字符串",
|
||||||
|
Long: "搜索文件中特定字符串",
|
||||||
|
Run: func(this *cobra.Command, args []string) {
|
||||||
|
if len(args) != 2 {
|
||||||
|
starlog.Errorln("应当传入两个参数,搜寻文件后缀和搜寻文本")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
err := searchText(stFolder, args[0], args[1], stNum, stautoGBK, stMax, stMin)
|
||||||
|
if err != nil {
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func searchText(folder string, filematch string, text string, thread int, autoGBK bool, max, min int) error {
|
||||||
|
data, err := ioutil.ReadDir(folder)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("read folder failed", folder, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
wg := stario.NewWaitGroup(thread)
|
||||||
|
searchFn := func(filepath string, text string) {
|
||||||
|
//starlog.Debugln("searching", filepath, text)
|
||||||
|
defer wg.Done()
|
||||||
|
fp, err := os.Open(filepath)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("open file failed", filepath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer fp.Close()
|
||||||
|
reader := bufio.NewReader(fp)
|
||||||
|
count := 0
|
||||||
|
for {
|
||||||
|
origin, err := reader.ReadString('\n')
|
||||||
|
count++
|
||||||
|
if stautoGBK && startext.IsGBK([]byte(origin)) {
|
||||||
|
originByte, _ := startext.GBK2UTF8([]byte(origin))
|
||||||
|
origin = string(originByte)
|
||||||
|
}
|
||||||
|
origin = strings.TrimSpace(origin)
|
||||||
|
if max != 0 && len(origin) > max {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if min != 0 && len(origin) < min {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.Contains(origin, text) {
|
||||||
|
fmt.Printf("file:%s line:%d matched:%s\n", filepath, count, origin)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, v := range data {
|
||||||
|
if v.IsDir() {
|
||||||
|
searchText(filepath.Join(folder, v.Name()), filematch, text, thread, autoGBK, stMax, stMin)
|
||||||
|
}
|
||||||
|
filepath := filepath.Join(folder, v.Name())
|
||||||
|
if matched, _ := regexp.MatchString(filematch, filepath); matched {
|
||||||
|
wg.Add(1)
|
||||||
|
go searchFn(filepath, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package sftp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/starssh"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TransferFile(s *starssh.StarSSH, local, remote string, isPull, fullname bool) error {
|
||||||
|
if !fullname && !isPull {
|
||||||
|
s.ShellOne("mkdir -p " + remote)
|
||||||
|
remote = remote + "/" + filepath.Base(local)
|
||||||
|
}
|
||||||
|
if !fullname && isPull {
|
||||||
|
os.MkdirAll(local, 0755)
|
||||||
|
local = filepath.Join(local, path.Base(remote))
|
||||||
|
}
|
||||||
|
if fullname && isPull {
|
||||||
|
os.MkdirAll(filepath.Dir(local), 0755)
|
||||||
|
}
|
||||||
|
if fullname && !isPull {
|
||||||
|
os.MkdirAll(path.Dir(remote), 0755)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package tcping
|
||||||
|
|
||||||
|
import "net"
|
||||||
|
|
||||||
|
// GetIP ...
|
||||||
|
func GetIP(hostname string) string {
|
||||||
|
addrs, err := net.LookupIP(hostname)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if ipv4 := addr.To4(); ipv4 != nil {
|
||||||
|
return ipv4.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
@ -0,0 +1,120 @@
|
|||||||
|
package tcping
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptrace"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HTTPing ...
|
||||||
|
type HTTPing struct {
|
||||||
|
target *Target
|
||||||
|
done chan struct{}
|
||||||
|
result *Result
|
||||||
|
Method string
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Pinger = (*HTTPing)(nil)
|
||||||
|
|
||||||
|
// NewHTTPing return new HTTPing
|
||||||
|
func NewHTTPing(method string) *HTTPing {
|
||||||
|
return &HTTPing{
|
||||||
|
done: make(chan struct{}),
|
||||||
|
Method: method,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTarget ...
|
||||||
|
func (ping *HTTPing) SetTarget(target *Target) {
|
||||||
|
ping.target = target
|
||||||
|
if ping.result == nil {
|
||||||
|
ping.result = &Result{Target: target}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start ping
|
||||||
|
func (ping *HTTPing) Start() <-chan struct{} {
|
||||||
|
go func() {
|
||||||
|
t := time.NewTicker(ping.target.Interval)
|
||||||
|
defer t.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-t.C:
|
||||||
|
if ping.result.Counter >= ping.target.Counter && ping.target.Counter != 0 {
|
||||||
|
ping.Stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
duration, resp, remoteAddr, err := ping.ping()
|
||||||
|
ping.result.Counter++
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Ping %s - failed: %s\n", ping.target, err)
|
||||||
|
} else {
|
||||||
|
defer resp.Body.Close()
|
||||||
|
length, _ := io.Copy(ioutil.Discard, resp.Body)
|
||||||
|
fmt.Printf("Ping %s(%s) - %s is open - time=%s method=%s status=%d bytes=%d\n", ping.target, remoteAddr, ping.target.Protocol, duration, ping.Method, resp.StatusCode, length)
|
||||||
|
if ping.result.MinDuration == 0 {
|
||||||
|
ping.result.MinDuration = duration
|
||||||
|
}
|
||||||
|
if ping.result.MaxDuration == 0 {
|
||||||
|
ping.result.MaxDuration = duration
|
||||||
|
}
|
||||||
|
ping.result.SuccessCounter++
|
||||||
|
if duration > ping.result.MaxDuration {
|
||||||
|
ping.result.MaxDuration = duration
|
||||||
|
} else if duration < ping.result.MinDuration {
|
||||||
|
ping.result.MinDuration = duration
|
||||||
|
}
|
||||||
|
ping.result.TotalDuration += duration
|
||||||
|
}
|
||||||
|
case <-ping.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return ping.done
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result return ping result
|
||||||
|
func (ping *HTTPing) Result() *Result {
|
||||||
|
return ping.result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the tcping
|
||||||
|
func (ping *HTTPing) Stop() {
|
||||||
|
ping.done <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ping HTTPing) ping() (time.Duration, *http.Response, string, error) {
|
||||||
|
var resp *http.Response
|
||||||
|
var body io.Reader
|
||||||
|
if ping.Method == "POST" {
|
||||||
|
body = bytes.NewBufferString("{}")
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(ping.Method, ping.target.String(), body)
|
||||||
|
req.Header.Set(http.CanonicalHeaderKey("User-Agent"), "tcping")
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, "", err
|
||||||
|
}
|
||||||
|
var remoteAddr string
|
||||||
|
trace := &httptrace.ClientTrace{
|
||||||
|
ConnectStart: func(network, addr string) {
|
||||||
|
remoteAddr = addr
|
||||||
|
},
|
||||||
|
}
|
||||||
|
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
|
||||||
|
duration, errIfce := timeIt(func() interface{} {
|
||||||
|
client := http.Client{Timeout: ping.target.Timeout}
|
||||||
|
resp, err = client.Do(req)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if errIfce != nil {
|
||||||
|
err := errIfce.(error)
|
||||||
|
return 0, nil, "", err
|
||||||
|
}
|
||||||
|
return time.Duration(duration), resp, remoteAddr, nil
|
||||||
|
}
|
@ -0,0 +1,149 @@
|
|||||||
|
package tcping
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Protocol ...
|
||||||
|
type Protocol int
|
||||||
|
|
||||||
|
func (protocol Protocol) String() string {
|
||||||
|
switch protocol {
|
||||||
|
case TCP:
|
||||||
|
return "tcp"
|
||||||
|
case HTTP:
|
||||||
|
return "http"
|
||||||
|
case HTTPS:
|
||||||
|
return "https"
|
||||||
|
}
|
||||||
|
return "unkown"
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TCP is tcp protocol
|
||||||
|
TCP Protocol = iota
|
||||||
|
// HTTP is http protocol
|
||||||
|
HTTP
|
||||||
|
// HTTPS is https protocol
|
||||||
|
HTTPS
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewProtocol convert protocol stirng to Protocol
|
||||||
|
func NewProtocol(protocol string) (Protocol, error) {
|
||||||
|
switch strings.ToLower(protocol) {
|
||||||
|
case TCP.String():
|
||||||
|
return TCP, nil
|
||||||
|
case HTTP.String():
|
||||||
|
return HTTP, nil
|
||||||
|
case HTTPS.String():
|
||||||
|
return HTTPS, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("protocol %s not support", protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Target is a ping
|
||||||
|
type Target struct {
|
||||||
|
Protocol Protocol
|
||||||
|
Host string
|
||||||
|
Port int
|
||||||
|
|
||||||
|
Counter int
|
||||||
|
Interval time.Duration
|
||||||
|
Timeout time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (target Target) String() string {
|
||||||
|
return fmt.Sprintf("%s://%s:%d", target.Protocol, target.Host, target.Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pinger is a ping interface
|
||||||
|
type Pinger interface {
|
||||||
|
Start() <-chan struct{}
|
||||||
|
Stop()
|
||||||
|
Result() *Result
|
||||||
|
SetTarget(target *Target)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping is a ping interface
|
||||||
|
type Ping interface {
|
||||||
|
Start() <-chan struct{}
|
||||||
|
|
||||||
|
Host() string
|
||||||
|
Port() int
|
||||||
|
Protocol() Protocol
|
||||||
|
Counter() int
|
||||||
|
|
||||||
|
Stop()
|
||||||
|
|
||||||
|
Result() Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result ...
|
||||||
|
type Result struct {
|
||||||
|
Counter int
|
||||||
|
SuccessCounter int
|
||||||
|
Target *Target
|
||||||
|
|
||||||
|
MinDuration time.Duration
|
||||||
|
MaxDuration time.Duration
|
||||||
|
TotalDuration time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avg return the average time of ping
|
||||||
|
func (result Result) Avg() time.Duration {
|
||||||
|
if result.SuccessCounter == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return result.TotalDuration / time.Duration(result.SuccessCounter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Failed return failed counter
|
||||||
|
func (result Result) Failed() int {
|
||||||
|
return result.Counter - result.SuccessCounter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (result Result) String() string {
|
||||||
|
const resultTpl = `
|
||||||
|
Ping statistics {{.Target}}
|
||||||
|
{{.Counter}} probes sent.
|
||||||
|
{{.SuccessCounter}} successful, {{.Failed}} failed.
|
||||||
|
Approximate trip times:
|
||||||
|
Minimum = {{.MinDuration}}, Maximum = {{.MaxDuration}}, Average = {{.Avg}}`
|
||||||
|
t := template.Must(template.New("result").Parse(resultTpl))
|
||||||
|
res := bytes.NewBufferString("")
|
||||||
|
t.Execute(res, result)
|
||||||
|
return res.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckURI check uri
|
||||||
|
func CheckURI(uri string) (schema, host string, port int, matched bool) {
|
||||||
|
const reExp = `^((?P<schema>((ht|f)tp(s?))|tcp)\://)?((([a-zA-Z0-9_\-]+\.)+[a-zA-Z]{2,})|((?:(?:25[0-5]|2[0-4]\d|[01]\d\d|\d?\d)((\.?\d)\.)){4})|(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9]))(:([0-9]+))?(/[a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~]*)?$`
|
||||||
|
pattern := regexp.MustCompile(reExp)
|
||||||
|
res := pattern.FindStringSubmatch(uri)
|
||||||
|
if len(res) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
matched = true
|
||||||
|
schema = res[2]
|
||||||
|
if schema == "" {
|
||||||
|
schema = "tcp"
|
||||||
|
}
|
||||||
|
host = res[6]
|
||||||
|
if res[17] == "" {
|
||||||
|
if schema == HTTPS.String() {
|
||||||
|
port = 443
|
||||||
|
} else {
|
||||||
|
port = 80
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
port, _ = strconv.Atoi(res[17])
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
package tcping
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TCPing ...
|
||||||
|
type TCPing struct {
|
||||||
|
target *Target
|
||||||
|
done chan struct{}
|
||||||
|
result *Result
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Pinger = (*TCPing)(nil)
|
||||||
|
|
||||||
|
// NewTCPing return a new TCPing
|
||||||
|
func NewTCPing() *TCPing {
|
||||||
|
tcping := TCPing{
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
return &tcping
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTarget set target for TCPing
|
||||||
|
func (tcping *TCPing) SetTarget(target *Target) {
|
||||||
|
tcping.target = target
|
||||||
|
if tcping.result == nil {
|
||||||
|
tcping.result = &Result{Target: target}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result return the result
|
||||||
|
func (tcping TCPing) Result() *Result {
|
||||||
|
return tcping.result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a tcping
|
||||||
|
func (tcping TCPing) Start() <-chan struct{} {
|
||||||
|
go func() {
|
||||||
|
t := time.NewTicker(tcping.target.Interval)
|
||||||
|
defer t.Stop()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-t.C:
|
||||||
|
if tcping.result.Counter >= tcping.target.Counter && tcping.target.Counter != 0 {
|
||||||
|
tcping.Stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
duration, remoteAddr, err := tcping.ping()
|
||||||
|
tcping.result.Counter++
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Ping %s - failed: %s\n", tcping.target, err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Ping %s(%s) - Connected - time=%s\n", tcping.target, remoteAddr, duration)
|
||||||
|
|
||||||
|
if tcping.result.MinDuration == 0 {
|
||||||
|
tcping.result.MinDuration = duration
|
||||||
|
}
|
||||||
|
if tcping.result.MaxDuration == 0 {
|
||||||
|
tcping.result.MaxDuration = duration
|
||||||
|
}
|
||||||
|
tcping.result.SuccessCounter++
|
||||||
|
if duration > tcping.result.MaxDuration {
|
||||||
|
tcping.result.MaxDuration = duration
|
||||||
|
} else if duration < tcping.result.MinDuration {
|
||||||
|
tcping.result.MinDuration = duration
|
||||||
|
}
|
||||||
|
tcping.result.TotalDuration += duration
|
||||||
|
}
|
||||||
|
case <-tcping.done:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return tcping.done
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the tcping
|
||||||
|
func (tcping *TCPing) Stop() {
|
||||||
|
tcping.done <- struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tcping TCPing) ping() (time.Duration, net.Addr, error) {
|
||||||
|
var remoteAddr net.Addr
|
||||||
|
duration, errIfce := timeIt(func() interface{} {
|
||||||
|
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", tcping.target.Host, tcping.target.Port), tcping.target.Timeout)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
remoteAddr = conn.RemoteAddr()
|
||||||
|
conn.Close()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if errIfce != nil {
|
||||||
|
err := errIfce.(error)
|
||||||
|
return 0, remoteAddr, err
|
||||||
|
}
|
||||||
|
return time.Duration(duration), remoteAddr, nil
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package tcping
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func timeIt(f func() interface{}) (int64, interface{}) {
|
||||||
|
startAt := time.Now()
|
||||||
|
res := f()
|
||||||
|
endAt := time.Now()
|
||||||
|
return endAt.UnixNano() - startAt.UnixNano(), res
|
||||||
|
}
|
||||||
|
|
||||||
|
// UseCustomeDNS will set the dns to default DNS resolver for global
|
||||||
|
func UseCustomeDNS(dns []string) {
|
||||||
|
resolver := net.Resolver{
|
||||||
|
PreferGo: true,
|
||||||
|
Dial: func(ctx context.Context, network, address string) (conn net.Conn, err error) {
|
||||||
|
for _, addr := range dns {
|
||||||
|
if conn, err = net.Dial("udp", addr+":53"); err != nil {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
},
|
||||||
|
}
|
||||||
|
net.DefaultResolver = &resolver
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatIP - trim spaces and format IP
|
||||||
|
//
|
||||||
|
// IP - the provided IP
|
||||||
|
//
|
||||||
|
// string - return "" if the input is neither valid IPv4 nor valid IPv6
|
||||||
|
// return IPv4 in format like "192.168.9.1"
|
||||||
|
// return IPv6 in format like "[2002:ac1f:91c5:1::bd59]"
|
||||||
|
func FormatIP(IP string) string {
|
||||||
|
|
||||||
|
host := strings.Trim(IP, "[ ]")
|
||||||
|
if parseIP := net.ParseIP(host); parseIP != nil && parseIP.To4() == nil {
|
||||||
|
host = fmt.Sprintf("[%s]", host)
|
||||||
|
}
|
||||||
|
|
||||||
|
return host
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package uac
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/starlog"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var fpath string
|
||||||
|
var fargs string
|
||||||
|
var workdir string
|
||||||
|
var showWindow bool
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Cmd.Flags().StringVarP(&fpath, "path", "p", "", "filepath/文件路径")
|
||||||
|
Cmd.Flags().StringVarP(&fargs, "args", "a", "", "args use space to split/参数,空格分隔")
|
||||||
|
Cmd.Flags().StringVarP(&workdir, "workdir", "d", "./", "workdir path")
|
||||||
|
Cmd.Flags().BoolVarP(&showWindow, "hide-window", "w", false, "hide the window show")
|
||||||
|
}
|
||||||
|
|
||||||
|
var Cmd = &cobra.Command{
|
||||||
|
Use: "uac",
|
||||||
|
Short: "run process with administrator permission",
|
||||||
|
Example: "vtqe uac 'c:\\program.exe arg1 arg2'",
|
||||||
|
Version: "2.0.0",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
showWindow = !showWindow
|
||||||
|
workdir, _ = filepath.Abs(workdir)
|
||||||
|
if fpath == "" && len(args) == 0 {
|
||||||
|
starlog.Errorln("Please enter a filepath")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if fpath != "" {
|
||||||
|
err := RunAsUacSimple(fpath, fargs, workdir, showWindow)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("StartAsUac Failed", err)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(args) > 0 {
|
||||||
|
err := RunAsUac(args[0], workdir, showWindow)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("StartAsUac Failed", err)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package uac
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/wincmd"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RunAsUacSimple(fpath string, cmdArgs string, workDir string, showWindow bool) error {
|
||||||
|
intShow := 0
|
||||||
|
if showWindow {
|
||||||
|
intShow = 1
|
||||||
|
}
|
||||||
|
return wincmd.StartProcess(fpath, cmdArgs, workDir, true, intShow)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunAsUac(cmdLine, workDir string, showWindow bool) error {
|
||||||
|
intShow := 0
|
||||||
|
if showWindow {
|
||||||
|
intShow = 1
|
||||||
|
}
|
||||||
|
fpath, args := getPathArgsFromString(cmdLine)
|
||||||
|
return wincmd.StartProcess(fpath, strings.Join(args, " "), workDir, true, intShow)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPathArgsFromString(cmdLine string) (string, []string) {
|
||||||
|
var fpath string
|
||||||
|
var cmdArgs []string
|
||||||
|
var markStart rune = -1
|
||||||
|
|
||||||
|
var tmp []rune
|
||||||
|
var lastRune rune
|
||||||
|
cmdLine = strings.TrimSpace(cmdLine)
|
||||||
|
for k, v := range cmdLine {
|
||||||
|
if v == ' ' || v == '"' || v == '\'' {
|
||||||
|
if k == 0 {
|
||||||
|
markStart = v
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if markStart == v && v == lastRune {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if lastRune != '\\' {
|
||||||
|
lastRune = v
|
||||||
|
if 0 == markStart {
|
||||||
|
markStart = v
|
||||||
|
continue
|
||||||
|
} else if markStart == v || markStart == -1 {
|
||||||
|
markStart = 0
|
||||||
|
if v == ' ' {
|
||||||
|
markStart = v
|
||||||
|
}
|
||||||
|
if fpath == "" {
|
||||||
|
fpath = string(tmp)
|
||||||
|
} else {
|
||||||
|
cmdArgs = append(cmdArgs, string(tmp))
|
||||||
|
}
|
||||||
|
tmp = []rune{}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastRune = v
|
||||||
|
tmp = append(tmp, v)
|
||||||
|
}
|
||||||
|
if len(tmp) != 0 {
|
||||||
|
if fpath == "" {
|
||||||
|
fpath = string(tmp)
|
||||||
|
} else {
|
||||||
|
cmdArgs = append(cmdArgs, string(tmp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fpath, cmdArgs
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package uac
|
||||||
|
|
||||||
|
import "github.com/spf13/cobra"
|
||||||
|
|
||||||
|
var Cmd = &cobra.Command{
|
||||||
|
Use: "uac",
|
||||||
|
Short: "run process with administrator permission",
|
||||||
|
Example: "vtqe uac 'c:\\program.exe arg1 arg2'",
|
||||||
|
Hidden: true,
|
||||||
|
}
|
Loading…
Reference in New Issue