diff --git a/net.c b/net.c
index 38ca29a..a1048ad 100644
--- a/net.c
+++ b/net.c
@@ -933,6 +933,10 @@ static const struct {
                 .name = "droplog",
                 .type = QEMU_OPT_STRING,
                 .help = "Set log filename for the reverse firewall",
+            }, {
+                .name = "allow",
+                .type = QEMU_OPT_STRING,
+                .help = "Add an allow rule for the reverse firewall",
             },
             { /* end of list */ }
         },
diff --git a/net/slirp.c b/net/slirp.c
index 38995ec..047edc2 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -58,6 +58,7 @@ static int get_str_sep(char *buf, int buf_size, const char
**pp, int sep)

 #define SLIRP_CFG_HOSTFWD 1
 #define SLIRP_CFG_LEGACY  2
+#define SLIRP_CFG_ALLOW   4

 struct slirp_config_str {
     struct slirp_config_str *next;
@@ -254,6 +255,9 @@ static int net_slirp_init(VLANState *vlan, const char
*model,
             if (slirp_hostfwd(s, config->str,
                               config->flags & SLIRP_CFG_LEGACY) < 0)
                 goto error;
+        } else if (config->flags & SLIRP_CFG_ALLOW) {
+            if (slirp_add_allow(config->str))
+                goto error;
         } else {
             if (slirp_guestfwd(s, config->str,
                                config->flags & SLIRP_CFG_LEGACY) < 0)
@@ -658,7 +662,9 @@ static int net_init_slirp_configs(const char *name,
const char *value, void *opa
 {
     struct slirp_config_str *config;

-    if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) {
+    if (strcmp(name, "hostfwd") != 0 &&
+        strcmp(name, "guestfwd") != 0 &&
+        strcmp(name, "allow") != 0) {
         return 0;
     }

@@ -668,6 +674,8 @@ static int net_init_slirp_configs(const char *name,
const char *value, void *opa

     if (!strcmp(name, "hostfwd")) {
         config->flags = SLIRP_CFG_HOSTFWD;
+    } else if (!strcmp(name, "allow")) {
+        config->flags = SLIRP_CFG_ALLOW;
     }

     config->next = slirp_configs;
diff --git a/qemu-options.hx b/qemu-options.hx
index e59bf93..e1143f3 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1067,9 +1067,9 @@ 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][,dropudp=y|n][,droplog=file]"
+    "
[,hostfwd=rule][,guestfwd=rule][,dropudp=y|n][,droplog=file][,allow=rule]\n"
 #ifndef _WIN32
-
"[,smb=dir[,smbserver=addr]]\n"
+    "         [,smb=dir[,smbserver=addr]]\n"
 #endif
     "                connect the user mode network stack to VLAN 'n',
configure its\n"
     "                DHCP server and enabled optional services\n"
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index a389cc5..4463862 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -47,6 +47,7 @@ size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr
guest_addr,
 /* Usermode firewall functions */
 void slirp_enable_drop_udp(void);
 void slirp_set_drop_log_fd(FILE *fd);
+int slirp_add_allow(const char *optarg);
 int slirp_drop_log(const char *format, ...);
 int slirp_should_drop(unsigned long dst_addr,
                       unsigned short dst_port,
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 29dd0ca..a6e2bc0 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -1113,10 +1113,22 @@ static int slirp_state_load(QEMUFile *f, void
*opaque, int version_id)
 }

 /*
+ * Allow rule for the usermode firewall
+ */
+struct ufw_allowed {
+    struct ufw_allowed *next;
+    unsigned long dst_addr;
+    /* Port range. For a single port, dst_lport = dst_hport. */
+    unsigned short dst_lport;   /* in host byte order */
+    unsigned short dst_hport;   /* in host byte order */
+};
+
+/*
  * Global variables for the usermode firewall
  */
 static int drop_udp = 0;
 static FILE *drop_log_fd = NULL;
+static struct ufw_allowed *fw_allowed_udp = NULL;

 void slirp_enable_drop_udp(void)
 {
@@ -1131,21 +1143,156 @@ void slirp_set_drop_log_fd(FILE *fd)
 int slirp_should_drop(unsigned long dst_addr,
                       unsigned short dst_port,
                       u_int8_t proto) {
+    struct ufw_allowed *fwa = NULL;
+    unsigned short dport;   /* host byte order */
+
     switch (proto) {
     case IPPROTO_UDP:
         if (drop_udp == 0) {
             return 0;
+        } else {
+            fwa = fw_allowed_udp;
         }
         break;
     case IPPROTO_TCP:
     default:
-        return 0;   /* unrecognized protocol. default pass. */
+        return 1;   /* unrecognized protocol. default drop. */
     }

+    /* Find matching allow rule. 0 works as a wildcard for address. */
+    for (; fwa; fwa = fwa->next) {
+        dport = ntohs(dst_port);
+        if ((fwa->dst_lport <= dport) && (dport <= fwa->dst_hport)) {
+            /* allow any destination if 0 */
+            if (fwa->dst_addr == 0 || fwa->dst_addr == dst_addr) {
+                return 0;
+            }
+        }
+    }
     return 1;
 }

 /*
+ * Register an allow rule for user mode firewall
+ */
+void slirp_add_allow_internal(unsigned long dst_addr,
+                              unsigned short dst_lport,
+                              unsigned short dst_hport,
+                              u_int8_t proto) {
+    struct ufw_allowed *fwa;
+
+    fwa = (struct ufw_allowed *)malloc(sizeof(struct ufw_allowed));
+    if (!fwa) {
+        DEBUG_MISC((dfd, "Unabled to create a new firewall rule "
+                    "due to malloc failure\n"));
+        exit(-1);
+    }
+
+    fwa->dst_addr = dst_addr;
+    fwa->dst_lport = dst_lport;
+    fwa->dst_hport = dst_hport;
+
+    switch (proto) {
+    case IPPROTO_UDP:
+        fwa->next = fw_allowed_udp;
+        fw_allowed_udp = fwa;
+        break;
+    case IPPROTO_TCP:
+    default:
+        free(fwa);
+        return;   /* unrecognized protocol */
+    }
+}
+
+/*
+ * Parse a null-terminated string specifying a network port or port range
(e.g.
+ * "[1024-65535]"). In case of a single port, lport and hport are the same.
+ * Returns 0 on success and -1 on error.
+ */
+int parse_port_range(const char *str,
+                     unsigned short *lport,
+                     unsigned short *hport) {
+    unsigned int low = 0, high = 0;
+    char *p, *arg = strdup(str);
+
+    p = rindex(arg, ']');
+    if ((*arg == '[') & (p != NULL)) {
+        p = arg + 1;   /* skip '[' */
+        low  = atoi(strsep(&p, "-"));
+        high = atoi(p);
+    } else {
+        low = atoi(arg);
+        high = low;
+    }
+
+    free(arg);
+
+    if ((low > 0) && (high > 0) && (low <= high) && (high < 65536)) {
+        *lport = low;
+        *hport = high;
+        return 0;
+    }
+
+    return -1;
+}
+
+/*
+ * Add allow rules for the usermode firewall.
+ */
+int slirp_add_allow(const char *optarg)
+{
+    /*
+     * we expect the following format:
+     *  dst_addr:dst_port OR dst_addr:[dst_lport-dst_hport]
+     */
+    char *argument = strdup(optarg), *p = argument;
+    char *dst_addr_str, *dst_port_str;
+    struct in_addr dst_addr;
+    unsigned short dst_lport, dst_hport;
+    char *proto_str;
+    u_int8_t proto;
+
+    proto_str = strsep(&p, ":");
+    if (!strcmp(proto_str, "udp")) {
+        proto = IPPROTO_UDP;
+    } else {
+        fprintf(stderr,
+                "Unknown protocol in a rule for the reverse firewall\n");
+        return -1;
+    }
+    dst_addr_str = strsep(&p, ":");
+    dst_port_str = p;
+
+    if (dst_addr_str == NULL || dst_port_str == NULL) {
+        fprintf(stderr,
+                "Invalid argument %s for -allow. We expect "
+                "dst_addr:dst_port or dst_addr:[dst_lport-dst_hport]\n",
+                optarg);
+        return -1;
+    }
+
+    /* handling ":port" notation (when IP address is omitted entirely). */
+    if (*dst_addr_str == '\0') {
+        dst_addr.s_addr = 0;
+    }
+    /* inet_aton returns 0 on failure. */
+    else if (inet_aton(dst_addr_str, &dst_addr) == 0) {
+        fprintf(stderr, "Invalid destination IP address: %s\n",
dst_addr_str);
+        return -1;
+    }
+
+    if (parse_port_range(dst_port_str, &dst_lport, &dst_hport) == -1) {
+        fprintf(stderr, "Invalid destination port or port range\n");
+        return -1;
+    }
+
+    slirp_add_allow_internal(dst_addr.s_addr, dst_lport, dst_hport, proto);
+
+    free(argument);
+    return 0;
+}
+
+/*
  * Write to drop-log
  */
 int slirp_drop_log(const char *format, ...)
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 954289a..29ee425 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -299,6 +299,15 @@ int tcp_emu(struct socket *, struct mbuf *);
 int tcp_ctl(struct socket *);
 struct tcpcb *tcp_drop(struct tcpcb *tp, int err);

+/* slirp.c */
+void slirp_add_allow_internal(unsigned long dst_addr,
+                              unsigned short dst_lport,
+                              unsigned short dst_hport,
+                              u_int8_t proto);
+int parse_port_range(const char *str,
+                     unsigned short *lport,
+                     unsigned short *hport);
+
 #ifdef USE_PPP
 #define MIN_MRU MINMRU
 #define MAX_MRU MAXMRU
diff --git a/slirp/udp.c b/slirp/udp.c
index f92731c..db7e4ca 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -104,7 +104,6 @@ udp_input(register struct mbuf *m, int iphlen)
          * User mode firewall
          */
         if (slirp_should_drop(ip->ip_dst.s_addr, uh->uh_dport,
IPPROTO_UDP)) {
-            /* DROP */
             slirp_drop_log(
                 "Dropped UDP: src:0x%08x:0x%04hx dst:0x%08x:0x%04hx %ld\n",
