Repository: canc3s/cDomain
Branch: main
Commit: 33b146dddddc
Files: 14
Total size: 23.0 KB
Directory structure:
gitextract_3rdbp39r/
├── README.md
├── cmd/
│ └── cDomain/
│ ├── README.md
│ └── cDomain.go
├── go.mod
├── go.sum
└── internal/
├── fileutil/
│ ├── doc.go
│ └── fileutil.go
├── filters/
│ └── filters.go
├── gologger/
│ ├── doc.go
│ └── gologger.go
├── requests/
│ └── options.go
└── runner/
├── options.go
├── request.go
└── runner.go
================================================
FILE CONTENTS
================================================
================================================
FILE: README.md
================================================
# cDomain
利用天眼查查询企业备案
[下载地址](https://github.com/canc3s/cDomain/releases)
## 介绍
可以通过两种方式查询自己想要的企业子公司
1. `-n` 参数:利用(http://beian.tianyancha.com)接口给出的关键字先进行查询。(方便,但会搜索结果受关键字影响,假如会出现一些公司名类同的公司的备案)

2. `-i` 参数:利用给出的公司id对该公司进行查询。(准确,结果唯一,但需要自己先去查找一级公司,该接口目前没有限制不需要 `cookie`)
3. `-f` 参数:对文件里的所有关键字和id进行查询。因为我比较推荐用id查询,而且为了方便多次递归查询,读文件时会先去该行尝试匹配是否存在公司id,假如不存在就把该行作为关键字进行查询。因此查询可以直接把`cSubsidiary`的结果文件当作`cDomain`的输入文件。
4. 因为天眼查风控比较严格,所以使用时会出现几种情况。一、因为某个ip一段时间内查询次数过多,所以查询时会自动跳到登陆界面,这种情况需要使用一个手机号进行登陆,然后增加cookie去继续查询。二、海外ip或者云服务器ip访问天眼查会显示海外用户,所以最好使用正常的出口ip进行查询。三、假如短时间呢使用很多很多次查询的话,天眼查会有人机判断的验证码,需要手动打开天眼查网站进行一下人机验证。(情况较少)
## 用法
```
admin@admin cSubsidiary % go run cDomain.go -h
██████╗██████╗ ██████╗ ███╗ ███╗ █████╗ ██╗███╗ ██╗
██╔════╝██╔══██╗██╔═══██╗████╗ ████║██╔══██╗██║████╗ ██║
██║ ██║ ██║██║ ██║██╔████╔██║███████║██║██╔██╗ ██║
██║ ██║ ██║██║ ██║██║╚██╔╝██║██╔══██║██║██║╚██╗██║
╚██████╗██████╔╝╚██████╔╝██║ ╚═╝ ██║██║ ██║██║██║ ╚████║
╚═════╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝
v0.0.4
https://github.com/canc3s/cDomain
Usage of cDomain:
-c string
天眼查的Cookie
-delay int
请求之间的延迟时间(秒)
-f string
包含公司ID号码的文件
-i string
公司ID号码
-n string
公司名称
-no-color
No Color
-o string
结果输出的文件(可选)
-silent
Silent mode
-timeout int
连接超时时间(秒) (default 15)
-verbose
详细模式
-version
显示软件版本号
```
查询子公司
```
admin@admin cSubsidiary % go run cSubsidiary.go -n 字节跳动
██████╗██████╗ ██████╗ ███╗ ███╗ █████╗ ██╗███╗ ██╗
██╔════╝██╔══██╗██╔═══██╗████╗ ████║██╔══██╗██║████╗ ██║
██║ ██║ ██║██║ ██║██╔████╔██║███████║██║██╔██╗ ██║
██║ ██║ ██║██║ ██║██║╚██╔╝██║██╔══██║██║██║╚██╗██║
╚██████╗██████╔╝╚██████╔╝██║ ╚═╝ ██║██║ ██║██║██║ ╚████║
╚═════╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝
v0.0.4
https://github.com/canc3s/cDomain
[INFO] 正在查询关键字 字节跳动
[Warning] find IP : 114.246.10.65
[Warning] find IP : 119.167.189.11
dgo.ink
myzijie.com
toutiaocloud.net
toutiaocloud.com
toutiaocloud.cn
bytedance.cn
bytedance.org
bytedance.com
bytedance.net
zjtdchina.cn
bytecdn.cn
bytedns.net
bytedance.tj.cn
shuiwu360.com
byteimg.com
bytefcdn.com
video518.com
jinritoutiao.js.cn
eat9.cn
cdndns1.com
cdndns2.com
bytedns2.com
bytedns1.com
syzjtd.com
mykailu.com
hzzqw.cn
yxlgzs.cn
nmklw.com
shangtout.com
```
## 其他
软件难免有一些问题,假如大家发现,欢迎大家提意见或者建议。
还有一个工具 `cSubsidiary` 我一般两个一起使用,参考[文章](https://canc3s.github.io/2021/03/01/cSubsidiary和cDomain使用指南/)
## Changelog
* 增加请求延迟功能,防止触发反爬虫(-delay 默认为0,不开启)
================================================
FILE: cmd/cDomain/README.md
================================================
# cDomain
利用天眼查查询企业备案
[下载地址](https://github.com/canc3s/cDomain/releases)
## 介绍
可以通过两种方式查询自己想要的企业子公司
1. `-n` 参数:利用(http://beian.tianyancha.com)接口给出的关键字先进行查询。(方便,但会搜索结果受关键字影响,假如会出现一些公司名类同的公司的备案)

2. `-i` 参数:利用给出的公司id对该公司进行查询。(准确,结果唯一,但需要自己先去查找一级公司,该接口目前没有限制不需要 `cookie`)
3. `-f` 参数:对文件里的所有关键字和id进行查询。因为我比较推荐用id查询,而且为了方便多次递归查询,读文件时会先去该行尝试匹配是否存在公司id,假如不存在就把该行作为关键字进行查询。因此查询可以直接把`cSubsidiary`的结果文件当作`cDomain`的输入文件。
4. 因为天眼查风控比较严格,所以使用时会出现几种情况。一、因为某个ip一段时间内查询次数过多,所以查询时会自动跳到登陆界面,这种情况需要使用一个手机号进行登陆,然后增加cookie去继续查询。二、海外ip或者云服务器ip访问天眼查会显示海外用户,所以最好使用正常的出口ip进行查询。三、假如短时间呢使用很多很多次查询的话,天眼查会有人机判断的验证码,需要手动打开天眼查网站进行一下人机验证。(情况较少)
## 用法
```
admin@admin cSubsidiary % go run cDomain.go -h
██████╗██████╗ ██████╗ ███╗ ███╗ █████╗ ██╗███╗ ██╗
██╔════╝██╔══██╗██╔═══██╗████╗ ████║██╔══██╗██║████╗ ██║
██║ ██║ ██║██║ ██║██╔████╔██║███████║██║██╔██╗ ██║
██║ ██║ ██║██║ ██║██║╚██╔╝██║██╔══██║██║██║╚██╗██║
╚██████╗██████╔╝╚██████╔╝██║ ╚═╝ ██║██║ ██║██║██║ ╚████║
╚═════╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝
v0.0.4
https://github.com/canc3s/cDomain
Usage of cDomain:
-c string
天眼查的Cookie
-f string
包含公司ID号码的文件
-i string
公司ID号码
-n string
公司名称
-no-color
No Color
-o string
结果输出的文件(可选)
-silent
Silent mode
-timeout int
连接超时时间 (default 15)
-verbose
详细模式
-version
显示软件版本号
```
查询子公司
```
admin@admin cSubsidiary % go run cSubsidiary.go -n 字节跳动
██████╗██████╗ ██████╗ ███╗ ███╗ █████╗ ██╗███╗ ██╗
██╔════╝██╔══██╗██╔═══██╗████╗ ████║██╔══██╗██║████╗ ██║
██║ ██║ ██║██║ ██║██╔████╔██║███████║██║██╔██╗ ██║
██║ ██║ ██║██║ ██║██║╚██╔╝██║██╔══██║██║██║╚██╗██║
╚██████╗██████╔╝╚██████╔╝██║ ╚═╝ ██║██║ ██║██║██║ ╚████║
╚═════╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝
v0.0.4
https://github.com/canc3s/cDomain
[INFO] 正在查询关键字 字节跳动
[Warning] find IP : 114.246.10.65
[Warning] find IP : 119.167.189.11
dgo.ink
myzijie.com
toutiaocloud.net
toutiaocloud.com
toutiaocloud.cn
bytedance.cn
bytedance.org
bytedance.com
bytedance.net
zjtdchina.cn
bytecdn.cn
bytedns.net
bytedance.tj.cn
shuiwu360.com
byteimg.com
bytefcdn.com
video518.com
jinritoutiao.js.cn
eat9.cn
cdndns1.com
cdndns2.com
bytedns2.com
bytedns1.com
syzjtd.com
mykailu.com
hzzqw.cn
yxlgzs.cn
nmklw.com
shangtout.com
```
## 其他
软件难免有一些问题,假如大家发现,欢迎大家提意见或者建议。
还有一个工具 `cSubsidiary` 我一般两个一起使用,我后面写个文章,详细写一下
================================================
FILE: cmd/cDomain/cDomain.go
================================================
package main
import (
"github.com/canc3s/cDomain/internal/runner"
)
func main() {
options := runner.ParseOptions()
runner.RunEnumeration(options)
}
================================================
FILE: go.mod
================================================
module github.com/canc3s/cDomain
go 1.15
require (
github.com/antchfx/htmlquery v1.2.3
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/mattn/go-colorable v0.1.8
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
)
================================================
FILE: go.sum
================================================
github.com/antchfx/htmlquery v1.2.3 h1:sP3NFDneHx2stfNXCKbhHFo8XgNjCACnU/4AO5gWz6M=
github.com/antchfx/htmlquery v1.2.3/go.mod h1:B0ABL+F5irhhMWg54ymEZinzMSi0Kt3I2if0BLYa3V0=
github.com/antchfx/xpath v1.1.6 h1:6sVh6hB5T6phw1pFpHRQ+C4bd8sNI+O58flqtg7h0R0=
github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
================================================
FILE: internal/fileutil/doc.go
================================================
// Package fileutil contains all the funcionality related to deal with files
package fileutil
================================================
FILE: internal/fileutil/fileutil.go
================================================
package fileutil
import (
"bufio"
"io"
"os"
)
// FileExists checks if a file exists and is not a directory
func FileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
// FolderExists checks if a folder exists
func FolderExists(folderpath string) bool {
_, err := os.Stat(folderpath)
return !os.IsNotExist(err)
}
// HasStdin determines if the user has piped input
func HasStdin() bool {
stat, err := os.Stdin.Stat()
if err != nil {
return false
}
mode := stat.Mode()
isPipedFromChrDev := (mode & os.ModeCharDevice) == 0
isPipedFromFIFO := (mode & os.ModeNamedPipe) != 0
return isPipedFromChrDev || isPipedFromFIFO
}
func ReadImf(input io.Reader) []string {
var imf []string
scanner := bufio.NewScanner(input)
for scanner.Scan() {
imf = append(imf,scanner.Text())
}
return imf
}
================================================
FILE: internal/filters/filters.go
================================================
package filters
import "regexp"
type Result struct {
Domains []string
Ips []string
}
func FilterIP(domains []string) Result {
var results Result
for _,domain := range domains {
re := regexp.MustCompile(`((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)`)
if re.MatchString(domain) {
results.Ips = append(results.Ips , domain)
} else {
results.Domains = append(results.Domains , domain)
}
}
return results
}
================================================
FILE: internal/gologger/doc.go
================================================
// Package gologger contains all the funcionality
package gologger
================================================
FILE: internal/gologger/gologger.go
================================================
package gologger
import (
"fmt"
"github.com/logrusorgru/aurora"
"github.com/mattn/go-colorable"
"os"
"strings"
"sync"
)
// Level defines all the available levels we can log at
type Level int
// Available logging levels
const (
Null Level = iota
Fatal
Silent
Label
Misc
Error
Warning
Info
Debug
Verbose
)
var (
// UseColors can be used to control coloring of the output
UseColors = true
// MaxLevel is the maximum level to log at. By default, logging
// is done at Info level. Using verbose will display all the errors too,
// Using silent will display only the most relevant information.
MaxLevel = Info
labels = map[Level]string{
Warning: "Warning",
Error: "Error",
Label: "WRN",
Fatal: "Fatal",
Debug: "DEBUG",
Info: "INFO",
}
mutex = &sync.Mutex{}
output = colorable.NewColorableStdout()
)
var stringBuilderPool = &sync.Pool{New: func() interface{} {
return new(strings.Builder)
}}
// wrap wraps a given label for a message to a logg-able representation.
// It checks if colors are specified and what level we are logging at.
func wrap(label string, level Level) string {
// Check if we are not using colors, if not, return
if !UseColors {
return label
}
switch level {
case Silent:
return label
case Info, Verbose:
return aurora.Blue(label).String()
case Fatal:
return aurora.Bold(aurora.Red(label)).String()
case Error:
return aurora.Red(label).String()
case Debug:
return aurora.Magenta(label).String()
case Warning, Label:
return aurora.Yellow(label).String()
default:
return label
}
}
// getLabel generates a label for a given message, depending on the level
// and the label passed.
func getLabel(level Level, label string, sb *strings.Builder) {
switch level {
case Silent, Misc:
return
case Error, Fatal, Info, Warning, Debug, Label:
sb.WriteString("[")
sb.WriteString(wrap(labels[level], level))
sb.WriteString("]")
sb.WriteString(" ")
return
case Verbose:
sb.WriteString("[")
sb.WriteString(wrap(label, level))
sb.WriteString("]")
sb.WriteString(" ")
return
default:
return
}
}
// log logs the actual message to the screen
func log(level Level, label string, format string, args ...interface{}) {
// Don't log if the level is null
if level == Null {
return
}
if level <= MaxLevel {
// Build the log message using the string builder pool
sb := stringBuilderPool.Get().(*strings.Builder)
// Get the label and append it to string builder
getLabel(level, label, sb)
message := fmt.Sprintf(format, args...)
sb.WriteString(message)
//if strings.HasSuffix(message, "\n") == false {
// sb.WriteString("\n")
//}
mutex.Lock()
switch level {
case Silent:
fmt.Fprint(os.Stdout, sb.String())
default:
fmt.Fprint(output, sb.String())
}
mutex.Unlock()
sb.Reset()
stringBuilderPool.Put(sb)
}
}
// Infof writes a info message on the screen with the default label
func Infof(format string, args ...interface{}) {
log(Info, "", format, args...)
}
// Warningf writes a warning message on the screen with the default label
func Warningf(format string, args ...interface{}) {
log(Warning, "", format, args...)
}
// Errorf writes an error message on the screen with the default label
func Errorf(format string, args ...interface{}) {
log(Error, "", format, args...)
}
// Debugf writes an error message on the screen with the default label
func Debugf(format string, args ...interface{}) {
log(Debug, "", format, args...)
}
// Verbosef writes a verbose message on the screen with a tabel
func Verbosef(format string, label string, args ...interface{}) {
log(Verbose, label, format, args...)
}
// Silentf writes a message on the stdout with no label
func Silentf(format string, args ...interface{}) {
log(Silent, "", format, args...)
}
// Fatalf exits the program if we encounter a fatal error
func Fatalf(format string, args ...interface{}) {
log(Fatal, "", format, args...)
os.Exit(1)
}
// Printf prints a string on screen without any extra stuff
func Printf(format string, args ...interface{}) {
log(Misc, "", format, args...)
}
// Labelf prints a string on screen with a label interface
func Labelf(format string, args ...interface{}) {
log(Label, "", format, args...)
}
================================================
FILE: internal/requests/options.go
================================================
package requests
import (
"crypto/tls"
"golang.org/x/net/html"
"net"
"net/http"
"time"
)
type Request struct {
Url string
Cookie string
}
type Response struct {
Body []byte
Page *html.Node
}
func DefaultTransport() *http.Transport {
transport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConnsPerHost: -1,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
DisableKeepAlives: true,
}
return transport
}
================================================
FILE: internal/runner/options.go
================================================
package runner
import (
"flag"
"github.com/canc3s/cDomain/internal/fileutil"
"github.com/canc3s/cDomain/internal/gologger"
"os"
)
const banner = `
██████╗██████╗ ██████╗ ███╗ ███╗ █████╗ ██╗███╗ ██╗
██╔════╝██╔══██╗██╔═══██╗████╗ ████║██╔══██╗██║████╗ ██║
██║ ██║ ██║██║ ██║██╔████╔██║███████║██║██╔██╗ ██║
██║ ██║ ██║██║ ██║██║╚██╔╝██║██╔══██║██║██║╚██╗██║
╚██████╗██████╔╝╚██████╔╝██║ ╚═╝ ██║██║ ██║██║██║ ╚████║
╚═════╝╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝
v`
// Version is the current version of C
const Version = `0.0.5`
type Options struct {
KeyWord string
CompanyID string // Target is a single URL/Domain to scan usng a template
InputFile string // Targets specifies the targets to scan using templates.
Cookie string
Delay int
Timeout int
Output string // Output is the file to write found subdomains to.
Silent bool
NoColor bool
Verbose bool
Version bool // Version specifies if we should just show version and exit
}
func ParseOptions() *Options {
options := &Options{}
flag.StringVar(&options.KeyWord, "n", "", "公司名称")
flag.StringVar(&options.CompanyID, "i", "", "公司ID号码")
flag.StringVar(&options.InputFile, "f", "", "包含公司ID号码的文件")
flag.StringVar(&options.Cookie, "c", "", "天眼查的Cookie")
flag.IntVar(&options.Timeout, "timeout", 15, "连接超时时间(秒)")
flag.IntVar(&options.Delay, "delay", 0, "请求之间的延迟时间(秒)")
flag.StringVar(&options.Output, "o", "", "结果输出的文件(可选)")
flag.BoolVar(&options.Silent, "silent", false, "Silent mode")
flag.BoolVar(&options.NoColor, "no-color", false, "No Color")
flag.BoolVar(&options.Verbose, "verbose", false, "详细模式")
flag.BoolVar(&options.Version, "version", false, "显示软件版本号")
flag.Parse()
options.configureOutput()
showBanner()
if options.Version {
gologger.Infof("Current Version: %s\n", Version)
os.Exit(0)
}
options.validateOptions()
return options
}
func (options *Options) validateOptions() {
if options.CompanyID != "" && len(options.CompanyID) < 5 {
gologger.Fatalf("公司ID %s 不正确!\n", options.CompanyID)
}
if options.InputFile != "" && !fileutil.FileExists(options.InputFile) {
gologger.Fatalf("文件 %s 不存在!\n", options.InputFile)
}
if options.KeyWord == "" && options.CompanyID == "" && options.InputFile == "" {
flag.PrintDefaults()
os.Exit(0)
}
}
// showBanner is used to show the banner to the user
func showBanner() {
gologger.Printf("%s%s\n", banner,Version)
gologger.Printf("\t\thttps://github.com/canc3s/cDomain\n\n")
//gologger.Labelf("请谨慎使用,您应对自己的行为负责\n")
//gologger.Labelf("开发人员不承担任何责任,也不对任何滥用或损坏负责.\n")
}
func (options *Options) configureOutput() {
// If the user desires verbose output, show verbose output
if options.Verbose {
gologger.MaxLevel = gologger.Verbose
}
if options.NoColor {
gologger.UseColors = false
}
if options.Silent {
gologger.MaxLevel = gologger.Silent
}
}
================================================
FILE: internal/runner/request.go
================================================
package runner
import (
"github.com/antchfx/htmlquery"
"github.com/canc3s/cDomain/internal/gologger"
"github.com/canc3s/cDomain/internal/requests"
"golang.org/x/net/html"
"io/ioutil"
"net/http"
"strconv"
"strings"
"time"
)
func GetPage(url string, options *Options) requests.Response {
time.Sleep(time.Duration(options.Delay) * time.Second)
var transport = requests.DefaultTransport()
var client = &http.Client{
Transport: transport,
//Timeout: time.Duration(options.Timeout),
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse /* 不进入重定向 */
},
}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5026.0 Safari/537.36 Edg/103.0.1254.0")
if options.Cookie != "" {
req.Header.Set("Cookie", options.Cookie)
}
resp, err := client.Do(req)
if err != nil {
gologger.Fatalf("请求发生错误,请检查网络连接\n%s\n", err)
}
if resp.StatusCode == 403 {
gologger.Fatalf("海外用户或者云服务器ip被禁止访问网站,请更换ip\n")
} else if resp.StatusCode == 401 {
gologger.Fatalf("天眼查Cookie有问题或过期,请重新获取\n")
} else if resp.StatusCode == 302 {
gologger.Fatalf("天眼查免费查询次数已用光,需要加Cookie\n")
}
body, _ := ioutil.ReadAll(resp.Body)
page,_ := htmlquery.Parse(strings.NewReader(string(body)))
return requests.Response{
Body: body,
Page:page,
}
}
func JudgePagesK(page *html.Node) int {
list := htmlquery.Find(page, "/html/body/div[2]/div/div[2]/div[1]/div[2]/div[3]/ul/li/a")
num := 1
if len(list) > 2 {
var err error
pages := htmlquery.InnerText(list[len(list)-2])
num,err = strconv.Atoi(strings.Trim(pages, "."))
if err != nil {
num = 1
}
}
return num
}
func JudgePagesI(page *html.Node) int {
list := htmlquery.Find(page, "/html/body/div/ul/li/a")
return len(list) - 1
}
func EnuDomainByKey(page *html.Node, domains *[]string) {
list := htmlquery.Find(page, "/html/body/div[2]/div/div[2]/div[1]/div[2]/div[2]/table/tbody/tr/td[5]/span")
for _,node := range list {
domain := htmlquery.InnerText(node)
*domains = append(*domains, domain)
}
}
func GetInformation(page *html.Node) []string {
list := htmlquery.Find(page, "/html/body/table/tbody/tr/td[5]")
var domains []string
for _,node := range list {
domain := htmlquery.InnerText(node)
domains = append(domains, domain)
}
return domains
}
func GetDomain(options *Options) []string {
resp := GetPage("https://www.tianyancha.com/pagination/icp.xhtml?ps=30&isAjaxLoad=true&pn=1&id="+options.CompanyID, options)
page := JudgePagesI(resp.Page)
domains := GetInformation(resp.Page)
for i := 2; i <= page; i++ {
resp := GetPage("https://www.tianyancha.com/pagination/icp.xhtml?ps=30&isAjaxLoad=true&pn="+strconv.Itoa(i)+"&id="+options.CompanyID, options)
domains = append(domains,GetInformation(resp.Page)...)
}
return domains
}
================================================
FILE: internal/runner/runner.go
================================================
package runner
import (
"fmt"
"github.com/canc3s/cDomain/internal/fileutil"
"github.com/canc3s/cDomain/internal/filters"
"github.com/canc3s/cDomain/internal/gologger"
"net/url"
"os"
"regexp"
"strconv"
)
type Targets struct {
ID []string
Name []string
}
func GetDomainByKey(options *Options) []string {
var domains []string
gologger.Infof("正在查询关键字 %s\n",options.KeyWord)
url := "https://beian.tianyancha.com/search/"+ url.QueryEscape(options.KeyWord)
resp := GetPage(url, options)
EnuDomainByKey(resp.Page, &domains)
num := JudgePagesK(resp.Page)
if num > 5 && options.Cookie == "" {
gologger.Errorf("域名过多,需要cookie才能完整查询\n")
num = 5
}
if num > 1 {
for i := 2; i <= num; i++ {
resp := GetPage(url+"/p"+strconv.Itoa(num), options)
EnuDomainByKey(resp.Page, &domains)
}
}
return domains
}
func GetDomainByID(options *Options) []string {
domains := GetDomain(options)
return domains
}
func RunEnumeration(options *Options) {
var domains []string
if options.InputFile != "" {
fin, error := os.OpenFile(options.InputFile, os.O_RDONLY, 0)
if error != nil {
gologger.Fatalf("文件读取失败:%s",error)
}
defer fin.Close()
imf := fileutil.ReadImf(fin)
targets := TransImf(imf)
for _,id := range targets.ID {
options.CompanyID = id
domains = append(domains,GetDomainByID(options)...)
}
for _,name := range targets.Name {
options.KeyWord = name
domains = append(domains,GetDomainByKey(options)...)
}
} else {
if options.KeyWord != "" && options.CompanyID == "" {
domains = GetDomainByKey(options)
} else if options.CompanyID != "" {
domains = GetDomainByID(options)
}
}
results := filters.FilterIP(domains)
for _,ip := range results.Ips {
gologger.Warningf("find IP : %s\n",ip)
}
for _,domain := range results.Domains {
fmt.Println(domain)
}
if options.Output != "" {
file, err := os.OpenFile(options.Output, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
gologger.Fatalf("结果无法写入文件:%s", err)
}
defer file.Close()
for _,domain := range results.Domains {
file.WriteString(domain+"\n")
}
}
}
func TransImf(imf []string) Targets {
var targets Targets
for _,i := range imf {
re := regexp.MustCompile(`(\d{5,11})`)
buf := re.FindStringSubmatch(i)
if buf == nil {
targets.Name = append(targets.Name, i)
}else{
targets.ID = append(targets.ID, buf[0])
}
}
return targets
}
gitextract_3rdbp39r/
├── README.md
├── cmd/
│ └── cDomain/
│ ├── README.md
│ └── cDomain.go
├── go.mod
├── go.sum
└── internal/
├── fileutil/
│ ├── doc.go
│ └── fileutil.go
├── filters/
│ └── filters.go
├── gologger/
│ ├── doc.go
│ └── gologger.go
├── requests/
│ └── options.go
└── runner/
├── options.go
├── request.go
└── runner.go
SYMBOL INDEX (51 symbols across 8 files)
FILE: cmd/cDomain/cDomain.go
function main (line 7) | func main() {
FILE: internal/fileutil/fileutil.go
function FileExists (line 10) | func FileExists(filename string) bool {
function FolderExists (line 19) | func FolderExists(folderpath string) bool {
function HasStdin (line 25) | func HasStdin() bool {
function ReadImf (line 39) | func ReadImf(input io.Reader) []string {
FILE: internal/filters/filters.go
type Result (line 5) | type Result struct
function FilterIP (line 10) | func FilterIP(domains []string) Result {
FILE: internal/gologger/gologger.go
type Level (line 13) | type Level
constant Null (line 17) | Null Level = iota
constant Fatal (line 18) | Fatal
constant Silent (line 19) | Silent
constant Label (line 20) | Label
constant Misc (line 21) | Misc
constant Error (line 22) | Error
constant Warning (line 23) | Warning
constant Info (line 24) | Info
constant Debug (line 25) | Debug
constant Verbose (line 26) | Verbose
function wrap (line 56) | func wrap(label string, level Level) string {
function getLabel (line 82) | func getLabel(level Level, label string, sb *strings.Builder) {
function log (line 104) | func log(level Level, label string, format string, args ...interface{}) {
function Infof (line 139) | func Infof(format string, args ...interface{}) {
function Warningf (line 144) | func Warningf(format string, args ...interface{}) {
function Errorf (line 149) | func Errorf(format string, args ...interface{}) {
function Debugf (line 154) | func Debugf(format string, args ...interface{}) {
function Verbosef (line 159) | func Verbosef(format string, label string, args ...interface{}) {
function Silentf (line 164) | func Silentf(format string, args ...interface{}) {
function Fatalf (line 169) | func Fatalf(format string, args ...interface{}) {
function Printf (line 175) | func Printf(format string, args ...interface{}) {
function Labelf (line 180) | func Labelf(format string, args ...interface{}) {
FILE: internal/requests/options.go
type Request (line 11) | type Request struct
type Response (line 16) | type Response struct
function DefaultTransport (line 21) | func DefaultTransport() *http.Transport {
FILE: internal/runner/options.go
constant banner (line 10) | banner = `
constant Version (line 21) | Version = `0.0.5`
type Options (line 24) | type Options struct
method validateOptions (line 69) | func (options *Options) validateOptions() {
method configureOutput (line 92) | func (options *Options) configureOutput() {
function ParseOptions (line 38) | func ParseOptions() *Options {
function showBanner (line 84) | func showBanner() {
FILE: internal/runner/request.go
function GetPage (line 15) | func GetPage(url string, options *Options) requests.Response {
function JudgePagesK (line 52) | func JudgePagesK(page *html.Node) int {
function JudgePagesI (line 66) | func JudgePagesI(page *html.Node) int {
function EnuDomainByKey (line 71) | func EnuDomainByKey(page *html.Node, domains *[]string) {
function GetInformation (line 79) | func GetInformation(page *html.Node) []string {
function GetDomain (line 90) | func GetDomain(options *Options) []string {
FILE: internal/runner/runner.go
type Targets (line 14) | type Targets struct
function GetDomainByKey (line 19) | func GetDomainByKey(options *Options) []string {
function GetDomainByID (line 39) | func GetDomainByID(options *Options) []string {
function RunEnumeration (line 44) | func RunEnumeration(options *Options) {
function TransImf (line 90) | func TransImf(imf []string) Targets {
Condensed preview — 14 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (32K chars).
[
{
"path": "README.md",
"chars": 2653,
"preview": "# cDomain\n 利用天眼查查询企业备案\n\n[下载地址](https://github.com/canc3s/cDomain/releases)\n\n## 介绍\n\n可以通过两种方式查询自己想要的企业子公司\n\n1. `-n` 参数:利用(h"
},
{
"path": "cmd/cDomain/README.md",
"chars": 2514,
"preview": "# cDomain\n 利用天眼查查询企业备案\n\n[下载地址](https://github.com/canc3s/cDomain/releases)\n\n## 介绍\n\n可以通过两种方式查询自己想要的企业子公司\n\n1. `-n` 参数:利用(h"
},
{
"path": "cmd/cDomain/cDomain.go",
"chars": 155,
"preview": "package main\n\nimport (\n\t\"github.com/canc3s/cDomain/internal/runner\"\n)\n\nfunc main() {\n\toptions := runner.ParseOptions()\n\n"
},
{
"path": "go.mod",
"chars": 234,
"preview": "module github.com/canc3s/cDomain\n\ngo 1.15\n\nrequire (\n\tgithub.com/antchfx/htmlquery v1.2.3\n\tgithub.com/logrusorgru/aurora"
},
{
"path": "go.sum",
"chars": 3373,
"preview": "github.com/antchfx/htmlquery v1.2.3 h1:sP3NFDneHx2stfNXCKbhHFo8XgNjCACnU/4AO5gWz6M=\ngithub.com/antchfx/htmlquery v1.2.3/"
},
{
"path": "internal/fileutil/doc.go",
"chars": 94,
"preview": "// Package fileutil contains all the funcionality related to deal with files\npackage fileutil\n"
},
{
"path": "internal/fileutil/fileutil.go",
"chars": 884,
"preview": "package fileutil\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"os\"\n)\n\n// FileExists checks if a file exists and is not a directory\nfunc Fil"
},
{
"path": "internal/filters/filters.go",
"chars": 450,
"preview": "package filters\n\nimport \"regexp\"\n\ntype Result struct {\n\tDomains \t[]string\n\tIps\t\t\t[]string\n}\n\nfunc FilterIP(domains []str"
},
{
"path": "internal/gologger/doc.go",
"chars": 67,
"preview": "// Package gologger contains all the funcionality\npackage gologger\n"
},
{
"path": "internal/gologger/gologger.go",
"chars": 4254,
"preview": "package gologger\n\nimport (\n\t\"fmt\"\n\t\"github.com/logrusorgru/aurora\"\n\t\"github.com/mattn/go-colorable\"\n\t\"os\"\n\t\"strings\"\n\t\"s"
},
{
"path": "internal/requests/options.go",
"chars": 575,
"preview": "package requests\n\nimport (\n\t\"crypto/tls\"\n\t\"golang.org/x/net/html\"\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n)\n\ntype Request struct {\n\tU"
},
{
"path": "internal/runner/options.go",
"chars": 2973,
"preview": "package runner\n\nimport (\n\t\"flag\"\n\t\"github.com/canc3s/cDomain/internal/fileutil\"\n\t\"github.com/canc3s/cDomain/internal/gol"
},
{
"path": "internal/runner/request.go",
"chars": 2890,
"preview": "package runner\n\nimport (\n\t\"github.com/antchfx/htmlquery\"\n\t\"github.com/canc3s/cDomain/internal/gologger\"\n\t\"github.com/can"
},
{
"path": "internal/runner/runner.go",
"chars": 2402,
"preview": "package runner\n\nimport (\n\t\"fmt\"\n\t\"github.com/canc3s/cDomain/internal/fileutil\"\n\t\"github.com/canc3s/cDomain/internal/filt"
}
]
About this extraction
This page contains the full source code of the canc3s/cDomain GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 14 files (23.0 KB), approximately 9.4k tokens, and a symbol index with 51 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.