From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:37223) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Q9gJb-0003ZM-Pb for qemu-devel@nongnu.org; Tue, 12 Apr 2011 12:19:45 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Q9gJV-0006ZJ-R5 for qemu-devel@nongnu.org; Tue, 12 Apr 2011 12:19:43 -0400 Received: from smtp-out.google.com ([216.239.44.51]:53950) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Q9gJV-0006Yq-Ge for qemu-devel@nongnu.org; Tue, 12 Apr 2011 12:19:37 -0400 Received: from wpaz1.hot.corp.google.com (wpaz1.hot.corp.google.com [172.24.198.65]) by smtp-out.google.com with ESMTP id p3CGJaLT028014 for ; Tue, 12 Apr 2011 09:19:36 -0700 Received: from pwj7 (pwj7.prod.google.com [10.241.219.71]) by wpaz1.hot.corp.google.com with ESMTP id p3CGIXv3017330 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for ; Tue, 12 Apr 2011 09:19:35 -0700 Received: by pwj7 with SMTP id 7so3112458pwj.12 for ; Tue, 12 Apr 2011 09:19:35 -0700 (PDT) MIME-Version: 1.0 Date: Tue, 12 Apr 2011 09:19:34 -0700 Message-ID: From: Daisuke Nojiri Content-Type: multipart/alternative; boundary=001636e0ae0fd0db1704a0bb0e73 Subject: [Qemu-devel] [PATCH] Slirp reverse UDP firewall List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org --001636e0ae0fd0db1704a0bb0e73 Content-Type: text/plain; charset=ISO-8859-1 This patch adds: -drop-udp, -allow-udp ADDR:PORT, -drop-log FILE e.g.) $ qemu -net user -drop-log qemu.drop -drop-udp -allow-udp 10.0.2.3:53 -drop-udp enables usermode firewall for out-going UDP packats from a guest. All UDP packets except ones allowed by -allow-udp will be dropped. 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]). If ADDR is ommitted, all addresses match the rule. Signed-off-by: Daisuke Nojiri --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1119,6 +1119,24 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, "vde|" #endif "socket],id=str[,option][,option][,...]\n", QEMU_ARCH_ALL) + +DEF("drop-udp", 0, QEMU_OPTION_drop_udp, +"-drop-udp\tDrop UDP packets by usermode firewall\n", +QEMU_ARCH_ALL) + +DEF("allow-udp", HAS_ARG, QEMU_OPTION_allow_udp, + "-allow-udp addr:port\n" + " Add an allowed rule for -drop-udp. If destination matches\n" + " the rule, the packet won't be dropped. 'port' can be a single\n" + " number (e.g. 53) or a range (e.g. [80-81]. If 'addr' is omitted, + " all addresses match.\n", + QEMU_ARCH_ALL) + +DEF("drop-log", HAS_ARG, QEMU_OPTION_drop_log, + "-drop-log file\n" + " Set usermode firewall log filename to 'file'.\n", + QEMU_ARCH_ALL) + STEXI @item -net nic[,vlan=@var{n}][,macaddr=@var{mac}][,model=@var{type}] [,name=@var{name}][,addr=@var{addr}][,vectors=@var{v}] @findex -net diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 67c70e3..1ce5d68 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -44,6 +44,15 @@ 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); +void slirp_set_drop_log_fd(FILE *fd); +void slirp_add_allow(const char *optarg, u_int8_t proto); +int slirp_drop_log(const char *format, ...); +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..d321316 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -1111,3 +1111,192 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) return 0; } + +/* + * 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) +{ + drop_udp = 1; +} + +void slirp_set_drop_log_fd(FILE *fd) +{ + drop_log_fd = 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 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. + */ +void slirp_add_allow(const char *optarg, u_int8_t proto) +{ + /* + * 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; + + 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); + exit(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); + exit(1); + } + + if (parse_port_range(dst_port_str, &dst_lport, &dst_hport) == -1) { + fprintf(stderr, "Invalid destination port or port range\n"); + exit(1); + } + + slirp_add_allow_internal(dst_addr.s_addr, dst_lport, dst_hport, proto); + + free(argument); +} + +/* + * Write to drop-log + */ +int slirp_drop_log(const char *format, ...) +{ + va_list args; + + if (!drop_log_fd) { + return 0; + } + + va_start(args, format); + vfprintf(drop_log_fd, format, args); + va_end(args); + + fflush(drop_log_fd); + + return 1; +} 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 02b3793..db7e4ca 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -67,6 +67,8 @@ udp_input(register struct mbuf *m, int iphlen) DEBUG_ARG("m = %lx", (long)m); DEBUG_ARG("iphlen = %d", iphlen); + time_t timestamp = time(NULL); + /* * Strip IP options, if any; should skip this, * make available to user, and use on returned packets, @@ -98,6 +100,28 @@ 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)) { + slirp_drop_log( + "Dropped 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); + goto bad; + } else { + 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); + } + /* * Save a copy of the IP header in case we want restore it * for sending an ICMP error message in response. diff --git a/vl.c b/vl.c index 68c3b53..b0583e3 100644 --- a/vl.c +++ b/vl.c @@ -2287,6 +2287,24 @@ int main(int argc, char **argv, char **envp) exit(1); break; #endif + case QEMU_OPTION_drop_udp: + slirp_enable_drop_udp(); + break; + case QEMU_OPTION_allow_udp: + slirp_add_allow(optarg, IPPROTO_UDP); + break; + case QEMU_OPTION_drop_log: + { + FILE *drop_log_fd; + drop_log_fd = fopen(optarg, "w"); + + if (!drop_log_fd) { + fprintf(stderr, "Cannot open drop log: %s\n", optarg); + exit(1); + } + slirp_set_drop_log_fd(drop_log_fd); + } + break; case QEMU_OPTION_bt: add_device_config(DEV_BT, optarg); break; --001636e0ae0fd0db1704a0bb0e73 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
This patch adds: -drop-udp, -allow-udp ADDR:PORT, -drop-log = FILE

=A0 e.g.) $ qemu -net user -drop-log qemu.dro= p -drop-udp -allow-udp 10.= 0.2.3:53

-drop-udp enables usermode firewall for out-going UDP p= ackats from a guest.
All UDP packets except ones allowed by -allo= w-udp will be dropped. Dropped
packets are logged in the file spe= cified by FILE. PORT can be a single number
(e.g. 53) or a range (e.g. [80-81]). If ADDR is ommitted, all addresse= s match
the rule.

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

--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1119,6 +1119,24 @@ DEF("netdev", HAS_ARG, QEMU_OPTIO= N_netdev,
=A0 =A0 =A0"vde|"
=A0#endif
=A0 =A0 =A0"socket],id=3Dstr[,option][,option][,...]\n", QEMU_ARC= H_ALL)
+
+DEF("drop-udp", 0, QEMU_OPTION_drop_udp,
<= div>+"-drop-udp\tDrop UDP packets by usermode firewall\n",<= div>+QEMU_ARCH_ALL)
+
+DEF("allow-udp", HAS_A= RG, QEMU_OPTION_allow_udp,
+ =A0 =A0"-allow-udp addr:port\n"
+ =A0 =A0" = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0Add an allowed rule for -drop-udp. If destin= ation matches\n"
+ =A0 =A0" =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0the rule, the packet won't be dropped. 'port' can be a sing= le\n"
+ =A0 =A0" =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0number (e.g. 53) or a r= ange (e.g. [80-81]. If 'addr' is omitted,
+ =A0 =A0"= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0all addresses match.\n",
+ = =A0 =A0QEMU_ARCH_ALL)
+
+DEF("drop-log", HAS_ARG, QEMU_OPTION_drop_log,
+ =A0 = =A0"-drop-log file\n"
+ =A0 =A0" =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0Set usermode firewall log filename to 'file'.\n"= ;,
+ =A0 =A0QEMU_ARCH_ALL)
+
=A0STEXI
=A0@item -net nic[,vlan=3D@var{n}][,mac= addr=3D@var{mac}][,model=3D@var{type}] [,name=3D@var{name}][,addr=3D@var{ad= dr}][,vectors=3D@var{v}]
=A0@findex -net
diff --git a/s= lirp/libslirp.h b/slirp/libslirp.h
index 67c70e3..1ce5d68 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -44,6 +44,15 @@ void slirp_socket_re= cv(Slirp *slirp, struct in_addr guest_addr,
=A0size_t slirp_socke= t_can_recv(Slirp *slirp, struct in_addr guest_addr,
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int guest_= port);
=A0
+/* Usermode firewall functions */
+void slirp_enable_drop_udp(void);
+void slirp_set_drop_log_fd(F= ILE *fd);
+void slirp_add_allow(const char *optarg, u_int8_t prot= o);
+int slirp_drop_log(const char *format, ...);
+int slirp_sho= uld_drop(unsigned long 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#else /* !CONFIG_SLIRP */
=A0
=A0st= atic inline void slirp_select_fill(int *pnfds, fd_set *readfds,
d= iff --git a/slirp/slirp.c b/slirp/slirp.c
index 1593be1..d321316 = 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -1111,3= +1111,192 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int ve= rsion_id)
=A0
=A0 =A0 =A0return 0;
=A0}
=
+
+/*
+ * Allow rule for the usermode firewall
+ */<= /div>
+struct ufw_allowed {
+ =A0 =A0struct ufw_allowed *next= ;
+ =A0 =A0unsigned long dst_addr;
+ =A0 =A0/* Port ran= ge. For a single port, dst_lport =3D dst_hport. */
+ =A0 =A0unsigned short dst_lport; =A0 /* in host byte order */
<= div>+ =A0 =A0unsigned short dst_hport; =A0 /* in host byte order */
+};
+
+/*
+ * Global variables for the use= rmode firewall
+ */
+static int drop_udp =3D 0;
+static FILE *dro= p_log_fd =3D NULL;
+static struct ufw_allowed *fw_allowed_udp =3D= NULL;
+
+void slirp_enable_drop_udp(void)
+{=
+ =A0 =A0drop_udp =3D 1;
+}
+
+void slir= p_set_drop_log_fd(FILE *fd)
+{
+ =A0 =A0drop_log_fd =3D= fd;
+}
+
+int slirp_should_drop(unsigned lon= g 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 =A0struct ufw_allowed *fwa =3D NULL;
+ =A0 =A0unsig= ned short dport; =A0 /* host byte order */
+
+ =A0 =A0switch (proto) {
+ =A0 =A0case IPPROTO_UDP:<= /div>
+ =A0 =A0 =A0 =A0if (drop_udp =3D=3D 0) {
+ =A0 =A0 =A0= =A0 =A0 =A0return 0;
+ =A0 =A0 =A0 =A0} else {
+ =A0 = =A0 =A0 =A0 =A0 =A0fwa =3D fw_allowed_udp;
+ =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0break;
+ =A0 =A0cas= e IPPROTO_TCP:
+ =A0 =A0default:
+ =A0 =A0 =A0 =A0retur= n 1; =A0 /* unrecognized protocol. default drop. */
+ =A0 =A0}
+
+ =A0 =A0/* Find matching allow rule. 0 works as a wild= card for address. */
+ =A0 =A0for (; fwa; fwa =3D fwa->next) {
+ =A0 =A0 =A0 = =A0dport =3D ntohs(dst_port);
+ =A0 =A0 =A0 =A0if ((fwa->dst_l= port <=3D dport) && (dport <=3D fwa->dst_hport)) {
+ =A0 =A0 =A0 =A0 =A0 =A0/* allow any destination if 0 */
+ =A0 =A0 =A0 =A0 =A0 =A0if (fwa->dst_addr =3D=3D 0 || fwa->dst_= addr =3D=3D dst_addr) {
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return 0= ;
+ =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0 =A0}
+ =A0 =A0}
+ =A0 =A0return 1;
+}
+
+/*
+ * Register an allow rule for user mode fir= ewall
+ */
+void slirp_add_allow_internal(unsigned long= 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 ufw_allowed *fwa= ;
+
+ =A0 =A0fwa =3D (struct ufw_allowed *)malloc(sizeo= f(struct ufw_allowed));
+ =A0 =A0if (!fwa) {
+ =A0 =A0 =A0 =A0DEBUG_MISC((dfd, "= ;Unabled to create a new firewall rule "
+ =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0"due to malloc failure\n"));
+ = =A0 =A0 =A0 =A0exit(-1);
+ =A0 =A0}
+
+ =A0 =A0fwa->dst_addr =3D dst_addr;
+ =A0 = =A0fwa->dst_lport =3D dst_lport;
+ =A0 =A0fwa->dst_hport = =3D dst_hport;
+
+ =A0 =A0switch (proto) {
+ = =A0 =A0case IPPROTO_UDP:
+ =A0 =A0 =A0 =A0fwa->next =3D fw_allowed_udp;
+ =A0 =A0 = =A0 =A0fw_allowed_udp =3D fwa;
+ =A0 =A0 =A0 =A0break;
= + =A0 =A0case IPPROTO_TCP:
+ =A0 =A0default:
+ =A0 =A0 = =A0 =A0free(fwa);
+ =A0 =A0 =A0 =A0return; =A0 /* unrecognized pr= otocol */
+ =A0 =A0}
+}
+
+/*
+ * Parse = a null-terminated string specifying a network port or port range (e.g.
+ * "[1024-65535]"). In case of a single port, lport and hp= ort 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.
+ */
+void slirp_ad= d_allow(const char *optarg, u_int8_t proto)
+{
+ =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 =A0dst_addr_str =3D strsep(&p, ":"= );
+ =A0 =A0dst_port_str =3D p;
+
+ =A0 =A0if (dst_addr_str =3D=3D NULL || dst_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 &quo= t;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"dst_addr:dst_port or ds= t_addr:[dst_lport-dst_hport]\n",
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0optarg);
+ =A0 =A0 =A0 =A0e= xit(1);
+ =A0 =A0}
+
+ =A0 =A0/* handling &qu= ot;:port" notation (when IP address is omitted entirely). */
+ =A0 =A0if (*dst_addr_str =3D=3D '\0') {
+ =A0 =A0 =A0 =A0dst_addr.s_addr =3D 0;
+ =A0 =A0}
+ =A0 =A0/* inet_aton returns 0 on failure. */
+ =A0 =A0else if = (inet_aton(dst_addr_str, &dst_addr) =3D=3D 0) {
+ =A0 =A0 =A0= =A0fprintf(stderr, "Invalid destination IP address: %s\n", dst_a= ddr_str);
+ =A0 =A0 =A0 =A0exit(1);
+ =A0 =A0}
+
+= =A0 =A0if (parse_port_range(dst_port_str, &dst_lport, &dst_hport) = =3D=3D -1) {
+ =A0 =A0 =A0 =A0fprintf(stderr, "Invalid desti= nation port or port range\n");
+ =A0 =A0 =A0 =A0exit(1);
+ =A0 =A0}
+
+= =A0 =A0slirp_add_allow_internal(dst_addr.s_addr, dst_lport, dst_hport, pro= to);
+
+ =A0 =A0free(argument);
+}
= +
+/*
+ * Write to drop-log
+ */
+int slirp_drop_log(con= st char *format, ...)
+{
+ =A0 =A0va_list args;
+
+ =A0 =A0if (!drop_log_fd) {
+ =A0 =A0 =A0 =A0retu= rn 0;
+ =A0 =A0}
+
+ =A0 =A0va_start(args, format);
+ =A0 =A0vfprintf(drop_log_fd, format, args);
+ =A0 =A0va_end(ar= gs);
+
+ =A0 =A0fflush(drop_log_fd);
+
<= div>+ =A0 =A0return 1;
+}
diff --git a/slirp/slirp.h b/slirp/slirp.h
inde= x 954289a..29ee425 100644
--- a/slirp/slirp.h
+++ b/sli= rp/slirp.h
@@ -299,6 +299,15 @@ int tcp_emu(struct socket *, stru= ct mbuf *);
=A0int tcp_ctl(struct socket *);
=A0struct tcpcb *tcp_drop(s= truct tcpcb *tp, int err);
=A0
+/* slirp.c */
+void slirp_add_allow_internal(unsigned long dst_addr,
+ =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned short dst_lpor= t,
+ =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);
+int parse_port_range(const char = *str,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned short *l= port,
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned short *hport);
+
=A0#ifdef USE_PPP
=A0#define MIN_MRU MINMRU
=A0#define MAX_MRU MAXMRU
diff --git a/slirp/udp.c b/slirp= /udp.c
index 02b3793..db7e4ca 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -67,6 +67,8= @@ udp_input(register struct mbuf *m, int iphlen)
=A0 DEBUG_ARG("m =3D %lx", (long)m)= ;
=A0 DEBUG_ARG("iphlen= =3D %d", iphlen);
=A0
+ =A0 =A0 =A0 =A0time_t tim= estamp =3D time(NULL);
+
=A0 /*
=A0 * Strip IP options, i= f any; should skip this,
=A0= * make available to user, and use on returned packets,
@@ -98,6 +100,28 @@ udp_input(register struct mbuf *m, int iphlen)
=A0 ip->ip_len =3D l= en;
=A0 }
=A0
+ =A0 =A0 =A0 =A0/*
+ =A0 =A0 =A0 =A0 * User m= ode firewall
+ =A0 =A0 =A0 =A0 */
+ =A0 =A0 =A0 =A0if (= slirp_should_drop(ip->ip_dst.s_addr, uh->uh_dport, IPPROTO_UDP)) {
+ =A0 =A0 =A0 =A0 =A0 =A0slirp_drop_log(
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Dropped 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 =A0= ntohs(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 = =A0goto bad;
+ =A0 =A0 =A0 =A0} else {
+ =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 * Save a copy of the IP header in case we want restore it
=A0 * for sending an ICMP= error message in response.
diff --git a/vl.c b/vl.c
in= dex 68c3b53..b0583e3 100644
--- a/vl.c
+++ b/vl.c
@@ -2287,6 +2287,24 @@ int main(int argc, char **argv,= char **envp)
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0exit(1);=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
=A0#endif
+ =A0 =A0 =A0 =A0 =A0 =A0case QEMU_OPTION_drop_udp:
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0slirp_enable_drop_udp();
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
+ =A0 =A0 =A0 =A0 =A0 =A0ca= se QEMU_OPTION_allow_udp:
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0slirp_= add_allow(optarg, IPPROTO_UDP);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= break;
+ =A0 =A0 =A0 =A0 =A0 =A0case QEMU_OPTION_drop_log:
+ =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0{
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0FILE *drop_log_fd;
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0drop_log_fd =3D fopen(optarg, "w");
+
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (!drop_log_fd) {
+ = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fprintf(stderr, "Cannot= open drop log: %s\n", optarg);
+ =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0exit(1);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0= =A0 =A0}
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0slirp_set_drop_log_fd(drop_lo= g_fd);
+ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
+ =A0 =A0 =A0= =A0 =A0 =A0 =A0 =A0break;
=A0 =A0 =A0 =A0 =A0 =A0 =A0case QEMU_O= PTION_bt:
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0add_device_config(DE= V_BT, optarg);
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;

--001636e0ae0fd0db1704a0bb0e73--