Skip to content

Commit

Permalink
fixup PMSN
Browse files Browse the repository at this point in the history
todo headscale
  • Loading branch information
BapiGso committed Nov 16, 2024
1 parent 89b0f15 commit af8ce3c
Show file tree
Hide file tree
Showing 10 changed files with 278 additions and 68 deletions.
36 changes: 22 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

## ABOUT

**Gopanel** It is a management panel written in Go language with zero dependencies, super simple deployment and very simple functions.
**gopanel** It is a management panel written in Go language with zero dependencies, super simple deployment and very simple functions.

❗Entertainment project, do not use in production environment

Expand All @@ -31,20 +31,28 @@ bash <(curl -s https://raw.githubusercontent.com/BapiGso/gopanel/master/shell/un
```

#### FUNCTION
- Panel security entrance
- Server monitoring
- cron
- webssh
- webdav server
- web file editor
- caddy manage
- frps manage
- frpc manage
- UnblockNeteaseMusic
- docker manage
- nftables
- headscale
- Panel security entrance
- Server monitoring([github.com/shirou/gopsutil](github.com/shirou/gopsutil))
- cron ([github.com/go-co-op/gocron/v2](https://github.com/go-co-op/gocron))
- webssh ([golang.org/x/crypto/ssh](https://golang.org/x/crypto/ssh))
- webdav server ([golang.org/x/net/webdav](https://golang.org/x/net/webdav))
- web file editor
- caddy manage ([github.com/caddyserver/caddy/v2](https://github.com/caddyserver/caddy))
- frps manage ([github.com/fatedier/frp](https://github.com/fatedier/frp))
- frpc manage ([github.com/fatedier/frp](https://github.com/fatedier/frp))
- ~~UnblockNeteaseMusic~~ ([github.com/cnsilvan/UnblockNeteaseMusic](https://github.com/cnsilvan/UnblockNeteaseMusic))
- docker manage ([github.com/docker/docker](https://github.com/docker/docker))
- firewall ([github.com/google/nftables](https://github.com/google/nftables))


#### TODO

- headscale ([github.com/juanfont/headscale](https://github.com/juanfont/headscale))

## LICENSE

released under the [GPL-2.0 License](https://github.com/BapiGso/gopanel/blob/master/LICENSE).

## Acknowledgments

I would like to extend my heartfelt thanks to the gopher developers and the open-source community for their invaluable contributions. Your efforts have made this project possible.
4 changes: 2 additions & 2 deletions assets/header.template
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@
<li><a href="/admin/docker" >docker</a></li>
<li><a href="/admin/frps" >frps</a></li>
<li><a href="/admin/frpc" >frpc</a></li>
<li><a href="/admin/headscale" >headscale</a></li>
<li><a href="/admin/UnblockNeteaseMusic">UnblockNeteaseMusic</a></li>
{{/* <li><a href="/admin/headscale" >headscale</a></li>*/}}
<!-- <li><a href="/admin/UnblockNeteaseMusic">UnblockNeteaseMusic</a></li>-->
<li><a href="/admin/term" >term</a></li>
<li><a href="/admin/cron" >cron</a></li>
<li><a href="/admin/firewall">firewall</a></li>
Expand Down
26 changes: 20 additions & 6 deletions assets/headscale.template
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,26 @@
<!-- <button @click="manageFrps('stop')">Stop frps</button> -->
<button @click="manageHeadscale('enable')">Switch Enable</button>
</p>
<div id="editor"></div>
<form action="/admin/headscale?status=start" method="POST" @submit.prevent="startHeadscale">
<label>服务器URL<input name="server_url" value="https://myheadscale.example.com:443"></label>
<label>监听地址<input name="listen_addr" value="0.0.0.0:8080"></label>
<label>指标监听地址<input name="metrics_listen_addr" value="127.0.0.1:9090"></label>
<label>gRPC监听地址<input name="grpc_listen_addr" value="127.0.0.1:50443"></label>
<label>Noise私钥路径<input name="private_key_path" value="/var/lib/headscale/noise_private.key"></label>
<label>IPv4前缀<input name="ipv4_prefix" value="100.64.0.0/10"></label>
<label>IPv6前缀<input name="ipv6_prefix" value="fd7a:115c:a1e0::/48"></label>
<label>基础域名<input name="base_domain" value="example.com"></label>
<button type="submit">保存配置</button>
</form>
</section>
<script type="text/javascript" src="/assets/js/ace.js"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('panel', () => ({
init(){
window.editor = ace.edit("editor");
{{/*editor.setValue("{{.headscaleConfig}}", -1);*/}}
},
{{/*init(){*/}}
{{/* window.editor = ace.edit("editor");*/}}
{{/* */}}{{/*editor.setValue("{{.headscaleConfig}}", -1);*/}}
{{/*},*/}}
updateConfig(){
fetch(`/admin/headscale`, {
method:'PUT',
Expand All @@ -35,7 +45,11 @@
alert(data);
location.reload();
})
}
},
async startHeadscale(e){
alert(await (await fetch(e.target.action,{method:"POST",body: new FormData(e.target)})).json())
location.reload()
},
})
)
})
Expand Down
3 changes: 2 additions & 1 deletion core/file/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func Process(c echo.Context) error {
}
}
if mode == "PMSN" {
perm, err := strconv.ParseUint(string(data), 10, 32)
perm, err := strconv.ParseUint(string(data), 8, 64)
if err != nil {
return err
}
Expand All @@ -85,6 +85,7 @@ func Process(c echo.Context) error {
}
}
if mode == "update" {

if err = os.WriteFile(path, data, 0644); err != nil {
return err
}
Expand Down
200 changes: 198 additions & 2 deletions core/headscale/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,52 @@ package headscale

import (
"errors"
_ "github.com/juanfont/headscale/cmd/headscale/cli"
"fmt"
"github.com/juanfont/headscale/hscontrol"
"github.com/juanfont/headscale/hscontrol/types"
"github.com/juanfont/headscale/hscontrol/util"
"github.com/labstack/echo/v4"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
"go4.org/netipx"
"io"
"net/http"
"net/netip"
"os"
"tailscale.com/net/tsaddr"
"time"
)

// headscaleConfig 定义了Headscale的配置结构
type headscaleConfig struct {
ServerURL string `form:"server_url"` // 服务器URL,客户端将连接到的地址
ListenAddr string `form:"listen_addr"` // 服务器监听地址
MetricsListenAddr string `form:"metrics_listen_addr"` // metrics监听地址
GRPCListenAddr string `form:"grpc_listen_addr"` // gRPC监听地址
PrivateKeyPath string `form:"private_key_path"` // Noise私钥路径
IPv4Prefix string `form:"ipv4_prefix"` // IPv4地址分配范围
IPv6Prefix string `form:"ipv6_prefix"` // IPv6地址分配范围
BaseDomain string `form:"base_domain"` // MagicDNS基础域名
}

const confPath = "/etc/headscale/config.yaml"

func Index(c echo.Context) error {
req := &headscaleConfig{}
if err := c.Bind(req); err != nil {
return err
}
if err := c.Validate(req); err != nil {
return err
}
switch c.Request().Method {
case "POST":
if c.QueryParam("status") == "start" {
cfg, err := types.LoadServerConfig()
//cfg, err := types.LoadServerConfig()
//if err != nil {
// return err
//}
cfg, err := loadServerConfig(req)
if err != nil {
return err
}
Expand All @@ -31,6 +60,7 @@ func Index(c echo.Context) error {
if err = app.Serve(); err != nil && !errors.Is(err, http.ErrServerClosed) {
return err
}

}

return c.JSON(200, "success")
Expand All @@ -57,3 +87,169 @@ func Index(c echo.Context) error {

return echo.ErrMethodNotAllowed
}

func loadServerConfig(c *headscaleConfig) (*types.Config, error) {
prefix4, err := prefixV4()
if err != nil {
return nil, err
}

prefix6, err := prefixV6()
if err != nil {
return nil, err
}
allocStr := "sequential"
var alloc types.IPAllocationStrategy
switch allocStr {
case string(types.IPAllocationStrategySequential):
alloc = types.IPAllocationStrategySequential
case string(types.IPAllocationStrategyRandom):
alloc = types.IPAllocationStrategyRandom
default:
return nil, fmt.Errorf("config error, prefixes.allocation is set to %s, which is not a valid strategy, allowed options: %s, %s", allocStr, types.IPAllocationStrategySequential, types.IPAllocationStrategyRandom)
}
return &types.Config{
ServerURL: c.ServerURL,
Addr: c.ListenAddr,
MetricsAddr: c.MetricsListenAddr,
GRPCAddr: c.GRPCListenAddr,
GRPCAllowInsecure: false,
DisableUpdateCheck: false,

PrefixV4: prefix4,
PrefixV6: prefix6,
IPAllocation: alloc,

NoisePrivateKeyPath: util.AbsolutePathFromConfigPath(
c.PrivateKeyPath,
),
//BaseDomain: dnsConfig.BaseDomain,
//
//DERP: derpConfig,

EphemeralNodeInactivityTimeout: viper.GetDuration(
"ephemeral_node_inactivity_timeout",
),

Database: types.DatabaseConfig{
Type: "sqlite3",
Debug: false,
Sqlite: types.SqliteConfig{
Path: "/var/lib/headscale/db.sqlite",
WriteAheadLog: false,
},
},
//
//TLS: tlsConfig(),
//
//DNSConfig: dnsToTailcfgDNS(dnsConfig),
//DNSUserNameInMagicDNS: dnsConfig.UserNameInMagicDNS,

ACMEEmail: "",
ACMEURL: "https://acme-v02.api.letsencrypt.org/directory",

UnixSocket: viper.GetString("unix_socket"),
UnixSocketPermission: util.GetFileMode("unix_socket_permission"),

//OIDC: OIDCConfig{
// OnlyStartIfOIDCIsAvailable: viper.GetBool(
// "oidc.only_start_if_oidc_is_available",
// ),
// Issuer: viper.GetString("oidc.issuer"),
// ClientID: viper.GetString("oidc.client_id"),
// ClientSecret: oidcClientSecret,
// Scope: viper.GetStringSlice("oidc.scope"),
// ExtraParams: viper.GetStringMapString("oidc.extra_params"),
// AllowedDomains: viper.GetStringSlice("oidc.allowed_domains"),
// AllowedUsers: viper.GetStringSlice("oidc.allowed_users"),
// AllowedGroups: viper.GetStringSlice("oidc.allowed_groups"),
// StripEmaildomain: viper.GetBool("oidc.strip_email_domain"),
// Expiry: func() time.Duration {
// // if set to 0, we assume no expiry
// if value := viper.GetString("oidc.expiry"); value == "0" {
// return maxDuration
// } else {
// expiry, err := model.ParseDuration(value)
// if err != nil {
// log.Warn().Msg("failed to parse oidc.expiry, defaulting back to 180 days")
//
// return defaultOIDCExpiryTime
// }
//
// return time.Duration(expiry)
// }
// }(),
// UseExpiryFromToken: viper.GetBool("oidc.use_expiry_from_token"),
//},

//LogTail: logTailConfig,
RandomizeClientPort: false,
//
//Policy: policyConfig(),
//
//CLI: CLIConfig{
// Address: viper.GetString("cli.address"),
// APIKey: viper.GetString("cli.api_key"),
// Timeout: viper.GetDuration("cli.timeout"),
// Insecure: viper.GetBool("cli.insecure"),
//},
//
//Log: logConfig,

// TODO(kradalby): Document these settings when more stable
Tuning: types.Tuning{
NotifierSendTimeout: time.Duration(1 * time.Minute),
BatchChangeDelay: time.Duration(1 * time.Second),
NodeMapSessionBufferedChanSize: 256,
},
}, nil
}

func prefixV4() (*netip.Prefix, error) {
prefixV4Str := viper.GetString("prefixes.v4")

if prefixV4Str == "" {
return nil, nil
}

prefixV4, err := netip.ParsePrefix(prefixV4Str)
if err != nil {
return nil, fmt.Errorf("parsing IPv4 prefix from config: %w", err)
}

builder := netipx.IPSetBuilder{}
builder.AddPrefix(tsaddr.CGNATRange())
ipSet, _ := builder.IPSet()
if !ipSet.ContainsPrefix(prefixV4) {
log.Warn().
Msgf("Prefix %s is not in the %s range. This is an unsupported configuration.",
prefixV4Str, tsaddr.CGNATRange())
}

return &prefixV4, nil
}

func prefixV6() (*netip.Prefix, error) {
prefixV6Str := viper.GetString("prefixes.v6")

if prefixV6Str == "" {
return nil, nil
}

prefixV6, err := netip.ParsePrefix(prefixV6Str)
if err != nil {
return nil, fmt.Errorf("parsing IPv6 prefix from config: %w", err)
}

builder := netipx.IPSetBuilder{}
builder.AddPrefix(tsaddr.TailscaleULARange())
ipSet, _ := builder.IPSet()

if !ipSet.ContainsPrefix(prefixV6) {
log.Warn().
Msgf("Prefix %s is not in the %s range. This is an unsupported configuration.",
prefixV6Str, tsaddr.TailscaleULARange())
}

return &prefixV6, nil
}
Loading

0 comments on commit af8ce3c

Please sign in to comment.