Skip to content

Commit

Permalink
Merge pull request #49 from deflect-ca/feature/no-challenge-if-basker…
Browse files Browse the repository at this point in the history
…ville-disabled

No challenge if baskerville disabled for site
  • Loading branch information
jeremy5189 authored Oct 9, 2023
2 parents fa6a9d1 + 2684d47 commit ba2cbd8
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 27 deletions.
2 changes: 2 additions & 0 deletions banjax-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,5 @@ disable_logging:
banning_log_file_temp: /etc/banjax/ban_ip_list_temp.log
session_cookie_hmac_secret: some_secret
session_cookie_ttl_seconds: 3600
sites_to_disable_baskerville:
localhost: true
18 changes: 12 additions & 6 deletions internal/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ type Config struct {
DisableKafka bool `yaml:"disable_kafka"`
SessionCookieHmacSecret string `yaml:"session_cookie_hmac_secret"`
SessionCookieTtlSeconds int `yaml:"session_cookie_ttl_seconds"`
SitesToDisableBaskerville map[string]bool `yaml:"sites_to_disable_baskerville"`
}

type RegexWithRate struct {
Expand All @@ -91,8 +92,9 @@ const (
)

type ExpiringDecision struct {
Decision Decision
Expires time.Time
Decision Decision
Expires time.Time
fromBaskerville bool
}

// XXX is this really how you make an enum in go?
Expand Down Expand Up @@ -382,7 +384,7 @@ func (failedChallengeStates FailedChallengeStates) String() string {
return buf.String()
}

func checkExpiringDecisionLists(clientIp string, decisionLists *DecisionLists) (Decision, bool) {
func checkExpiringDecisionLists(clientIp string, decisionLists *DecisionLists) (ExpiringDecision, bool) {
expiringDecision, ok := (*decisionLists).ExpiringDecisionLists[clientIp]
if !ok {
// log.Println("no mention in expiring lists")
Expand All @@ -393,7 +395,7 @@ func checkExpiringDecisionLists(clientIp string, decisionLists *DecisionLists) (
ok = false
}
}
return expiringDecision.Decision, ok
return expiringDecision, ok
}

// XXX mmm could hold the lock for a while?
Expand All @@ -419,6 +421,7 @@ func updateExpiringDecisionLists(
decisionLists *DecisionLists,
now time.Time,
newDecision Decision,
fromBaskerville bool,
) {
decisionListsMutex.Lock()
defer decisionListsMutex.Unlock()
Expand All @@ -430,11 +433,14 @@ func updateExpiringDecisionLists(
return
}
}
// log.Println("!!! existing and new: ", existingExpiringDecision.Decision, newDecision)
if config.Debug {
log.Println("Update expiringDecision with existing and new: ", existingExpiringDecision.Decision, newDecision)
log.Println("From baskerville", fromBaskerville)
}

purgeNginxAuthCacheForIp(ip)
expires := now.Add(time.Duration(config.ExpiringDecisionTtlSeconds) * time.Second)
(*decisionLists).ExpiringDecisionLists[ip] = ExpiringDecision{newDecision, expires}
(*decisionLists).ExpiringDecisionLists[ip] = ExpiringDecision{newDecision, expires, fromBaskerville}
}

type MetricsLogLine struct {
Expand Down
40 changes: 23 additions & 17 deletions internal/http_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -930,33 +930,39 @@ func decisionForNginx2(
// changing the decision.
// XXX i forget if that comment is stale^
decisionListsMutex.Lock()
decision, ok = checkExpiringDecisionLists(clientIp, decisionLists)
expiringDecision, ok := checkExpiringDecisionLists(clientIp, decisionLists)
decisionListsMutex.Unlock()
if !ok {
// log.Println("no mention in expiring lists")
} else {
switch decision {
switch expiringDecision.Decision {
case Allow:
accessGranted(c, config, DecisionListResultToString[ExpiringAccessGranted])
// log.Println("access granted from expiring lists")
decisionForNginxResult.DecisionListResult = ExpiringAccessGranted
return
case Challenge:
// log.Println("challenge from expiring lists")
sendOrValidateShaChallengeResult := sendOrValidateShaChallenge(
config,
c,
banner,
rateLimitMutex,
failedChallengeStates,
Block, // FailAction
decisionListsMutex,
decisionLists,
)
decisionForNginxResult.DecisionListResult = ExpiringChallenge
decisionForNginxResult.ShaChallengeResult = &sendOrValidateShaChallengeResult.ShaChallengeResult
decisionForNginxResult.TooManyFailedChallengesResult = &sendOrValidateShaChallengeResult.TooManyFailedChallengesResult
return
// Check if expiringDecision.fromBaskerville, if true, check if domain disabled baskerville
_, disabled := config.SitesToDisableBaskerville[requestedHost]
if expiringDecision.fromBaskerville && disabled {
log.Printf("domain %s disabled baskerville, skip expiring challenge for %s", requestedHost, clientIp)
} else {
// log.Println("challenge from expiring lists")
sendOrValidateShaChallengeResult := sendOrValidateShaChallenge(
config,
c,
banner,
rateLimitMutex,
failedChallengeStates,
Block, // FailAction
decisionListsMutex,
decisionLists,
)
decisionForNginxResult.DecisionListResult = ExpiringChallenge
decisionForNginxResult.ShaChallengeResult = &sendOrValidateShaChallengeResult.ShaChallengeResult
decisionForNginxResult.TooManyFailedChallengesResult = &sendOrValidateShaChallengeResult.TooManyFailedChallengesResult
return
}
case NginxBlock, IptablesBlock:
accessDenied(c, config, DecisionListResultToString[ExpiringBlock])
// log.Println("access denied from expiring lists")
Expand Down
1 change: 1 addition & 0 deletions internal/iptables.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ func (b Banner) BanOrChallengeIp(
&(*b.DecisionLists),
time.Now(),
decision,
false, // not from baskerville
)

if decision == IptablesBlock {
Expand Down
30 changes: 26 additions & 4 deletions internal/kafka.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,34 @@ import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"io/ioutil"
"log"
"os"
"sync"
"time"

"github.com/google/uuid"
"github.com/segmentio/kafka-go"
)

/*
sample baskerville message:
{
"Value": "0.0.0.0",
"Name": "challenge_ip",
"duration": 15.0,
"session_id": "ID",
"source": "behave",
"start": "2023-09-27 08:04:43",
"host": "example.com",
"end": "2023-09-27 08:04:58",
"urls": "[[\"2023-09-27 08:04:43\", \"/some/url\"], [\"2023-09-27 08:04:58\", \"/another/url\"]]"
}
*/
type commandMessage struct {
Name string
Value string
Host string `json:"host"`
}

func getDialer(config *Config) *kafka.Dialer {
Expand All @@ -34,7 +50,7 @@ func getDialer(config *Config) *kafka.Dialer {
log.Fatalf("KAFKA: failed to load cert + key pair: %s", err)
}

caCert, err := ioutil.ReadFile(config.KafkaSslCa)
caCert, err := os.ReadFile(config.KafkaSslCa)
if err != nil {
log.Fatalf("KAFKA: failed to read CA root: %s", err)
}
Expand Down Expand Up @@ -122,22 +138,28 @@ func handleCommand(
) {
switch command.Name {
case "challenge_ip":
// exempt a site from challenge according to config
_, disabled := config.SitesToDisableBaskerville[command.Host]

// XXX do a real valid IP check?
if len(command.Value) > 4 {
if len(command.Value) > 4 && !disabled {
updateExpiringDecisionLists(
config,
command.Value,
decisionListsMutex,
decisionLists,
time.Now(),
Challenge,
true, // from baskerville, provide to http_server to distinguish from regex
)
log.Printf("KAFKA: added to global challenge lists: Challenge %s\n", command.Value)
} else if disabled {
log.Printf("KAFKA: not challenge %s, site %s disables baskerville\n", command.Value, command.Host)
} else {
log.Printf("KAFKA: command value looks malformed: %s\n", command.Value)
}
default:
log.Printf("KAFKA:unrecognized command name: %s\n", command.Name)
log.Printf("KAFKA: unrecognized command name: %s\n", command.Name)
}
}

Expand Down

0 comments on commit ba2cbd8

Please sign in to comment.