Skip to content

Commit 24921b7

Browse files
authored
Merge pull request #7 from deflect-ca/hotfix/reload-config-structs
Hotfix/reload config structs
2 parents 9a6519f + e0c5bd3 commit 24921b7

3 files changed

Lines changed: 77 additions & 30 deletions

File tree

banjax.go

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ package main
99
import (
1010
"encoding/json"
1111
"flag"
12-
"github.com/equalitie/banjax/internal"
13-
"gopkg.in/yaml.v2"
1412
"io/ioutil"
1513
"log"
1614
"os"
@@ -19,6 +17,9 @@ import (
1917
"sync"
2018
"syscall"
2119
"time"
20+
21+
"github.com/equalitie/banjax/internal"
22+
"gopkg.in/yaml.v2"
2223
)
2324

2425
func load_config(config *internal.Config, standaloneTestingPtr *bool, configFilenamePtr *string, restartTime int) {
@@ -68,6 +69,18 @@ func load_config(config *internal.Config, standaloneTestingPtr *bool, configFile
6869
}
6970

7071
func main() {
72+
// XXX protects ipToRegexStates and failedChallengeStates
73+
// (why both? because there are too many parameters already?)
74+
var rateLimitMutex sync.Mutex
75+
ipToRegexStates := internal.IpToRegexStates{}
76+
failedChallengeStates := internal.FailedChallengeStates{}
77+
78+
var passwordProtectedPaths internal.PasswordProtectedPaths
79+
80+
// XXX protects decisionLists
81+
var decisionListsMutex sync.Mutex
82+
var decisionLists internal.DecisionLists
83+
7184
standaloneTestingPtr := flag.Bool("standalone-testing", false, "makes it easy to test standalone")
7285
configFilenamePtr := flag.String("config-file", "/etc/banjax/banjax-config.yaml", "config file")
7386
flag.Parse()
@@ -88,7 +101,10 @@ func main() {
88101
go func() {
89102
for _ = range sighup_channel {
90103
log.Println("got SIGHUP; reloading config")
104+
rateLimitMutex.Lock()
91105
load_config(&config, standaloneTestingPtr, configFilenamePtr, restartTime)
106+
rateLimitMutex.Unlock()
107+
configToStructs(&config, &passwordProtectedPaths, &decisionLists)
92108
}
93109
}()
94110

@@ -113,17 +129,7 @@ func main() {
113129
}
114130
log.Println(config.KafkaBrokers)
115131

116-
// XXX protects decisionLists
117-
var decisionListsMutex sync.Mutex
118-
decisionLists := internal.ConfigToDecisionLists(&config)
119-
120-
passwordProtectedPaths := internal.ConfigToPasswordProtectedPaths(&config)
121-
122-
// XXX protects ipToRegexStates and failedChallengeStates
123-
// (why both? because there are too many parameters already?)
124-
var rateLimitMutex sync.Mutex
125-
ipToRegexStates := internal.IpToRegexStates{}
126-
failedChallengeStates := internal.FailedChallengeStates{}
132+
configToStructs(&config, &passwordProtectedPaths, &decisionLists)
127133

128134
// XXX this interface exists to make mocking out the iptables stuff
129135
// in testing easier. there might be a better way to do it.
@@ -228,3 +234,17 @@ func main() {
228234

229235
wg.Wait()
230236
}
237+
238+
var configToStructsMutex sync.Mutex
239+
240+
func configToStructs(
241+
config *internal.Config,
242+
passwordProtectedPaths *internal.PasswordProtectedPaths,
243+
decisionLists *internal.DecisionLists,
244+
) {
245+
configToStructsMutex.Lock()
246+
defer configToStructsMutex.Unlock()
247+
248+
*passwordProtectedPaths = internal.ConfigToPasswordProtectedPaths(config)
249+
*decisionLists = internal.ConfigToDecisionLists(config)
250+
}

banjax_test.go

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
package main
44

55
import (
6+
"fmt"
67
"io"
78
"io/ioutil"
89
"log"
10+
"math/rand"
911
"net/http"
1012
"os"
1113
"path/filepath"
@@ -115,6 +117,15 @@ func httpTester(t *testing.T, resources []TestResource) {
115117
}
116118
}
117119

120+
func httpStress(resources []TestResource, repeat int) {
121+
client := http.Client{}
122+
for _, resource := range resources {
123+
for i := 0; i <= repeat; i++ {
124+
httpRequest(client, resource)
125+
}
126+
}
127+
}
128+
118129
func httpRequest(client http.Client, resource TestResource) *http.Response {
119130
req, err := http.NewRequest(resource.method, endpoint+resource.name, nil)
120131
if err != nil {
@@ -133,20 +144,25 @@ func httpRequest(client http.Client, resource TestResource) *http.Response {
133144
return resp
134145
}
135146

147+
func randomXClientIP() http.Header {
148+
ip := fmt.Sprintf("10.2.0.%d", rand.Intn(252))
149+
return http.Header{"X-Client-IP": {ip}}
150+
}
151+
136152
func TestBanjaxEndpoint(t *testing.T) {
137153
banjax_resources := []TestResource{
138-
{"GET", "/auth_request", 200, nil, nil},
139-
{"POST", "/auth_request", 200, nil, nil},
140-
{"PUT", "/auth_request", 200, nil, nil},
141-
{"PATCH", "/auth_request", 200, nil, nil},
142-
{"HEAD", "/auth_request", 200, nil, nil},
143-
{"OPTIONS", "/auth_request", 200, nil, nil},
144-
{"DELETE", "/auth_request", 200, nil, nil},
145-
{"CONNECT", "/auth_request", 200, nil, nil},
146-
{"TRACE", "/auth_request", 200, nil, nil},
147-
{"GET", "/info", 200, nil, nil},
148-
{"GET", "/decision_lists", 200, nil, nil},
149-
{"GET", "/rate_limit_states", 200, nil, nil},
154+
{"GET", "/auth_request", 200, randomXClientIP(), nil},
155+
{"POST", "/auth_request", 200, randomXClientIP(), nil},
156+
{"PUT", "/auth_request", 200, randomXClientIP(), nil},
157+
{"PATCH", "/auth_request", 200, randomXClientIP(), nil},
158+
{"HEAD", "/auth_request", 200, randomXClientIP(), nil},
159+
{"OPTIONS", "/auth_request", 200, randomXClientIP(), nil},
160+
{"DELETE", "/auth_request", 200, randomXClientIP(), nil},
161+
{"CONNECT", "/auth_request", 200, randomXClientIP(), nil},
162+
{"TRACE", "/auth_request", 200, randomXClientIP(), nil},
163+
{"GET", "/info", 200, randomXClientIP(), nil},
164+
{"GET", "/decision_lists", 200, randomXClientIP(), nil},
165+
{"GET", "/rate_limit_states", 200, randomXClientIP(), nil},
150166
}
151167
httpTester(t, banjax_resources)
152168
}
@@ -157,19 +173,29 @@ func TestProtectedResources(t *testing.T) {
157173
protected_res := "wp-admin"
158174
httpTester(t, []TestResource{
159175
{"GET", "/info", 200, nil, []string{"2022-01-02"}},
160-
{"GET", "/auth_request?path=" + protected_res, 401, nil, nil},
176+
{"GET", "/auth_request?path=" + protected_res, 401, randomXClientIP(), nil},
161177
})
162178

163179
protected_res = "wp-admin2"
164180
reloadConfig(fixtureConfigTestReload)
165181
httpTester(t, []TestResource{
166182
{"GET", "/info", 200, nil, []string{"2022-02-03"}},
167-
{"GET", "/auth_request?path=" + protected_res, 401, nil, nil},
183+
{"GET", "/auth_request?path=" + protected_res, 401, randomXClientIP(), nil},
168184
})
169185
}
170186

171187
func reloadConfig(path string) {
188+
done := make(chan bool)
189+
// Simulate activity of http requests when the config is reloaded
190+
go func() {
191+
httpStress(
192+
[]TestResource{{"GET", "/auth_request", 200, randomXClientIP(), nil}},
193+
50)
194+
done <- true
195+
}()
196+
172197
copyConfigFile(path)
173198
syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
174199
time.Sleep(1 * time.Second)
200+
<-done
175201
}

internal/regex_rate_limiter.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ package internal
99
import (
1010
"bytes"
1111
"encoding/json"
12-
"github.com/hpcloud/tail"
1312
"log"
1413
"net/url"
1514
"strconv"
1615
"strings"
1716
"sync"
1817
"time"
18+
19+
"github.com/hpcloud/tail"
1920
)
2021

2122
func RunLogTailer(
@@ -152,6 +153,7 @@ func consumeLine(
152153
return
153154
}
154155

156+
rateLimitMutex.Lock()
155157
// log.Println(line.Text[secondSpace+firstSpace+2:])
156158
for _, regex_with_rate := range config.RegexesWithRates {
157159
ruleResult := RuleResult{}
@@ -174,7 +176,6 @@ func consumeLine(
174176
}
175177
ruleResult.SkipHost = false
176178

177-
rateLimitMutex.Lock()
178179
states, ok := (*ipToRegexStates)[ipString]
179180
if !ok {
180181
// log.Println("we haven't seen this IP before")
@@ -212,9 +213,9 @@ func consumeLine(
212213
(*(*ipToRegexStates)[ipString])[regex_with_rate.Rule].NumHits = 0 // XXX should it be 1?...
213214
}
214215

215-
rateLimitMutex.Unlock()
216216
consumeLineResult.RuleResults = append(consumeLineResult.RuleResults, ruleResult)
217217
}
218218

219+
rateLimitMutex.Unlock()
219220
return
220221
}

0 commit comments

Comments
 (0)