@@ -929,6 +929,10 @@ static const struct {
.name = "drop",
.type = QEMU_OPT_STRING,
.help = "Enable the simple reverse firewall",
+ }, {
+ .name = "droplog",
+ .type = QEMU_OPT_STRING,
+ .help = "Set log filename for the reverse firewall",
},
{ /* end of list */ }
},
@@ -141,7 +141,8 @@ 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, unsigned char drop)
+ const char *vsmbserver, unsigned char drop,
+ FILE *drop_log)
{
/* default settings according to historic slirp */
struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
@@ -245,8 +246,8 @@ 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, drop, s);
+ s->slirp = slirp_init(restricted, net, mask, host, vhostname,
tftp_export,
+ bootfile, dhcp, dns, drop, drop_log, s);
QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
for (config = slirp_configs; config; config = config->next) {
@@ -690,10 +691,12 @@ int net_init_slirp(QemuOpts *opts,
const char *bootfile;
const char *smb_export;
const char *vsmbsrv;
+ const char *droplog_filename;
char *vnet = NULL;
int restricted = 0;
int ret;
unsigned char drop = 0;
+ FILE *drop_log = NULL;
vhost = qemu_opt_get(opts, "host");
vhostname = qemu_opt_get(opts, "hostname");
@@ -741,11 +744,20 @@ int net_init_slirp(QemuOpts *opts,
}
}
+ droplog_filename = qemu_opt_get(opts, "droplog");
+ if (droplog_filename) {
+ drop_log = fopen(droplog_filename, "w");
+ if (!drop_log) {
+ error_report("Unable to open reverse firewall log");
+ 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, drop);
+ vnamesrv, smb_export, vsmbsrv, drop, drop_log);
while (slirp_configs) {
config = slirp_configs;
@@ -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][,drop=udp|all]"
+ "
[,hostfwd=rule][,guestfwd=rule][,drop=udp|all][,droplog=file]"
#ifndef _WIN32
"[,smb=dir[,smbserver=addr]]\n"
#endif
@@ -15,7 +15,7 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
const char *vhostname, const char *tftp_path,
const char *bootfile, struct in_addr vdhcp_start,
struct in_addr vnameserver, unsigned char drop,
- void *opaque);
+ FILE *drop_log, void *opaque);
void slirp_cleanup(Slirp *slirp);
void slirp_select_fill(int *pnfds,
@@ -48,6 +48,7 @@ size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr
guest_addr,
/* Reverse Firewall */
#define SLIRP_DROP_UDP 1
+int slirp_drop_log(FILE *drop_log, const char *format, ...);
int slirp_should_drop(Slirp *slirp,
struct in_addr dst_addr,
unsigned short dst_port,
@@ -200,7 +200,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, unsigned char drop, void
*opaque)
+ struct in_addr vnameserver, unsigned char drop,
+ FILE *drop_log, void *opaque)
{
Slirp *slirp = qemu_mallocz(sizeof(Slirp));
@@ -231,6 +232,7 @@ Slirp *slirp_init(int restricted, struct in_addr
vnetwork,
slirp->vnameserver_addr = vnameserver;
slirp->drop = drop;
+ slirp->drop_log = drop_log;
slirp->opaque = opaque;
@@ -248,6 +250,9 @@ void slirp_cleanup(Slirp *slirp)
unregister_savevm(NULL, "slirp", slirp);
+ if (slirp->drop_log) {
+ fclose(slirp->drop_log);
+ }
qemu_free(slirp->tftp_prefix);
qemu_free(slirp->bootp_filename);
qemu_free(slirp);
@@ -1114,6 +1119,9 @@ static int slirp_state_load(QEMUFile *f, void *opaque,
int version_id)
return 0;
}
+/*
+ * Returns 1 if the packet should be dropped.
+ */
int slirp_should_drop(Slirp *slirp,
struct in_addr dst_addr,
unsigned short dst_port,
@@ -1130,3 +1138,23 @@ int slirp_should_drop(Slirp *slirp,
return 1;
}
+
+/*
+ * Write to drop-log
+ */
+int slirp_drop_log(FILE *drop_log, const char *format, ...)
+{
+ va_list args;
+
+ if (!drop_log) {
+ return 0;
+ }
+
+ va_start(args, format);
+ vfprintf(drop_log, format, args);
+ va_end(args);
+
+ fflush(drop_log);
+
+ return 1;
+}
@@ -182,6 +182,7 @@ struct Slirp {
/* Reverse Firewall configuration */
unsigned char drop;
+ FILE *drop_log;
/* ARP cache for the guest IP addresses (XXX: allow many entries) */
uint8_t client_ethaddr[6];
@@ -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,
@@ -104,6 +106,14 @@ udp_input(register struct mbuf *m, int iphlen)
if (slirp_should_drop(
slirp, ip->ip_dst, uh->uh_dport, IPPROTO_UDP)) {
/* DROP */
+ slirp_drop_log(
+ 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 {
/* PASS */
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 <dnojiri@google.com>