From f0922ef574c1c5f78b229d745a595435ae3a62f4 Mon Sep 17 00:00:00 2001
From: Alexander Graf <agraf@suse.de>
Date: Wed, 12 Dec 2012 19:19:26 +0100
Subject: [PATCH] Legacy Patch kvm-studio-slirp-nooutgoing.patch

---
 qemu-options.hx  | 10 ++++++++++
 slirp/socket.c   |  8 ++++++++
 slirp/tcp_subr.c | 16 ++++++++++++++++
 vl.c             |  9 +++++++++
 4 files changed, 43 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 470c2b4017..2839c8609f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2463,6 +2463,16 @@ Store the QEMU process PID in @var{file}. It is useful if you launch QEMU
 from a script.
 ETEXI
 
+DEF("nooutgoing", HAS_ARG, QEMU_OPTION_nooutgoing, \
+    "-nooutgoing <IP>\n" \
+    "                incoming traffic only from IP, no outgoing\n", \
+    QEMU_ARCH_ALL)
+STEXI
+@item -nooutgoing
+Forbid userspace networking to make outgoing connections. Only accept incoming
+connections from ip address IP.
+ETEXI
+
 DEF("singlestep", 0, QEMU_OPTION_singlestep, \
     "-singlestep     always run in singlestep mode\n", QEMU_ARCH_ALL)
 STEXI
diff --git a/slirp/socket.c b/slirp/socket.c
index 77b0c98197..94dcd9a802 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -531,6 +531,8 @@ sorecvfrom(struct socket *so)
 	} /* if ping packet */
 }
 
+extern int slirp_nooutgoing;
+
 /*
  * sendto() a socket
  */
@@ -561,6 +563,12 @@ sosendto(struct socket *so, struct mbuf *m)
 
 	DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
 
+	/* Only allow DNS requests */
+	if (slirp_nooutgoing && ntohs(addr.sin_port) != 53) {
+		errno = EHOSTUNREACH;
+		return -1;
+	}
+
 	/* Don't care what port we get */
 	ret = sendto(so->s, m->m_data, m->m_len, 0,
 		     (struct sockaddr *)&addr, sizeof (struct sockaddr));
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index 8b7c2b5c44..dd1f53afaa 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -324,6 +324,9 @@ tcp_sockclosed(struct tcpcb *tp)
  * nonblocking.  Connect returns after the SYN is sent, and does
  * not wait for ACK+SYN.
  */
+
+extern int slirp_nooutgoing;
+
 int tcp_fconnect(struct socket *so)
 {
   Slirp *slirp = so->slirp;
@@ -332,6 +335,11 @@ int tcp_fconnect(struct socket *so)
   DEBUG_CALL("tcp_fconnect");
   DEBUG_ARG("so = %lx", (long )so);
 
+  if (slirp_nooutgoing) {
+    errno = EHOSTUNREACH;
+    return -1;
+  }
+
   if( (ret = so->s = qemu_socket(AF_INET,SOCK_STREAM,0)) >= 0) {
     int opt, s=so->s;
     struct sockaddr_in addr;
@@ -424,6 +432,13 @@ tcp_connect(struct socket *inso)
 		tcp_close(sototcpcb(so)); /* This will sofree() as well */
 		return;
 	}
+
+	if (slirp_nooutgoing && addr.sin_addr.s_addr != slirp_nooutgoing) {
+		tcp_close(sototcpcb(so)); /* This will sofree() as well */
+		close(s);
+		return;
+	}
+
 	qemu_set_nonblock(s);
 	opt = 1;
 	setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
@@ -434,6 +449,7 @@ tcp_connect(struct socket *inso)
 
 	so->so_fport = addr.sin_port;
 	so->so_faddr = addr.sin_addr;
+
 	/* Translate connections from localhost to the real hostname */
         if (so->so_faddr.s_addr == 0 ||
             (so->so_faddr.s_addr & loopback_mask) ==
diff --git a/vl.c b/vl.c
index 5f01540d2e..206e96d12d 100644
--- a/vl.c
+++ b/vl.c
@@ -217,6 +217,7 @@ const char *vnc_display;
 int acpi_enabled = 1;
 int no_hpet = 0;
 int fd_bootchk = 1;
+int slirp_nooutgoing = 0;
 static int no_reboot;
 int no_shutdown = 0;
 int cursor_hide = 1;
@@ -3263,6 +3264,14 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_singlestep:
                 singlestep = 1;
                 break;
+            case QEMU_OPTION_nooutgoing:
+                slirp_nooutgoing = inet_addr(optarg);
+                if (slirp_nooutgoing == INADDR_NONE) {
+                    printf("Invalid address: %s.\nOnly addresses of the format "
+                           "xxx.xxx.xxx.xxx are supported.\n", optarg);
+                    exit(1);
+                }
+                break;
             case QEMU_OPTION_S:
                 autostart = 0;
                 break;
