summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--asn/mapping.go105
-rw-r--r--go.mod2
-rw-r--r--go.sum4
3 files changed, 111 insertions, 0 deletions
diff --git a/asn/mapping.go b/asn/mapping.go
new file mode 100644
index 0000000..79372a2
--- /dev/null
+++ b/asn/mapping.go
@@ -0,0 +1,105 @@
+package asn
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "path/filepath"
+
+ "github.com/adrg/xdg"
+ "github.com/gocarina/gocsv"
+)
+
+const SOURCE string = "https://cdn.jsdelivr.net/gh/ipverse/as-metadata@master/as.csv"
+
+type AsnEntry struct {
+ ASN int `csv:"asn"`
+ Handle string `csv:"handle"`
+ Description string `csv:"description"`
+ CountryCode string `csv:"country-code"`
+}
+
+type AsnMap map[int]AsnEntry
+
+// localPath returns the destination of local copy of asn metadata
+func localPath() string {
+ return filepath.Join(xdg.DataHome, "/audidi/as.csv")
+}
+
+// downloadAsnSource downloads ASN metadata source to disk
+func downloadAsnSource() error {
+ resp, err := http.Get(SOURCE)
+ if err != nil {
+ return fmt.Errorf("error fetching ASN metadata: %s", err)
+ }
+ if resp.StatusCode != http.StatusOK {
+ return fmt.Errorf("error fetching ASN metadata: http %d", resp.StatusCode)
+ }
+ defer resp.Body.Close()
+
+ file, err := os.Create(localPath())
+ if err != nil {
+ return fmt.Errorf("can't open file to write ASN metadata: %s", err)
+ }
+
+ if _, err := io.Copy(file, resp.Body); err != nil {
+ return fmt.Errorf("can't copy ASN metadata to file: %s", err)
+ }
+
+ return nil
+}
+
+// useAsnSource returns either a local cached version of
+// ASN source bytes or download from source
+func useAsnSource() ([]byte, error) {
+ path := localPath()
+ os.MkdirAll(filepath.Dir(path), os.ModePerm)
+
+ if info, err := os.Stat(path); os.IsNotExist(err) || info.Size() == 0 {
+ log.Println("downloading ASN metadata...")
+ if err := downloadAsnSource(); err != nil {
+ return nil, err
+ }
+ log.Println("ASN metadata downloaded")
+ }
+
+ bytes, err := os.ReadFile(path)
+ if err != nil {
+ return nil, fmt.Errorf("can't open file to read ASN metadata: %s", err)
+ }
+
+ return bytes, nil
+}
+
+// parseMetadata parse raw bytes of ASN metadata into readable entries
+func parseMetadata(bytes []byte) ([]AsnEntry, error) {
+ var entries []AsnEntry
+
+ if err := gocsv.UnmarshalBytes(bytes, &entries); err != nil {
+ return nil, fmt.Errorf("can't parse ASN metadata: %s", err)
+ }
+
+ return entries, nil
+}
+
+// GetMapping returns a pointer to ASN-metadata mappings
+func GetMapping() *AsnMap {
+ bytes, err := useAsnSource()
+ if err != nil {
+ log.Fatalln("Failed to load ASN metadata: ", err)
+ }
+
+ entries, err := parseMetadata(bytes)
+ if err != nil {
+ log.Fatalln("Failed to parse ASN metadata (Delete data and retry): ", err)
+ }
+
+ mapping := make(AsnMap)
+ for _, entry := range entries {
+ mapping[entry.ASN] = entry
+ }
+
+ return &mapping
+}
diff --git a/go.mod b/go.mod
index 7507e58..6413654 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,9 @@ module src.eltr.ac/eltrac/audidi
go 1.26.5
require (
+ github.com/adrg/xdg v0.5.3 // indirect
github.com/gocarina/gocsv v0.0.0-20261101205459-d0dd027dcbfa // indirect
github.com/ohler55/ojg v1.28.9 // indirect
github.com/x-way/crawlerdetect v0.2.32 // indirect
+ golang.org/x/sys v0.26.0 // indirect
)
diff --git a/go.sum b/go.sum
index b882144..29a7f15 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,10 @@
+github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=
+github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
github.com/gocarina/gocsv v0.0.0-20261101205459-d0dd027dcbfa h1:u6dQLh7NdeVIBn4fE4YL9PiHFephNp7t7rUSU+fulro=
github.com/gocarina/gocsv v0.0.0-20261101205459-d0dd027dcbfa/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
github.com/ohler55/ojg v1.28.9 h1:VL2vdN1CjniaNABNOFjorAW+/o7eBQDc4z5jO49jkHM=
github.com/ohler55/ojg v1.28.9/go.mod h1:/Y5dGWkekv9ocnUixuETqiL58f+5pAsUfg5P8e7Pa2o=
github.com/x-way/crawlerdetect v0.2.32 h1:kmYHC8lk5T91PDETQ3h9pF35GUyrdzmi3KX64jPvHt4=
github.com/x-way/crawlerdetect v0.2.32/go.mod h1:BPHLsB3FOuiwoWyhAvnqeiUSAEKd34O7BcsTCcxHRj4=
+golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
+golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=