Skip to content

Commit 953be2b

Browse files
committed
initial
0 parents  commit 953be2b

8 files changed

+367
-0
lines changed

LICENSE

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Copyright 2018 Remco Verhoef
2+
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+

README.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# gogreynoise [![](https://godoc.org/github.com/dutchcoders/gogreynoise?status.svg)](http://godoc.org/github.com/dutchcoders/gogreynoise) [![Go Report Card](https://goreportcard.com/badge/dutchcoders/gogreynoise)](https://goreportcard.com/report/dutchcoders/gogreynoise)
2+
3+
Golang client for Greynoise.io. The client currently only implements /context, but it is easy to extend other features.
4+
5+
## Usage
6+
7+
```
8+
package greynoise
9+
10+
import (
11+
"fmt"
12+
"net"
13+
14+
greynoise "github.com/dutchcoders/gogreynoise"
15+
)
16+
17+
func ExampleExamples_output() {
18+
client, err := greynoise.New(
19+
greynoise.WithKey("{key}"),
20+
)
21+
if err != nil {
22+
panic(err.Error)
23+
}
24+
25+
ip := net.ParseIP("8.8.8.8")
26+
result, err := client.Context(ip)
27+
if err != nil {
28+
panic(err.Error)
29+
}
30+
31+
fmt.Printf("Actor: %s\n", result.Actor)
32+
}
33+
```
34+
35+
## Contributors
36+
37+
* [Remco Verhoef](https://twitter.com/remco_verhoef)
38+
39+
## Copyright and license
40+
41+
Code released under [Apache License 2.0](LICENSE).
42+

client.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package greynoise
2+
3+
import (
4+
"fmt"
5+
"net"
6+
"net/http"
7+
"net/url"
8+
)
9+
10+
type Client struct {
11+
Key string
12+
13+
*http.Client
14+
baseURL *url.URL
15+
}
16+
17+
// Context will return more information about a given IP address. Returns time ranges, IP metadata (network owner,
18+
// ASN,reverse DNS pointer, country), associated actors, activity tags, and raw port scan and web
19+
// request information.
20+
func (c *Client) Context(ip net.IP) (*ContextResult, error) {
21+
request, err := c.NewRequest("GET", fmt.Sprintf("/v2/noise/context/%s", ip.String()), nil)
22+
if err != nil {
23+
return nil, err
24+
}
25+
26+
output := ContextResult{}
27+
if err := c.Do(request, &output); err != nil {
28+
return nil, err
29+
}
30+
31+
return &output, nil
32+
}
33+
34+
type optionFn func(*Client)
35+
36+
// WithKey contains the Greynoise API key
37+
func WithKey(key string) optionFn {
38+
return func(c *Client) {
39+
c.Key = key
40+
}
41+
}
42+
43+
// New returns a Greynoise API client
44+
func New(options ...optionFn) (*Client, error) {
45+
baseURL, err := url.Parse("https://enterprise.api.greynoise.io/v2/noise/")
46+
if err != nil {
47+
panic(err)
48+
}
49+
50+
c := &Client{
51+
baseURL: baseURL,
52+
Client: http.DefaultClient,
53+
}
54+
55+
for _, optionFn := range options {
56+
optionFn(c)
57+
58+
}
59+
60+
return c, nil
61+
}

driver.go

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package greynoise
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"io"
8+
"io/ioutil"
9+
"net/http"
10+
"net/http/httputil"
11+
"net/url"
12+
"os"
13+
)
14+
15+
// NewRequest prepares http.Request to call the Greynoise API
16+
func (c *Client) NewRequest(method, urlStr string, body interface{}) (*http.Request, error) {
17+
rel, err := url.Parse(urlStr)
18+
if err != nil {
19+
return nil, err
20+
}
21+
22+
u := c.baseURL.ResolveReference(rel)
23+
24+
var buf io.ReadWriter
25+
if body != nil {
26+
buf = new(bytes.Buffer)
27+
err := json.NewEncoder(buf).Encode(body)
28+
if err != nil {
29+
return nil, err
30+
}
31+
}
32+
33+
req, err := http.NewRequest(method, u.String(), buf)
34+
if err != nil {
35+
return nil, err
36+
}
37+
38+
req.Header.Add("Content-Type", "text/json; charset=UTF-8")
39+
req.Header.Add("Accept", "text/json")
40+
req.Header.Add("Key", c.Key)
41+
req.Header.Add("User-Agent", "gogreynoise")
42+
43+
return req, nil
44+
}
45+
46+
// Do will execute the http.Request and decode the result
47+
func (wd *Client) Do(req *http.Request, v interface{}) error {
48+
if dump, err := httputil.DumpRequestOut(req, true); err == nil {
49+
os.Stdout.Write(dump)
50+
}
51+
52+
resp, err := wd.Client.Do(req)
53+
if err != nil {
54+
return err
55+
}
56+
57+
r := resp.Body
58+
defer r.Close()
59+
60+
if true {
61+
} else if dump, err := httputil.DumpResponse(resp, true); err == nil {
62+
os.Stdout.Write(dump)
63+
64+
resp.Body = ioutil.NopCloser(bytes.NewBuffer(dump))
65+
}
66+
67+
r2 := r
68+
69+
if resp.StatusCode != http.StatusOK {
70+
result := ErrorResult{}
71+
json.NewDecoder(r2).Decode(&result)
72+
return fmt.Errorf(result.Error)
73+
}
74+
75+
err = json.NewDecoder(r2).Decode(&v)
76+
if err != nil {
77+
return err
78+
}
79+
80+
return nil
81+
}

error.go

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package greynoise
2+
3+
import "fmt"
4+
5+
type Error struct {
6+
ErrorCode int `json:"error_code"`
7+
ErrorString string `json:"error"`
8+
}
9+
10+
func (de *Error) Error() string {
11+
return fmt.Sprintf("%s (%d)", de.ErrorString, de.ErrorCode)
12+
}

greynoise_test.go

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package greynoise
2+
3+
import (
4+
"fmt"
5+
"net"
6+
7+
greynoise "github.com/dutchcoders/gogreynoise"
8+
)
9+
10+
func ExampleExamples_output() {
11+
client, err := greynoise.New(
12+
greynoise.WithKey("{key}"),
13+
)
14+
if err != nil {
15+
panic(err.Error)
16+
}
17+
18+
ip := net.ParseIP("8.8.8.8")
19+
result, err := client.Context(ip)
20+
if err != nil {
21+
panic(err.Error)
22+
}
23+
24+
fmt.Printf("Actor: %s\n", result.Actor)
25+
}

merge.go

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package greynoise
2+
3+
import (
4+
"fmt"
5+
"reflect"
6+
)
7+
8+
func Merge(dest interface{}, src interface{}) error {
9+
vSrc := reflect.ValueOf(src)
10+
11+
vDst := reflect.ValueOf(dest)
12+
if vDst.Kind() == reflect.Ptr {
13+
vDst = vDst.Elem()
14+
}
15+
return merge(vDst, vSrc)
16+
}
17+
18+
func merge(dest reflect.Value, src reflect.Value) error {
19+
switch src.Kind() {
20+
case reflect.Func:
21+
if !dest.CanSet() {
22+
return nil
23+
}
24+
src = src.Call([]reflect.Value{})[0]
25+
if src.Kind() == reflect.Ptr {
26+
src = src.Elem()
27+
}
28+
if err := merge(dest, src); err != nil {
29+
return err
30+
}
31+
case reflect.Struct:
32+
// try to set the struct
33+
if src.Type() == dest.Type() {
34+
if !dest.CanSet() {
35+
return nil
36+
}
37+
38+
dest.Set(src)
39+
return nil
40+
}
41+
42+
for i := 0; i < src.NumMethod(); i++ {
43+
tMethod := src.Type().Method(i)
44+
45+
df := dest.FieldByName(tMethod.Name)
46+
if df.Kind() == 0 {
47+
continue
48+
}
49+
50+
if err := merge(df, src.Method(i)); err != nil {
51+
return err
52+
}
53+
}
54+
55+
for i := 0; i < src.NumField(); i++ {
56+
tField := src.Type().Field(i)
57+
58+
df := dest.FieldByName(tField.Name)
59+
if df.Kind() == 0 {
60+
continue
61+
}
62+
63+
if err := merge(df, src.Field(i)); err != nil {
64+
return err
65+
}
66+
}
67+
68+
case reflect.Map:
69+
x := reflect.MakeMap(dest.Type())
70+
for _, k := range src.MapKeys() {
71+
x.SetMapIndex(k, src.MapIndex(k))
72+
}
73+
dest.Set(x)
74+
case reflect.Slice:
75+
x := reflect.MakeSlice(dest.Type(), src.Len(), src.Len())
76+
for j := 0; j < src.Len(); j++ {
77+
merge(x.Index(j), src.Index(j))
78+
}
79+
dest.Set(x)
80+
case reflect.Chan:
81+
case reflect.Ptr:
82+
if !src.IsNil() && dest.CanSet() {
83+
fmt.Println(src.Type().Name())
84+
fmt.Println(dest.Type().Name())
85+
x := reflect.New(dest.Type().Elem())
86+
merge(x.Elem(), src.Elem())
87+
dest.Set(x)
88+
}
89+
default:
90+
if !dest.CanSet() {
91+
return nil
92+
}
93+
dest.Set(src)
94+
}
95+
96+
return nil
97+
}

messages.go

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package greynoise
2+
3+
// ContextResult is the result of the /context api
4+
type ContextResult struct {
5+
Actor string `json:"actor"`
6+
FirstSeen string `json:"first_seen"`
7+
IP string `json:"ip"`
8+
LastSeen string `json:"last_seen"`
9+
Metadata struct {
10+
ASN string `json:"asn"`
11+
Category string `json:"category"`
12+
City string `json:"city"`
13+
Country string `json:"country"`
14+
CountryCode string `json:"country_code"`
15+
Organization string `json:"organization"`
16+
Os string `json:"os"`
17+
Rdns string `json:"rdns"`
18+
Tor bool `json:"tor"`
19+
} `json:"metadata"`
20+
RawData struct {
21+
Scan []struct {
22+
Port int64 `json:"port"`
23+
Protocol string `json:"protocol"`
24+
} `json:"scan"`
25+
Web struct {
26+
} `json:"web"`
27+
} `json:"raw_data"`
28+
Seen bool `json:"seen"`
29+
Tags []string `json:"tags"`
30+
}
31+
32+
// ErrorResult is the result when an error occurs
33+
type ErrorResult struct {
34+
Error string `json:"error"`
35+
}

0 commit comments

Comments
 (0)