作者:飞天魔鬼
免责声明:本文仅供学习研究,严禁从事非法活动,任何后果由使用者本人负责。
0x00 简介
在平时使用golang写一些小工具的时候,ip地址解析是必须要使用的功能之一。很多工具解析ip只是简单的生成C段、B段、A段的全部ip地址,并不支持cidr的方式来灵活的生成ip。
比如我们要扫描10.1.1.1/22网段,这时候简单的生成C段B段就不顶事儿了。于是就有了自己实现一个可以将nmap格式的ip地址范围解析生成ip的golang类库的想法。
0x01 TODO
实现可以解析以下ip地址段,获取其包含的全部ip
192.168.0.1
192.168.0.1/24
192.168.0.1-22
192.168.0.*
192.168.0.1,192.168.2.1/24,192.168.3.1-100,192.168.4.*
0x02 实现解析cidr来生成ip
func DealCIDR(cidr string) ([]string, error) {
ip, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return nil, err
}
var ips []string
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); ip_tools(ip) {
ips = append(ips, ip.String())
}
return ips[1 : len(ips)-1], nil
}
func ip_tools(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
1、DealCIDR函数接收一个cidr格式的IP地址范围,使用net库中的ParseCIDR()函数来获取当前cidr的ip地址和该ip地址对应的网络(例如:传入192.0.2.1/24 获得返回192.0.2.1地址和其对应的网络192.0.2.0/24)
2、使用一个for循环来循环遍历该网络地址中包含的所有ip,循环的初始值应该为该网络对应的子网掩码所包含的ip中的第一个,即为ip.Mask(ipnet.Mask)。其中ipnet.Mask为当前网络所对应的子网掩码,使用ip.Mask()即可获取当前网络对应的子网掩码所包含的ip中的第一个。
3、for循环的条件应该是当前网络是否包含当前的ip地址,即为ipnet.Contains(ip)
4、实现ip的自增就要再写一个函数ip_tools来实现。该函数需要传入一个net.IP来实现ip的自增或者自减。这里需要注意的是IP数据类型其实是一个内部为byte类型的切片,而byte类型的最大值为255,只要255再加1,byte就会变成0,所以可以利用这一点来实现ip地址的自增和移位。
0x03 实现解析「*」来批量获取C、B、A段全部ip
func DealAsterisk(s string) ([]string, error) {
i := strings.Count(s, "*")
switch i {
case 1:
return DealCIDR(strings.Replace(s, "*", "1", -1) + "/24")
case 2:
return DealCIDR(strings.Replace(s, "*", "1", -1) + "/16")
case 3:
return DealCIDR(strings.Replace(s, "*", "1", -1) + "/8")
}
return nil, errors.New("wrong Asterisk")
}
1、原理很简单,传入的string我们直接统计其个数,如果为1个则是C段的全部ip,如果为2个则是B段的全部ip,如果为3个则是A段的全部ip。
2、然后调用我们上面写好的DealCIDR函数来直接进行处理即可。
3、如果格式错误则会报错。
0x04 处理「-」,来获取范围内的ip
func DealHyphen(s string) ([]string, error) {
tmp := strings.Split(s, ".")
//TODO 异常处理
if len(tmp) == 4 {
iprange_tmp := strings.Split(tmp[3], "-")
var ips []string
tail, _ := strconv.Atoi(iprange_tmp[1])
for head, _ := strconv.Atoi(iprange_tmp[0]); head <= tail; head++ {
ips = append(ips, tmp[0]+"."+tmp[1]+"."+tmp[2]+"."+strconv.Itoa(head))
}
return ips, nil
} else {
return nil, errors.New("wrong Hyphen")
}
}
原理很简单,将传入的ip范围按点分割,获取到最后的数值之后再依次添加进slice。
0x05 Handler函数
func Handler(s string) ([]string, []error) {
IPstrings := strings.Split(strings.Trim(s, ","), ",")
var ips []string
var err []error
for i := 0; i < len(IPstrings); i++ {
if strings.Contains(IPstrings[i], "*") {
//TODO 192.168.0.*
ips_tmp, err_tmp := DealAsterisk(IPstrings[i])
err = append(err, err_tmp)
ips = append(ips, ips_tmp...)
} else if strings.Contains(IPstrings[i], "/") {
//TODO 192.168.0.1/24
ips_tmp, err_tmp := DealCIDR(IPstrings[i])
err = append(err, err_tmp)
ips = append(ips, ips_tmp...)
} else if strings.Contains(IPstrings[i], "-") {
//TODO 192.668.0.1-255
ips_tmp, err_tmp := DealHyphen(IPstrings[i])
err = append(err, err_tmp)
ips = append(ips, ips_tmp...)
} else {
//TODO singel ip
ips = append(ips, IPstrings[i])
}
}
fmt.Println("hello")
return ips, err
}
将传入的字符串按逗号进行分割,然后判断其中的元素是否含有特定的字符,再调用相应的函数处理即可。
0x06 完整代码
package nmapIPrange
import (
"errors"
"fmt"
"net"
"strconv"
"strings"
)
func DealCIDR(cidr string) ([]string, error) {
ip, ipnet, err := net.ParseCIDR(cidr)
if err != nil {
return nil, err
}
var ips []string
//在循环里创建的所有函数变量共享相同的变量。
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); ip_tools(ip) {
ips = append(ips, ip.String())
}
return ips[1 : len(ips)-1], nil
}
func ip_tools(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
func DealAsterisk(s string) ([]string, error) {
i := strings.Count(s, "*")
switch i {
case 1:
return DealCIDR(strings.Replace(s, "*", "1", -1) + "/24")
case 2:
return DealCIDR(strings.Replace(s, "*", "1", -1) + "/16")
case 3:
return DealCIDR(strings.Replace(s, "*", "1", -1) + "/8")
}
return nil, errors.New("wrong Asterisk")
}
func DealHyphen(s string) ([]string, error) {
tmp := strings.Split(s, ".")
//TODO 异常处理
if len(tmp) == 4 {
iprange_tmp := strings.Split(tmp[3], "-")
var ips []string
tail, _ := strconv.Atoi(iprange_tmp[1])
for head, _ := strconv.Atoi(iprange_tmp[0]); head <= tail; head++ {
ips = append(ips, tmp[0]+"."+tmp[1]+"."+tmp[2]+"."+strconv.Itoa(head))
}
return ips, nil
} else {
return nil, errors.New("wrong Hyphen")
}
}
func Handler(s string) ([]string, []error) {
IPstrings := strings.Split(strings.Trim(s, ","), ",")
var ips []string
var err []error
for i := 0; i < len(IPstrings); i++ {
if strings.Contains(IPstrings[i], "*") {
//TODO 192.168.0.*
ips_tmp, err_tmp := DealAsterisk(IPstrings[i])
err = append(err, err_tmp)
ips = append(ips, ips_tmp...)
} else if strings.Contains(IPstrings[i], "/") {
//TODO 192.168.0.1/24
ips_tmp, err_tmp := DealCIDR(IPstrings[i])
err = append(err, err_tmp)
ips = append(ips, ips_tmp...)
} else if strings.Contains(IPstrings[i], "-") {
//TODO 192.668.0.1-255
ips_tmp, err_tmp := DealHyphen(IPstrings[i])
err = append(err, err_tmp)
ips = append(ips, ips_tmp...)
} else {
//TODO singel ip
ips = append(ips, IPstrings[i])
}
}
fmt.Println("hello")
return ips, err
}
0x07 总结
运行效果:
项目地址:https://github.com/gooderbrother/nmap-IPrange
时间原因有个别异常处理没做,大佬们有时间可以提个issue,记得start。
0x08 了解更多安全知识
欢迎关注我们的安全公众号,学习更多安全知识!!!
欢迎关注我们的安全公众号,学习更多安全知识!!!
欢迎关注我们的安全公众号,学习更多安全知识!!!