我必须通过VPN发出http请求。有使用cURL制作我需要的php代码,没有其他要求:
curl_setopt($cu, CURLOPT_INTERFACE, "tun0");
此接口来自ifconfig:
tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500
inet 10.13.13.2 netmask 255.255.255.255 destination 10.13.13.1
inet6 fe80::80ee:132:d102:a52d prefixlen 64 scopeid 0x20<link>
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 100 (UNSPEC)
我的go代码(据我了解,我应该绑定到tun0的ip):
package main
import (
"io/ioutil"
"log"
"net"
"net/http"
"time"
)
func main() {
httpTransport := &http.Transport{}
ief, err := net.InterfaceByName("tun0")
if err != nil {
log.Fatal(err)
}
addrs, err := ief.Addrs()
if err != nil {
log.Fatal(err)
}
tcpAddr := &net.TCPAddr{IP: addrs[0].(*net.IPNet).IP}
println(tcpAddr.String())
httpTransport.Dial = (&net.Dialer{
Timeout: 20 * time.Second,
LocalAddr: tcpAddr,
}).Dial
c := &http.Client{
Transport: httpTransport,
Timeout: 30 * time.Second,
}
req, err := http.NewRequest(
http.MethodGet,
"http://example.com/",
nil,
)
if err != nil {
log.Fatal(err)
}
resp, err := c.Do(req)
if err != nil {
log.Fatal(err)
}
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
println(string(bytes))
}
那我得到的是:
10.13.13.2:0
2019/03/21 15:29:42 Get http://example.com/: dial tcp 10.13.13.2:0->93.184.216.34:80: i/o timeout
exit status 1
带有cUrl的Php代码可快速获取此页面。我用Go代码尝试了很多次,所以超时什么也做不了。有什么想法如何在Go中替换一个PHP字符串吗?
更新
PHP代码通过tun0获取同一页面,并输出:
<?php
$cu = curl_init();
curl_setopt($cu, CURLOPT_URL, "http://example.com");
curl_setopt($cu, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($cu, CURLOPT_CONNECTTIMEOUT, 20);
curl_setopt($cu, CURLOPT_TIMEOUT, 30);
curl_setopt($cu, CURLOPT_INTERFACE, "tun0");
$result = curl_exec($cu);;
curl_close($cu);
echo $result . PHP_EOL;
输出:
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
body {
background-color: #f0f0f2;
margin: 0;
padding: 0;
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
div {
width: 600px;
margin: 5em auto;
padding: 50px;
background-color: #fff;
border-radius: 1em;
}
a:link, a:visited {
color: #38488f;
text-decoration: none;
}
@media (max-width: 700px) {
body {
background-color: #fff;
}
div {
width: auto;
margin: 0 auto;
border-radius: 0;
padding: 1em;
}
}
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is established to be used for illustrative examples in documents. You may use this
domain in examples without prior coordination or asking for permission.</p>
<p><a href="http://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
答案 0 :(得分:0)
我有一个可行的例子:
package main
import (
"fmt"
"io/ioutil"
"net"
"net/http"
)
func main() {
ifname := "tun0"
iface, err := net.InterfaceByName(ifname)
if err != nil {
panic(fmt.Sprintf("could not get interface: %s", err))
}
addrs, err := iface.Addrs()
if err != nil {
panic(fmt.Sprintf("could not get addresses from interface: %s", err))
}
fmt.Printf("%+v\n", addrs)
c := &http.Client{
Transport: &http.Transport{
Dial: (&net.Dialer{
LocalAddr: &net.TCPAddr{
IP: addrs[0].(*net.IPNet).IP,
//IP: net.ParseIP("192.168.0.2"),
//IP: net.ParseIP("127.0.0.1"),
},
}).Dial,
},
}
r, err := c.Get("http://localhost/ip")
if err != nil {
panic(fmt.Sprintf("couldn't get http:%s", err))
}
b, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(fmt.Sprintf("could not read body:%s", err))
}
fmt.Printf("%s", b)
}
您可以在LocalAddr
注释中看到在我的环境中进行测试的不同地址。
我使用了本地运行的this,可以看到以下内容:
$ go run main.go
[myipv6 myipv4]
{"origin":"192.168.0.2"}
在这里,输出的第二行是来自服务器的响应。 如果我更改代码以强制127.0.0.1(如所评论),我会得到:
$ go run main.go
[myipv6 myipv4]
{"origin":"127.0.0.1"}
这意味着服务器确实看到了另一个源地址。
我认为,您的代码有效,但是如您在输出中看到的,您有一个I / O超时。
原因可能是因为您的VPN连接不允许连接到目的地。该程序似乎与您要求的连接正确,根据您的ifconfig输出,消息dial tcp 10.13.13.2:0->93.184.216.34:80
正确。
此外,如果我特别连接到封闭端口,则会得到以下信息:
panic: couldn't get http:Get http://localhost:81/ip: dial tcp 192.168.0.2:0->127.0.0.1:81: connect: connection refused
这表明您的地址正确。