From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:45100) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QArw5-0000Cb-JQ for qemu-devel@nongnu.org; Fri, 15 Apr 2011 18:56:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QArw3-000671-Ex for qemu-devel@nongnu.org; Fri, 15 Apr 2011 18:56:21 -0400 Received: from smtp-out.google.com ([216.239.44.51]:56672) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QArw3-00066s-73 for qemu-devel@nongnu.org; Fri, 15 Apr 2011 18:56:19 -0400 Received: from kpbe18.cbf.corp.google.com (kpbe18.cbf.corp.google.com [172.25.105.82]) by smtp-out.google.com with ESMTP id p3FMuHZn004373 for ; Fri, 15 Apr 2011 15:56:17 -0700 Received: from pvg16 (pvg16.prod.google.com [10.241.210.144]) by kpbe18.cbf.corp.google.com with ESMTP id p3FMuAMW024338 (version=TLSv1/SSLv3 cipher=RC4-MD5 bits=128 verify=NOT) for ; Fri, 15 Apr 2011 15:56:11 -0700 Received: by pvg16 with SMTP id 16so1961185pvg.15 for ; Fri, 15 Apr 2011 15:56:10 -0700 (PDT) MIME-Version: 1.0 Date: Fri, 15 Apr 2011 15:56:10 -0700 Message-ID: From: Daisuke Nojiri Content-Type: multipart/alternative; boundary=000e0cd2bd74a911ad04a0fcf2fc Subject: [Qemu-devel] [PATCH 1/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 --000e0cd2bd74a911ad04a0fcf2fc Content-Type: text/plain; charset=ISO-8859-1 This patch series adds a simple reverse UDP firewall functionality to Slirp. The series consists of three patches. Each adds one -net user option: 1. drop=udp|all - enables the firewall 2. droplog=FILE - sets the drop log filename 3. allow=PROTO:ADDR:PORT - adds an allow rule 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 8d6a555..2742741 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 = "drop", + .type = QEMU_OPT_STRING, + .help = "Enable the simple reverse firewall", }, { /* end of list */ } }, diff --git a/net/slirp.c b/net/slirp.c index b41c60a..c0a3740 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -141,7 +141,7 @@ static int net_slirp_init(VLANState *vlan, const char *model, const char *vhostname, const char *tftp_export, const char *bootfile, const char *vdhcp_start, const char *vnameserver, const char *smb_export, - const char *vsmbserver) + const char *vsmbserver, unsigned char drop) { /* default settings according to historic slirp */ struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */ @@ -246,7 +246,7 @@ static int net_slirp_init(VLANState *vlan, const char *model, s = DO_UPCAST(SlirpState, nc, nc); s->slirp = slirp_init(restricted, net, mask, host, vhostname, - tftp_export, bootfile, dhcp, dns, s); + tftp_export, bootfile, dhcp, dns, drop, s); QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); for (config = slirp_configs; config; config = config->next) { @@ -693,6 +693,7 @@ int net_init_slirp(QemuOpts *opts, char *vnet = NULL; int restricted = 0; int ret; + unsigned char drop = 0; vhost = qemu_opt_get(opts, "host"); vhostname = qemu_opt_get(opts, "hostname"); @@ -726,11 +727,25 @@ int net_init_slirp(QemuOpts *opts, restricted = 1; } + if (qemu_opt_get(opts, "drop")) { + switch (qemu_opt_get(opts, "drop")[0]) { + case 'u': + drop |= SLIRP_DROP_UDP; + break; + case 'a': + drop |= SLIRP_DROP_UDP; + break; + default: + error_report("Unknown protocol name given to drop option"); + return -1; + } + } + qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0); ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost, vhostname, tftp_export, bootfile, vdhcp_start, - vnamesrv, smb_export, vsmbsrv); + vnamesrv, smb_export, vsmbsrv, drop); while (slirp_configs) { config = slirp_configs; @@ -768,4 +783,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..ef3e726 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][,drop=udp|all]" #ifndef _WIN32 "[,smb=dir[,smbserver=addr]]\n" #endif diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 67c70e3..5778bf4 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -14,7 +14,8 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork, struct in_addr vnetmask, struct in_addr vhost, const char *vhostname, const char *tftp_path, const char *bootfile, struct in_addr vdhcp_start, - struct in_addr vnameserver, void *opaque); + struct in_addr vnameserver, unsigned char drop, + void *opaque); void slirp_cleanup(Slirp *slirp); void slirp_select_fill(int *pnfds, @@ -44,6 +45,14 @@ 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); +/* Reverse Firewall */ +#define SLIRP_DROP_UDP 1 + +int slirp_should_drop(Slirp *slirp, + struct in_addr 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..298ccb4 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -200,7 +200,7 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork, struct in_addr vnetmask, struct in_addr vhost, const char *vhostname, const char *tftp_path, const char *bootfile, struct in_addr vdhcp_start, - struct in_addr vnameserver, void *opaque) + struct in_addr vnameserver, unsigned char drop, void *opaque) { Slirp *slirp = qemu_mallocz(sizeof(Slirp)); @@ -230,6 +230,8 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork, slirp->vdhcp_startaddr = vdhcp_start; slirp->vnameserver_addr = vnameserver; + slirp->drop = drop; + slirp->opaque = opaque; register_savevm(NULL, "slirp", 0, 3, @@ -1111,3 +1113,20 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) return 0; } + +int slirp_should_drop(Slirp *slirp, + struct in_addr dst_addr, + unsigned short dst_port, + u_int8_t proto) { + switch (proto) { + case IPPROTO_UDP: + if (!(slirp->drop & SLIRP_DROP_UDP)) { + return 0; + } + break; + default: + return 0; /* unrecognized protocol. default pass. */ + } + + return 1; +} diff --git a/slirp/slirp.h b/slirp/slirp.h index 954289a..bfea30d 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -180,6 +180,9 @@ struct Slirp { struct in_addr vdhcp_startaddr; struct in_addr vnameserver_addr; + /* Reverse Firewall configuration */ + unsigned char drop; + /* ARP cache for the guest IP addresses (XXX: allow many entries) */ uint8_t client_ethaddr[6]; diff --git a/slirp/udp.c b/slirp/udp.c index 02b3793..95c4af0 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -98,6 +98,17 @@ udp_input(register struct mbuf *m, int iphlen) ip->ip_len = len; } + /* + * User mode firewall + */ + if (slirp_should_drop( + slirp, ip->ip_dst, 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. --000e0cd2bd74a911ad04a0fcf2fc 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 three patches. Each adds one -net u= ser option:

=A0 =A0 1. drop=3Dudp|all - enables th= e firewall
=A0 =A0 2. droplog=3DFILE - sets the drop log filename
=A0 = =A0 3. allow=3DPROTO:ADDR:PORT - adds an allow rule

=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=A0source=A0and the destination of the dropped pa= ckets are logged in the file
specified=A0by FILE.=A0PORT can be a= single number (e.g. 53) or a range
(e.g. [80-81]). ADDR can be=A0a=A0single address (e.g. 1.2.3.4) or a r= ange
(e.g. 1.2.3.4/24). If ADDR= =A0is ommitted,=A0all addresses match the rule.
If PROTO is omitt= ed, all protocols match the=A0rule.

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 8d6a555..2742741 100644
--- a/net.c
+++ b/net.c
@@ -925,6 +925,10 @@ static c= onst struct {
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.name =3D "= guestfwd",
=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 "IP address and port to= forward guest TCP connections",
+ =A0 =A0 =A0 =A0 =A0 =A0},= {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.name =3D "drop",
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.type =3D QEMU_OPT_STRING,
= + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.help =3D "Enable the simple 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 b41c60a..c0a374= 0 100644
--- a/net/slirp.c
+++ b/net/slirp.c
= @@ -141,7 +141,7 @@ static int net_slirp_init(VLANState *vlan, const char *= model,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const char *vho= stname, const char *tftp_export,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0const char *bootfile, const char *vdhcp_start,
=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const char *vna= meserver, const char *smb_export,
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const char *vsmbs= erver)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const= char *vsmbserver, unsigned char drop)
=A0{
=A0 =A0 =A0= /* default settings according to historic slirp */
=A0 =A0 =A0struct in_addr net =A0=3D { .s_addr =3D htonl(0x0a000200) }= ; /* 10.0.2.0 */
@@ -246,7 +246,7 @@ static int net_slirp_init(VL= ANState *vlan, const char *model,
=A0 =A0 =A0s =3D DO_UPCAST(Slir= pState, nc, nc);
=A0
=A0 =A0 =A0s->slirp =3D slirp_init(restricted, net, m= ask, host, vhostname,
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0tftp_export, bootfile, dhcp, dns, s);
+ =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tftp_export, bootfile, dhcp, dns, dr= op, s);
=A0 =A0 =A0QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
= =A0
=A0 =A0 =A0for (config =3D slirp_configs; config; config =3D = config->next) {
@@ -693,6 +693,7 @@ int net_init_slirp(QemuOpt= s *opts,
=A0 =A0 =A0char *vnet =3D NULL;
=A0 =A0 =A0int restricted = =3D 0;
=A0 =A0 =A0int ret;
+ =A0 =A0unsigned char drop = =3D 0;
=A0
=A0 =A0 =A0vhost =A0 =A0 =A0 =3D qemu_opt_ge= t(opts, "host");
=A0 =A0 =A0vhostname =A0 =3D qemu_opt_= get(opts, "hostname");
@@ -726,11 +727,25 @@ int net_init_slirp(QemuOpts *opts,
=A0= =A0 =A0 =A0 =A0restricted =3D 1;
=A0 =A0 =A0}
=A0
+ =A0 =A0if (qemu_opt_get(opts, "drop")) {
+ =A0 = =A0 =A0 =A0switch (qemu_opt_get(opts, "drop")[0]) {
+ =A0 =A0 =A0 =A0case 'u':
+ =A0 =A0 =A0 =A0 =A0 =A0= drop |=3D SLIRP_DROP_UDP;
+ =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0case 'a':
+ =A0 =A0 =A0 =A0 =A0 =A0dr= op |=3D SLIRP_DROP_UDP;
+ =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0default:
+ =A0 =A0 =A0 =A0 =A0 =A0error_rep= ort("Unknown protocol name given to drop option");
+ = =A0 =A0 =A0 =A0 =A0 =A0return -1;
+ =A0 =A0 =A0 =A0}
+ = =A0 =A0}
+
=A0 =A0 =A0qemu_opt_foreach(opts, net_init_s= lirp_configs, NULL, 0);
=A0
=A0 =A0 =A0ret =3D net_slirp_init(vlan, "user"= , name, restricted, vnet, vhost,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 vhostname, tftp_export, bootfile, vdhcp_start,
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 vnamesrv, smb_export, v= smbsrv);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 vnamesrv, smb_export= , vsmbsrv, drop);
=A0
=A0 =A0 =A0while (slirp_configs) = {
=A0 =A0 =A0 =A0 =A0config =3D slirp_configs;
@@ -768,= 4 +783,3 @@ int net_slirp_parse_legacy(QemuOptsList *opts_list, const char = *optarg, int *ret
=A0
=A0 =A0 =A0return 1;
=A0}
-
diff --git a/qemu-options.hx b/qemu-options.hx
index ef60730..e= f3e726 100644
--- a/qemu-options.hx
+++ b/qemu-options.= hx
@@ -1067,7 +1067,7 @@ 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&quo= t;
=A0 =A0 =A0" =A0 =A0 =A0 =A0 [,hostname=3Dhost][,dhcpstar= t=3Daddr][,dns=3Daddr][,tftp=3Ddir][,bootfile=3Df]\n"
- =A0 =A0" =A0 =A0 =A0 =A0 [,hostfwd=3Drule][,guestfwd=3Drule]&qu= ot;
+ =A0 =A0" =A0 =A0 =A0 =A0 [,hostfwd=3Drule][,guestfwd= =3Drule][,drop=3Dudp|all]"
=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 =A0 "[,smb=3Ddir[,smbserver=3Daddr]]\n"
=A0#endif
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 67c70e3..5778bf4 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -14,7 +14,8 @@ Slirp *slirp_init= (int restricted, struct in_addr vnetwork,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct in_addr vnetmask, struct= in_addr vhost,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const char= *vhostname, const char *tftp_path,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0const char *bootfile, struct in_addr vdhcp_start,
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct in_addr vnameserver, void = *opaque);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct in_addr vna= meserver, unsigned char drop,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0void *opaque);
=A0void slirp_cleanup(Slirp *slirp);
=A0
=A0void slirp_select_fill(int *pnfds,
@@ -44,6= +45,14 @@ void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr,<= /div>
=A0size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr gues= t_addr,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int guest_= port);
=A0
+/* Reverse Firewall */
+#define S= LIRP_DROP_UDP =A0 =A01
+
+int slirp_should_drop(Slirp *= slirp,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct in_add= r dst_addr,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned short dst_port,<= /div>
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u_int8_t proto);
+
=A0#else /* !CONFIG_SLIRP */
=A0
=A0= static inline void slirp_select_fill(int *pnfds, fd_set *readfds,
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 1593be1..29= 8ccb4 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -200,7 +200,7 @@ Slirp *slirp_init(int restricted, struct in_add= r vnetwork,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct in_addr vnetmask, struct= in_addr vhost,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0const char= *vhostname, const char *tftp_path,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0const char *bootfile, struct in_addr vdhcp_start,
- =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct in_addr vnameserver, void = *opaque)
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct in_addr vnam= eserver, unsigned char drop, void *opaque)
=A0{
=A0 =A0= =A0Slirp *slirp =3D qemu_mallocz(sizeof(Slirp));
=A0
@@ -230,6 +230,8 @@ Slirp *slirp_init(int restricted, st= ruct in_addr vnetwork,
=A0 =A0 =A0slirp->vdhcp_startaddr =3D v= dhcp_start;
=A0 =A0 =A0slirp->vnameserver_addr =3D vnameserver= ;
=A0
+ =A0 =A0slirp->drop =3D drop;
+
=A0 =A0 =A0sli= rp->opaque =3D opaque;
=A0
=A0 =A0 =A0register_savev= m(NULL, "slirp", 0, 3,
@@ -1111,3 +1113,20 @@ static in= t slirp_state_load(QEMUFile *f, void *opaque, int version_id)
=A0
=A0 =A0 =A0return 0;
=A0}
+
+int slirp_should_drop(Slirp *slirp,
+ =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 =A0unsigned short dst_port,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0u_int8_t proto) {
+ =A0 =A0switch (proto) {
+ =A0 =A0case IPPROTO_UDP:
+ =A0 =A0 =A0 =A0if (!(slirp->drop & SLIRP_DROP_UDP)) {
+= =A0 =A0 =A0 =A0 =A0 =A0return 0;
+ =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0break;
+ =A0 =A0default:
+ =A0 = =A0 =A0 =A0return 0; =A0 /* unrecognized protocol. default pass. */
+ =A0 =A0}
+
+ =A0 =A0return 1;
+}
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 954289a..bfea30d 100644
--- a/slirp/slirp.h
= +++ b/slirp/slirp.h
@@ -180,6 +180,9 @@ struct Slirp {
= =A0 =A0 =A0struct in_addr vdhcp_startaddr;
=A0 =A0 =A0struct in_a= ddr vnameserver_addr;
=A0
+ =A0 =A0/* Reverse Firewall configuration */
= + =A0 =A0unsigned char drop;
+
=A0 =A0 =A0/* ARP cache = for the guest IP addresses (XXX: allow many entries) */
=A0 =A0 = =A0uint8_t client_ethaddr[6];
=A0
diff --git a/slirp/udp.c b/slirp/udp.c
index 0= 2b3793..95c4af0 100644
--- a/slirp/udp.c
+++ b/slirp/ud= p.c
@@ -98,6 +98,17 @@ udp_input(register struct mbuf *m, int iph= len)
=A0 i= p->ip_len =3D len;
=A0 }
=A0
+ =A0 =A0 =A0 =A0/*
+ =A0 =A0 =A0 =A0 * User mode firewall
+ =A0 =A0 =A0 =A0 */
+ =A0 =A0 =A0 =A0if (slirp_should_drop(=
+ =A0 =A0 =A0 =A0 =A0 =A0slirp, ip->ip_dst, uh->uh_dport, = IPPROTO_UDP)) {
+ =A0 =A0 =A0 =A0 =A0 =A0/* DROP */
+ = =A0 =A0 =A0 =A0 =A0 =A0goto bad;
+ =A0 =A0 =A0 =A0} else {
+ =A0 =A0 =A0 =A0 =A0 =A0/* PASS */
+ =A0 =A0 =A0 =A0}
=
+
=A0 /*
=A0 * Save a copy of the IP header in case we want restore it<= /div>
=A0 *= for sending an ICMP error message in response.

--000e0cd2bd74a911ad04a0fcf2fc--