From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:42572) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QAs3R-000423-LJ for qemu-devel@nongnu.org; Fri, 15 Apr 2011 19:03:59 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QAs3P-00071V-Bo for qemu-devel@nongnu.org; Fri, 15 Apr 2011 19:03:57 -0400 Received: from smtp-out.google.com ([216.239.44.51]:59189) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QAs3O-00071P-UV for qemu-devel@nongnu.org; Fri, 15 Apr 2011 19:03:55 -0400 Received: from wpaz24.hot.corp.google.com (wpaz24.hot.corp.google.com [172.24.198.88]) by smtp-out.google.com with ESMTP id p3FN3sx1022825 for ; Fri, 15 Apr 2011 16:03:54 -0700 Received: from pvg3 (pvg3.prod.google.com [10.241.210.131]) by wpaz24.hot.corp.google.com with ESMTP id p3FN3FbM020909 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for ; Fri, 15 Apr 2011 16:03:53 -0700 Received: by pvg3 with SMTP id 3so1808211pvg.18 for ; Fri, 15 Apr 2011 16:03:53 -0700 (PDT) MIME-Version: 1.0 Date: Fri, 15 Apr 2011 16:03:52 -0700 Message-ID: From: Daisuke Nojiri Content-Type: multipart/alternative; boundary=001636e0a5a33d924204a0fd0e65 Subject: [Qemu-devel] [PATCH 3/4] Slirp Reverse UDP Firewall List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org, Blue Swirl , Jan Kiszka --001636e0a5a33d924204a0fd0e65 Content-Type: text/plain; charset=ISO-8859-1 This patch series adds a simple reverse UDP firewall functionality to Slirp. The series consists of four patches: 1. drop=udp|all - enables the firewall 2. droplog=FILE - sets the drop log filename 3. allow=PROTO:ADDR:PORT - adds an allow rule 4. parse network mask (e.g. /24) for ADDR e.g.) $ qemu -net user,drop=udp,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]). ADDR can be a single address (e.g. 1.2.3.4) or a range (e.g. 1.2.3.4/24). If ADDR is ommitted, all addresses match the rule. If PROTO is omitted, all protocols match the rule. TCP support will follow in another patch series. Signed-off-by: Daisuke Nojiri diff --git a/net.c b/net.c index 0707188..35ec2ae 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 07e1353..5a1fdcc 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -34,6 +34,12 @@ #include "qemu_socket.h" #include "slirp/libslirp.h" +int slirp_add_allow(Slirp *slirp, const char *optarg); + +int parse_port_range(const char *str, + unsigned short *lport, + unsigned short *hport); + static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) { const char *p, *p1; @@ -58,6 +64,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; @@ -255,6 +262,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(s->slirp, config->str)) + goto error; } else { if (slirp_guestfwd(s, config->str, config->flags & SLIRP_CFG_LEGACY) < 0) @@ -659,7 +669,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; } @@ -669,6 +681,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; @@ -795,3 +809,89 @@ int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret return 1; } + +/* + * 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(Slirp *slirp, 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; + } 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(slirp, dst_addr, dst_lport, dst_hport, proto); + + free(argument); + return 0; +} diff --git a/qemu-options.hx b/qemu-options.hx index 7a8872b..b536f82 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1067,9 +1067,10 @@ 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][,drop=udp|all][,droplog=file]" + " [,hostfwd=rule][,guestfwd=rule][,drop=udp|all][,droplog=file]\n" + " [,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 f1e48a7..1f4ddb1 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -54,6 +54,13 @@ int slirp_should_drop(Slirp *slirp, unsigned short dst_port, u_int8_t proto); +/* slirp.c */ +void slirp_add_allow_internal(Slirp *slirp, + struct in_addr dst_addr, + unsigned short dst_lport, + unsigned short dst_hport, + 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 81fd85b..928025e 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -233,6 +233,7 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork, slirp->drop = drop; slirp->drop_log = drop_log; + QSIMPLEQ_INIT(&(slirp->udp_allows)); slirp->opaque = opaque; @@ -1126,20 +1127,64 @@ int slirp_should_drop(Slirp *slirp, struct in_addr dst_addr, unsigned short dst_port, u_int8_t proto) { + /* struct rfw_allow *allows = NULL; */ + QSIMPLEQ_HEAD(rfw_allows, rfw_allow) *allows; + struct rfw_allow *allow; + unsigned short dport; /* host byte order */ + switch (proto) { case IPPROTO_UDP: if (!(slirp->drop & SLIRP_DROP_UDP)) { return 0; + } else { + allows = (struct rfw_allows*)&slirp->udp_allows; } break; default: - return 0; /* unrecognized protocol. default pass. */ + return 1; /* unrecognized protocol. default drop. */ } + /* Find matching allow rule. 0 works as a wildcard for address. */ + QSIMPLEQ_FOREACH(allow, allows, next) { + dport = ntohs(dst_port); + if ((allow->dst_lport <= dport) && (dport <= allow->dst_hport)) { + /* allow any destination if 0 */ + if (allow->dst_addr.s_addr == 0 + || allow->dst_addr.s_addr == dst_addr.s_addr) { + return 0; + } + } + } return 1; } /* + * Register an allow rule for user mode firewall + */ +void slirp_add_allow_internal(Slirp *slirp, + struct in_addr dst_addr, + unsigned short dst_lport, + unsigned short dst_hport, + u_int8_t proto) { + struct rfw_allow *allow = qemu_malloc(sizeof(struct rfw_allow)); + + allow->dst_addr = dst_addr; + allow->dst_lport = dst_lport; + allow->dst_hport = dst_hport; + + switch (proto) { + case IPPROTO_UDP: + QSIMPLEQ_INSERT_HEAD(&(slirp->udp_allows), allow, next); + break; + case IPPROTO_TCP: + default: + qemu_free(allow); + return; /* unrecognized protocol */ + } +} + + +/* * Write to drop-log */ int slirp_drop_log(FILE *drop_log, const char *format, ...) diff --git a/slirp/slirp.h b/slirp/slirp.h index d95953c..619bbee 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -170,6 +170,16 @@ int inet_aton(const char *cp, struct in_addr *ia); int qemu_socket(int domain, int type, int protocol); +struct rfw_allow { + /* struct rfw_allow *next; */ + QSIMPLEQ_ENTRY(rfw_allow) next; + + struct in_addr 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 */ +}; + struct Slirp { QTAILQ_ENTRY(Slirp) entry; @@ -183,6 +193,7 @@ struct Slirp { /* Reverse Firewall configuration */ unsigned char drop; FILE *drop_log; + QSIMPLEQ_HEAD(rfw_allows, rfw_allow) udp_allows; /* ARP cache for the guest IP addresses (XXX: allow many entries) */ uint8_t client_ethaddr[6]; @@ -303,6 +314,7 @@ int tcp_emu(struct socket *, struct mbuf *); int tcp_ctl(struct socket *); struct tcpcb *tcp_drop(struct tcpcb *tp, int err); + #ifdef USE_PPP #define MIN_MRU MINMRU #define MAX_MRU MAXMRU diff --git a/slirp/udp.c b/slirp/udp.c index 6519d36..5c602d1 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -116,7 +116,14 @@ udp_input(register struct mbuf *m, int iphlen) timestamp); goto bad; } else { - /* PASS */ + slirp_drop_log( + slirp->drop_log, + "Allowed UDP: src:0x%08x:0x%04hx dst:0x%08x:0x%04hx %ld\n", + ntohl(ip->ip_src.s_addr), + ntohs(uh->uh_sport), + ntohl(ip->ip_dst.s_addr), + ntohs(uh->uh_dport), + timestamp); } /* --001636e0a5a33d924204a0fd0e65 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
This patch series adds a simple reverse UDP firewall functionality to = Slirp.
The series consists of four patches:

<= div>=A0 =A0 1. drop=3Dudp|all - enables the firewall
=A0 =A0 2. d= roplog=3DFILE - sets the drop log filename
=A0 =A0 3. allow=3DPROTO:ADDR:PORT - adds an allow rule
=A0 = =A0 4. parse network mask (e.g. /24) for ADDR

=A0 = e.g.) $ qemu -net user,drop=3Dudp,droplog=3Dqemu.drop,allow=3Dudp: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 packet= s are logged in the file
specified by FILE. PORT can be a single = number (e.g. 53) or a range
(e.g. [80-81]). ADDR can be a single address (e.g. 1.2.3.4) or a range=
(e.g. 1.2.3.4/24). If ADDR is = ommitted, all addresses match the rule.
If PROTO is omitted, all = protocols match the rule.

TCP support will follow in another patch series.
<= div>
Signed-off-by: Daisuke Nojiri <dnojiri@google.com>

diff --git a/net.c b/net.c
index 0707188..35ec2ae 100644
--- a/net.c
+++ b/net.c
@@ -933,6 +933,10 @@ static c= onst struct {
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.name =3D "= droplog",
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.type =3D QEMU_OPT_STRING,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.help =3D "Set log filename for t= he reverse firewall",
+ =A0 =A0 =A0 =A0 =A0 =A0}, {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.name =3D "allow",
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.type =3D QEMU_OPT_STRING,
= + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.help =3D "Add an allow rule for the = reverse firewall",
=A0 =A0 =A0 =A0 =A0 =A0 =A0},
= =A0 =A0 =A0 =A0 =A0 =A0 =A0{ /* end of list */ }
=A0 =A0 =A0 =A0 = =A0},
diff --git a/net/slirp.c b/net/slirp.c
index 07e1353..5a1fdc= c 100644
--- a/net/slirp.c
+++ b/net/slirp.c
= @@ -34,6 +34,12 @@
=A0#include "qemu_socket.h"
=A0#include "slirp/libslirp.h"
=A0
+int slirp= _add_allow(Slirp *slirp, const char *optarg);
+
+int pa= rse_port_range(const char *str,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 unsigned short *lport,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned short *hport);
+
=A0static int get_str_sep(char *buf, int buf_size, const = char **pp, int sep)
=A0{
=A0 =A0 =A0const char *p, *p1;=
@@ -58,6 +64,7 @@ static int get_str_sep(char *buf, int buf_size= , const char **pp, int sep)
=A0
=A0#define SLIRP_CFG_HOSTFWD 1
=A0#define SLIR= P_CFG_LEGACY =A02
+#define SLIRP_CFG_ALLOW =A0 4
=A0
=A0struct slirp_config_str {
=A0 =A0 =A0struct slirp_conf= ig_str *next;
@@ -255,6 +262,9 @@ static int net_slirp_init(VLANState *vlan, const c= har *model,
=A0 =A0 =A0 =A0 =A0 =A0 =A0if (slirp_hostfwd(s, confi= g->str,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0config->flags & SLIRP_CFG_LEGACY) < 0)
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto error;
+ =A0 =A0 =A0= =A0} else if (config->flags & SLIRP_CFG_ALLOW) {
+ =A0 = =A0 =A0 =A0 =A0 =A0if (slirp_add_allow(s->slirp, config->str))
<= div>+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto error;
=A0 =A0 =A0 =A0 =A0} else {
=A0 =A0 =A0 =A0 =A0 =A0 =A0if (s= lirp_guestfwd(s, config->str,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 config->flags & SLIRP_CFG_LEGACY) &l= t; 0)
@@ -659,7 +669,9 @@ static int net_init_slirp_configs(const= char *name, const char *value, void *opa
=A0{
=A0 =A0 =A0struct slirp_config_str *config;
= =A0
- =A0 =A0if (strcmp(name, "hostfwd") !=3D 0 &&a= mp; strcmp(name, "guestfwd") !=3D 0) {
+ =A0 =A0if (str= cmp(name, "hostfwd") !=3D 0 &&
+ =A0 =A0 =A0 =A0strcmp(name, "guestfwd") !=3D 0 &&<= /div>
+ =A0 =A0 =A0 =A0strcmp(name, "allow") !=3D 0) {
<= div>=A0 =A0 =A0 =A0 =A0return 0;
=A0 =A0 =A0}
=A0
=
@@ -669,6 +681,8 @@ static int net_init_slirp_configs(const char *name= , const char *value, void *opa
=A0
=A0 =A0 =A0if (!strcmp(name, "hostfwd")) {
=A0 =A0 =A0 =A0 =A0config->flags =3D SLIRP_CFG_HOSTFWD;
+ =A0 =A0} else if (!strcmp(name, "allow")) {
+ =A0 = =A0 =A0 =A0config->flags =3D SLIRP_CFG_ALLOW;
=A0 =A0 =A0}
=A0
=A0 =A0 =A0config->next =3D sl= irp_configs;
@@ -795,3 +809,89 @@ int net_slirp_parse_legacy(Qemu= OptsList *opts_list, const char *optarg, int *ret
=A0
= =A0 =A0 =A0return 1;
=A0}
+
+/*
+ * Parse a null-terminated s= tring specifying a network port or port range (e.g.
+ * "[10= 24-65535]"). In case of a single port, lport and hport are the same.
+ * Returns 0 on success and -1 on error.
+ */
+in= t parse_port_range(const char *str,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 unsigned short *lport,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 unsigned short *hport) {
+ =A0 =A0unsigned int low =3D 0, high =3D 0;
+ =A0 =A0char *= p, *arg =3D strdup(str);
+
+ =A0 =A0p =3D rindex(arg, &= #39;]');
+ =A0 =A0if ((*arg =3D=3D '[') & (p !=3D= NULL)) {
+ =A0 =A0 =A0 =A0p =3D arg + 1; =A0 /* skip '['= */
+ =A0 =A0 =A0 =A0low =A0=3D atoi(strsep(&p, "-"));
=
+ =A0 =A0 =A0 =A0high =3D atoi(p);
+ =A0 =A0} else {
+ =A0 =A0 =A0 =A0low =3D atoi(arg);
+ =A0 =A0 =A0 =A0high =3D = low;
+ =A0 =A0}
+
+ =A0 =A0free(arg);
+
+ =A0 =A0if ((low > 0) &&a= mp; (high > 0) && (low <=3D high) && (high < 65536= )) {
+ =A0 =A0 =A0 =A0*lport =3D low;
+ =A0 =A0 =A0 =A0= *hport =3D high;
+ =A0 =A0 =A0 =A0return 0;
+ =A0 =A0}
+
+ =A0= =A0return -1;
+}
+
+/*
+ * Add all= ow rules for the usermode firewall.
+ */
+int slirp_add= _allow(Slirp *slirp, const char *optarg)
+{
+ =A0 =A0/*
+ =A0 =A0 * we expect the following= format:
+ =A0 =A0 * =A0dst_addr:dst_port OR dst_addr:[dst_lport-= dst_hport]
+ =A0 =A0 */
+ =A0 =A0char *argument =3D str= dup(optarg), *p =3D argument;
+ =A0 =A0char *dst_addr_str, *dst_port_str;
+ =A0 =A0struct = in_addr dst_addr;
+ =A0 =A0unsigned short dst_lport, dst_hport;
+ =A0 =A0char *proto_str;
+ =A0 =A0u_int8_t proto;
=
+
+ =A0 =A0proto_str =3D strsep(&p, ":");
+ =A0 =A0if= (!strcmp(proto_str, "udp")) {
+ =A0 =A0 =A0 =A0proto = =3D IPPROTO_UDP;
+ =A0 =A0} else {
+ =A0 =A0 =A0 =A0fpr= intf(stderr,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Unknown proto= col in a rule for the reverse firewall\n");
+ =A0 =A0 =A0 =A0return -1;
+ =A0 =A0}
+ =A0 =A0ds= t_addr_str =3D strsep(&p, ":");
+ =A0 =A0dst_port_s= tr =3D p;
+
+ =A0 =A0if (dst_addr_str =3D=3D NULL || ds= t_port_str =3D=3D NULL) {
+ =A0 =A0 =A0 =A0fprintf(stderr,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0"Invalid argument %s for -allow. We expect "
+ =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0"dst_addr:dst_port or dst_addr:[dst_lport-d= st_hport]\n",
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0optarg);
+ =A0 =A0 =A0 =A0return -1;
+ =A0 =A0}
+
+ =A0 =A0/* handling ":port" notation (when IP address is omitte= d entirely). */
+ =A0 =A0if (*dst_addr_str =3D=3D '\0') {=
+ =A0 =A0 =A0 =A0dst_addr.s_addr =3D 0;
+ =A0 =A0} else if (inet_aton(dst_addr_str, &dst_addr) =3D=3D 0) {=
+ =A0 =A0 =A0 =A0fprintf(stderr, "Invalid destination IP ad= dress: %s\n", dst_addr_str);
+ =A0 =A0 =A0 =A0return -1;
+ =A0 =A0}
+
+ =A0 =A0if (parse_port_range(dst_port_str, &dst_lport, &am= p;dst_hport) =3D=3D -1) {
+ =A0 =A0 =A0 =A0fprintf(stderr, "= Invalid destination port or port range\n");
+ =A0 =A0 =A0 = =A0return -1;
+ =A0 =A0}
+
+ =A0 =A0slirp_add_allow_internal(slirp, d= st_addr, dst_lport, dst_hport, proto);
+
+ =A0 =A0free(= argument);
+ =A0 =A0return 0;
+}
diff --git a= /qemu-options.hx b/qemu-options.hx
index 7a8872b..b536f82 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1067,9 +1067,10 @@ DEF("net"= ;, HAS_ARG, QEMU_OPTION_net,
=A0#ifdef CONFIG_SLIRP
=A0= =A0 =A0"-net user[,vlan=3Dn][,name=3Dstr][,net=3Daddr[/mask]][,host= =3Daddr][,restrict=3Dy|n]\n"
=A0 =A0 =A0" =A0 =A0 =A0 =A0 [,hostname=3Dhost][,dhcpstart=3Daddr= ][,dns=3Daddr][,tftp=3Ddir][,bootfile=3Df]\n"
- =A0 =A0"= ; =A0 =A0 =A0 =A0 [,hostfwd=3Drule][,guestfwd=3Drule][,drop=3Dudp|all][,dro= plog=3Dfile]"
+ =A0 =A0" =A0 =A0 =A0 =A0 [,hostfwd=3Dru= le][,guestfwd=3Drule][,drop=3Dudp|all][,droplog=3Dfile]\n"
+ =A0 =A0" =A0 =A0 =A0 =A0 [,allow=3Drule]\n"
=A0#= ifndef _WIN32
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "[,smb=3Ddir[,smbserver=3Daddr= ]]\n"
+ =A0 =A0" =A0 =A0 =A0 =A0 [,smb=3Ddir[,smbserver= =3Daddr]]\n"
=A0#endif
=A0 =A0 =A0" =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0c= onnect the user mode network stack to VLAN 'n', configure its\n&quo= t;
=A0 =A0 =A0" =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DHCP server a= nd enabled optional services\n"
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index f1e48= a7..1f4ddb1 100644
--- a/slirp/libslirp.h
+++ b/slirp/l= ibslirp.h
@@ -54,6 +54,13 @@ int slirp_should_drop(Slirp *slirp,<= /div>
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned short dst_port= ,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u_int8_t proto);=
=A0
+/* slirp.c */
+void slirp_add_allow_int= ernal(Slirp *slirp,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0struct in_addr dst_addr,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned = short dst_lport,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0unsigned short dst_hport,
+ =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u_int8_t proto);
+
=A0#else /* !CONFIG_SLIRP */
=A0
=A0static inline void slirp_select_fill(int *pnfds, fd_s= et *readfds,
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 81fd85b..928025e 100644
--- a/slirp/slirp.c
+++ = b/slirp/slirp.c
@@ -233,6 +233,7 @@ Slirp *slirp_init(int restricted, struct in_addr v= network,
=A0
=A0 =A0 =A0slirp->drop =3D drop;
<= div>=A0 =A0 =A0slirp->drop_log =3D drop_log;
+ =A0 =A0QSIMPLEQ= _INIT(&(slirp->udp_allows));
=A0
=A0 =A0 =A0slirp->opaque =3D opaque;
=A0
@@ -1126,20 +1127,64 @@ int slirp_should_drop(Slirp *slirp,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct in_addr dst_addr,<= /div>
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned short dst= _port,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u_int8_t proto) {
=
+ =A0 =A0/* struct rfw_allow *allows =3D NULL; */
+ =A0 =A0Q= SIMPLEQ_HEAD(rfw_allows, rfw_allow) *allows;
+ =A0 =A0struct rfw_= allow *allow;
+ =A0 =A0unsigned short dport; =A0 /* host byte ord= er */
+
=A0 =A0 =A0switch (proto) {
=A0 =A0 =A0case IPPR= OTO_UDP:
=A0 =A0 =A0 =A0 =A0if (!(slirp->drop & SLIRP_DROP= _UDP)) {
=A0 =A0 =A0 =A0 =A0 =A0 =A0return 0;
+ =A0 =A0= =A0 =A0} else {
+ =A0 =A0 =A0 =A0 =A0 =A0allows =3D (struct rfw_= allows*)&slirp->udp_allows;
=A0 =A0 =A0 =A0 =A0}
=A0 =A0 =A0 =A0 =A0break;
=A0= =A0 =A0default:
- =A0 =A0 =A0 =A0return 0; =A0 /* unrecognized p= rotocol. default pass. */
+ =A0 =A0 =A0 =A0return 1; =A0 /* unrec= ognized protocol. default drop. */
=A0 =A0 =A0}
=A0
+ =A0 =A0/* Find matching allow rule. = 0 works as a wildcard for address. */
+ =A0 =A0QSIMPLEQ_FOREACH(a= llow, allows, next) {
+ =A0 =A0 =A0 =A0dport =3D ntohs(dst_port);=
+ =A0 =A0 =A0 =A0if ((allow->dst_lport <=3D dport) &&a= mp; (dport <=3D allow->dst_hport)) {
+ =A0 =A0 =A0 =A0 =A0 =A0/* allow any destination if 0 */
+ = =A0 =A0 =A0 =A0 =A0 =A0if (allow->dst_addr.s_addr =3D=3D 0
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0|| allow->dst_addr.s_addr =3D=3D dst_addr= .s_addr) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return 0;
+ =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0}
+ = =A0 =A0}
=A0 =A0 =A0return 1;
=A0}
=A0
<= div>=A0/*
+ * Register an allow rule for user mode firewall
=
+ */
+void slirp_add_allow_internal(Slirp *slirp,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct in= _addr dst_addr,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0unsigned short dst_lport,
+ =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned short dst_hport,
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u_int8_t proto) = {
+ =A0 =A0struct rfw_allow *allow =3D qemu_malloc(sizeof(struct rfw_all= ow));
+
+ =A0 =A0allow->dst_addr =3D dst_addr;
=
+ =A0 =A0allow->dst_lport =3D dst_lport;
+ =A0 =A0allow-&= gt;dst_hport =3D dst_hport;
+
+ =A0 =A0switch (proto) {
+ =A0 =A0case IPPROTO_= UDP:
+ =A0 =A0 =A0 =A0QSIMPLEQ_INSERT_HEAD(&(slirp->udp_al= lows), allow, next);=A0
+ =A0 =A0 =A0 =A0break;
+ =A0 = =A0case IPPROTO_TCP:
+ =A0 =A0default:
+ =A0 =A0 =A0 =A0qemu_free(allow);
+ = =A0 =A0 =A0 =A0return; =A0 /* unrecognized protocol */
+ =A0 =A0}=
+}
+
+
+/*
=A0 * Write t= o drop-log
=A0 */
=A0int slirp_drop_log(FILE *drop_log, const char *format, ...)
diff --git a/slirp/slirp.h b/slirp/slirp.h
index d95953c..619b= bee 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -170,6 +170,16 @@ int inet_aton(const char *cp, struct in_addr *ia)= ;
=A0int qemu_socket(int domain, int type, int protocol);
=A0
=A0
+struct rfw_allow {
+ =A0 =A0/* st= ruct rfw_allow *next; */
+ =A0 =A0QSIMPLEQ_ENTRY(rfw_allow) next;
+
+ =A0 = =A0struct in_addr dst_addr;
+ =A0 =A0/* Port range. For a single = port, dst_lport =3D dst_hport. */
+ =A0 =A0unsigned short dst_lpo= rt; =A0 /* in host byte order */
+ =A0 =A0unsigned short dst_hport; =A0 /* in host byte order */
<= div>+};
+
=A0struct Slirp {
=A0 =A0 =A0QTAILQ= _ENTRY(Slirp) entry;
=A0
@@ -183,6 +193,7 @@ struct Sli= rp {
=A0 =A0 =A0/* Reverse Firewall configuration */
=A0 =A0 =A0unsign= ed char drop;
=A0 =A0 =A0FILE *drop_log;
+ =A0 =A0QSIMP= LEQ_HEAD(rfw_allows, rfw_allow) udp_allows;
=A0
=A0 =A0= =A0/* ARP cache for the guest IP addresses (XXX: allow many entries) */
=A0 =A0 =A0uint8_t client_ethaddr[6];
@@ -303,6 +314,7 @@ in= t tcp_emu(struct socket *, struct mbuf *);
=A0int tcp_ctl(struct = socket *);
=A0struct tcpcb *tcp_drop(struct tcpcb *tp, int err);<= /div>
=A0
+
=A0#ifdef USE_PPP
=A0#define MIN_MRU MI= NMRU
=A0#define MAX_MRU MAXMRU
diff --git a/slirp/udp.c= b/slirp/udp.c
index 6519d36..5c602d1 100644
--- a/slir= p/udp.c
+++ b/slirp/udp.c
@@ -116,7 +116,14 @@ udp_input(register st= ruct mbuf *m, int iphlen)
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0time= stamp);
=A0 =A0 =A0 =A0 =A0 =A0 =A0goto bad;
=A0 =A0 = =A0 =A0 =A0} else {
- =A0 =A0 =A0 =A0 =A0 =A0/* PASS */
+ =A0 =A0 =A0 =A0 =A0 =A0slirp_drop_log(
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0slirp->drop_log,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0"Allowed UDP: src:0x%08x:0x%04hx dst:0x%08x:0x%04hx %ld\n",
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ntohl(ip->ip_src.s_addr),
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ntohs(uh->uh_sport),
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ntohl(ip->ip_dst.s_addr),
+ =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0ntohs(uh->uh_dport),
+ =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0timestamp);
=A0 =A0 =A0 =A0 =A0}
=A0
=A0 = /*

--001636e0a5a33d924204a0fd0e65--