├── .github ├── FUNDING.yml └── workflows │ └── go.yml ├── .gitignore ├── LICENSE ├── README.md ├── addr.go ├── addr_test.go ├── as.go ├── as_test.go ├── fqdn.go ├── fqdn_test.go ├── go.mod ├── go.sum ├── graph.go ├── netblock.go └── netblock_test.go /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [caffix] 2 | custom: ["https://www.buymeacoffee.com/caffix"] -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | 7 | jobs: 8 | test: 9 | name: Test 10 | strategy: 11 | matrix: 12 | os: [ "ubuntu-latest", "macos-latest", "windows-latest" ] 13 | go-version: [ "1.19" ] 14 | runs-on: ${{ matrix.os }} 15 | steps: 16 | - 17 | name: setup Go ${{ matrix.go-version }} 18 | uses: actions/setup-go@v3 19 | with: 20 | go-version: ${{ matrix.go-version }} 21 | - 22 | name: checkout 23 | uses: actions/checkout@v3 24 | - 25 | name: simple test 26 | run: go test -v 27 | - 28 | name: test with GC pressure 29 | run: go test -v 30 | env: 31 | GOGC: 1 32 | - 33 | name: test with race detector 34 | run: go test -v -race 35 | coverage: 36 | name: Coverage 37 | runs-on: ubuntu-latest 38 | steps: 39 | - name: setup Go 40 | uses: actions/setup-go@v3 41 | with: 42 | go-version: 1.19 43 | - name: checkout 44 | uses: actions/checkout@v3 45 | - name: measure coverage 46 | run: go test -v -coverprofile=coverage.out 47 | - name: report coverage 48 | run: | 49 | bash <(curl -s https://codecov.io/bash) 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # netmap 2 | 3 | ![GitHub Test Status](https://github.com/caffix/netmap/workflows/tests/badge.svg) 4 | [![GoDoc](https://img.shields.io/static/v1?label=godoc&message=reference&color=blue)](https://pkg.go.dev/github.com/caffix/netmap?tab=overview) 5 | [![License](https://img.shields.io/github/license/caffix/netmap)](https://www.apache.org/licenses/LICENSE-2.0) 6 | [![Go Report](https://goreportcard.com/badge/github.com/caffix/netmap)](https://goreportcard.com/report/github.com/caffix/netmap) 7 | [![CodeFactor](https://www.codefactor.io/repository/github/caffix/netmap/badge)](https://www.codefactor.io/repository/github/caffix/netmap) 8 | [![Codecov](https://codecov.io/gh/caffix/netmap/branch/master/graph/badge.svg)](https://codecov.io/gh/caffix/netmap) 9 | [![Follow on Twitter](https://img.shields.io/twitter/follow/jeff_foley.svg?logo=twitter)](https://twitter.com/jeff_foley) 10 | 11 | Graphing package for mapping and visualizing the Internet. 12 | 13 | ## Installation [![Go Version](https://img.shields.io/github/go-mod/go-version/caffix/netmap)](https://golang.org/dl/) 14 | 15 | ```bash 16 | go get -v -u github.com/caffix/netmap 17 | ``` 18 | 19 | This package is currently in development. -------------------------------------------------------------------------------- /addr.go: -------------------------------------------------------------------------------- 1 | // Copyright © by Jeff Foley 2017-2023. All rights reserved. 2 | // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package netmap 6 | 7 | import ( 8 | "context" 9 | "errors" 10 | "fmt" 11 | "net/netip" 12 | "strings" 13 | "time" 14 | 15 | "github.com/caffix/stringset" 16 | "github.com/owasp-amass/asset-db/types" 17 | "github.com/owasp-amass/open-asset-model/domain" 18 | "github.com/owasp-amass/open-asset-model/network" 19 | ) 20 | 21 | // UpsertAddress creates an IP address in the graph. 22 | func (g *Graph) UpsertAddress(ctx context.Context, addr string) (*types.Asset, error) { 23 | ip, err := netip.ParseAddr(addr) 24 | if err != nil { 25 | return nil, err 26 | } 27 | 28 | var t string 29 | if ip.Is4() { 30 | t = "IPv4" 31 | } else if ip.Is6() { 32 | t = "IPv6" 33 | } else { 34 | return nil, fmt.Errorf("%s is not a valid IPv4 or IPv6 IP address", addr) 35 | } 36 | 37 | return g.DB.Create(nil, "", &network.IPAddress{ 38 | Address: ip, 39 | Type: t, 40 | }) 41 | } 42 | 43 | // NameAddrPair represents a relationship between a DNS name and an IP address it eventually resolves to. 44 | type NameAddrPair struct { 45 | FQDN *domain.FQDN 46 | Addr *network.IPAddress 47 | } 48 | 49 | // NamesToAddrs returns a NameAddrPair for each name / address combination discovered in the graph. 50 | func (g *Graph) NamesToAddrs(ctx context.Context, since time.Time, names ...string) ([]*NameAddrPair, error) { 51 | nameAddrMap := make(map[string]*stringset.Set, len(names)) 52 | defer func() { 53 | for _, ss := range nameAddrMap { 54 | ss.Close() 55 | } 56 | }() 57 | 58 | remaining := stringset.New() 59 | defer remaining.Close() 60 | remaining.InsertMany(names...) 61 | 62 | from := "(relations inner join assets on relations.from_asset_id = assets.id)" 63 | where := "where assets.type = 'FQDN' and relations.type in ('a_record','aaaa_record') " 64 | likeset := "and assets.content->>'name' in ('" + strings.Join(remaining.Slice(), "','") + "')" 65 | query := from + where + likeset 66 | if !since.IsZero() { 67 | query += " and relations.last_seen > " + since.Format("2006-01-02 15:04:05") 68 | } 69 | 70 | rels, err := g.DB.RelationQuery(query) 71 | if err != nil { 72 | return nil, err 73 | } else if len(rels) == 0 { 74 | return nil, errors.New("no names to query") 75 | } 76 | 77 | for _, rel := range rels { 78 | if f, ok := rel.FromAsset.Asset.(*domain.FQDN); ok { 79 | remaining.Remove(f.Name) 80 | 81 | if _, found := nameAddrMap[f.Name]; !found { 82 | nameAddrMap[f.Name] = stringset.New() 83 | } 84 | if a, ok := rel.ToAsset.Asset.(*network.IPAddress); ok { 85 | nameAddrMap[f.Name].Insert(a.Address.String()) 86 | } 87 | } 88 | } 89 | 90 | // Get to the end of the CNAME alias chains 91 | for _, name := range remaining.Slice() { 92 | var results []struct { 93 | Name string 94 | Addr string 95 | } 96 | 97 | if err := g.DB.RawQuery(cnameQuery(name, since), &results); err == nil && len(results) > 0 { 98 | remaining.Remove(name) 99 | 100 | for _, res := range results { 101 | if _, found := nameAddrMap[name]; !found { 102 | nameAddrMap[name] = stringset.New() 103 | } 104 | nameAddrMap[name].Insert(res.Addr) 105 | } 106 | } 107 | } 108 | 109 | query = `SELECT fqdns.content->>'name',ips.content->>'name' FROM (((( 110 | assets AS fqdns INNER JOIN relations AS r1 ON fqdns.id = r1.from_asset_id) 111 | INNER JOIN assets AS srvs ON r1.to_asset_id = srvs.id) 112 | INNER JOIN relations AS r2 ON srvs.id = r2.from_asset_id) 113 | INNER JOIN assets AS ips ON r2.to_asset_id = ips.id) 114 | WHERE fqdns.type = 'FQDN' AND srvs.type = 'FQDN' AND ips.type = 'IPAddress' 115 | AND r1.type = 'srv_record' AND r2.type IN ('a_record', 'aaaa_record')` 116 | if !since.IsZero() { 117 | query += " AND r1.last_seen > " + since.Format("2006-01-02 15:04:05") + 118 | " AND r2.last_seen > " + since.Format("2006-01-02 15:04:05") 119 | } 120 | query += " AND fqdns.content->>'name' in ('" + strings.Join(remaining.Slice(), "','") + "')" 121 | 122 | var results []struct { 123 | Name string 124 | Addr string 125 | } 126 | // Get to the IPs associated with SRV records 127 | if err := g.DB.RawQuery(query, &results); err == nil && len(results) > 0 { 128 | for _, res := range results { 129 | remaining.Remove(res.Name) 130 | if _, found := nameAddrMap[res.Name]; !found { 131 | nameAddrMap[res.Name] = stringset.New() 132 | } 133 | nameAddrMap[res.Name].Insert(res.Addr) 134 | } 135 | } 136 | 137 | if len(nameAddrMap) == 0 { 138 | return nil, errors.New("no pairs to process") 139 | } 140 | 141 | pairs := generatePairsFromAddrMap(nameAddrMap) 142 | if len(pairs) == 0 { 143 | return nil, errors.New("no addresses were discovered") 144 | } 145 | return pairs, nil 146 | } 147 | 148 | func cnameQuery(name string, since time.Time) string { 149 | query := `WITH RECURSIVE 150 | traverse_cname(fqdn) AS ( 151 | VALUES('` + name + `') 152 | UNION 153 | SELECT cnames.content->>'name' FROM ((assets AS fqdns 154 | INNER JOIN relations ON fqdns.id = relations.from_asset_id) 155 | INNER JOIN assets AS cnames ON relations.to_asset_id = cnames.id), traverse_cname 156 | WHERE fqdns.type = 'FQDN' AND cnames.type = 'FQDN'` 157 | if !since.IsZero() { 158 | query += " and relations.last_seen > " + since.Format("2006-01-02 15:04:05") 159 | } 160 | query += ` AND relations.type = 'cname_record' AND fqdns.content->>'name' = traverse_cname.fqdn 161 | ) 162 | SELECT fqdns.content->>'name', ips.content->>'address' FROM ((assets AS fqdns 163 | INNER JOIN relations ON fqdns.id = relations.from_asset_id) 164 | INNER JOIN assets AS ips ON relations.to_asset_id = ips.id) 165 | WHERE fqdns.type = 'FQDN' AND ips.type = 'IPAddress'` 166 | if !since.IsZero() { 167 | query += " and relations.last_seen > " + since.Format("2006-01-02 15:04:05") 168 | } 169 | return query + ` AND relations.type IN ('a_record', 'aaaa_record') AND fqdns.content->>'name' IN traverse_cname` 170 | } 171 | 172 | func generatePairsFromAddrMap(addrMap map[string]*stringset.Set) []*NameAddrPair { 173 | var pairs []*NameAddrPair 174 | 175 | for name, set := range addrMap { 176 | for _, addr := range set.Slice() { 177 | if ip, err := netip.ParseAddr(addr); err == nil { 178 | address := &network.IPAddress{Address: ip} 179 | if ip.Is4() { 180 | address.Type = "IPv4" 181 | } else if ip.Is6() { 182 | address.Type = "IPv6" 183 | } 184 | pairs = append(pairs, &NameAddrPair{ 185 | FQDN: &domain.FQDN{Name: name}, 186 | Addr: address, 187 | }) 188 | } 189 | } 190 | } 191 | return pairs 192 | } 193 | 194 | // UpsertA creates FQDN, IP address and A record edge in the graph and associates them with a source and event. 195 | func (g *Graph) UpsertA(ctx context.Context, fqdn, addr string) error { 196 | return g.addrRecord(ctx, fqdn, addr, "a_record") 197 | } 198 | 199 | // UpsertAAAA creates FQDN, IP address and AAAA record edge in the graph and associates them with a source and event. 200 | func (g *Graph) UpsertAAAA(ctx context.Context, fqdn, addr string) error { 201 | return g.addrRecord(ctx, fqdn, addr, "aaaa_record") 202 | } 203 | 204 | func (g *Graph) addrRecord(ctx context.Context, fqdn, addr, rrtype string) error { 205 | name, err := g.UpsertFQDN(ctx, fqdn) 206 | if err != nil { 207 | return err 208 | } 209 | 210 | ip, err := g.UpsertAddress(ctx, addr) 211 | if err != nil { 212 | return err 213 | } 214 | 215 | _, err = g.DB.Create(name, rrtype, ip.Asset) 216 | return err 217 | } 218 | -------------------------------------------------------------------------------- /addr_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © by Jeff Foley 2017-2023. All rights reserved. 2 | // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package netmap 6 | 7 | import ( 8 | "context" 9 | "testing" 10 | "time" 11 | 12 | "github.com/owasp-amass/open-asset-model/network" 13 | ) 14 | 15 | func TestAddress(t *testing.T) { 16 | g := NewGraph("memory", "", "") 17 | defer g.Remove() 18 | 19 | t.Run("Testing UpsertAddress...", func(t *testing.T) { 20 | want := "192.168.1.1" 21 | 22 | if got, err := g.UpsertAddress(context.Background(), want); err != nil { 23 | t.Errorf("error inserting address:%v\n", err) 24 | } else if a, ok := got.Asset.(*network.IPAddress); !ok || a.Address.String() != want { 25 | t.Error("IP address was not returned properly") 26 | } 27 | }) 28 | 29 | t.Run("Testing UpsertA...", func(t *testing.T) { 30 | err := g.UpsertA(context.Background(), "owasp.org", "192.168.1.1") 31 | if err != nil { 32 | t.Errorf("error inserting fqdn: %v", err) 33 | } 34 | }) 35 | 36 | t.Run("Testing UpsertAAAA...", func(t *testing.T) { 37 | err := g.UpsertAAAA(context.Background(), "owasp.org", "2001:0db8:85a3:0000:0000:8a2e:0370:7334") 38 | 39 | if err != nil { 40 | t.Errorf("error inserting AAAA record: %v", err) 41 | } 42 | }) 43 | } 44 | 45 | func TestNameToAddrs(t *testing.T) { 46 | fqdn := "caffix.net" 47 | addr := "192.168.1.1" 48 | 49 | g := NewGraph("memory", "", "") 50 | defer g.Remove() 51 | 52 | ctx := context.Background() 53 | if _, err := g.NamesToAddrs(ctx, time.Time{}, fqdn); err == nil { 54 | t.Errorf("did not return an error when provided parameters not existing in the graph") 55 | } 56 | 57 | _ = g.UpsertA(ctx, fqdn, addr) 58 | if pairs, err := g.NamesToAddrs(ctx, time.Time{}, fqdn); err != nil || len(pairs) == 0 || 59 | pairs[0].FQDN.Name != fqdn || pairs[0].Addr.Address.String() != addr { 60 | t.Errorf("failed to obtain the name / address pairs: %v", err) 61 | } 62 | 63 | if pairs, err := g.NamesToAddrs(ctx, time.Time{}, "doesnot.exist"); err == nil { 64 | t.Errorf("did not return an error when provided a name not existing in the graph: %v", pairs) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /as.go: -------------------------------------------------------------------------------- 1 | // Copyright © by Jeff Foley 2017-2023. All rights reserved. 2 | // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package netmap 6 | 7 | import ( 8 | "context" 9 | "time" 10 | 11 | "github.com/owasp-amass/asset-db/types" 12 | "github.com/owasp-amass/open-asset-model/network" 13 | ) 14 | 15 | // UpsertAS adds/updates an autonomous system in the graph. 16 | func (g *Graph) UpsertAS(ctx context.Context, asn int, desc string) (*types.Asset, error) { 17 | 18 | a, err := g.DB.Create(nil, "", &network.AutonomousSystem{Number: asn}) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | _, err = g.DB.Create(a, "managed_by", &network.RIROrganization{Name: desc}) 24 | return a, err 25 | } 26 | 27 | // UpsertInfrastructure adds/updates an associated IP address, netblock and autonomous system in the graph. 28 | func (g *Graph) UpsertInfrastructure(ctx context.Context, asn int, desc, addr, cidr string) error { 29 | ip, err := g.UpsertAddress(ctx, addr) 30 | if err != nil { 31 | return err 32 | } 33 | 34 | netblock, err := g.UpsertNetblock(ctx, cidr) 35 | if err != nil { 36 | return err 37 | } 38 | // Create the edge between the CIDR and the address 39 | if _, err := g.DB.Create(netblock, "contains", ip.Asset); err != nil { 40 | return err 41 | } 42 | 43 | as, err := g.UpsertAS(ctx, asn, desc) 44 | if err != nil { 45 | return err 46 | } 47 | // Create the edge between the AS and the netblock 48 | if _, err := g.DB.Create(as, "announces", netblock.Asset); err != nil { 49 | return err 50 | } 51 | return nil 52 | } 53 | 54 | // ReadASDescription the description property of an autonomous system in the graph. 55 | func (g *Graph) ReadASDescription(ctx context.Context, asn int, since time.Time) string { 56 | assets, err := g.DB.FindByContent(&network.AutonomousSystem{Number: asn}, since) 57 | if err != nil || len(assets) == 0 { 58 | return "" 59 | } 60 | 61 | if rels, err := g.DB.OutgoingRelations(assets[0], since, "managed_by"); err == nil && len(rels) > 0 { 62 | a, err := g.DB.FindById(rels[0].ToAsset.ID, since) 63 | if err != nil { 64 | return "" 65 | } else if rir, ok := a.Asset.(*network.RIROrganization); ok { 66 | return rir.Name 67 | } 68 | } 69 | 70 | return "" 71 | } 72 | 73 | func (g *Graph) ReadASPrefixes(ctx context.Context, asn int, since time.Time) []string { 74 | var prefixes []string 75 | 76 | assets, err := g.DB.FindByContent(&network.AutonomousSystem{Number: asn}, since) 77 | if err != nil || len(assets) == 0 { 78 | return prefixes 79 | } 80 | 81 | if rels, err := g.DB.OutgoingRelations(assets[0], since, "announces"); err == nil && len(rels) > 0 { 82 | for _, rel := range rels { 83 | if a, err := g.DB.FindById(rel.ToAsset.ID, since); err != nil { 84 | continue 85 | } else if netblock, ok := a.Asset.(*network.Netblock); ok { 86 | prefixes = append(prefixes, netblock.Cidr.String()) 87 | } 88 | } 89 | } 90 | return prefixes 91 | } 92 | -------------------------------------------------------------------------------- /as_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © by Jeff Foley 2017-2023. All rights reserved. 2 | // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package netmap 6 | 7 | import ( 8 | "context" 9 | "testing" 10 | "time" 11 | 12 | "github.com/owasp-amass/open-asset-model/network" 13 | ) 14 | 15 | func TestAS(t *testing.T) { 16 | g := NewGraph("memory", "", "") 17 | defer g.Remove() 18 | 19 | asn := 667 20 | newdesc := "Great AS" 21 | cidr := "10.0.0.0/8" 22 | addr := "10.0.0.1" 23 | 24 | t.Run("Testing UpsertAS...", func(t *testing.T) { 25 | got, err := g.UpsertAS(context.Background(), asn, newdesc) 26 | if err != nil { 27 | t.Errorf("error inserting AS: %v\n", err) 28 | } 29 | 30 | if as, ok := got.Asset.(*network.AutonomousSystem); !ok { 31 | t.Error("failed to read the inserted autonomous system") 32 | } else if as.Number != asn { 33 | t.Errorf("returned value for InsertAS is not the same as the test asn value. got: %d, want: %d", as.Number, asn) 34 | } 35 | }) 36 | 37 | t.Run("Testing UpsertInfrastructure", func(t *testing.T) { 38 | err := g.UpsertInfrastructure(context.Background(), asn, newdesc, addr, cidr) 39 | if err != nil { 40 | t.Errorf("error inserting infrastructure: %v", err) 41 | } 42 | }) 43 | 44 | t.Run("Testing ReadASDescription", func(t *testing.T) { 45 | got := g.ReadASDescription(context.Background(), asn, time.Time{}) 46 | 47 | if got != newdesc { 48 | t.Errorf("expected: %v, got: %v", newdesc, got) 49 | } 50 | }) 51 | 52 | t.Run("Testing ReadASPrefixes", func(t *testing.T) { 53 | got := g.ReadASPrefixes(context.Background(), asn, time.Time{}) 54 | 55 | if len(got) != 1 || got[0] != cidr { 56 | t.Errorf("expected: %v, got: %v\n", cidr, got) 57 | } 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /fqdn.go: -------------------------------------------------------------------------------- 1 | // Copyright © by Jeff Foley 2017-2023. All rights reserved. 2 | // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package netmap 6 | 7 | import ( 8 | "context" 9 | "time" 10 | 11 | "github.com/owasp-amass/asset-db/types" 12 | "github.com/owasp-amass/open-asset-model/domain" 13 | "golang.org/x/net/publicsuffix" 14 | ) 15 | 16 | // UpsertFQDN adds a fully qualified domain name to the graph. 17 | func (g *Graph) UpsertFQDN(ctx context.Context, name string) (*types.Asset, error) { 18 | d, err := publicsuffix.EffectiveTLDPlusOne(name) 19 | if err != nil { 20 | return nil, err 21 | } 22 | _, _ = g.DB.Create(nil, "", &domain.FQDN{Name: d}) 23 | 24 | return g.DB.Create(nil, "", &domain.FQDN{Name: name}) 25 | } 26 | 27 | // UpsertCNAME adds the FQDNs and CNAME record between them to the graph. 28 | func (g *Graph) UpsertCNAME(ctx context.Context, fqdn, target string) error { 29 | return g.insertAlias(ctx, fqdn, target, "cname_record") 30 | } 31 | 32 | // IsCNAMENode returns true if the FQDN has a CNAME edge to another FQDN in the graph. 33 | func (g *Graph) IsCNAMENode(ctx context.Context, fqdn string, since time.Time) bool { 34 | return g.checkForOutEdge(ctx, fqdn, "cname_record", since) 35 | } 36 | 37 | func (g *Graph) insertAlias(ctx context.Context, fqdn, target, relation string) error { 38 | fAsset, err := g.UpsertFQDN(ctx, fqdn) 39 | if err != nil { 40 | return err 41 | } 42 | 43 | tAsset, err := g.UpsertFQDN(ctx, target) 44 | if err != nil { 45 | return err 46 | } 47 | 48 | _, err = g.DB.Create(fAsset, relation, tAsset.Asset) 49 | return err 50 | } 51 | 52 | // UpsertPTR adds the FQDNs and PTR record between them to the graph. 53 | func (g *Graph) UpsertPTR(ctx context.Context, fqdn, target string) error { 54 | return g.insertAlias(ctx, fqdn, target, "ptr_record") 55 | } 56 | 57 | // IsPTRNode returns true if the FQDN has a PTR edge to another FQDN in the graph. 58 | func (g *Graph) IsPTRNode(ctx context.Context, fqdn string, since time.Time) bool { 59 | return g.checkForOutEdge(ctx, fqdn, "ptr_record", since) 60 | } 61 | 62 | // UpsertSRV adds the FQDNs and SRV record between them to the graph. 63 | func (g *Graph) UpsertSRV(ctx context.Context, service, target string) error { 64 | return g.insertAlias(ctx, service, target, "srv_record") 65 | } 66 | 67 | // UpsertNS adds the FQDNs and NS record between them to the graph. 68 | func (g *Graph) UpsertNS(ctx context.Context, fqdn, target string) error { 69 | return g.insertAlias(ctx, fqdn, target, "ns_record") 70 | } 71 | 72 | // IsNSNode returns true if the FQDN has a NS edge pointing to it in the graph. 73 | func (g *Graph) IsNSNode(ctx context.Context, fqdn string, since time.Time) bool { 74 | return g.checkForInEdge(ctx, fqdn, "ns_record", since) 75 | } 76 | 77 | // UpsertMX adds the FQDNs and MX record between them to the graph. 78 | func (g *Graph) UpsertMX(ctx context.Context, fqdn, target string) error { 79 | return g.insertAlias(ctx, fqdn, target, "mx_record") 80 | } 81 | 82 | // IsMXNode returns true if the FQDN has a MX edge pointing to it in the graph. 83 | func (g *Graph) IsMXNode(ctx context.Context, fqdn string, since time.Time) bool { 84 | return g.checkForInEdge(ctx, fqdn, "mx_record", since) 85 | } 86 | 87 | func (g *Graph) checkForInEdge(ctx context.Context, id, relation string, since time.Time) bool { 88 | if assets, err := g.DB.FindByContent(&domain.FQDN{Name: id}, since); err == nil { 89 | for _, a := range assets { 90 | if fqdn, ok := a.Asset.(*domain.FQDN); ok && fqdn.Name == id { 91 | if rels, err := g.DB.IncomingRelations(a, since, relation); err == nil && len(rels) > 0 { 92 | return true 93 | } 94 | break 95 | } 96 | } 97 | } 98 | return false 99 | } 100 | 101 | func (g *Graph) checkForOutEdge(ctx context.Context, id, relation string, since time.Time) bool { 102 | if assets, err := g.DB.FindByContent(&domain.FQDN{Name: id}, since); err == nil { 103 | for _, a := range assets { 104 | if fqdn, ok := a.Asset.(*domain.FQDN); ok && fqdn.Name == id { 105 | if rels, err := g.DB.OutgoingRelations(a, since, relation); err == nil && len(rels) > 0 { 106 | return true 107 | } 108 | break 109 | } 110 | } 111 | } 112 | return false 113 | } 114 | -------------------------------------------------------------------------------- /fqdn_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © by Jeff Foley 2017-2023. All rights reserved. 2 | // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package netmap 6 | 7 | import ( 8 | "context" 9 | "testing" 10 | "time" 11 | 12 | "github.com/owasp-amass/open-asset-model/domain" 13 | ) 14 | 15 | func TestFQDN(t *testing.T) { 16 | g := NewGraph("memory", "", "") 17 | defer g.Remove() 18 | 19 | name := "owasp.org" 20 | ctx := context.Background() 21 | service := "testservice.com" 22 | t.Run("Testing UpsertFQDN...", func(t *testing.T) { 23 | if a, err := g.UpsertFQDN(ctx, name); err != nil { 24 | t.Errorf("failed inserting FQDN: %v", err) 25 | } else if fqdn, ok := a.Asset.(*domain.FQDN); !ok || fqdn.Name != name { 26 | t.Error("error expecting FQDN") 27 | } 28 | }) 29 | 30 | t.Run("Testing UpsertCNAME...", func(t *testing.T) { 31 | if err := g.UpsertCNAME(ctx, name, name); err != nil { 32 | t.Errorf("failed inserting CNAME: %v", err) 33 | } 34 | }) 35 | 36 | t.Run("Testing IsCNAMENode...", func(t *testing.T) { 37 | if !g.IsCNAMENode(ctx, name, time.Time{}) { 38 | t.Error("failed to obtain CNAME from node") 39 | } 40 | }) 41 | 42 | t.Run("Testing UpsertPTR...", func(t *testing.T) { 43 | if err := g.UpsertPTR(ctx, name, name); err != nil { 44 | t.Errorf("failed to InsertPTR: %v", err) 45 | } 46 | }) 47 | 48 | t.Run("Testing IsPTRNode...", func(t *testing.T) { 49 | if !g.IsPTRNode(ctx, name, time.Time{}) { 50 | t.Errorf("failed to find PTRNode: %s", name) 51 | } 52 | }) 53 | 54 | t.Run("Testing UpsertSRV...", func(t *testing.T) { 55 | if err := g.UpsertSRV(ctx, service, name); err != nil { 56 | t.Errorf("failed inserting service into database: %v", err) 57 | } 58 | }) 59 | 60 | t.Run("Testing UpsertNS...", func(t *testing.T) { 61 | if err := g.UpsertNS(ctx, name, name); err != nil { 62 | t.Errorf("failed inserting NS record: %v", err) 63 | } 64 | }) 65 | 66 | t.Run("Testing IsNSNode...", func(t *testing.T) { 67 | if !g.IsNSNode(ctx, name, time.Time{}) { 68 | t.Error("failed to locate NS node") 69 | } 70 | }) 71 | 72 | t.Run("Testing UpsertMX...", func(t *testing.T) { 73 | if err := g.UpsertMX(ctx, name, name); err != nil { 74 | t.Errorf("failure to insert MX record: %v", err) 75 | } 76 | }) 77 | 78 | t.Run("Testing IsMXNode...", func(t *testing.T) { 79 | if !g.IsMXNode(ctx, name, time.Time{}) { 80 | t.Errorf("failed to locate MX node") 81 | } 82 | }) 83 | } 84 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/caffix/netmap 2 | 3 | go 1.21 4 | 5 | toolchain go1.21.4 6 | 7 | require ( 8 | github.com/caffix/stringset v0.1.2 9 | github.com/glebarez/sqlite v1.10.0 10 | github.com/owasp-amass/asset-db v0.3.6-0.20240115064351-93bd10b2e248 11 | github.com/owasp-amass/open-asset-model v0.2.1-0.20240113165517-79f7a07407c7 12 | github.com/rubenv/sql-migrate v1.6.0 13 | golang.org/x/net v0.20.0 14 | gorm.io/driver/postgres v1.5.4 15 | gorm.io/gorm v1.25.5 16 | ) 17 | 18 | require ( 19 | github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect 20 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 21 | github.com/dgraph-io/badger v1.6.2 // indirect 22 | github.com/dgraph-io/ristretto v0.1.1 // indirect 23 | github.com/dustin/go-humanize v1.0.1 // indirect 24 | github.com/glebarez/go-sqlite v1.22.0 // indirect 25 | github.com/go-gorp/gorp/v3 v3.1.0 // indirect 26 | github.com/go-sql-driver/mysql v1.7.1 // indirect 27 | github.com/golang/glog v1.2.0 // indirect 28 | github.com/golang/protobuf v1.5.3 // indirect 29 | github.com/google/uuid v1.5.0 // indirect 30 | github.com/jackc/pgpassfile v1.0.0 // indirect 31 | github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect 32 | github.com/jackc/pgx/v5 v5.5.2 // indirect 33 | github.com/jackc/puddle/v2 v2.2.1 // indirect 34 | github.com/jinzhu/inflection v1.0.0 // indirect 35 | github.com/jinzhu/now v1.1.5 // indirect 36 | github.com/mattn/go-isatty v0.0.20 // indirect 37 | github.com/mattn/go-sqlite3 v1.14.19 // indirect 38 | github.com/pkg/errors v0.9.1 // indirect 39 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect 40 | golang.org/x/crypto v0.18.0 // indirect 41 | golang.org/x/sync v0.6.0 // indirect 42 | golang.org/x/sys v0.16.0 // indirect 43 | golang.org/x/text v0.14.0 // indirect 44 | google.golang.org/protobuf v1.32.0 // indirect 45 | gorm.io/datatypes v1.2.0 // indirect 46 | gorm.io/driver/mysql v1.5.2 // indirect 47 | gorm.io/driver/sqlite v1.5.4 // indirect 48 | modernc.org/libc v1.40.2 // indirect 49 | modernc.org/mathutil v1.6.0 // indirect 50 | modernc.org/memory v1.7.2 // indirect 51 | modernc.org/sqlite v1.28.0 // indirect 52 | ) 53 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= 2 | github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= 3 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 4 | github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= 5 | github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= 6 | github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= 7 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 8 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 9 | github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 10 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 11 | github.com/caffix/stringset v0.1.1 h1:Tm4b7SBFAsRTBbBX90eP8xBv6BxSuU2w+6G/JNXtNpg= 12 | github.com/caffix/stringset v0.1.1/go.mod h1:9Ztc521vlcp8IWdtIowZyWbbddMKR9Rdr+d0pgnjcvk= 13 | github.com/caffix/stringset v0.1.2 h1:AnBiZ5dH8AqOtDsUPdFt7ZzHk5RqmGixmfZFlxzZh4U= 14 | github.com/caffix/stringset v0.1.2/go.mod h1:eWeJ1l/1Tc3SO5eybwwMIltkoPNkej2y5d4sHQlHOxw= 15 | github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= 16 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 17 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 18 | github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= 19 | github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 20 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 21 | github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 22 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 23 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 24 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 25 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 26 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 27 | github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= 28 | github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= 29 | github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= 30 | github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= 31 | github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= 32 | github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= 33 | github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= 34 | github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= 35 | github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 36 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 37 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 38 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 39 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 40 | github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= 41 | github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= 42 | github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= 43 | github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= 44 | github.com/glebarez/sqlite v1.9.0 h1:Aj6bPA12ZEx5GbSF6XADmCkYXlljPNUY+Zf1EQxynXs= 45 | github.com/glebarez/sqlite v1.9.0/go.mod h1:YBYCoyupOao60lzp1MVBLEjZfgkq0tdB1voAQ09K9zw= 46 | github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc= 47 | github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA= 48 | github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= 49 | github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= 50 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 51 | github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= 52 | github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= 53 | github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= 54 | github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= 55 | github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs= 56 | github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= 57 | github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY= 58 | github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY= 59 | github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc= 60 | github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE= 61 | github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= 62 | github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= 63 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 64 | github.com/golang/glog v1.1.1 h1:jxpi2eWoU84wbX9iIEyAeeoac3FLuifZpY9tcNUD9kw= 65 | github.com/golang/glog v1.1.1/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= 66 | github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= 67 | github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= 68 | github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= 69 | github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= 70 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 71 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 72 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 73 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 74 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 75 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 76 | github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= 77 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 78 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 79 | github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= 80 | github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 81 | github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= 82 | github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 83 | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 84 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= 85 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 86 | github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= 87 | github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= 88 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 89 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 90 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 91 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= 92 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= 93 | github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= 94 | github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= 95 | github.com/jackc/pgx/v5 v5.4.2 h1:u1gmGDwbdRUZiwisBm/Ky2M14uQyUP65bG8+20nnyrg= 96 | github.com/jackc/pgx/v5 v5.4.2/go.mod h1:q6iHT8uDNXWiFNOlRqJzBTaSH3+2xCXkokxHZC5qWFY= 97 | github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= 98 | github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= 99 | github.com/jackc/pgx/v5 v5.5.2 h1:iLlpgp4Cp/gC9Xuscl7lFL1PhhW+ZLtXZcrfCt4C3tA= 100 | github.com/jackc/pgx/v5 v5.5.2/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= 101 | github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= 102 | github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= 103 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 104 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 105 | github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= 106 | github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 107 | github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= 108 | github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= 109 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 110 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 111 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 112 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 113 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 114 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 115 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 116 | github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= 117 | github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 118 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 119 | github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= 120 | github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= 121 | github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= 122 | github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= 123 | github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= 124 | github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= 125 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 126 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= 127 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 128 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 129 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 130 | github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= 131 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 132 | github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= 133 | github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= 134 | github.com/mattn/go-sqlite3 v1.14.19/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= 135 | github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= 136 | github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4= 137 | github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= 138 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 139 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 140 | github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 141 | github.com/nelsam/hel/v2 v2.3.3/go.mod h1:1ZTGfU2PFTOd5mx22i5O0Lc2GY933lQ2wb/ggy+rL3w= 142 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 143 | github.com/owasp-amass/asset-db v0.3.1 h1:YNM60WYr2k6bJmgju7zrKs5dHfvs7BUg0pewhERk49E= 144 | github.com/owasp-amass/asset-db v0.3.1/go.mod h1:ylDCIg2bFmQChSdjr8rJAdVFX/XAHECSedMM9fiCW7w= 145 | github.com/owasp-amass/asset-db v0.3.3 h1:M+JckW/TJV9piOKP8gTpTCm4J5jJ0XHJxaK/FWGgX0M= 146 | github.com/owasp-amass/asset-db v0.3.3/go.mod h1:0dIY3OAQaoAG+dVOE8f57r61WgGJx1bvnn9DV4l6K8c= 147 | github.com/owasp-amass/asset-db v0.3.6-0.20240115064351-93bd10b2e248 h1:MkNSdxiht8KCEtdPgDYkMJ2Gz0kAaqr0qZnyiJ/cyq4= 148 | github.com/owasp-amass/asset-db v0.3.6-0.20240115064351-93bd10b2e248/go.mod h1:OkERYUKyC17AJTwJe9mH7vU5EfTwv7jLfyBLnV34Otw= 149 | github.com/owasp-amass/open-asset-model v0.1.0-alpha.0.20230622033932-2f80ca929692 h1:s5k5cTCRbVbIoRIwA44oWB4j/GGaYrmq1H3yqX1ic5A= 150 | github.com/owasp-amass/open-asset-model v0.1.0-alpha.0.20230622033932-2f80ca929692/go.mod h1:nwviDUc6sKkHScZFwXeNJNP2M4pgMTvB7we5r+EfNSk= 151 | github.com/owasp-amass/open-asset-model v0.2.0 h1:wkuFKOjYL6G0kIBbHDFGXAAxq3UlnVVp1iG+tFODPTg= 152 | github.com/owasp-amass/open-asset-model v0.2.0/go.mod h1:nwviDUc6sKkHScZFwXeNJNP2M4pgMTvB7we5r+EfNSk= 153 | github.com/owasp-amass/open-asset-model v0.2.1-0.20240113165517-79f7a07407c7 h1:AlftpLOnwYLCUGiqoWEfQ1LAZ0AjfcL5IWF21miRQdI= 154 | github.com/owasp-amass/open-asset-model v0.2.1-0.20240113165517-79f7a07407c7/go.mod h1:DOX+SiD6PZBroSMnsILAmpf0SHi6TVpqjV4uNfBeg7g= 155 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 156 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 157 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 158 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 159 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 160 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 161 | github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= 162 | github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= 163 | github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= 164 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= 165 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 166 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 167 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 168 | github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0= 169 | github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= 170 | github.com/rubenv/sql-migrate v1.6.0 h1:IZpcTlAx/VKXphWEpwWJ7BaMq05tYtE80zYz+8a5Il8= 171 | github.com/rubenv/sql-migrate v1.6.0/go.mod h1:m3ilnKP7sNb4eYkLsp6cGdPOl4OBcXM6rcbzU+Oqc5k= 172 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 173 | github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 174 | github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= 175 | github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 176 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 177 | github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 178 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 179 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 180 | github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= 181 | github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= 182 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 183 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 184 | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 185 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 186 | github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= 187 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 188 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 189 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 190 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 191 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 192 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 193 | github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= 194 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 195 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 196 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 197 | golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= 198 | golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= 199 | golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= 200 | golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= 201 | golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= 202 | golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= 203 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 204 | golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= 205 | golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= 206 | golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= 207 | golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 208 | golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= 209 | golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= 210 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 211 | golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= 212 | golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 213 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 214 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 215 | golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 216 | golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 217 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 218 | golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= 219 | golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 220 | golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= 221 | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 222 | golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= 223 | golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 224 | golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c= 225 | golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= 226 | golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= 227 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 228 | golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= 229 | golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 230 | golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= 231 | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 232 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 233 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 234 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 235 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 236 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 237 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 238 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 239 | google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= 240 | google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 241 | google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= 242 | google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 243 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 244 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 245 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 246 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 247 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 248 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 249 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 250 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 251 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 252 | gorm.io/datatypes v1.2.0 h1:5YT+eokWdIxhJgWHdrb2zYUimyk0+TaFth+7a0ybzco= 253 | gorm.io/datatypes v1.2.0/go.mod h1:o1dh0ZvjIjhH/bngTpypG6lVRJ5chTBxE09FH/71k04= 254 | gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= 255 | gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= 256 | gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs= 257 | gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8= 258 | gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= 259 | gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= 260 | gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo= 261 | gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0= 262 | gorm.io/driver/sqlite v1.5.2 h1:TpQ+/dqCY4uCigCFyrfnrJnrW9zjpelWVoEVNy5qJkc= 263 | gorm.io/driver/sqlite v1.5.2/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4= 264 | gorm.io/driver/sqlite v1.5.4/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4= 265 | gorm.io/driver/sqlserver v1.4.1 h1:t4r4r6Jam5E6ejqP7N82qAJIJAht27EGT41HyPfXRw0= 266 | gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= 267 | gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= 268 | gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho= 269 | gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= 270 | gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= 271 | gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= 272 | gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= 273 | gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= 274 | modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= 275 | modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= 276 | modernc.org/libc v1.40.2 h1:pzVHG9jwYZNWANfltHiU3HYfrzYIsX6ysRLJ93adZXA= 277 | modernc.org/libc v1.40.2/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE= 278 | modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= 279 | modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= 280 | modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= 281 | modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= 282 | modernc.org/memory v1.7.1 h1:9J+2/GKTlV503mk3yv8QJ6oEpRCUrRy0ad8TXEPoV8M= 283 | modernc.org/memory v1.7.1/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= 284 | modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= 285 | modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= 286 | modernc.org/sqlite v1.24.0 h1:EsClRIWHGhLTCX44p+Ri/JLD+vFGo0QGjasg2/F9TlI= 287 | modernc.org/sqlite v1.24.0/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= 288 | modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA= 289 | modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= 290 | modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ= 291 | modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= 292 | -------------------------------------------------------------------------------- /graph.go: -------------------------------------------------------------------------------- 1 | // Copyright © by Jeff Foley 2017-2023. All rights reserved. 2 | // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package netmap 6 | 7 | import ( 8 | "embed" 9 | "fmt" 10 | "math/rand" 11 | "os" 12 | 13 | "github.com/glebarez/sqlite" 14 | db "github.com/owasp-amass/asset-db" 15 | pgmigrations "github.com/owasp-amass/asset-db/migrations/postgres" 16 | sqlitemigrations "github.com/owasp-amass/asset-db/migrations/sqlite3" 17 | "github.com/owasp-amass/asset-db/repository" 18 | migrate "github.com/rubenv/sql-migrate" 19 | "gorm.io/driver/postgres" 20 | "gorm.io/gorm" 21 | ) 22 | 23 | // Graph is the object for managing a network infrastructure link graph. 24 | type Graph struct { 25 | DB *db.AssetDB 26 | dsn string 27 | dbtype repository.DBType 28 | } 29 | 30 | // NewGraph returns an intialized Graph object. 31 | func NewGraph(system, path string, options string) *Graph { 32 | var dsn string 33 | var dbtype repository.DBType 34 | 35 | switch system { 36 | case "memory": 37 | dbtype = repository.SQLite 38 | dsn = fmt.Sprintf("file:sqlite%d?mode=memory&cache=shared", rand.Int31n(100)) 39 | case "local": 40 | dbtype = repository.SQLite 41 | dsn = path 42 | case "postgres": 43 | dbtype = repository.Postgres 44 | dsn = path 45 | default: 46 | return nil 47 | } 48 | 49 | store := db.New(dbtype, dsn) 50 | if store == nil { 51 | return nil 52 | } 53 | 54 | g := &Graph{ 55 | DB: store, 56 | dsn: dsn, 57 | dbtype: dbtype, 58 | } 59 | 60 | var name string 61 | var fs embed.FS 62 | var database gorm.Dialector 63 | switch dbtype { 64 | case repository.SQLite: 65 | name = "sqlite3" 66 | fs = sqlitemigrations.Migrations() 67 | database = sqlite.Open(g.dsn) 68 | case repository.Postgres: 69 | name = "postgres" 70 | fs = pgmigrations.Migrations() 71 | database = postgres.Open(g.dsn) 72 | } 73 | 74 | sql, err := gorm.Open(database, &gorm.Config{}) 75 | if err != nil { 76 | return nil 77 | } 78 | 79 | migrationsSource := migrate.EmbedFileSystemMigrationSource{ 80 | FileSystem: fs, 81 | Root: "/", 82 | } 83 | 84 | sqlDb, err := sql.DB() 85 | if err != nil { 86 | panic(err) 87 | } 88 | 89 | _, err = migrate.Exec(sqlDb, name, migrationsSource, migrate.Up) 90 | if err != nil { 91 | panic(err) 92 | } 93 | return g 94 | } 95 | 96 | func (g *Graph) Remove() { 97 | switch g.dbtype { 98 | case repository.SQLite: 99 | os.Remove(g.dsn) 100 | case repository.Postgres: 101 | teardownPostgres(g.dsn) 102 | } 103 | } 104 | 105 | func teardownPostgres(dsn string) { 106 | db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) 107 | if err != nil { 108 | panic(err) 109 | } 110 | 111 | migrationsSource := migrate.EmbedFileSystemMigrationSource{ 112 | FileSystem: pgmigrations.Migrations(), 113 | Root: "/", 114 | } 115 | 116 | sqlDb, err := db.DB() 117 | if err != nil { 118 | panic(err) 119 | } 120 | 121 | _, err = migrate.Exec(sqlDb, "postgres", migrationsSource, migrate.Down) 122 | if err != nil { 123 | panic(err) 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /netblock.go: -------------------------------------------------------------------------------- 1 | // Copyright © by Jeff Foley 2017-2023. All rights reserved. 2 | // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package netmap 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "net/netip" 11 | 12 | "github.com/owasp-amass/asset-db/types" 13 | "github.com/owasp-amass/open-asset-model/network" 14 | ) 15 | 16 | // UpsertNetblock adds a netblock/CIDR to the graph. 17 | func (g *Graph) UpsertNetblock(ctx context.Context, cidr string) (*types.Asset, error) { 18 | prefix, err := netip.ParsePrefix(cidr) 19 | if err != nil { 20 | return nil, err 21 | } 22 | 23 | var t string 24 | ip := prefix.Addr() 25 | if ip.Is4() { 26 | t = "IPv4" 27 | } else if ip.Is6() { 28 | t = "IPv6" 29 | } else { 30 | return nil, fmt.Errorf("%s is not a valid IPv4 or IPv6 IP address", ip.String()) 31 | } 32 | 33 | return g.DB.Create(nil, "", &network.Netblock{ 34 | Cidr: prefix, 35 | Type: t, 36 | }) 37 | } 38 | -------------------------------------------------------------------------------- /netblock_test.go: -------------------------------------------------------------------------------- 1 | // Copyright © by Jeff Foley 2017-2023. All rights reserved. 2 | // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | package netmap 6 | 7 | import ( 8 | "context" 9 | "testing" 10 | 11 | "github.com/owasp-amass/open-asset-model/network" 12 | ) 13 | 14 | func TestNetblock(t *testing.T) { 15 | g := NewGraph("memory", "", "") 16 | defer g.Remove() 17 | 18 | t.Run("Testing UpsertNetblock...", func(t *testing.T) { 19 | a, err := g.UpsertNetblock(context.Background(), "10.0.0.0/8") 20 | if err != nil { 21 | t.Errorf("error inserting netblock: %v", err) 22 | } 23 | 24 | if netblock, ok := a.Asset.(*network.Netblock); !ok || netblock.Cidr.String() != "10.0.0.0/8" { 25 | t.Error("insert returned an invalid netblock") 26 | } 27 | }) 28 | } 29 | --------------------------------------------------------------------------------