feat: complete basic functions

Support http,dns and mysql connection. Support custom http, dns response. Support dns rebinding.
Support mysql load local files and jdbc deserialize exploit.
This commit is contained in:
Li4n0
2021-04-21 18:55:16 +08:00
parent e9db8ddb24
commit 3559894acc
114 changed files with 41617 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
package server
import (
"github.com/li4n0/revsuit/pkg/dns"
"github.com/li4n0/revsuit/pkg/mysql"
"github.com/li4n0/revsuit/pkg/rhttp"
)
type noticeConfig struct {
DingTalk string
Lark string
WeiXin string
Slack string
}
type Config struct {
Addr string
Token string
Database string
LogLevel string
Notice noticeConfig
rhttp.Config
DNS dns.Config
Mysql mysql.Config
}
+29
View File
@@ -0,0 +1,29 @@
package server
import (
"io"
"github.com/gin-gonic/gin"
"github.com/li4n0/revsuit/internal/record"
log "unknwon.dev/clog/v2"
)
func ping(c *gin.Context) {
c.SetCookie("token", c.Request.Header["Token"][0], 0, "/revsuit/api/", c.Request.Host, true, true)
c.String(200, "pong")
}
func events(c *gin.Context) {
log.Info("Receive connection from ", c.Request.RemoteAddr)
c.Stream(func(w io.Writer) bool {
c.SSEvent("message", "connect succeed")
select {
case <-c.Writer.CloseNotify():
return false
case r := <-record.Channel():
c.SSEvent("message", r.GetFlag())
}
return true
})
log.Info(c.Request.RemoteAddr, "disconnect")
}
+83
View File
@@ -0,0 +1,83 @@
package server
import (
"io/fs"
"net/http"
"github.com/gin-gonic/gin"
"github.com/li4n0/revsuit/frontend"
"github.com/li4n0/revsuit/pkg/dns"
"github.com/li4n0/revsuit/pkg/mysql"
"github.com/li4n0/revsuit/pkg/rhttp"
log "unknwon.dev/clog/v2"
)
func (revsuit *Revsuit) registerRouter() {
revsuit.http.Router = gin.Default()
revsuit.registerPlatformRouter()
revsuit.registerHttpRouter()
}
func (revsuit *Revsuit) registerPlatformRouter() {
// /api need Authorization
api := revsuit.http.Router.Group("/revsuit/api")
api.Use(func(c *gin.Context) {
cookieToken, err := c.Request.Cookie("token")
if !(c.Request.Header.Get("Token") == revsuit.http.Token || err == nil && cookieToken.Value == revsuit.http.Token) {
c.Abort()
c.Status(403)
return
}
})
revsuit.http.ApiGroup = api
//platform routers
api.GET("/events", events)
api.GET("/ping", ping)
}
func (revsuit *Revsuit) registerHttpRouter() {
revsuit.http.Router.NoRoute(revsuit.http.Receive)
//register frontend
fe, err := fs.Sub(frontend.FS, "dist")
if err != nil {
log.Fatal("Failed to sub path `dist`: %v", err)
}
revsuit.http.Router.StaticFS("/revsuit/admin", http.FS(fe))
// init record router group
recordGroup := revsuit.http.ApiGroup.Group("/record")
httpGroup := recordGroup.Group("/http")
httpGroup.GET("", rhttp.ListRecords)
dnsGroup := recordGroup.Group("/dns")
dnsGroup.GET("", dns.List)
mysqlGroup := recordGroup.Group("/mysql")
mysqlGroup.GET("", mysql.List)
// init rule router group
ruleGroup := revsuit.http.ApiGroup.Group("/rule")
httpGroup = ruleGroup.Group("/http")
httpGroup.GET("", rhttp.ListRules)
httpGroup.POST("", rhttp.UpsertRules)
httpGroup.DELETE("", rhttp.DeleteRules)
dnsGroup = ruleGroup.Group("/dns")
dnsGroup.GET("", dns.ListRules)
dnsGroup.POST("", dns.UpsertRules)
dnsGroup.DELETE("", dns.DeleteRules)
mysqlGroup = ruleGroup.Group("/mysql")
mysqlGroup.GET("", mysql.ListRules)
mysqlGroup.POST("", mysql.UpsertRules)
mysqlGroup.DELETE("", mysql.DeleteRules)
// init file router group
fileGroup := revsuit.http.ApiGroup.Group("/file")
fileGroup.GET("/mysql/:id", mysql.GetFile)
}
+136
View File
@@ -0,0 +1,136 @@
package server
import (
"github.com/gin-gonic/gin"
"github.com/li4n0/revsuit/internal/database"
"github.com/li4n0/revsuit/internal/notice"
"github.com/li4n0/revsuit/pkg/dns"
"github.com/li4n0/revsuit/pkg/mysql"
http "github.com/li4n0/revsuit/pkg/rhttp"
"gorm.io/gorm/logger"
log "unknwon.dev/clog/v2"
)
type Revsuit struct {
http *http.Server
dns *dns.Server
mysql *mysql.Server
}
func initDatabase(dsn string) {
err := database.InitDB("sqlite", dsn)
if err != nil {
log.Fatal(err.Error())
}
err = database.DB.AutoMigrate(&http.Record{})
err = database.DB.AutoMigrate(&dns.Record{})
err = database.DB.AutoMigrate(&mysql.Record{})
err = database.DB.AutoMigrate(&http.Rule{})
err = database.DB.AutoMigrate(&dns.Rule{})
err = database.DB.AutoMigrate(&mysql.Rule{})
err = database.DB.AutoMigrate(&mysql.File{})
if err != nil {
log.Fatal(err.Error())
}
}
func initLog(level string) {
var logLevel log.Level
switch level {
case "debug":
gin.SetMode(gin.DebugMode)
database.DB.Logger.LogMode(logger.Info)
logLevel = log.LevelTrace
case "info":
gin.SetMode(gin.DebugMode)
database.DB.Logger.LogMode(logger.Info)
logLevel = log.LevelInfo
case "warning":
gin.SetMode(gin.ReleaseMode)
database.DB.Logger.LogMode(logger.Warn)
logLevel = log.LevelWarn
case "error":
gin.SetMode(gin.ReleaseMode)
database.DB.Logger.LogMode(logger.Error)
logLevel = log.LevelError
case "fatal":
gin.SetMode(gin.ReleaseMode)
database.DB.Logger.LogMode(logger.Error)
logLevel = log.LevelFatal
}
_ = log.NewConsole(100,
log.ConsoleConfig{
Level: logLevel,
})
}
func initNotice(nc noticeConfig) {
n := notice.New()
if nc.DingTalk != "" {
n.AddBot(&notice.DingTalk{
URL: nc.DingTalk,
})
}
if nc.Lark != "" {
n.AddBot(&notice.Lark{
URL: nc.Lark,
})
}
if nc.WeiXin != "" {
n.AddBot(&notice.Weixin{
URL: nc.WeiXin,
})
}
if nc.Slack != "" {
n.AddBot(&notice.Slack{
URL: nc.Slack,
})
}
}
func New(c *Config) *Revsuit {
initDatabase(c.Database)
initLog(c.LogLevel)
initNotice(c.Notice)
s := &Revsuit{
http: http.GetServer(),
}
if c.DNS.Enable {
s.dns = dns.GetServer()
}
if c.Mysql.Enable {
s.mysql = mysql.GetServer()
s.mysql.Config = c.Mysql
}
if c.Addr != "" {
s.http.SetAddr(c.Addr)
}
if c.Token != "" {
s.http.SetToken(c.Token)
}
if c.IpHeader != "" {
s.http.SetIpHeader(c.IpHeader)
}
return s
}
func (revsuit *Revsuit) Run() {
defer log.Stop()
revsuit.registerRouter()
if revsuit.dns != nil {
go revsuit.dns.Run()
}
if revsuit.mysql != nil {
go revsuit.mysql.Run()
}
revsuit.http.Run()
}