Patchwork [1/3] Slirp Reverse UDP Firewall

login
register
mail settings
Submitter Daisuke Nojiri
Date April 13, 2011, 12:53 a.m.
Message ID <BANLkTi=-qQCgzAaGEkkSYoR34byOkW4vKQ@mail.gmail.com>
Download mbox | patch
Permalink /patch/90903/
State New
Headers show

Comments

Daisuke Nojiri - April 13, 2011, 12:53 a.m.
This patch series adds a reverse UDP firewall functionality to Slirp.
The series consists of three patches. Each adds one -net user option:

    1. dropudp=y|n - enables the firewall
    2. droplog=FILE - sets the drop log filename
    3. allow=udp:ADDR:PORT - adds an allow rule

  e.g.) $ qemu -net user,dropudp=y,droplog=qemu.drop,allow=udp:10.0.2.3:53

All UDP packets except ones allowed by allow rules will be dropped. The
source
and the destination of the dropped packets are logged in the file specified
by FILE.
PORT can be a single number (e.g. 53) or a range (e.g. [80-81]). If ADDR is
ommitted, all addresses match the rule.

TCP support will follow (in another patch series).

Signed-off-by: Daisuke Nojiri <dnojiri@google.com>

  * for sending an ICMP error message in response.

Patch

diff --git a/net.c b/net.c
index 8d6a555..95256ce 100644
--- a/net.c
+++ b/net.c
@@ -925,6 +925,10 @@  static const struct {
                 .name = "guestfwd",
                 .type = QEMU_OPT_STRING,
                 .help = "IP address and port to forward guest TCP
connections",
+            }, {
+                .name = "dropudp",
+                .type = QEMU_OPT_STRING,
+                .help = "Enable UDP reverse firewall",
             },
             { /* end of list */ }
         },
diff --git a/net/slirp.c b/net/slirp.c
index b41c60a..c3a296a 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -726,6 +726,11 @@  int net_init_slirp(QemuOpts *opts,
         restricted = 1;
     }

+    if (qemu_opt_get(opts, "dropudp") &&
+        qemu_opt_get(opts, "dropudp")[0] == 'y') {
+        slirp_enable_drop_udp();
+    }
+
     qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0);

     ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost,
@@ -768,4 +773,3 @@  int net_slirp_parse_legacy(QemuOptsList *opts_list,
const char *optarg, int *ret

     return 1;
 }
-
diff --git a/qemu-options.hx b/qemu-options.hx
index ef60730..d0a14a7 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1067,7 +1067,7 @@  DEF("net", HAS_ARG, QEMU_OPTION_net,
 #ifdef CONFIG_SLIRP
     "-net
user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=y|n]\n"
     "
[,hostname=host][,dhcpstart=addr][,dns=addr][,tftp=dir][,bootfile=f]\n"
-    "         [,hostfwd=rule][,guestfwd=rule]"
+    "         [,hostfwd=rule][,guestfwd=rule][,dropudp=y|n]"
 #ifndef _WIN32

"[,smb=dir[,smbserver=addr]]\n"
 #endif
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 67c70e3..3e88f37 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -44,6 +44,12 @@  void slirp_socket_recv(Slirp *slirp, struct in_addr
guest_addr,
 size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
                              int guest_port);

+/* Usermode firewall functions */
+void slirp_enable_drop_udp(void);
+int slirp_should_drop(unsigned long dst_addr,
+                      unsigned short dst_port,
+                      u_int8_t proto);
+
 #else /* !CONFIG_SLIRP */

 static inline void slirp_select_fill(int *pnfds, fd_set *readfds,
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 1593be1..c570ef5 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -1111,3 +1111,31 @@  static int slirp_state_load(QEMUFile *f, void
*opaque, int version_id)

     return 0;
 }
+
+
+/*
+ * Global variables for the usermode firewall
+ */
+static int drop_udp = 0;
+
+void slirp_enable_drop_udp(void)
+{
+    drop_udp = 1;
+}
+
+int slirp_should_drop(unsigned long dst_addr,
+                      unsigned short dst_port,
+                      u_int8_t proto) {
+    switch (proto) {
+    case IPPROTO_UDP:
+        if (drop_udp == 0) {
+            return 0;
+        }
+        break;
+    case IPPROTO_TCP:
+    default:
+        return 0;   /* unrecognized protocol. default pass. */
+    }
+
+    return 1;
+}
diff --git a/slirp/udp.c b/slirp/udp.c
index 02b3793..7e583b4 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -98,6 +98,16 @@  udp_input(register struct mbuf *m, int iphlen)
  ip->ip_len = len;
  }

+        /*
+         * User mode firewall
+         */
+        if (slirp_should_drop(ip->ip_dst.s_addr, uh->uh_dport,
IPPROTO_UDP)) {
+            /* DROP */
+            goto bad;
+        } else {
+            /* PASS */
+        }
+
  /*
  * Save a copy of the IP header in case we want restore it