add webhook notification events
This commit is contained in:
parent
466d69eae0
commit
b886843a5d
BIN
cmd/frpc/frpc
Executable file
BIN
cmd/frpc/frpc
Executable file
Binary file not shown.
9
cmd/frpc/frpc.ini
Normal file
9
cmd/frpc/frpc.ini
Normal file
@ -0,0 +1,9 @@
|
||||
[common]
|
||||
server_addr = 127.0.0.1
|
||||
server_port = 7000
|
||||
|
||||
[proxy_name]
|
||||
type = tcp
|
||||
local_ip = 192.168.178.192
|
||||
local_port = 22
|
||||
plugin = http_proxy
|
BIN
cmd/frps/frps
Executable file
BIN
cmd/frps/frps
Executable file
Binary file not shown.
3
cmd/frps/frps.ini
Normal file
3
cmd/frps/frps.ini
Normal file
@ -0,0 +1,3 @@
|
||||
[common]
|
||||
bind_port = 7000
|
||||
webhook_url = https://webhook.site/d8593a16-2efd-4973-88fc-150e7606f957
|
@ -62,6 +62,7 @@ var (
|
||||
dashboardTLSMode bool
|
||||
dashboardTLSCertFile string
|
||||
dashboardTLSKeyFile string
|
||||
webhookURL string
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -93,6 +94,7 @@ func init() {
|
||||
rootCmd.PersistentFlags().BoolVarP(&dashboardTLSMode, "dashboard_tls_mode", "", false, "dashboard tls mode")
|
||||
rootCmd.PersistentFlags().StringVarP(&dashboardTLSCertFile, "dashboard_tls_cert_file", "", "", "dashboard tls cert file")
|
||||
rootCmd.PersistentFlags().StringVarP(&dashboardTLSKeyFile, "dashboard_tls_key_file", "", "", "dashboard tls key file")
|
||||
rootCmd.PersistentFlags().StringVarP(&webhookURL, "webhook_url", "w", "", "webhook")
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
@ -176,6 +178,7 @@ func parseServerCommonCfgFromCmd() (cfg config.ServerCommonConf, err error) {
|
||||
cfg.LogMaxDays = logMaxDays
|
||||
cfg.SubDomainHost = subDomainHost
|
||||
cfg.TLSOnly = tlsOnly
|
||||
cfg.WebhookURL = webhookURL
|
||||
|
||||
// Only token authentication is supported in cmd mode
|
||||
cfg.ServerConfig = auth.GetDefaultServerConf()
|
||||
|
2
go.mod
2
go.mod
@ -54,6 +54,7 @@ require (
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/parnurzeal/gorequest v0.2.16 // indirect
|
||||
github.com/pion/dtls/v2 v2.2.7 // indirect
|
||||
github.com/pion/logging v0.2.2 // indirect
|
||||
github.com/pion/transport/v2 v2.2.1 // indirect
|
||||
@ -78,6 +79,7 @@ require (
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect
|
||||
moul.io/http2curl v1.0.0 // indirect
|
||||
)
|
||||
|
||||
// TODO(fatedier): Temporary use the modified version, update to the official version after merging into the official repository.
|
||||
|
12
go.sum
12
go.sum
@ -36,6 +36,7 @@ github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
|
||||
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
@ -86,6 +87,9 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI=
|
||||
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/reedsolomon v1.9.15 h1:g2erWKD2M6rgnPf89fCji6jNlhMKMdXcuNHMW1SYCIo=
|
||||
@ -99,10 +103,15 @@ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/Qd
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU=
|
||||
github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM=
|
||||
github.com/onsi/gomega v1.27.8 h1:gegWiwZjBsf2DgiSbf5hpokZ98JVDMcWkUiigk6/KXc=
|
||||
github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJKFnNQ=
|
||||
github.com/parnurzeal/gorequest v0.2.16 h1:T/5x+/4BT+nj+3eSknXmCTnEVGSzFzPGdpqmUVVZXHQ=
|
||||
github.com/parnurzeal/gorequest v0.2.16/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
|
||||
github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8=
|
||||
github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s=
|
||||
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
|
||||
@ -275,6 +284,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
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=
|
||||
@ -286,3 +296,5 @@ k8s.io/client-go v0.27.4 h1:vj2YTtSJ6J4KxaC88P4pMPEQECWMY8gqPqsTgUKzvjk=
|
||||
k8s.io/client-go v0.27.4/go.mod h1:ragcly7lUlN0SRPk5/ZkGnDjPknzb37TICq07WhI6Xc=
|
||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
|
||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
|
||||
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=
|
||||
|
@ -194,6 +194,8 @@ type ServerCommonConf struct {
|
||||
PprofEnable bool `ini:"pprof_enable" json:"pprof_enable"`
|
||||
// NatHoleAnalysisDataReserveHours specifies the hours to reserve nat hole analysis data.
|
||||
NatHoleAnalysisDataReserveHours int64 `ini:"nat_hole_analysis_data_reserve_hours" json:"nat_hole_analysis_data_reserve_hours"`
|
||||
// WebhookURL is the endpoint we send webhook events to
|
||||
WebhookURL string `ini:"webhook_url" json:"webhook_url"`
|
||||
}
|
||||
|
||||
// GetDefaultServerConf returns a server configuration with reasonable
|
||||
@ -224,6 +226,7 @@ func GetDefaultServerConf() ServerCommonConf {
|
||||
HTTPPlugins: make(map[string]plugin.HTTPPluginOptions),
|
||||
UDPPacketSize: 1500,
|
||||
NatHoleAnalysisDataReserveHours: 7 * 24,
|
||||
WebhookURL: "",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,6 +155,7 @@ type Control struct {
|
||||
|
||||
xl *xlog.Logger
|
||||
ctx context.Context
|
||||
webhook *Webhook
|
||||
}
|
||||
|
||||
func NewControl(
|
||||
@ -193,6 +194,7 @@ func NewControl(
|
||||
serverCfg: serverCfg,
|
||||
xl: xlog.FromContextSafe(ctx),
|
||||
ctx: ctx,
|
||||
webhook: NewWebhook(serverCfg.WebhookURL),
|
||||
}
|
||||
ctl.msgTransporter = transport.NewMessageTransporter(ctl.sendCh)
|
||||
return ctl
|
||||
@ -401,6 +403,7 @@ func (ctl *Control) stoper() {
|
||||
pxy.Close()
|
||||
ctl.pxyManager.Del(pxy.GetName())
|
||||
metrics.Server.CloseProxy(pxy.GetName(), pxy.GetConf().GetBaseConfig().ProxyType)
|
||||
ctl.webhook.OnDisconnect(ctl.loginMsg.RunID)
|
||||
|
||||
notifyContent := &plugin.CloseProxyContent{
|
||||
User: plugin.UserInfo{
|
||||
@ -496,6 +499,7 @@ func (ctl *Control) manager() {
|
||||
resp.RemoteAddr = remoteAddr
|
||||
xl.Info("new proxy [%s] type [%s] success", m.ProxyName, m.ProxyType)
|
||||
metrics.Server.NewProxy(m.ProxyName, m.ProxyType)
|
||||
ctl.webhook.OnConnect(ctl.conn, m, ctl.loginMsg)
|
||||
}
|
||||
ctl.sendCh <- resp
|
||||
case *msg.NatHoleVisitor:
|
||||
@ -624,6 +628,8 @@ func (ctl *Control) CloseProxy(closeMsg *msg.CloseProxy) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
ctl.webhook.OnDisconnect(ctl.loginMsg.RunID)
|
||||
|
||||
if ctl.serverCfg.MaxPortsPerClient > 0 {
|
||||
ctl.portsUsedNum -= pxy.GetUsedPortsNum()
|
||||
}
|
||||
|
105
server/webhook_controller.go
Normal file
105
server/webhook_controller.go
Normal file
@ -0,0 +1,105 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/fatedier/frp/pkg/msg"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
// ClientIP is the IP address of the connected proxy
|
||||
ClientIP string `json:"client_ip"`
|
||||
// RemotePort is the Port number of the proxy
|
||||
RemotePort int `json:"remote_port"`
|
||||
// LocalAddr is the IP address of this frps instance
|
||||
LocalAddr string `json:"local_addr"`
|
||||
// ProxyName is the name of the connected proxy
|
||||
ProxyName string `json:"proxy_name"`
|
||||
// ProxyType is the type of the connected proxy (tcp or ssh)
|
||||
ProxyType string `json:"proxy_type"`
|
||||
// Headers is a map of the connected proxy headers
|
||||
Headers map[string]string `json:"headers"`
|
||||
// Os is the operating system the frpc is running on
|
||||
Os string `json:"os"`
|
||||
// Arch is the system architecture of the frpc
|
||||
Arch string `json:"arch"`
|
||||
// Version is the frpc proxy version
|
||||
Version string `json:"version"`
|
||||
// Hostname is the name of the frpc machine
|
||||
Hostname string `json:"hostname"`
|
||||
}
|
||||
|
||||
type Payload struct {
|
||||
// Event is the name of the webhook event (offline or online)
|
||||
Event string `json:"event"`
|
||||
// UniqueID is the ID of the proxy
|
||||
UniqueID string `json:"unique_id"`
|
||||
// Data is a struct containing the information of the connected proxy
|
||||
Data *Data `json:"data"`
|
||||
}
|
||||
|
||||
type Webhook struct {
|
||||
endpoint string
|
||||
client *gorequest.SuperAgent
|
||||
connections map[string]Payload
|
||||
}
|
||||
|
||||
// NewWebhook returns an instance of the webhook object for each connected proxy
|
||||
func NewWebhook(endpoint string) *Webhook {
|
||||
return &Webhook{
|
||||
endpoint: endpoint,
|
||||
client: gorequest.New(),
|
||||
connections: map[string]Payload{},
|
||||
}
|
||||
}
|
||||
|
||||
// OnConnect is called when a proxy gets connected
|
||||
func (w *Webhook) OnConnect(conn net.Conn, m *msg.NewProxy, l *msg.Login) string {
|
||||
uniqueID := l.RunID
|
||||
d := &Data{
|
||||
ClientIP: conn.RemoteAddr().String(),
|
||||
LocalAddr: conn.LocalAddr().String(),
|
||||
ProxyName: m.ProxyName,
|
||||
ProxyType: m.ProxyType,
|
||||
RemotePort: m.RemotePort,
|
||||
Headers: m.Headers,
|
||||
Os: l.Os,
|
||||
Arch: l.Arch,
|
||||
Version: l.Version,
|
||||
Hostname: l.Hostname,
|
||||
}
|
||||
|
||||
p := Payload{
|
||||
Event: "online",
|
||||
UniqueID: uniqueID,
|
||||
Data: d,
|
||||
}
|
||||
|
||||
w.connections[uniqueID] = p
|
||||
w.send(p)
|
||||
|
||||
return uniqueID
|
||||
}
|
||||
|
||||
// OnDisconnect is called when a proxy disconnects
|
||||
func (w *Webhook) OnDisconnect(id string) {
|
||||
if p, ok := w.connections[id]; ok {
|
||||
p.Event = "offline"
|
||||
w.send(p)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Webhook) send(p Payload) {
|
||||
b, err := json.Marshal(&p)
|
||||
if err != nil {
|
||||
fmt.Printf("error marshalling payload: %s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
w.client.Post(w.endpoint).
|
||||
Send(string(b)).
|
||||
End()
|
||||
}
|
Loading…
Reference in New Issue
Block a user