Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
projectdiscovery
GitHub Repository: projectdiscovery/nuclei
Path: blob/dev/pkg/reporting/exporters/splunk/splunkhec.go
2070 views
1
package splunk
2
3
import (
4
"bytes"
5
"crypto/tls"
6
"fmt"
7
"io"
8
"net"
9
"net/http"
10
"time"
11
12
"github.com/pkg/errors"
13
"github.com/projectdiscovery/nuclei/v3/pkg/output"
14
"github.com/projectdiscovery/nuclei/v3/pkg/protocols/common/protocolstate"
15
"github.com/projectdiscovery/nuclei/v3/pkg/utils/json"
16
"github.com/projectdiscovery/retryablehttp-go"
17
"github.com/projectdiscovery/useragent"
18
)
19
20
// Options contains necessary options required for splunk communication
21
type Options struct {
22
// Host is the hostname and port of the splunk instance
23
Host string `yaml:"host" validate:"required"`
24
Port int `yaml:"port" validate:"gte=0,lte=65535"`
25
// SSL (optional) enables ssl for splunk connection
26
SSL bool `yaml:"ssl"`
27
// SSLVerification (optional) disables SSL verification for splunk
28
SSLVerification bool `yaml:"ssl-verification"`
29
// Token for HEC instance
30
Token string `yaml:"token" validate:"required"`
31
IndexName string `yaml:"index-name" validate:"required"`
32
33
HttpClient *retryablehttp.Client `yaml:"-"`
34
ExecutionId string `yaml:"-"`
35
}
36
37
type data struct {
38
Event *output.ResultEvent `json:"event"`
39
}
40
41
// Exporter type for splunk
42
type Exporter struct {
43
url string
44
authentication string
45
splunk *http.Client
46
}
47
48
// New creates and returns a new exporter for splunk
49
func New(option *Options) (*Exporter, error) {
50
var ei *Exporter
51
52
dialers := protocolstate.GetDialersWithId(option.ExecutionId)
53
if dialers == nil {
54
return nil, fmt.Errorf("dialers not initialized for %s", option.ExecutionId)
55
}
56
57
var client *http.Client
58
if option.HttpClient != nil {
59
client = option.HttpClient.HTTPClient
60
} else {
61
client = &http.Client{
62
Timeout: 5 * time.Second,
63
Transport: &http.Transport{
64
MaxIdleConns: 10,
65
MaxIdleConnsPerHost: 10,
66
DialContext: dialers.Fastdialer.Dial,
67
DialTLSContext: dialers.Fastdialer.DialTLS,
68
TLSClientConfig: &tls.Config{InsecureSkipVerify: option.SSLVerification},
69
},
70
}
71
}
72
73
// preparing url for splunk
74
scheme := "http://"
75
if option.SSL {
76
scheme = "https://"
77
}
78
79
// Authentication header for HEC
80
authentication := "Splunk " + option.Token
81
82
// add HEC endpoint, index, source, sourcetype
83
addr := option.Host
84
if option.Port > 0 {
85
addr = net.JoinHostPort(addr, fmt.Sprint(option.Port))
86
}
87
base_url := fmt.Sprintf("%s%s", scheme, addr)
88
sourcetype := "nuclei:splunk-hec:exporter:json"
89
url := fmt.Sprintf("%s/services/collector/event?index=%s&sourcetype=%s&source=%s", base_url, option.IndexName, sourcetype, base_url)
90
91
ei = &Exporter{
92
url: url,
93
authentication: authentication,
94
splunk: client,
95
}
96
return ei, nil
97
}
98
99
// Export exports a passed result event to Splunk
100
func (exporter *Exporter) Export(event *output.ResultEvent) error {
101
// creating a request
102
req, err := http.NewRequest(http.MethodPost, exporter.url, nil)
103
if err != nil {
104
return errors.Wrap(err, "could not make request")
105
}
106
if len(exporter.authentication) > 0 {
107
req.Header.Add("Authorization", exporter.authentication)
108
}
109
userAgent := useragent.PickRandom()
110
req.Header.Set("User-Agent", userAgent.Raw)
111
req.Header.Add("Content-Type", "application/json")
112
113
d := data{Event: event}
114
b, err := json.Marshal(&d)
115
if err != nil {
116
return err
117
}
118
req.Body = io.NopCloser(bytes.NewReader(b))
119
120
res, err := exporter.splunk.Do(req)
121
if err != nil {
122
return err
123
}
124
125
b, err = io.ReadAll(res.Body)
126
if err != nil {
127
return errors.New(err.Error() + "error thrown by splunk " + string(b))
128
}
129
if res.StatusCode >= http.StatusMultipleChoices {
130
return errors.New("splunk responded with an error: " + string(b))
131
}
132
return nil
133
}
134
135
// Close closes the exporter after operation
136
func (exporter *Exporter) Close() error {
137
return nil
138
}
139
140