Add endpoint to configure port forwarding without going to the host

This commit is contained in:
Guillaume Rose
2021-09-13 16:29:02 +02:00
parent fee3bc05ee
commit ec068dea94
3 changed files with 85 additions and 18 deletions

View File

@@ -37,6 +37,8 @@ var (
exitCode int
)
const gatewayIP = "192.168.127.1"
func main() {
flag.Var(&endpoints, "listen", fmt.Sprintf("URL where the tap send packets (default %s)", transport.DefaultURL))
flag.BoolVar(&debug, "debug", false, "Print debug info")
@@ -107,7 +109,7 @@ func main() {
CaptureFile: captureFile(),
MTU: mtu,
Subnet: "192.168.127.0/24",
GatewayIP: "192.168.127.1",
GatewayIP: gatewayIP,
GatewayMacAddress: "5a:94:ef:e4:0c:dd",
DHCPStaticLeases: map[string]string{
"192.168.127.2": "5a:94:ef:e4:0c:ee",
@@ -118,7 +120,7 @@ func main() {
Records: []types.Record{
{
Name: "gateway",
IP: net.ParseIP("192.168.127.1"),
IP: net.ParseIP(gatewayIP),
},
{
Name: "host",
@@ -131,7 +133,7 @@ func main() {
Records: []types.Record{
{
Name: "gateway",
IP: net.ParseIP("192.168.127.1"),
IP: net.ParseIP(gatewayIP),
},
{
Name: "host",
@@ -207,21 +209,19 @@ func run(ctx context.Context, g *errgroup.Group, configuration *types.Configurat
if err != nil {
return errors.Wrap(err, "cannot listen")
}
g.Go(func() error {
<-ctx.Done()
return ln.Close()
})
g.Go(func() error {
err := http.Serve(ln, withProfiler(vn))
if err != nil {
if err != http.ErrServerClosed {
return err
}
return err
}
return nil
})
httpServe(ctx, g, ln, withProfiler(vn))
}
ln, err := vn.Listen("tcp", fmt.Sprintf("%s:80", gatewayIP))
if err != nil {
return err
}
mux := http.NewServeMux()
mux.Handle("/services/forwarder/all", vn.Mux())
mux.Handle("/services/forwarder/expose", vn.Mux())
mux.Handle("/services/forwarder/unexpose", vn.Mux())
httpServe(ctx, g, ln, mux)
if debug {
g.Go(func() error {
debugLog:
@@ -290,6 +290,23 @@ func run(ctx context.Context, g *errgroup.Group, configuration *types.Configurat
return nil
}
func httpServe(ctx context.Context, g *errgroup.Group, ln net.Listener, mux http.Handler) {
g.Go(func() error {
<-ctx.Done()
return ln.Close()
})
g.Go(func() error {
err := http.Serve(ln, mux)
if err != nil {
if err != http.ErrServerClosed {
return err
}
return err
}
return nil
})
}
func withProfiler(vn *virtualnetwork.VirtualNetwork) http.Handler {
mux := vn.Mux()
if debug {

View File

@@ -160,7 +160,12 @@ func (f *PortsForwarder) Mux() http.Handler {
if req.Protocol == "" {
req.Protocol = types.TCP
}
if err := f.Expose(req.Protocol, req.Local, req.Remote); err != nil {
remote, err := remote(req, r.RemoteAddr)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := f.Expose(req.Protocol, req.Local, remote); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -187,3 +192,19 @@ func (f *PortsForwarder) Mux() http.Handler {
})
return mux
}
// if the request doesn't have an IP in the remote field, use the IP from the incoming http request.
func remote(req types.ExposeRequest, ip string) (string, error) {
remoteIP, _, err := net.SplitHostPort(req.Remote)
if err != nil {
return "", err
}
if remoteIP == "" {
host, _, err := net.SplitHostPort(ip)
if err != nil {
return "", err
}
return fmt.Sprintf("%s%s", host, req.Remote), nil
}
return req.Remote, nil
}

View File

@@ -141,4 +141,33 @@ address=/foobar/1.2.3.4
g.Expect(resp.StatusCode).To(Equal(http.StatusOK))
}).Should(Succeed())
})
It("should reach a http server in the VM using dynamic port forwarding configured within the VM", func() {
_, err := sshExec("sudo podman run --rm --name http-test -d -p 8080:80 -t docker.io/library/nginx:alpine")
Expect(err).ShouldNot(HaveOccurred())
defer func() {
_, err := sshExec("sudo podman stop http-test")
Expect(err).ShouldNot(HaveOccurred())
}()
_, err = net.Dial("tcp", "127.0.0.1:9090")
Expect(err.Error()).To(HaveSuffix("connection refused"))
_, err = sshExec(`curl http://gateway.containers.internal/services/forwarder/expose -X POST -d'{"local":":9090", "remote":":8080"}'`)
Expect(err).ShouldNot(HaveOccurred())
Eventually(func(g Gomega) {
resp, err := http.Get("http://127.0.0.1:9090")
g.Expect(err).ShouldNot(HaveOccurred())
g.Expect(resp.StatusCode).To(Equal(http.StatusOK))
}).Should(Succeed())
_, err = sshExec(`curl http://gateway.containers.internal/services/forwarder/unexpose -X POST -d'{"local":":9090"}'`)
Expect(err).ShouldNot(HaveOccurred())
Eventually(func(g Gomega) {
_, err = net.Dial("tcp", "127.0.0.1:9090")
g.Expect(err.Error()).To(HaveSuffix("connection refused"))
}).Should(Succeed())
})
})