-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
196 lines (183 loc) · 5.8 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
package config
import (
"encoding/xml"
"errors"
"fmt"
"io"
"os"
"strconv"
"strings"
)
const (
defaultMaxWorkers = 20
defaultWazuhConfigFile = "/var/ossec/etc/ossec.conf"
defaultIntegratorConfigFile = "/var/ossec/etc/integrator.conf"
)
type Config struct {
WazuhConfig WazuhConfig `xml:"ossec_config"`
IntegratorConfig IntegratorConfig `xml:"integrator_config"`
}
type IntegratorConfig struct {
MaxWorkers int `xml:"max_workers"`
}
type WazuhConfig struct {
Integrations []Integration `xml:"integration"`
}
type Integration struct {
Name string `xml:"name" json:"name"`
HookURL string `xml:"hook_url" json:"hook_url,omitempty"`
APIKey string `xml:"api_key" json:"api_key,omitempty"`
Level int `xml:"level" json:"level,omitempty"`
RawRuleID string `xml:"rule_id" json:"rule_id,omitempty"`
RuleIDs []int `xml:"-" json:"-"`
RawGroup string `xml:"group" json:"group,omitempty"`
Groups []string `xml:"-" json:"-"`
RawEventLocation string `xml:"event_location" json:"event_location,omitempty"`
EventLocations []string `xml:"-" json:"-"`
AlertFormat string `xml:"alert_format" json:"alert_format,omitempty"`
}
// GetConfig parse ossec.conf then returns config struct
func GetConfig() (*Config, error) {
wazuhConfFile := defaultWazuhConfigFile
integratorConfFile := defaultIntegratorConfigFile
// development
env := os.Getenv("ENV")
if env == "dev" {
wazuhConfFile = "./ossec.conf"
integratorConfFile = "./integrator.conf"
}
// load wazuh config
wazuhConf, err := os.Open(wazuhConfFile)
if err != nil {
return nil, fmt.Errorf("read wazuh config err: %w", err)
}
defer wazuhConf.Close()
data, _ := io.ReadAll(wazuhConf)
var wazuhConfig WazuhConfig
err = xml.Unmarshal(data, &wazuhConfig)
if err != nil {
return nil, fmt.Errorf("unmarshal err: %w", err)
}
// load integrator config
var integratorConf *os.File
integratorConf, err = os.Open(integratorConfFile)
if err != nil {
return nil, fmt.Errorf("read integrator config err: %w", err)
}
defer integratorConf.Close()
data, _ = io.ReadAll(integratorConf)
var integratorConfig IntegratorConfig
err = xml.Unmarshal(data, &integratorConfig)
if err != nil {
return nil, fmt.Errorf("unmarshal err: %w", err)
}
if check, dup := entryIsDuplicate(wazuhConfig); check {
return nil, fmt.Errorf("duplicate entry: %s", dup)
}
if integratorConfig.MaxWorkers == 0 {
integratorConfig.MaxWorkers = defaultMaxWorkers
}
newIntegrations := make([]Integration, 0)
for _, integration := range wazuhConfig.Integrations {
if len(integration.Name) == 0 {
return nil, errors.New("name can't be empty")
}
integrationBin := fmt.Sprintf("/var/ossec/integrations/%s", integration.Name)
// development
if env == "dev" {
integrationBin = "./custom-integration.sh"
}
if _, err = os.Stat(integrationBin); os.IsNotExist(err) {
return nil, fmt.Errorf("%s doesn't exist", integrationBin)
}
if integration.Name != "slack" && integration.Name != "pagerduty" && integration.Name != "virustotal" && !strings.HasPrefix(integration.Name, "custom-") {
return nil, errors.New("name must be 'slack', 'pagerduty', 'virustotal' or 'custom-'")
}
if integration.Level < 1 || integration.Level > 16 {
return nil, errors.New("level must in range 1-16")
}
if integration.RawRuleID != "" {
ruleIDs := strings.Split(integration.RawRuleID, ",")
if len(ruleIDs) > 0 {
for _, sRuleID := range ruleIDs {
var ruleID int
ruleID, err = strconv.Atoi(sRuleID)
if err != nil {
return nil, errors.New("rule_id must be a number or multiple numbers separated by commas")
}
integration.RuleIDs = append(integration.RuleIDs, ruleID)
}
integration.RuleIDs = unique(integration.RuleIDs)
} else {
var ruleID int
ruleID, err = strconv.Atoi(integration.RawRuleID)
if err != nil {
return nil, errors.New("rule_id must be a number or multiple numbers separated by commas")
}
integration.RuleIDs = append(integration.RuleIDs, ruleID)
}
}
if integration.RawGroup != "" {
groups := strings.Split(integration.RawGroup, ",")
if len(groups) > 0 {
integration.Groups = append(integration.Groups, groups...)
} else {
integration.Groups = append(integration.Groups, integration.RawGroup)
}
}
if integration.RawEventLocation != "" {
eventLocations := strings.Split(integration.RawEventLocation, ",")
if len(eventLocations) > 0 {
integration.EventLocations = append(integration.EventLocations, eventLocations...)
} else {
integration.EventLocations = append(integration.EventLocations, integration.RawEventLocation)
}
}
if integration.AlertFormat != "json" {
return nil, errors.New("alert_format must be 'json'")
}
newIntegrations = append(newIntegrations, integration)
}
return &Config{
WazuhConfig: WazuhConfig{
Integrations: newIntegrations,
},
IntegratorConfig: integratorConfig,
}, nil
}
func unique(intSlice []int) []int {
keys := make(map[int]bool)
var list []int
for _, entry := range intSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}
func uniqueString(intSlice []string) ([]string, []string) {
keys := make(map[string]bool)
var list []string
var duplicate []string
for _, entry := range intSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
} else {
duplicate = append(duplicate, entry)
}
}
return list, duplicate
}
func entryIsDuplicate(input WazuhConfig) (bool, string) {
names := make([]string, 0)
for _, integration := range input.Integrations {
names = append(names, integration.Name)
}
_, duplicate := uniqueString(names)
if len(duplicate) > 0 {
return true, strings.Join(duplicate, " ")
}
return false, ""
}