1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "github.com/gookit/color"
  6. "net"
  7. "os"
  8. "regexp"
  9. "strconv"
  10. "strings"
  11. "sync"
  12. )
  13. var (
  14. port int //端口
  15. portRange string //端口范围
  16. parallelCounts int //并行数
  17. )
  18. func init() {
  19. flag.IntVar(&port, "p", 80, "port")
  20. flag.StringVar(&portRange, "r", "", "range ports. eg. 1-65535")
  21. flag.IntVar(&parallelCounts, "n", 50, "parallel counts")
  22. //给默认用法输出,加点自定义的提示
  23. flag.Usage = func() {
  24. fmt.Println("Usege:portscan [options] <ip> \noptions:")
  25. flag.PrintDefaults()
  26. }
  27. flag.Parse()
  28. }
  29. func scanPort(ip net.IP, port int, wg *sync.WaitGroup, parallelChan *chan int) {
  30. defer wg.Done()
  31. tcpAddr := net.TCPAddr{
  32. IP: ip,
  33. Port: port,
  34. }
  35. conn, err := net.DialTCP("tcp", nil, &tcpAddr)
  36. if err == nil {
  37. color.Green.Println("port " + strconv.Itoa(port) + " is opening")
  38. _ = conn.Close()
  39. }
  40. <-*parallelChan //通道不需要接收
  41. }
  42. func main() {
  43. args := flag.Args() //获取命令行参数
  44. if len(args) != 1 { //如果一个参数未输入
  45. flag.Usage() //打印用法
  46. os.Exit(1) //退出
  47. }
  48. //解析IP格式是否为点分十进制,获取命令行第一个参数,注意这里是不包含flag绑定的那几个参数
  49. ip := net.ParseIP(flag.Arg(0))
  50. if ip == nil {
  51. fmt.Println("ip address is not a valid format,please check for this.")
  52. os.Exit(4)
  53. } else {
  54. wg := sync.WaitGroup{} // 用于协程任务控制
  55. if portRange == "" { //没指定端口范围的话,则扫描指定段端口
  56. wg.Add(1)
  57. parallelChan := make(chan int)
  58. go func() {
  59. parallelChan <- 1
  60. }()
  61. go scanPort(ip, port, &wg, &parallelChan)
  62. wg.Wait()
  63. } else { //如果-r参数传入了
  64. //从头匹配数字-数字的格式
  65. matched, _ := regexp.Match(`^\d+-\d+$`, []byte(portRange))
  66. if !matched {
  67. fmt.Println("the ports range is not a valid format,please check for this.")
  68. os.Exit(2)
  69. }
  70. ports := strings.Split(portRange, "-") //-符号分割
  71. startPort, err1 := strconv.Atoi(ports[0]) //字符串转int
  72. endPort, err2 := strconv.Atoi(ports[1])
  73. if err1 != nil || err2 != nil || startPort < 1 || endPort < 2 || endPort <= startPort || parallelCounts < 1 {
  74. flag.Usage()
  75. os.Exit(3)
  76. }
  77. wg.Add(endPort - startPort + 1)
  78. parallelChan := make(chan int, parallelCounts) // 用于控制协程数
  79. for i := startPort; i <= endPort; i++ {
  80. parallelChan <- 1
  81. go scanPort(ip, i, &wg, &parallelChan)
  82. }
  83. wg.Wait()
  84. }
  85. }
  86. }

image.png

优化

输出加上时间戳,加入端口超范围判断。

  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "net"
  6. "os"
  7. "regexp"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. "time"
  12. "github.com/gookit/color"
  13. )
  14. var (
  15. port int //端口
  16. portRange string //端口范围
  17. parallelCounts int //并行数
  18. )
  19. func init() {
  20. flag.IntVar(&port, "p", 80, "port")
  21. flag.StringVar(&portRange, "r", "", "range ports. eg. 1-65535")
  22. flag.IntVar(&parallelCounts, "n", 50, "parallel counts")
  23. //给默认用法输出,加点自定义的提示
  24. flag.Usage = func() {
  25. fmt.Println("Usege:portscan [options] <ip> \noptions:")
  26. flag.PrintDefaults()
  27. }
  28. flag.Parse()
  29. }
  30. func scanPort(ip net.IP, port int, wg *sync.WaitGroup, parallelChan *chan int) {
  31. defer wg.Done()
  32. tcpAddr := net.TCPAddr{
  33. IP: ip,
  34. Port: port,
  35. }
  36. conn, err := net.DialTCP("tcp", nil, &tcpAddr)
  37. if err == nil {
  38. timeStr := time.Now().Format("2006-01-02 15:04:05") //获取时间戳,这是固定写法
  39. color.Cyan.Printf("[%s]", timeStr)
  40. color.Green.Println(" port " + strconv.Itoa(port) + " is opening")
  41. _ = conn.Close()
  42. }
  43. <-*parallelChan //通道不需要接收
  44. }
  45. func main() {
  46. args := flag.Args() //获取命令行参数
  47. if len(args) != 1 { //如果一个参数未输入
  48. flag.Usage() //打印用法
  49. os.Exit(1) //退出
  50. }
  51. //解析IP格式是否为点分十进制,获取命令行第一个参数,注意这里是不包含flag绑定的那几个参数
  52. ip := net.ParseIP(flag.Arg(0))
  53. if ip == nil {
  54. color.Red.Println("ip address is not a valid format, please check for this.")
  55. os.Exit(4)
  56. } else {
  57. wg := sync.WaitGroup{} // 用于协程任务控制
  58. if portRange == "" { //没指定端口范围的话,则扫描-p参数,启用一个协程
  59. if port > 65535 {
  60. color.Red.Println("The port is too big, please check for this.")
  61. os.Exit(6)
  62. }
  63. wg.Add(1)
  64. parallelChan := make(chan int)
  65. go func() {
  66. parallelChan <- 1
  67. }()
  68. go scanPort(ip, port, &wg, &parallelChan)
  69. wg.Wait()
  70. } else { //如果-r参数传入了
  71. //从头匹配数字-数字的格式
  72. matched, _ := regexp.Match(`^\d+-\d+$`, []byte(portRange))
  73. if !matched {
  74. color.Red.Println("the ports range is not a valid format,please check for this.")
  75. os.Exit(2)
  76. }
  77. ports := strings.Split(portRange, "-") //-符号分割
  78. startPort, err1 := strconv.Atoi(ports[0]) //字符串转int
  79. endPort, err2 := strconv.Atoi(ports[1])
  80. if startPort > 65535 || endPort > 65535 {
  81. color.Red.Println("The port is too big, please check for this.")
  82. os.Exit(3)
  83. }
  84. if err1 != nil || err2 != nil || startPort < 1 || endPort < 2 || endPort <= startPort || parallelCounts < 1 {
  85. flag.Usage()
  86. os.Exit(5)
  87. }
  88. wg.Add(endPort - startPort + 1)
  89. parallelChan := make(chan int, parallelCounts) // 用于控制协程数
  90. for i := startPort; i <= endPort; i++ {
  91. parallelChan <- 1
  92. go scanPort(ip, i, &wg, &parallelChan)
  93. }
  94. wg.Wait()
  95. }
  96. }
  97. }

image.png