检查IP地址是否在私有网络空间中。

huangapple go评论66阅读模式
英文:

Check if IP address is in private network space

问题

我有一个使用Go语言编写的程序,它接受来自客户端的URL,并使用net/http包获取它们。在进行进一步处理之前,我想检查URL是否映射到私有(非可路由/RFC1918网络)地址空间。

一种直接的方法是执行显式的DNS请求,并检查地址是否属于已知的私有范围。之后,执行URL的HTTP GET请求。

有没有更好的方法来实现这一点?最好能够与http.Client集成,以便作为GET请求的一部分执行。

英文:

I have a program in go which accepts URLs from clients and gets them using the net/http package. Before doing further processing, I would like to check if the URL maps to private (non-routable / RFC1918 networks) address space.

The straight-forward way would be to perform an explicit DNS request and check the address for the known private ranges. After that, perform the HTTP GET request for the URL.

Is there a better way to accomplish this? Preferably integrating with http.Client so it can be performed as a part of the GET request.

答案1

得分: 30

你可能还想包括对回环地址(IPv4或IPv6)以及IPv6链路本地或唯一本地地址的检查。以下是一个示例,其中包含RFC1918地址列表以及其他地址,并对它们进行简单的检查,使用isPrivateIP(ip net.IP)函数:

var privateIPBlocks []*net.IPNet

func init() {
    for _, cidr := range []string{
        "127.0.0.0/8",    // IPv4回环地址
        "10.0.0.0/8",     // RFC1918
        "172.16.0.0/12",  // RFC1918
        "192.168.0.0/16", // RFC1918
        "169.254.0.0/16", // RFC3927链路本地地址
        "::1/128",        // IPv6回环地址
        "fe80::/10",      // IPv6链路本地地址
        "fc00::/7",       // IPv6唯一本地地址
    } {
        _, block, err := net.ParseCIDR(cidr)
        if err != nil {
            panic(fmt.Errorf("解析 %q 时出错:%v", cidr, err))
        }
        privateIPBlocks = append(privateIPBlocks, block)
    }
}

func isPrivateIP(ip net.IP) bool {
    if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
        return true
    }

    for _, block := range privateIPBlocks {
        if block.Contains(ip) {
            return true
        }
    }
    return false
}

这段代码定义了一个privateIPBlocks变量,其中包含了RFC1918地址以及其他地址的列表。在init()函数中,将这些地址解析为*net.IPNet类型,并将它们添加到privateIPBlocks中。isPrivateIP(ip net.IP)函数用于检查给定的IP地址是否为私有地址。它首先检查IP地址是否为回环地址、链路本地单播地址或链路本地多播地址,如果是,则返回true。然后,它遍历privateIPBlocks中的每个地址块,检查给定的IP地址是否包含在其中,如果是,则返回true。如果IP地址既不是回环地址、链路本地单播地址或链路本地多播地址,也不包含在privateIPBlocks中的任何地址块中,则返回false

英文:

You might also want to include checks for loopback (IPv4 or IPv6) and/or IPv6 link-local or unique-local addresses. Here is an example with a list of RFC1918 address plus these others and a simple check against them as isPrivateIP(ip net.IP):

var privateIPBlocks []*net.IPNet

func init() {
	for _, cidr := range []string{
		"127.0.0.0/8",    // IPv4 loopback
		"10.0.0.0/8",     // RFC1918
		"172.16.0.0/12",  // RFC1918
		"192.168.0.0/16", // RFC1918
		"169.254.0.0/16", // RFC3927 link-local
		"::1/128",        // IPv6 loopback
		"fe80::/10",      // IPv6 link-local
		"fc00::/7",       // IPv6 unique local addr
	} {
		_, block, err := net.ParseCIDR(cidr)
		if err != nil {
			panic(fmt.Errorf("parse error on %q: %v", cidr, err))
		}
		privateIPBlocks = append(privateIPBlocks, block)
	}
}

func isPrivateIP(ip net.IP) bool {
    if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
        return true
    }

    for _, block := range privateIPBlocks {
    	if block.Contains(ip) {
	    	return true
  		}
    }
    return false
  }

答案2

得分: 10

这应该在Go 1.17(2021年第四季度,5年后)更容易实现,正如Go 101所报道的:

请参阅提交 c73fcccCL 272668

> ## net: 添加 IP.IsPrivate()
>
> 添加 IsPrivate() 助手函数,用于根据 RFC 1918 和 RFC 4193 检查 IP 是否为私有地址。

这修复了由Aaran McGuire提出的golang问题29146

> net包似乎有很多用于报告IP地址的助手函数,例如:
>
> - IsLoopback()
> - IsMulticast()
> - IsInterfaceLocalMulticast()
>
> 但是没有助手函数来报告IP地址是否在私有范围内(RFC 1918RFC 4193)。

英文:

That should be easier to do with Go 1.17 (Q4 2021, 5 years later), as reported by Go 101:

See commit c73fccc and CL 272668:

> ## net: add IP.IsPrivate()
>
> Add IsPrivate() helper to check if an IP is private according to RFC 1918 & RFC 4193

That fixes golang issue 29146 raised by Aaran McGuire:

> The net package seems to have many helpers to report what an IP is. e.g:
>
> - IsLoopback()
> - IsMulticast()
> - IsInterfaceLocalMulticast()
>
> However there are no helpers to report if a IP address is in the private ranges (RFC 1918 & RFC 4193).

答案3

得分: 4

package main

import (
	"fmt"
	"net"
)

func main() {
	fmt.Println(privateIPCheck("1.1.1.1"))  // False,因为这不是私有IP
	fmt.Println(privateIPCheck("10.8.0.1")) // True,因为这是私有IP
}

// 检查IP是否为私有IP
func privateIPCheck(ip string) bool {
	ipAddress := net.ParseIP(ip)
	return ipAddress.IsPrivate()
}

这需要 Go 1.17 版本。

英文:
package main

import (
	"fmt"
	"net"
)

func main() {
	fmt.Println(privateIPCheck("1.1.1.1"))  // False since this is not a private IP
	fmt.Println(privateIPCheck("10.8.0.1")) // True: Since this is a private ip.
}

// Check if a ip is private.
func privateIPCheck(ip string) bool {
	ipAddress := net.ParseIP(ip)
	return ipAddress.IsPrivate()
}

This requires Go 1.17.

答案4

得分: 2

似乎没有比我描述的更好的方法来完成这个任务。结合@MichaelHausenblas的代码和@JimB的建议,我的代码最终变成了这样。

func privateIP(ip string) (bool, error) {
    var err error
    private := false
    IP := net.ParseIP(ip)
    if IP == nil {
        err = errors.New("Invalid IP")
    } else {
        _, private24BitBlock, _ := net.ParseCIDR("10.0.0.0/8")
        _, private20BitBlock, _ := net.ParseCIDR("172.16.0.0/12")
        _, private16BitBlock, _ := net.ParseCIDR("192.168.0.0/16")
        private = private24BitBlock.Contains(IP) || private20BitBlock.Contains(IP) || private16BitBlock.Contains(IP)
    }
    return private, err
}
英文:

It seems there's no better way to accomplish than the one I described. Combining code from @MichaelHausenblas with the suggestion from @JimB, my code ended up kind of like this.

func privateIP(ip string) (bool, error) {
	var err error
	private := false
	IP := net.ParseIP(ip)
	if IP == nil {
		err = errors.New("Invalid IP")
	} else {
		_, private24BitBlock, _ := net.ParseCIDR("10.0.0.0/8")
		_, private20BitBlock, _ := net.ParseCIDR("172.16.0.0/12")
		_, private16BitBlock, _ := net.ParseCIDR("192.168.0.0/16")
		private = private24BitBlock.Contains(IP) || private20BitBlock.Contains(IP) || private16BitBlock.Contains(IP)
	}
	return private, err
}

huangapple
  • 本文由 发表于 2016年12月20日 19:01:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/41240761.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定