diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index f567a677ef..333405234a 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -93,5 +93,6 @@ VNIC Vtpm vulnerabilityassessmentsettings vulnmgmt +whois wil xssmatchstatement diff --git a/go.mod b/go.mod index e0b83dab0e..adab686ae7 100644 --- a/go.mod +++ b/go.mod @@ -417,7 +417,11 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) -require github.com/moby/buildkit v0.13.2 +require ( + github.com/likexian/whois v1.15.3 + github.com/likexian/whois-parser v1.24.16 + github.com/moby/buildkit v0.13.2 +) require ( cloud.google.com/go/auth v0.5.0 // indirect @@ -440,6 +444,7 @@ require ( github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect github.com/lasiar/canonicalheader v1.1.1 // indirect + github.com/likexian/gokit v0.25.15 // indirect github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect github.com/smarty/assertions v1.15.1 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect diff --git a/go.sum b/go.sum index a851730e96..4f93ae68d6 100644 --- a/go.sum +++ b/go.sum @@ -787,6 +787,12 @@ github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSio github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= +github.com/likexian/gokit v0.25.15 h1:QjospM1eXhdMMHwZRpMKKAHY/Wig9wgcREmLtf9NslY= +github.com/likexian/gokit v0.25.15/go.mod h1:S2QisdsxLEHWeD/XI0QMVeggp+jbxYqUxMvSBil7MRg= +github.com/likexian/whois v1.15.3 h1:0emFSUSUj98Q12Wer3iM3eROPXjg+CyUBlibGPNbKHw= +github.com/likexian/whois v1.15.3/go.mod h1:a6sGAAKEb+O3JRBuW2x/QDM80l5hJ07p0+SjQkJ1c+0= +github.com/likexian/whois-parser v1.24.16 h1:WdHt6ICtapm/2M2ue84n541nHDbNBD7M8HsxgXKcEV8= +github.com/likexian/whois-parser v1.24.16/go.mod h1:k5zmKRZ7xPg1TLv3BGT4g/LOPRIMhvdNMeB0F53V/jk= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= diff --git a/providers/github/go.mod b/providers/github/go.mod index 4460f2abdf..39011f98e7 100644 --- a/providers/github/go.mod +++ b/providers/github/go.mod @@ -241,6 +241,9 @@ require ( github.com/ldez/gomoddirectives v0.2.4 // indirect github.com/ldez/tagliatelle v0.5.0 // indirect github.com/leonklingele/grouper v1.1.2 // indirect + github.com/likexian/gokit v0.25.15 // indirect + github.com/likexian/whois v1.15.3 // indirect + github.com/likexian/whois-parser v1.24.16 // indirect github.com/lithammer/fuzzysearch v1.1.8 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lufeee/execinquery v1.2.1 // indirect diff --git a/providers/github/go.sum b/providers/github/go.sum index 012acb38a9..d16b95b8b0 100644 --- a/providers/github/go.sum +++ b/providers/github/go.sum @@ -766,6 +766,12 @@ github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSio github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= +github.com/likexian/gokit v0.25.15 h1:QjospM1eXhdMMHwZRpMKKAHY/Wig9wgcREmLtf9NslY= +github.com/likexian/gokit v0.25.15/go.mod h1:S2QisdsxLEHWeD/XI0QMVeggp+jbxYqUxMvSBil7MRg= +github.com/likexian/whois v1.15.3 h1:0emFSUSUj98Q12Wer3iM3eROPXjg+CyUBlibGPNbKHw= +github.com/likexian/whois v1.15.3/go.mod h1:a6sGAAKEb+O3JRBuW2x/QDM80l5hJ07p0+SjQkJ1c+0= +github.com/likexian/whois-parser v1.24.16 h1:WdHt6ICtapm/2M2ue84n541nHDbNBD7M8HsxgXKcEV8= +github.com/likexian/whois-parser v1.24.16/go.mod h1:k5zmKRZ7xPg1TLv3BGT4g/LOPRIMhvdNMeB0F53V/jk= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= diff --git a/providers/google-workspace/go.mod b/providers/google-workspace/go.mod index 9eedae9e7a..942a720664 100644 --- a/providers/google-workspace/go.mod +++ b/providers/google-workspace/go.mod @@ -232,6 +232,9 @@ require ( github.com/ldez/gomoddirectives v0.2.4 // indirect github.com/ldez/tagliatelle v0.5.0 // indirect github.com/leonklingele/grouper v1.1.2 // indirect + github.com/likexian/gokit v0.25.15 // indirect + github.com/likexian/whois v1.15.3 // indirect + github.com/likexian/whois-parser v1.24.16 // indirect github.com/lithammer/fuzzysearch v1.1.8 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lufeee/execinquery v1.2.1 // indirect diff --git a/providers/google-workspace/go.sum b/providers/google-workspace/go.sum index 4277b13701..2ec14c6ebc 100644 --- a/providers/google-workspace/go.sum +++ b/providers/google-workspace/go.sum @@ -756,6 +756,12 @@ github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSio github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= +github.com/likexian/gokit v0.25.15 h1:QjospM1eXhdMMHwZRpMKKAHY/Wig9wgcREmLtf9NslY= +github.com/likexian/gokit v0.25.15/go.mod h1:S2QisdsxLEHWeD/XI0QMVeggp+jbxYqUxMvSBil7MRg= +github.com/likexian/whois v1.15.3 h1:0emFSUSUj98Q12Wer3iM3eROPXjg+CyUBlibGPNbKHw= +github.com/likexian/whois v1.15.3/go.mod h1:a6sGAAKEb+O3JRBuW2x/QDM80l5hJ07p0+SjQkJ1c+0= +github.com/likexian/whois-parser v1.24.16 h1:WdHt6ICtapm/2M2ue84n541nHDbNBD7M8HsxgXKcEV8= +github.com/likexian/whois-parser v1.24.16/go.mod h1:k5zmKRZ7xPg1TLv3BGT4g/LOPRIMhvdNMeB0F53V/jk= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= diff --git a/providers/k8s/go.mod b/providers/k8s/go.mod index b5c5716a0d..31d8fb2586 100644 --- a/providers/k8s/go.mod +++ b/providers/k8s/go.mod @@ -263,6 +263,9 @@ require ( github.com/ldez/gomoddirectives v0.2.4 // indirect github.com/ldez/tagliatelle v0.5.0 // indirect github.com/leonklingele/grouper v1.1.2 // indirect + github.com/likexian/gokit v0.25.15 // indirect + github.com/likexian/whois v1.15.3 // indirect + github.com/likexian/whois-parser v1.24.16 // indirect github.com/lithammer/fuzzysearch v1.1.8 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lufeee/execinquery v1.2.1 // indirect diff --git a/providers/k8s/go.sum b/providers/k8s/go.sum index edeb02bc6c..cd908d71a7 100644 --- a/providers/k8s/go.sum +++ b/providers/k8s/go.sum @@ -775,6 +775,12 @@ github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSio github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= +github.com/likexian/gokit v0.25.15 h1:QjospM1eXhdMMHwZRpMKKAHY/Wig9wgcREmLtf9NslY= +github.com/likexian/gokit v0.25.15/go.mod h1:S2QisdsxLEHWeD/XI0QMVeggp+jbxYqUxMvSBil7MRg= +github.com/likexian/whois v1.15.3 h1:0emFSUSUj98Q12Wer3iM3eROPXjg+CyUBlibGPNbKHw= +github.com/likexian/whois v1.15.3/go.mod h1:a6sGAAKEb+O3JRBuW2x/QDM80l5hJ07p0+SjQkJ1c+0= +github.com/likexian/whois-parser v1.24.16 h1:WdHt6ICtapm/2M2ue84n541nHDbNBD7M8HsxgXKcEV8= +github.com/likexian/whois-parser v1.24.16/go.mod h1:k5zmKRZ7xPg1TLv3BGT4g/LOPRIMhvdNMeB0F53V/jk= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= diff --git a/providers/network/resources/network.lr b/providers/network/resources/network.lr index e94e21e178..982d72c046 100644 --- a/providers/network/resources/network.lr +++ b/providers/network/resources/network.lr @@ -402,3 +402,72 @@ dns.dkimRecord @defaults("dnsTxt") { // Whether the DKIM entry and public key is valid valid() bool } + +// Domain and IP whois information +whois { + init(target string) + // Host, either registered name or IP (e.g., mondoo.com) + host string + // Domain whois information + domain() whois.domainInfo + // Registrar whois information + registrar() whois.contact + // Registrant whois information + registrant() whois.contact + // Admin whois information + administrative() whois.contact + // Tech whois information + technical() whois.contact + // Billing whois information + billing() whois.contact +} + +// Whois domain information +private whois.domainInfo @defaults("domain extension status") { + // Domain name + domain string + // Name + name string + // Punycode representation of the domain + punyCode string + // Domain extension + extension string + // Used whois server + whoisServer string + // Registration status + status []string + // Name servers + nameServers []string + // DNSSEC status + dnssec bool + // Creation date + createdAt time + // Updated date + updatedAt time + // Expiration date + expiresAt time +} + +// Whois contact information +private whois.contact @defaults("name") { + // Name + name string + // Organization + organization string + // Street + street string + // City + city string + // State or Province + province string + // Postal code + postalCode string + // Country + country string + // Phone number + phone string + // Email address + email string + // Registrar URL + registrarUrl string +} \ No newline at end of file diff --git a/providers/network/resources/network.lr.go b/providers/network/resources/network.lr.go index 08acfb3333..6b4235f023 100644 --- a/providers/network/resources/network.lr.go +++ b/providers/network/resources/network.lr.go @@ -118,6 +118,18 @@ func init() { // to override args, implement: initDnsDkimRecord(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) Create: createDnsDkimRecord, }, + "whois": { + Init: initWhois, + Create: createWhois, + }, + "whois.domainInfo": { + // to override args, implement: initWhoisDomainInfo(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) + Create: createWhoisDomainInfo, + }, + "whois.contact": { + // to override args, implement: initWhoisContact(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) + Create: createWhoisContact, + }, } } @@ -636,6 +648,90 @@ var getDataFields = map[string]func(r plugin.Resource) *plugin.DataRes{ "dns.dkimRecord.valid": func(r plugin.Resource) *plugin.DataRes { return (r.(*mqlDnsDkimRecord).GetValid()).ToDataRes(types.Bool) }, + "whois.host": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhois).GetHost()).ToDataRes(types.String) + }, + "whois.domain": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhois).GetDomain()).ToDataRes(types.Resource("whois.domainInfo")) + }, + "whois.registrar": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhois).GetRegistrar()).ToDataRes(types.Resource("whois.contact")) + }, + "whois.registrant": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhois).GetRegistrant()).ToDataRes(types.Resource("whois.contact")) + }, + "whois.administrative": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhois).GetAdministrative()).ToDataRes(types.Resource("whois.contact")) + }, + "whois.technical": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhois).GetTechnical()).ToDataRes(types.Resource("whois.contact")) + }, + "whois.billing": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhois).GetBilling()).ToDataRes(types.Resource("whois.contact")) + }, + "whois.domainInfo.domain": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisDomainInfo).GetDomain()).ToDataRes(types.String) + }, + "whois.domainInfo.name": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisDomainInfo).GetName()).ToDataRes(types.String) + }, + "whois.domainInfo.punyCode": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisDomainInfo).GetPunyCode()).ToDataRes(types.String) + }, + "whois.domainInfo.extension": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisDomainInfo).GetExtension()).ToDataRes(types.String) + }, + "whois.domainInfo.whoisServer": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisDomainInfo).GetWhoisServer()).ToDataRes(types.String) + }, + "whois.domainInfo.status": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisDomainInfo).GetStatus()).ToDataRes(types.Array(types.String)) + }, + "whois.domainInfo.nameServers": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisDomainInfo).GetNameServers()).ToDataRes(types.Array(types.String)) + }, + "whois.domainInfo.dnssec": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisDomainInfo).GetDnssec()).ToDataRes(types.Bool) + }, + "whois.domainInfo.createdAt": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisDomainInfo).GetCreatedAt()).ToDataRes(types.Time) + }, + "whois.domainInfo.updatedAt": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisDomainInfo).GetUpdatedAt()).ToDataRes(types.Time) + }, + "whois.domainInfo.expiresAt": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisDomainInfo).GetExpiresAt()).ToDataRes(types.Time) + }, + "whois.contact.name": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisContact).GetName()).ToDataRes(types.String) + }, + "whois.contact.organization": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisContact).GetOrganization()).ToDataRes(types.String) + }, + "whois.contact.street": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisContact).GetStreet()).ToDataRes(types.String) + }, + "whois.contact.city": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisContact).GetCity()).ToDataRes(types.String) + }, + "whois.contact.province": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisContact).GetProvince()).ToDataRes(types.String) + }, + "whois.contact.postalCode": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisContact).GetPostalCode()).ToDataRes(types.String) + }, + "whois.contact.country": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisContact).GetCountry()).ToDataRes(types.String) + }, + "whois.contact.phone": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisContact).GetPhone()).ToDataRes(types.String) + }, + "whois.contact.email": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisContact).GetEmail()).ToDataRes(types.String) + }, + "whois.contact.registrarUrl": func(r plugin.Resource) *plugin.DataRes { + return (r.(*mqlWhoisContact).GetRegistrarUrl()).ToDataRes(types.String) + }, } func GetData(resource plugin.Resource, field string, args map[string]*llx.RawData) *plugin.DataRes { @@ -1348,6 +1444,130 @@ var setDataFields = map[string]func(r plugin.Resource, v *llx.RawData) bool { r.(*mqlDnsDkimRecord).Valid, ok = plugin.RawToTValue[bool](v.Value, v.Error) return }, + "whois.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhois).__id, ok = v.Value.(string) + return + }, + "whois.host": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhois).Host, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.domain": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhois).Domain, ok = plugin.RawToTValue[*mqlWhoisDomainInfo](v.Value, v.Error) + return + }, + "whois.registrar": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhois).Registrar, ok = plugin.RawToTValue[*mqlWhoisContact](v.Value, v.Error) + return + }, + "whois.registrant": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhois).Registrant, ok = plugin.RawToTValue[*mqlWhoisContact](v.Value, v.Error) + return + }, + "whois.administrative": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhois).Administrative, ok = plugin.RawToTValue[*mqlWhoisContact](v.Value, v.Error) + return + }, + "whois.technical": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhois).Technical, ok = plugin.RawToTValue[*mqlWhoisContact](v.Value, v.Error) + return + }, + "whois.billing": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhois).Billing, ok = plugin.RawToTValue[*mqlWhoisContact](v.Value, v.Error) + return + }, + "whois.domainInfo.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisDomainInfo).__id, ok = v.Value.(string) + return + }, + "whois.domainInfo.domain": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisDomainInfo).Domain, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.domainInfo.name": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisDomainInfo).Name, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.domainInfo.punyCode": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisDomainInfo).PunyCode, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.domainInfo.extension": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisDomainInfo).Extension, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.domainInfo.whoisServer": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisDomainInfo).WhoisServer, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.domainInfo.status": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisDomainInfo).Status, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "whois.domainInfo.nameServers": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisDomainInfo).NameServers, ok = plugin.RawToTValue[[]interface{}](v.Value, v.Error) + return + }, + "whois.domainInfo.dnssec": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisDomainInfo).Dnssec, ok = plugin.RawToTValue[bool](v.Value, v.Error) + return + }, + "whois.domainInfo.createdAt": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisDomainInfo).CreatedAt, ok = plugin.RawToTValue[*time.Time](v.Value, v.Error) + return + }, + "whois.domainInfo.updatedAt": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisDomainInfo).UpdatedAt, ok = plugin.RawToTValue[*time.Time](v.Value, v.Error) + return + }, + "whois.domainInfo.expiresAt": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisDomainInfo).ExpiresAt, ok = plugin.RawToTValue[*time.Time](v.Value, v.Error) + return + }, + "whois.contact.__id": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisContact).__id, ok = v.Value.(string) + return + }, + "whois.contact.name": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisContact).Name, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.contact.organization": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisContact).Organization, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.contact.street": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisContact).Street, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.contact.city": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisContact).City, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.contact.province": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisContact).Province, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.contact.postalCode": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisContact).PostalCode, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.contact.country": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisContact).Country, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.contact.phone": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisContact).Phone, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.contact.email": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisContact).Email, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, + "whois.contact.registrarUrl": func(r plugin.Resource, v *llx.RawData) (ok bool) { + r.(*mqlWhoisContact).RegistrarUrl, ok = plugin.RawToTValue[string](v.Value, v.Error) + return + }, } func SetData(resource plugin.Resource, field string, val *llx.RawData) error { @@ -3565,3 +3785,337 @@ func (c *mqlDnsDkimRecord) GetValid() *plugin.TValue[bool] { return c.valid() }) } + +// mqlWhois for the whois resource +type mqlWhois struct { + MqlRuntime *plugin.Runtime + __id string + // optional: if you define mqlWhoisInternal it will be used here + Host plugin.TValue[string] + Domain plugin.TValue[*mqlWhoisDomainInfo] + Registrar plugin.TValue[*mqlWhoisContact] + Registrant plugin.TValue[*mqlWhoisContact] + Administrative plugin.TValue[*mqlWhoisContact] + Technical plugin.TValue[*mqlWhoisContact] + Billing plugin.TValue[*mqlWhoisContact] +} + +// createWhois creates a new instance of this resource +func createWhois(runtime *plugin.Runtime, args map[string]*llx.RawData) (plugin.Resource, error) { + res := &mqlWhois{ + MqlRuntime: runtime, + } + + err := SetAllData(res, args) + if err != nil { + return res, err + } + + if res.__id == "" { + res.__id, err = res.id() + if err != nil { + return nil, err + } + } + + if runtime.HasRecording { + args, err = runtime.ResourceFromRecording("whois", res.__id) + if err != nil || args == nil { + return res, err + } + return res, SetAllData(res, args) + } + + return res, nil +} + +func (c *mqlWhois) MqlName() string { + return "whois" +} + +func (c *mqlWhois) MqlID() string { + return c.__id +} + +func (c *mqlWhois) GetHost() *plugin.TValue[string] { + return &c.Host +} + +func (c *mqlWhois) GetDomain() *plugin.TValue[*mqlWhoisDomainInfo] { + return plugin.GetOrCompute[*mqlWhoisDomainInfo](&c.Domain, func() (*mqlWhoisDomainInfo, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("whois", c.__id, "domain") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.(*mqlWhoisDomainInfo), nil + } + } + + return c.domain() + }) +} + +func (c *mqlWhois) GetRegistrar() *plugin.TValue[*mqlWhoisContact] { + return plugin.GetOrCompute[*mqlWhoisContact](&c.Registrar, func() (*mqlWhoisContact, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("whois", c.__id, "registrar") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.(*mqlWhoisContact), nil + } + } + + return c.registrar() + }) +} + +func (c *mqlWhois) GetRegistrant() *plugin.TValue[*mqlWhoisContact] { + return plugin.GetOrCompute[*mqlWhoisContact](&c.Registrant, func() (*mqlWhoisContact, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("whois", c.__id, "registrant") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.(*mqlWhoisContact), nil + } + } + + return c.registrant() + }) +} + +func (c *mqlWhois) GetAdministrative() *plugin.TValue[*mqlWhoisContact] { + return plugin.GetOrCompute[*mqlWhoisContact](&c.Administrative, func() (*mqlWhoisContact, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("whois", c.__id, "administrative") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.(*mqlWhoisContact), nil + } + } + + return c.administrative() + }) +} + +func (c *mqlWhois) GetTechnical() *plugin.TValue[*mqlWhoisContact] { + return plugin.GetOrCompute[*mqlWhoisContact](&c.Technical, func() (*mqlWhoisContact, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("whois", c.__id, "technical") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.(*mqlWhoisContact), nil + } + } + + return c.technical() + }) +} + +func (c *mqlWhois) GetBilling() *plugin.TValue[*mqlWhoisContact] { + return plugin.GetOrCompute[*mqlWhoisContact](&c.Billing, func() (*mqlWhoisContact, error) { + if c.MqlRuntime.HasRecording { + d, err := c.MqlRuntime.FieldResourceFromRecording("whois", c.__id, "billing") + if err != nil { + return nil, err + } + if d != nil { + return d.Value.(*mqlWhoisContact), nil + } + } + + return c.billing() + }) +} + +// mqlWhoisDomainInfo for the whois.domainInfo resource +type mqlWhoisDomainInfo struct { + MqlRuntime *plugin.Runtime + __id string + // optional: if you define mqlWhoisDomainInfoInternal it will be used here + Domain plugin.TValue[string] + Name plugin.TValue[string] + PunyCode plugin.TValue[string] + Extension plugin.TValue[string] + WhoisServer plugin.TValue[string] + Status plugin.TValue[[]interface{}] + NameServers plugin.TValue[[]interface{}] + Dnssec plugin.TValue[bool] + CreatedAt plugin.TValue[*time.Time] + UpdatedAt plugin.TValue[*time.Time] + ExpiresAt plugin.TValue[*time.Time] +} + +// createWhoisDomainInfo creates a new instance of this resource +func createWhoisDomainInfo(runtime *plugin.Runtime, args map[string]*llx.RawData) (plugin.Resource, error) { + res := &mqlWhoisDomainInfo{ + MqlRuntime: runtime, + } + + err := SetAllData(res, args) + if err != nil { + return res, err + } + + // to override __id implement: id() (string, error) + + if runtime.HasRecording { + args, err = runtime.ResourceFromRecording("whois.domainInfo", res.__id) + if err != nil || args == nil { + return res, err + } + return res, SetAllData(res, args) + } + + return res, nil +} + +func (c *mqlWhoisDomainInfo) MqlName() string { + return "whois.domainInfo" +} + +func (c *mqlWhoisDomainInfo) MqlID() string { + return c.__id +} + +func (c *mqlWhoisDomainInfo) GetDomain() *plugin.TValue[string] { + return &c.Domain +} + +func (c *mqlWhoisDomainInfo) GetName() *plugin.TValue[string] { + return &c.Name +} + +func (c *mqlWhoisDomainInfo) GetPunyCode() *plugin.TValue[string] { + return &c.PunyCode +} + +func (c *mqlWhoisDomainInfo) GetExtension() *plugin.TValue[string] { + return &c.Extension +} + +func (c *mqlWhoisDomainInfo) GetWhoisServer() *plugin.TValue[string] { + return &c.WhoisServer +} + +func (c *mqlWhoisDomainInfo) GetStatus() *plugin.TValue[[]interface{}] { + return &c.Status +} + +func (c *mqlWhoisDomainInfo) GetNameServers() *plugin.TValue[[]interface{}] { + return &c.NameServers +} + +func (c *mqlWhoisDomainInfo) GetDnssec() *plugin.TValue[bool] { + return &c.Dnssec +} + +func (c *mqlWhoisDomainInfo) GetCreatedAt() *plugin.TValue[*time.Time] { + return &c.CreatedAt +} + +func (c *mqlWhoisDomainInfo) GetUpdatedAt() *plugin.TValue[*time.Time] { + return &c.UpdatedAt +} + +func (c *mqlWhoisDomainInfo) GetExpiresAt() *plugin.TValue[*time.Time] { + return &c.ExpiresAt +} + +// mqlWhoisContact for the whois.contact resource +type mqlWhoisContact struct { + MqlRuntime *plugin.Runtime + __id string + // optional: if you define mqlWhoisContactInternal it will be used here + Name plugin.TValue[string] + Organization plugin.TValue[string] + Street plugin.TValue[string] + City plugin.TValue[string] + Province plugin.TValue[string] + PostalCode plugin.TValue[string] + Country plugin.TValue[string] + Phone plugin.TValue[string] + Email plugin.TValue[string] + RegistrarUrl plugin.TValue[string] +} + +// createWhoisContact creates a new instance of this resource +func createWhoisContact(runtime *plugin.Runtime, args map[string]*llx.RawData) (plugin.Resource, error) { + res := &mqlWhoisContact{ + MqlRuntime: runtime, + } + + err := SetAllData(res, args) + if err != nil { + return res, err + } + + // to override __id implement: id() (string, error) + + if runtime.HasRecording { + args, err = runtime.ResourceFromRecording("whois.contact", res.__id) + if err != nil || args == nil { + return res, err + } + return res, SetAllData(res, args) + } + + return res, nil +} + +func (c *mqlWhoisContact) MqlName() string { + return "whois.contact" +} + +func (c *mqlWhoisContact) MqlID() string { + return c.__id +} + +func (c *mqlWhoisContact) GetName() *plugin.TValue[string] { + return &c.Name +} + +func (c *mqlWhoisContact) GetOrganization() *plugin.TValue[string] { + return &c.Organization +} + +func (c *mqlWhoisContact) GetStreet() *plugin.TValue[string] { + return &c.Street +} + +func (c *mqlWhoisContact) GetCity() *plugin.TValue[string] { + return &c.City +} + +func (c *mqlWhoisContact) GetProvince() *plugin.TValue[string] { + return &c.Province +} + +func (c *mqlWhoisContact) GetPostalCode() *plugin.TValue[string] { + return &c.PostalCode +} + +func (c *mqlWhoisContact) GetCountry() *plugin.TValue[string] { + return &c.Country +} + +func (c *mqlWhoisContact) GetPhone() *plugin.TValue[string] { + return &c.Phone +} + +func (c *mqlWhoisContact) GetEmail() *plugin.TValue[string] { + return &c.Email +} + +func (c *mqlWhoisContact) GetRegistrarUrl() *plugin.TValue[string] { + return &c.RegistrarUrl +} diff --git a/providers/network/resources/network.lr.manifest.yaml b/providers/network/resources/network.lr.manifest.yaml index 592b707068..78ecf7ecc8 100755 --- a/providers/network/resources/network.lr.manifest.yaml +++ b/providers/network/resources/network.lr.manifest.yaml @@ -260,3 +260,45 @@ resources: string: {} user: {} min_mondoo_version: 9.1.0 + whois: + fields: + admin: {} + administrative: {} + billing: {} + domain: {} + host: {} + registrant: {} + registrar: {} + target: {} + tech: {} + technical: {} + min_mondoo_version: 9.0.0 + whois.contact: + fields: + city: {} + country: {} + email: {} + name: {} + organization: {} + phone: {} + postalCode: {} + province: {} + registrarUrl: {} + street: {} + is_private: true + min_mondoo_version: 9.0.0 + whois.domainInfo: + fields: + createdAt: {} + dnssec: {} + domain: {} + expiresAt: {} + extension: {} + name: {} + nameServers: {} + punyCode: {} + status: {} + updatedAt: {} + whoisServer: {} + is_private: true + min_mondoo_version: 9.0.0 diff --git a/providers/network/resources/whois.go b/providers/network/resources/whois.go new file mode 100644 index 0000000000..7d42387138 --- /dev/null +++ b/providers/network/resources/whois.go @@ -0,0 +1,149 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package resources + +import ( + "github.com/likexian/whois" + whoisparser "github.com/likexian/whois-parser" + "go.mondoo.com/cnquery/v11/llx" + "go.mondoo.com/cnquery/v11/providers-sdk/v1/plugin" + "go.mondoo.com/cnquery/v11/providers-sdk/v1/util/convert" + "go.mondoo.com/cnquery/v11/providers/network/connection" + "go.mondoo.com/cnquery/v11/types" +) + +func initWhois(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) { + conn := runtime.Connection.(*connection.HostConnection) + host := conn.Conf.Host + if target, ok := args["target"]; ok { + host = target.Value.(string) + delete(args, "target") + } + + args["host"] = llx.StringData(host) + return args, nil, nil +} + +func (d *mqlWhois) id() (string, error) { + return "whois/" + d.Host.Data, nil +} + +func (d *mqlWhois) fetch() error { + host := d.Host.Data + + // set default values + d.Domain = plugin.TValue[*mqlWhoisDomainInfo]{Data: nil, Error: nil, State: plugin.StateIsSet | plugin.StateIsNull} + d.Registrar = plugin.TValue[*mqlWhoisContact]{Data: nil, Error: nil, State: plugin.StateIsSet | plugin.StateIsNull} + d.Registrant = plugin.TValue[*mqlWhoisContact]{Data: nil, Error: nil, State: plugin.StateIsSet | plugin.StateIsNull} + d.Administrative = plugin.TValue[*mqlWhoisContact]{Data: nil, Error: nil, State: plugin.StateIsSet | plugin.StateIsNull} + d.Technical = plugin.TValue[*mqlWhoisContact]{Data: nil, Error: nil, State: plugin.StateIsSet | plugin.StateIsNull} + d.Billing = plugin.TValue[*mqlWhoisContact]{Data: nil, Error: nil, State: plugin.StateIsSet | plugin.StateIsNull} + + // fetch whois data + rawWhoisResult, err := whois.Whois(host) + if err != nil { + return err + } + + result, err := whoisparser.Parse(rawWhoisResult) + if err != nil { + return err + } + + domainInfo, err := newMqlWhoisDomain(d.MqlRuntime, result.Domain) + if domainInfo != nil { + d.Domain = plugin.TValue[*mqlWhoisDomainInfo]{Data: domainInfo, Error: err, State: plugin.StateIsSet} + } + + registrar, err := newMqlWhoisContact(d.MqlRuntime, result.Registrar) + if registrar != nil { + d.Registrar = plugin.TValue[*mqlWhoisContact]{Data: registrar, Error: err, State: plugin.StateIsSet} + } + + registrant, err := newMqlWhoisContact(d.MqlRuntime, result.Registrant) + if registrant != nil { + d.Registrant = plugin.TValue[*mqlWhoisContact]{Data: registrant, Error: err, State: plugin.StateIsSet} + } + + administrative, err := newMqlWhoisContact(d.MqlRuntime, result.Administrative) + if administrative != nil { + d.Administrative = plugin.TValue[*mqlWhoisContact]{Data: administrative, Error: err, State: plugin.StateIsSet} + } + + technical, err := newMqlWhoisContact(d.MqlRuntime, result.Technical) + if technical != nil { + d.Technical = plugin.TValue[*mqlWhoisContact]{Data: technical, Error: err, State: plugin.StateIsSet} + } + + billing, err := newMqlWhoisContact(d.MqlRuntime, result.Billing) + if billing != nil { + d.Billing = plugin.TValue[*mqlWhoisContact]{Data: billing, Error: err, State: plugin.StateIsSet} + } + return nil +} + +func (d *mqlWhois) domain() (*mqlWhoisDomainInfo, error) { + return nil, d.fetch() +} + +func (d *mqlWhois) registrar() (*mqlWhoisContact, error) { + return nil, d.fetch() +} + +func (d *mqlWhois) registrant() (*mqlWhoisContact, error) { + return nil, d.fetch() +} + +func (d *mqlWhois) administrative() (*mqlWhoisContact, error) { + return nil, d.fetch() +} + +func (d *mqlWhois) technical() (*mqlWhoisContact, error) { + return nil, d.fetch() +} + +func (d *mqlWhois) billing() (*mqlWhoisContact, error) { + return nil, d.fetch() +} + +func newMqlWhoisDomain(runtime *plugin.Runtime, domain *whoisparser.Domain) (*mqlWhoisDomainInfo, error) { + if domain == nil { + return nil, nil + } + mqlDomainInfo, err := CreateResource(runtime, "whois.domainInfo", map[string]*llx.RawData{ + "__id": llx.StringData(domain.ID), + "domain": llx.StringData(domain.Domain), + "name": llx.StringData(domain.Name), + "punyCode": llx.StringData(domain.Punycode), + "extension": llx.StringData(domain.Extension), + "whoisServer": llx.StringData(domain.WhoisServer), + "status": llx.ArrayData(convert.SliceAnyToInterface(domain.Status), types.String), + "nameServers": llx.ArrayData(convert.SliceAnyToInterface(domain.NameServers), types.String), + "dnssec": llx.BoolData(domain.DNSSec), + "createdAt": llx.TimeDataPtr(domain.CreatedDateInTime), + "updatedAt": llx.TimeDataPtr(domain.UpdatedDateInTime), + "expiresAt": llx.TimeDataPtr(domain.ExpirationDateInTime), + }) + return mqlDomainInfo.(*mqlWhoisDomainInfo), err +} + +func newMqlWhoisContact(runtime *plugin.Runtime, contact *whoisparser.Contact) (*mqlWhoisContact, error) { + if contact == nil { + return nil, nil + } + mqlContact, err := CreateResource(runtime, "whois.contact", map[string]*llx.RawData{ + "__id": llx.StringData(contact.ID), + "name": llx.StringData(contact.Name), + "organization": llx.StringData(contact.Organization), + "street": llx.StringData(contact.Street), + "city": llx.StringData(contact.City), + "province": llx.StringData(contact.Province), + "postalCode": llx.StringData(contact.PostalCode), + "country": llx.StringData(contact.Country), + "phone": llx.StringData(contact.Phone), + "email": llx.StringData(contact.Email), + "registrarUrl": llx.StringData(contact.ReferralURL), + }) + return mqlContact.(*mqlWhoisContact), err +}