Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

manage force_pull message for one blocklist #2615

Merged
merged 2 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 22 additions & 7 deletions pkg/apiserver/apic.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,12 +612,23 @@
}

// update blocklists
if err := a.UpdateBlocklists(data.Links, add_counters); err != nil {
if err := a.UpdateBlocklists(data.Links, add_counters, forcePull); err != nil {
return fmt.Errorf("while updating blocklists: %w", err)
}
return nil
}

// we receive a link to a blocklist, we pull the content of the blocklist and we create one alert
func (a *apic) PullBlocklist(blocklist *modelscapi.BlocklistLink, forcePull bool) error {
add_counters, _ := makeAddAndDeleteCounters()

Check warning on line 623 in pkg/apiserver/apic.go

View check run for this annotation

Codecov / codecov/patch

pkg/apiserver/apic.go#L622-L623

Added lines #L622 - L623 were not covered by tests
if err := a.UpdateBlocklists(&modelscapi.GetDecisionsStreamResponseLinks{
Blocklists: []*modelscapi.BlocklistLink{blocklist},
}, add_counters, forcePull); err != nil {
return fmt.Errorf("while pulling blocklist: %w", err)
}
return nil
}

// if decisions is whitelisted: return representation of the whitelist ip or cidr
// if not whitelisted: empty string
func (a *apic) whitelistedBy(decision *models.Decision) string {
Expand Down Expand Up @@ -704,7 +715,7 @@
return false, nil
}

func (a *apic) updateBlocklist(client *apiclient.ApiClient, blocklist *modelscapi.BlocklistLink, add_counters map[string]map[string]int) error {
func (a *apic) updateBlocklist(client *apiclient.ApiClient, blocklist *modelscapi.BlocklistLink, add_counters map[string]map[string]int, forcePull bool) error {

Check warning on line 718 in pkg/apiserver/apic.go

View check run for this annotation

Codecov / codecov/patch

pkg/apiserver/apic.go#L718

Added line #L718 was not covered by tests
if blocklist.Scope == nil {
log.Warningf("blocklist has no scope")
return nil
Expand All @@ -713,12 +724,16 @@
log.Warningf("blocklist has no duration")
return nil
}
forcePull, err := a.ShouldForcePullBlocklist(blocklist)
if err != nil {
return fmt.Errorf("while checking if we should force pull blocklist %s: %w", *blocklist.Name, err)
if !forcePull {
_forcePull, err := a.ShouldForcePullBlocklist(blocklist)

Check warning on line 728 in pkg/apiserver/apic.go

View check run for this annotation

Codecov / codecov/patch

pkg/apiserver/apic.go#L727-L728

Added lines #L727 - L728 were not covered by tests
if err != nil {
return fmt.Errorf("while checking if we should force pull blocklist %s: %w", *blocklist.Name, err)
}
forcePull = _forcePull

Check warning on line 732 in pkg/apiserver/apic.go

View check run for this annotation

Codecov / codecov/patch

pkg/apiserver/apic.go#L730-L732

Added lines #L730 - L732 were not covered by tests
}
blocklistConfigItemName := fmt.Sprintf("blocklist:%s:last_pull", *blocklist.Name)
var lastPullTimestamp *string
var err error

Check warning on line 736 in pkg/apiserver/apic.go

View check run for this annotation

Codecov / codecov/patch

pkg/apiserver/apic.go#L736

Added line #L736 was not covered by tests
if !forcePull {
lastPullTimestamp, err = a.dbClient.GetConfigItem(blocklistConfigItemName)
if err != nil {
Expand Down Expand Up @@ -758,7 +773,7 @@
return nil
}

func (a *apic) UpdateBlocklists(links *modelscapi.GetDecisionsStreamResponseLinks, add_counters map[string]map[string]int) error {
func (a *apic) UpdateBlocklists(links *modelscapi.GetDecisionsStreamResponseLinks, add_counters map[string]map[string]int, forcePull bool) error {
if links == nil {
return nil
}
Expand All @@ -772,7 +787,7 @@
return fmt.Errorf("while creating default client: %w", err)
}
for _, blocklist := range links.Blocklists {
if err := a.updateBlocklist(defaultClient, blocklist, add_counters); err != nil {
if err := a.updateBlocklist(defaultClient, blocklist, add_counters, forcePull); err != nil {
return err
}
}
Expand Down
31 changes: 31 additions & 0 deletions pkg/apiserver/apic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,37 @@ func TestAPICPullTopBLCacheForceCall(t *testing.T) {
require.NoError(t, err)
}

func TestAPICPullBlocklistCall(t *testing.T) {
api := getAPIC(t)
httpmock.Activate()
defer httpmock.DeactivateAndReset()

httpmock.RegisterResponder("GET", "http://api.crowdsec.net/blocklist1", func(req *http.Request) (*http.Response, error) {
assert.Equal(t, "", req.Header.Get("If-Modified-Since"))
return httpmock.NewStringResponse(200, "1.2.3.4"), nil
})
url, err := url.ParseRequestURI("http://api.crowdsec.net/")
require.NoError(t, err)

apic, err := apiclient.NewDefaultClient(
url,
"/api",
fmt.Sprintf("crowdsec/%s", version.String()),
nil,
)
require.NoError(t, err)

api.apiClient = apic
err = api.PullBlocklist(&modelscapi.BlocklistLink{
URL: ptr.Of("http://api.crowdsec.net/blocklist1"),
Name: ptr.Of("blocklist1"),
Scope: ptr.Of("Ip"),
Remediation: ptr.Of("ban"),
Duration: ptr.Of("24h"),
}, true)
require.NoError(t, err)
}

func TestAPICPush(t *testing.T) {
tests := []struct {
name string
Expand Down
48 changes: 45 additions & 3 deletions pkg/apiserver/papi_cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

"github.com/crowdsecurity/crowdsec/pkg/apiclient"
"github.com/crowdsecurity/crowdsec/pkg/models"
"github.com/crowdsecurity/crowdsec/pkg/modelscapi"
"github.com/crowdsecurity/crowdsec/pkg/types"
)

Expand All @@ -19,6 +20,23 @@
Decisions []string `json:"decisions"`
}

type blocklistLink struct {
// blocklist name
Name string `json:"name"`
// blocklist url
Url string `json:"url"`
// blocklist remediation
Remediation string `json:"remediation"`
// blocklist scope
Scope string `json:"scope,omitempty"`
// blocklist duration
Duration string `json:"duration,omitempty"`
}

type forcePull struct {
Blocklist *blocklistLink `json:"blocklist,omitempty"`
}

func DecisionCmd(message *Message, p *Papi, sync bool) error {
switch message.Header.OperationCmd {
case "delete":
Expand Down Expand Up @@ -144,11 +162,35 @@
log.Infof("Received reauth command from PAPI, resetting token")
p.apiClient.GetClient().Transport.(*apiclient.JWTTransport).ResetToken()
case "force_pull":
log.Infof("Received force_pull command from PAPI, pulling community and 3rd-party blocklists")
err := p.apic.PullTop(true)
data, err := json.Marshal(message.Data)

Check warning on line 165 in pkg/apiserver/papi_cmd.go

View check run for this annotation

Codecov / codecov/patch

pkg/apiserver/papi_cmd.go#L165

Added line #L165 was not covered by tests
if err != nil {
return fmt.Errorf("failed to force pull operation: %s", err)
return err
}
forcePullMsg := forcePull{}
if err := json.Unmarshal(data, &forcePullMsg); err != nil {
return fmt.Errorf("message for '%s' contains bad data format: %s", message.Header.OperationType, err)

Check warning on line 171 in pkg/apiserver/papi_cmd.go

View check run for this annotation

Codecov / codecov/patch

pkg/apiserver/papi_cmd.go#L167-L171

Added lines #L167 - L171 were not covered by tests
}

if forcePullMsg.Blocklist == nil {
log.Infof("Received force_pull command from PAPI, pulling community and 3rd-party blocklists")
err = p.apic.PullTop(true)
if err != nil {
return fmt.Errorf("failed to force pull operation: %s", err)
}
} else {
log.Infof("Received force_pull command from PAPI, pulling blocklist %s", forcePullMsg.Blocklist.Name)
err = p.apic.PullBlocklist(&modelscapi.BlocklistLink{
Name: &forcePullMsg.Blocklist.Name,
URL: &forcePullMsg.Blocklist.Url,
Remediation: &forcePullMsg.Blocklist.Remediation,
Scope: &forcePullMsg.Blocklist.Scope,
Duration: &forcePullMsg.Blocklist.Duration,
}, true)
if err != nil {
return fmt.Errorf("failed to force pull operation: %s", err)
}

Check warning on line 191 in pkg/apiserver/papi_cmd.go

View check run for this annotation

Codecov / codecov/patch

pkg/apiserver/papi_cmd.go#L174-L191

Added lines #L174 - L191 were not covered by tests
}

default:
return fmt.Errorf("unknown command '%s' for operation type '%s'", message.Header.OperationCmd, message.Header.OperationType)
}
Expand Down