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
* for sending an ICMP error message in response.