newgen
兔子 4 years ago
parent f89188761d
commit 7835d1fae7

@ -0,0 +1,33 @@
package main
import (
"github.com/spf13/cobra"
)
var httpPort, httpIP, httpPath, httpBasicAuth, httpCertKey, logPath string
var doUpload, daemon bool
func init() {
httpcmd.Flags().StringVarP(&httpPort, "port", "p", "80", "监听端口")
httpcmd.Flags().StringVarP(&httpIP, "ip", "i", "0.0.0.0", "监听ip")
httpcmd.Flags().StringVarP(&httpPath, "folder", "f", "./", "本地文件地址")
httpcmd.Flags().BoolVarP(&doUpload, "upload", "u", false, "是否开启文件上传")
httpcmd.Flags().BoolVarP(&doUpload, "daemon", "d", false, "以后台进程运行")
httpcmd.Flags().StringVarP(&httpBasicAuth, "auth", "a", "", "HTTP BASIC AUTH认证(用户名:密码)")
httpcmd.Flags().StringVarP(&httpBasicAuth, "log", "l", "", "log地址")
httpcmd.Flags().StringVarP(&httpCertKey, "cert", "c", "", "TLS证书路径用:分割证书与密钥")
httpcmd.Flags().MarkHidden("front")
}
// httpCmd represents the http command
var httpcmd = &cobra.Command{
Use: "http",
Short: "HTTP文件服务器",
Long: `HTTP文件服务器`,
Run: func(cmd *cobra.Command, args []string) {
if daemon {
}
},
}

@ -0,0 +1,304 @@
package httpserver
import (
"encoding/base64"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"b612.me/starainrt"
"b612.me/starlog"
)
func RunHttpServer(listenIp, port, basicAuth, path, cert string, doUpload bool) {
var err error
http.HandleFunc("/", httplisten)
path, _ = filepath.Abs(path)
starlog.Infoln("Listening On Port:" + port)
if up {
starlog.Infoln("upload is openned,path is /vtqeupload1127")
http.HandleFunc("/vtqeupload1127", uploadfile)
}
if certKey == "" {
err = http.ListenAndServe(ip+":"+port, nil)
} else {
certs := strings.Split(certKey, ":")
if len(certs) != 2 {
starlog.Criticalln("证书不正确!")
return
}
err = http.ListenAndServeTLS(ip+":"+port, certs[0], certs[1], nil)
}
if err != nil {
starlog.Criticalln("Error:" + err.Error())
}
}
func httplisten(w http.ResponseWriter, r *http.Request) {
log := starlog.Std.NewFlag()
w.Header().Set("Server", "Vicorique")
w.Header().Set("Powered", "B612.ME")
write401 := func() {
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>`))
}
if basicAuth != "" {
authHeader := strings.TrimSpace(r.Header.Get("Authorization"))
if len(authHeader) == 0 {
log.Noticeln("No Authed! Get Path is", r.URL.Path, r.RemoteAddr)
write401()
return
} else {
userAuth := base64.StdEncoding.EncodeToString([]byte(basicAuth))
authStr := strings.Split(authHeader, " ")
if strings.TrimSpace(authStr[1]) != userAuth {
log.Noticeln("Auth Failed! Get Path is", r.URL.Path, r.RemoteAddr, "pwd enter is", authHeader)
write401()
return
}
}
}
p := r.URL.Path
cmd := r.URL.Query()["cmd"]
log.Noticeln("Get " + p + " " + r.RemoteAddr)
fullpath, _ := filepath.Abs(path + p)
if p == "/" {
ReadFolder(w, r, fullpath, true)
return
}
if up {
if p == "/vtqeupload1127/web" {
w.Write([]byte(`<html><body><form id= "uploadForm" action= "../vtqeupload1127" method= "post" enctype ="multipart/form-data">
<h1 >B612 File Upload Page </h1>
<p > <input type ="file" name="victorique" /></p>
<input type ="submit" value="上传"/>
</form>
<h2>Copyright@b612.me </h2></body></html>`))
return
}
}
if !starainrt.Exists(fullpath) {
w.WriteHeader(404)
if len(cmd) != 0 {
if cmd[0] == "header" {
for k, v := range r.Header {
for _, v2 := range v {
fmt.Fprintf(w, "%s:%s\n", k, v2)
}
}
}
}
w.Write([]byte("<h1>404 NOT FOUND</h1>"))
return
}
if starainrt.IsFolder(fullpath) {
ReadFolder(w, r, fullpath, false)
return
}
fpdst, err := os.Open(fullpath)
if err != nil {
log.Errorln(err)
w.WriteHeader(403)
w.Write([]byte("<h1>403 NO ACCESS</h1>"))
return
}
fpinfo, _ := os.Stat(fullpath)
name := filepath.Base(fullpath)
tmp := strings.Split(name, ".")
ext := ""
if len(tmp) >= 2 {
ext = strings.ToLower(tmp[len(tmp)-1])
}
switch ext {
case "jpeg", "jpg", "jpe":
w.Header().Set("Content-Type", "image/jpeg")
case "mpeg", "mpg", "mkv":
w.Header().Set("Content-Type", "video/mpeg")
case "mp4":
w.Header().Set("Content-Type", "video/mp4")
case "pdf":
w.Header().Set("Content-Type", "application/pdf")
default:
w.Header().Set("Content-Type", "application/download")
w.Header().Set("Content-Disposition", "attachment;filename="+name)
}
etag := new(starainrt.StarCrypto).MD5([]byte(fpinfo.ModTime().String()))
w.Header().Set("Content-Transfer-Encoding", "binary")
w.Header().Set("Accept-Ranges", "bytes")
w.Header().Set("ETag", etag)
w.Header().Set("Last-Modified", strings.ReplaceAll(fpinfo.ModTime().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST"), "UTC", "GMT"))
isRange := false
var rangeStart, rangeEnd int64
rangeEnd = -1
for k, v := range r.Header {
if strings.ToLower(k) == "range" {
if strings.Index(v[0], "bytes=") < 0 {
break
}
v[0] = strings.Replace(v[0], "bytes=", "", -1)
data := strings.Split(v[0], "-")
if len(data) == 0 {
break
}
rangeStart, _ = strconv.ParseInt(data[0], 10, 64)
if len(data) == 2 {
rangeEnd, _ = strconv.ParseInt(data[1], 10, 64)
}
//w.WriteHeader(206) //206 支持断点续传
isRange = true
break
}
}
defer fpdst.Close()
var transferData int
if !isRange {
w.Header().Set("Content-Length", strconv.FormatInt(fpinfo.Size(), 10))
w.WriteHeader(200)
for {
buf := make([]byte, 1048576)
n, err := fpdst.Read(buf)
if n != 0 {
ns, err := w.Write(buf[0:n])
transferData += ns
if err != nil {
starlog.Errorln("Transfer Error:", err)
}
}
if err != nil {
if err == io.EOF {
break
}
break
}
}
} else {
w.Header().Set("Content-Length", strconv.FormatInt(fpinfo.Size(), 10))
if rangeEnd == -1 {
w.Header().Set("Content-Range", `bytes `+strconv.FormatInt(rangeStart, 10)+"-"+strconv.FormatInt(fpinfo.Size(), 10)+"/"+strconv.FormatInt(fpinfo.Size(), 10))
//w.Header().Set("Content-Length", strconv.FormatInt(fpinfo.Size()-rangeStart, 10))
} else {
w.Header().Set("Content-Range", `bytes `+strconv.FormatInt(rangeStart, 10)+"-"+strconv.FormatInt(rangeEnd, 10)+"/"+strconv.FormatInt(fpinfo.Size(), 10))
//w.Header().Set("Content-Length", strconv.FormatInt(1+rangeEnd-rangeStart, 10))
}
w.WriteHeader(206)
fpdst.Seek(int64(rangeStart), 0)
count := rangeStart
for {
buf := make([]byte, 1048576)
n, err := fpdst.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return
}
if rangeEnd == -1 {
ns, err := w.Write(buf[0:n])
transferData += ns
if err != nil {
starlog.Errorln("Transfer Error:", err)
}
} else {
if count > rangeEnd {
break
}
if count+int64(n) > rangeEnd {
w.Write(buf[0 : rangeEnd-count+1])
break
} else {
ns, err := w.Write(buf[0:n])
transferData += ns
if err != nil {
starlog.Errorln("Transfer Error:", err)
}
count += int64(n)
}
}
}
}
var tani string
tani = fmt.Sprintf("%v Byte", transferData)
if f64 := float64(transferData) / 1024; f64 > 1 {
tani = fmt.Sprintf("%v KB", f64)
if f64 = float64(f64) / 1024; f64 > 1 {
tani = fmt.Sprintf("%v MB", f64)
if f64 = float64(f64) / 1024; f64 > 1 {
tani = fmt.Sprintf("%v GB", f64)
}
}
}
log.Infoln(fpinfo.Name(), "客户端下载已结束,共传输大小:"+tani)
}
func ReadFolder(w http.ResponseWriter, r *http.Request, fullpath string, isroot bool) {
dir, err := ioutil.ReadDir(fullpath)
if err != nil {
starlog.Errorln(err)
w.WriteHeader(403)
w.Write([]byte("<h1>May Cannot Access!</h1>"))
}
w.Write([]byte("<html>\n<style>\np{margin: 2px auto}\n</style>\n<h1>B612 Http Server - " + Version + "</h1>"))
if up {
w.Write([]byte("<a href=/vtqeupload1127/web>Upload Web Page Is Openned!</a><br /><br />"))
}
w.Write([]byte("<hr /><pre>\n"))
if r.URL.Path == "/" {
r.URL.Path = ""
} else if r.URL.Path[len(r.URL.Path)-1:] == "/" {
r.URL.Path = r.URL.Path[0 : len(r.URL.Path)-1]
}
if !isroot {
w.Write([]byte(fmt.Sprintf("<p><a href='%s'>%s</a> %s</p>\n", r.URL.Path+"/..", "..", "上层文件夹")))
}
for _, v := range dir {
if v.Name() != "." || v.Name() != ".." {
if !v.IsDir() {
w.Write([]byte(fmt.Sprintf("<p><a href='%s'>%s</a> %d %s</p>\n", r.URL.Path+"/"+v.Name(), v.Name(), int(v.Size()), v.ModTime().Format("2006-01-02 15:04:05"))))
} else {
w.Write([]byte(fmt.Sprintf("<p><a href='%s'>%s</a> %s %s</p>\n", r.URL.Path+"/"+v.Name(), v.Name(), "文件夹", v.ModTime().Format("2006-01-02 15:04:05"))))
}
}
}
w.Write([]byte("</pre>\n</html>"))
return
}
func uploadfile(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
w.Write([]byte("USE POST METHOD!"))
return
}
r.ParseMultipartForm(10485760)
file, handler, err := r.FormFile("victorique")
if err != nil {
starlog.Errorln(err)
w.WriteHeader(502)
w.Write([]byte(err.Error()))
return
}
defer file.Close()
starlog.Noticef("Upload %s From %s\n", handler.Filename, r.RemoteAddr)
fmt.Fprintf(w, `<html><body><p>%v</p><h2><a href="./vtqeupload1127/web">Return To Web Page</a></h2></body></html>`, handler.Header)
os.Mkdir("./vtqeupload1127", 0755)
f, err := os.OpenFile("./vtqeupload1127/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0755)
if err != nil {
starlog.Errorln(err)
return
}
defer f.Close()
io.Copy(f, file)
}

@ -6,6 +6,10 @@ import (
// Vtqe is my own toolbox
func init() {
cmdMain.AddCommand(tcpingcmd, httpcmd)
}
var cmdMain = &cobra.Command{
Short: "Victorique Wisdom ToolBox",
Long: "中二的工具箱:未来を照らし出せ!",

@ -0,0 +1,17 @@
package ping
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 ping
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 ping
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\-\._\?\,\'/\\\+&amp;%\$#\=~]*)?$`
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 ping
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 ping
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,43 @@
package ping
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestFormatIP(t *testing.T) {
Convey("IP", t, func() {
Convey("for v4 success", func() {
rc := FormatIP("192.168.0.1")
So(rc, ShouldEqual, "192.168.0.1")
})
Convey("for v4 failure", func() {
rc := FormatIP("192.0.1")
So(rc, ShouldEqual, "")
})
Convey("for v4 format", func() {
rc := FormatIP("[192.0.1.1] ")
So(rc, ShouldEqual, "192.0.1.1")
})
Convey("for v6 success", func() {
rc := FormatIP("[2002:ac1f:91c5:1::bd59]")
So(rc, ShouldEqual, "[2002:ac1f:91c5:1::bd59]")
})
Convey("for v6 failure", func() {
rc := FormatIP("2002:ac1f:91c5:1:")
So(rc, ShouldEqual, "")
})
Convey("for v6 format", func() {
rc := FormatIP("2002:ac1f:91c5:1::bd59 ")
So(rc, ShouldEqual, "[2002:ac1f:91c5:1::bd59]")
})
})
}

@ -28,10 +28,6 @@ var (
dnsServer []string
)
func init() {
cmdMain.AddCommand(tcpingcmd)
}
var tcpingcmd = &cobra.Command{
Use: "tcping",
Short: "tcp ping",

Loading…
Cancel
Save