From 6e0f323e8e01b93179616f1610812ca8137af3b4 Mon Sep 17 00:00:00 2001 From: Jett Wang Date: Wed, 9 Oct 2024 12:59:28 +0800 Subject: [PATCH 1/8] Refactor RadiusService to use a mutex for EapStateCache --- toughradius/radius.go | 49 +++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/toughradius/radius.go b/toughradius/radius.go index 4cd7020f..c3532b7f 100644 --- a/toughradius/radius.go +++ b/toughradius/radius.go @@ -65,6 +65,7 @@ type RadiusService struct { EapStateCache map[string]EapState TaskPool *ants.Pool arclock sync.Mutex + eaplock sync.Mutex } func NewRadiusService() *RadiusService { @@ -149,44 +150,30 @@ func (s *RadiusService) GetUserForAcct(username string) (user *models.RadiusUser return user, nil } +func (s *RadiusService) UpdateUserField(username string, field string, value interface{}) { + err := app.GDB(). + Model(&models.RadiusUser{}). + Where("username = ?", username). + Update(field, value).Error + if err != nil { + log.Error2(fmt.Sprintf("update user %s error", field), zap.Error(err), zap.String("namespace", "radius")) + } +} + func (s *RadiusService) UpdateUserMac(username string, macaddr string) { - err := app.GDB(). - Model(&models.RadiusUser{}). - Where("username = ?", username). - Update("mac_addr", macaddr).Error - if err != nil { - log.Error2("update user mac error", zap.Error(err), zap.String("namespace", "radius")) - } + s.UpdateUserField(username, "mac_addr", macaddr) } func (s *RadiusService) UpdateUserVlanid1(username string, vlanid1 int) { - err := app.GDB(). - Model(&models.RadiusUser{}). - Where("username = ?", username). - Update("vlanid1", vlanid1).Error - if err != nil { - log.Error2("update user vlanid1 error", zap.Error(err), zap.String("namespace", "radius")) - } + s.UpdateUserField(username, "vlanid1", vlanid1) } func (s *RadiusService) UpdateUserVlanid2(username string, vlanid2 int) { - err := app.GDB(). - Model(&models.RadiusUser{}). - Where("username = ?", username). - Update("vlanid2", vlanid2).Error - if err != nil { - log.Error2("update user vlanid2 error", zap.Error(err), zap.String("namespace", "radius")) - } + s.UpdateUserField(username, "vlanid2", vlanid2) } func (s *RadiusService) UpdateUserLastOnline(username string) { - err := app.GDB(). - Model(&models.RadiusUser{}). - Where("username = ?", username). - Update("last_online", time.Now()).Error - if err != nil { - log.Error2("update user last online error", zap.Error(err), zap.String("namespace", "radius")) - } + s.UpdateUserField(username, "last_online", time.Now()) } func (s *RadiusService) GetIntConfig(name string, defval int64) int64 { @@ -421,6 +408,8 @@ func (s *RadiusService) CheckRequestSecret(r *radius.Packet, secret []byte) { // State add func (s *RadiusService) AddEapState(stateid, username string, challenge []byte, eapMethad string) { + s.eaplock.Lock() + defer s.eaplock.Unlock() s.EapStateCache[stateid] = EapState{ Username: username, StateID: stateid, @@ -432,6 +421,8 @@ func (s *RadiusService) AddEapState(stateid, username string, challenge []byte, // State get func (s *RadiusService) GetEapState(stateid string) (state *EapState, err error) { + s.eaplock.Lock() + defer s.eaplock.Unlock() val, ok := s.EapStateCache[stateid] if ok { return &val, nil @@ -441,5 +432,7 @@ func (s *RadiusService) GetEapState(stateid string) (state *EapState, err error) // State delete func (s *RadiusService) DeleteEapState(stateid string) { + s.eaplock.Lock() + defer s.eaplock.Unlock() delete(s.EapStateCache, stateid) } From 2f2b1192e99a9fa5642fd64d70614d250d16665d Mon Sep 17 00:00:00 2001 From: Jett Wang Date: Wed, 9 Oct 2024 13:04:17 +0800 Subject: [PATCH 2/8] Refactor log.Error2 to log.ErrorDetail for more descriptive error messages --- common/zaplog/log/say.go | 2 +- freeradius/handlers.go | 12 ++++++------ toughradius/acct_ops.go | 2 +- toughradius/acct_start.go | 4 ++-- toughradius/acct_stop.go | 4 ++-- toughradius/acct_update.go | 4 ++-- toughradius/radius.go | 28 ++++++++++++++-------------- toughradius/radius_acct.go | 5 ++--- toughradius/radius_auth.go | 10 +++++----- tr069/handlers.go | 22 +++++++++++----------- 10 files changed, 46 insertions(+), 47 deletions(-) diff --git a/common/zaplog/log/say.go b/common/zaplog/log/say.go index 28feffc8..9e7101d2 100644 --- a/common/zaplog/log/say.go +++ b/common/zaplog/log/say.go @@ -40,7 +40,7 @@ func Error(args ...interface{}) { zap.S().Error(args...) } -func Error2(msg string, fields ...zap.Field) { +func ErrorDetail(msg string, fields ...zap.Field) { defer zap.L().Sync() zap.L().Error(msg, fields...) } diff --git a/freeradius/handlers.go b/freeradius/handlers.go index 5337aaf7..1bf45b47 100644 --- a/freeradius/handlers.go +++ b/freeradius/handlers.go @@ -60,7 +60,7 @@ func (s *FreeradiusServer) FreeradiusAuthorize(c echo.Context) error { var user models.RadiusUser err := app.GDB().Where("username=?", username).First(&user).Error if err != nil { - log.Error2("radius auth error", + log.ErrorDetail("radius auth error", zap.String("namespace", "freeradius"), zap.String("username", username), zap.String("nasip", nasip), @@ -72,7 +72,7 @@ func (s *FreeradiusServer) FreeradiusAuthorize(c echo.Context) error { // Check user status if user.Status == common.DISABLED { - log.Error2("radius auth error", + log.ErrorDetail("radius auth error", zap.String("namespace", "freeradius"), zap.String("username", username), zap.String("nasip", nasip), @@ -84,7 +84,7 @@ func (s *FreeradiusServer) FreeradiusAuthorize(c echo.Context) error { var expireTime = time.Time(user.ExpireTime) // Check user expiration if expireTime.Before(time.Now()) { - log.Error2("radius auth error", + log.ErrorDetail("radius auth error", zap.String("namespace", "freeradius"), zap.String("username", username), zap.String("nasip", nasip), @@ -97,7 +97,7 @@ func (s *FreeradiusServer) FreeradiusAuthorize(c echo.Context) error { // Current number online count, err := getOnlineCount(username) if err != nil { - log.Error2("radius auth error", + log.ErrorDetail("radius auth error", zap.String("namespace", "freeradius"), zap.String("username", username), zap.String("nasip", nasip), @@ -108,7 +108,7 @@ func (s *FreeradiusServer) FreeradiusAuthorize(c echo.Context) error { } var activeNum = user.ActiveNum if count > 0 && activeNum > 0 && count >= int64(activeNum) { - log.Error2("radius auth error", + log.ErrorDetail("radius auth error", zap.String("namespace", "freeradius"), zap.String("username", username), zap.String("nasip", nasip), @@ -176,7 +176,7 @@ func (s *FreeradiusServer) FreeradiusAccounting(c echo.Context) error { nasip := webform.GetVal("nasip") err := updateRadiusOnline(webform) if err != nil { - log.Error2("radius accounting error", + log.ErrorDetail("radius accounting error", zap.String("namespace", "freeradius"), zap.String("username", username), zap.String("nasip", nasip), diff --git a/toughradius/acct_ops.go b/toughradius/acct_ops.go index bc340e92..01ca54b9 100644 --- a/toughradius/acct_ops.go +++ b/toughradius/acct_ops.go @@ -36,7 +36,7 @@ func (s *AcctService) DoAcctDisconnect(r *radius.Request, vpe *models.NetVpe, us _ = rfc2866.AcctSessionID_Set(packet, []byte(sessionid)) response, err := radius.Exchange(context.Background(), packet, fmt.Sprintf("%s:%d", nasrip, vpe.CoaPort)) if err != nil { - log.Error2("radius disconnect error", + log.ErrorDetail("radius disconnect error", zap.String("namespace", "radius"), zap.String("username", username), zap.Error(err), diff --git a/toughradius/acct_start.go b/toughradius/acct_start.go index 165c7e3d..4a497d41 100644 --- a/toughradius/acct_start.go +++ b/toughradius/acct_start.go @@ -11,7 +11,7 @@ func (s *AcctService) DoAcctStart(r *radius.Request, vr *VendorRequest, username online := GetNetRadiusOnlineFromRequest(r, vr, vpe, nasrip) err := s.AddRadiusOnline(online) if err != nil { - log.Error2("add radius online error", + log.ErrorDetail("add radius online error", zap.String("namespace", "radius"), zap.String("username", username), zap.Error(err), @@ -19,7 +19,7 @@ func (s *AcctService) DoAcctStart(r *radius.Request, vr *VendorRequest, username } if err = s.AddRadiusAccounting(online, true); err != nil { - log.Error2("add radius accounting error", + log.ErrorDetail("add radius accounting error", zap.String("namespace", "radius"), zap.String("username", username), zap.Error(err), diff --git a/toughradius/acct_stop.go b/toughradius/acct_stop.go index 2f218c96..cf671a1d 100644 --- a/toughradius/acct_stop.go +++ b/toughradius/acct_stop.go @@ -12,7 +12,7 @@ func (s *AcctService) DoAcctStop(r *radius.Request, vr *VendorRequest, username if err := s.EndRadiusAccounting(online); err != nil { err := s.AddRadiusAccounting(online, false) if err != nil { - log.Error2("add radius accounting error", + log.ErrorDetail("add radius accounting error", zap.String("namespace", "radius"), zap.String("username", username), zap.Error(err), @@ -21,7 +21,7 @@ func (s *AcctService) DoAcctStop(r *radius.Request, vr *VendorRequest, username } if err := s.RemoveRadiusOnline(online.AcctSessionId); err != nil { - log.Error2("remove radius online error", + log.ErrorDetail("remove radius online error", zap.String("namespace", "radius"), zap.String("username", username), zap.Error(err), diff --git a/toughradius/acct_update.go b/toughradius/acct_update.go index 3bdf58ec..c5ce7456 100644 --- a/toughradius/acct_update.go +++ b/toughradius/acct_update.go @@ -33,7 +33,7 @@ func (s *AcctService) DoAcctUpdate(r *radius.Request, vr *VendorRequest, usernam if !exists { err := s.AddRadiusOnline(online) if err != nil { - log.Error2("add radius online error", + log.ErrorDetail("add radius online error", zap.String("namespace", "radius"), zap.String("username", username), zap.Error(err), @@ -44,7 +44,7 @@ func (s *AcctService) DoAcctUpdate(r *radius.Request, vr *VendorRequest, usernam // 更新在线信息 err := s.UpdateRadiusOnlineData(online) if err != nil { - log.Error2("update radius online error", + log.ErrorDetail("update radius online error", zap.String("namespace", "radius"), zap.String("username", username), zap.Error(err), diff --git a/toughradius/radius.go b/toughradius/radius.go index c3532b7f..a9419f97 100644 --- a/toughradius/radius.go +++ b/toughradius/radius.go @@ -151,29 +151,29 @@ func (s *RadiusService) GetUserForAcct(username string) (user *models.RadiusUser } func (s *RadiusService) UpdateUserField(username string, field string, value interface{}) { - err := app.GDB(). - Model(&models.RadiusUser{}). - Where("username = ?", username). - Update(field, value).Error - if err != nil { - log.Error2(fmt.Sprintf("update user %s error", field), zap.Error(err), zap.String("namespace", "radius")) - } + err := app.GDB(). + Model(&models.RadiusUser{}). + Where("username = ?", username). + Update(field, value).Error + if err != nil { + log.ErrorDetail(fmt.Sprintf("update user %s error", field), zap.Error(err), zap.String("namespace", "radius")) + } } func (s *RadiusService) UpdateUserMac(username string, macaddr string) { - s.UpdateUserField(username, "mac_addr", macaddr) + s.UpdateUserField(username, "mac_addr", macaddr) } func (s *RadiusService) UpdateUserVlanid1(username string, vlanid1 int) { - s.UpdateUserField(username, "vlanid1", vlanid1) + s.UpdateUserField(username, "vlanid1", vlanid1) } func (s *RadiusService) UpdateUserVlanid2(username string, vlanid2 int) { - s.UpdateUserField(username, "vlanid2", vlanid2) + s.UpdateUserField(username, "vlanid2", vlanid2) } func (s *RadiusService) UpdateUserLastOnline(username string) { - s.UpdateUserField(username, "last_online", time.Now()) + s.UpdateUserField(username, "last_online", time.Now()) } func (s *RadiusService) GetIntConfig(name string, defval int64) int64 { @@ -409,7 +409,7 @@ func (s *RadiusService) CheckRequestSecret(r *radius.Packet, secret []byte) { // State add func (s *RadiusService) AddEapState(stateid, username string, challenge []byte, eapMethad string) { s.eaplock.Lock() - defer s.eaplock.Unlock() + defer s.eaplock.Unlock() s.EapStateCache[stateid] = EapState{ Username: username, StateID: stateid, @@ -422,7 +422,7 @@ func (s *RadiusService) AddEapState(stateid, username string, challenge []byte, // State get func (s *RadiusService) GetEapState(stateid string) (state *EapState, err error) { s.eaplock.Lock() - defer s.eaplock.Unlock() + defer s.eaplock.Unlock() val, ok := s.EapStateCache[stateid] if ok { return &val, nil @@ -433,6 +433,6 @@ func (s *RadiusService) GetEapState(stateid string) (state *EapState, err error) // State delete func (s *RadiusService) DeleteEapState(stateid string) { s.eaplock.Lock() - defer s.eaplock.Unlock() + defer s.eaplock.Unlock() delete(s.EapStateCache, stateid) } diff --git a/toughradius/radius_acct.go b/toughradius/radius_acct.go index d5d7b0b7..19d33dcb 100644 --- a/toughradius/radius_acct.go +++ b/toughradius/radius_acct.go @@ -27,7 +27,7 @@ func (s *AcctService) ServeRADIUS(w radius.ResponseWriter, r *radius.Request) { if ret := recover(); ret != nil { err, ok := ret.(error) if ok { - log.Error2("radius accounting error", + log.ErrorDetail("radius accounting error", zap.Error(err), zap.String("namespace", "radius"), zap.String("metrics", app.MetricsRadiusAcctDrop), @@ -73,7 +73,6 @@ func (s *AcctService) ServeRADIUS(w radius.ResponseWriter, r *radius.Request) { vendorReq := s.ParseVendor(r, vpe.VendorCode) - s.SendResponse(w, r) log.Info2("radius accounting", @@ -116,7 +115,7 @@ func (s *AcctService) SendResponse(w radius.ResponseWriter, r *radius.Request) { resp := r.Response(radius.CodeAccountingResponse) err := w.Write(resp) if err != nil { - log.Error2("radius accounting response error", + log.ErrorDetail("radius accounting response error", zap.Error(err), zap.String("namespace", "radius"), zap.String("metrics", app.MetricsRadiusAcctDrop), diff --git a/toughradius/radius_auth.go b/toughradius/radius_auth.go index 750eb719..18e2697f 100644 --- a/toughradius/radius_auth.go +++ b/toughradius/radius_auth.go @@ -27,7 +27,7 @@ func (s *AuthService) ServeRADIUS(w radius.ResponseWriter, r *radius.Request) { switch ret.(type) { case error: err := ret.(error) - log.Error2("radius auth error", + log.ErrorDetail("radius auth error", zap.Error(err), zap.String("namespace", "radius"), zap.String("metrics", app.MetricsRadiusAuthDrop), @@ -35,7 +35,7 @@ func (s *AuthService) ServeRADIUS(w radius.ResponseWriter, r *radius.Request) { s.SendReject(w, r, err) case AuthError: err := ret.(AuthError) - log.Error2("radius auth error", + log.ErrorDetail("radius auth error", zap.String("namespace", "radius"), zap.String("metrics", err.Type), zap.Error(err.Err), @@ -284,7 +284,7 @@ func (s *AuthService) SendAccept(w radius.ResponseWriter, r *radius.Request, res if ret := recover(); ret != nil { err2, ok := ret.(error) if ok { - log.Error2("radius write accept error", + log.ErrorDetail("radius write accept error", zap.String("namespace", "radius"), zap.String("metrics", app.MetricsRadiusAuthDrop), zap.Error(err2), @@ -311,7 +311,7 @@ func (s *AuthService) SendReject(w radius.ResponseWriter, r *radius.Request, err if ret := recover(); ret != nil { err2, ok := ret.(error) if ok { - log.Error2("radius write reject response error", + log.ErrorDetail("radius write reject response error", zap.String("namespace", "radius"), zap.String("metrics", app.MetricsRadiusAuthDrop), zap.Error(err2), @@ -348,7 +348,7 @@ func (s *AuthService) SendEapFailureReject(w radius.ResponseWriter, r *radius.Re if ret := recover(); ret != nil { err2, ok := ret.(error) if ok { - log.Error2("radius write eap reject response error", + log.ErrorDetail("radius write eap reject response error", zap.String("namespace", "radius"), zap.String("metrics", app.MetricsRadiusAuthDrop), zap.Error(err2), diff --git a/tr069/handlers.go b/tr069/handlers.go index 6d841d37..f3d7e2bd 100644 --- a/tr069/handlers.go +++ b/tr069/handlers.go @@ -137,7 +137,7 @@ func (s *Tr069Server) Tr069Index(c echo.Context) error { if bodyLen > 0 { msg, err = cwmp.ParseXML(requestBody) if err != nil { - log.Error2("cwmp read xml error", zap.String("namespace", "tr069"), zap.Error(err)) + log.ErrorDetail("cwmp read xml error", zap.String("namespace", "tr069"), zap.Error(err)) return c.String(http.StatusBadRequest, fmt.Sprintf("cwmp read xml error %s", err.Error())) } @@ -196,7 +196,7 @@ func (s *Tr069Server) Tr069Index(c echo.Context) error { fmt.Sprintf("Recv Cwmp %s Message %s", msg.GetName(), common.ToJson(msg))) err := app.UpdateCwmpPresetTaskStatus(msg) if err != nil { - log.Error2("UpdateCwmpPresetTaskStatus error", + log.ErrorDetail("UpdateCwmpPresetTaskStatus error", zap.String("namespace", "tr069"), zap.Error(err)) } } @@ -281,12 +281,12 @@ func (s *Tr069Server) processTransferComplete(c echo.Context, msg cwmp.Message) err := app.UpdateCwmpPresetTaskStatus(tc) if err != nil && err != gorm.ErrRecordNotFound { - log.Error2("UpdateCwmpPresetTaskStatus error", zap.String("namespace", "tr069"), zap.Error(err)) + log.ErrorDetail("UpdateCwmpPresetTaskStatus error", zap.String("namespace", "tr069"), zap.Error(err)) } err = app.UpdateCwmpConfigSessionStatus(tc) if err != nil && err != gorm.ErrRecordNotFound { - log.Error2("UpdateCwmpConfigSessionStatus error", zap.String("namespace", "tr069"), zap.Error(err)) + log.ErrorDetail("UpdateCwmpConfigSessionStatus error", zap.String("namespace", "tr069"), zap.Error(err)) } } }() @@ -329,34 +329,34 @@ func (s *Tr069Server) processInformEvent(c echo.Context, lastInform *cwmp.Inform case lastInform.IsEvent(cwmp.EventBootStrap) && lastInform.RetryCount == 0: err := cpe.CreateCwmpPresetEventTask(app.BootStrapEvent, "") if err != nil { - log.Error2("CreateCwmpPresetEventTask error", zap.String("namespace", "tr069"), zap.Error(err)) + log.ErrorDetail("CreateCwmpPresetEventTask error", zap.String("namespace", "tr069"), zap.Error(err)) } err = cpe.UpdateManagementAuthInfo("bootstrap-session-"+common.UUID(), 1000, false) if err != nil { - log.Error2("UpdateManagementAuthInfo error", zap.String("namespace", "tr069"), zap.Error(err)) + log.ErrorDetail("UpdateManagementAuthInfo error", zap.String("namespace", "tr069"), zap.Error(err)) } case lastInform.IsEvent(cwmp.EventBoot) && lastInform.RetryCount == 0: err := cpe.ActiveCwmpSchedEventTask() if err != nil { - log.Error2("ActiveCwmpSchedEventTask error ", zap.String("namespace", "tr069"), zap.Error(err)) + log.ErrorDetail("ActiveCwmpSchedEventTask error ", zap.String("namespace", "tr069"), zap.Error(err)) } err = cpe.CreateCwmpPresetEventTask(app.BootEvent, "") if err != nil { - log.Error2("CreateCwmpPresetEventTask error ", zap.String("namespace", "tr069"), zap.Error(err)) + log.ErrorDetail("CreateCwmpPresetEventTask error ", zap.String("namespace", "tr069"), zap.Error(err)) } err = cpe.UpdateManagementAuthInfo("bootstrap-session-"+common.UUID(), 1000, false) if err != nil { - log.Error2("UpdateManagementAuthInfo error ", zap.String("namespace", "tr069"), zap.Error(err)) + log.ErrorDetail("UpdateManagementAuthInfo error ", zap.String("namespace", "tr069"), zap.Error(err)) } case lastInform.IsEvent(cwmp.EventPeriodic) && lastInform.RetryCount == 0: err := cpe.CreateCwmpPresetEventTask(app.PeriodicEvent, "") if err != nil { - log.Error2("CreateCwmpPresetEventTask error ", zap.String("namespace", "tr069"), zap.Error(err)) + log.ErrorDetail("CreateCwmpPresetEventTask error ", zap.String("namespace", "tr069"), zap.Error(err)) } case lastInform.IsEvent(cwmp.EventScheduled) && lastInform.RetryCount == 0: err := cpe.CreateCwmpSchedEventTask(lastInform.CommandKey) if err != nil { - log.Error2("CreateCwmpSchedEventTask error", zap.String("namespace", "tr069"), zap.Error(err)) + log.ErrorDetail("CreateCwmpSchedEventTask error", zap.String("namespace", "tr069"), zap.Error(err)) } case lastInform.IsEvent(cwmp.EventValueChange) && lastInform.RetryCount == 0: cpe.NotifyDataUpdate(true) From 0ddbdd54941b6bb828c388d699ba1c54a51c8dcd Mon Sep 17 00:00:00 2001 From: Jett Wang Date: Wed, 9 Oct 2024 13:25:03 +0800 Subject: [PATCH 3/8] Refactor RadiusService to use a mutex for EapStateCache and add RadsecWorker configuration option --- config/config.go | 15 +++++++----- toughradius/radsec_server.go | 46 +++++++++++++++++++++++++----------- toughradius/server.go | 1 + 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/config/config.go b/config/config.go index 487d2407..edcc9b49 100644 --- a/config/config.go +++ b/config/config.go @@ -47,12 +47,13 @@ type FreeradiusConfig struct { } type RadiusdConfig struct { - Enabled bool `yaml:"enabled" json:"enabled"` - Host string `yaml:"host" json:"host"` - AuthPort int `yaml:"auth_port" json:"auth_port"` - AcctPort int `yaml:"acct_port" json:"acct_port"` - RadsecPort int `yaml:"radsec_port" json:"radsec_port"` - Debug bool `yaml:"debug" json:"debug"` + Enabled bool `yaml:"enabled" json:"enabled"` + Host string `yaml:"host" json:"host"` + AuthPort int `yaml:"auth_port" json:"auth_port"` + AcctPort int `yaml:"acct_port" json:"acct_port"` + RadsecPort int `yaml:"radsec_port" json:"radsec_port"` + RadsecWorker int `yaml:"radsec_worker" json:"radsec_worker"` + Debug bool `yaml:"debug" json:"debug"` } // Tr069Config tr069 API 配置 @@ -211,6 +212,7 @@ var DefaultAppConfig = &AppConfig{ AuthPort: 1812, AcctPort: 1813, RadsecPort: 2083, + RadsecWorker: 100, Debug: true, }, Logger: LogConfig{ @@ -269,6 +271,7 @@ func LoadConfig(cfile string) *AppConfig { setEnvIntValue("TOUGHRADIUS_RADIUS_AUTHPORT", &cfg.Radiusd.AuthPort) setEnvIntValue("TOUGHRADIUS_RADIUS_ACCTPORT", &cfg.Radiusd.AcctPort) setEnvIntValue("TOUGHRADIUS_RADIUS_RADSEC_PORT", &cfg.Radiusd.RadsecPort) + setEnvIntValue("TOUGHRADIUS_RADIUS_RADSEC_WORKER", &cfg.Radiusd.RadsecWorker) setEnvBoolValue("TOUGHRADIUS_RADIUS_DEBUG", &cfg.Radiusd.Debug) setEnvBoolValue("TOUGHRADIUS_RADIUS_ENABLED", &cfg.Radiusd.Enabled) diff --git a/toughradius/radsec_server.go b/toughradius/radsec_server.go index c3a263a3..ad8192a5 100644 --- a/toughradius/radsec_server.go +++ b/toughradius/radsec_server.go @@ -64,6 +64,8 @@ type RadsecPacketServer struct { // This should only be set to true for debugging purposes. InsecureSkipVerify bool + RadsecWorker int + // ErrorLog specifies an optional logger for errors // around packet accepting, processing, and validation. // If nil, logging is done via the log package's standard logger. @@ -77,6 +79,7 @@ type RadsecPacketServer struct { listeners map[net.Conn]uint lastActive chan struct{} // closed when the last active item finishes activeCount int32 + workerPool chan struct{} } func (s *RadsecPacketServer) initLocked() { @@ -84,6 +87,7 @@ func (s *RadsecPacketServer) initLocked() { s.ctx, s.ctxDone = context.WithCancel(context.Background()) s.listeners = make(map[net.Conn]uint) s.lastActive = make(chan struct{}) + s.workerPool = make(chan struct{}, s.RadsecWorker) } } @@ -202,6 +206,9 @@ func (s *RadsecPacketServer) Serve(conn net.Conn) error { go func(packet *radius.Packet, conn net.Conn) { defer s.activeDone() + s.workerPool <- struct{}{} + defer func() { <-s.workerPool }() + key := requestKey{ IP: conn.RemoteAddr().String(), Identifier: packet.Identifier, @@ -237,26 +244,37 @@ func (s *RadsecPacketServer) Serve(conn net.Conn) error { } } +// initTLSConfig initializes a tls.Config with the given certificate and key +func (s *RadsecPacketServer) initTLSConfig(capath, crtfile, keyfile string) (*tls.Config, error) { + crt, err := tls.LoadX509KeyPair(crtfile, keyfile) + if err != nil { + return nil, err + } + + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{crt}, + Time: time.Now, + Rand: rand.Reader, + ClientAuth: tls.VerifyClientCertIfGiven, + } + + if common.FileExists(capath) { + cabytes, _ := os.ReadFile(capath) + pool := x509.NewCertPool() + pool.AppendCertsFromPEM(cabytes) + tlsConfig.ClientCAs = pool + } + + return tlsConfig, nil +} + // ListenAndServe starts a RADIUS server on the address given in s. func (s *RadsecPacketServer) ListenAndServe(capath, crtfile, keyfile string) error { - crt, err := tls.LoadX509KeyPair(crtfile, keyfile) + tlsConfig, err := s.initTLSConfig(capath, crtfile, keyfile) if err != nil { return err } - tlsConfig := &tls.Config{} - tlsConfig.Certificates = []tls.Certificate{crt} - tlsConfig.Time = time.Now - tlsConfig.Rand = rand.Reader - tlsConfig.ClientAuth = tls.VerifyClientCertIfGiven - - if common.FileExists(capath) { - cabytes, _ := os.ReadFile(capath) - pool := x509.NewCertPool() - pool.AppendCertsFromPEM(cabytes) - tlsConfig.ClientCAs = pool - } - if s.Handler == nil { return errors.New("radius: nil RadsecHandler") } diff --git a/toughradius/server.go b/toughradius/server.go index b5aeccd1..a47da641 100644 --- a/toughradius/server.go +++ b/toughradius/server.go @@ -64,6 +64,7 @@ func ListenRadsecServer(service *RadsecService) error { Handler: service, SecretSource: service, InsecureSkipVerify: true, + RadsecWorker: app.GConfig().Radiusd.RadsecWorker, } log.Infof("Starting Radius Resec server on %s", server.Addr) From b84f4331fea10e6b1f6de7b3d53a61cee93e06fc Mon Sep 17 00:00:00 2001 From: Jett Wang Date: Wed, 9 Oct 2024 13:27:09 +0800 Subject: [PATCH 4/8] Refactor log.Warn2 to log.WarnDetail for more descriptive error messages --- common/zaplog/log/say.go | 2 +- toughradius/vendor_parse.go | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/zaplog/log/say.go b/common/zaplog/log/say.go index 9e7101d2..3cf9f3cf 100644 --- a/common/zaplog/log/say.go +++ b/common/zaplog/log/say.go @@ -29,7 +29,7 @@ func Warn(args ...interface{}) { zap.S().Warn(args...) } -func Warn2(msg string, fields ...zap.Field) { +func WarnDetail(msg string, fields ...zap.Field) { defer zap.L().Sync() zap.L().Warn(msg, fields...) } diff --git a/toughradius/vendor_parse.go b/toughradius/vendor_parse.go index 8c28158e..a492ce12 100644 --- a/toughradius/vendor_parse.go +++ b/toughradius/vendor_parse.go @@ -60,7 +60,7 @@ func parseVendorDefault(r *radius.Request) *VendorRequest { if macval != "" { attrs.MacAddr = strings.ReplaceAll(macval, "-", ":") } else { - log.Warn2("rfc2865.CallingStationID is empty", zap.String("namespace", "radius")) + log.WarnDetail("rfc2865.CallingStationID is empty", zap.String("namespace", "radius")) } nasportid := rfc2869.NASPortID_GetString(r.Packet) if nasportid == "" { @@ -83,12 +83,12 @@ func parseVendorH3c(r *radius.Request) *VendorRequest { attrs.MacAddr = ipha } } else { - log.Warn2("h3c.H3CIPHostAddr is empty", zap.String("namespace", "radius")) + log.WarnDetail("h3c.H3CIPHostAddr is empty", zap.String("namespace", "radius")) macval := rfc2865.CallingStationID_GetString(r.Packet) if macval != "" { attrs.MacAddr = strings.ReplaceAll(macval, "-", ":") } else { - log.Warn2("rfc2865.CallingStationID is empty", zap.String("namespace", "radius")) + log.WarnDetail("rfc2865.CallingStationID is empty", zap.String("namespace", "radius")) } } @@ -109,10 +109,10 @@ func parseVendorZte(r *radius.Request) *VendorRequest { if len(macval) > 12 { attrs.MacAddr = fmt.Sprintf("%s:%s:%s:%s:%s:%s", macval[0:2], macval[2:4], macval[4:6], macval[6:8], macval[8:10], macval[10:12]) } else { - log.Warn2("rfc2865.CallingStationID length < 12", zap.String("namespace", "radius")) + log.WarnDetail("rfc2865.CallingStationID length < 12", zap.String("namespace", "radius")) } } else { - log.Warn2("rfc2865.CallingStationID is empty", zap.String("namespace", "radius")) + log.WarnDetail("rfc2865.CallingStationID is empty", zap.String("namespace", "radius")) } nasportid := rfc2869.NASPortID_GetString(r.Packet) if nasportid == "" { @@ -130,7 +130,7 @@ func parseVendorRadback(r *radius.Request) *VendorRequest { if macval != "" { attrs.MacAddr = strings.ReplaceAll(macval, "-", ":") } else { - log.Warn2("rfc2865.CallingStationID is empty", zap.String("namespace", "radius")) + log.WarnDetail("rfc2865.CallingStationID is empty", zap.String("namespace", "radius")) } nasportid := rfc2869.NASPortID_GetString(r.Packet) if nasportid == "" { From 9a9edd111a41f25a36055e61b92fceb05106ad31 Mon Sep 17 00:00:00 2001 From: Jett Wang Date: Wed, 9 Oct 2024 13:43:35 +0800 Subject: [PATCH 5/8] Refactor RejectCache to use a read-write mutex for concurrent access --- toughradius/radius_eap.go | 374 ++++++++++++++--------------- toughradius/radius_reject_delay.go | 80 +++--- 2 files changed, 222 insertions(+), 232 deletions(-) diff --git a/toughradius/radius_eap.go b/toughradius/radius_eap.go index e93373d3..89345f53 100644 --- a/toughradius/radius_eap.go +++ b/toughradius/radius_eap.go @@ -13,265 +13,247 @@ import ( "github.com/talkincode/toughradius/v8/app" "github.com/talkincode/toughradius/v8/common" "github.com/talkincode/toughradius/v8/common/zaplog/log" + "go.uber.org/zap" "layeh.com/radius" "layeh.com/radius/rfc2865" "layeh.com/radius/rfc2869" ) const ( - EapMd5Method = "eap-md5" - EapMschapv2Method = "eap-mschapv2" - EapTlsMethod = "eap-tls" - EapPeapMethod = "eap-peap" - EapTtlsMethod = "eap-ttls" - EapGtcMethod = "eap-gtc" - EapSimMethod = "eap-sim" - EapAkaMethod = "eap-aka" - EapFastMethod = "eap-fast" - EapPaxMethod = "eap-pax" - EapPskMethod = "eap-psk" - EapSakeMethod = "eap-sake" - EapIkev2Method = "eap-ikev2" - EapTncMethod = "eap-tnc" - EapOTPMethod = "eap-otp" + EapMd5Method = "eap-md5" + EapMschapv2Method = "eap-mschapv2" + EapTlsMethod = "eap-tls" + EapPeapMethod = "eap-peap" + EapTtlsMethod = "eap-ttls" + EapGtcMethod = "eap-gtc" + EapSimMethod = "eap-sim" + EapAkaMethod = "eap-aka" + EapFastMethod = "eap-fast" + EapPaxMethod = "eap-pax" + EapPskMethod = "eap-psk" + EapSakeMethod = "eap-sake" + EapIkev2Method = "eap-ikev2" + EapTncMethod = "eap-tnc" + EapOTPMethod = "eap-otp" ) const ( - EAPCodeRequest = 1 // EAP Request message - EAPCodeResponse = 2 // EAP Response message - EAPCodeSuccess = 3 // Indicates successful authentication - EAPCodeFailure = 4 // Indicates failed authentication - EAPCodeNakNak = 5 // Used by the peer to negotiate the authentication method (Response only) - EAPCodeMD5Challenge = 6 // MD5-Challenge EAP method - EAPCodeOTP = 7 // One-Time Password (OTP) EAP method - EAPCodeGTC = 8 // Generic Token Card (GTC) EAP method - EAPCodeTLSv1 = 13 // EAP-TLS method, using TLSv1 - EAPCodeMSCHAPv2 = 26 // EAP method for Microsoft Challenge Handshake Authentication Protocol version 2 - EAPCodeSIM = 18 // EAP-SIM method for GSM networks - EAPCodeAKA = 23 // EAP-AKA method for UMTS authentication and key agreement - EAPCodePEAP = 25 // Protected EAP (PEAP), a method that creates an encrypted channel to protect transmitted information - EAPCodeTTLS = 21 // Tunneled Transport Layer Security (TTLS) EAP method - EAPCodeFAST = 43 // Flexible Authentication via Secure Tunneling (EAP-FAST) method - EAPCodePAX = 46 // Password Authenticated Exchange (EAP-PAX) method - EAPCodePSK = 47 // Pre-Shared Key (EAP-PSK) method - EAPCodeSAKE = 48 // SIM Authentication Key Exchange (EAP-SAKE) method - EAPCodeIKEv2 = 49 // EAP method based on Internet Key Exchange version 2 (EAP-IKEv2) + EAPCodeRequest = 1 // EAP Request message + EAPCodeResponse = 2 // EAP Response message + EAPCodeSuccess = 3 // Indicates successful authentication + EAPCodeFailure = 4 // Indicates failed authentication + EAPCodeNakNak = 5 // Used by the peer to negotiate the authentication method (Response only) + EAPCodeMD5Challenge = 6 // MD5-Challenge EAP method + EAPCodeOTP = 7 // One-Time Password (OTP) EAP method + EAPCodeGTC = 8 // Generic Token Card (GTC) EAP method + EAPCodeTLSv1 = 13 // EAP-TLS method, using TLSv1 + EAPCodeMSCHAPv2 = 26 // EAP method for Microsoft Challenge Handshake Authentication Protocol version 2 + EAPCodeSIM = 18 // EAP-SIM method for GSM networks + EAPCodeAKA = 23 // EAP-AKA method for UMTS authentication and key agreement + EAPCodePEAP = 25 // Protected EAP (PEAP), a method that creates an encrypted channel to protect transmitted information + EAPCodeTTLS = 21 // Tunneled Transport Layer Security (TTLS) EAP method + EAPCodeFAST = 43 // Flexible Authentication via Secure Tunneling (EAP-FAST) method + EAPCodePAX = 46 // Password Authenticated Exchange (EAP-PAX) method + EAPCodePSK = 47 // Pre-Shared Key (EAP-PSK) method + EAPCodeSAKE = 48 // SIM Authentication Key Exchange (EAP-SAKE) method + EAPCodeIKEv2 = 49 // EAP method based on Internet Key Exchange version 2 (EAP-IKEv2) ) const ( - EAPTypeIdentity = 1 - EAPTypeNotification = 2 - EAPTypeNak = 3 // Response only - EAPTypeMD5Challenge = 4 - EAPTypeOTP = 5 // One-Time Password - EAPTypeGTC = 6 // Generic Token Card - // EAPTypeTLS 7-9 Reserved - EAPTypeTLS = 13 - EAPTypeMSCHAPv2 = 26 + EAPTypeIdentity = 1 + EAPTypeNotification = 2 + EAPTypeNak = 3 // Response only + EAPTypeMD5Challenge = 4 + EAPTypeOTP = 5 // One-Time Password + EAPTypeGTC = 6 // Generic Token Card + // EAPTypeTLS 7-9 Reserved + EAPTypeTLS = 13 + EAPTypeMSCHAPv2 = 26 +) + +const ( + EAPHeaderLength = 4 + EAPMD5ChallengeLength = 16 + EAPOTPChallengeMessage = "Please enter a one-time password" ) type EAPHeader struct { - Code uint8 - Identifier uint8 - Length uint16 + Code uint8 + Identifier uint8 + Length uint16 } // NewEAPSuccess creates a new EAP-Success packet. func NewEAPSuccess(identifier uint8) *EAPHeader { - return &EAPHeader{ - Code: EAPCodeSuccess, - Identifier: identifier, - Length: 4, // EAP header is always 4 bytes for Success/Failure - } + return &EAPHeader{ + Code: EAPCodeSuccess, + Identifier: identifier, + Length: EAPHeaderLength, // EAP header is always 4 bytes for Success/Failure + } } // NewEAPFailure creates a new EAP-Failure packet. func NewEAPFailure(identifier uint8) *EAPHeader { - return &EAPHeader{ - Code: EAPCodeFailure, - Identifier: identifier, - Length: 4, // EAP header is always 4 bytes for Success/Failure - } + return &EAPHeader{ + Code: EAPCodeFailure, + Identifier: identifier, + Length: EAPHeaderLength, // EAP header is always 4 bytes for Success/Failure + } } // Serialize serializes the EAP-Success or EAP-Failure packet to bytes. func (eap *EAPHeader) Serialize() []byte { - buffer := bytes.NewBuffer(nil) + buffer := bytes.NewBuffer(nil) - // Write EAP header - binary.Write(buffer, binary.BigEndian, eap) + // Write EAP header + binary.Write(buffer, binary.BigEndian, eap) - return buffer.Bytes() + return buffer.Bytes() } type EAPMessage struct { - EAPHeader - Type uint8 - Data []byte + EAPHeader + Type uint8 + Data []byte } // Encode 编码 EAP 消息为字节切片 func (msg *EAPMessage) Encode() []byte { - // 初始化 EAP 消息的基础长度 - length := 5 // Code, Identifier, Length, Type 字段总共占用 5 字节 - var data []byte - if msg.Data != nil { - data = msg.Data - length += len(data) - } - buffer := make([]byte, length) - buffer[0] = msg.Code - buffer[1] = msg.Identifier - binary.BigEndian.PutUint16(buffer[2:4], uint16(length)) - buffer[4] = msg.Type - - if len(data) > 0 { - copy(buffer[5:], data) - } - return buffer + // 初始化 EAP 消息的基础长度 + length := 5 // Code, Identifier, Length, Type 字段总共占用 5 字节 + var data []byte + if msg.Data != nil { + data = msg.Data + length += len(data) + } + buffer := make([]byte, length) + buffer[0] = msg.Code + buffer[1] = msg.Identifier + binary.BigEndian.PutUint16(buffer[2:4], uint16(length)) + buffer[4] = msg.Type + + if len(data) > 0 { + copy(buffer[5:], data) + } + return buffer } // String() // Returns a string representation of the EAP message. func (msg *EAPMessage) String() string { - buff := strings.Builder{} - buff.WriteString("EAPMessage{") - buff.WriteString("Code=") - buff.WriteString(strconv.FormatUint(uint64(msg.Code), 10)) - buff.WriteString(", Identifier=") - buff.WriteString(strconv.FormatUint(uint64(msg.Identifier), 10)) - buff.WriteString(", Length=") - buff.WriteString(strconv.FormatUint(uint64(msg.Length), 10)) - buff.WriteString(", Type=") - buff.WriteString(strconv.FormatUint(uint64(msg.Type), 10)) - buff.WriteString(", Data=") - buff.WriteString(fmt.Sprintf("%x", msg.Data)) - buff.WriteString("}") - return buff.String() + buff := strings.Builder{} + buff.WriteString("EAPMessage{") + buff.WriteString("Code=") + buff.WriteString(strconv.FormatUint(uint64(msg.Code), 10)) + buff.WriteString(", Identifier=") + buff.WriteString(strconv.FormatUint(uint64(msg.Identifier), 10)) + buff.WriteString(", Length=") + buff.WriteString(strconv.FormatUint(uint64(msg.Length), 10)) + buff.WriteString(", Type=") + buff.WriteString(strconv.FormatUint(uint64(msg.Type), 10)) + buff.WriteString(", Data=") + buff.WriteString(fmt.Sprintf("%x", msg.Data)) + buff.WriteString("}") + return buff.String() } func parseEAPMessage(packet *radius.Packet) (*EAPMessage, error) { - // 从RADIUS请求中获取EAP-Message属性 - attr, err := rfc2869.EAPMessage_Lookup(packet) - if err != nil { - return nil, err - } - - // 解析EAP消息 - eap := &EAPMessage{ - EAPHeader: EAPHeader{ - Code: attr[0], - Identifier: attr[1], - Length: binary.BigEndian.Uint16(attr[2:4]), - }, - Type: attr[4], - Data: attr[5:], - } - return eap, nil + // 从RADIUS请求中获取EAP-Message属性 + attr, err := rfc2869.EAPMessage_Lookup(packet) + if err != nil { + return nil, err + } + + // 解析EAP消息 + eap := &EAPMessage{ + EAPHeader: EAPHeader{ + Code: attr[0], + Identifier: attr[1], + Length: binary.BigEndian.Uint16(attr[2:4]), + }, + Type: attr[4], + Data: attr[5:], + } + return eap, nil } // GenerateRandomBytes 生成一个指定长度的随机字节数组 func generateRandomBytes(n int) ([]byte, error) { - b := make([]byte, n) - _, err := rand.Read(b) - // 注意这里返回的 n 是读取的字节数 - if err != nil { - return nil, err - } - return b, nil + b := make([]byte, n) + _, err := rand.Read(b) + // 注意这里返回的 n 是读取的字节数 + if err != nil { + log.Error("Failed to generate random bytes", zap.Error(err)) + return nil, err + } + return b, nil } func generateMessageAuthenticator(r *radius.Packet, secret string) []byte { - // 创建一个新的MD5哈希 - b, _ := r.MarshalBinary() - // 创建一个新的MD5哈希 - mac := hmac.New(md5.New, []byte(secret)) - // 写入RADIUS包 - mac.Write(b) - // 计算Message-Authenticator属性的值 - authenticator := mac.Sum(nil) - return authenticator + // 创建一个新的MD5哈希 + b, _ := r.MarshalBinary() + // 创建一个新的MD5哈希 + mac := hmac.New(md5.New, []byte(secret)) + // 写入RADIUS包 + mac.Write(b) + // 计算Message-Authenticator属性的值 + authenticator := mac.Sum(nil) + return authenticator } -func (s *AuthService) sendEapMD5ChallengeRequest(w radius.ResponseWriter, r *radius.Request, secret string) error { - // 创建一个新的RADIUS响应 - var resp = r.Response(radius.CodeAccessChallenge) - - eapChallenge, err := generateRandomBytes(16) - if err != nil { - return err - } +func (s *AuthService) sendEapChallengeRequest(w radius.ResponseWriter, r *radius.Request, secret string, eapType uint8, eapChallenge []byte, method string) error { + // 创建一个新的RADIUS响应 + var resp = r.Response(radius.CodeAccessChallenge) - state := common.UUID() - s.AddEapState(state, rfc2865.UserName_GetString(r.Packet), eapChallenge, EapMd5Method) + state := common.UUID() + s.AddEapState(state, rfc2865.UserName_GetString(r.Packet), eapChallenge, method) - rfc2865.State_SetString(resp, state) + rfc2865.State_SetString(resp, state) - // 创建EAP-Request/MD5-Challenge消息 - eapMessage := []byte{0x01, r.Identifier, 0x00, 0x16, EAPTypeMD5Challenge, 0x10} - eapMessage = append(eapMessage, eapChallenge...) + // 创建EAP-Request消息 + eapMessage := []byte{0x01, r.Identifier} + eapMessage = append(eapMessage, []byte{0x00, 0x00}...) // Length, will be set later + eapMessage = append(eapMessage, eapType) // Type for EAP + eapMessage = append(eapMessage, eapChallenge...) + + // Set the length + binary.BigEndian.PutUint16(eapMessage[2:4], uint16(len(eapMessage))) - // 设置EAP-Message属性 - rfc2869.EAPMessage_Set(resp, eapMessage) - rfc2869.MessageAuthenticator_Set(resp, make([]byte, 16)) + // 设置EAP-Message属性 + rfc2869.EAPMessage_Set(resp, eapMessage) + rfc2869.MessageAuthenticator_Set(resp, make([]byte, 16)) - authenticator := generateMessageAuthenticator(resp, secret) - // 设置Message-Authenticator属性 - rfc2869.MessageAuthenticator_Set(resp, authenticator) + authenticator := generateMessageAuthenticator(resp, secret) + // 设置Message-Authenticator属性 + rfc2869.MessageAuthenticator_Set(resp, authenticator) - // debug message - if app.GConfig().Radiusd.Debug { - log.Info(FmtResponse(resp, r.RemoteAddr)) - } + // debug message + if app.GConfig().Radiusd.Debug { + log.Info(FmtResponse(resp, r.RemoteAddr)) + } - // 发送RADIUS响应 - return w.Write(resp) + // 发送RADIUS响应 + return w.Write(resp) } -func (s *AuthService) verifyEapMD5Response(eapid uint8, password string, challenge, response []byte) bool { - hash := md5.New() - hash.Write([]byte{eapid}) - hash.Write([]byte(password)) - hash.Write(challenge) - expectedResponse := hash.Sum(nil) - return bytes.Equal(expectedResponse, response[1:]) +func (s *AuthService) sendEapMD5ChallengeRequest(w radius.ResponseWriter, r *radius.Request, secret string) error { + eapChallenge, err := generateRandomBytes(EAPMD5ChallengeLength) + if err != nil { + return err + } + return s.sendEapChallengeRequest(w, r, secret, EAPTypeMD5Challenge, eapChallenge, EapMd5Method) } - -// sendEapOTPChallengeRequest func (s *AuthService) sendEapOTPChallengeRequest(w radius.ResponseWriter, r *radius.Request, secret string) error { - // 创建一个新的RADIUS响应 - var resp = r.Response(radius.CodeAccessChallenge) - - eapChallenge := []byte("Please enter a one-time password") - - state := common.UUID() - s.AddEapState(state, rfc2865.UserName_GetString(r.Packet), eapChallenge, EapOTPMethod) - - rfc2865.State_SetString(resp, state) - - // 创建EAP-Request/OTP-Challenge消息 - eapMessage := []byte{0x01, r.Identifier} - eapMessage = append(eapMessage, []byte{0x00, 0x00}...) // Length, will be set later - eapMessage = append(eapMessage, EAPTypeOTP) // Type for EAP-OTP - eapMessage = append(eapMessage, eapChallenge...) - - // Set the length - binary.BigEndian.PutUint16(eapMessage[2:4], uint16(len(eapMessage))) - - // 设置EAP-Message属性 - rfc2869.EAPMessage_Set(resp, eapMessage) - rfc2869.MessageAuthenticator_Set(resp, make([]byte, 16)) - - authenticator := generateMessageAuthenticator(resp, secret) - // 设置Message-Authenticator属性 - rfc2869.MessageAuthenticator_Set(resp, authenticator) - - // debug message - if app.GConfig().Radiusd.Debug { - log.Info(FmtResponse(resp, r.RemoteAddr)) - } + eapChallenge := []byte(EAPOTPChallengeMessage) + return s.sendEapChallengeRequest(w, r, secret, EAPTypeOTP, eapChallenge, EapOTPMethod) +} - // 发送RADIUS响应 - return w.Write(resp) -} \ No newline at end of file +func (s *AuthService) verifyEapMD5Response(eapid uint8, password string, challenge, response []byte) bool { + hash := md5.New() + hash.Write([]byte{eapid}) + hash.Write([]byte(password)) + hash.Write(challenge) + expectedResponse := hash.Sum(nil) + return bytes.Equal(expectedResponse, response[1:]) +} diff --git a/toughradius/radius_reject_delay.go b/toughradius/radius_reject_delay.go index 89aed60e..4b3d7575 100644 --- a/toughradius/radius_reject_delay.go +++ b/toughradius/radius_reject_delay.go @@ -1,58 +1,66 @@ package toughradius import ( - "sync" - "sync/atomic" - "time" + "sync" + "sync/atomic" + "time" ) type RejectItem struct { - Rejects int64 - LastReject time.Time - Lock sync.RWMutex + Rejects int64 + LastReject time.Time + Lock sync.RWMutex } func (ri *RejectItem) Incr() { - ri.Lock.Lock() - atomic.AddInt64(&ri.Rejects, 1) - ri.LastReject = time.Now() - ri.Lock.Unlock() + ri.Lock.Lock() + defer ri.Lock.Unlock() + atomic.AddInt64(&ri.Rejects, 1) + ri.LastReject = time.Now() } func (ri *RejectItem) IsOver(max int64) bool { - ri.Lock.RLock() - defer ri.Lock.RUnlock() - if time.Since(ri.LastReject).Seconds() > 10 { - atomic.StoreInt64(&ri.Rejects, 0) - return false - } - return ri.Rejects > max && time.Since(ri.LastReject).Seconds() < 10 + ri.Lock.RLock() + defer ri.Lock.RUnlock() + if time.Since(ri.LastReject).Seconds() > 10 { + ri.Lock.RUnlock() + ri.Lock.Lock() + defer ri.Lock.Unlock() + if time.Since(ri.LastReject).Seconds() > 10 { + atomic.StoreInt64(&ri.Rejects, 0) + } + return false + } + return atomic.LoadInt64(&ri.Rejects) > max } type RejectCache struct { - Items map[string]*RejectItem - Lock sync.Mutex + Items map[string]*RejectItem + Lock sync.RWMutex } func (rc *RejectCache) GetItem(username string) *RejectItem { - rc.Lock.Lock() - defer rc.Lock.Unlock() - if len(rc.Items) >= 65535 { - rc.Items = make(map[string]*RejectItem, 0) - return nil - } - return rc.Items[username] + rc.Lock.RLock() + defer rc.Lock.RUnlock() + if len(rc.Items) >= 65535 { + rc.Lock.RUnlock() + rc.Lock.Lock() + defer rc.Lock.Unlock() + if len(rc.Items) >= 65535 { + rc.Items = make(map[string]*RejectItem, 0) + } + return nil + } + return rc.Items[username] } func (rc *RejectCache) SetItem(username string) { - rc.Lock.Lock() - _, ok := rc.Items[username] - if !ok { - rc.Items[username] = &RejectItem{ - Rejects: 1, - LastReject: time.Now(), - Lock: sync.RWMutex{}, - } - } - rc.Lock.Unlock() + rc.Lock.Lock() + defer rc.Lock.Unlock() + if _, ok := rc.Items[username]; !ok { + rc.Items[username] = &RejectItem{ + Rejects: 1, + LastReject: time.Now(), + } + } } From e6711d62167a283f0423c8a8e1962fd655c363ed Mon Sep 17 00:00:00 2001 From: Jett Wang Date: Wed, 9 Oct 2024 13:47:18 +0800 Subject: [PATCH 6/8] Refactor RejectCache to use a read-write mutex for concurrent access --- toughradius/radius.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toughradius/radius.go b/toughradius/radius.go index a9419f97..6e1c5788 100644 --- a/toughradius/radius.go +++ b/toughradius/radius.go @@ -82,7 +82,7 @@ func NewRadiusService() *RadiusService { TaskPool: pool, RejectCache: &RejectCache{ Items: make(map[string]*RejectItem), - Lock: sync.Mutex{}, + Lock: sync.RWMutex{}, }} return s } From 30d48a32a6dc592990fca20e93db0d94381287fb Mon Sep 17 00:00:00 2001 From: Jett Wang Date: Wed, 9 Oct 2024 14:11:52 +0800 Subject: [PATCH 7/8] Refactor panic messages in GetCurrUser and GetCurrUserlevel functions --- webserver/server.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webserver/server.go b/webserver/server.go index 9b4ec142..2d5323ae 100644 --- a/webserver/server.go +++ b/webserver/server.go @@ -269,7 +269,7 @@ func GetCurrUser(c echo.Context) *models.SysOpr { sess, _ := session.Get(UserSession, c) username := sess.Values[UserSessionName] if username == nil || username == "" { - panic("用户未登录") + panic("user not login") } user := models.SysOpr{} err := app.GApp().DB().Where("username = ?", username).First(&user).Error @@ -281,7 +281,7 @@ func GetCurrUserlevel(c echo.Context) string { sess, _ := session.Get(UserSession, c) level := sess.Values[UserSessionLevel] if level == nil || level == "" { - panic("用户未登录") + panic("user not login") } return level.(string) } From 339021aeea126bd15b5c492341d30c3b48393c80 Mon Sep 17 00:00:00 2001 From: Jett Wang Date: Wed, 9 Oct 2024 14:12:14 +0800 Subject: [PATCH 8/8] 2024-10-09 14:12:13 : --- assets/buildinfo.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/assets/buildinfo.txt b/assets/buildinfo.txt index d39215be..8207ae62 100644 --- a/assets/buildinfo.txt +++ b/assets/buildinfo.txt @@ -1,8 +1,8 @@ -BuildVersion=latest v8.0.7 2024-10-09 12:43:22 +BuildVersion=latest v8.0.7 2024-10-09 14:12:13 ReleaseVersion=v8.0.7 -BuildTime=2024-10-09 12:43:22 +BuildTime=2024-10-09 14:12:13 BuildName=toughradius -CommitID=7a0e1adf0260dd93bb0ad92d9d30c6ce13594984 -CommitDate=Fri, 24 May 2024 12:10:21 +0800 +CommitID=f33f34d9a034dd98d3c86db4da716be2b3db96e0 +CommitDate=Wed, 9 Oct 2024 14:11:52 +0800 CommitUser=jamiesun.net@gmail.com -CommitSubject=2024-05-24 12:10:02 : fix radius account update bug +CommitSubject=Refactor panic messages in GetCurrUser and GetCurrUserlevel functions