Skip to content

Commit

Permalink
20230504
Browse files Browse the repository at this point in the history
  • Loading branch information
cylonchau committed May 4, 2023
1 parent 4593ad1 commit 067f021
Show file tree
Hide file tree
Showing 26 changed files with 209 additions and 135 deletions.
17 changes: 5 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ Uranus is a Linux firewalld central controller. In Greek mythology, Uranus king

[Click](#Screenshot)

![](./images/Uranus.png)

## Features
- Full firewalld features (currently converted OS debian11, centos7)
- Full D-BUS API convert to REST API.
- Full firewalld features
- Full D-BUS API convert to REST API.(currently converted OS debian11, centos7)
- Based dbus remotely.
- HTTP restful API.
- Declarative API and Imperative API.
- Asynchronous batch interface (only add).
- Can control thousands of linux machine via firewall gateway remotely.
Expand All @@ -22,6 +23,7 @@ Uranus is a Linux firewalld central controller. In Greek mythology, Uranus king
- Only HTTP Service (without store).
- UI based VUE-element-admin.
- Support datacenter tag and machine management.
- Support SQLite & MySQL databases.

## TODO
- [X] Asynchronous batch process
Expand All @@ -33,7 +35,6 @@ Uranus is a Linux firewalld central controller. In Greek mythology, Uranus king
- [X] Deplyment on Kubernetes & Docker
- [ ] Prometheus Metics.
- [ ] WAF SDK.
- [ ] Token destory


## Deploy
Expand All @@ -59,14 +60,6 @@ docker run -d --rm cylonchau/uranus

if you think update you dbus-daemon verion to lasest, can use `dbus.spec` make your package.


## Thanks libs
- [kubernetes workqueue](https://github.com/kubernetes/kubernetes)
- [klog](https://github.com/kubernetes/kubernetes)
- [godbus](https://github.com/godbus/dbus)
- [gin](https://github.com/gin-gonic/gin)
- [viper](https://github.com/spf13/viper)

## use

[HTTP API DOC](https://documenter.getpostman.com/view/12796679/UV5agGNr)
Expand Down
Binary file added images/Uranus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion server/apis/code.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ var (
ErrZoneNotFount = &Errno{Code: 40004, Message: "Not found the zone"}
ErrForwardNotFount = &Errno{Code: 40004, Message: "The Forward in the zone is empty"}

// auther errors
// token errors
ErrEncrypt = &Errno{Code: 50101, Message: "success"}
ErrUserNotFound = &Errno{Code: 50102, Message: "User not found"}
ErrTokenInvalid = &Errno{Code: 50103, Message: "Invalied token"}
ErrPasswordIncorrect = &Errno{Code: 50104, Message: "Incorrect username or password"}
ErrUserExist = &Errno{Code: 50105, Message: "User exists"}
ErrUserNotExist = &Errno{Code: 50106, Message: "User does not exist"}
ErrNeedAuth = &Errno{Code: 50107, Message: "Your need authetication"}
ErrTokenDestoryed = &Errno{Code: 50108, Message: "Token is destoryed"}
ErrSendSMSTooMany = &Errno{Code: 50109, Message: "已超出当日限制,请明天再试"}
ErrVerifyCode = &Errno{Code: 50110, Message: "验证码错误"}
ErrEmailOrPassword = &Errno{Code: 50111, Message: "邮箱或密码错误"}
Expand Down
6 changes: 4 additions & 2 deletions server/apis/firewalld_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@ type ResponseSlice struct {
Data interface{} `form:"data" json:"data,omitempty"`
}

func AuthFailed(ctx *gin.Context, msg *Errno) {
func AuthFailed(ctx *gin.Context, msg *Errno, data interface{}) {
ctx.JSON(http.StatusUnauthorized, Response{
Code: msg.Code,
Msg: msg.Message,
Data: data,
})
}

// API403Response ....
func Auth403Failed(ctx *gin.Context, msg *Errno) {
func Auth403Failed(ctx *gin.Context, msg *Errno, data interface{}) {
ctx.JSON(http.StatusForbidden, Response{
Code: msg.Code,
Msg: msg.Message,
Data: data,
})
}

Expand Down
4 changes: 2 additions & 2 deletions server/apis/user_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ type InfoQuery struct {
}

type InfoResp struct {
Username string `form:"token" json:"token" binding:"required"`
UserRole string `form:"token" json:"token" binding:"required"`
Username string `form:"username" json:"username" binding:"required"`
UserRole string `form:"role" json:"role" binding:"required"`
}
8 changes: 4 additions & 4 deletions server/app/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"reflect"

"github.com/cylonchau/firewalld-gateway/server/apis"
"github.com/cylonchau/firewalld-gateway/server/app/auther"
token2 "github.com/cylonchau/firewalld-gateway/utils/auther"
userModel "github.com/cylonchau/firewalld-gateway/utils/model"

"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -46,7 +46,7 @@ func (u *Auth) signinHandler(c *gin.Context) {
var ip uint32
if ip, enconterError = userModel.GetRequestIP(c.Request); enconterError == nil {
userModel.LastLogin(int64(user.ID), ip)
if token, enconterError = auther.GenToken(int64(user.ID)); enconterError == nil {
if token, enconterError = token2.GenToken(int64(user.ID)); enconterError == nil {
apis.SuccessResponse(c, nil, apis.UserResp{
UserID: uint64(user.ID),
Token: token,
Expand All @@ -56,7 +56,7 @@ func (u *Auth) signinHandler(c *gin.Context) {
}
}

if token, enconterError = auther.GenToken(int64(user.ID)); enconterError == nil {
if token, enconterError = token2.GenToken(int64(user.ID)); enconterError == nil {
apis.SuccessResponse(c, nil, apis.UserResp{
UserID: uint64(user.ID),
Token: token,
Expand Down Expand Up @@ -98,7 +98,7 @@ func (u *Auth) userInfoHandler(c *gin.Context) {
return
}

uid, err := auther.GetInfo(userInfoQuery.Token)
uid, err := token2.GetInfo(userInfoQuery.Token)
if err != nil {
apis.APIResponse(c, err, nil)
return
Expand Down
70 changes: 70 additions & 0 deletions server/app/firewalld/v1/dashboard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package v1

import (
"github.com/gin-gonic/gin"

code "github.com/cylonchau/firewalld-gateway/server/apis"
"github.com/cylonchau/firewalld-gateway/utils/firewalld"
)

type DashboardRouter struct{}

func (this *DashboardRouter) RegisterPortAPI(g *gin.RouterGroup) {
dashboardGroup := g.Group("/dashboard")
dashboardGroup.GET("/", this.getRuntimeStatus)

}

// getRuntimeStatus ...
// @Summary getRuntimeStatus
// @Produce json
// @Success 200 {object} internal.Response
// @Router /fw/v1/dashboard [GET]
func (this *DashboardRouter) getRuntimeStatus(c *gin.Context) {

var query = &code.Query{}
err := c.BindQuery(query)

if err != nil {
code.APIResponse(c, err, nil)
return
}

dbusClient, err := firewalld.NewDbusClientService(query.Ip)
if err != nil {
code.ConnectDbusService(c, err)
return
}
defer dbusClient.Destroy()
defaultPolicy := dbusClient.GetDefaultPolicy()
defaultZone := dbusClient.GetDefaultZone()
var richCount, portCount, serviceCount int
var natStatus bool

if richs, err := dbusClient.GetRichRules(defaultZone); err == nil {
richCount = len(richs)
if ports, err := dbusClient.GetPorts(defaultZone); err == nil {
portCount = len(ports)
if services, err := dbusClient.GetServices(); err == nil {
serviceCount = len(services)
if b, err := dbusClient.QueryMasquerade(defaultZone); err == nil {
natStatus = b
}
}
}
}

if err == nil {
status := make(map[string]interface{})
status["default_zone"] = defaultZone
status["default_policy"] = defaultPolicy
status["nat_status"] = natStatus
status["rich"] = richCount
status["port"] = portCount
status["service"] = serviceCount
code.SuccessResponse(c, code.OK, status)
} else {
code.SuccessResponse(c, code.OK, err)
}

}
16 changes: 8 additions & 8 deletions server/app/firewalld/v1/masquerade.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import (
type MasqueradeRouter struct{}

func (this *MasqueradeRouter) RegisterPortAPI(g *gin.RouterGroup) {
portGroup := g.Group("/masquerade")

portGroup.PUT("/", this.enableInRuntime)
portGroup.DELETE("/", this.disableInRuntime)
portGroup.GET("/", this.queryInRuntime)
portGroup.PUT("/permanent", this.enableInPermanent)
portGroup.DELETE("/permanent", this.disableInPermanent)
portGroup.GET("/query", this.queryInPermanent)
masqueradeGroup := g.Group("/masquerade")

masqueradeGroup.PUT("/", this.enableInRuntime)
masqueradeGroup.DELETE("/", this.disableInRuntime)
masqueradeGroup.GET("/", this.queryInRuntime)
masqueradeGroup.PUT("/permanent", this.enableInPermanent)
masqueradeGroup.DELETE("/permanent", this.disableInPermanent)
masqueradeGroup.GET("/query", this.queryInPermanent)
}

// enableInRuntime ...
Expand Down
8 changes: 4 additions & 4 deletions server/app/firewalld/v1/nat.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import (
type NATRouter struct{}

func (this *NATRouter) RegisterNATRouterAPI(g *gin.RouterGroup) {
portGroup := g.Group("/nat")
natGroup := g.Group("/nat")

portGroup.POST("/", this.addForwardInRuntime)
portGroup.GET("/", this.getForwardInRuntime)
portGroup.DELETE("/", this.delForwardInRuntime)
natGroup.POST("/", this.addForwardInRuntime)
natGroup.GET("/", this.getForwardInRuntime)
natGroup.DELETE("/", this.delForwardInRuntime)
}

// addForward ...
Expand Down
8 changes: 4 additions & 4 deletions server/app/firewalld/v1/rich_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
type RichRuleRouter struct{}

func (this *RichRuleRouter) RegisterPortAPI(g *gin.RouterGroup) {
portGroup := g.Group("/rich")
portGroup.POST("/", this.addRichRuleAtRuntime)
portGroup.GET("/", this.getRichRulesAtRuntime)
portGroup.DELETE("/", this.delRichRuleAtRuntime)
richGroup := g.Group("/rich")
richGroup.POST("/", this.addRichRuleAtRuntime)
richGroup.GET("/", this.getRichRulesAtRuntime)
richGroup.DELETE("/", this.delRichRuleAtRuntime)
}

// GetRichRules ...
Expand Down
12 changes: 6 additions & 6 deletions server/app/firewalld/v1/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import (
type ServiceRouter struct{}

func (this *ServiceRouter) RegisterPortAPI(g *gin.RouterGroup) {
portGroup := g.Group("/service")
portGroup.GET("/", this.getServicesAtRuntime)
portGroup.DELETE("/", this.deleteServicesAtRuntime)
portGroup.POST("/", this.addServicesAtRuntime)
portGroup.POST("/new", this.newServiceAtPermanent)
portGroup.GET("/list", this.listServicesAtRuntime)
serivceGroup := g.Group("/service")
serivceGroup.GET("/", this.getServicesAtRuntime)
serivceGroup.DELETE("/", this.deleteServicesAtRuntime)
serivceGroup.POST("/", this.addServicesAtRuntime)
serivceGroup.POST("/new", this.newServiceAtPermanent)
serivceGroup.GET("/list", this.listServicesAtRuntime)

}

Expand Down
18 changes: 0 additions & 18 deletions server/app/firewalld/v1/stroage.go

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package auther
package middlewares

import (
"strings"

"github.com/gin-gonic/gin"

"github.com/cylonchau/firewalld-gateway/server/apis"
"github.com/cylonchau/firewalld-gateway/utils/auther"
"github.com/cylonchau/firewalld-gateway/utils/model"
)

// JWTAuthMiddleware 基于JWT的认证中间件
Expand All @@ -17,26 +19,32 @@ func JWTAuthMiddleware() func(c *gin.Context) {
// 这里的具体实现方式要依据你的实际业务情况决定
authHeader := c.Request.Header.Get("Authorization")
if authHeader == "" {
apis.AuthFailed(c, apis.ErrNeedAuth)
apis.AuthFailed(c, apis.ErrNeedAuth, nil)
c.Abort() // 中止
return
}
// 按空格分割
parts := strings.SplitN(authHeader, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
apis.AuthFailed(c, apis.ErrTokenInvalid)
apis.Auth403Failed(c, apis.ErrTokenInvalid, nil)
c.Abort()
return
}
tokenStr := parts[1]
if model.TokenIsDestoryed(tokenStr) {
apis.Auth403Failed(c, apis.ErrTokenDestoryed, nil)
c.Abort()
return
}
// parts[1]是获取到的tokenString,我们使用之前定义好的解析JWT的函数来解析它
mc, err := ParseToken(parts[1])
mc, err := auther.ParseToken(tokenStr)
if err != nil {
apis.AuthFailed(c, apis.ErrTokenInvalid)
apis.Auth403Failed(c, apis.ErrTokenInvalid, err.Error())
c.Abort()
return
}
// 将当前请求的userid信息保存到请求的上下文c上
c.Set(UserIDKey, mc.UserID)
c.Set(auther.UserIDKey, mc.UserID)

c.Next() // 后续的处理函数可以用过c.Get("username")来获取当前请求的用户信息
}
Expand Down
7 changes: 5 additions & 2 deletions server/app/router/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ import (

"github.com/cylonchau/firewalld-gateway/config"
"github.com/cylonchau/firewalld-gateway/server/app/auth"
"github.com/cylonchau/firewalld-gateway/server/app/auther"
"github.com/cylonchau/firewalld-gateway/server/app/firewalld/host"
"github.com/cylonchau/firewalld-gateway/server/app/firewalld/tag"
"github.com/cylonchau/firewalld-gateway/server/app/firewalld/template"
Token "github.com/cylonchau/firewalld-gateway/server/app/firewalld/token"
fv1 "github.com/cylonchau/firewalld-gateway/server/app/firewalld/v1"
fv2 "github.com/cylonchau/firewalld-gateway/server/app/firewalld/v2"
fv3 "github.com/cylonchau/firewalld-gateway/server/app/firewalld/v3"
"github.com/cylonchau/firewalld-gateway/server/app/middlewares"
)

func RegisteredRouter(e *gin.Engine) {
e.Handle("GET", "ping", ping)

firewallAPI := e.Group("/fw")
authAPI := e.Group("/auth")
firewallAPI.Use(auther.JWTAuthMiddleware())
firewallAPI.Use(middlewares.JWTAuthMiddleware())

fv1Group := firewallAPI.Group("/v1")
fv2Group := firewallAPI.Group("/v2")
Expand All @@ -46,6 +46,9 @@ func RegisteredRouter(e *gin.Engine) {
serviceRouter := &fv1.ServiceRouter{}
serviceRouter.RegisterPortAPI(fv1Group)

dashboardRouter := &fv1.DashboardRouter{}
dashboardRouter.RegisterPortAPI(fv1Group)

natv2Router := &fv2.NatRouter{}
natv2Router.RegisterPortAPI(fv2Group)

Expand Down
Loading

0 comments on commit 067f021

Please sign in to comment.