pkg/urlhaus/api.go
// this file is part of dohli.
//
// Copyright (c) 2020 Dima Krasner
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Package urlhaus queries host information from URLHaus.
package urlhaus
import (
"bytes"
"context"
"encoding/json"
"io/ioutil"
"log"
"net/http"
"time"
"github.com/dimkr/dohli/pkg/queue"
)
const (
url = "https://urlhaus-api.abuse.ch"
timeout = 5 * time.Second
)
// Client is a URLHaus API client.
type Client struct{}
func (client *Client) Connect() error {
return nil
}
func (client *Client) IsAsync() bool {
return true
}
type hostResponse struct {
QueryStatus string `json:"query_status"`
Blacklists map[string]string `json:"blacklists"`
}
func (client *Client) IsBad(parent context.Context, msg *queue.DomainAccessMessage) bool {
ctx, cancel := context.WithTimeout(parent, timeout)
defer cancel()
request, err := http.NewRequestWithContext(ctx, "POST", url+"/v1/host", bytes.NewBuffer([]byte("host="+msg.Domain)))
if err != nil {
return false
}
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
response, err := http.DefaultClient.Do(request)
if err != nil {
return false
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return false
}
j, err := ioutil.ReadAll(response.Body)
if err != nil {
return false
}
var parsedResponse hostResponse
if err := json.Unmarshal(j, &parsedResponse); err != nil {
log.Printf("Failed to parse %s: %v", j, err)
return false
}
if parsedResponse.QueryStatus != "ok" {
return false
}
for _, status := range parsedResponse.Blacklists {
if status != "not listed" {
log.Println(msg.Domain, " is blocked by URLHaus")
return true
}
}
return false
}