正则匹配IPv4地址

一个IPv4地址.号分成了四部分,每一部分都由8位二进制组成,十进制范围是0-255,即二进制的范围是00000000-11111111

IPv6的格式更加复杂,本节的代码不适用于IPv6。

本节的代码findIPv4.go将分为4个部分,第一部分:

  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "net"
  7. "os"
  8. "path/filepath"
  9. "regexp"
  10. )
  11. func findIp(input string) string {
  12. partIp := "(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])"
  13. grammer := partIp+"\\."+partIp+"\\."+partIp+"\\."+partIp
  14. matchMe := regexp.MustCompile(grammer)
  15. return matchMe.FindString(input)
  16. }

findIPv4.go的代码相对之前的复杂一些,所以需要使用的包比较多。

这部分代码定义的正则表达式,能够匹配IPv4地址,是整个程序的核心,如果你定义的正则表达式不正确,将永远找不到你想要的IPv4地址!

代码中的正则表达式稍后我会解释,在此之前必须了解IPv4地址的结构,比如IPv4的点分十进制表示方法以及每一部分都不能超过255,只有这样你能写出恰当的正则表达式。

正则表达式partIp定义了在一个IPv4地址中,每一部分可能出现的情况,比如可能是250-255的三位数,也可能是200-249,100-199,或者10-99两位数,0-9的个位数,以上的情况必须都考虑在内。

grammer变量定义了IPv4地址的四个部分,每一部分必须匹配partIp

findIPv4.go可以在任意文本文件中帮助你找到IPv4地址。

如果你有特殊需求,比如要搜索特定的IP地址,直接修改findIPv4.go的正则表达式即可。

第二部分:

  1. func main() {
  2. arguments := os.Args
  3. if len(arguments) < 2 {
  4. fmt.Printf("usage: %s logfile\n",filepath.Base(arguments[0]))
  5. os.Exit(1)
  6. }
  7. for _, filename := range arguments[1:] {
  8. f,err := os.Open(filename)
  9. if err != nil {
  10. fmt.Printf("error openning file %s\n",err)
  11. os.Exit(-1)
  12. }
  13. defer f.Close()

首先通过os.Args获取搜索的文件,然后检查命令行参数的长度是否符合要求。接下来通过一个for`循环迭代处理。

第四部分代码:

  1. r := bufio.NewReader(f)
  2. for {
  3. line,err := r.ReadString('\n')
  4. if err == io.EOF {
  5. break
  6. } else if err != nil {
  7. fmt.Printf("error openning file %s\n",err)
  8. break
  9. }

类似于selectColumn.go的代码,我们使用bufio.ReadString*()逐行读取文本。

最后一部分:

  1. ip := findIp(line)
  2. trail := net.ParseIP(ip)
  3. if trail.To4() == nil {
  4. continue
  5. } else {
  6. fmt.Println(ip)
  7. }
  8. }
  9. }
  10. }

对逐行读取的文本执行findIp()函数,netParseIP()会再次确保获取的是有效的IPv4地址。

执行findIPv4.go得到下面的输出:

$ go run findIPv4.go auth.log

116.112.10.1 151.1.51.5 192.168.1.1

其实findIPv4.go会打印出很多重复的行(如果文件中有很多重复的IPv4地址)。我们可以配合UNIX命令对输出进一步处理,可以获得更加清晰直观的结果:

go run findIPv4.go auth.log | sort -rn | uniq -c | sort -rn

38 191.168.1.1

22 182.12.5.1

….

9 10.18.2.64

sort -rnfindIPv4.go的输出作为输入,排序后倒序输出,uniq -c计算重复ip的出现次数,最后sort -rn按照重复ip的出现次数倒叙输出。

再次强调,findIPv4.go的核心是正则表达四的实现。如果正则表达式定义错误了,就会匹配不到你想要的数据,或者匹配到错误的数据。