├── .travis.yml
├── .vscode
└── launch.json
├── README.md
├── build_linux64.bat
├── build_mac64.bat
├── build_win64.bat
├── config.yml
├── config
└── mysql.go
├── dutyfree.sql
├── main.go
└── scanproxy
├── checkhttp.go
├── checksocks.go
├── getip.go
├── recover.go
├── saveproxy.go
└── scanport.go
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 | go:
3 | - 1.12
4 | - 1.11
5 | - 1.10.x
6 | - 1.9
7 | - 1.8
8 |
9 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // 使用 IntelliSense 了解相关属性。
3 | // 悬停以查看现有属性的描述。
4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Launch",
9 | "type": "go",
10 | "request": "launch",
11 | "mode": "debug",
12 | "remotePath": "",
13 | "port": 2345,
14 | "host": "127.0.0.1",
15 | "program": "${fileDirname}",
16 | "env": {},
17 | "args": [],
18 | "showLog": true
19 | }
20 | ]
21 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/JimYJ/scanproxy)
2 | [](https://goreportcard.com/report/github.com/JimYJ/scanproxy)
3 |
4 | # scanproxy
5 | scanproxy is auto scan IP & port,and check that is proxy if port is open...(scanproxy是一个自动扫描端口,并且检测是否是代理服务器的程序)
6 |
7 | ### Command line parameter:命令行参数
8 |
9 | -a country codes, see ISO 3166-1 (default "CN")
10 | -f scan mode, fast is only scan common port, default is scan all port
11 | -i set scan how many IP segment in same times, it will affect memory footprint (default 10)
12 | -m maximum concurrency number (default 200)
13 |
14 | ### e.g.
15 |
16 | ```
17 | scanproxy_linux_amd64 -a JP -f -m 1000 -i 20
18 | ```
19 |
--------------------------------------------------------------------------------
/build_linux64.bat:
--------------------------------------------------------------------------------
1 | set GOPATH=D:\MyWorkSpace\Gopath
2 | set GOARCH=amd64
3 | set GOOS=linux
4 | go build -v -o scanproxy_linux_amd64
5 | pause
--------------------------------------------------------------------------------
/build_mac64.bat:
--------------------------------------------------------------------------------
1 | set GOPATH=D:\MyWorkSpace\Gopath
2 | set GOARCH=amd64
3 | set GOOS=darwin
4 | go build -v -o scanproxy_mac_amd64
5 | pause
--------------------------------------------------------------------------------
/build_win64.bat:
--------------------------------------------------------------------------------
1 | set GOPATH=D:\MyWorkSpace\Gopath
2 | set GOARCH=amd64
3 | set GOOS=windows
4 | go build -v -o scanproxy_win_amd64.exe
5 | pause
--------------------------------------------------------------------------------
/config.yml:
--------------------------------------------------------------------------------
1 | mysql :
2 | host : your host
3 | port : 3306
4 | user : your user
5 | pass : your pass
6 | name : yser rable
7 |
--------------------------------------------------------------------------------
/config/mysql.go:
--------------------------------------------------------------------------------
1 | package config
2 |
3 | import (
4 | "io/ioutil"
5 | "log"
6 | "sync"
7 |
8 | mysql "github.com/JimYJ/easysql/mysql/v2"
9 | cache "github.com/patrickmn/go-cache"
10 |
11 | "gopkg.in/yaml.v2"
12 | )
13 |
14 | var (
15 | once sync.Once
16 | c *cache.Cache
17 | )
18 |
19 | // 初始化参数
20 | var (
21 | Host, User, Pass, Name string
22 | Port int
23 | )
24 |
25 | // Config 基础配置
26 | type config struct {
27 | MySQL Mysql
28 | }
29 |
30 | // Mysql 数据库配置
31 | type Mysql struct {
32 | Host, User, Pass, Name string
33 | Port int
34 | }
35 |
36 | func init() {
37 | configInit()
38 | MySQL()
39 | }
40 |
41 | func (conf *config) getConfig() *config {
42 | yamlFile, err := ioutil.ReadFile("config.yml")
43 | if err != nil {
44 | log.Fatal("yamlFile.Get err:", err)
45 | return nil
46 | }
47 | err = yaml.Unmarshal(yamlFile, conf)
48 | if err != nil {
49 | log.Fatal("yamlFile.Get err:", err)
50 | return nil
51 | }
52 | return conf
53 | }
54 |
55 | // configInit 获取配置文件
56 | func configInit() {
57 | var conf config
58 | conf.getConfig()
59 | Host = conf.MySQL.Host
60 | Pass = conf.MySQL.Pass
61 | Port = conf.MySQL.Port
62 | User = conf.MySQL.User
63 | Name = conf.MySQL.Name
64 | mysql.Init(Host, Port, Name, User, Pass, "utf8mb4", 500, 500)
65 | mysql.ReleaseMode()
66 | }
67 |
68 | // MySQL 连接数据库
69 | func MySQL() *mysql.MysqlDB {
70 | mysql.UseCache()
71 | mdb, err := mysql.GetMysqlConn()
72 | if err != nil {
73 | log.Fatal(err)
74 | }
75 | return mdb
76 | }
77 |
--------------------------------------------------------------------------------
/dutyfree.sql:
--------------------------------------------------------------------------------
1 | SET NAMES utf8mb4;
2 | SET FOREIGN_KEY_CHECKS = 0;
3 |
4 | -- ----------------------------
5 | -- Table structure for apniciplib
6 | -- ----------------------------
7 | DROP TABLE IF EXISTS `apniciplib`;
8 | CREATE TABLE `apniciplib` (
9 | `id` int(11) NOT NULL AUTO_INCREMENT,
10 | `startip` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
11 | `endip` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
12 | `area` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
13 | `status` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
14 | PRIMARY KEY (`id`) USING BTREE,
15 | INDEX `page`(`id`, `area`) USING BTREE
16 | ) ENGINE = InnoDB AUTO_INCREMENT = 3410333 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
17 |
18 | -- ----------------------------
19 | -- Table structure for proxyip
20 | -- ----------------------------
21 | DROP TABLE IF EXISTS `proxyip`;
22 | CREATE TABLE `proxyip` (
23 | `id` int(11) NOT NULL AUTO_INCREMENT,
24 | `ip` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
25 | `port` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
26 | `protocol` enum('socks4','socks5','https','http') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
27 | `area` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
28 | `createtime` datetime(0) NULL DEFAULT NULL,
29 | `updatetime` datetime(0) NULL DEFAULT NULL,
30 | `status` tinyint(4) NULL DEFAULT NULL,
31 | PRIMARY KEY (`id`) USING BTREE
32 | ) ENGINE = InnoDB AUTO_INCREMENT = 908 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
33 |
34 | -- ----------------------------
35 | -- Table structure for scanrecord
36 | -- ----------------------------
37 | DROP TABLE IF EXISTS `scanrecord`;
38 | CREATE TABLE `scanrecord` (
39 | `id` int(11) NOT NULL AUTO_INCREMENT,
40 | `ipid` int(11) NULL DEFAULT NULL,
41 | `area` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
42 | `startip` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
43 | `createtime` datetime(0) NULL DEFAULT NULL,
44 | `updatetime` datetime(0) NULL DEFAULT NULL,
45 | PRIMARY KEY (`id`) USING BTREE
46 | ) ENGINE = InnoDB AUTO_INCREMENT = 12 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
47 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "log"
6 |
7 | "github.com/JimYJ/scanproxy/config"
8 |
9 | "github.com/JimYJ/scanproxy/scanproxy"
10 | )
11 |
12 | var (
13 | ipStep = 10
14 | area string
15 | ipstep int
16 | mode bool
17 | maxConcurrent int
18 | )
19 |
20 | func main() {
21 | mysql := config.MySQL()
22 | defer mysql.Close()
23 | if mode {
24 | log.Println("now work in fast mode,ip scan step:", ipstep, "area:", area, "maxConcurrent:", maxConcurrent)
25 | scanproxy.SetQueueMaxConcurrent(maxConcurrent)
26 | scanproxy.InternetFastScan(area, ipstep)
27 | } else {
28 | log.Println("now work in normal mode,ip scan step:", ipstep, "area:", area)
29 | scanproxy.InternetAllScan(area, ipstep)
30 | }
31 | }
32 |
33 | func init() {
34 | flag.BoolVar(&mode, "f", false, "scan mode, fast is only scan common port, default is scan all port(shorthand)")
35 | flag.IntVar(&ipstep, "i", 10, "set scan how many IP segment in same times, it will affect memory footprint(shorthand)")
36 | flag.IntVar(&maxConcurrent, "m", 200, "maximum concurrency number(shorthand)")
37 | flag.StringVar(&area, "a", "CN", "country codes, see ISO 3166-1(shorthand)")
38 | flag.Parse()
39 | }
40 |
--------------------------------------------------------------------------------
/scanproxy/checkhttp.go:
--------------------------------------------------------------------------------
1 | package scanproxy
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "log"
7 | "net/http"
8 | "net/url"
9 | "strconv"
10 | "strings"
11 | "time"
12 | )
13 |
14 | var (
15 | timeouts = 10
16 | testWeb = "http://www.zmhui.net/"
17 | testKeyWord = "miaotuApp"
18 | )
19 |
20 | //checkHTTP 测试是否是HTTP代理服务器
21 | func checkHTTP(ip string, port int, protocol string) bool {
22 | strURL := fmt.Sprintf("%v://%v:%v", protocol, ip, port)
23 | proxyURL, err := url.Parse(strURL)
24 | if err == nil {
25 | client := http.Client{
26 | Transport: &http.Transport{
27 | Proxy: http.ProxyURL(proxyURL),
28 | },
29 | Timeout: time.Duration(timeouts) * time.Second,
30 | }
31 | resp, err2 := client.Get(testWeb)
32 | if resp != nil {
33 | defer resp.Body.Close()
34 | }
35 | if err2 == nil {
36 | if resp.StatusCode == http.StatusOK {
37 | body, err3 := ioutil.ReadAll(resp.Body)
38 | // log.Println(string(body))
39 | if err3 == nil && strings.Contains(string(body), testKeyWord) {
40 | return true
41 | }
42 | log.Println("err3:", err3)
43 | }
44 | } else {
45 | log.Println("err2:", err2)
46 | }
47 | } else {
48 | log.Println("err:", err)
49 | }
50 | return false
51 | }
52 |
53 | func checkHTTPForList(iplist *[]map[string]int) *[]map[string]string {
54 | var proxyOK []map[string]string
55 | for i := 0; i < len(*iplist); i++ {
56 | for k, v := range (*iplist)[i] {
57 | if checkHTTP(k, v, "http") {
58 | proxy := map[string]string{"ip": k, "port": strconv.Itoa(v), "protocol": "http"}
59 | proxyOK = append(proxyOK, proxy)
60 | }
61 | if checkHTTP(k, v, "https") {
62 | proxy := map[string]string{"ip": k, "port": strconv.Itoa(v), "protocol": "https"}
63 | proxyOK = append(proxyOK, proxy)
64 | }
65 | }
66 | }
67 | return &proxyOK
68 | }
69 |
--------------------------------------------------------------------------------
/scanproxy/checksocks.go:
--------------------------------------------------------------------------------
1 | package scanproxy
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "log"
7 | "net/http"
8 | "strconv"
9 | "strings"
10 | "time"
11 |
12 | "golang.org/x/net/proxy"
13 | "h12.io/socks"
14 | )
15 |
16 | //checkSocks 测试是否是SOCKS代理,支持SOCKS4,SOCKS4a,SOCKS5
17 | func checkSocks(ip string, port int, protocol int) bool {
18 | strURL := fmt.Sprintf("%v:%v", ip, port)
19 | client := http.Client{
20 | Transport: &http.Transport{
21 | Dial: socks.DialSocksProxy(protocol, strURL),
22 | },
23 | Timeout: time.Duration(timeouts) * time.Second,
24 | }
25 | resp, err := client.Get(testWeb)
26 | if err == nil {
27 | if resp.StatusCode == http.StatusOK {
28 | body, err := ioutil.ReadAll(resp.Body)
29 | if err == nil && strings.Contains(string(body), testKeyWord) {
30 | return true
31 | }
32 | }
33 | } else {
34 | log.Println(err)
35 | if resp != nil {
36 | defer resp.Body.Close()
37 | }
38 | }
39 | return false
40 | }
41 |
42 | //checkSocks5 测试是否是SOCKS5代理
43 | func checkSocks5(ip string, port int, protocol string) bool {
44 | strURL := fmt.Sprintf("%v:%v", ip, port)
45 | dialer, err := proxy.SOCKS5(protocol, strURL, nil, proxy.Direct)
46 | if err == nil {
47 | httpTransport := &http.Transport{}
48 | httpClient := &http.Client{Transport: httpTransport}
49 | httpTransport.Dial = dialer.Dial
50 | resp, err := httpClient.Get(testWeb)
51 | if resp != nil {
52 | defer resp.Body.Close()
53 | }
54 | log.Println(err, resp)
55 | if err == nil {
56 | if resp.StatusCode == http.StatusOK {
57 | body, err := ioutil.ReadAll(resp.Body)
58 | if err == nil && strings.Contains(string(body), testKeyWord) {
59 | return true
60 | }
61 | }
62 | }
63 | }
64 | return false
65 | }
66 |
67 | func checkSocksForList(iplist *[]map[string]int) *[]map[string]string {
68 | var proxyOK []map[string]string
69 | for i := 0; i < len(*iplist); i++ {
70 | for k, v := range (*iplist)[i] {
71 | if checkSocks(k, v, socks.SOCKS4) {
72 | proxy := map[string]string{"ip": k, "port": strconv.Itoa(v), "protocol": "socks4"}
73 | proxyOK = append(proxyOK, proxy)
74 | }
75 | if checkSocks(k, v, socks.SOCKS4A) {
76 | proxy := map[string]string{"ip": k, "port": strconv.Itoa(v), "protocol": "socks4a"}
77 | proxyOK = append(proxyOK, proxy)
78 | }
79 | if checkSocks(k, v, socks.SOCKS5) {
80 | proxy := map[string]string{"ip": k, "port": strconv.Itoa(v), "protocol": "socks5"}
81 | proxyOK = append(proxyOK, proxy)
82 | }
83 | }
84 | }
85 | return &proxyOK
86 | }
87 |
--------------------------------------------------------------------------------
/scanproxy/getip.go:
--------------------------------------------------------------------------------
1 | package scanproxy
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "log"
7 | "strconv"
8 | "strings"
9 | "time"
10 |
11 | "github.com/JimYJ/scanproxy/config"
12 | )
13 |
14 | var (
15 | //ipCount 可扫描IP总数
16 | ipCount int64 = 0
17 | )
18 |
19 | //getApnicIP 获取可扫描IP列表
20 | func getApnicIP(area string, curPage int, prePage int) (*[]map[string]interface{}, int64, int, error) {
21 | mysqlDB := config.MySQL()
22 | paginate, total, totalPage := paginate(area, curPage, prePage)
23 | if total == 0 || totalPage == 0 {
24 | return nil, 0, 0, errors.New("area is error")
25 | }
26 | var query string
27 | restart:
28 | recordID, IPID := getRecord(area)
29 | if area != "" {
30 | query = fmt.Sprintf("select id,startip,area from apniciplib where area = ? and id > ? %s", paginate)
31 | } else {
32 | query = fmt.Sprintf("select id,startip,area from apniciplib where id < ? %s", paginate)
33 | }
34 | iplist, err := mysqlDB.GetResults(query, area, IPID)
35 | if err != nil {
36 | return nil, 0, 0, err
37 | }
38 | if len(iplist) == 0 {
39 | saveRecord(0, recordID, "", area)
40 | goto restart
41 | }
42 | startIP := iplist[len(iplist)-1]["startip"]
43 | id, ok := iplist[len(iplist)-1]["id"].(int64)
44 | if ok {
45 | saveRecord(id, recordID, startIP, area)
46 | } else {
47 | log.Println("get ip list error!")
48 | }
49 | return &iplist, total, totalPage, nil
50 | }
51 |
52 | func paginate(area string, curPage int, prePage int) (string, int64, int) {
53 | if ipCount == 0 {
54 | getIPCount(area)
55 | if ipCount == 0 {
56 | log.Println("area is error!")
57 | return "", 0, 0
58 | }
59 | }
60 | totalPage := getTotalPage(prePage)
61 | if curPage > totalPage {
62 | curPage = totalPage
63 | }
64 | if curPage == 0 || curPage == 1 {
65 | return fmt.Sprintf("limit 0,%d", prePage), ipCount, totalPage
66 | }
67 | start := (curPage - 1) * prePage
68 | return "limit " + strconv.Itoa(start) + "," + strconv.Itoa(prePage), ipCount, totalPage
69 | }
70 |
71 | func getTotalPage(prePage int) int {
72 | totalPage := int(ipCount) / prePage
73 | if int(ipCount)%prePage != 0 {
74 | totalPage++
75 | }
76 | return totalPage
77 | }
78 |
79 | //getIPCount 获取IP总数
80 | func getIPCount(area string) error {
81 | mysqlConn := config.MySQL()
82 | var query string
83 | if area != "" {
84 | query = "select count(id) as count from apniciplib where area = ?"
85 | } else {
86 | query = "select count(id) as count from apniciplib"
87 | }
88 | count, err := mysqlConn.GetVal(query, area)
89 | if err != nil {
90 | return err
91 | }
92 | ipCount = count.(int64)
93 | return nil
94 | }
95 |
96 | //getIPLocalNetwork 获取内网IP列表
97 | func getIPLocalNetwork() []string {
98 | var a int
99 | var iplist = make([]string, 255)
100 | for i := 1; i < 256; i++ {
101 | a = i - 1
102 | iplist[a] = fmt.Sprintf("192.168.10.%d", i)
103 | }
104 | return iplist
105 | }
106 |
107 | func formatInternetIPList(ips interface{}) []string {
108 | ipsatrt, ok := ips.(string)
109 | if !ok {
110 | return nil
111 | }
112 | var iplist = make([]string, 0)
113 | b := strings.Split(ipsatrt, ".")
114 | c := strings.Join(b[0:len(b)-1], ".")
115 | for i := 1; i <= 254; i++ {
116 | iplist = append(iplist, c+"."+strconv.Itoa(i))
117 | }
118 | return iplist
119 | }
120 |
121 | func saveRecord(id, recordID int64, startip interface{}, area string) {
122 | mysqlConn := config.MySQL()
123 | var query string
124 | nowTime := time.Now().Local().Format("2006-01-02 15:04:05")
125 | var err error
126 | for i := 0; i < 3; i++ {
127 | if recordID == 0 {
128 | query = "insert scanrecord set ipid = ?,area = ?,createtime = ?,updatetime = ?,startip = ?"
129 | _, err = mysqlConn.Insert(query, id, area, nowTime, nowTime, startip)
130 | } else {
131 | query = "update scanrecord set ipid = ?,updatetime = ?,startip = ? where id =?"
132 | _, err = mysqlConn.Update(query, id, nowTime, startip, recordID)
133 | }
134 | if err != nil {
135 | log.Println(err)
136 | } else {
137 | break
138 | }
139 | }
140 | }
141 |
142 | func getRecord(area string) (int64, int64) {
143 | mysqlConn := config.MySQL()
144 | query := "select id,ipid from scanrecord where area = ?"
145 | var rs map[string]interface{}
146 | var err error
147 | for i := 0; i < 3; i++ {
148 | err = nil
149 | rs, err = mysqlConn.GetRow(query, area)
150 | if err == nil {
151 | break
152 | }
153 | }
154 | if err != nil {
155 | log.Println(err)
156 | return 0, 0
157 | }
158 | id, ok := rs["id"].(int64)
159 | ipid, ok2 := rs["ipid"].(int64)
160 | if !ok || !ok2 {
161 | return 0, 0
162 | }
163 | return id, ipid
164 | }
165 |
--------------------------------------------------------------------------------
/scanproxy/recover.go:
--------------------------------------------------------------------------------
1 | package scanproxy
2 |
3 | import "log"
4 |
5 | // HandelRecover 异常捕获
6 | func HandelRecover() {
7 | if r := recover(); r != nil {
8 | log.Println("[Fatal]", r)
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/scanproxy/saveproxy.go:
--------------------------------------------------------------------------------
1 | package scanproxy
2 |
3 | import (
4 | "errors"
5 | "log"
6 | "time"
7 |
8 | "github.com/JimYJ/scanproxy/config"
9 | )
10 |
11 | func saveProxy(proxyList *[]map[string]string, area interface{}) (bool, error) {
12 | if proxyList == nil {
13 | return false, errors.New("proxyList is nil")
14 | }
15 | mysqlDB := config.MySQL()
16 | rollBack := false
17 | var err2 error
18 | nowTime := time.Now().Local().Format("2006-01-02 15:04:05")
19 | var proxyExist = make([]int64, len(*proxyList))
20 | for i := 0; i < len(*proxyList); i++ {
21 | checkExist, err := mysqlDB.GetVal("select id from proxyip where ip = ? and port = ? and protocol = ?", (*proxyList)[i]["ip"], (*proxyList)[i]["port"], (*proxyList)[i]["protocol"])
22 | if err != nil || checkExist == nil {
23 | proxyExist[i] = 0
24 | } else {
25 | id, ok := checkExist.(int64)
26 | if ok {
27 | proxyExist[i] = id
28 | } else {
29 | proxyExist[i] = 0
30 | }
31 | }
32 | }
33 | tx, _ := mysqlDB.Begin()
34 | for i := 0; i < len(*proxyList); i++ {
35 | if proxyExist[i] == 0 {
36 | _, err2 = tx.Insert("insert into proxyip set ip = ?,port = ?,protocol = ?,area = ?,status = ?,createtime = ?,updatetime = ?", (*proxyList)[i]["ip"], (*proxyList)[i]["port"], (*proxyList)[i]["protocol"], area, 1, nowTime, nowTime)
37 | } else {
38 | _, err2 = tx.Update("update proxyip set updatetime = ? where id = ?", nowTime, proxyExist[i])
39 | }
40 | if err2 != nil {
41 | rollBack = true
42 | }
43 | }
44 | if rollBack {
45 | tx.Rollback()
46 | return false, err2
47 | }
48 | tx.Commit()
49 | log.Println("save proxy:", proxyList)
50 | return true, nil
51 | }
52 |
--------------------------------------------------------------------------------
/scanproxy/scanport.go:
--------------------------------------------------------------------------------
1 | package scanproxy
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "log"
7 | "net"
8 | "sync"
9 | "time"
10 |
11 | "github.com/JimYJ/go-queue"
12 |
13 | tcp "github.com/tevino/tcp-shaker"
14 | )
15 |
16 | var (
17 | checkPortTimeout = 5 * time.Second
18 | portMax = 65535
19 | step = 1
20 | once sync.Once
21 | queueMaxConcurrent = 1000
22 | fastScanPort = [...]int{3128, 8000, 8888, 8080, 8088, 1080, 9000, 80, 8118, 53281, 54566, 808, 443, 8081, 8118, 65103, 3333, 45619, 65205, 45619, 55379, 65535, 2855, 10200, 22722, 64334, 3654, 53124, 5433}
23 | )
24 |
25 | //checkPort 查询端口是否开放
26 | func checkPort(ipstr string, port int, ch chan map[string]int) {
27 | ip := net.ParseIP(ipstr)
28 | if ip == nil {
29 | log.Println("error IP format:", ipstr)
30 | ch <- nil
31 | }
32 | // tcpAddr := net.TCPAddr{
33 | // IP: ip,
34 | // Port: port,
35 | // }
36 | address := fmt.Sprintf("%v:%v", ip, port)
37 | conn, err := net.DialTimeout("tcp", address, checkPortTimeout) //("tcp", nil, &tcpAddr)
38 | if err == nil {
39 | log.Println("open IP & port", ip, port)
40 | conn.Close()
41 | ch <- map[string]int{string(ipstr): port}
42 | } else {
43 | // log.Println("scan port fail:", ipstr, port)
44 | if conn != nil {
45 | conn.Close()
46 | }
47 | ch <- nil
48 | }
49 | }
50 |
51 | //checkPortBySyn syn方式查询端口是否开放,仅支持linux2.4+
52 | func checkPortBySyn(ipstr string, port int, ch chan map[string]int) {
53 | defer HandelRecover()
54 | ip := net.ParseIP(ipstr)
55 | if ip == nil {
56 | log.Println("error IP format:", ipstr)
57 | ch <- nil
58 | }
59 | address := fmt.Sprintf("%v:%v", ip, port)
60 | checker := tcp.NewChecker(true)
61 | if err := checker.InitChecker(); err != nil {
62 | log.Fatal("Checker init failed:", err)
63 | ch <- nil
64 | }
65 | err := checker.CheckAddr(address, checkPortTimeout)
66 | switch err {
67 | case tcp.ErrTimeout:
68 | // fmt.Println("Connect to host timed out")
69 | ch <- nil
70 | case nil:
71 | log.Println("open IP & port", ip, port)
72 | ch <- map[string]int{ipstr: port}
73 | default:
74 | // if e, ok := err.(*tcp.ErrConnect); ok {
75 | // fmt.Println("Connect to host failed:", e)
76 | // } else {
77 | // fmt.Println("Error occurred while connecting:", err)
78 | // }
79 | ch <- nil
80 | }
81 | }
82 |
83 | //checkPortBySynForQueue syn方式查询端口是否开放,仅支持linux2.4+ 队列专用函数
84 | func checkPortBySynForQueue(value ...interface{}) error {
85 | defer HandelRecover()
86 | if len(value) < 3 {
87 | return errors.New("value len is error")
88 | }
89 | ipstr := value[0].(string)
90 | port := value[1].(int)
91 | ch := value[2].(chan map[string]int)
92 | ip := net.ParseIP(ipstr)
93 | if ip == nil {
94 | log.Println("error IP format:", ipstr)
95 | ch <- nil
96 | }
97 | address := fmt.Sprintf("%v:%v", ip, port)
98 | checker := tcp.NewChecker(true)
99 | if err := checker.InitChecker(); err != nil {
100 | // log.Fatal("Checker init failed:", err)
101 | ch <- nil
102 | }
103 | err := checker.CheckAddr(address, checkPortTimeout)
104 | switch err {
105 | case tcp.ErrTimeout:
106 | // fmt.Println("Connect to host timed out")
107 | ch <- nil
108 | case nil:
109 | log.Println("open IP & port", ip, port)
110 | ch <- map[string]int{ipstr: port}
111 | default:
112 | // if e, ok := err.(*tcp.ErrConnect); ok {
113 | // fmt.Println("Connect to host failed:", e)
114 | // } else {
115 | // fmt.Println("Error occurred while connecting:", err)
116 | // }
117 | ch <- nil
118 | }
119 | return err
120 | }
121 |
122 | func scanPort(iplist *[]string, startPort int, stepMax int) (*[]map[string]int, int) {
123 | ch := make(chan map[string]int, 2000)
124 | var portOkList []map[string]int
125 | var value map[string]int
126 | i := 0
127 | //分阶段扫描端口
128 | for n := startPort; n <= stepMax; n++ {
129 | //循环处理IP段
130 | // log.Println("scan port:", n)
131 | for j := len(*iplist) - 1; j >= 0; j-- {
132 | go checkPortBySyn((*iplist)[j], n, ch)
133 | time.Sleep(1 * time.Millisecond)
134 | i++
135 | }
136 | }
137 | //分阶段回收被BLOCK的协程
138 | // log.Println(i)
139 | for m := 1; m <= i; m++ {
140 | // for value := range ch {
141 | value = <-ch
142 | // log.Println(value)
143 | if value != nil {
144 | portOkList = append(portOkList, value)
145 | }
146 | }
147 | close(ch)
148 | return &portOkList, stepMax
149 | }
150 |
151 | //scanAllPort 分段扫描65535全部端口
152 | func scanAllPort(iplist *[]string) *[]map[string]int {
153 | var stepMax int
154 | var portOkList []map[string]int
155 | for i := 0; i < len(fastScanPort); i++ {
156 | if (step + i) > portMax {
157 | stepMax = portMax
158 | } else {
159 | stepMax = step + i
160 | }
161 | portOpen, endPort := scanPort(iplist, i, stepMax)
162 | i = endPort
163 | if portOpen != nil {
164 | portOkList = append(portOkList, (*portOpen)...)
165 | }
166 | // log.Println(portOkList)
167 | }
168 | return &portOkList
169 | }
170 |
171 | //scanFastPort 快速扫描常用端口,将请求发送到队列
172 | func scanFastPort(iplist *[]string, getarea interface{}, ch chan map[string]int) {
173 | getArea, ok := getarea.(string)
174 | if !ok {
175 | return
176 | }
177 | listenQueueResults(ch, getArea)
178 | for n := 0; n <= len(fastScanPort)-1; n++ {
179 | // log.Println("scan port:", n)
180 | for j := len(*iplist) - 1; j >= 0; j-- {
181 | job := new(queue.Job)
182 | job.ID = time.Now().Local().UnixNano()
183 | job.FuncQueue = checkPortBySynForQueue
184 | job.Payload = []interface{}{(*iplist)[j], fastScanPort[n], ch}
185 | queue.JobQueue <- job
186 | // time.Sleep(1 * time.Second)
187 | }
188 | }
189 | }
190 |
191 | func listenQueueResults(ch chan map[string]int, getArea string) {
192 | once.Do(func() {
193 | go func() {
194 | for {
195 | // for value := range ch {
196 | var portOkList []map[string]int
197 | for i := 0; i < queueMaxConcurrent; i++ {
198 | value := <-ch
199 | // log.Println(value)
200 | if value != nil {
201 | if value != nil {
202 | portOkList = append(portOkList, value)
203 | }
204 | }
205 | }
206 | if portOkList != nil {
207 | go func() {
208 | httpProxy := checkHTTPForList(&portOkList)
209 | socksProxy := checkSocksForList(&portOkList)
210 | allproxyList := append((*httpProxy), (*socksProxy)...)
211 | if allproxyList != nil {
212 | saveProxy(&allproxyList, getArea)
213 | }
214 | }()
215 | }
216 | }
217 | }()
218 | })
219 | }
220 |
221 | //InternetAllScan 全部IP或指定区域IP扫描全端口
222 | func InternetAllScan(area string, ipStep int) {
223 | totalPage := 1
224 | var ipmap *[]map[string]interface{}
225 | var err error
226 | var iplist []string
227 | for i := 1; i <= totalPage; i++ {
228 | iplist = make([]string, 0)
229 | ipmap, _, totalPage, err = getApnicIP(area, i, ipStep)
230 | if err != nil {
231 | log.Fatalln(err)
232 | }
233 | getArea := (*ipmap)[0]["area"]
234 | for m := 0; m < len(*ipmap); m++ {
235 | startip := (*ipmap)[m]["startip"]
236 | log.Println("start scan IP:", startip)
237 | iplist = append(iplist, formatInternetIPList(startip)...)
238 | }
239 | portOpenList := scanAllPort(&iplist)
240 | go func() {
241 | httpProxy := checkHTTPForList(portOpenList)
242 | socksProxy := checkSocksForList(portOpenList)
243 | allproxyList := append((*httpProxy), (*socksProxy)...)
244 | if allproxyList != nil {
245 | saveProxy(&allproxyList, getArea)
246 | }
247 | }()
248 | }
249 | }
250 |
251 | //InternetFastScan 常用代理端口快速扫描
252 | func InternetFastScan(area string, ipStep int) {
253 | totalPage := 1
254 | var ipmap *[]map[string]interface{}
255 | var err error
256 | var iplist []string
257 | queue.InitQueue(queueMaxConcurrent, false, false)
258 | ch := make(chan map[string]int, queueMaxConcurrent)
259 | for i := 1; i <= totalPage; i++ {
260 | iplist = nil
261 | for j := 0; j < 3; j++ {
262 | ipmap, _, totalPage, err = getApnicIP(area, i, ipStep)
263 | if err != nil {
264 | log.Println(err)
265 | } else {
266 | break
267 | }
268 | time.Sleep(10 * time.Second)
269 | }
270 | getArea := (*ipmap)[0]["area"]
271 | for m := 0; m < len(*ipmap); m++ {
272 | startip := (*ipmap)[m]["startip"]
273 | log.Println("start fast scan IP:", startip)
274 | iplist = append(iplist, formatInternetIPList(startip)...)
275 | }
276 | scanFastPort(&iplist, getArea, ch)
277 | time.Sleep(15 * time.Second)
278 | }
279 | }
280 |
281 | //SetQueueMaxConcurrent 设置队列并发数
282 | func SetQueueMaxConcurrent(maxConcurrent int) {
283 | if maxConcurrent < 1 {
284 | return
285 | }
286 | queueMaxConcurrent = maxConcurrent
287 | }
288 |
--------------------------------------------------------------------------------