Antonio Ojea 108c2aebd4 portmap plugin should flush previous udp connections
conntrack does not have any way to track UDP connections, so
it relies on timers to delete a connection.
The problem is that UDP is connectionless, so a client will keep
sending traffic despite the server has gone, thus renewing the
conntrack entries.
Pods that use portmaps to expose UDP services need to flush the existing
conntrack entries on the port exposed when they are created,
otherwise conntrack will keep sending the traffic to the previous IP
until the connection age (the client stops sending traffic)

Signed-off-by: Antonio Ojea <aojea@redhat.com>
2020-11-23 16:29:52 +01:00

87 lines
1.7 KiB
Go

// Echosvr is a simple TCP echo server
//
// It prints its listen address on stdout
// 127.0.0.1:xxxxx
// A test should wait for this line, parse it
// and may then attempt to connect.
package main
import (
"bufio"
"fmt"
"io"
"log"
"net"
"os"
"strings"
"time"
)
func main() {
// Start TCP server
listener, err := net.Listen("tcp", ":")
if err != nil {
panic(err)
}
defer listener.Close()
// use the same port for UDP
_, port, err := net.SplitHostPort(listener.Addr().String())
if err != nil {
panic(err)
}
fmt.Printf("127.0.0.1:%s\n", port)
go func() {
for {
conn, err := listener.Accept()
if err != nil {
panic(err)
}
go handleConnection(conn)
}
}()
// Start UDP server
addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%s", port))
if err != nil {
log.Fatalf("Error from net.ResolveUDPAddr(): %s", err)
}
sock, err := net.ListenUDP("udp", addr)
if err != nil {
log.Fatalf("Error from ListenUDP(): %s", err)
}
defer sock.Close()
buffer := make([]byte, 1024)
for {
n, addr, err := sock.ReadFrom(buffer)
if err != nil {
log.Fatalf("Error from ReadFrom(): %s", err)
}
sock.SetWriteDeadline(time.Now().Add(1 * time.Minute))
n, err = sock.WriteTo(buffer[0:n], addr)
if err != nil {
return
}
}
}
func handleConnection(conn net.Conn) {
conn.SetReadDeadline(time.Now().Add(1 * time.Minute))
content, err := bufio.NewReader(conn).ReadString('\n')
if err != nil && err != io.EOF {
fmt.Fprint(os.Stderr, err.Error())
return
}
conn.SetWriteDeadline(time.Now().Add(1 * time.Minute))
if _, err = conn.Write([]byte(strings.TrimSuffix(content, "\n"))); err != nil {
fmt.Fprint(os.Stderr, err.Error())
return
}
if err = conn.Close(); err != nil {
fmt.Fprint(os.Stderr, err.Error())
return
}
}