Skip to content

Commit 6af6817

Browse files
committed
v0.1.15 update fixUrl
1 parent fd5b50f commit 6af6817

8 files changed

+303
-54
lines changed

HISTORY.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## v0.1.15 update fixUrl
2+
3+
- support redis/socks5/mysql ```./fofa --fixUrl --size 1000 --fields host 'protocol=socks5 || protocol=redis'```
4+
15
## v0.1.14 search add uniqByIP
26

37
- search add uniqByIP argument, which can be used to filter data as group by ip. ```./fofa --fixUrl --size 1000 --fields host --uniqByIP 'host="edu.cn"'```

README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,10 @@ every 500ms generate one line, never stop
246246
- ☑ fields/f
247247
- ☑ size/s
248248
- group/g 根据字段聚合:group by ip 根据ip合并,比如查询一个app会有很多域名,其中多个域名对应一个ip,这时只测试其中一个就好了
249-
- ☑ fixUrl 构建完整的url,默认的字段如果是http的话前面没有http://前缀,导致命令行一些工具不能使用,通过这个参数进行修复
250-
- ☑ 可以配合urlPrefix使用,比如不用http://而用redis://
249+
- ☑ fixUrl build valid url,默认的字段如果是http的话前面没有http://前缀,导致命令行一些工具不能使用,通过这个参数进行修复
250+
- ☑ can use with urlPrefix, such as use `app://` instead of `http://`
251+
- ☑ support socks5
252+
- ☑ support redis
251253
- ☑ full 匹配所有,而不只是一年内的
252254
- ☑ format
253255
- ☑ csv

account.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,7 @@ func (c *Client) freeSize() int {
102102
if info.RemainApiQuery > 0 {
103103
return info.RemainApiData
104104
}
105-
default:
106-
// other level, ignore free limit check
107-
return -1
108105
}
109-
return 0
106+
// other level, ignore free limit check
107+
return -1
110108
}

account_test.go

+22
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,16 @@ func TestClient_AccountInfo(t *testing.T) {
6060

6161
var cli *Client
6262
var err error
63+
64+
// 请求失败
65+
errTs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
66+
67+
}))
68+
defer ts.Close()
69+
_, err = NewClient(WithURL(errTs.URL + "[email protected]&key=wrong"))
70+
assert.EqualError(t, err, "unexpected end of JSON input")
71+
72+
// 账号无效
6373
_, err = NewClient(WithURL(ts.URL + "[email protected]&key=wrong"))
6474
assert.Contains(t, err.Error(), "[-700] Account Invalid")
6575

@@ -108,6 +118,18 @@ func TestClient_AccountInfo(t *testing.T) {
108118
assert.Equal(t, 10, cli.Account.FCoin)
109119
assert.Equal(t, 100, cli.freeSize())
110120

121+
// 订阅商业版
122+
account = validAccounts[7]
123+
cli, err = NewClient(WithURL(ts.URL + "?email=" + account.Email + "&key=" + account.Key))
124+
assert.Nil(t, err)
125+
assert.True(t, cli.Account.IsVIP)
126+
assert.Equal(t, VipLevelSubBuss, cli.Account.VIPLevel)
127+
assert.Equal(t, 0, cli.Account.FCoin)
128+
assert.Equal(t, 100000, cli.freeSize())
129+
// 构造异常
130+
cli.Server = errTs.URL
131+
assert.Equal(t, 100000, cli.freeSize())
132+
111133
// 红队?
112134
account = validAccounts[8]
113135
cli, err = NewClient(WithURL(ts.URL + "?email=" + account.Email + "&key=" + account.Key))

client_test.go

+73-5
Large diffs are not rendered by default.

cmd/fofa/cmd/search.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ var searchCmd = &cli.Command{
7373
},
7474
&cli.StringFlag{
7575
Name: "urlPrefix",
76-
Value: "http://",
76+
Value: "",
7777
Usage: "prefix of url, default is http://, can be redis:// and so on ",
7878
Destination: &urlPrefix,
7979
},
@@ -118,6 +118,12 @@ func hasBodyField(fields []string) bool {
118118
// SearchAction search action
119119
func SearchAction(ctx *cli.Context) error {
120120
// valid same config
121+
for _, arg := range ctx.Args().Slice() {
122+
if arg[0] == '-' {
123+
return errors.New(fmt.Sprintln("there is args after fofa query:", arg))
124+
}
125+
}
126+
121127
query := ctx.Args().First()
122128
if len(query) == 0 {
123129
return errors.New("fofa query cannot be empty")

host.go

+93-34
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ import (
99
"strings"
1010
)
1111

12+
const (
13+
NoHostWithFixURL = "host field must included when fixUrl option set"
14+
)
15+
1216
// HostResults /search/all api results
1317
type HostResults struct {
1418
Mode string `json:"mode"`
@@ -47,14 +51,24 @@ type SearchOptions struct {
4751
}
4852

4953
// fixHostToUrl 替换host为url
50-
func fixHostToUrl(res [][]string, fields []string, hostIndex int, urlPrefix string) [][]string {
54+
func fixHostToUrl(res [][]string, fields []string, hostIndex int, urlPrefix string, protocolIndex int) [][]string {
55+
5156
newRes := make([][]string, 0, len(res))
5257
for _, row := range res {
5358
newRow := make([]string, 0, len(fields))
5459
for j, r := range row {
5560
if j == hostIndex {
5661
if !strings.Contains(r, "://") {
57-
r = urlPrefix + r
62+
if urlPrefix != "" {
63+
r = urlPrefix + r
64+
} else if protocolIndex != -1 &&
65+
(row[protocolIndex] == "socks5" || row[protocolIndex] == "redis" ||
66+
row[protocolIndex] == "http" || row[protocolIndex] == "https" ||
67+
row[protocolIndex] == "mongodb" || row[protocolIndex] == "mysql") {
68+
r = row[protocolIndex] + "://" + r
69+
} else {
70+
r = "http://" + r
71+
}
5872
}
5973
}
6074
newRow = append(newRow, r)
@@ -64,6 +78,71 @@ func fixHostToUrl(res [][]string, fields []string, hostIndex int, urlPrefix stri
6478
return newRes
6579
}
6680

81+
// fixUrlCheck 检查参数,构建新的field和记录相关字段的偏移
82+
// 返回hostIndex, protocolIndex, fields, rawFieldSize, err
83+
func (c *Client) fixUrlCheck(fields []string, options ...SearchOptions) (int, int, []string, int, error) {
84+
noSetFields := false
85+
if len(fields) == 0 {
86+
noSetFields = true
87+
fields = []string{"host", "ip", "port"}
88+
}
89+
rawFieldSize := len(fields)
90+
91+
// 确保urlfix开启后带上了protocol字段
92+
protocolIndex := -1
93+
hostIndex := -1
94+
if len(options) > 0 && options[0].FixUrl {
95+
if noSetFields {
96+
fields = []string{"host", "ip", "port", "protocol"}
97+
rawFieldSize = len(fields)
98+
hostIndex = 0
99+
protocolIndex = 3
100+
} else {
101+
// 检查host字段存在
102+
for index, f := range fields {
103+
switch f {
104+
case "host":
105+
hostIndex = index
106+
break
107+
}
108+
}
109+
if hostIndex == -1 {
110+
err := errors.New(NoHostWithFixURL)
111+
return hostIndex, protocolIndex, fields, rawFieldSize, err
112+
}
113+
for index, f := range fields {
114+
switch f {
115+
case "protocol":
116+
protocolIndex = index
117+
break
118+
}
119+
}
120+
if protocolIndex == -1 {
121+
fields = append(fields, "protocol")
122+
protocolIndex = len(fields) - 1
123+
}
124+
}
125+
}
126+
return hostIndex, protocolIndex, fields, rawFieldSize, nil
127+
}
128+
129+
func (c *Client) postProcess(res [][]string, fields []string,
130+
hostIndex int, protocolIndex int, rawFieldSize int, options ...SearchOptions) [][]string {
131+
if len(options) > 0 && options[0].FixUrl {
132+
res = fixHostToUrl(res, fields, hostIndex, options[0].UrlPrefix, protocolIndex)
133+
}
134+
135+
// 返回用户指定的字段
136+
if rawFieldSize != len(fields) {
137+
var newRes [][]string
138+
for _, r := range res {
139+
newRes = append(newRes, r[0:rawFieldSize])
140+
}
141+
return newRes
142+
}
143+
return res
144+
}
145+
67146
// HostSearch search fofa host data
68147
// query fofa query string
69148
// size data size: -1 means all,0 means just data total info, >0 means actual size
@@ -112,23 +191,22 @@ func (c *Client) HostSearch(query string, size int, fields []string, options ...
112191
perPage = 1000
113192
}
114193

115-
if len(fields) == 0 {
116-
fields = []string{"ip", "port"}
194+
hostIndex, protocolIndex, fields, rawFieldSize, err := c.fixUrlCheck(fields, options...)
195+
if err != nil {
196+
return nil, err
117197
}
118198

199+
uniqIPMap := make(map[string]bool)
119200
// 确认fields包含ip
120201
ipIndex := -1
121-
uniqIPMap := make(map[string]bool)
122202
if uniqByIP {
123-
ipExists := false
124203
for index, f := range fields {
125204
if f == "ip" {
126205
ipIndex = index
127-
ipExists = true
128206
break
129207
}
130208
}
131-
if !ipExists {
209+
if ipIndex == -1 {
132210
fields = append(fields, "ip")
133211
ipIndex = len(fields) - 1
134212
}
@@ -213,18 +291,7 @@ func (c *Client) HostSearch(query string, size int, fields []string, options ...
213291
}
214292

215293
// 后处理
216-
if len(options) > 0 && options[0].FixUrl {
217-
urlPrefix := options[0].UrlPrefix
218-
if urlPrefix == "" {
219-
urlPrefix = "http://"
220-
}
221-
for i, f := range fields {
222-
if f == "host" {
223-
res = fixHostToUrl(res, fields, i, urlPrefix)
224-
break
225-
}
226-
}
227-
}
294+
res = c.postProcess(res, fields, hostIndex, protocolIndex, rawFieldSize, options...)
228295

229296
return
230297
}
@@ -272,8 +339,11 @@ func (c *Client) DumpSearch(query string, allSize int, batchSize int, fields []s
272339
if perPage < 1 || perPage > 100000 {
273340
return errors.New("batchSize must between 1 and 100000")
274341
}
275-
if len(fields) == 0 {
276-
fields = []string{"host", "ip", "port"}
342+
343+
// 确保urlfix开启后带上了protocol字段
344+
hostIndex, protocolIndex, fields, rawFieldSize, err := c.fixUrlCheck(fields, options...)
345+
if err != nil {
346+
return err
277347
}
278348

279349
// 分页取数据
@@ -331,18 +401,7 @@ func (c *Client) DumpSearch(query string, allSize int, batchSize int, fields []s
331401
}
332402

333403
// 后处理
334-
if len(options) > 0 && options[0].FixUrl {
335-
urlPrefix := options[0].UrlPrefix
336-
if urlPrefix == "" {
337-
urlPrefix = "http://"
338-
}
339-
for i, f := range fields {
340-
if f == "host" {
341-
results = fixHostToUrl(results, fields, i, urlPrefix)
342-
break
343-
}
344-
}
345-
}
404+
results = c.postProcess(results, fields, hostIndex, protocolIndex, rawFieldSize, options...)
346405

347406
if c.onResults != nil {
348407
c.onResults(results)

0 commit comments

Comments
 (0)