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

我正在使用 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 中做到这一点。有人可以帮助我吗?非常感谢!



DIEA
浏览 429回答 4
4回答

RISEBY

传递network给Control函数的是tcp4IPv4 连接或tcp6IPv6 连接(如果您正在建立传出 TCP 连接)。        // 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 连接的情况下,其他字符串也是可能的。)已知网络是“tcp”、“tcp4”(仅限 IPv4)、“tcp6”(仅限 IPv6)、“udp”、“udp4”(仅限 IPv4)、“udp6”(仅限 IPv6)、“ip” 、“ip4”(仅限 IPv4)、“ip6”(仅限 IPv6)、“unix”、“unixgram”和“unixpacket”。

弑天下

哦。我自己解决了这个问题。我们无法配置强制 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)        }...我为 transport.go 添加了一个 ipv6only 标志,一个 getTcpString() 并且它有效。

30秒到达战场

这适用于 go1.17.1:var (    zeroDialer net.Dialer    httpClient = &http.Client{        Timeout: 10 * time.Second,    })func init() {    transport := http.DefaultTransport.(*http.Transport).Clone()    transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {        return zeroDialer.DialContext(ctx, "tcp4", addr)    }    httpClient.Transport = transport}

慕雪6442864

我认为即使服务器正在侦听“tcp6”,使用“tcp”运行 net.Dial 的客户端也应该可以正常工作——在双栈设置中。当我遇到这个问题时,罪魁祸首是 /etc/hosts。它有一个主机条目,映射到 ipv4 地址而不是 ipv6 地址。这导致连接被拒绝。我的测试示例如下:客户端代码:package mainimport "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 mainimport "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 文件一起正常工作。谢谢。
打开App,查看更多内容
随时随地看视频慕课网APP