From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:44440) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Q9ozE-0002HQ-0u for qemu-devel@nongnu.org; Tue, 12 Apr 2011 21:35:19 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Q9oOD-00074h-11 for qemu-devel@nongnu.org; Tue, 12 Apr 2011 20:57:03 -0400 Received: from smtp-out.google.com ([74.125.121.67]:36338) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Q9oOC-00072r-E5 for qemu-devel@nongnu.org; Tue, 12 Apr 2011 20:57:00 -0400 Received: from wpaz17.hot.corp.google.com (wpaz17.hot.corp.google.com [172.24.198.81]) by smtp-out.google.com with ESMTP id p3D0uxFB004448 for ; Tue, 12 Apr 2011 17:56:59 -0700 Received: from pwi14 (pwi14.prod.google.com [10.241.219.14]) by wpaz17.hot.corp.google.com with ESMTP id p3D0uv9N015307 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for ; Tue, 12 Apr 2011 17:56:57 -0700 Received: by pwi14 with SMTP id 14so126963pwi.35 for ; Tue, 12 Apr 2011 17:56:56 -0700 (PDT) MIME-Version: 1.0 Date: Tue, 12 Apr 2011 17:56:56 -0700 Message-ID: From: Daisuke Nojiri Content-Type: multipart/alternative; boundary=001636e0ae0f0f523704a0c24947 Subject: [Qemu-devel] [PATCH 3/3] Slirp Reverse UDP Firewall List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org --001636e0ae0f0f523704a0c24947 Content-Type: text/plain; charset=ISO-8859-1 This patch series adds a reverse UDP firewall functionality to Slirp. The series consists of three patches. Each adds one -net user option: 1. dropudp=y|n - enables the firewall 2. droplog=FILE - sets the drop log filename 3. allow=udp:ADDR:PORT - adds an allow rule e.g.) $ qemu -net user,dropudp=y,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]). 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.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", ntohl(ip->ip_src.s_addr), @@ -114,7 +113,13 @@ udp_input(register struct mbuf *m, int iphlen) timestamp); goto bad; } else { - /* PASS */ + 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); } /* --001636e0ae0f0f523704a0c24947 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
This patch series adds a reverse UDP firewall functionality to Slirp.<= /div>
The series consists of three patches. Each adds one -net user opt= ion:

=A0 =A0 1. dropudp=3Dy|n - enables the firewa= ll
=A0 =A0 2. droplog=3DFILE - sets the drop log filename
=A0 = =A0 3. allow=3Dudp:ADDR:PORT - adds an allow rule

= =A0 e.g.) $ qemu -net user,dropudp=3Dy,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]). If ADDR is
ommitted, all addresses match the rule.

TCP s= upport will follow (in another patch series).

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

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 {
=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 38995ec..047edc= 2 100644
--- a/net/slirp.c
+++ b/net/slirp.c
= @@ -58,6 +58,7 @@ static int get_str_sep(char *buf, int buf_size, const cha= r **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;
@@ -254,6 +255,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(config->str))
+ =A0 =A0= =A0 =A0 =A0 =A0 =A0 =A0goto error;
=A0 =A0 =A0 =A0 =A0} else {
=A0 =A0 =A0 =A0 =A0 =A0 =A0if (slirp_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) < 0)
@@ -658,7 +662,9 @@ st= atic 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
=
@@ -668,6 +674,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;
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,
=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][,d= ropudp=3Dy|n][,droplog=3Dfile]"
+ =A0 =A0" =A0 =A0 =A0 = =A0 [,hostfwd=3Drule][,guestfwd=3Drule][,dropudp=3Dy|n][,droplog=3Dfile][,a= llow=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 = =A0connect the user mode network stack to VLAN 'n', configure its\n= "
=A0 =A0 =A0" =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0DHCP server and enabl= ed optional services\n"
diff --git a/slirp/libslirp.h b/slir= p/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,
=A0/* Usermode fire= wall functions */
=A0void slirp_enable_drop_udp(void);
=A0void slirp_set_drop_log_fd(FILE *fd);
+int slirp_add_allow(con= st char *optarg);
=A0int slirp_drop_log(const char *format, ...);=
=A0int slirp_should_drop(unsigned long dst_addr,
=A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0unsigned short dst_port,
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 29dd0ca..a6= e2bc0 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -1113,10 +1113,22 @@ static int slirp_state_load(QEMUFile *f, vo= id *opaque, int version_id)
=A0}
=A0
=A0/*
+ * Allow rule for the us= ermode firewall
+ */
+struct ufw_allowed {
+ = =A0 =A0struct ufw_allowed *next;
+ =A0 =A0unsigned long dst_addr;=
+ =A0 =A0/* Port range. For a single port, dst_lport =3D dst_hport. */
+ =A0 =A0unsigned short dst_lport; =A0 /* in host byte order */
=
+ =A0 =A0unsigned short dst_hport; =A0 /* in host byte order */
<= div>+};
+
+/*
=A0 * Global variables for the usermode firewall<= /div>
=A0 */
=A0static int drop_udp =3D 0;
=A0stati= c FILE *drop_log_fd =3D NULL;
+static struct ufw_allowed *fw_allo= wed_udp =3D NULL;
=A0
=A0void slirp_enable_drop_udp(void)
=A0{
=
@@ -1131,21 +1143,156 @@ void slirp_set_drop_log_fd(FILE *fd)
=A0int slirp_should_drop(unsigned long dst_addr,
=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 =A0struct ufw_allowed *fwa =3D NULL;
+ =A0 =A0unsigned= short dport; =A0 /* host byte order */
+
=A0 =A0 =A0sw= itch (proto) {
=A0 =A0 =A0case IPPROTO_UDP:
=A0 =A0 =A0 =A0 =A0if (drop_udp =3D=3D 0) {
=A0 =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 =A0 =A0 =A0break;
=A0 =A0 =A0case IPPROTO_TCP:
=A0 =A0 =A0default:
- =A0 =A0 =A0 =A0return 0; =A0 /* unreco= gnized protocol. default pass. */
+ =A0 =A0 =A0 =A0return 1; =A0 = /* unrecognized protocol. default drop. */
=A0 =A0 =A0}
=A0
+ =A0 =A0/* Find matching allow rule. 0 works as a wildcard = 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 =A0 =A0return 1;
=A0}
=A0
=A0/*
+ * Register an allow rule for user mode= firewall
+ */
+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.
+ */
+int slirp_add= _allow(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}
+ =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 a= ddress: %s\n", dst_addr_str);
+ =A0 =A0 =A0 =A0return -1;
+ =A0 =A0}
+
+ =A0 =A0if (parse_port_range(dst_port_str, &dst_lport, &dst_hport= ) =3D=3D -1) {
+ =A0 =A0 =A0 =A0fprintf(stderr, "Invalid des= tination port or port range\n");
+ =A0 =A0 =A0 =A0return -1;
+ =A0 =A0}
+
+ =A0 =A0slirp_add_allow_internal(dst_addr.s_addr, dst_lport, dst_hport, p= roto);
+
+ =A0 =A0free(argument);
+ =A0 =A0re= turn 0;
+}
+
+/*
=A0 * Write to drop-log
=A0 */
=A0int 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 *);
=A0int tc= p_ctl(struct socket *);
=A0struct tcpcb *tcp_drop(struct tcpcb *t= p, 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_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);
+int 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#ifdef USE_PPP
=A0#define MIN_MRU MINMRU
=A0#define MAX_MRU MAXMRU
diff --git a/slirp/udp.c b/slirp/udp.c=
index f92731c..db7e4ca 100644
--- a/slirp/udp.c
<= div> +++ b/slirp/udp.c
@@ -104,7 +104,6 @@ udp_input(register struct m= buf *m, int iphlen)
=A0 =A0 =A0 =A0 =A0 * User mode firewall
=A0 =A0 =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 =A0/* DROP */
=A0 =A0 =A0 =A0 =A0 =A0 = =A0slirp_drop_log(
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Dropp= ed UDP: src:0x%08x:0x%04hx dst:0x%08x:0x%04hx %ld\n",
=A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0ntohl(ip->ip_src.s_addr),
@@ -114,7 +113,13 @@ udp_input(register struct mbuf *m, int iphlen)
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0timestamp);
=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 =A0sl= irp_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 =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}
=A0
=A0 /*

--001636e0ae0f0f523704a0c24947--