golang强制net / http客户端使用IPv4 / IPv6

时间:2018-10-30 00:39:16

标签: go web-crawler

我正在使用go1.11 net / http,想确定某个域是否仅为ipv6。

您做了什么?

我创建自己的DialContext是因为我想检测域是否仅为ipv6。下面的代码

package main
import (
    "errors"
    "fmt"
    "net"
    "net/http"
    "syscall"
    "time"
)
func ModifiedTransport() {
    var MyTransport = &http.Transport{
        DialContext: (&net.Dialer{
            Timeout:   30 * time.Second,
            KeepAlive: 30 * time.Second,
            DualStack: false,
            Control: func(network, address string, c syscall.RawConn) error {
                if network == "ipv4" {
                    // I want to  cancel connection here client.Get("http://myexample.com") return a non-nil err.
                    return errors.New("you should not use ipv4")
                }
                return nil
            },
        }).DialContext,
        MaxIdleConns:          100,
        IdleConnTimeout:       90 * time.Second,
        TLSHandshakeTimeout:   10 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
    }
    var myClient = http.Client{Transport: MyTransport}
    resp, myerr := myClient.Get("http://www.github.com")
    if myerr != nil {
        fmt.Println("request error")
        return 
    }
    var buffer = make([]byte, 1000)
    resp.Body.Read(buffer)
    fmt.Println(string(buffer))
}
func main(){
    ModifiedTransport();
}

即使我可以进入network == "ipv4",我现在也不怎么关闭请求。

添加

Python可以通过Force requests to use IPv4 / IPv6解决问题。我不知道该怎么做在golang中。有人可以帮我吗? 非常感谢!

3 个答案:

答案 0 :(得分:1)

传递给network函数的Control是用于IPv4连接的tcp4或用于IPv6连接的tcp6(如果要建立传出TCP连接)。 / p>

摘自type Dialer的评论:

        // Network and address parameters passed to Control method are not
        // necessarily the ones passed to Dial. For example, passing "tcp" to Dial
        // will cause the Control function to be called with "tcp4" or "tcp6".

(在非TCP连接的情况下,可以使用other strings。)

  

已知网络为“ tcp”,“ tcp4”(仅IPv4),“ tcp6”(仅IPv6),“ udp”,“ udp4”(仅IPv4),“ udp6”(仅IPv6), “ ip”,“ ip4”(仅IPv4),“ ip6”(仅IPv6),“ unix”,“ unixgram”和“ unixpacket”。

答案 1 :(得分:0)

哦。我自己解决了问题。

我们无法配置强制ipv6连接,因为它是硬编码的

...
if cm.scheme() == "https" && t.DialTLS != nil {
        var err error
        pconn.conn, err = t.DialTLS("tcp", cm.addr())
        if err != nil {
            return nil, wrapErr(err)
        }
...

code here。)

我为transport.go添加了一个ipv6only标志,一个getTcpString()即可。

diff here

答案 2 :(得分:0)

我认为即使服务器正在侦听“ tcp6”,运行net.Dial的客户端也应该可以正常工作-在双堆栈设置中。

当我遇到这个问题时,罪魁祸首是/ etc / hosts。它具有映射到ipv4地址而不是ipv6地址的主机条目。这导致连接被拒绝。

我的测试示例如下:

客户代码:

package main

import "net"
import "fmt"

func main() {
    conn, err := net.Dial("tcp", "hostname:9876")
    if err != nil {
        fmt.Println("Error in net.Dial", err)
        return
    }

    conn.Close()
    fmt.Println("Successful")
}

服务器代码:

package main

import "net"
import "fmt"

func main() {
    lis, err := net.Listen("tcp6", ":9876")
    if err != nil {
        fmt.Println("Error in listen", err)
        return
    }

    for {
        _, err := lis.Accept()
        if err != nil {
            fmt.Println("Error in Accept", err)
            return
        }
    }
}

此代码在双堆栈设置中的干净的/ etc / hosts文件中应该可以正常工作。

谢谢。