Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Implementation of a UDP proxy in Golang
// Implementation of a UDP proxy
package main
import (
"flag"
"fmt"
"log"
"net"
"os"
"strings"
"sync"
)
// Information maintained for each client/server connection
type Connection struct {
ClientAddr *net.UDPAddr // Address of the client
ServerConn *net.UDPConn // UDP connection to server
}
// Generate a new connection by opening a UDP connection to the server
func NewConnection(srvAddr, cliAddr *net.UDPAddr) *Connection {
conn := new(Connection)
conn.ClientAddr = cliAddr
srvudp, err := net.DialUDP("udp", nil, srvAddr)
if checkreport(1, err) {
return nil
}
conn.ServerConn = srvudp
return conn
}
// Global state
// Connection used by clients as the proxy server
var ProxyConn *net.UDPConn
// Address of server
var ServerAddr *net.UDPAddr
// Mapping from client addresses (as host:port) to connection
var ClientDict map[string]*Connection = make(map[string]*Connection)
// Mutex used to serialize access to the dictionary
var dmutex *sync.Mutex = new(sync.Mutex)
func setup(hostport string, port int) bool {
// Set up Proxy
saddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port))
if checkreport(1, err) {
return false
}
pudp, err := net.ListenUDP("udp", saddr)
if checkreport(1, err) {
return false
}
ProxyConn = pudp
Vlogf(2, "Proxy serving on port %d\n", port)
// Get server address
srvaddr, err := net.ResolveUDPAddr("udp", hostport)
if checkreport(1, err) {
return false
}
ServerAddr = srvaddr
Vlogf(2, "Connected to server at %s\n", hostport)
return true
}
func dlock() {
dmutex.Lock()
}
func dunlock() {
dmutex.Unlock()
}
// Go routine which manages connection from server to single client
func RunConnection(conn *Connection) {
var buffer [1500]byte
for {
// Read from server
n, err := conn.ServerConn.Read(buffer[0:])
if checkreport(1, err) {
continue
}
// Relay it to client
_, err = ProxyConn.WriteToUDP(buffer[0:n], conn.ClientAddr)
if checkreport(1, err) {
continue
}
Vlogf(3, "Relayed '%s' from server to %s.\n",
string(buffer[0:n]), conn.ClientAddr.String())
}
}
// Routine to handle inputs to Proxy port
func RunProxy() {
var buffer [1500]byte
for {
n, cliaddr, err := ProxyConn.ReadFromUDP(buffer[0:])
if checkreport(1, err) {
continue
}
Vlogf(3, "Read '%s' from client %s\n",
string(buffer[0:n]), cliaddr.String())
saddr := cliaddr.String()
dlock()
conn, found := ClientDict[saddr]
if !found {
conn = NewConnection(ServerAddr, cliaddr)
if conn == nil {
dunlock()
continue
}
ClientDict[saddr] = conn
dunlock()
Vlogf(2, "Created new connection for client %s\n", saddr)
// Fire up routine to manage new connection
go RunConnection(conn)
} else {
Vlogf(5, "Found connection for client %s\n", saddr)
dunlock()
}
// Relay to server
_, err = conn.ServerConn.Write(buffer[0:n])
if checkreport(1, err) {
continue
}
}
}
var verbosity int = 6
// Log result if verbosity level high enough
func Vlogf(level int, format string, v ...interface{}) {
if level <= verbosity {
log.Printf(format, v...)
}
}
// Handle errors
func checkreport(level int, err error) bool {
if err == nil {
return false
}
Vlogf(level, "Error: %s", err.Error())
return true
}
func main() {
var ihelp *bool = flag.Bool("h", false, "Show help information")
var ipport *int = flag.Int("p", 6667, "Proxy port")
var isport *int = flag.Int("P", 6666, "Server port")
var ishost *string = flag.String("H", "localhost", "Server address")
var iverb *int = flag.Int("v", 1, "Verbosity (0-6)")
// var idrop *float64 = flag.Float64("d", 0.0, "Packet drop rate")
flag.Parse()
verbosity = *iverb
if *ihelp {
flag.Usage()
os.Exit(0)
}
if flag.NArg() > 0 {
ok := true
fields := strings.Split(flag.Arg(0), ":")
ok = ok && len(fields) == 2
if ok {
*ishost = fields[0]
n, err := fmt.Sscanf(fields[1], "%d", isport)
ok = ok && n == 1 && err == nil
}
if !ok {
flag.Usage()
os.Exit(0)
}
}
hostport := fmt.Sprintf("%s:%d", *ishost, *isport)
Vlogf(3, "Proxy port = %d, Server address = %s\n",
*ipport, hostport)
if setup(hostport, *ipport) {
RunProxy()
}
os.Exit(0)
}
@lipoiq

This comment has been minimized.

Copy link

@lipoiq lipoiq commented May 16, 2015

how to sent client IP address at server?

@DineshGuptaa

This comment has been minimized.

Copy link

@DineshGuptaa DineshGuptaa commented Aug 23, 2018

Hi,
I didn't see anywhere connection is closed. Is connection will remain open after go routine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment