@@ -2,13 +2,16 @@ package main
22
33import (
44 "context"
5- // "crypto/tls"
5+ "crypto/tls"
66 "encoding/base64"
7+ "encoding/json"
78 "fmt"
9+ "io"
810 "net"
911 "net/http"
1012 "net/netip"
1113 "os"
14+ "strconv"
1215 "strings"
1316 "syscall"
1417 "time"
@@ -21,6 +24,7 @@ import (
2124 "github.com/urnetwork/proxy"
2225 "github.com/urnetwork/server"
2326 "github.com/urnetwork/server/model"
27+ "github.com/urnetwork/server/router"
2428)
2529
2630// FIXME this is meant to be deployed with no lb and no containers
@@ -35,9 +39,11 @@ import (
3539// -ldflags "-X main.Version=$WARP_VERSION-$WARP_VERSION_CODE"
3640var Version string
3741
42+ // FIXME warp port blocks
3843const ListenSocksPort = 8080
3944const ListenHttpPort = 8081
4045const ListenHttpsPort = 8082
46+ const ListenApiPort = 8083
4147
4248func DefaultProxySettings () * ProxySettings {
4349 return & ProxySettings {
@@ -89,7 +95,15 @@ func main() {
8995 panic (err )
9096 }
9197
92- glog .Infof ("Listen socks5 (:%d), http (:%d), https (:%d)" , ListenSocksPort , ListenHttpPort , ListenHttpsPort )
98+ glog .Infof ("Listen api (:%d), socks5 (:%d), http (:%d), https (:%d)" , ListenApiPort , ListenSocksPort , ListenHttpPort , ListenHttpsPort )
99+
100+ newApiServer (
101+ ctx ,
102+ cancel ,
103+ proxyDeviceManager ,
104+ transportTls ,
105+ settings ,
106+ )
93107
94108 newSocks5Server (
95109 ctx ,
@@ -242,31 +256,8 @@ func (self *httpServer) run() {
242256 }
243257 }
244258
245- headerAuth := r .Header .Get ("Proxy-Authorization" )
246-
247- bearerPrefix := "bearer "
248- basicPrefix := "basic "
249-
250- if len (bearerPrefix ) < len (headerAuth ) && strings .ToLower (headerAuth [:len (bearerPrefix )]) == bearerPrefix {
251- signedProxyId := headerAuth [len (bearerPrefix ):]
252- proxyId , err := model .ParseSignedProxyId (signedProxyId )
253- if err == nil {
254- return proxyId , nil
255- }
256- } else if len (basicPrefix ) < len (headerAuth ) && strings .ToLower (headerAuth [:len (basicPrefix )]) == basicPrefix {
257- // user:pass
258- combinedSignedProxyId , err := base64 .StdEncoding .DecodeString (headerAuth [len (basicPrefix ):])
259- if err != nil {
260- return server.Id {}, err
261- }
262- signedProxyId := strings .SplitN (string (combinedSignedProxyId ), ":" , 2 )[0 ]
263- proxyId , err := model .ParseSignedProxyId (signedProxyId )
264- if err == nil {
265- return proxyId , nil
266- }
267- }
268-
269- return server.Id {}, fmt .Errorf ("Not authorized" )
259+ authHeader := r .Header .Get ("Proxy-Authorization" )
260+ return authHeaderProxyId (authHeader )
270261 }
271262
272263 connectDial := func (r * http.Request , network string , addr string ) (net.Conn , error ) {
@@ -333,3 +324,140 @@ func (self *httpServer) run() {
333324 case <- self .ctx .Done ():
334325 }
335326}
327+
328+ type apiServer struct {
329+ ctx context.Context
330+ cancel context.CancelFunc
331+ proxyDeviceManager * ProxyDeviceManager
332+ transportTls * server.TransportTls
333+ settings * ProxySettings
334+ }
335+
336+ func newApiServer (
337+ ctx context.Context ,
338+ cancel context.CancelFunc ,
339+ proxyDeviceManager * ProxyDeviceManager ,
340+ transportTls * server.TransportTls ,
341+ settings * ProxySettings ,
342+ ) * apiServer {
343+ s := & apiServer {
344+ ctx : ctx ,
345+ cancel : cancel ,
346+ proxyDeviceManager : proxyDeviceManager ,
347+ transportTls : transportTls ,
348+ settings : settings ,
349+ }
350+
351+ go server .HandleError (s .run , cancel )
352+
353+ return s
354+ }
355+
356+ func (self * apiServer ) run () {
357+ defer self .cancel ()
358+
359+ routes := []* router.Route {
360+ router .NewRoute ("POST" , "/warmup" , self .HandleWarmup ),
361+ }
362+
363+ reusePort := false
364+
365+ httpServerOptions := server.HttpServerOptions {
366+ ReadTimeout : 15 * time .Second ,
367+ WriteTimeout : 30 * time .Second ,
368+ IdleTimeout : 5 * time .Minute ,
369+ }
370+
371+ tlsConfig := & tls.Config {
372+ GetConfigForClient : self .transportTls .GetTlsConfigForClient ,
373+ }
374+
375+ err := server .HttpListenAndServeTlsWithReusePort (
376+ self .ctx ,
377+ net .JoinHostPort ("" , strconv .Itoa (ListenApiPort )),
378+ router .NewRouter (self .ctx , routes ),
379+ reusePort ,
380+ httpServerOptions ,
381+ tlsConfig ,
382+ )
383+ if err != nil {
384+ panic (err )
385+ }
386+ }
387+
388+ type WarmupRequest struct {
389+ TimeoutSeconds int `json:"timeout_seconds,omitempty"`
390+ }
391+
392+ type WarmupResponse struct {
393+ Ready bool `json:"ready"`
394+ }
395+
396+ func (self * apiServer ) HandleWarmup (w http.ResponseWriter , r * http.Request ) {
397+ authHeader := r .Header .Get ("Authorization" )
398+ proxyId , err := authHeaderProxyId (authHeader )
399+ if err != nil {
400+ http .Error (w , err .Error (), http .StatusUnauthorized )
401+ return
402+ }
403+
404+ var warmupRequest WarmupRequest
405+
406+ defer r .Body .Close ()
407+ bodyBytes , err := io .ReadAll (r .Body )
408+
409+ if 0 < len (bodyBytes ) {
410+ err = json .Unmarshal (bodyBytes , & warmupRequest )
411+ if err != nil {
412+ http .Error (w , err .Error (), http .StatusInternalServerError )
413+ return
414+ }
415+ }
416+ // else use the default object
417+
418+ proxyDevice , err := self .proxyDeviceManager .OpenProxyDevice (proxyId )
419+ if err != nil {
420+ http .Error (w , err .Error (), http .StatusInternalServerError )
421+ return
422+ }
423+
424+ timeout := time .Duration (warmupRequest .TimeoutSeconds ) * time .Second
425+ ready := proxyDevice .WaitForReady (r .Context (), timeout )
426+
427+ warmupResponse := & WarmupResponse {
428+ Ready : ready ,
429+ }
430+
431+ out , err := json .Marshal (warmupResponse )
432+ if err != nil {
433+ http .Error (w , err .Error (), http .StatusInternalServerError )
434+ return
435+ }
436+ w .Write (out )
437+ }
438+
439+ func authHeaderProxyId (authHeader string ) (server.Id , error ) {
440+ bearerPrefix := "bearer "
441+ basicPrefix := "basic "
442+
443+ if len (bearerPrefix ) < len (authHeader ) && strings .ToLower (authHeader [:len (bearerPrefix )]) == bearerPrefix {
444+ signedProxyId := authHeader [len (bearerPrefix ):]
445+ proxyId , err := model .ParseSignedProxyId (signedProxyId )
446+ if err == nil {
447+ return proxyId , nil
448+ }
449+ } else if len (basicPrefix ) < len (authHeader ) && strings .ToLower (authHeader [:len (basicPrefix )]) == basicPrefix {
450+ // user:pass
451+ combinedSignedProxyId , err := base64 .StdEncoding .DecodeString (authHeader [len (basicPrefix ):])
452+ if err != nil {
453+ return server.Id {}, err
454+ }
455+ signedProxyId := strings .SplitN (string (combinedSignedProxyId ), ":" , 2 )[0 ]
456+ proxyId , err := model .ParseSignedProxyId (signedProxyId )
457+ if err == nil {
458+ return proxyId , nil
459+ }
460+ }
461+
462+ return server.Id {}, fmt .Errorf ("Not authorized" )
463+ }
0 commit comments