aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--android/avd/hardware-properties.ini22
-rw-r--r--android/avd/hw-config-defs.h23
-rw-r--r--android/avd/info.c65
-rw-r--r--android/avd/info.h6
-rw-r--r--android/main-common.c67
-rw-r--r--android/main-common.h2
-rw-r--r--android/main-ui.c55
-rw-r--r--android/main.c59
-rw-r--r--android/qemulator.c2
-rw-r--r--android/qemulator.h4
-rw-r--r--qemu-options.hx93
-rw-r--r--slirp-android/libslirp.h57
-rw-r--r--slirp-android/slirp.c302
-rw-r--r--slirp-android/socket.c21
-rw-r--r--slirp-android/tcp_subr.c169
-rw-r--r--slirp-android/udp.c51
-rw-r--r--slirp-android/udp.h4
-rw-r--r--vl-android.c362
18 files changed, 1150 insertions, 214 deletions
diff --git a/android/avd/hardware-properties.ini b/android/avd/hardware-properties.ini
index 6b106f4..89acf9f 100644
--- a/android/avd/hardware-properties.ini
+++ b/android/avd/hardware-properties.ini
@@ -24,6 +24,8 @@
#
# Ram size
+# Default value will be computed based on screen pixels
+# or skin version
name = hw.ramSize
type = integer
default = 0
@@ -146,6 +148,23 @@ type = diskSize
abstract = Cache partition size
default = 66MB
+# LCD width
+name = hw.lcd.width
+type = integer
+default = 320
+abstract = LCD pixel width
+
+name = hw.lcd.height
+type = integer
+default = 640
+abstract = LCD pixel height
+
+name = hw.lcd.depth
+type = integer
+default = 16
+abstract = LCD color depth
+description = Must be 16 or 32. Color bit depth of emulated framebuffer.
+
# LCD density
name = hw.lcd.density
type = integer
@@ -155,9 +174,10 @@ description = Must be one of 120, 160 or 240. A value used to roughly describe t
# Maximum VM heap size
# Higher values are required for high-dpi devices
+# Default will depend on RAM size.
name = vm.heapSize
type = integer
-default = 16
+default = 0
abstract = Max VM application heap size
description = The maximum heap size a Dalvik application might allocate before being killed by the system. Value is in megabytes.
diff --git a/android/avd/hw-config-defs.h b/android/avd/hw-config-defs.h
index 0c87bdb..4afc4d7 100644
--- a/android/avd/hw-config-defs.h
+++ b/android/avd/hw-config-defs.h
@@ -144,6 +144,27 @@ HWCFG_DISKSIZE(
"")
HWCFG_INT(
+ hw_lcd_width,
+ "hw.lcd.width",
+ 320,
+ "LCD pixel width",
+ "")
+
+HWCFG_INT(
+ hw_lcd_height,
+ "hw.lcd.height",
+ 640,
+ "LCD pixel height",
+ "")
+
+HWCFG_INT(
+ hw_lcd_depth,
+ "hw.lcd.depth",
+ 16,
+ "LCD color depth",
+ "Must be 16 or 32. Color bit depth of emulated framebuffer.")
+
+HWCFG_INT(
hw_lcd_density,
"hw.lcd.density",
160,
@@ -153,7 +174,7 @@ HWCFG_INT(
HWCFG_INT(
vm_heapSize,
"vm.heapSize",
- 16,
+ 0,
"Max VM application heap size",
"The maximum heap size a Dalvik application might allocate before being killed by the system. Value is in megabytes.")
diff --git a/android/avd/info.c b/android/avd/info.c
index 058226c..e3d38bb 100644
--- a/android/avd/info.c
+++ b/android/avd/info.c
@@ -93,6 +93,12 @@ AvdInfo* android_avdInfo;
*/
#define SDCARD_PATH "sdcard.path"
+/* the name of the .ini file that will contain the complete hardware
+ * properties for the AVD. This will be used to launch the corresponding
+ * core from the UI.
+ */
+#define CORE_HARDWARE_INI "qemu-hardware.ini"
+
/* certain disk image files are mounted read/write by the emulator
* to ensure that several emulators referencing the same files
* do not corrupt these files, we need to lock them and respond
@@ -134,11 +140,12 @@ struct AvdInfo {
char* contentPath;
IniFile* rootIni; /* root <foo>.ini file */
IniFile* configIni; /* virtual device's config.ini */
- IniFile* hardwareIni; /* skin-specific hardware.ini */
+ IniFile* skinHardwareIni; /* skin-specific hardware.ini */
/* for both */
char* skinName; /* skin name */
char* skinDirPath; /* skin directory */
+ char* coreHardwareIniPath; /* core hardware.ini path */
/* image files */
char* imagePath [ AVD_IMAGE_MAX ];
@@ -157,6 +164,7 @@ avdInfo_free( AvdInfo* i )
AFREE(i->skinName);
AFREE(i->skinDirPath);
+ AFREE(i->coreHardwareIniPath);
for (nn = 0; nn < i->numSearchPaths; nn++)
AFREE(i->searchPaths[nn]);
@@ -168,9 +176,9 @@ avdInfo_free( AvdInfo* i )
i->configIni = NULL;
}
- if (i->hardwareIni) {
- iniFile_free(i->hardwareIni);
- i->hardwareIni = NULL;
+ if (i->skinHardwareIni) {
+ iniFile_free(i->skinHardwareIni);
+ i->skinHardwareIni = NULL;
}
if (i->rootIni) {
@@ -558,7 +566,7 @@ imageLoader_empty( ImageLoader* l, unsigned flags )
}
-/* copy image file from a given source
+/* copy image file from a given source
* assumes locking is needed.
*/
static void
@@ -606,7 +614,7 @@ imageLoader_load( ImageLoader* l,
/* set image state */
l->pState[0] = (flags & IMAGE_DONT_LOCK) == 0
- ? IMAGE_STATE_MUSTLOCK
+ ? IMAGE_STATE_MUSTLOCK
: IMAGE_STATE_READONLY;
/* check user-provided path */
@@ -651,7 +659,7 @@ imageLoader_load( ImageLoader* l,
if (flags & IMAGE_REQUIRED) {
AvdInfo* i = l->info;
- derror("could not find required %s image (%s).",
+ derror("could not find required %s image (%s).",
l->imageText, l->imageFile);
if (i->inAndroidBuild) {
@@ -1088,6 +1096,22 @@ _getSDCardPath( AvdInfo* i, AvdInfoParams* params )
params->forcePaths[AVD_IMAGE_SDCARD] = path;
}
+static int
+_getCoreHwIniPath( AvdInfo* i, const char* basePath )
+{
+ char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
+
+ p = bufprint(temp, end, "%s/%s", basePath, CORE_HARDWARE_INI);
+ if (p >= end) {
+ DD("Path too long for %s:", CORE_HARDWARE_INI, basePath);
+ return -1;
+ }
+
+ D("using core hw config path: %s", temp);
+ i->coreHardwareIniPath = ASTRDUP(temp);
+ return 0;
+}
+
AvdInfo*
avdInfo_new( const char* name, AvdInfoParams* params )
{
@@ -1107,7 +1131,8 @@ avdInfo_new( const char* name, AvdInfoParams* params )
if ( _getSdkRoot(i) < 0 ||
_getRootIni(i) < 0 ||
_getContentPath(i) < 0 ||
- _getConfigIni(i) < 0 )
+ _getConfigIni(i) < 0 ||
+ _getCoreHwIniPath(i, i->contentPath) < 0 )
goto FAIL;
/* look for image search paths. handle post 1.1/pre cupcake
@@ -1280,7 +1305,7 @@ _getBuildImagePaths( AvdInfo* i, AvdInfoParams* params )
/* if the user provided one cache image, lock & use it */
if ( params->forcePaths[l->id] != NULL ) {
- imageLoader_load(l, IMAGE_REQUIRED |
+ imageLoader_load(l, IMAGE_REQUIRED |
IMAGE_IGNORE_IF_LOCKED);
}
}
@@ -1373,7 +1398,7 @@ _getBuildSkin( AvdInfo* i, AvdInfoParams* params )
/* Read a hardware.ini if it is located in the skin directory */
static int
-_getBuildHardwareIni( AvdInfo* i )
+_getBuildSkinHardwareIni( AvdInfo* i )
{
char temp[PATH_MAX], *p=temp, *end=p+sizeof(temp);
@@ -1387,14 +1412,13 @@ _getBuildHardwareIni( AvdInfo* i )
}
D("found skin-specific hardware.ini: %s", temp);
- i->hardwareIni = iniFile_newFromFile(temp);
- if (i->hardwareIni == NULL)
+ i->skinHardwareIni = iniFile_newFromFile(temp);
+ if (i->skinHardwareIni == NULL)
return -1;
return 0;
}
-
AvdInfo*
avdInfo_newForAndroidBuild( const char* androidBuildRoot,
const char* androidOut,
@@ -1413,12 +1437,13 @@ avdInfo_newForAndroidBuild( const char* androidBuildRoot,
i->deviceName = ASTRDUP("<build>");
if (_getBuildConfigIni(i) < 0 ||
- _getBuildImagePaths(i, params) < 0 )
+ _getBuildImagePaths(i, params) < 0 ||
+ _getCoreHwIniPath(i, i->androidOut) < 0 )
goto FAIL;
/* we don't need to fail if there is no valid skin */
_getBuildSkin(i, params);
- _getBuildHardwareIni(i);
+ _getBuildSkinHardwareIni(i);
return i;
@@ -1492,8 +1517,8 @@ avdInfo_getHwConfig( AvdInfo* i, AndroidHwConfig* hw )
if (ini != i->configIni)
iniFile_free(ini);
- if (ret == 0 && i->hardwareIni != NULL) {
- ret = androidHwConfig_read(hw, i->hardwareIni);
+ if (ret == 0 && i->skinHardwareIni != NULL) {
+ ret = androidHwConfig_read(hw, i->skinHardwareIni);
}
/* special product-specific hardware configuration */
@@ -1539,3 +1564,9 @@ avdInfo_getTracePath( AvdInfo* i, const char* traceName )
}
return ASTRDUP(tmp);
}
+
+const char*
+avdInfo_getCoreHwIniPath( AvdInfo* i )
+{
+ return i->coreHardwareIniPath;
+}
diff --git a/android/avd/info.h b/android/avd/info.h
index 2b2899f..9ccee30 100644
--- a/android/avd/info.h
+++ b/android/avd/info.h
@@ -183,6 +183,12 @@ int avdInfo_getHwConfig( AvdInfo* i, AndroidHwConfig* hw );
/* Returns a *copy* of the path used to store trace 'foo'. result must be freed by caller */
char* avdInfo_getTracePath( AvdInfo* i, const char* traceName );
+/* Returns the path of the hardware.ini where we will write the AVD's
+ * complete hardware configuration before launching the corresponding
+ * core.
+ */
+const char* avdInfo_getCoreHwIniPath( AvdInfo* i );
+
/* */
#endif /* ANDROID_AVD_INFO_H */
diff --git a/android/main-common.c b/android/main-common.c
index bb07943..a63983b 100644
--- a/android/main-common.c
+++ b/android/main-common.c
@@ -341,6 +341,7 @@ void
parse_skin_files(const char* skinDirPath,
const char* skinName,
AndroidOptions* opts,
+ AndroidHwConfig* hwConfig,
AConfig* *skinConfig,
char* *skinPath)
{
@@ -433,6 +434,53 @@ FOUND_SKIN:
skin_network_delay = aconfig_str(n, "delay", 0);
}
+ /* extract framebuffer information from the skin.
+ *
+ * for version 1 of the skin format, they are in the top-level
+ * 'display' element.
+ *
+ * for version 2 of the skin format, they are under parts.device.display
+ */
+ n = aconfig_find(root, "display");
+ if (n == NULL) {
+ n = aconfig_find(root, "parts");
+ if (n != NULL) {
+ n = aconfig_find(root, "device");
+ if (n != NULL) {
+ n = aconfig_find(root, "display");
+ }
+ }
+ }
+
+ if (n != NULL) {
+ int width = aconfig_int(n, "width", hwConfig->hw_lcd_width);
+ int height = aconfig_int(n, "height", hwConfig->hw_lcd_height);
+ int depth = aconfig_int(n, "bpp", hwConfig->hw_lcd_depth);
+
+ if (width > 0 && height > 0) {
+ /* The emulated framebuffer wants sizes that are multiples of 4 */
+ if (((width|height) & 3) != 0) {
+ width = (width+3) & ~3;
+ height = (height+3) & ~3;
+ D("adjusting LCD dimensions to (%dx%dx)", width, height);
+ }
+
+ /* only depth values of 16 and 32 are correct. 16 is the default. */
+ if (depth != 32 && depth != 16) {
+ depth = 16;
+ D("adjusting LCD bit depth to %d", depth);
+ }
+
+ hwConfig->hw_lcd_width = width;
+ hwConfig->hw_lcd_height = height;
+ hwConfig->hw_lcd_depth = depth;
+ }
+ else {
+ D("ignoring invalid skin LCD dimensions (%dx%dx%d)",
+ width, height, depth);
+ }
+ }
+
*skinConfig = root;
*skinPath = strdup(path);
return;
@@ -536,22 +584,3 @@ init_sdl_ui(AConfig* skinConfig,
qemulator_get()->onion_rotation = rotate;
}
}
-
-int64_t get_screen_pixels(AConfig* skinConfig)
-{
- int64_t pixels = 0;
- AConfig* disp;
-
- if (skinConfig != NULL) {
- disp = aconfig_find(skinConfig, "display");
- if (disp != NULL) {
- int width = aconfig_int(disp, "width", 0);
- int height = aconfig_int(disp, "height", 0);
- pixels = (int64_t)width*height;
- }
- }
- if (pixels == 0)
- pixels = 320*240;
-
- return pixels;
-}
diff --git a/android/main-common.h b/android/main-common.h
index c5131df..88ebb70 100644
--- a/android/main-common.h
+++ b/android/main-common.h
@@ -16,6 +16,7 @@
#include "android/cmdline-option.h"
#include "android/skin/keyset.h"
#include "android/config.h"
+#include "android/avd/hw-config.h"
/* Common routines used by both android/main.c and android/main-ui.c */
@@ -45,6 +46,7 @@ extern const char* skin_network_delay;
void parse_skin_files(const char* skinDirPath,
const char* skinName,
AndroidOptions* opts,
+ AndroidHwConfig* hwConfig,
AConfig* *skinConfig,
char* *skinPath);
diff --git a/android/main-ui.c b/android/main-ui.c
index 273f402..f1f8539 100644
--- a/android/main-ui.c
+++ b/android/main-ui.c
@@ -490,8 +490,6 @@ int main(int argc, char **argv)
char* android_build_out = NULL;
AndroidOptions opts[1];
- /* LCD density value to pass to the core. */
- char lcd_density[16];
/* net.shared_net_ip boot property value. */
char boot_prop_ip[64];
boot_prop_ip[0] = '\0';
@@ -876,7 +874,7 @@ int main(int argc, char **argv)
user_config_init();
- parse_skin_files(opts->skindir, opts->skin, opts,
+ parse_skin_files(opts->skindir, opts->skin, opts, hw,
&skinConfig, &skinPath);
if (!opts->netspeed) {
@@ -1257,6 +1255,7 @@ int main(int argc, char **argv)
derror( "physical memory size must be between 32 and 4096 MB" );
exit(1);
}
+ hw->hw_ramSize = ramSize;
}
if (!opts->memory) {
int ramSize = hw->hw_ramSize;
@@ -1266,8 +1265,7 @@ int main(int argc, char **argv)
* size through its hardware.ini (i.e. legacy ones) or when
* in the full Android build system.
*/
- int64_t pixels = get_screen_pixels(skinConfig);
-
+ int64_t pixels = hw->hw_lcd_width * hw->hw_lcd_height;
/* The following thresholds are a bit liberal, but we
* essentially want to ensure the following mappings:
*
@@ -1285,8 +1283,30 @@ int main(int argc, char **argv)
else
ramSize = 256;
}
- bufprint(tmp, tmpend, "%d", ramSize);
- opts->memory = android_strdup(tmp);
+ hw->hw_ramSize = ramSize;
+ }
+
+ D("Physical RAM size: %dMB\n", hw->hw_ramSize);
+
+ if (hw->vm_heapSize == 0) {
+ /* Compute the default heap size based on the RAM size.
+ * Essentially, we want to ensure the following liberal mappings:
+ *
+ * 96MB RAM -> 16MB heap
+ * 128MB RAM -> 24MB heap
+ * 256MB RAM -> 48MB heap
+ */
+ int ramSize = hw->hw_ramSize;
+ int heapSize;
+
+ if (ramSize < 100)
+ heapSize = 16;
+ else if (ramSize < 192)
+ heapSize = 24;
+ else
+ heapSize = 48;
+
+ hw->vm_heapSize = heapSize;
}
if (opts->trace) {
@@ -1296,11 +1316,6 @@ int main(int argc, char **argv)
args[n++] = "off";
}
- /* Pass LCD density value to the core. */
- snprintf(lcd_density, sizeof(lcd_density), "%d", hw->hw_lcd_density);
- args[n++] = "-lcd-density";
- args[n++] = lcd_density;
-
/* Pass boot properties to the core. */
if (opts->prop != NULL) {
ParamList* pl = opts->prop;
@@ -1465,21 +1480,15 @@ int main(int argc, char **argv)
* launch the core with the -android-hw <file> option.
*/
{
- TempFile* tempHw = tempfile_create();
- if (tempHw == NULL) {
- derror("Could not create temporary hardware.ini: %s", strerror(errno));
- exit(2);
- }
-
- const char* tempHwPath = tempfile_path(tempHw);
- IniFile* hwIni = iniFile_newFromMemory("", NULL);
+ const char* coreHwIniPath = avdInfo_getCoreHwIniPath(avd);
+ IniFile* hwIni = iniFile_newFromMemory("", NULL);
androidHwConfig_write(hw, hwIni);
- if (iniFile_saveToFile(hwIni, tempHwPath) < 0) {
- derror("Could not write temporary hardware.ini: %s", tempHwPath);
+ if (iniFile_saveToFile(hwIni, coreHwIniPath) < 0) {
+ derror("Could not write hardware.ini to %s: %s", coreHwIniPath, strerror(errno));
exit(2);
}
args[n++] = "-android-hw";
- args[n++] = strdup(tempHwPath);
+ args[n++] = strdup(coreHwIniPath);
}
if(VERBOSE_CHECK(init)) {
diff --git a/android/main.c b/android/main.c
index 51ef6d7..7a228f0 100644
--- a/android/main.c
+++ b/android/main.c
@@ -298,8 +298,6 @@ int main(int argc, char **argv)
char* android_build_out = NULL;
AndroidOptions opts[1];
- /* LCD density value to pass to the core. */
- char lcd_density[16];
/* net.shared_net_ip boot property value. */
char boot_prop_ip[64];
boot_prop_ip[0] = '\0';
@@ -667,7 +665,7 @@ int main(int argc, char **argv)
user_config_init();
- parse_skin_files(opts->skindir, opts->skin, opts,
+ parse_skin_files(opts->skindir, opts->skin, opts, hw,
&skinConfig, &skinPath);
if (!opts->netspeed) {
@@ -1050,6 +1048,7 @@ int main(int argc, char **argv)
derror( "physical memory size must be between 32 and 4096 MB" );
exit(1);
}
+ hw->hw_ramSize = ramSize;
}
if (!opts->memory) {
int ramSize = hw->hw_ramSize;
@@ -1059,8 +1058,7 @@ int main(int argc, char **argv)
* size through its hardware.ini (i.e. legacy ones) or when
* in the full Android build system.
*/
- int64_t pixels = get_screen_pixels(skinConfig);
-
+ int64_t pixels = hw->hw_lcd_width * hw->hw_lcd_height;
/* The following thresholds are a bit liberal, but we
* essentially want to ensure the following mappings:
*
@@ -1078,8 +1076,30 @@ int main(int argc, char **argv)
else
ramSize = 256;
}
- bufprint(tmp, tmpend, "%d", ramSize);
- opts->memory = android_strdup(tmp);
+ hw->hw_ramSize = ramSize;
+ }
+
+ D("Physical RAM size: %dMB\n", hw->hw_ramSize);
+
+ if (hw->vm_heapSize == 0) {
+ /* Compute the default heap size based on the RAM size.
+ * Essentially, we want to ensure the following liberal mappings:
+ *
+ * 96MB RAM -> 16MB heap
+ * 128MB RAM -> 24MB heap
+ * 256MB RAM -> 48MB heap
+ */
+ int ramSize = hw->hw_ramSize;
+ int heapSize;
+
+ if (ramSize < 100)
+ heapSize = 16;
+ else if (ramSize < 192)
+ heapSize = 24;
+ else
+ heapSize = 48;
+
+ hw->vm_heapSize = heapSize;
}
if (opts->trace) {
@@ -1089,11 +1109,6 @@ int main(int argc, char **argv)
args[n++] = "off";
}
- /* Pass LCD density value to the core. */
- snprintf(lcd_density, sizeof(lcd_density), "%d", get_device_dpi(opts));
- args[n++] = "-lcd-density";
- args[n++] = lcd_density;
-
/* Pass boot properties to the core. */
if (opts->prop != NULL) {
ParamList* pl = opts->prop;
@@ -1216,9 +1231,7 @@ int main(int argc, char **argv)
args[n++] = opts->memcheck;
}
- /* physical memory */
- args[n++] = "-m";
- args[n++] = opts->memory;
+ /* physical memory is now in hw->hw_ramSize */
/* on Linux, the 'dynticks' clock sometimes doesn't work
* properly. this results in the UI freezing while emulation
@@ -1262,21 +1275,15 @@ int main(int argc, char **argv)
* launch the core with the -android-hw <file> option.
*/
{
- TempFile* tempHw = tempfile_create();
- if (tempHw == NULL) {
- derror("Could not create temporary hardware.ini: %s", strerror(errno));
- exit(2);
- }
-
- const char* tempHwPath = tempfile_path(tempHw);
- IniFile* hwIni = iniFile_newFromMemory("", NULL);
+ const char* coreHwIniPath = avdInfo_getCoreHwIniPath(avd);
+ IniFile* hwIni = iniFile_newFromMemory("", NULL);
androidHwConfig_write(hw, hwIni);
- if (iniFile_saveToFile(hwIni, tempHwPath) < 0) {
- derror("Could not write temporary hardware.ini: %s", tempHwPath);
+ if (iniFile_saveToFile(hwIni, coreHwIniPath) < 0) {
+ derror("Could not write hardware.ini to %s: %s", coreHwIniPath, strerror(errno));
exit(2);
}
args[n++] = "-android-hw";
- args[n++] = strdup(tempHwPath);
+ args[n++] = strdup(coreHwIniPath);
}
if(VERBOSE_CHECK(init)) {
diff --git a/android/qemulator.c b/android/qemulator.c
index ee9ccbb..b15d751 100644
--- a/android/qemulator.c
+++ b/android/qemulator.c
@@ -258,7 +258,7 @@ qemulator_set_title(QEmulator* emulator)
* Helper routines
*/
-int
+static int
get_device_dpi( AndroidOptions* opts )
{
int dpi_device = corecmd_get_hw_lcd_density();
diff --git a/android/qemulator.h b/android/qemulator.h
index 189cc53..bd77ae1 100644
--- a/android/qemulator.h
+++ b/android/qemulator.h
@@ -66,8 +66,4 @@ qemulator_get_layout( QEmulator* emulator );
QFrameBuffer*
qemulator_get_first_framebuffer(QEmulator* emulator);
-/* A helper routine for getting device DPI. */
-int
-get_device_dpi( AndroidOptions* opts );
-
#endif // QEMU_ANDROID_QEMULATOR_H
diff --git a/qemu-options.hx b/qemu-options.hx
index baae81b..80efaa6 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1440,6 +1440,95 @@ Set the initial date of the real time clock. Valid formats for
@code{2006-06-17}. The default value is @code{now}.
ETEXI
+/* Start user mode network stack restrictions */
+DEF("drop-udp", 0, QEMU_OPTION_drop_udp, \
+ "-drop-udp starts filtering all UDP packets\n")
+STEXI
+
+@item -drop-udp
+Enable dropping of all UDP packets.
+ETEXI
+
+
+DEF("drop-tcp", 0, QEMU_OPTION_drop_tcp, \
+ "-drop-tcp starts filtering all TCP packets\n")
+STEXI
+
+@item -drop-tcp
+Enable dropping of all TCP packets.
+ETEXI
+
+
+DEF("allow-tcp", HAS_ARG, QEMU_OPTION_allow_tcp, \
+ "-allow-tcp Only allows TCP packets for host:port\n")
+STEXI
+
+@item -allow-tcp @var{host}:@var{port}
+Allows communication with the host named @code{host} and with
+the port @code{port}.
+ETEXI
+
+
+DEF("drop-log", 0, QEMU_OPTION_drop_log, \
+ "-drop-log Creates a log for dropped connections\n")
+STEXI
+
+@item -drop-log @var{file}
+Creates a log for dropped connections in the file @code{file}.
+ETEXI
+
+/* Additional network restriction options */
+
+DEF("max-dns-conns", HAS_ARG, QEMU_OPTION_max_dns_conns, \
+ "-max-dns-conns limit \n"
+ " Limits the maximum DNS connections\n")
+STEXI
+@item -max-dns-conns @var{limit}
+Limits the maximum DNS connections to @var{limit}.
+ETEXI
+
+DEF("allow-udp", HAS_ARG, QEMU_OPTION_allow_udp, \
+ "-allow-udp host:port \n"
+ " Allows udp connections to go through to host:port\n")
+STEXI
+@item -allow-udp @var{host}:@var{port}
+Allows udp connections to go through to @var{host}:@var{port}.
+ETEXI
+
+DEF("dns-log", HAS_ARG, QEMU_OPTION_dns_log, \
+ "-dns-log file Creates a log of DNS lookups\n")
+STEXI
+@item -dns-log @var{file}
+Creates a log of DNS lookups as @var{file}.
+ETEXI
+
+
+DEF("net-forward", HAS_ARG, QEMU_OPTION_net_forward, \
+"-net-forward dst_net:dst_mask:dst_port:redirect_ip:redirect_port:\n"
+" Forwards guest network traffic sent to dst_net(dst_mask):dst_port\n"
+" to redirect_ip:redirect_port\n")
+
+STEXI
+@item -net-forward @var{settings}
+Forwards network traffic using the settings @code{settings}.
+ETEXI
+
+
+DEF("net-forward-tcp2sink", HAS_ARG, QEMU_OPTION_net_forward_tcp2sink, \
+"-net-forward-tcp2sink sink_ip:sink_port\n"
+" Forwards all dropped and non-forwarded guest network traffic\n"
+" to specified ip:port. \n")
+
+STEXI
+@item -net-forward-tcp2sink @var{settings}
+Forwards all dropped and non-forwarded network traffic to sink ip:port.
+ETEXI
+
+
+
+/* End User mode network stack restrictions */
+
+
DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
"-icount [N|auto]\n" \
" enable virtual instruction counter with 2^N clock ticks per\n" \
@@ -1631,10 +1720,6 @@ DEF("charmap", HAS_ARG, QEMU_OPTION_charmap, \
"-charmap <file>"
" use specific key character map\n")
-DEF("android-gui", HAS_ARG, QEMU_OPTION_android_gui, \
- "-android-gui width=<width>,height=<height>,bpp=<bits per pixel>"
- " width, height, and bits per pixel for the graphic console\n")
-
DEF("android-hw", HAS_ARG, QEMU_OPTION_android_hw, \
"-android-hw <file> read hardware initialization from ini file\n")
diff --git a/slirp-android/libslirp.h b/slirp-android/libslirp.h
index 6086384..120e3d3 100644
--- a/slirp-android/libslirp.h
+++ b/slirp-android/libslirp.h
@@ -2,7 +2,9 @@
#define _LIBSLIRP_H
#include <stdint.h>
+#include <stdio.h>
#include "sockets.h"
+#include "slirp.h"
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# define socket_close winsock2_socket_close3
@@ -16,6 +18,8 @@
extern "C" {
#endif
+struct mbuf;
+
int inet_strtoip(const char* str, uint32_t *ip);
char* inet_iptostr(uint32_t ip);
@@ -32,6 +36,59 @@ void slirp_input(const uint8_t *pkt, int pkt_len);
int slirp_can_output(void);
void slirp_output(const uint8_t *pkt, int pkt_len);
+/* ---------------------------------------------------*/
+/* User mode network stack restrictions */
+void slirp_drop_udp();
+void slirp_drop_tcp();
+void slirp_add_allow(unsigned long dst_addr, int dst_lport,
+ int dst_hport, u_int8_t proto);
+void slirp_drop_log_fd(FILE* fd);
+int slirp_should_drop(unsigned long dst_addr,
+ int dst_port,
+ u_int8_t proto);
+int slirp_drop_log(const char* format, ...);
+
+/* for network forwards */
+void slirp_add_net_forward(unsigned long dest_ip, unsigned long dest_mask,
+ int dest_lport, int dest_hport,
+ unsigned long redirect_ip, int redirect_port);
+
+int slirp_should_net_forward(unsigned long remote_ip, int remote_port,
+ unsigned long *redirect_ip, int *redirect_port);
+/* ---------------------------------------------------*/
+
+/**
+ * Additional network stack modifications, aiming to detect and log
+ * any network activity initiated by any binary outisde the context of
+ * the running browser.
+ */
+
+void slirp_dns_log_fd(FILE* fd);
+/** Logs the DNS name in DNS query issued by the VM. */
+int slirp_log_dns(struct mbuf* m, int dropped);
+/** IP packet dump of DNS queris and responses. */
+int slirp_dump_dns(struct mbuf* m);
+/** Sets an upper limit for the number of allowed DNS requests from
+ * the VM.
+ */
+void slirp_set_max_dns_conns(int max_dns_conns);
+/* Returns the max number of allowed DNS requests.*/
+int slirp_get_max_dns_conns();
+
+/**
+ * Modifications for implementing "-net-forward-tcp2sink' option.
+ */
+
+void slirp_forward_dropped_tcp2sink(unsigned long sink_ip, int sink_port);
+int slirp_should_forward_dropped_tcp2sink();
+unsigned long slirp_get_tcp_sink_ip();
+int slirp_get_tcp_sink_port();
+
+
+
+
+/* ---------------------------------------------------*/
+
void slirp_redir_loop(void (*func)(void *opaque, int is_udp,
const SockAddress *laddr,
const SockAddress *faddr),
diff --git a/slirp-android/slirp.c b/slirp-android/slirp.c
index dc94a99..015918f 100644
--- a/slirp-android/slirp.c
+++ b/slirp-android/slirp.c
@@ -32,6 +32,12 @@
#include "android/android.h"
#include "sockets.h"
+#include "qemu-queue.h"
+
+/* proto types */
+static void slirp_net_forward_init(void);
+
+
#define D(...) VERBOSE_PRINT(slirp,__VA_ARGS__)
#define DN(...) do { if (VERBOSE_CHECK(slirp)) dprintn(__VA_ARGS__); } while (0)
@@ -81,7 +87,7 @@ int slirp_add_dns_server(const SockAddress* new_dns_addr)
return -1;
dns_ip = sock_address_get_ip(new_dns_addr);
- if (dns_ip < 0)
+ if (dns_ip == -1)
return -1;
dns_addr[dns_addr_count++] = dns_ip;
@@ -259,6 +265,8 @@ void slirp_init(int restricted, const char *special_ip)
alias_addr_ip = special_addr_ip | CTL_ALIAS;
getouraddr();
register_savevm("slirp", 0, 1, slirp_state_save, slirp_state_load, NULL);
+
+ slirp_net_forward_init();
}
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
@@ -819,6 +827,298 @@ void if_encap(const uint8_t *ip_data, int ip_data_len)
}
}
+
+/*---------------------------------------------------*/
+/* User mode network stack restrictions */
+struct fw_allow_entry {
+ struct fw_allow_entry* next;
+ unsigned long dst_addr; /* host byte order */
+ /* Allowed port range. dst_lport should be the same as dst_hport for a
+ * single port. */
+ unsigned short dst_lport; /* host byte order */
+ unsigned short dst_hport; /* host byte order */
+};
+
+static int drop_udp = 0;
+static int drop_tcp = 0;
+static struct fw_allow_entry* allow_tcp_entries = NULL;
+static struct fw_allow_entry* allow_udp_entries = NULL;
+static FILE* drop_log_fd = NULL;
+static FILE* dns_log_fd = NULL;
+static int max_dns_conns = -1; /* unlimited max DNS connections by default */
+static int slirp_net_forward_inited = 0;
+
+void slirp_drop_udp() {
+ drop_udp = 1;
+}
+
+void slirp_drop_tcp() {
+ drop_tcp = 1;
+}
+
+/* TCP traffic forwarding to a sink - If enabled, all TCP traffic to any
+ * ip/port that is not explicitly forwared using '-net-forward', and which would
+ * otherwise be dropped if '-drop-tcp' has been specified, is redirected to the
+ * specified ip:port
+ */
+int forward_dropped_tcp2sink = 0;
+static unsigned long tcp_sink_ip;
+int tcp_sink_port;
+
+void slirp_forward_dropped_tcp2sink(unsigned long sink_ip, int sink_port) {
+ tcp_sink_ip = sink_ip;
+ tcp_sink_port = sink_port;
+ forward_dropped_tcp2sink = 1;
+}
+
+int slirp_should_forward_dropped_tcp2sink() {
+ return forward_dropped_tcp2sink;
+}
+
+unsigned long slirp_get_tcp_sink_ip() {
+ return tcp_sink_ip;
+}
+int slirp_get_tcp_sink_port() {
+ return tcp_sink_port;
+}
+
+/* Fill in the firewall rules. dst_lport and dst_hport are in host byte order */
+void slirp_add_allow(unsigned long dst_addr,
+ int dst_lport, int dst_hport,
+ u_int8_t proto) {
+
+ struct fw_allow_entry** ate;
+ switch (proto) {
+ case IPPROTO_TCP:
+ ate = &allow_tcp_entries;
+ break;
+ case IPPROTO_UDP:
+ ate = &allow_udp_entries;
+ break;
+ default:
+ return; // unknown protocol for the FW
+ }
+
+ while(*ate != NULL)
+ ate = &(*ate)->next;
+
+ *ate = malloc(sizeof(**ate));
+ if (*ate == NULL) {
+ DEBUG_MISC((dfd,
+ "Unable to create new firewall record, malloc failed\n"));
+ exit(-1);
+ }
+
+ (*ate)->next = NULL;
+ (*ate)->dst_addr = dst_addr;
+ (*ate)->dst_lport = dst_lport;
+ (*ate)->dst_hport = dst_hport;
+}
+
+void slirp_drop_log_fd(FILE* fd) {
+ drop_log_fd = fd;
+}
+
+void slirp_dns_log_fd(FILE* fd) {
+ dns_log_fd = fd;
+}
+
+/* Address and ports are in host byte order */
+int slirp_should_drop(unsigned long dst_addr,
+ int dst_port,
+ u_int8_t proto) {
+
+ struct fw_allow_entry* ate;
+
+ switch (proto) {
+ case IPPROTO_TCP:
+ if (drop_tcp != 0)
+ ate = allow_tcp_entries;
+ else
+ return 0;
+ break;
+ case IPPROTO_UDP:
+ if (drop_udp != 0)
+ ate = allow_udp_entries;
+ else
+ return 0;
+ break;
+ default:
+ return 1; // unknown protocol for the FW
+ }
+
+ while(ate) {
+ if ((ate->dst_lport <= dst_port) && (dst_port <= ate->dst_hport)) {
+ // allow any destination if 0
+ if (ate->dst_addr == 0 || ate->dst_addr == dst_addr)
+ return 0;
+ }
+ ate = ate->next;
+ }
+
+ return 1;
+}
+
+/*
+ * log DNS requests in a separate log
+ */
+int
+slirp_log_dns(struct mbuf* m, int dropped) {
+ char dns_query[256]; // max allowable dns name size
+ int c = 0;
+ int i= 0;
+ int index = 0;
+ int offset = 40 + 1; // udp/ip headers length + 1;
+ int trim_bytes = 4;
+
+ if (!dns_log_fd)
+ return -1;
+
+ /* We assume one DNS name per query: 300 = 255 (max dns name length)
+ * + 40 (udp/ip hdr) + 1 byte DNS peamble + 4 bytes DNS suffix
+ */
+ if (m->m_len < offset || m->m_len > 300) {
+ DEBUG_MISC((dfd,"Malformed DNS qeury, length %d \n", (int)m->m_len));
+ return -1;
+ }
+ for (i = offset; i < m->m_len - trim_bytes && index < sizeof(dns_query); i++, index++) {
+ c = m->m_data[i];
+ if (c < ' ' || c > '~')
+ c = '.';
+
+ dns_query[index] = (char)c;
+ }
+ dns_query[index] = '\0';
+ if (!dropped) {
+ fprintf(dns_log_fd, "Sent DNS query for, %s\n" , dns_query);
+ } else {
+ fprintf(dns_log_fd, "Dropped DNS query for, %s\n" , dns_query);
+ }
+ fflush(dns_log_fd);
+ return 1;
+}
+
+/*
+ * log DNS requests in a separate log
+ */
+int
+slirp_dump_dns(struct mbuf* m) {
+
+ if (!dns_log_fd)
+ return 0;
+ // first we write the length of the record then the record (IP packet)
+ if (!fwrite(&(m->m_len), sizeof(int), 1, dns_log_fd) ||
+ !fwrite(m->m_data, m->m_len, 1, dns_log_fd)) {
+ return 0;
+ }
+
+ fflush(dns_log_fd);
+ return 1;
+}
+
+/* Log dropped/accepted packet info */
+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;
+}
+
+
+/* Set max DNS requests allowed to be issued from the VM */
+void slirp_set_max_dns_conns(int num_conns) {
+ max_dns_conns = num_conns;
+}
+
+int slirp_get_max_dns_conns() {
+ return max_dns_conns;
+}
+
+/* generic guest network redirection functionality for ipv4 */
+struct net_forward_entry {
+ QTAILQ_ENTRY(net_forward_entry) next;
+ /* ip addresses are also in host byte order */
+ unsigned long dest_ip; /* the destination address they try to contact */
+ unsigned long dest_mask; /* the mask to apply to the address for matching */
+ /* Range of ports they were trying to contact. In case of a single port,
+ * dest_lport should be the same as dest_hport */
+ int dest_lport; /* Host byte order */
+ int dest_hport; /* Host byte order */
+
+ unsigned long redirect_ip;
+ int redirect_port; /* Host byte order */
+};
+
+static QTAILQ_HEAD(net_forwardq, net_forward_entry) net_forwards;
+
+static void slirp_net_forward_init(void)
+{
+ if (!slirp_net_forward_inited) {
+ QTAILQ_INIT(&net_forwards);
+ slirp_net_forward_inited = 1;
+ }
+}
+
+/* all addresses and ports ae in host byte order */
+void slirp_add_net_forward(unsigned long dest_ip, unsigned long dest_mask,
+ int dest_lport, int dest_hport,
+ unsigned long redirect_ip, int redirect_port)
+{
+ slirp_net_forward_init();
+
+ struct net_forward_entry *entry = malloc(sizeof(*entry));
+ if (entry == NULL) {
+ DEBUG_MISC((dfd, "Unable to create new forwarding entry, malloc failed\n"));
+ exit(-1);
+ }
+
+ entry->dest_ip = dest_ip;
+ entry->dest_mask = dest_mask;
+ entry->dest_lport = dest_lport;
+ entry->dest_hport = dest_hport;
+ entry->redirect_ip = redirect_ip;
+ entry->redirect_port = redirect_port;
+
+ QTAILQ_INSERT_TAIL(&net_forwards, entry, next);
+}
+
+/* remote_port and redir_port arguments
+ * are in network byte order (tcp_subr.c) */
+int slirp_should_net_forward(unsigned long remote_ip, int remote_port,
+ unsigned long *redirect_ip, int *redirect_port)
+{
+ struct net_forward_entry *entry;
+
+ for (entry = net_forwards.tqh_first;
+ entry != NULL; entry = entry->next.tqe_next) {
+
+ if ((entry->dest_lport <= remote_port)
+ && (remote_port <= entry->dest_hport)) {
+ if ((entry->dest_ip & entry->dest_mask)
+ == (remote_ip & entry->dest_mask)) {
+ *redirect_ip = entry->redirect_ip;
+ *redirect_port = entry->redirect_port;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*---------------------------------------------------*/
+
+
+
+
static void _slirp_redir_loop(void (*func)(void *opaque, int is_udp,
const SockAddress *laddr,
const SockAddress *faddr),
diff --git a/slirp-android/socket.c b/slirp-android/socket.c
index 44640a8..285a8ef 100644
--- a/slirp-android/socket.c
+++ b/slirp-android/socket.c
@@ -570,6 +570,26 @@ sosendto(struct socket *so, struct mbuf *m)
addr_port = so->so_faddr_port;
+ /*
+ * test for generic forwarding; this function replaces the arguments
+ * only on success
+ */
+ unsigned long faddr = addr_ip;
+ int fport = addr_port;
+
+ if (slirp_should_net_forward(faddr, fport, &faddr, &fport)) {
+ slirp_drop_log(
+ "Redirected UDP: src: 0x%08lx:0x%04x org dst: 0x%08lx:0x%04x "
+ "new dst: 0x%08lx:0x%04x\n",
+ so->so_laddr_ip, so->so_laddr_port,
+ addr_ip, addr_port,
+ faddr, fport
+ );
+ }
+ addr_ip = faddr;
+ addr_port = fport;
+
+
sock_address_init_inet(&addr, addr_ip, addr_port);
DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%08x\n", addr_port, addr_ip));
@@ -779,4 +799,3 @@ sofwdrain(struct socket *so)
else
sofcantsendmore(so);
}
-
diff --git a/slirp-android/tcp_subr.c b/slirp-android/tcp_subr.c
index b8b680c..0550d4b 100644
--- a/slirp-android/tcp_subr.c
+++ b/slirp-android/tcp_subr.c
@@ -377,6 +377,29 @@ tcp_proxy_event( struct socket* so,
tcp_input(NULL, sizeof(struct ip), so);
}
+
+/* Tests if an IP address corresponds to a special Qemu service (eg, the DNS
+ * server or the gateway - see ctl.h) and if so, rewrites it with the real
+ * address of the service.
+ */
+int is_qemu_special_address(unsigned long dst_addr, unsigned long *redir_addr)
+{
+ if ((dst_addr & htonl(0xffffff00)) == special_addr_ip) {
+ /* It's an alias */
+
+ int last_byte = dst_addr & 0xff;
+
+ if (CTL_IS_DNS(last_byte))
+ *redir_addr = dns_addr[last_byte - CTL_DNS];
+ else
+ *redir_addr = loopback_addr_ip;
+
+ return 1;
+ }
+ return 0;
+}
+
+
/*
* Connect to a host on the Internet
* Called by tcp_input
@@ -390,41 +413,56 @@ tcp_proxy_event( struct socket* so,
int tcp_fconnect(struct socket *so)
{
int ret=0;
- int try_proxy = 1;
SockAddress sockaddr;
- uint32_t sock_ip;
- uint16_t sock_port;
+ unsigned long sock_ip;
+ int sock_port;
DEBUG_CALL("tcp_fconnect");
DEBUG_ARG("so = %lx", (long )so);
- sock_ip = so->so_faddr_ip;
- sock_port = so->so_faddr_port;
-
- if ((sock_ip & 0xffffff00) == special_addr_ip) {
- /* It's an alias */
- int last_byte = sock_ip & 0xff;
-
- if (CTL_IS_DNS(last_byte))
- sock_ip = dns_addr[last_byte - CTL_DNS];
- else
- sock_ip = loopback_addr_ip;
- try_proxy = 0;
- }
-
- sock_address_init_inet( &sockaddr, sock_ip, sock_port );
-
- DEBUG_MISC((dfd, " connect()ing, addr=%s, proxy=%d\n",
- sock_address_to_string(&sockaddr), try_proxy));
-
- if (try_proxy) {
- if (!proxy_manager_add(&sockaddr, SOCKET_STREAM, (ProxyEventFunc) tcp_proxy_event, so)) {
- soisfconnecting(so);
- so->s = -1;
- so->so_state |= SS_PROXIFIED;
- return 0;
- }
+ /* when true, a connection that otherwise would be dropped will instead be
+ * redirected to the sink ('-net-forward-tcp2sink') */
+ int forward_dropped_to_sink = 0;
+
+
+ /*-------------------------------------------------------------*/
+ /* User mode network stack restrictions */
+ if (slirp_should_drop(so->so_faddr_ip, so->so_faddr_port, IPPROTO_TCP)) {
+
+ /* If forwarding to sink is enabled, don't actually drop it */
+ if (slirp_should_forward_dropped_tcp2sink()) {
+ slirp_drop_log(
+ "About to be dropped TCP forwarded to sink: "
+ "src: 0x%08lx:0x%04x dst: 0x%08lx:0x%04x\n",
+ so->so_laddr_ip,
+ so->so_laddr_port,
+ so->so_faddr_ip,
+ so->so_faddr_port
+ );
+ forward_dropped_to_sink = 1;
+ }
+ else {
+ slirp_drop_log(
+ "Dropped TCP: src: 0x%08lx:0x%04x dst: 0x%08lx:0x%04x\n",
+ so->so_laddr_ip,
+ so->so_laddr_port,
+ so->so_faddr_ip,
+ so->so_faddr_port
+ );
+ //errno = ENETUNREACH;
+ errno = ECONNREFUSED;
+ return -1;
+ }
+ } else {
+ slirp_drop_log(
+ "Allowed TCP: src: 0x%08lx:0x%04x dst: 0x%08lx:0x%04x\n",
+ so->so_laddr_ip,
+ so->so_laddr_port,
+ so->so_faddr_ip,
+ so->so_faddr_port
+ );
}
+ /*-------------------------------------------------------------*/
if ((ret=so->s=socket_create_inet(SOCKET_STREAM)) >= 0)
{
@@ -434,6 +472,79 @@ int tcp_fconnect(struct socket *so)
socket_set_xreuseaddr(s);
socket_set_oobinline(s);
+
+ if (forward_dropped_to_sink) {
+
+ /* This connection would normally be dropped, but since forwarding of
+ * dropped connections is enabled, redirect it to the sink */
+ sock_ip = slirp_get_tcp_sink_ip();
+ sock_port= slirp_get_tcp_sink_port();
+ slirp_drop_log(
+ "Redirected would-be dropped TCP to sink: "
+ "src: 0x%08lx:0x%04x org dst: 0x%08lx:0x%04x "
+ "new dst: 0x%08lx:0x%04x\n",
+ so->so_laddr_ip, so->so_laddr_port,
+ so->so_faddr_ip, so->so_faddr_port,
+ sock_ip, sock_port
+ );
+ }
+ else { /* An allowed connection */
+
+ unsigned long faddr;
+ int fport;
+
+ /* Determine if the connection should be redirected
+ * due to a -net-forward rule */
+ /* faddr and fport are modified only on success */
+ if (slirp_should_net_forward(so->so_faddr_ip, so->so_faddr_port,
+ &faddr, &fport)) {
+ slirp_drop_log(
+ "Redirected TCP: src: 0x%08lx:0x%04x org dst: 0x%08lx:0x%04x "
+ "new dst: 0x%08lx:0x%04x\n",
+ so->so_laddr_ip, so->so_laddr_port,
+ so->so_faddr_ip, so->so_faddr_port,
+ faddr, fport
+ );
+ sock_ip = faddr; /* forced dst addr */
+ sock_port= fport; /* forced dst port */
+ }
+ /* Determine if this is a connection to a special qemu service,
+ * and change the destination address accordingly.
+ * 'faddr' is modified only onsuccess */
+ else if (is_qemu_special_address(so->so_faddr_ip, &faddr)) {
+
+ /* We keep the original destination port. If a special service
+ * listens on a different port than the standard, then appropriate
+ * forwarding should be set up using -net-forward, e.g., as it is
+ * the case with Mawler's DNS traffic, which is redirected to the
+ * special DNS port:
+ * -net-forward 0.0.0.0:0.0.0.0:53:127.0.0.1:21737 */
+
+ sock_ip = faddr; /* real DNS/gateway addr */
+ sock_port= so->so_faddr_port;/* original dst port */
+
+ }
+ /* A normal connection - keep the original destination addr/port */
+ else {
+
+ if (!proxy_manager_add(&sockaddr, SOCKET_STREAM,
+ (ProxyEventFunc) tcp_proxy_event, so)) {
+ soisfconnecting(so);
+ so->s = -1;
+ so->so_state |= SS_PROXIFIED;
+ return 0;
+ }
+
+ sock_ip = so->so_faddr_ip; /* original dst addr */
+ sock_port= so->so_faddr_port; /* original dst port */
+ }
+ }
+
+ DEBUG_MISC((dfd, " connect()ing, addr=%s, proxy=%d\n",
+ sock_address_to_string(&sockaddr), try_proxy));
+
+ sock_address_init_inet( &sockaddr, sock_ip, sock_port );
+
/* We don't care what port we get */
socket_connect(s, &sockaddr);
diff --git a/slirp-android/udp.c b/slirp-android/udp.c
index 9091505..a9c9a82 100644
--- a/slirp-android/udp.c
+++ b/slirp-android/udp.c
@@ -47,6 +47,10 @@
struct udpstat udpstat;
#endif
+/* Keeps track of the number of DNS requests. Used to implement the firewall
+ * option that restricts the number of DNS requests (-max_dns_conns). */
+u_int dns_num_conns;
+
struct socket udb;
static u_int8_t udp_tos(struct socket *so);
@@ -68,6 +72,7 @@ void
udp_init(void)
{
udb.so_next = udb.so_prev = &udb;
+ dns_num_conns = 0;
}
/* m->m_data points at ip packet header
* m->m_len length ip packet
@@ -121,6 +126,33 @@ udp_input(register struct mbuf *m, int iphlen)
ip->ip_len = len;
}
+ /* ------------------------------------------------------*/
+ /* User mode network stack restrictions */
+ /* slirp_should_drop requires host byte ordering in arguments */
+ if (slirp_should_drop(ntohl(ip->ip_dst.addr), ntohs(uh->uh_dport.port),
+ IPPROTO_UDP)) {
+ slirp_drop_log(
+ "Dropped UDP: src: 0x%08lx:0x%04x dst: 0x%08lx:0x%04x\n",
+ ip->ip_src.addr,
+ uh->uh_sport.port,
+ ip->ip_dst.addr,
+ uh->uh_dport.port
+ );
+ goto bad; /* drop the packet */
+ }
+ else {
+ slirp_drop_log(
+ "Allowed UDP: src: 0x%08lx:0x%04x dst: 0x%08lx:0x%04x\n",
+ ip->ip_src.addr,
+ uh->uh_sport.port,
+ ip->ip_dst.addr,
+ uh->uh_dport.port
+ );
+ }
+ /* ------------------------------------------------------*/
+
+
+
/*
* Save a copy of the IP header in case we want restore it
* for sending an ICMP error message in response.
@@ -164,6 +196,18 @@ udp_input(register struct mbuf *m, int iphlen)
goto bad;
}
+ // DNS logging and FW rules
+ if (ntohs(uh->uh_dport.port) == 53) {
+ if (!slirp_dump_dns(m)) {
+ DEBUG_MISC((dfd,"Error logging DNS packet"));
+ }
+ dns_num_conns++;
+ if (slirp_get_max_dns_conns() != -1 &&
+ dns_num_conns > slirp_get_max_dns_conns())
+ goto bad;
+ }
+
+
/*
* Locate pcb for datagram.
*/
@@ -309,6 +353,13 @@ int udp_output2_(struct socket *so, struct mbuf *m,
STAT(udpstat.udps_opackets++);
+ // DNS logging
+ if (so != NULL && so->so_faddr_port == htons(53)) {
+ if (!slirp_dump_dns(m)) {
+ DEBUG_MISC((dfd,"Error logging DNS packet"));
+ }
+ }
+
error = ip_output(so, m);
return (error);
diff --git a/slirp-android/udp.h b/slirp-android/udp.h
index 4350ec3..2224181 100644
--- a/slirp-android/udp.h
+++ b/slirp-android/udp.h
@@ -69,7 +69,6 @@ struct udpiphdr {
#define ui_ulen ui_u.uh_ulen
#define ui_sum ui_u.uh_sum
-#ifdef LOG_ENABLED
struct udpstat {
/* input statistics: */
u_long udps_ipackets; /* total input packets */
@@ -83,7 +82,6 @@ struct udpstat {
/* output statistics: */
u_long udps_opackets; /* total output packets */
};
-#endif
/*
* Names for UDP sysctl objects
@@ -91,9 +89,7 @@ struct udpstat {
#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */
#define UDPCTL_MAXID 2
-#ifdef LOG_ENABLED
extern struct udpstat udpstat;
-#endif
extern struct socket udb;
struct mbuf;
diff --git a/vl-android.c b/vl-android.c
index caef03d..1afc8d2 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -338,9 +338,6 @@ extern char* op_http_proxy;
// Path to the file containing specific key character map.
char* op_charmap_file = NULL;
-/* Framebuffer dimensions, passed with -android-gui option. */
-char* android_op_gui = NULL;
-
/* Path to hardware initialization file passed with -android-hw option. */
char* android_op_hwini = NULL;
@@ -509,42 +506,6 @@ static void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
#endif
}
-/* Parses -android-gui command line option, extracting width, height and bits
- * per pixel parameters for the GUI console used in this session of the
- * emulator. -android-gui option contains exactly three comma-separated positive
- * integer numbers in strict order: width goes first, width goes next, and bits
- * per pixel goes third. This routine verifies that format and return 0 if all
- * three numbers were extracted, or -1 if string format was incorrect for that
- * option. Note that this routine does not verify that extracted values are
- * correct!
- */
-static int
-parse_androig_gui_option(const char* op, int* width, int* height, int* bpp)
-{
- char val[128];
-
- if (get_param_value(val, 128, "width", op)) {
- *width = strtol(val, NULL, 0);
- } else {
- fprintf(stderr, "option -android-gui is missing width parameter\n");
- return -1;
- }
- if (get_param_value(val, 128, "height", op)) {
- *height = strtol(val, NULL, 0);
- } else {
- fprintf(stderr, "option -android-gui is missing height parameter\n");
- return -1;
- }
- if (get_param_value(val, 128, "bpp", op)) {
- *bpp = strtol(val, NULL, 0);
- } else {
- fprintf(stderr, "option -android-gui is missing bpp parameter\n");
- return -1;
- }
-
- return 0;
-}
-
/***********************************************************/
void hw_error(const char *fmt, ...)
{
@@ -3659,6 +3620,164 @@ append_param(char* param_str, const char* arg, int size)
}
}
+/* Parses an integer
+ * Pararm:
+ * str String containing a number to be parsed.
+ * result Passes the parsed integer in this argument
+ * returns 0 if ok, -1 if failed
+ */
+int
+parse_int(const char *str, int *result)
+{
+ char* r;
+ *result = strtol(str, &r, 0);
+ if (r == NULL || *r != '\0')
+ return -1;
+
+ return 0;
+}
+
+
+/* parses a null-terminated string specifying a network port (e.g., "80") or
+ * port range (e.g., "[6666-7000]"). In case of a single port, lport and hport
+ * are the same. Returns 0 on success, -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);
+
+ if ((*arg == '[') && ((p = strrchr(arg, ']')) != NULL)) {
+ p = arg + 1; /* skip '[' */
+ low = atoi(strtok(p, "-"));
+ high = atoi(strtok(NULL, "-"));
+ if ((low > 0) && (high > 0) && (low < high) && (high < 65535)) {
+ *lport = low;
+ *hport = high;
+ }
+ }
+ else {
+ low = atoi(arg);
+ if ((0 < low) && (low < 65535)) {
+ *lport = low;
+ *hport = low;
+ }
+ }
+ free(arg);
+ if (low != 0)
+ return 0;
+ return -1;
+}
+
+/*
+ * Implements the generic port forwarding option
+ */
+void
+net_slirp_forward(const char *optarg)
+{
+ /*
+ * we expect the following format:
+ * dst_net:dst_mask:dst_port:redirect_ip:redirect_port OR
+ * dst_net:dst_mask:[dp_range_start-dp_range_end]:redirect_ip:redirect_port
+ */
+ char *argument = strdup(optarg), *p = argument;
+ char *dst_net, *dst_mask, *dst_port;
+ char *redirect_ip, *redirect_port;
+ uint32_t dnet, dmask, rip;
+ unsigned short dlport, dhport, rport;
+
+
+ dst_net = strtok(p, ":");
+ dst_mask = strtok(NULL, ":");
+ dst_port = strtok(NULL, ":");
+ redirect_ip = strtok(NULL, ":");
+ redirect_port = strtok(NULL, ":");
+
+ if (dst_net == NULL || dst_mask == NULL || dst_port == NULL ||
+ redirect_ip == NULL || redirect_port == NULL) {
+ fprintf(stderr,
+ "Invalid argument for -net-forward, we expect "
+ "dst_net:dst_mask:dst_port:redirect_ip:redirect_port or "
+ "dst_net:dst_mask:[dp_range_start-dp_range_end]"
+ ":redirect_ip:redirect_port: %s\n",
+ optarg);
+ exit(1);
+ }
+
+ /* inet_strtoip converts dotted address to host byte order */
+ if (inet_strtoip(dst_net, &dnet) == -1) {
+ fprintf(stderr, "Invalid destination IP net: %s\n", dst_net);
+ exit(1);
+ }
+ if (inet_strtoip(dst_mask, &dmask) == -1) {
+ fprintf(stderr, "Invalid destination IP mask: %s\n", dst_mask);
+ exit(1);
+ }
+ if (inet_strtoip(redirect_ip, &rip) == -1) {
+ fprintf(stderr, "Invalid redirect IP address: %s\n", redirect_ip);
+ exit(1);
+ }
+
+ if (parse_port_range(dst_port, &dlport, &dhport) == -1) {
+ fprintf(stderr, "Invalid destination port or port range\n");
+ exit(1);
+ }
+
+ rport = atoi(redirect_port);
+ if (!rport) {
+ fprintf(stderr, "Invalid redirect port: %s\n", redirect_port);
+ exit(1);
+ }
+
+ dnet &= dmask;
+
+ slirp_add_net_forward(dnet, dmask, dlport, dhport,
+ rip, rport);
+
+ free(argument);
+}
+
+
+/* Parses an -allow-tcp or -allow-udp argument and inserts a corresponding
+ * entry in the allows list */
+void
+slirp_allow(const char *optarg, u_int8_t proto)
+{
+ /*
+ * we expect the following format:
+ * dst_ip:dst_port OR dst_ip:[dst_lport-dst_hport]
+ */
+ char *argument = strdup(optarg), *p = argument;
+ char *dst_ip_str, *dst_port_str;
+ uint32_t dst_ip;
+ unsigned short dst_lport, dst_hport;
+
+ dst_ip_str = strtok(p, ":");
+ dst_port_str = strtok(NULL, ":");
+
+ if (dst_ip_str == NULL || dst_port_str == NULL) {
+ fprintf(stderr,
+ "Invalid argument %s for -allow. We expect "
+ "dst_ip:dst_port or dst_ip:[dst_lport-dst_hport]\n",
+ optarg);
+ exit(1);
+ }
+
+ if (inet_strtoip(dst_ip_str, &dst_ip) == -1) {
+ fprintf(stderr, "Invalid destination IP address: %s\n", dst_ip_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(dst_ip, dst_lport, dst_hport, proto);
+
+ free(argument);
+}
+
int main(int argc, char **argv, char **envp)
{
const char *gdbstub_dev = NULL;
@@ -3706,9 +3825,7 @@ int main(int argc, char **argv, char **envp)
#endif
CPUState *env;
int show_vnc_port = 0;
-#ifdef CONFIG_STANDALONE_CORE
IniFile* hw_ini = NULL;
-#endif // CONFIG_STANDALONE_CORE
/* Container for the kernel initialization parameters collected in this
* routine. */
char kernel_cmdline_append[1024];
@@ -4416,6 +4533,89 @@ int main(int argc, char **argv, char **envp)
}
}
break;
+
+ /* -------------------------------------------------------*/
+ /* User mode network stack restrictions */
+ case QEMU_OPTION_drop_udp:
+ slirp_drop_udp();
+ break;
+ case QEMU_OPTION_drop_tcp:
+ slirp_drop_tcp();
+ break;
+ case QEMU_OPTION_allow_tcp:
+ slirp_allow(optarg, IPPROTO_TCP);
+ break;
+ case QEMU_OPTION_allow_udp:
+ slirp_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_drop_log_fd(drop_log_fd);
+ }
+ break;
+
+ case QEMU_OPTION_dns_log:
+ {
+ FILE* dns_log_fd;
+ dns_log_fd = fopen(optarg, "wb");
+
+ if (dns_log_fd == NULL) {
+ fprintf(stderr, "Cannot open dns log: %s\n", optarg);
+ exit(1);
+ }
+
+ slirp_dns_log_fd(dns_log_fd);
+ }
+ break;
+
+
+ case QEMU_OPTION_max_dns_conns:
+ {
+ int max_dns_conns = 0;
+ if (parse_int(optarg, &max_dns_conns)) {
+ fprintf(stderr,
+ "qemu: syntax: -max-dns-conns max_connections\n");
+ exit(1);
+ }
+ if (max_dns_conns <= 0 || max_dns_conns == LONG_MAX) {
+ fprintf(stderr,
+ "Invalid arg for max dns connections: %s\n",
+ optarg);
+ exit(1);
+ }
+ slirp_set_max_dns_conns(max_dns_conns);
+ }
+ break;
+
+ case QEMU_OPTION_net_forward:
+ net_slirp_forward(optarg);
+ break;
+ case QEMU_OPTION_net_forward_tcp2sink:
+ {
+ SockAddress saddr;
+
+ if (parse_host_port(&saddr, optarg)) {
+ fprintf(stderr,
+ "Invalid ip/port %s for "
+ "-forward-dropped-tcp2sink. "
+ "We expect 'sink_ip:sink_port'\n",
+ optarg);
+ exit(1);
+ }
+ slirp_forward_dropped_tcp2sink(saddr.u.inet.address,
+ saddr.u.inet.port);
+ }
+ break;
+ /* -------------------------------------------------------*/
+
case QEMU_OPTION_tb_size:
tb_size = strtol(optarg, NULL, 0);
if (tb_size < 0)
@@ -4508,10 +4708,6 @@ int main(int argc, char **argv, char **envp)
op_charmap_file = (char*)optarg;
break;
- case QEMU_OPTION_android_gui:
- android_op_gui = (char*)optarg;
- break;
-
case QEMU_OPTION_android_hw:
android_op_hwini = (char*)optarg;
break;
@@ -4608,17 +4804,6 @@ int main(int argc, char **argv, char **envp)
}
}
- /* Parse GUI option early, so when we init framebuffer in goldfish we have
- * saved display parameters. */
- if (android_op_gui) {
- if (parse_androig_gui_option(android_op_gui,
- &android_display_width,
- &android_display_height,
- &android_display_bpp)) {
- PANIC("Unable to parse -android-gui parameter: %s", android_op_gui);
- }
- }
-
/* Initialize character map. */
if (android_charmap_setup(op_charmap_file)) {
if (op_charmap_file) {
@@ -4641,20 +4826,33 @@ int main(int argc, char **argv, char **envp)
data_dir = CONFIG_QEMU_SHAREDIR;
}
-#ifdef CONFIG_STANDALONE_CORE
- /* Initialize hardware configuration. */
- if (android_op_hwini) {
- hw_ini = iniFile_newFromFile(android_op_hwini);
- if (hw_ini == NULL) {
+ if (!android_op_hwini) {
+ PANIC("Missing -android-hw <file> option!");
+ }
+ hw_ini = iniFile_newFromFile(android_op_hwini);
+ if (hw_ini == NULL) {
PANIC("Could not find %s file.", android_op_hwini);
- }
- } else {
- hw_ini = iniFile_newFromMemory("", 0);
}
-
androidHwConfig_read(android_hw, hw_ini);
iniFile_free(hw_ini);
-#endif // CONFIG_STANDALONE_CORE
+
+ {
+ int width = android_hw->hw_lcd_width;
+ int height = android_hw->hw_lcd_height;
+ int depth = android_hw->hw_lcd_depth;
+
+ /* A bit of sanity checking */
+ if (width <= 0 || height <= 0 ||
+ (depth != 16 && depth != 32) ||
+ (((width|height) & 3) != 0) )
+ {
+ PANIC("Invalid display configuration (%d,%d,%d)",
+ width, height, depth);
+ }
+ android_display_width = width;
+ android_display_height = height;
+ android_display_bpp = depth;
+ }
#ifdef CONFIG_NAND_LIMITS
/* Init nand stuff. */
@@ -4689,11 +4887,10 @@ int main(int argc, char **argv, char **envp)
}
/* Initialize LCD density */
- if (android_op_lcd_density) {
- char* end;
- long density = strtol(android_op_lcd_density, &end, 0);
- if (end == NULL || *end || density < 0) {
- PANIC("option -lcd-density must be a positive integer");
+ if (android_hw->hw_lcd_density) {
+ long density = android_hw->hw_lcd_density;
+ if (density <= 0) {
+ PANIC("Invalid hw.lcd.density value: %ld", density);
}
hwLcd_setBootProperty(density);
}
@@ -4968,8 +5165,12 @@ int main(int argc, char **argv, char **envp)
}
/* init the memory */
- if (ram_size == 0)
- ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
+ if (ram_size == 0) {
+ ram_size = android_hw->hw_ramSize * 1024LL * 1024;
+ if (ram_size == 0) {
+ ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
+ }
+ }
#ifdef CONFIG_KQEMU
/* FIXME: This is a nasty hack because kqemu can't cope with dynamic
@@ -5199,16 +5400,11 @@ int main(int argc, char **argv, char **envp)
/* just use the first displaystate for the moment */
ds = get_displaystate();
- if (android_op_gui) {
- /* Initialize display from the command line parameters. */
- android_display_reset(ds,
- android_display_width,
- android_display_height,
- android_display_bpp);
- } else {
- /* By default, use 320x480x16 */
- android_display_reset(ds, 320, 480, 16);
- }
+ /* Initialize display from the command line parameters. */
+ android_display_reset(ds,
+ android_display_width,
+ android_display_height,
+ android_display_bpp);
if (display_type == DT_DEFAULT) {
#if defined(CONFIG_SDL) || defined(CONFIG_COCOA)