I'm using some code from Jan Newmarch's book on Go to run a daytime server on my mac. It uses this code
func main() {
service := ":1200"
tcpAddr, err := net.ResolveTCPAddr("ip4", service)
checkError(err)
listener, err := net.ListenTCP("tcp", tcpAddr)
checkError(err)
however, when I run it (on a Mac), I get this error
Fatal error: unknown network ip4
Is there anything other than ip4 that I can include in this code to avoid that error?
tcpAddr, err := net.ResolveTCPAddr("ip4", service)
Note, I also tried ip6 and got the same error.
According to the documentation for ResolveTCPAddr the only valid values for the net arg are "tcp", "tcp4" and "tcp6"
I suspect you're getting mixed up between ResolveTCPAddr and ResolveIPAddr
"ip4" isn't a valid network for ResolveTCPAddr (source).
Use ResolveIPAddr for resolving a general IP address.
"ip4" is not a valid string
See the Documentation for ResolveTCPAddr
ResolveTCPAddr parses addr as a TCP address of the form "host:port" or
"[ipv6-host%zone]:port" and resolves a pair of domain name and port
name on the network net, which must be "tcp", "tcp4" or "tcp6". A
literal address or host name for IPv6 must be enclosed in square
brackets, as in "[::1]:80", "[ipv6-host]:http" or
"[ipv6-host%zone]:80".
And the code:
func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
switch net {
case "tcp", "tcp4", "tcp6":
case "": // a hint wildcard for Go 1.0 undocumented behavior
net = "tcp"
default:
return nil, UnknownNetworkError(net)
}
a, err := resolveInternetAddr(net, addr, noDeadline)
if err != nil {
return nil, err
}
return a.toAddr().(*TCPAddr), nil
}
Related
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)
...
I need to send a UDPv6 datagram being able to track this message by a local receiver (or via tcpdump).
daddr, err = net.ResolveUDPAddr("udp6", "[address]:port")
if err != nil {
return err
}
conn, err := net.DialUDP("udp6", nil, daddr)
if err != nil {
return err
}
defer conn.Close()
conn.Write(...)
Unlike IPv4 this code doesn't work with IPv6. For example, when I try to send a datagram to a multicast address, e.g. to [FF01::DB8:0:0]:5000, I get connect: invalid argument. The same happens when I try to send it to [fe80::20c:29ff:fee1:d66]:5000 (my IPv6 address according to ifconfig).
In both cases (link-local and interface-local multicast) you have forgotten to specify the scope ID. Without this, it is impossible to determine which interface to use, and you get an Invalid argument error from the operating system.
net.UDPAddr uses the Zone field to store the scope ID. You need to ensure that you have provided one, either by setting Zone explicitly or by using the percent-suffix notation.
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
package main
import (
"fmt"
"net"
)
func main() {
var localaddr net.TCPAddr
var remoteaddr net.TCPAddr
localaddr.IP = net.ParseIP("192.168.1.104")
localaddr.Port = 6000
remoteaddr.IP = net.ParseIP("192.168.1.104")
remoteaddr.Port = 5000
if localaddr.IP == nil || remoteaddr.IP == nil {
fmt.Println("error")
}
if _, err := net.DialTCP("tcp", &localaddr, &remoteaddr); err != nil {
fmt.Println(err)
}
fmt.Println("End")
}
If the function specify local IP address, it always reports a run time error "dial tcp 192.168.1.104:5000: An invalid argument was supplied." I'm confused, should it always be a nil for local IP address ?
go version : 1.1 Beta
OS: Win7 64bit
Tried in go 1.0.3, it seemed OK
Go's net package, like most such implementations, recognizes port-only syntax for connecting to localhost:
:5000
is equivalent to
<my-ip-address>:5000
Thus, you can do:
net.Dial("tcp", ":5000")
No, it is ok to have laddr argument specified in DialTCP. The problem is that the specified port (6000) is outside of default Win7 dynamic port range and couldn't be used for outgoing connection. It works on Linux and Mac, actually (if you don't forget to change the IP address to one of your own system).