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
Related
I'm trying to find a standard way to close a connection between a client and server in a UDP connection.
Currently, I came up with the following solution, however, I'm not sure whether this is an idiomatic way or not?
Basically what I'm doing here on the server-side (handleClient function) is to conn.WriteTo(nil, Addr) which write nil to the UDP address. on the client side I check if the read() function retrieved any data or not, in case the number of the reading byte is zero, the client gives up on reading.
if n ==0 || err != nil {
break
}
Here is my simplified Server.go file:
func handleClient(conn *net.UDPConn) {
b := make([]byte, 1024)
n, Addr, err := conn.ReadFrom(b[0:])
if err != nil {
panic(err)
}
fmt.Println("read: ", n, " bytes", Addr.String())
// write the data back to the client, just for debug purpose
conn.WriteTo(b[0:n], Addr)
// let the client know that server has no more data
conn.WriteTo(nil, Addr)
}
And this is my client.go file
conn, err := net.Dial("udp", ":14000")
if err != nil {
panic(err)
}
defer conn.Close()
conn.Write([]byte("I'm client "))
for {
b := make([]byte, 512)
n, err := conn.Read(b)
if n ==0 || err != nil {
fmt.Println(">", n, err)
break
}
fmt.Println(string(b))
}
fmt.Println("finished.")
There is no standard way to do this. UDP is a stateless protocol so there is no "connection" like you would have with a TCP connection. DNS for example has no concept of a state, a client sends a request and the server will respond, no state is maintained, this is usually the selling point of UDP.
The applications are responsible for maintain state, so if you want a stateful protocol on top of UDP you also have to handle closing such a connection yourself. You might take inspiration from FTP or TFTP on how to implement this. Or consider using a stateful transport layer protocol like TCP or QUIC to handle stateful connections for you.
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)
...
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)
}
I'm new to Go, and as one of my first test project I would like to write a simple client/server program that uses UDP. I got it to work, but there are a lot of ways to do it and I would like to know which is the best way.
net.Listen() vs net.ListenUDP() vs net.ListenPacket()
net.Read() vs net.ReadFrom() vs net.ReadFromUDP()
net.Write() vs net.WriteTo() vs net.WriteToUDP()
Let's examine your question.
1. net.Listen() vs. net.ListenUDP() vs. net.ListenPacket()
net.Listen()
Listen announces on the local network address laddr. The network net must be a stream-oriented network: "tcp", "tcp4", "tcp6", "unix" or "unixpacket". See Dial for the syntax of laddr.
Usage Example #1:
tcpSock, err := net.Listen("tcp", "0.0.0.0:8080")
Usage Example #2
unixSock, err := net.Listen("unix", "/var/app/server.sock")
We can see in the source that net.Listen() works as a switch statement that calls either net.ListenTCP or net.ListenUnix or the default error:
func Listen(net, laddr string) (Listener, error) {
la, err := resolveAddr("listen", net, laddr, noDeadline)
if err != nil {
return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
}
var l Listener
switch la := la.toAddr().(type) {
case *TCPAddr:
l, err = ListenTCP(net, la)
case *UnixAddr:
l, err = ListenUnix(net, la)
default:
return nil, &OpError{
Op: "listen",
Net: net,
Addr: la,
Err: &AddrError{Err: "unexpected address type", Addr: laddr},
}
}
if err != nil {
return nil, err // l is non-nil interface containing nil pointer
}
return l, nil
}
Additional info at net.Listen() Docs
So then, we can eliminate net.ListenUDP from the initial comparison; and look at net.ListenPacket().
net.ListenPacket()
ListenPacket announces on the local network address laddr. The network net must be a packet-oriented network: "udp", "udp4", "udp6", "ip", "ip4", "ip6" or "unixgram". See Dial for the syntax of laddr.
Usage Example #1:
pListener, err := net.ListenPacket("ip4", "0.0.0.0:9090")
And, if we look under the hood, we can see that it operates in much the same way as net.Listen():
func ListenPacket(net, laddr string) (PacketConn, error) {
la, err := resolveAddr("listen", net, laddr, noDeadline)
if err != nil {
return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
}
var l PacketConn
switch la := la.toAddr().(type) {
case *UDPAddr:
l, err = ListenUDP(net, la)
case *IPAddr:
l, err = ListenIP(net, la)
case *UnixAddr:
l, err = ListenUnixgram(net, la)
default:
return nil, &OpError{
Op: "listen",
Net: net,
Addr: la,
Err: &AddrError{Err: "unexpected address type", Addr: laddr},
}
}
if err != nil {
return nil, err // l is non-nil interface containing nil pointer
}
return l, nil
}
2. net.Read() vs. net.ReadFrom() vs net.ReadFromUDP()
As you might expect, these functions are used to read from the various net connections.
net.Read()
If you look at the net package - you can see that all of the Read() functions come from types that implement the Conn interface.
IPConn.Read
TCPConn.Read
UDPConn.Read
UnixConn.Read
The Conn interface is defined as:
... a generic stream-oriented network connection.
In order to implement net.Conn you need to have the following methods:
type Conn interface {
// Read reads data from the connection.
// Read can be made to time out and return a Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetReadDeadline.
Read(b []byte) (n int, err error)
// Write writes data to the connection.
// Write can be made to time out and return a Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetWriteDeadline.
Write(b []byte) (n int, err error)
// Close closes the connection.
// Any blocked Read or Write operations will be unblocked and return errors.
Close() error
// LocalAddr returns the local network address.
LocalAddr() Addr
// RemoteAddr returns the remote network address.
RemoteAddr() Addr
// SetDeadline sets the read and write deadlines associated
// with the connection. It is equivalent to calling both
// SetReadDeadline and SetWriteDeadline.
//
// A deadline is an absolute time after which I/O operations
// fail with a timeout (see type Error) instead of
// blocking. The deadline applies to all future I/O, not just
// the immediately following call to Read or Write.
//
// An idle timeout can be implemented by repeatedly extending
// the deadline after successful Read or Write calls.
//
// A zero value for t means I/O operations will not time out.
SetDeadline(t time.Time) error
// SetReadDeadline sets the deadline for future Read calls.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
// SetWriteDeadline sets the deadline for future Write calls.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
// A zero value for t means Write will not time out.
SetWriteDeadline(t time.Time) error
}
Source code
So, that should make it clear that there is actually no net.Read(); but, rather, Read() functions that operate on types which implement the net.Conn interface.
net.ReadFrom()
Just as with net.Read(), all of the implementations come from implementing an interface. In this case, that interface is net.PacketConn
IPConn.ReadFrom
UDPConn.ReadFrom
UnixConn.ReadFrom
PacketConn is a generic packet-oriented network connection.
type PacketConn interface {
// ReadFrom reads a packet from the connection,
// copying the payload into b. It returns the number of
// bytes copied into b and the return address that
// was on the packet.
// ReadFrom can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
// see SetDeadline and SetReadDeadline.
ReadFrom(b []byte) (n int, addr Addr, err error)
// WriteTo writes a packet with payload b to addr.
// WriteTo can be made to time out and return
// an error with Timeout() == true after a fixed time limit;
// see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
WriteTo(b []byte, addr Addr) (n int, err error)
// Close closes the connection.
// Any blocked ReadFrom or WriteTo operations will be unblocked
// and return errors.
Close() error
// LocalAddr returns the local network address.
LocalAddr() Addr
// SetDeadline sets the read and write deadlines associated
// with the connection.
SetDeadline(t time.Time) error
// SetReadDeadline sets the deadline for future Read calls.
// If the deadline is reached, Read will fail with a timeout
// (see type Error) instead of blocking.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
// SetWriteDeadline sets the deadline for future Write calls.
// If the deadline is reached, Write will fail with a timeout
// (see type Error) instead of blocking.
// A zero value for t means Write will not time out.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
SetWriteDeadline(t time.Time) error
}
Note: the TCPConn.ReadFrom comes from implementing the io.ReaderFrom ReadFrom method.
3. net.Write()
As you might have guessed, we're looking at the same pattern over and over again. This is called implementing an interface. I'll leave you to look up this particular method and how it works using the above explanation as a road map.
You would do well to take a look at the Effective Go parts about interfaces first.
More net package info available at the source and GoDoc
If you only work with UDP packets, the best solution is to use the UDP functions.
net.ListenUDP() for example could listen for udp, udp4 and udp6 packages. net.ListenPacket could listen for all UDP packets, but also for ip, ip4, ip6 and unixgram packets. net.Listen() could listen for tcp, tcp4, tcp6, unix and unixpacket packets.
Source: http://golang.org/pkg/net/
I have a Go program hosting a simple HTTP service on localhost:8080 so I can connect my public nginx host to it via the proxy_pass directive, as a reverse proxy to serve part of my site's requests. This is all working great, no problems there.
I want to convert the Go program to host the HTTP service on a Unix domain socket instead of a local TCP socket for improved security and to reduce the unnecessary protocol overhead of TCP.
PROBLEM:
The problem is that Unix domain sockets cannot be reused once they are bind() to, even after program termination. The second time (and every time after) I run the Go program it exits with a fatal error "address already in use".
Common practice is to unlink() Unix domain sockets (i.e. remove the file) when the server shuts down. However, this is tricky in Go. My first attempt was to use the defer statement in my main func (see below), but it is not getting run if I interrupt the process with a signal like CTRL-C. I suppose this is to be expected. Disappointing, but not unexpected.
QUESTION: Is there a best practice on how to unlink() the socket when the server process shuts down (either gracefully or ungracefully)?
Here's part of my func main() that starts the server listening for reference:
// Create the HTTP server listening on the requested socket:
l, err := net.Listen("unix", "/tmp/mysocket")
if err != nil {
log.Fatal(err)
} else {
// Unix sockets must be unlink()ed before being reused again.
// Unfortunately, this defer is not run when a signal is received, e.g. CTRL-C.
defer func() {
os.Remove("/tmp/mysocket")
}()
log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
}
Here is the complete solution I used. The code I posted in my question was a simplified version for clear demonstration purposes.
// Create the socket to listen on:
l, err := net.Listen(socketType, socketAddr)
if err != nil {
log.Fatal(err)
return
}
// Unix sockets must be unlink()ed before being reused again.
// Handle common process-killing signals so we can gracefully shut down:
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, os.Interrupt, os.Kill, syscall.SIGTERM)
go func(c chan os.Signal) {
// Wait for a SIGINT or SIGKILL:
sig := <-c
log.Printf("Caught signal %s: shutting down.", sig)
// Stop listening (and unlink the socket if unix type):
l.Close()
// And we're done:
os.Exit(0)
}(sigc)
// Start the HTTP server:
log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
I sure hope this is good and effective Go code that would make the Go authors proud. It certainly looks so to me. If it is not, that would be embarrassing on my part. :)
For anyone curious, this is part of https://github.com/JamesDunne/go-index-html which is a simple HTTP directory listing generator with some extra features that web servers don't give you out of the box.
You can end your main func with the signal handler and spawn separate go routines for your other tasks instead. That way, you can leverage the defer mechanism and handle all (signal-based or not) shut downs cleanly:
func main() {
// Create the HTTP server listening on the requested socket:
l, err := net.Listen("unix", "/tmp/mysocket")
if err != nil {
log.Fatal(err)
return
}
// Just work with defer here; this works as long as the signal handling
// happens in the main Go routine.
defer l.Close()
// Make sure the server does not block the main
go func() {
log.Fatal(http.Serve(l, http.HandlerFunc(indexHtml)))
}()
// Use a buffered channel so we don't miss any signals
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGTERM)
// Block until a signal is received.
s := <-c
fmt.Println("Got signal:", s)
// ...and exit, running all the defer statements
}
In modern Go, you may use the syscall.Unlink() - docs here:
import (
"net"
"syscall"
...
)
...
socketpath := "/tmp/somesocket"
// carry on with your socket creation:
addr, err := net.ResolveUnixAddr("unixgram", socketpath)
if err != nil {
return err;
}
// always remove the named socket from the fs if its there
err = syscall.Unlink(socketpath)
if err != nil {
// not really important if it fails
log.Error("Unlink()",err)
}
// carry on with socket bind()
conn, err := net.ListenUnixgram("unixgram", addr);
if err != nil {
return err;
}