我必须通过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
带卷曲的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>
我有一个工作示例:
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("%+vn", 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
中看到我在环境中测试的不同地址。
我使用了一个本地运行的httpbin,我可以看到:
$ 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连接不允许连接到目的地。该程序似乎执行了您询问的正确连接,Messages dial tcp 10.13.13.2:0->93.184.216.34:80
是根据您的IFCONFIG输出正确的。
另外,如果我特别连接到封闭端口,我会得到:
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
表明您的地址正确。