mirror of
https://github.com/onyx-and-iris/q3rcon-proxy.git
synced 2025-01-18 08:40:53 +00:00
initial commit
This commit is contained in:
commit
cfa445db14
19
.vscode/launch.json
vendored
Normal file
19
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "http server",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${workspaceFolder}/cmd/http/main.go",
|
||||
"env": {
|
||||
"LILPROXY_TARGET": "localhost:9001",
|
||||
"LILPROXY_PORT":":9000"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
10
Dockerfile
Normal file
10
Dockerfile
Normal file
@ -0,0 +1,10 @@
|
||||
FROM golang:alpine
|
||||
|
||||
# Move to /dist directory as the place for resulting binary folder
|
||||
WORKDIR /dist
|
||||
|
||||
# Copy binary from build to main folder
|
||||
COPY ./main .
|
||||
|
||||
# Command to run when starting the container
|
||||
ENTRYPOINT [ "/dist/main" ]
|
29
cmd/http/main.go
Normal file
29
cmd/http/main.go
Normal file
@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/dgparker/lilproxy/pkg/udpproxy"
|
||||
)
|
||||
|
||||
func main() {
|
||||
target := os.Getenv("LILPROXY_TARGET")
|
||||
if target == "" {
|
||||
log.Fatal("env LILPROXY_TARGET required")
|
||||
}
|
||||
|
||||
port := os.Getenv("LILPROXY_PORT")
|
||||
if port == "" {
|
||||
log.Fatal("env LILPROXY_PORT required")
|
||||
}
|
||||
|
||||
c, err := udpproxy.New(port, target)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("lilproxy initialized")
|
||||
|
||||
log.Fatal(c.ListenAndServe())
|
||||
}
|
66
pkg/udpproxy/session.go
Normal file
66
pkg/udpproxy/session.go
Normal file
@ -0,0 +1,66 @@
|
||||
package udpproxy
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
serverConn *net.UDPConn
|
||||
proxyConn *net.UDPConn
|
||||
caddr *net.UDPAddr
|
||||
updateTime time.Time
|
||||
}
|
||||
|
||||
func createSession(caddr *net.UDPAddr, raddr *net.UDPAddr, proxyConn *net.UDPConn) (*Session, error) {
|
||||
serverConn, err := net.DialUDP("udp", nil, raddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
session := &Session{
|
||||
serverConn: serverConn,
|
||||
proxyConn: proxyConn,
|
||||
caddr: caddr,
|
||||
updateTime: time.Now(),
|
||||
}
|
||||
|
||||
go session.listen()
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (s *Session) listen() error {
|
||||
for {
|
||||
buf := make([]byte, 1024)
|
||||
_, err := s.serverConn.Read(buf)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
go s.proxyFrom(buf)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Session) proxyFrom(buf []byte) error {
|
||||
s.updateTime = time.Now()
|
||||
_, err := s.proxyConn.WriteToUDP(buf, s.caddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) proxyTo(buf []byte) error {
|
||||
s.updateTime = time.Now()
|
||||
_, err := s.serverConn.Write(buf)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
84
pkg/udpproxy/udpproxy.go
Normal file
84
pkg/udpproxy/udpproxy.go
Normal file
@ -0,0 +1,84 @@
|
||||
package udpproxy
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
laddr *net.UDPAddr
|
||||
raddr *net.UDPAddr
|
||||
|
||||
proxyConn *net.UDPConn
|
||||
|
||||
mutex sync.RWMutex
|
||||
sessions map[string]*Session
|
||||
}
|
||||
|
||||
func New(port, target string) (*Client, error) {
|
||||
laddr, err := net.ResolveUDPAddr("udp", port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
raddr, err := net.ResolveUDPAddr("udp", target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{
|
||||
laddr: laddr,
|
||||
raddr: raddr,
|
||||
mutex: sync.RWMutex{},
|
||||
sessions: map[string]*Session{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListenAndServe() error {
|
||||
var err error
|
||||
c.proxyConn, err = net.ListenUDP("udp", c.laddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go c.pruneSessions()
|
||||
|
||||
for {
|
||||
buf := make([]byte, 2048)
|
||||
_, caddr, err := c.proxyConn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
session, found := c.sessions[caddr.String()]
|
||||
if !found {
|
||||
session, err = createSession(caddr, c.raddr, c.proxyConn)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
c.sessions[caddr.String()] = session
|
||||
}
|
||||
|
||||
go session.proxyTo(buf)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) pruneSessions() {
|
||||
ticker := time.NewTicker(1 * time.Minute)
|
||||
|
||||
// the locks here could be abusive and i dont even know if this is a real
|
||||
// problem but we definitely need to clean up stale sessions
|
||||
for range ticker.C {
|
||||
for _, session := range c.sessions {
|
||||
c.mutex.RLock()
|
||||
if time.Since(session.updateTime) > time.Minute*5 {
|
||||
delete(c.sessions, session.caddr.String())
|
||||
}
|
||||
c.mutex.RUnlock()
|
||||
}
|
||||
}
|
||||
}
|
83
pkg/udpproxy/udpproxy_test.go
Normal file
83
pkg/udpproxy/udpproxy_test.go
Normal file
@ -0,0 +1,83 @@
|
||||
package udpproxy
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSendAndReceive(t *testing.T) {
|
||||
go runLilProxy()
|
||||
go runUDPServer()
|
||||
|
||||
paddr, err := net.ResolveUDPAddr("udp", "localhost:9000")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
conn, err := net.DialUDP("udp", nil, paddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
buf := make([]byte, 2048)
|
||||
_, _, err = conn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("response received: %s", string(buf))
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
time.Sleep(1 * time.Second)
|
||||
_, err = conn.Write([]byte("hi\n"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runLilProxy() {
|
||||
port := ":9000"
|
||||
target := "localhost:9001"
|
||||
|
||||
c, err := New(port, target)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Fatal(c.ListenAndServe())
|
||||
}
|
||||
|
||||
func runUDPServer() {
|
||||
taddr, err := net.ResolveUDPAddr("udp", ":9001")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
conn, err := net.ListenUDP("udp", taddr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for {
|
||||
buf := make([]byte, 2048)
|
||||
_, caddr, err := conn.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("request received: %s", string(buf))
|
||||
|
||||
_, err = conn.WriteToUDP([]byte("bye\n"), caddr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
4
vendor/modules.txt
vendored
Normal file
4
vendor/modules.txt
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# github.com/google/martian/v3 v3.3.2
|
||||
## explicit; go 1.11
|
||||
# golang.org/x/sys v0.3.0
|
||||
## explicit; go 1.17
|
Loading…
Reference in New Issue
Block a user