2024-08-15 08:38:28 +08:00
|
|
|
package whois
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
2026-03-19 11:53:07 +08:00
|
|
|
// ===== Specialized parsers kept from old parse.go =====
|
2024-08-16 21:30:27 +08:00
|
|
|
|
2024-08-15 08:38:28 +08:00
|
|
|
func dotCNParser(domain, data string) (Result, error) {
|
|
|
|
|
var res = Result{
|
|
|
|
|
domain: domain,
|
|
|
|
|
rawData: data,
|
|
|
|
|
}
|
|
|
|
|
var r PersonalInfo
|
2026-03-19 11:53:07 +08:00
|
|
|
|
|
|
|
|
trim := strings.TrimSpace(data)
|
|
|
|
|
if strings.HasPrefix(trim, "No matching record.") {
|
2024-08-15 08:38:28 +08:00
|
|
|
res.exists = false
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
2026-03-19 11:53:07 +08:00
|
|
|
if strings.HasPrefix(trim, "the Domain Name you apply can not be registered online") {
|
2024-08-16 21:30:27 +08:00
|
|
|
res.exists = false
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
2026-03-19 11:53:07 +08:00
|
|
|
|
2024-08-16 21:30:27 +08:00
|
|
|
res.hasUpdateDate = false
|
|
|
|
|
res.hasRegisterDate = true
|
|
|
|
|
res.hasExpireDate = true
|
2024-08-15 08:38:28 +08:00
|
|
|
res.exists = true
|
2024-08-15 15:10:18 +08:00
|
|
|
statusMap := make(map[string]struct{})
|
2024-08-15 08:38:28 +08:00
|
|
|
split := strings.Split(data, "\n")
|
|
|
|
|
for _, line := range split {
|
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
|
if strings.HasPrefix(line, "Domain Name:") {
|
|
|
|
|
res.nsServers = []string{}
|
|
|
|
|
res.domain = strings.TrimSpace(strings.TrimPrefix(line, "Domain Name:"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "ROID:") {
|
|
|
|
|
res.domainID = strings.TrimSpace(strings.TrimPrefix(line, "ROID:"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Registration Time:") {
|
|
|
|
|
res.registerDate = parseCNDate(strings.TrimSpace(strings.TrimPrefix(line, "Registration Time:")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Expiration Time:") {
|
|
|
|
|
res.expireDate = parseCNDate(strings.TrimSpace(strings.TrimPrefix(line, "Expiration Time:")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Sponsoring Registrar:") {
|
2026-03-19 11:53:07 +08:00
|
|
|
res.registrar = strings.TrimSpace(strings.TrimPrefix(line, "Sponsoring Registrar:"))
|
2024-08-15 08:38:28 +08:00
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Status:") {
|
2024-08-15 15:10:18 +08:00
|
|
|
statusMap[strings.Split(strings.TrimSpace(strings.TrimPrefix(line, "Status:")), " ")[0]] = struct{}{}
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Domain Status:") {
|
|
|
|
|
statusMap[strings.Split(strings.TrimSpace(strings.TrimPrefix(line, "Domain Status:")), " ")[0]] = struct{}{}
|
2024-08-15 08:38:28 +08:00
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Name Server:") {
|
|
|
|
|
res.nsServers = append(res.nsServers, strings.TrimSpace(strings.TrimPrefix(line, "Name Server:")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "DNSSEC:") {
|
|
|
|
|
res.dnssec = strings.TrimSpace(strings.TrimPrefix(line, "DNSSEC:"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Registrant:") {
|
|
|
|
|
r.Name = strings.TrimSpace(strings.TrimPrefix(line, "Registrant:"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Registrant Contact Email:") {
|
|
|
|
|
r.Email = strings.TrimSpace(strings.TrimPrefix(line, "Registrant Contact Email:"))
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-08-15 15:10:18 +08:00
|
|
|
for status := range statusMap {
|
|
|
|
|
res.statusRaw = append(res.statusRaw, status)
|
|
|
|
|
}
|
2024-08-15 08:38:28 +08:00
|
|
|
res.registerInfo = r
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func dotJPParser(domain, data string) (Result, error) {
|
|
|
|
|
var res = Result{
|
|
|
|
|
domain: domain,
|
|
|
|
|
rawData: data,
|
|
|
|
|
}
|
|
|
|
|
var r PersonalInfo
|
|
|
|
|
split := strings.Split(data, "\n")
|
|
|
|
|
startAddress := false
|
|
|
|
|
for _, line := range split {
|
|
|
|
|
if strings.HasPrefix(line, "No match!!") {
|
|
|
|
|
res.exists = false
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
|
if strings.HasPrefix(line, "[Domain Name]") {
|
2024-08-15 15:10:18 +08:00
|
|
|
res.exists = true
|
2024-08-16 21:30:27 +08:00
|
|
|
res.hasUpdateDate = true
|
|
|
|
|
res.hasRegisterDate = true
|
|
|
|
|
res.hasExpireDate = true
|
2024-08-15 08:38:28 +08:00
|
|
|
res.nsServers = []string{}
|
|
|
|
|
res.domain = strings.TrimSpace(strings.TrimPrefix(line, "[Domain Name]"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[登録者名]") {
|
|
|
|
|
r.Name = strings.TrimSpace(strings.TrimPrefix(line, "[登録者名]"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[Name Server]") {
|
|
|
|
|
res.nsServers = append(res.nsServers, strings.TrimSpace(strings.TrimPrefix(line, "[Name Server]")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[状態]") {
|
2024-08-15 15:10:18 +08:00
|
|
|
res.statusRaw = append(res.statusRaw, strings.TrimSpace(strings.TrimPrefix(line, "[状態]")))
|
2024-08-15 08:38:28 +08:00
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[ロック状態]") {
|
2024-08-15 15:10:18 +08:00
|
|
|
res.statusRaw = append(res.statusRaw, strings.TrimSpace(strings.TrimPrefix(line, "[ロック状態]")))
|
2024-08-15 08:38:28 +08:00
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[登録年月日]") {
|
|
|
|
|
res.registerDate = parseJPDate(strings.TrimSpace(strings.TrimPrefix(line, "[登録年月日]")), true)
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[最終更新]") {
|
|
|
|
|
res.updateDate = parseJPDate(strings.TrimSpace(strings.TrimPrefix(line, "[最終更新]")), false)
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[有効期限]") {
|
|
|
|
|
res.expireDate = parseJPDate(strings.TrimSpace(strings.TrimPrefix(line, "[有効期限]")), true)
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[名前]") {
|
|
|
|
|
r.Name = strings.TrimSpace(strings.TrimPrefix(line, "[名前]"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[組織名]") {
|
|
|
|
|
r.Org = strings.TrimSpace(strings.TrimPrefix(line, "[組織名]"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[Email]") {
|
|
|
|
|
r.Email = strings.TrimSpace(strings.TrimPrefix(line, "[Email]"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[住所]") {
|
|
|
|
|
r.Addr = strings.TrimSpace(strings.TrimPrefix(line, "[住所]"))
|
2026-03-19 11:53:07 +08:00
|
|
|
startAddress = true
|
2024-08-15 08:38:28 +08:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[Postal Address]") {
|
|
|
|
|
startAddress = false
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if startAddress {
|
|
|
|
|
r.Addr += "\n" + line
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[電話番号]") {
|
|
|
|
|
r.Phone = strings.TrimSpace(strings.TrimPrefix(line, "[電話番号]"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "[FAX番号]") {
|
|
|
|
|
r.Fax = strings.TrimSpace(strings.TrimPrefix(line, "[FAX番号]"))
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res.registerInfo = r
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func dotTWParser(domain, data string) (Result, error) {
|
|
|
|
|
var res = Result{
|
|
|
|
|
domain: domain,
|
|
|
|
|
rawData: data,
|
|
|
|
|
}
|
|
|
|
|
split := strings.Split(data, "\n")
|
|
|
|
|
startNs := false
|
|
|
|
|
var currentStatus uint8 = 0
|
|
|
|
|
var startIdx int
|
|
|
|
|
var r, a, t, p PersonalInfo
|
|
|
|
|
for idx, line := range split {
|
|
|
|
|
line = strings.TrimSpace(line)
|
2026-03-19 11:53:07 +08:00
|
|
|
if strings.HasPrefix(line, "No Found") || strings.HasPrefix(line, "網域名稱不合規定") || strings.Contains(strings.ToLower(line), "reserved name") {
|
2024-08-15 08:38:28 +08:00
|
|
|
res.exists = false
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Domain Name:") {
|
|
|
|
|
res.exists = true
|
2024-08-16 21:30:27 +08:00
|
|
|
res.hasUpdateDate = true
|
|
|
|
|
res.hasRegisterDate = true
|
|
|
|
|
res.hasExpireDate = true
|
2024-08-15 08:38:28 +08:00
|
|
|
res.nsServers = []string{}
|
|
|
|
|
res.domain = strings.TrimSpace(strings.TrimPrefix(line, "Domain Name:"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Registration Service Provider:") {
|
|
|
|
|
startNs = false
|
2026-03-19 11:53:07 +08:00
|
|
|
res.registrar = strings.TrimSpace(strings.TrimPrefix(line, "Registration Service Provider:"))
|
2024-08-15 08:38:28 +08:00
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Record created on") {
|
|
|
|
|
res.registerDate = parseCNDate(strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(line, "Record created on"), "(UTC+8)")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Record expires on") {
|
|
|
|
|
res.expireDate = parseCNDate(strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(line, "Record expires on"), "(UTC+8)")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Domain Status:") {
|
2024-08-15 15:10:18 +08:00
|
|
|
res.statusRaw = append(res.statusRaw, strings.TrimSpace(strings.TrimPrefix(line, "Domain Status:")))
|
2024-08-15 08:38:28 +08:00
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Domain servers in listed order:") {
|
|
|
|
|
startNs = true
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Registrant:") {
|
|
|
|
|
currentStatus = 1
|
|
|
|
|
startIdx = idx
|
|
|
|
|
p = PersonalInfo{}
|
|
|
|
|
continue
|
|
|
|
|
}
|
2026-03-19 11:53:07 +08:00
|
|
|
if strings.HasPrefix(line, "Administrative Contact:") {
|
|
|
|
|
currentStatus = 2
|
|
|
|
|
startIdx = idx
|
|
|
|
|
p = PersonalInfo{}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Technical Contact:") {
|
|
|
|
|
currentStatus = 3
|
|
|
|
|
startIdx = idx
|
|
|
|
|
p = PersonalInfo{}
|
|
|
|
|
continue
|
|
|
|
|
}
|
2024-08-15 08:38:28 +08:00
|
|
|
if currentStatus > 0 {
|
|
|
|
|
if line == "(Redacted for privacy)" {
|
|
|
|
|
switch currentStatus {
|
|
|
|
|
case 1:
|
|
|
|
|
r = p
|
|
|
|
|
case 2:
|
|
|
|
|
a = p
|
|
|
|
|
case 3:
|
|
|
|
|
t = p
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
switch idx - startIdx {
|
|
|
|
|
case 1:
|
|
|
|
|
p.Name = line
|
|
|
|
|
case 3:
|
|
|
|
|
p.Email = line
|
|
|
|
|
case 4:
|
|
|
|
|
p.Country = line
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-19 11:53:07 +08:00
|
|
|
if startNs && line != "" {
|
2024-08-15 08:38:28 +08:00
|
|
|
res.nsServers = append(res.nsServers, line)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res.registerInfo = r
|
|
|
|
|
res.adminInfo = a
|
|
|
|
|
res.techInfo = t
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-16 21:30:27 +08:00
|
|
|
func dotEduParser(domain, data string) (Result, error) {
|
|
|
|
|
var res = Result{
|
|
|
|
|
domain: domain,
|
|
|
|
|
rawData: data,
|
|
|
|
|
}
|
|
|
|
|
split := strings.Split(data, "\n")
|
|
|
|
|
startNs := false
|
|
|
|
|
var currentStatus uint8 = 0
|
|
|
|
|
var startIdx int
|
|
|
|
|
var r, a, t, p PersonalInfo
|
|
|
|
|
for idx, line := range split {
|
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
|
if startNs && len(line) == 0 {
|
|
|
|
|
startNs = false
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "NO MATCH:") {
|
|
|
|
|
res.exists = false
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Domain Name:") {
|
|
|
|
|
res.exists = true
|
|
|
|
|
res.hasUpdateDate = true
|
|
|
|
|
res.hasRegisterDate = true
|
|
|
|
|
res.hasExpireDate = true
|
|
|
|
|
res.nsServers = []string{}
|
|
|
|
|
res.domain = strings.TrimSpace(strings.TrimPrefix(line, "Domain Name:"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Domain record activated:") {
|
|
|
|
|
res.registerDate = parseEduDate(strings.TrimSpace(strings.TrimPrefix(line, "Domain record activated:")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Domain record last updated:") {
|
|
|
|
|
res.updateDate = parseEduDate(strings.TrimSpace(strings.TrimPrefix(line, "Domain record last updated:")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Domain expires:") {
|
|
|
|
|
res.expireDate = parseEduDate(strings.TrimSpace(strings.TrimPrefix(line, "Domain expires:")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Registrant:") {
|
|
|
|
|
currentStatus = 1
|
|
|
|
|
startIdx = idx
|
|
|
|
|
p = PersonalInfo{}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Administrative Contact:") {
|
|
|
|
|
currentStatus = 2
|
|
|
|
|
startIdx = idx
|
|
|
|
|
p = PersonalInfo{}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Technical Contact:") {
|
|
|
|
|
currentStatus = 3
|
|
|
|
|
startIdx = idx
|
|
|
|
|
p = PersonalInfo{}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Name Servers:") {
|
|
|
|
|
startNs = true
|
|
|
|
|
continue
|
|
|
|
|
}
|
2026-03-19 11:53:07 +08:00
|
|
|
if startNs && line != "" {
|
2024-08-16 21:30:27 +08:00
|
|
|
res.nsServers = append(res.nsServers, line)
|
|
|
|
|
}
|
|
|
|
|
if currentStatus > 0 {
|
|
|
|
|
switch idx - startIdx {
|
|
|
|
|
case 1:
|
|
|
|
|
p.Name = line
|
|
|
|
|
case 2, 3, 4, 5:
|
|
|
|
|
p.Addr += line
|
|
|
|
|
case 6:
|
|
|
|
|
p.Phone = line
|
|
|
|
|
case 7:
|
|
|
|
|
p.Email = line
|
|
|
|
|
}
|
|
|
|
|
if len(line) == 0 {
|
|
|
|
|
switch currentStatus {
|
|
|
|
|
case 1:
|
|
|
|
|
r = p
|
|
|
|
|
case 2:
|
|
|
|
|
a = p
|
|
|
|
|
case 3:
|
|
|
|
|
t = p
|
|
|
|
|
}
|
|
|
|
|
currentStatus = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res.registerInfo = r
|
|
|
|
|
res.adminInfo = a
|
|
|
|
|
res.techInfo = t
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func dotIntParser(domain, data string) (Result, error) {
|
|
|
|
|
var res = Result{
|
|
|
|
|
domain: domain,
|
|
|
|
|
rawData: data,
|
|
|
|
|
}
|
|
|
|
|
split := strings.Split(data, "\n")
|
|
|
|
|
var currentStatus uint8 = 0
|
|
|
|
|
var r, a, t, p PersonalInfo
|
|
|
|
|
for _, line := range split {
|
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
|
if strings.Contains(line, "but this server does not have") {
|
|
|
|
|
res.exists = false
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "domain:") {
|
|
|
|
|
res.exists = true
|
|
|
|
|
res.hasUpdateDate = true
|
|
|
|
|
res.hasRegisterDate = true
|
|
|
|
|
res.hasExpireDate = false
|
|
|
|
|
res.nsServers = []string{}
|
|
|
|
|
res.domain = strings.TrimSpace(strings.TrimPrefix(line, "domain:"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "created:") {
|
|
|
|
|
res.registerDate = parseYMDDate(strings.TrimSpace(strings.TrimPrefix(line, "created:")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "changed:") {
|
|
|
|
|
res.updateDate = parseYMDDate(strings.TrimSpace(strings.TrimPrefix(line, "changed:")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "organisation:") {
|
|
|
|
|
currentStatus = 1
|
|
|
|
|
p = PersonalInfo{
|
|
|
|
|
Org: strings.TrimSpace(strings.TrimPrefix(line, "organisation:")),
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "contact:") && strings.Contains(line, "administrative") {
|
|
|
|
|
currentStatus = 2
|
|
|
|
|
p = PersonalInfo{}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "contact:") && strings.Contains(line, "technical") {
|
|
|
|
|
currentStatus = 3
|
|
|
|
|
p = PersonalInfo{}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "nserver:") {
|
|
|
|
|
nsList := strings.Split(strings.TrimSpace(strings.TrimPrefix(line, "nserver:")), " ")
|
|
|
|
|
for idx, ns := range nsList {
|
|
|
|
|
if idx == 0 {
|
|
|
|
|
res.nsServers = append(res.nsServers, ns)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
res.nsIps = append(res.nsIps, ns)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if currentStatus > 0 {
|
|
|
|
|
if strings.HasPrefix(line, "address:") {
|
|
|
|
|
p.Addr += strings.TrimSpace(strings.TrimPrefix(line, "address:")) + "\n"
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "phone:") {
|
|
|
|
|
p.Phone = strings.TrimSpace(strings.TrimPrefix(line, "phone:"))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "e-mail:") {
|
|
|
|
|
p.Email = strings.TrimSpace(strings.TrimPrefix(line, "e-mail:"))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "fax-no:") {
|
|
|
|
|
p.Fax = strings.TrimSpace(strings.TrimPrefix(line, "fax-no:"))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if len(line) == 0 {
|
|
|
|
|
p.Addr = strings.TrimSpace(p.Addr)
|
|
|
|
|
switch currentStatus {
|
|
|
|
|
case 1:
|
|
|
|
|
r = p
|
|
|
|
|
case 2:
|
|
|
|
|
a = p
|
|
|
|
|
case 3:
|
|
|
|
|
t = p
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
res.registerInfo = r
|
|
|
|
|
res.adminInfo = a
|
|
|
|
|
res.techInfo = t
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func dotAmParser(domain, data string) (Result, error) {
|
|
|
|
|
var res = Result{
|
|
|
|
|
domain: domain,
|
|
|
|
|
rawData: data,
|
|
|
|
|
}
|
|
|
|
|
split := strings.Split(data, "\n")
|
|
|
|
|
var currentStatus uint8 = 0
|
|
|
|
|
statusMap := make(map[string]struct{})
|
|
|
|
|
var r, a, t, p PersonalInfo
|
|
|
|
|
startNs := false
|
|
|
|
|
var tmpSlice []string
|
|
|
|
|
for _, line := range split {
|
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
|
if strings.HasPrefix(line, "Status:") {
|
|
|
|
|
statusMap[strings.Split(strings.TrimSpace(strings.TrimPrefix(line, "Status:")), " ")[0]] = struct{}{}
|
|
|
|
|
}
|
|
|
|
|
if strings.Contains(line, "No match") {
|
|
|
|
|
res.exists = false
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Domain name:") {
|
|
|
|
|
res.exists = true
|
|
|
|
|
res.hasUpdateDate = true
|
|
|
|
|
res.hasRegisterDate = true
|
|
|
|
|
res.hasExpireDate = false
|
|
|
|
|
res.nsServers = []string{}
|
|
|
|
|
res.domain = strings.TrimSpace(strings.TrimPrefix(line, "Domain name:"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Registered:") {
|
|
|
|
|
res.registerDate = parseYMDDate(strings.TrimSpace(strings.TrimPrefix(line, "Registered:")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Last modified:") {
|
|
|
|
|
res.updateDate = parseYMDDate(strings.TrimSpace(strings.TrimPrefix(line, "Last modified:")))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Registrar:") {
|
2026-03-19 11:53:07 +08:00
|
|
|
res.registrar = strings.TrimSpace(strings.TrimPrefix(line, "Registrar:"))
|
2024-08-16 21:30:27 +08:00
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Registrant:") {
|
|
|
|
|
currentStatus = 1
|
|
|
|
|
p = PersonalInfo{}
|
2026-03-19 11:53:07 +08:00
|
|
|
tmpSlice = []string{}
|
2024-08-16 21:30:27 +08:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Administrative contact:") {
|
|
|
|
|
currentStatus = 2
|
|
|
|
|
p = PersonalInfo{}
|
2026-03-19 11:53:07 +08:00
|
|
|
tmpSlice = []string{}
|
2024-08-16 21:30:27 +08:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "Technical contact:") {
|
|
|
|
|
currentStatus = 3
|
|
|
|
|
p = PersonalInfo{}
|
2026-03-19 11:53:07 +08:00
|
|
|
tmpSlice = []string{}
|
2024-08-16 21:30:27 +08:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "DNS servers (") {
|
|
|
|
|
startNs = true
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if startNs {
|
|
|
|
|
tmp := strings.Split(line, "-")
|
|
|
|
|
for idx, ns := range tmp {
|
|
|
|
|
ns = strings.TrimSpace(ns)
|
2026-03-19 11:53:07 +08:00
|
|
|
if ns == "" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2024-08-16 21:30:27 +08:00
|
|
|
if idx == 0 {
|
|
|
|
|
res.nsServers = append(res.nsServers, ns)
|
2026-03-19 11:53:07 +08:00
|
|
|
} else {
|
|
|
|
|
res.nsIps = append(res.nsIps, ns)
|
2024-08-16 21:30:27 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if len(line) == 0 {
|
|
|
|
|
startNs = false
|
|
|
|
|
}
|
|
|
|
|
if currentStatus > 0 {
|
|
|
|
|
tmpSlice = append(tmpSlice, line)
|
|
|
|
|
if len(line) == 0 {
|
|
|
|
|
switch currentStatus {
|
|
|
|
|
case 1:
|
2026-03-19 11:53:07 +08:00
|
|
|
p.Addr = strings.TrimSpace(strings.Join(tmpSlice, "\n"))
|
2024-08-16 21:30:27 +08:00
|
|
|
r = p
|
|
|
|
|
case 2:
|
|
|
|
|
if len(tmpSlice) > 2 {
|
2026-03-19 11:53:07 +08:00
|
|
|
p.Addr = strings.TrimSpace(strings.Join(tmpSlice[:len(tmpSlice)-2], "\n"))
|
|
|
|
|
p.Email = strings.TrimSpace(tmpSlice[len(tmpSlice)-2])
|
|
|
|
|
p.Phone = strings.TrimSpace(tmpSlice[len(tmpSlice)-1])
|
2024-08-16 21:30:27 +08:00
|
|
|
} else {
|
2026-03-19 11:53:07 +08:00
|
|
|
p.Addr = strings.TrimSpace(strings.Join(tmpSlice, "\n"))
|
2024-08-16 21:30:27 +08:00
|
|
|
}
|
|
|
|
|
a = p
|
|
|
|
|
case 3:
|
|
|
|
|
if len(tmpSlice) > 2 {
|
2026-03-19 11:53:07 +08:00
|
|
|
p.Addr = strings.TrimSpace(strings.Join(tmpSlice[:len(tmpSlice)-2], "\n"))
|
|
|
|
|
p.Email = strings.TrimSpace(tmpSlice[len(tmpSlice)-2])
|
|
|
|
|
p.Phone = strings.TrimSpace(tmpSlice[len(tmpSlice)-1])
|
2024-08-16 21:30:27 +08:00
|
|
|
} else {
|
2026-03-19 11:53:07 +08:00
|
|
|
p.Addr = strings.TrimSpace(strings.Join(tmpSlice, "\n"))
|
2024-08-16 21:30:27 +08:00
|
|
|
}
|
|
|
|
|
t = p
|
|
|
|
|
}
|
2026-03-19 11:53:07 +08:00
|
|
|
tmpSlice = []string{}
|
2024-08-16 21:30:27 +08:00
|
|
|
currentStatus = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for status := range statusMap {
|
|
|
|
|
res.statusRaw = append(res.statusRaw, status)
|
|
|
|
|
}
|
|
|
|
|
res.registerInfo = r
|
|
|
|
|
res.adminInfo = a
|
|
|
|
|
res.techInfo = t
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-19 11:53:07 +08:00
|
|
|
func dotMkParser(domain, data string) (Result, error) {
|
|
|
|
|
var res = Result{
|
|
|
|
|
domain: domain,
|
|
|
|
|
rawData: data,
|
|
|
|
|
}
|
|
|
|
|
var r, a, t PersonalInfo
|
|
|
|
|
|
|
|
|
|
split := strings.Split(data, "\n")
|
|
|
|
|
cid := 0
|
|
|
|
|
for _, line := range split {
|
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
|
if !res.exists {
|
|
|
|
|
for _, token := range []string{"%ERROR:101: no entries found"} {
|
|
|
|
|
if strings.HasPrefix(line, token) {
|
|
|
|
|
res.exists = false
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "domain:") {
|
|
|
|
|
res.exists = true
|
|
|
|
|
res.hasRegisterDate = true
|
|
|
|
|
res.hasExpireDate = true
|
|
|
|
|
res.nsServers = []string{}
|
|
|
|
|
res.domain = strings.TrimSpace(strings.TrimPrefix(line, "domain:"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "registered:") {
|
|
|
|
|
res.registerDate = parseMkDate(strings.TrimSpace(strings.TrimPrefix(line, "registered:")), 2)
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "expire:") {
|
|
|
|
|
res.expireDate = parseMkDate(strings.TrimSpace(strings.TrimPrefix(line, "expire:")), 2)
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "changed:") {
|
|
|
|
|
if res.updateDate.IsZero() {
|
|
|
|
|
res.updateDate = parseMkDate(strings.TrimSpace(strings.TrimPrefix(line, "changed:")), 2)
|
|
|
|
|
res.hasUpdateDate = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "registrar:") {
|
|
|
|
|
res.registrar = strings.TrimSpace(strings.TrimPrefix(line, "registrar:"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if strings.HasPrefix(line, "contact:") {
|
|
|
|
|
cid++
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "org:") {
|
|
|
|
|
switch cid {
|
|
|
|
|
case 1:
|
|
|
|
|
r.Org = strings.TrimSpace(strings.TrimPrefix(line, "org:"))
|
|
|
|
|
case 2:
|
|
|
|
|
a.Org = strings.TrimSpace(strings.TrimPrefix(line, "org:"))
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "name:") {
|
|
|
|
|
switch cid {
|
|
|
|
|
case 1:
|
|
|
|
|
r.Name = strings.TrimSpace(strings.TrimPrefix(line, "name:"))
|
|
|
|
|
case 2:
|
|
|
|
|
a.Name = strings.TrimSpace(strings.TrimPrefix(line, "name:"))
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "address:") {
|
|
|
|
|
switch cid {
|
|
|
|
|
case 1:
|
|
|
|
|
r.Addr += strings.TrimSpace(strings.TrimPrefix(line, "address:")) + "\n"
|
|
|
|
|
case 2:
|
|
|
|
|
a.Addr += strings.TrimSpace(strings.TrimPrefix(line, "address:")) + "\n"
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "phone:") {
|
|
|
|
|
switch cid {
|
|
|
|
|
case 1:
|
|
|
|
|
r.Phone = strings.TrimSpace(strings.TrimPrefix(line, "phone:"))
|
|
|
|
|
case 2:
|
|
|
|
|
a.Phone = strings.TrimSpace(strings.TrimPrefix(line, "phone:"))
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "e-mail:") {
|
|
|
|
|
switch cid {
|
|
|
|
|
case 1:
|
|
|
|
|
r.Email = strings.TrimSpace(strings.TrimPrefix(line, "e-mail:"))
|
|
|
|
|
case 2:
|
|
|
|
|
a.Email = strings.TrimSpace(strings.TrimPrefix(line, "e-mail:"))
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "nserver:") {
|
|
|
|
|
res.nsServers = append(res.nsServers, strings.TrimSpace(strings.TrimPrefix(line, "nserver:")))
|
|
|
|
|
}
|
2024-08-16 21:30:27 +08:00
|
|
|
}
|
2026-03-19 11:53:07 +08:00
|
|
|
r.Addr = strings.TrimSpace(r.Addr)
|
|
|
|
|
a.Addr = strings.TrimSpace(a.Addr)
|
|
|
|
|
res.registerInfo = r
|
|
|
|
|
res.adminInfo = a
|
|
|
|
|
res.techInfo = t
|
|
|
|
|
return res, nil
|
2024-08-15 08:38:28 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-19 11:53:07 +08:00
|
|
|
func dotArParser(domain, data string) (Result, error) {
|
|
|
|
|
var res = Result{
|
|
|
|
|
domain: domain,
|
|
|
|
|
rawData: data,
|
|
|
|
|
}
|
|
|
|
|
var r, a, t PersonalInfo
|
|
|
|
|
|
|
|
|
|
split := strings.Split(data, "\n")
|
|
|
|
|
for _, line := range split {
|
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
|
if !res.exists {
|
|
|
|
|
for _, token := range []string{"El dominio no se encuentra registrado en NIC Argentina"} {
|
|
|
|
|
if strings.HasPrefix(line, token) {
|
|
|
|
|
res.exists = false
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "domain:") {
|
|
|
|
|
res.exists = true
|
|
|
|
|
res.hasRegisterDate = true
|
|
|
|
|
res.hasExpireDate = true
|
|
|
|
|
res.nsServers = []string{}
|
|
|
|
|
res.domain = strings.TrimSpace(strings.TrimPrefix(line, "domain:"))
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "registered:") {
|
|
|
|
|
res.registerDate = parseYMDHMSDate(strings.TrimSpace(strings.TrimPrefix(line, "registered:")), -3)
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "expire:") {
|
|
|
|
|
res.expireDate = parseYMDHMSDate(strings.TrimSpace(strings.TrimPrefix(line, "expire:")), -3)
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "changed:") {
|
|
|
|
|
if res.updateDate.IsZero() {
|
|
|
|
|
res.updateDate = parseYMDHMSDate(strings.TrimSpace(strings.TrimPrefix(line, "changed:")), -3)
|
|
|
|
|
res.hasUpdateDate = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(line, "registrar:") {
|
|
|
|
|
res.registrar = strings.TrimSpace(strings.TrimPrefix(line, "registrar:"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if strings.HasPrefix(line, "name:") {
|
|
|
|
|
r.Name = strings.TrimSpace(strings.TrimPrefix(line, "name:"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if strings.HasPrefix(line, "nserver:") {
|
|
|
|
|
tmp := strings.Split(strings.TrimSpace(strings.TrimPrefix(line, "nserver:")), " ")
|
|
|
|
|
for idx, ns := range tmp {
|
|
|
|
|
if idx == 0 {
|
|
|
|
|
res.nsServers = append(res.nsServers, ns)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
clean := strings.TrimSpace(strings.ReplaceAll(strings.ReplaceAll(ns, "(", ""), ")", ""))
|
|
|
|
|
if clean != "" {
|
|
|
|
|
res.nsIps = append(res.nsIps, clean)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
r.Addr = strings.TrimSpace(r.Addr)
|
|
|
|
|
a.Addr = strings.TrimSpace(a.Addr)
|
|
|
|
|
res.registerInfo = r
|
|
|
|
|
res.adminInfo = a
|
|
|
|
|
res.techInfo = t
|
|
|
|
|
return res, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ===== Date helpers kept for specialized parsers =====
|
|
|
|
|
|
2024-08-15 08:38:28 +08:00
|
|
|
func parseCNDate(date string) time.Time {
|
|
|
|
|
t, _ := time.ParseInLocation("2006-01-02 15:04:05", date, time.FixedZone("CST", 8*3600))
|
2026-03-19 11:53:07 +08:00
|
|
|
return t.In(time.Local)
|
2024-08-15 08:38:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseJPDate(date string, onlyMD bool) time.Time {
|
|
|
|
|
if onlyMD {
|
|
|
|
|
t, _ := time.ParseInLocation("2006/01/02", date, time.FixedZone("JST", 9*3600))
|
2026-03-19 11:53:07 +08:00
|
|
|
return t.In(time.Local)
|
2024-08-15 08:38:28 +08:00
|
|
|
}
|
|
|
|
|
t, _ := time.ParseInLocation("2006/01/02 15:04:05 (JST)", date, time.FixedZone("JST", 9*3600))
|
2026-03-19 11:53:07 +08:00
|
|
|
return t.In(time.Local)
|
2024-08-15 08:38:28 +08:00
|
|
|
}
|
2024-08-16 21:30:27 +08:00
|
|
|
|
|
|
|
|
func parseEduDate(date string) time.Time {
|
|
|
|
|
t, _ := time.Parse("02-Jan-2006", date)
|
2026-03-19 11:53:07 +08:00
|
|
|
return t.In(time.Local)
|
2024-08-16 21:30:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseYMDDate(date string) time.Time {
|
|
|
|
|
t, _ := time.Parse("2006-01-02", date)
|
2026-03-19 11:53:07 +08:00
|
|
|
return t.In(time.Local)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseYMDHMSDate(date string, tz int) time.Time {
|
|
|
|
|
t, _ := time.ParseInLocation("2006-01-02 15:04:05", date, time.FixedZone("myzone", tz*3600))
|
|
|
|
|
return t.In(time.Local)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseMkDate(date string, tz int) time.Time {
|
|
|
|
|
t, err := time.ParseInLocation("02.01.2006 15:04:05", date, time.FixedZone("myzone", tz*3600))
|
|
|
|
|
if err == nil {
|
|
|
|
|
return t.In(time.Local)
|
|
|
|
|
}
|
|
|
|
|
t, _ = time.Parse("02.01.2006", date)
|
|
|
|
|
return t.In(time.Local)
|
2024-08-16 21:30:27 +08:00
|
|
|
}
|