// Package proxy is a wrapper around proxyguard that integrates it with eduvpn-common settings // - leaves out some options not applicable to the common integration, e.g. fwmark // - integrates with eduvpn-common's logger // - integrates eduvpn-common's user agent package proxy import ( "context" "fmt" "log/slog" "codeberg.org/eduVPN/proxyguard" "codeberg.org/eduVPN/eduvpn-common/i18n/err" "codeberg.org/eduVPN/eduvpn-common/internal/httpwrap" ) // Logger is defined here such that we can update the proxyguard logger type Logger struct{} // Logf logs a message with parameters func (l *Logger) Logf(msg string, params ...any) { slog.Info("Proxyguard log", "msg", fmt.Sprintf(msg, params...)) } // Log logs a message func (l *Logger) Log(msg string) { slog.Info("Proxyguard log", "msg", msg) } // Proxy is the ProxyGuard client with a channel used for restarting type Proxy struct { proxyguard.Client resChan chan struct{} } // NewProxyguard sets up proxyguard for proxied WireGuard connections func NewProxyguard(ctx context.Context, lp int, tcpsp int, peer string, setupSocket func(fd int)) (*Proxy, error) { proxyguard.UpdateLogger(&Logger{}) proxy := Proxy{ Client: proxyguard.Client{ Peer: peer, ListenPort: lp, TCPSourcePort: tcpsp, SetupSocket: setupSocket, UserAgent: httpwrap.UserAgent, }, resChan: make(chan struct{}), } _, err := proxy.Setup(ctx) if err != nil { return nil, i18nerr.WrapInternal(err, "The ProxyGuard DNS could not be resolved") } return &proxy, nil } // Tunnel tunnels the ProxyGuard connection. `wglisten` is the WireGuard listen port func (p *Proxy) Tunnel(ctx context.Context, wglisten int) error { errChan := make(chan error, 1) gctx, cancel := context.WithCancel(ctx) go func() { err := p.Client.Tunnel(gctx, wglisten) if err != nil { err = i18nerr.WrapInternal(err, "The VPN proxy exited") } errChan <- err }() select { case err := <-errChan: cancel() return err case <-p.resChan: cancel() <-errChan return p.Tunnel(ctx, wglisten) } } // Restart restarts the existing ProxyGuard process, for e.g. roaming func (p *Proxy) Restart() { p.resChan <- struct{}{} }