Go语言学习#9-如何操作IP地址


=Start=

缘由:

之前在博客中记录过用Python处理过IP地址相关的操作,比如「Python中如何获取当前机器的IP地址」和「Python的netaddr模块使用记录」;还有Java版本的「Java中如何判断一个IP是否在一个网段里面?」。这里记录一下如何用Go 语言进行处理,方便以后使用和参考。

正文:

参考解答:

判断某个IP是否在某个IP区间里面(先转换成IP类型(也即[]byte类型),然后利用bytes.Compare进行比较即可):

package main

import (
    "bytes"
    "fmt"
    "net"
)

var (
    // func ParseIP(s string) IP
    // type IP []byte
    ip1 = net.ParseIP("216.14.49.184")
    ip2 = net.ParseIP("216.14.49.191")
)

func check(ip string) bool {
    trial := net.ParseIP(ip)
    if trial.To4() == nil {
        fmt.Printf("%v is not an IPv4 address\n", trial)
        return false
    }
    // func Compare(a, b []byte) int
    if bytes.Compare(trial, ip1) >= 0 && bytes.Compare(trial, ip2) <= 0 {
        fmt.Printf("%v is between %v and %v\n", trial, ip1, ip2)
        return true
    }
    fmt.Printf("%v is NOT between %v and %v\n", trial, ip1, ip2)
    return false
}

func main() {
    fmt.Printf("value of ip1: %v, type: %T\n", ip1, ip1)
    check("1.2.3.4")
    check("216.14.49.185")
    check("1::16")
}

&

下面的一段代码实现了几个功能:

  • 借助 http://myexternalip.com/raw 获取当前机器的外网IP;
  • 利用 taobao 的API查询IP的地理位置相关信息;
  • 获取本机的内网IP;
  • 将IP字符串转换成整型&将整型转换成IP字符串;
  • 判断IP是否在某个区间内;
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net"
    "net/http"
    "os"
    "strconv"
    "strings"
)

type IPInfo struct {
    Code int `json:"code"`
    Data IP  `json:"data`
}

type IP struct {
    Country   string `json:"country"`
    CountryId string `json:"country_id"`
    Area      string `json:"area"`
    AreaId    string `json:"area_id"`
    Region    string `json:"region"`
    RegionId  string `json:"region_id"`
    City      string `json:"city"`
    CityId    string `json:"city_id"`
    Isp       string `json:"isp"`
}

func main() {

    external_ip := get_external()

    external_ip = strings.Replace(external_ip, "\n", "", -1)
    fmt.Println("公网ip是: ", external_ip)

    fmt.Println("------Dividing Line------")

    ip := net.ParseIP(external_ip)
    if ip == nil {
        fmt.Println("您输入的不是有效的IP地址,请重新输入!")
    } else {
        result := TabaoAPI(string(external_ip))
        if result != nil {
            fmt.Println("国家:", result.Data.Country)
            fmt.Println("地区:", result.Data.Area)
            fmt.Println("城市:", result.Data.City)
            fmt.Println("运营商:", result.Data.Isp)
        }
    }

    fmt.Println("------Dividing Line------")

    GetIntranetIp()

    fmt.Println("------Dividing Line------")

    ip_int := inet_aton(net.ParseIP(external_ip))
    fmt.Println("Convert IPv4 address to decimal number(base 10) :", ip_int)

    ip_result := inet_ntoa(ip_int)
    fmt.Println("Convert decimal number(base 10) to IPv4 address:", ip_result)

    fmt.Println("------Dividing Line------")

    is_between := IpBetween(net.ParseIP("0.0.0.0"), net.ParseIP("255.255.255.255"), net.ParseIP(external_ip))
    fmt.Println("check result: ", is_between)

    fmt.Println("------Dividing Line------")
    is_public_ip := IsPublicIP(net.ParseIP(external_ip))
    fmt.Println("It is public ip: ", is_public_ip)

    is_public_ip = IsPublicIP(net.ParseIP("169.254.85.131"))
    fmt.Println("It is public ip: ", is_public_ip)

    fmt.Println("------Dividing Line------")
    fmt.Println(GetPulicIP())
}

func get_external() string {
    resp, err := http.Get("http://myexternalip.com/raw")
    if err != nil {
        return ""
    }
    defer resp.Body.Close()
    // buf := new(bytes.Buffer)
    // buf.ReadFrom(resp.Body)
    // s := buf.String()
    // return s
    content, _ := ioutil.ReadAll(resp.Body)
    return string(content)
}

func GetIntranetIp() {
    addrs, err := net.InterfaceAddrs()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    for _, address := range addrs {
        // 检查ip地址判断是否回环地址
        if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
            if ipnet.IP.To4() != nil {
                fmt.Println("ip:", ipnet.IP.String())
            }
        }
    }
}

func TabaoAPI(ip string) *IPInfo {
    url := "http://ip.taobao.com/service/getIpInfo.php?ip="
    url += ip

    resp, err := http.Get(url)
    if err != nil {
        return nil
    }
    defer resp.Body.Close()

    out, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return nil
    }
    var result IPInfo
    if err := json.Unmarshal(out, &result); err != nil {
        return nil
    }

    return &result
}

func inet_ntoa(ipnr int64) net.IP {
    var bytes [4]byte
    bytes[0] = byte(ipnr & 0xFF)
    bytes[1] = byte((ipnr >> 8) & 0xFF)
    bytes[2] = byte((ipnr >> 16) & 0xFF)
    bytes[3] = byte((ipnr >> 24) & 0xFF)

    return net.IPv4(bytes[3], bytes[2], bytes[1], bytes[0])
}

func inet_aton(ipnr net.IP) int64 {
    bits := strings.Split(ipnr.String(), ".")

    b0, _ := strconv.Atoi(bits[0])
    b1, _ := strconv.Atoi(bits[1])
    b2, _ := strconv.Atoi(bits[2])
    b3, _ := strconv.Atoi(bits[3])

    var sum int64

    sum += int64(b0) << 24
    sum += int64(b1) << 16
    sum += int64(b2) << 8
    sum += int64(b3)

    return sum
}

func IpBetween(from net.IP, to net.IP, test net.IP) bool {
    if from == nil || to == nil || test == nil {
        fmt.Println("An ip input is nil") // or return an error!?
        return false
    }

    from16 := from.To16()
    to16 := to.To16()
    test16 := test.To16()
    if from16 == nil || to16 == nil || test16 == nil {
        fmt.Println("An ip did not convert to a 16 byte") // or return an error!?
        return false
    }

    if bytes.Compare(test16, from16) >= 0 && bytes.Compare(test16, to16) <= 0 {
        return true
    }
    return false
}

func IsPublicIP(IP net.IP) bool {
    if IP.IsLoopback() || IP.IsLinkLocalMulticast() || IP.IsLinkLocalUnicast() {
        return false
    }
    if ip4 := IP.To4(); ip4 != nil {
        switch true {
        case ip4[0] == 10:
            return false
        case ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31:
            return false
        case ip4[0] == 192 && ip4[1] == 168:
            return false
        default:
            return true
        }
    }
    return false
}

func GetPulicIP() string {
    conn, _ := net.Dial("udp", "8.8.8.8:80")
    defer conn.Close()
    localAddr := conn.LocalAddr().String()
    idx := strings.LastIndex(localAddr, ":")
    return localAddr[0:idx]
}

 

参考链接:

=END=


《“Go语言学习#9-如何操作IP地址”》 有 1 条评论

  1. 全球 IPv4 地址耗尽,IPv6 来了!
    https://mp.weixin.qq.com/s/wMdDiu0o4JfUiqD8hAB75w
    `
    就在昨天,2019 年 11 月 26 日,全球 43 亿个 IPv4 地址正式耗尽,很多人表示忧虑。不过不用担心,IPv4 的下一代 IP 协议 IPv6 将会从根本上解决 IPv4 地址耗尽的问题。

    下面通过一篇长文来了解下什么是 IPv6。

    主要内容包括:
    IPv6 的基本概念
    IPv6 在 Linux 操作系统下的实现
    IPv6 的实验
    IPv6 的过渡技术介绍
    IPv6 在 Linux 平台下 socket 编程应该注意的问题
    实现简易版 TGW 支持 IPv6 雏形 demo
    `

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注