From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:45957) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QAuUk-0003Q4-60 for qemu-devel@nongnu.org; Fri, 15 Apr 2011 21:40:19 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QAuUh-0002OE-Vm for qemu-devel@nongnu.org; Fri, 15 Apr 2011 21:40:18 -0400 Received: from smtp-out.google.com ([74.125.121.67]:59906) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QAuUh-0002OA-FC for qemu-devel@nongnu.org; Fri, 15 Apr 2011 21:40:15 -0400 Received: from kpbe19.cbf.corp.google.com (kpbe19.cbf.corp.google.com [172.25.105.83]) by smtp-out.google.com with ESMTP id p3G1eDrx001748 for ; Fri, 15 Apr 2011 18:40:14 -0700 Received: from pvg4 (pvg4.prod.google.com [10.241.210.132]) by kpbe19.cbf.corp.google.com with ESMTP id p3G1eBx0026120 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for ; Fri, 15 Apr 2011 18:40:11 -0700 Received: by pvg4 with SMTP id 4so1805284pvg.0 for ; Fri, 15 Apr 2011 18:40:11 -0700 (PDT) MIME-Version: 1.0 Date: Fri, 15 Apr 2011 18:40:10 -0700 Message-ID: From: Daisuke Nojiri Content-Type: multipart/alternative; boundary=000e0cd2dc1433d9e004a0ff3dc4 Subject: [Qemu-devel] [PATCH 4/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 --000e0cd2dc1433d9e004a0ff3dc4 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. TCP support will follow in another patch series. Signed-off-by: Daisuke Nojiri diff --git a/net/slirp.c b/net/slirp.c index 51e4728..a22ca5c 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -142,6 +142,66 @@ static NetClientInfo net_slirp_info = { .cleanup = net_slirp_cleanup, }; +/* + * Parse network address in CIDR notation (e.g. 1.2.3.4/24). + * + * If mask notation is not found (e.g. 1.2.3.4), it copies default_mask to + * mask. If default_mask is NULL, it automatically sets mask based on the + * discovered address. + */ +static int parse_network_address(const char *network, + struct in_addr *net, + struct in_addr *mask, + struct in_addr *default_mask) +{ + char buf[20]; + uint32_t addr; + char *end; + int shift; + + if (get_str_sep(buf, sizeof(buf), &network, '/') < 0) { + if (!inet_aton(network, net)) { + return -1; + } + if (default_mask != NULL) { + mask->s_addr = default_mask->s_addr; + } else { + addr = ntohl(net->s_addr); + if (!(addr & 0x80000000)) { + mask->s_addr = htonl(0xff000000); /* class A */ + } else if ((addr & 0xfff00000) == 0xac100000) { + mask->s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */ + } else if ((addr & 0xc0000000) == 0x80000000) { + mask->s_addr = htonl(0xffff0000); /* class B */ + } else if ((addr & 0xffff0000) == 0xc0a80000) { + mask->s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16*/ + } else if ((addr & 0xffff0000) == 0xc6120000) { + mask->s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */ + } else if ((addr & 0xe0000000) == 0xe0000000) { + mask->s_addr = htonl(0xffffff00); /* class C */ + } else { + mask->s_addr = htonl(0xfffffff0); /* multicast/reserved */ + } + } + } else { + if (!inet_aton(buf, net)) { + return -1; + } + shift = strtol(network, &end, 10); + if (*end != '\0') { + if (!inet_aton(network, mask)) { + return -1; + } + } else if (shift < 4 || shift > 32) { + return -1; + } else { + mask->s_addr = htonl(0xffffffff << (32 - shift)); + } + } + net->s_addr &= mask->s_addr; + return 0; +} + static int net_slirp_init(VLANState *vlan, const char *model, const char *name, int restricted, const char *vnetwork, const char *vhost, @@ -162,10 +222,6 @@ static int net_slirp_init(VLANState *vlan, const char *model, #endif VLANClientState *nc; SlirpState *s; - char buf[20]; - uint32_t addr; - int shift; - char *end; struct slirp_config_str *config; if (!tftp_export) { @@ -176,42 +232,9 @@ static int net_slirp_init(VLANState *vlan, const char *model, } if (vnetwork) { - if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) { - if (!inet_aton(vnetwork, &net)) { - return -1; - } - addr = ntohl(net.s_addr); - if (!(addr & 0x80000000)) { - mask.s_addr = htonl(0xff000000); /* class A */ - } else if ((addr & 0xfff00000) == 0xac100000) { - mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */ - } else if ((addr & 0xc0000000) == 0x80000000) { - mask.s_addr = htonl(0xffff0000); /* class B */ - } else if ((addr & 0xffff0000) == 0xc0a80000) { - mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */ - } else if ((addr & 0xffff0000) == 0xc6120000) { - mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */ - } else if ((addr & 0xe0000000) == 0xe0000000) { - mask.s_addr = htonl(0xffffff00); /* class C */ - } else { - mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */ - } - } else { - if (!inet_aton(buf, &net)) { - return -1; - } - shift = strtol(vnetwork, &end, 10); - if (*end != '\0') { - if (!inet_aton(vnetwork, &mask)) { - return -1; - } - } else if (shift < 4 || shift > 32) { - return -1; - } else { - mask.s_addr = htonl(0xffffffff << (32 - shift)); - } + if(parse_network_address(vnetwork, &net, &mask, NULL)) { + return -1; } - net.s_addr &= mask.s_addr; host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr); dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr); dns.s_addr = net.s_addr | (htonl(0x0203) & ~mask.s_addr); @@ -857,10 +880,11 @@ int slirp_add_allow(Slirp *slirp, const char *optarg) */ char *argument = strdup(optarg), *p = argument; char *dst_addr_str, *dst_port_str; - struct in_addr dst_addr; + struct in_addr dst_addr, dst_mask; unsigned short dst_lport, dst_hport; char *proto_str; u_int8_t proto; + struct in_addr default_mask = { .s_addr = htonl(0xffffffff) }; proto_str = strsep(&p, ":"); if (!strcmp(proto_str, "udp")) { @@ -887,9 +911,11 @@ int slirp_add_allow(Slirp *slirp, const char *optarg) /* 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; + } else { + if (parse_network_address( + dst_addr_str, &dst_addr, &dst_mask, &default_mask)) { + return -1; + } } if (parse_port_range(dst_port_str, &dst_lport, &dst_hport) == -1) { @@ -899,7 +925,8 @@ int slirp_add_allow(Slirp *slirp, const char *optarg) return -1; } - slirp_add_allow_internal(slirp, dst_addr, dst_lport, dst_hport, proto); + slirp_add_allow_internal( + slirp, dst_addr, dst_mask, dst_lport, dst_hport, proto); free(argument); return 0; diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 1f4ddb1..9e95715 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -54,9 +54,9 @@ 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, + struct in_addr dst_mask, unsigned short dst_lport, unsigned short dst_hport, u_int8_t proto); diff --git a/slirp/slirp.c b/slirp/slirp.c index 928025e..e00e9f6 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -1149,8 +1149,9 @@ int slirp_should_drop(Slirp *slirp, 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) { + if (allow->dst_addr.s_addr == 0 || + allow->dst_addr.s_addr == + (dst_addr.s_addr & allow->dst_mask.s_addr)) { return 0; } } @@ -1163,12 +1164,14 @@ int slirp_should_drop(Slirp *slirp, */ void slirp_add_allow_internal(Slirp *slirp, struct in_addr dst_addr, + struct in_addr dst_mask, 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_mask = dst_mask; allow->dst_lport = dst_lport; allow->dst_hport = dst_hport; diff --git a/slirp/slirp.h b/slirp/slirp.h index 619bbee..a5c467f 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -175,6 +175,7 @@ struct rfw_allow { QSIMPLEQ_ENTRY(rfw_allow) next; struct in_addr dst_addr; + struct in_addr dst_mask; /* 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 */ --000e0cd2dc1433d9e004a0ff3dc4 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.

TCP suppor= t will follow in another patch series.

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

d= iff --git a/net/slirp.c b/net/slirp.c
index 51e4728..a22ca5c 1006= 44
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -142,6 +142= ,66 @@ static NetClientInfo net_slirp_info =3D {
=A0 =A0 =A0.clea= nup =3D net_slirp_cleanup,
=A0};
=A0
+/*
+ * Parse network address in CIDR notation (e.g. 1.2.3.4/24).
+ *
+ * If mask notation is not found (e.g. 1.2.3.4), it cop= ies default_mask to
+ * mask. If default_mask is NULL, it automat= ically sets mask based on the
+ * discovered address.
+ */
+static int parse_network_address(const char *network,
=
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0s= truct in_addr *net,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0struct in_addr *mask,
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct in_addr *default_= mask)
+{
+ =A0 =A0char buf[20];
+ =A0 =A0uint32_t addr;<= /div>
+ =A0 =A0char *end;
+ =A0 =A0int shift;
+
+ =A0 =A0if (get_str_sep(buf, sizeof(buf), &network, '/'= ) < 0) {
+ =A0 =A0 =A0 =A0if (!inet_aton(network, net)) {
+ =A0 =A0 = =A0 =A0 =A0 =A0return -1;
+ =A0 =A0 =A0 =A0}
+ =A0 =A0 = =A0 =A0if (default_mask !=3D NULL) {
+ =A0 =A0 =A0 =A0 =A0 =A0mas= k->s_addr =3D default_mask->s_addr;
+ =A0 =A0 =A0 =A0} else {
+ =A0 =A0 =A0 =A0 =A0 =A0addr =3D ntohl= (net->s_addr);
+ =A0 =A0 =A0 =A0 =A0 =A0if (!(addr & 0x800= 00000)) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask->s_addr =3D ht= onl(0xff000000); /* class A */
+ =A0 =A0 =A0 =A0 =A0 =A0} else if= ((addr & 0xfff00000) =3D=3D 0xac100000) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask->s_addr =3D htonl(0xfff00000)= ; /* priv. 172.16.0.0/12 */
= + =A0 =A0 =A0 =A0 =A0 =A0} else if ((addr & 0xc0000000) =3D=3D 0x800000= 00) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask->s_addr =3D htonl(= 0xffff0000); /* class B */
+ =A0 =A0 =A0 =A0 =A0 =A0} else if ((addr & 0xffff0000) =3D=3D 0xc= 0a80000) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask->s_addr =3D h= tonl(0xffff0000); /* priv. 192.168.0.0/16= */
+ =A0 =A0 =A0 =A0 =A0 =A0} else if ((addr & 0xffff000= 0) =3D=3D 0xc6120000) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask->s_addr =3D htonl(0xfffe0000)= ; /* tests 198.18.0.0/15 */
= + =A0 =A0 =A0 =A0 =A0 =A0} else if ((addr & 0xe0000000) =3D=3D 0xe00000= 00) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask->s_addr =3D htonl(= 0xffffff00); /* class C */
+ =A0 =A0 =A0 =A0 =A0 =A0} else {
+ =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0mask->s_addr =3D htonl(0xfffffff0); /* multicast/reserved */
+ =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0}
+ = =A0 =A0} else {
+ =A0 =A0 =A0 =A0if (!inet_aton(buf, net)) {
+ =A0 =A0 =A0 =A0 =A0 =A0return -1;
+ =A0 =A0 =A0 =A0}
=
+ =A0 =A0 =A0 =A0shift =3D strtol(network, &end, 10);
+ = =A0 =A0 =A0 =A0if (*end !=3D '\0') {
+ =A0 =A0 =A0 =A0 = =A0 =A0if (!inet_aton(network, mask)) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -1;
+ =A0 =A0 =A0 =A0 =A0= =A0}
+ =A0 =A0 =A0 =A0} else if (shift < 4 || shift > 32) = {
+ =A0 =A0 =A0 =A0 =A0 =A0return -1;
+ =A0 =A0 =A0 =A0= } else {
+ =A0 =A0 =A0 =A0 =A0 =A0mask->s_addr =3D htonl(0xfff= fffff << (32 - shift));
+ =A0 =A0 =A0 =A0}
+ =A0 =A0}
+ =A0 =A0net->s_a= ddr &=3D mask->s_addr;
+ =A0 =A0return 0;
+}
+
=A0static int net_slirp_init(VLANState *vlan, const char= *model,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0c= onst char *name, int restricted,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const char *vne= twork, const char *vhost,
@@ -162,10 +222,6 @@ static int net_sli= rp_init(VLANState *vlan, const char *model,
=A0#endif
= =A0 =A0 =A0VLANClientState *nc;
=A0 =A0 =A0SlirpState *s;
- =A0 =A0char buf[20];
-= =A0 =A0uint32_t addr;
- =A0 =A0int shift;
- =A0 =A0cha= r *end;
=A0 =A0 =A0struct slirp_config_str *config;
=A0=
=A0 =A0 =A0if (!tftp_export) {
@@ -176,42 +232,9 @@ static int net_slirp_init(VLANState *vlan, const = char *model,
=A0 =A0 =A0}
=A0
=A0 =A0 =A0if (= vnetwork) {
- =A0 =A0 =A0 =A0if (get_str_sep(buf, sizeof(buf), &a= mp;vnetwork, '/') < 0) {
- =A0 =A0 =A0 =A0 =A0 =A0if (!inet_aton(vnetwork, &net)) {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -1;
- =A0 =A0 =A0 =A0 = =A0 =A0}
- =A0 =A0 =A0 =A0 =A0 =A0addr =3D ntohl(net.s_addr);
- =A0 =A0 =A0 =A0 =A0 =A0if (!(addr & 0x80000000)) {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask.s_addr =3D htonl(0xff000000); /*= class A */
- =A0 =A0 =A0 =A0 =A0 =A0} else if ((addr & 0xfff= 00000) =3D=3D 0xac100000) {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask= .s_addr =3D htonl(0xfff00000); /* priv. 17= 2.16.0.0/12 */
- =A0 =A0 =A0 =A0 =A0 =A0} else if ((addr & 0xc0000000) =3D=3D 0x8= 0000000) {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask.s_addr =3D htonl= (0xffff0000); /* class B */
- =A0 =A0 =A0 =A0 =A0 =A0} else if ((= addr & 0xffff0000) =3D=3D 0xc0a80000) {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask.s_addr =3D htonl(0xffff0000); /*= priv. 192.168.0.0/16 */
- = =A0 =A0 =A0 =A0 =A0 =A0} else if ((addr & 0xffff0000) =3D=3D 0xc6120000= ) {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask.s_addr =3D htonl(0xfffe= 0000); /* tests 198.18.0.0/15 */
- =A0 =A0 =A0 =A0 =A0 =A0} else if ((addr & 0xe0000000) =3D=3D 0xe= 0000000) {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask.s_addr =3D htonl= (0xffffff00); /* class C */
- =A0 =A0 =A0 =A0 =A0 =A0} else {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask.s_addr =3D htonl(0xfffffff0); = /* multicast/reserved */
- =A0 =A0 =A0 =A0 =A0 =A0}
- =A0 =A0 =A0 =A0} else {
- =A0 =A0 =A0 =A0 =A0 =A0if (!inet_aton(buf, &net)) {
- = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -1;
- =A0 =A0 =A0 =A0 =A0 = =A0}
- =A0 =A0 =A0 =A0 =A0 =A0shift =3D strtol(vnetwork, &end= , 10);
- =A0 =A0 =A0 =A0 =A0 =A0if (*end !=3D '\0') {
- =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0if (!inet_aton(vnetwork, &mask)) {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -1;
- =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0}
- =A0 =A0 =A0 =A0 =A0 =A0} else if (shif= t < 4 || shift > 32) {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -1;
- =A0 =A0 =A0 = =A0 =A0 =A0} else {
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mask.s_addr = =3D htonl(0xffffffff << (32 - shift));
- =A0 =A0 =A0 =A0 = =A0 =A0}
+ =A0 =A0 =A0 =A0if(parse_network_address(vnetwork, &= ;net, &mask, NULL)) {
+ =A0 =A0 =A0 =A0 =A0 =A0return -1;
=A0 =A0 =A0 =A0 =A0}
- =A0 =A0 =A0 =A0net.s_addr &=3D mask.s_addr;
=A0 =A0 = =A0 =A0 =A0host.s_addr =3D net.s_addr | (htonl(0x0202) & ~mask.s_addr);=
=A0 =A0 =A0 =A0 =A0dhcp.s_addr =3D net.s_addr | (htonl(0x020f) &= amp; ~mask.s_addr);
=A0 =A0 =A0 =A0 =A0dns.s_addr =A0=3D net.s_addr | (htonl(0x0203) &= ~mask.s_addr);
@@ -857,10 +880,11 @@ int slirp_add_allow(Slirp *= slirp, const char *optarg)
=A0 =A0 =A0 */
=A0 =A0 =A0ch= ar *argument =3D strdup(optarg), *p =3D argument;
=A0 =A0 =A0char *dst_addr_str, *dst_port_str;
- =A0 =A0struc= t in_addr dst_addr;
+ =A0 =A0struct in_addr dst_addr, dst_mask;
=A0 =A0 =A0unsigned short dst_lport, dst_hport;
=A0 =A0 = =A0char *proto_str;
=A0 =A0 =A0u_int8_t proto;
+ =A0 =A0struct in_addr default_m= ask =3D { .s_addr =3D htonl(0xffffffff) };
=A0
=A0 =A0 = =A0proto_str =3D strsep(&p, ":");
=A0 =A0 =A0if (!s= trcmp(proto_str, "udp")) {
@@ -887,9 +911,11 @@ int slirp_add_allow(Slirp *slirp, const char *opt= arg)
=A0 =A0 =A0/* handling ":port" notation (when IP a= ddress is omitted entirely). */
=A0 =A0 =A0if (*dst_addr_str =3D= =3D '\0') {
=A0 =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 address: %s\n", ds= t_addr_str);
- =A0 =A0 =A0 =A0return -1;
+ =A0 =A0} else {
+ =A0 =A0 =A0 =A0if (parse_network_address= (
+ =A0 =A0 =A0 =A0 =A0 =A0dst_addr_str, &dst_addr, &dst_= mask, &default_mask)) {
+ =A0 =A0 =A0 =A0 =A0 =A0return -1;
+ =A0 =A0 =A0 =A0}
=A0 =A0 =A0}
=A0
=A0 =A0 =A0if (parse_port_range(dst_port_str, &dst_l= port, &dst_hport) =3D=3D -1) {
@@ -899,7 +925,8 @@ int slirp_= add_allow(Slirp *slirp, const char *optarg)
=A0 =A0 =A0 =A0 =A0re= turn -1;
=A0 =A0 =A0}
=A0
- =A0 =A0slirp_add_allow_internal(slir= p, dst_addr, dst_lport, dst_hport, proto);
+ =A0 =A0slirp_add_all= ow_internal(
+ =A0 =A0 =A0 =A0slirp, dst_addr, dst_mask, dst_lpor= t, dst_hport, proto);
=A0
=A0 =A0 =A0free(argument);
=A0 =A0 =A0return 0= ;
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
inde= x 1f4ddb1..9e95715 100644
--- a/slirp/libslirp.h
+++ b/= slirp/libslirp.h
@@ -54,9 +54,9 @@ int slirp_should_drop(Slirp *slirp,
=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 */
=A0void slirp_add_allow_internal(S= lirp *slirp,
=A0 =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 =A0struct in_addr dst_mask,
=A0 =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 =A0 =A0unsigned sho= rt dst_hport,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u_int8_= t proto);
diff --git a/slirp/slirp.c b/slirp/slirp.c
in= dex 928025e..e00e9f6 100644
--- a/slirp/slirp.c
+++ b/s= lirp/slirp.c
@@ -1149,8 +1149,9 @@ int slirp_should_drop(Slirp *s= lirp,
=A0 =A0 =A0 =A0 =A0dport =3D ntohs(dst_port);
=A0 =A0 =A0 = =A0 =A0if ((allow->dst_lport <=3D dport) && (dport <=3D al= low->dst_hport)) {
=A0 =A0 =A0 =A0 =A0 =A0 =A0/* allow any des= tination 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 d= st_addr.s_addr) {
+ =A0 =A0 =A0 =A0 =A0 =A0if (allow->dst_addr= .s_addr =3D=3D 0 ||
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0allow->ds= t_addr.s_addr =3D=3D
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(dst_addr.s= _addr & allow->dst_mask.s_addr)) {
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return 0;
=A0 =A0 =A0 =A0= =A0 =A0 =A0}
=A0 =A0 =A0 =A0 =A0}
@@ -1163,12 +1164,14= @@ int slirp_should_drop(Slirp *slirp,
=A0 */
=A0void = slirp_add_allow_internal(Slirp *slirp,
=A0 =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 =A0struct in_addr dst_mask,
=A0 =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 =A0 =A0unsigned sho= rt dst_hport,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u_int8_= t proto) {
=A0 =A0 =A0struct rfw_allow *allow =3D qemu_malloc(siz= eof(struct rfw_allow));
=A0
=A0 =A0 =A0allow->dst_ad= dr =3D dst_addr;
+ =A0 =A0allow->dst_mask =3D dst_mask;
=A0 =A0 =A0allow->dst_lport =3D dst_lport;
=A0 =A0 =A0all= ow->dst_hport =3D dst_hport;
=A0
diff --git a/slirp/= slirp.h b/slirp/slirp.h
index 619bbee..a5c467f 100644
-= -- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -175,6 +175,7 @@ struct rfw_allow {
=A0 =A0 =A0QSIMPLEQ_ENTRY(rfw_allow) next;
=A0
=A0 =A0 =A0struct in_addr dst_addr;
+ =A0 =A0struct in_addr dst_= mask;
=A0 =A0 =A0/* Port range. For a single port, dst_lport =3D dst_hport. */
=A0 =A0 =A0unsigned short dst_lport; =A0 /* in host byte order */
=A0 =A0 =A0unsigned short dst_hport; =A0 /* in host byte order */<= /div>

--000e0cd2dc1433d9e004a0ff3dc4--