-
-
Save virtualsafety/4380950 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment