├── .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 | [![Build Status](https://travis-ci.org/JimYJ/scanproxy.svg?branch=master)](https://travis-ci.org/JimYJ/scanproxy) 2 | [![Go Report Card](https://goreportcard.com/badge/github.com/JimYJ/scanproxy)](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 | --------------------------------------------------------------------------------