I'm trying to use specific source IP port, but net.DialTimeout does not have laddr parameter
my_dial, err := net.DialTimeout("tcp", addr, 3*time.Second)
conn := tls.Client(my_dial, tlsconf)
Then I checked the document, the only method that support laddr is:
func DialIP(network string, laddr, raddr *IPAddr) (*IPConn, error)
But it returns net.IPConn instead of net.Conn.
Any ideas?
Dial and DialTimeout are just helpers around the net.Dialer type, which has all the available options documented.
You can set a local address and the timeout. The Dialer also has a DialContext method to use a context directly rather than a timeout if desired.
d := net.Dialer{
LocalAddr: lAddr,
Timeout: timeout,
}
conn, err := d.Dial(network, address)
...
Related
I'd like to create a fake gRPC service for testing such that my main code won't break when it executes:
conn, err := grpc.Dial(addr, grpcOpts...)
I found a few examples (e.g., 1, 2) but it doesn't generate addr of this fake gRPC that could use to pass into grpc.Dial method:
listener, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalln(err)
}
server := grpc.NewServer()
pb.RegisterDepositServiceServer(server, &account.DepositServer{})
log.Fatalln(server.Serve(listener))
I.e., it listens to a preconfigured port and creates a server without a real address. What I want instead is:
fakeGRPCService := grpc.NewServer(%random_address that I can either pass explicitly or it'll be generated randomly%)
config.service_1_addr = fakeGRPCService.addr
startCoreService(config) // where conn, err := grpc.Dial(addr, grpcOpts...) will be executed
Update: what I probably want is:
listener, err := net.Listen("tcp", ":50051")
server := grpc.NewServer()
server.Serve(listener)
As net.DialTCP seems like the only way to get net.TCPConn, I'm not sure how to set timeouts while doing the DialTCP. https://golang.org/pkg/net/#DialTCP
func connectAddress(addr *net.TCPAddr, wg *sync.WaitGroup) error {
start := time.Now()
conn, err := net.DialTCP("tcp", nil, addr)
if err != nil {
log.Printf("Dial failed for address: %s, err: %s", addr.String(), err.Error())
return err
}
elasped := time.Since(start)
log.Printf("Connected to address: %s in %dms", addr.String(), elasped.Nanoseconds()/1000000)
conn.Close()
wg.Done()
return nil
}
Use net.Dialer with either the Timeout or Deadline fields set.
d := net.Dialer{Timeout: timeout}
conn, err := d.Dial("tcp", addr)
if err != nil {
// handle error
}
A variation is to call Dialer.DialContext with a deadline or timeout applied to the context.
Type assert to *net.TCPConn if you specifically need that type instead of a net.Conn:
tcpConn, ok := conn.(*net.TCPConn)
One can use net.DialTimeout:
func DialTimeout(network, address string, timeout time.Duration) (Conn, error)
DialTimeout acts like Dial but takes a timeout.
The timeout includes name resolution, if required. When using TCP, and the
host in the address parameter resolves to multiple IP addresses, the timeout
is spread over each consecutive dial, such that each is given an appropriate
fraction of the time to connect.
See func Dial for a description of the network and address parameters.
I'm working on a Go program that sends out a UDP broadcast to query existence of devices on the local network and then reads the replies. Using Wireshark I confirm that the packet is broadcast and that the single device on (my) network replies (ten times, in fact) but my application blocks on the read as if it does not see the incoming packet. Here is the code:
func Discover(timeout int) ([]string, error) {
inBuf := make([]byte, 1024)
devices := make([]string, 0)
var readLen int
var fromAddr *net.UDPAddr
// get server connection
server := fmt.Sprintf("%s:%d", bcastIP, udpDiscoverPort) // "255.255.255.255", 10000
serverAddr, err = net.ResolveUDPAddr("udp", server)
checkErr(err)
ourAddr, err = net.ResolveUDPAddr("udp", "192.168.1.132:10000")
checkErr(err)
conn, err = net.DialUDP("udp", ourAddr, serverAddr)
checkErr(err)
defer conn.Close()
// send the Discover message
discoverMsg := []byte(magic)
discoverMsg = append(discoverMsg, discovery...)
sendLen, err := conn.Write(discoverMsg)
checkErr(err)
fmt.Println("Sent", sendLen, "bytes")
// read one reply
readLen, fromAddr, err = conn.ReadFromUDP(inBuf)
fmt.Println("Read ", readLen, "bytesfrom ", fromAddr)
txtutil.Dump(string(inBuf[:readLen]))
return devices, nil
}
checkErr(err) prints a diagnostic and exits if err is not nil, BTW.
The information in the replies looks like:
Internet Protocol Version 4, Src: 192.168.1.126 (192.168.1.126), Dst: 192.168.1.132 (192.168.1.132)
User Datagram Protocol, Src Port: ndmp (10000), Dst Port: ndmp (10000)
I have tried "0.0.0.0:10000", ":10000" and "127.0.0.1:10000" in place of "192.168.1.132:10000" and none seem to make any difference.
Any suggestions as to what I'm doing wrong are welcome!
You need to use ListenUDP instead of DialUDP. When you use DialUDP, it creates a "connected" UDP port, and only packets originating from the remote address are returned on read.
conn, err = net.ListenUDP("udp", ourAddr)
Since the connection doesn't have a default destination, you will also need to use WriteTo* methods to send packets:
sendLen, err := conn.WriteToUDP(discoverMsg, serverAddr)
I've bound several vpn on the server which is ppp0 ~ ppp4.
Now comes the problem.I want to start 5 progresses each one use the difference network interface.
proc0 -> ppp0
proc1 -> ppp1
proc2 -> ppp2
proc3 -> ppp3
proc4 -> ppp4
I now how to do this with c language.Just use setsockopt with parameter SO_BINDTODEVICE.
But how to do this with net package in golang?
You probably want net.Interfaces() to get a slice of net.Interface() representing the network interfaces on your system, or, as you know the interface names, you can use net.InterfaceByName() to get a particular net.Interface.
ppp0, err := net.InterfaceByName("ppp0")
You can then call Interface.Addrs() on the returned net.Interface and get the interface's IP address(es).
addrs, err := ppp0.Addrs()
You can then use the desired address in the rest of your code (probably using net.ListenIP or net.DialIP.
addr, err := net.ResolveIPAddr("ip4", addrs[0])
// check err
conn, err := net.ListenIP("ip4:pptp", addr)
// check err, then do stuff with conn
Regarding doing this for more than one interface concurrently, you can launch a goroutine for each listener / interface, and move the traffic over channels, but this really depends on what you want to do. (are you just logging the data, sending the data, modifying the data etc.)
The dialer's LocalAddr doesn't work for ppp interfaces, we should set the SOL_SOCKET flag to socket using setsockopt, for go 1.11+ you can create a dialer like this
dialer := net.Dialer{
Control: func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
err := syscall.SetsockoptString(int(fd), syscall.SOL_SOCKET, 25, "ppp0")
if err != nil {
log.Printf("control: %s", err)
return
}
})
},
}
// use the dialer
When I run this code an incoming UDP packet gets read in, however no packet gets sent back out. Why is this? (I verified this fact with wireshark). I want to be able to communicate two ways over a UDP connection, how do I achieve this with golang?
//Node 1
func main() {
addr := net.UDPAddr{
Port: 7000,
IP: net.ParseIP("127.0.0.1"),
}
conn, err := net.ListenUDP("udp", &addr)
defer conn.Close()
if err != nil {
panic(err)
}
for {
b := make([]byte, 10)
conn.Read(b)
fmt.Println(string(b[:]))
conn.Write([]byte("sending back"))
}
}
func main() {
sock, _ := net.Dial("udp", "127.0.0.1:7000")
buf := make([]byte, 10)
sock.Write([]byte("first send"))
sock.Read(buf)
fmt.Println(string(buf[:]))
}
Remember, UDP is connection-less. When you call conn.Write, your listener doesn't know where to send the packet. In your server code, you should be using UDPConn.ReadFromUDP and UDPConn.WriteToUDP to obtain and specify the client address, as mentioned in the documentation:
The returned connection's ReadFrom and WriteTo methods can be used to receive and send UDP packets with per-packet addressing.
Your modified Node 1 loop could then look something like the following:
for {
b := make([]byte, 10)
n, clientAddr, _ := conn.ReadFromUDP(b) // TODO: error check
fmt.Println(string(b[:n]))
conn.WriteToUDP([]byte("sending back"), clientAddr)
}