package virtualnetwork import ( "context" "encoding/json" "net" "net/http" "strconv" "github.com/containers/gvisor-tap-vsock/pkg/tcpproxy" "github.com/containers/gvisor-tap-vsock/pkg/types" log "github.com/sirupsen/logrus" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/adapters/gonet" "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" ) func (n *VirtualNetwork) ServicesMux() *http.ServeMux { mux := http.NewServeMux() mux.Handle("/services/", http.StripPrefix("/services", n.servicesMux)) mux.HandleFunc("/stats", func(w http.ResponseWriter, _ *http.Request) { _ = json.NewEncoder(w).Encode(statsAsJSON(n.networkSwitch.Sent, n.networkSwitch.Received, n.stack.Stats())) }) mux.HandleFunc("/cam", func(w http.ResponseWriter, _ *http.Request) { _ = json.NewEncoder(w).Encode(n.networkSwitch.CAM()) }) mux.HandleFunc("/leases", func(w http.ResponseWriter, _ *http.Request) { _ = json.NewEncoder(w).Encode(n.ipPool.Leases()) }) mux.HandleFunc("/tunnel", func(w http.ResponseWriter, r *http.Request) { ip := r.URL.Query().Get("ip") if ip == "" { http.Error(w, "ip is mandatory", http.StatusInternalServerError) return } port, err := strconv.Atoi(r.URL.Query().Get("port")) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } hj, ok := w.(http.Hijacker) if !ok { http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError) return } conn, bufrw, err := hj.Hijack() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer conn.Close() if err := bufrw.Flush(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if _, err := conn.Write([]byte(`OK`)); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } remote := tcpproxy.DialProxy{ DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) { return gonet.DialContextTCP(ctx, n.stack, tcpip.FullAddress{ NIC: 1, Addr: tcpip.AddrFrom4Slice(net.ParseIP(ip).To4()), Port: uint16(port), }, ipv4.ProtocolNumber) }, OnDialError: func(_ net.Conn, dstDialErr error) { log.Errorf("cannot dial: %v", dstDialErr) }, } remote.HandleConn(conn) }) return mux } func (n *VirtualNetwork) Mux() *http.ServeMux { mux := n.ServicesMux() mux.HandleFunc(types.ConnectPath, func(w http.ResponseWriter, _ *http.Request) { hj, ok := w.(http.Hijacker) if !ok { http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError) return } conn, bufrw, err := hj.Hijack() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer conn.Close() if err := bufrw.Flush(); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } _ = n.networkSwitch.Accept(context.Background(), conn, n.configuration.Protocol) }) return mux }