使用指定的以太网IP地址进行HTTP请求。

huangapple go评论81阅读模式
英文:

make http request with a specified ethernet ip

问题

我在我的机器上有几个公共IP地址。我想指定使用哪一个IP地址进行请求。

我可以使用curl命令来实现:

curl --interface 111.222.333.444 https://www.iplocation.net/find-ip-address | grep "Your IP address"

其中111.222.333.444是我用于向互联网发出请求的本地IP地址之一。

如何在golang中实现相同的功能?

#这个方法...

package main

import (
    "bytes"
    "fmt"
    "github.com/PuerkitoBio/goquery"
    "io/ioutil"
    "net"
    "net/http"
    "os"
    "time"
)

func main() {
    var localAddr = "111.222.333.444"
    localAddress, _ := net.ResolveTCPAddr("tcp", localAddr)

    // 创建一个类似http.DefaultTransport的传输对象,但指定了localAddr
    transport := &http.Transport{
        Proxy: http.ProxyFromEnvironment,
        Dial: (&net.Dialer{
            Timeout:   30 * time.Second,
            KeepAlive: 30 * time.Second,
            LocalAddr: localAddress,
        }).Dial,
        TLSHandshakeTimeout: 10 * time.Second,
    }

    client := &http.Client{
        Transport: transport,
    }

    response, err := client.Get("https://www.whatismyip.com/")

    if err != nil {
        fmt.Printf("%s", err)
        os.Exit(1)
    } else {
        defer response.Body.Close()
        contents, err := ioutil.ReadAll(response.Body)
        if err != nil {
            fmt.Printf("%s", err)
            os.Exit(1)
        }
        var contentsStr = string(contents)
        fmt.Printf("%s\n", contentsStr)
        var doc = DocByHtmlString(contentsStr)

        doc.Find("div").Each(func(i int, s *goquery.Selection) {
            attr, exists := s.Attr("class")
            if exists {
                if attr == "ip" {
                    fmt.Println(s.Text())
                    fmt.Println("expected ip is " + localAddr)
                }
            }
        })
    }
}

func DocByHtmlString(html string) *goquery.Document {
    doc, err := goquery.NewDocumentFromReader(bytes.NewBufferString(html))
    if err != nil {
        panic(err)
    }
    return doc
}

...总是给我返回以下结果:

Your IP Address Is: 555.666.777.888 // 我机器上的主IP地址
expected ip is 111.222.333.444

#另一种方法

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net"
)

func main() {
    ief, err := net.InterfaceByName("eth0")
    if err != nil {
        log.Fatal(err)
    }
    addrs, err := ief.Addrs()
    if err != nil {
        log.Fatal(err)
    }
    tcpAddr := &net.TCPAddr{
        IP: addrs[3].(*net.IPNet).IP,
        // Port: 8080,
    }
    d := net.Dialer{LocalAddr: tcpAddr}
    conn, err2 := d.Dial("tcp", "www.whatismyip.com:80")
    if err2 != nil {
        log.Fatal(err2)
    }
    fmt.Println(`conn.LocalAddr()`)
    fmt.Println(conn.LocalAddr())
    fmt.Println(`conn.RemoteAddr()`)
    fmt.Println(conn.RemoteAddr())
    defer conn.Close()
    bytesResult, err3 := ioutil.ReadAll(conn)
    if err3 != nil {
        log.Fatal(err3)
    }
    fmt.Println(`string(bytesResult)`)
    fmt.Println(string(bytesResult))
}

输出结果为:

conn.LocalAddr()
111.222.333.213:37036 
conn.RemoteAddr()
141.101.120.15:80
                     // 15秒的暂停
string(bytesResult)
                     // 空字符串

#ifconfig

Ubuntu 14.04.3 LTS (GNU/Linux 3.13.0-63-generic x86_64)

$ ifconfig
eth0      Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.208  Bcast:111.222.333.255  Mask:255.255.255.0
          inet6 addr: de90::216:3cff:fe56:698c/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:942000 errors:0 dropped:0 overruns:0 frame:0
          TX packets:336708 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:133860794 (133.8 MB)  TX bytes:84577381 (84.5 MB)

eth0:0    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.209  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:1    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.212  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:2    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.213  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:3    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.216  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:4    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.217  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:5    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.220  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:6    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.221  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:7    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.224  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:8    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.225  Bcast:111.222.333.255  Mask:255.255.255.0

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
英文:

I have several public ip addresses on my machine. I want to specify which one to use for a request.

I can do it using curl:

curl --interface 111.222.333.444 https://www.iplocation.net/find-ip-address | grep "Your IP address"

where 111.222.333.444 is one of my local ip addresses which I am using to make requests to the internet.

How to do the same using golang?

#This method...

package main

import (
	"bytes"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"time"
)

func main() {
	var localAddr = "111.222.333.444"
	localAddress, _ := net.ResolveTCPAddr("tcp", localAddr)

	// Create a transport like http.DefaultTransport, but with a specified localAddr
	transport := &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
			LocalAddr: localAddress,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
	}

	client := &http.Client{
		Transport: transport,
	}

	response, err := client.Get("https://www.whatismyip.com/")

	if err != nil {
		fmt.Printf("%s", err)
		os.Exit(1)
	} else {
		defer response.Body.Close()
		contents, err := ioutil.ReadAll(response.Body)
		if err != nil {
			fmt.Printf("%s", err)
			os.Exit(1)
		}
		var contentsStr = string(contents)
		fmt.Printf("%s\n", contentsStr)
		var doc = DocByHtmlString(contentsStr)

		doc.Find("div").Each(func(i int, s *goquery.Selection) {
			attr, exists := s.Attr("class")
			if exists {
				if attr == "ip" {
					fmt.Println(s.Text())
					fmt.Println("expected ip is " + localAddr)
				}
			}
		})
	}
}

func DocByHtmlString(html string) *goquery.Document {
	doc, err := goquery.NewDocumentFromReader(bytes.NewBufferString(html))
	if err != nil {
		panic(err)
	}
	return doc
}

... gives me always the following result:

Your IP Address Is: 555.666.777.888 // main IP address on my machine
expected ip is 111.222.333.444

#Another method

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net"
)

func main() {
	ief, err := net.InterfaceByName("eth0")
	if err != nil {
		log.Fatal(err)
	}
	addrs, err := ief.Addrs()
	if err != nil {
		log.Fatal(err)
	}
	tcpAddr := &net.TCPAddr{
		IP: addrs[3].(*net.IPNet).IP,
		// Port: 8080,
	}
	d := net.Dialer{LocalAddr: tcpAddr}
	conn, err2 := d.Dial("tcp", "www.whatismyip.com:80")
	if err2 != nil {
		log.Fatal(err2)
	}
	fmt.Println(`conn.LocalAddr()`)
	fmt.Println(conn.LocalAddr())
	fmt.Println(`conn.RemoteAddr()`)
	fmt.Println(conn.RemoteAddr())
	defer conn.Close()
	bytesResult, err3 := ioutil.ReadAll(conn)
	if err3 != nil {
		log.Fatal(err3)
	}
	fmt.Println(`string(bytesResult)`)
	fmt.Println(string(bytesResult))
}

gives output

conn.LocalAddr()
111.222.333.213:37036 
conn.RemoteAddr()
141.101.120.15:80
                     // 15 seconds pause
string(bytesResult)
                     // empty string

#ifcongif

Ubuntu 14.04.3 LTS (GNU/Linux 3.13.0-63-generic x86_64)

$ ifconfig
eth0      Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.208  Bcast:111.222.333.255  Mask:255.255.255.0
          inet6 addr: de90::216:3cff:fe56:698c/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:942000 errors:0 dropped:0 overruns:0 frame:0
          TX packets:336708 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:133860794 (133.8 MB)  TX bytes:84577381 (84.5 MB)

eth0:0    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.209  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:1    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.212  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:2    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.213  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:3    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.216  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:4    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.217  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:5    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.220  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:6    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.221  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:7    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.224  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

eth0:8    Link encap:Ethernet  HWaddr 00:18:3c:96:69:8c  
          inet addr:111.222.333.225  Bcast:111.222.333.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

答案1

得分: 3

谢谢 @JimB。工作解决方案:

package main

import (
	"bytes"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"time"
)

func main() {
	ief, err := net.InterfaceByName("eth0")
	if err != nil {
		log.Fatal(err)
	}
	addrs, err := ief.Addrs()
	if err != nil {
		log.Fatal(err)
	}
	tcpAddr := &net.TCPAddr{
		IP: addrs[3].(*net.IPNet).IP, // 选择第3个IP地址
	}
	d := net.Dialer{LocalAddr: tcpAddr}
	conn, err2 := d.Dial("tcp", "www.whatismyip.com:80")
	if err2 != nil {
		log.Fatal(err2)
	}
	fmt.Println(`conn.LocalAddr()`)
	fmt.Println(conn.LocalAddr())
	fmt.Println(`conn.RemoteAddr()`)
	fmt.Println(conn.RemoteAddr())
	defer conn.Close()

	transport := &http.Transport{
		Proxy:               http.ProxyFromEnvironment,
		Dial:                (&net.Dialer{LocalAddr: tcpAddr}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
	}

	client := &http.Client{
		Transport: transport,
	}

	response, err := client.Get("https://www.whatismyip.com/")

	if err != nil {
		fmt.Printf("%s", err)
		os.Exit(1)
	} else {
		defer response.Body.Close()
		contents, err := ioutil.ReadAll(response.Body)
		if err != nil {
			fmt.Printf("%s", err)
			os.Exit(1)
		}
		var contentsStr = string(contents)
		fmt.Printf("%s\n", contentsStr)
		var doc = DocByHtmlString(contentsStr)

		doc.Find("div").Each(func(i int, s *goquery.Selection) {
			attr, exists := s.Attr("class")
			if exists {
				if attr == "ip" {
					fmt.Println(s.Text())
				}
			}
		})
	}
}

func DocByHtmlString(html string) *goquery.Document {
	doc, err := goquery.NewDocumentFromReader(bytes.NewBufferString(html))
	if err != nil {
		panic(err)
	}
	return doc
}

最后打印出Your IP Address Is: 111.222.333.213,与预期一致。

英文:

Thank you @JimB. Working solution:

package main
import (
"bytes"
"fmt"
"github.com/PuerkitoBio/goquery"
"io/ioutil"
"log"
"net"
"net/http"
"os"
"time"
)
func main() {
ief, err := net.InterfaceByName("eth0")
if err != nil {
log.Fatal(err)
}
addrs, err := ief.Addrs()
if err != nil {
log.Fatal(err)
}
tcpAddr := &net.TCPAddr{
IP: addrs[3].(*net.IPNet).IP, // Choosing ip address number 3
}
d := net.Dialer{LocalAddr: tcpAddr}
conn, err2 := d.Dial("tcp", "www.whatismyip.com:80")
if err2 != nil {
log.Fatal(err2)
}
fmt.Println(`conn.LocalAddr()`)
fmt.Println(conn.LocalAddr())
fmt.Println(`conn.RemoteAddr()`)
fmt.Println(conn.RemoteAddr())
defer conn.Close()
transport := &http.Transport{
Proxy:               http.ProxyFromEnvironment,
Dial:                (&net.Dialer{LocalAddr: tcpAddr}).Dial,
TLSHandshakeTimeout: 10 * time.Second,
}
client := &http.Client{
Transport: transport,
}
response, err := client.Get("https://www.whatismyip.com/")
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
} else {
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
}
var contentsStr = string(contents)
fmt.Printf("%s\n", contentsStr)
var doc = DocByHtmlString(contentsStr)
doc.Find("div").Each(func(i int, s *goquery.Selection) {
attr, exists := s.Attr("class")
if exists {
if attr == "ip" {
fmt.Println(s.Text())
}
}
})
}
}
func DocByHtmlString(html string) *goquery.Document {
doc, err := goquery.NewDocumentFromReader(bytes.NewBufferString(html))
if err != nil {
panic(err)
}
return doc
}

Prints in the end Your IP Address Is: 111.222.333.213 as expected.

huangapple
  • 本文由 发表于 2015年9月11日 16:04:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/32518539.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定