1
0
mirror of https://github.com/simh/simh.git synced 2026-01-11 23:52:58 +00:00

ETHER: Add Apple vmnet support when running on macOS

Base vmnet support covers bridged network interfaces and locally
accessible TAP network connections. These reflect the vmnet bridged
and host behaviors which are leveraged under the covers, but configured
using the original sim_ether commands.  The resulting bridged case
behaves like the Windows network connections do (with direct access
to and from the local LAN as well as the host system) using the natural
interface name.  NAT behaviors are specifically supported using the
original SLiRP code since the vmnet support depends on simulators
primarily getting IPv4 addressing via DHCP, but essentially no simh
simulators actually had OS network code which used DHCP and all
merely used static network address setup.  The vmnet (shared/NAT)
support can't be configured to operate with the same DHCP and static
IP addresses provided by the original SLiRP implementation and to
avoid the need to specifically change hard coded simulator IPv4
addresses before things could work.

- Detect which network interfaces are WiFi (when possible) and thus
  not useful candidates for bridging.
- Cleanly report when running as root is needed.
- Avoid allowing network connections to interfaces which aren't
  actually connected to a network.
- Add support to explicitly set TAP network host side network
  interface's IPv4 address and netmask.  This optional support is
  provided specifically for the Apple vmnet case, but not for other
  platforms using TAP network connections due to the various ways
  that must be handled with external commands.
- Add host system's IPv4 address, netmask, media type and connection
  state to interface descriptions visible via SHOW ETHERNET.
  Some system environments may have a significant number of potential
  network interfaces, most of which aren't interesting to connect
  simulators to.  Knowing which interfaces are actually in useful
  states helps users select the correct device.

The vmnet aspect of this functionality was originally inspired by
Calvin Buckley's pull request to the open-simh repository.  That
solution wouldn't actually operate well certainly for NAT cases due
to the forced DHCP to non-configurable address blocks and the lack
of any way to support static addresses TCP or  UDP port mapping.
This commit is contained in:
Mark Pizzolato 2025-06-06 14:51:46 -10:00
parent fd60c6b0f7
commit 61fe27cb47
7 changed files with 1491 additions and 638 deletions

View File

@ -28,7 +28,7 @@ On Windows using the WinPcap interface, the simulated computer can "talk" to
the host computer on the same interface. On other platforms with libpcap
(*nix), the simulated computer can not "talk" to the host computer via the
selected interface, since simulator transmitted packets are not received
by the host's network stack. The workaround for this is to use a second NIC
by the host's network stack. One workaround for this is to use a second NIC
in the host and connect them both into the same network; then the host and
the simulator can communicate over the physical LAN.
@ -47,6 +47,12 @@ tested on include: Linux, FreeBSD, OpenBSD, NetBSD and OSX. Each of these
platforms has some way to create a tap pseudo device (and possibly then to
bridge it with a physical network interface).
Relatively recently, macOS (since version 10.15 sometime in 2019) has
functionality integrated into the OS that automatically provides bridging to
address this problem. The capability is provided by the vmnet facility of
the OS. The simh sim_ether layer now leverages this vmnet functionality
(when available), and building of simh on automatically includes it.
The following steps were performed to get a working SIMH vax simulator
sharing a physical NIC and allowing Host<->SIMH vax communications:
@ -129,8 +135,9 @@ NetBSD (NetBSD 5.0.2)
# Run simulator and "attach xq tap:tap0"
OSX (Snow Leopard)
OSX Does NOT have native support for tun/tap interfaces. It also does not have native
support for bridging.
On older versons of the macOS (OS/X) operating systems (prior to 10.15)
OSX Does NOT have native support for tun/tap interfaces. Those versions
also do not have native support for bridging.
Mattias Nissler has created tun/tap functionality available at http://tuntaposx.sourceforge.net/
@ -177,8 +184,9 @@ Linux (Ubuntu 11.10):
sim> attach xq vde:/tmp/switch1 #simulator uses IP address 192.168.6.2
OSX:
The macports package manager (http://www.macports.org) can be used to
install the net/vde2 package.
The homebrew package manager (https://brew.sh/) or macports package manager
(http://www.macports.org) can be used to install the net/vde2 package. vde
is no longer needed given support for the vmnet functionality now available.
-------------------------------------------------------------------------------
Another alternative to direct pcap and tun/tap networking on all environments is
@ -226,8 +234,8 @@ Windows notes:
3. The first time the Npcap/WinPCAP driver is used, it will be dynamically
loaded, and the user must be an Administrator on the machine to do so.
If you need to run as an unprivileged user, you must set the "npf" driver
to autostart.
If you need/want to run as an unprivileged user, you must set the "npf"
driver to autostart.
Current Npcap and WinPcap installers provide an option to configure this
at installation time, so if that choice is made, then there is no need for
administrator privileged to run simulators with network support.
@ -331,13 +339,17 @@ Building on Linux, {Free|Net|Open}BSD, OS/X, Solaris, other *nix:
RedHat/Fedora Based distributions:
# yum install libpcap-devel
OS/X : The libpcap components are installed as part of the Xcode
developer package. Instructions to install Xcode on various
OSX versions are available at:
OS/X : The libpcap and vmnet components are installed as part of
the Xcode developer package. The simplest way to install
the Xcode developer components is merely to type "git" at a
terminal shell prompt and answer yes to the dialog that pops
up to install this feature. Instructions to install Xcode
on various OSX versions are available at:
https://guide.macports.org/chunked/installing.xcode.html
Be sure to install the command line tools which are installed
with the command "xcode-select --install" in more recent
versions of the Apple developer support.
On older macOS versions, be sure to install the command line
tools which are installed with the command
"xcode-select --install" for slightly older recent versions
of the Apple developer support.
HP-UX : ftp://hpux.connect.org.uk/hpux/Networking/Admin/

View File

@ -105,7 +105,7 @@ Simulator binaries for x86 Linus, x86 macOS, and Windows for all recent changes
- More complete host system information displayed in SHOW VERSION output.
- Simulator THROTTLING can only be enabled once per simulator run. This avoids potential errant behaviors when arbitrarily switching throttling settings.
- EXAMINE memory commands will now produce minimal output that summarizes multiple successive locations with the same contents and may be aborted by SIGINT (Control-C).
-
- Ethernet enhancements on all platforms and and much simplified platform support on macOS.
#### All simulators build cleanly under OpenVMS on ia64 systems.

346
makefile
View File

@ -547,7 +547,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin)
OSNAME = OSX
LIBEXT = dylib
ifneq (include,$(findstring include,$(UNSUPPORTED_BUILD)))
INCPATH:=$(shell LANG=C; ${GCC} -x c -v -E /dev/null 2>&1 | grep -A 10 '> search starts here' | grep '^ ' | grep -v 'framework directory' | tr -d '\n')
INCPATH:=$(shell LANG=C; ${GCC} -x c -v -E /dev/null 2>&1 | grep -A 10 '> search starts here' | grep '^ ' | awk '{ print $$1 }' | tr '\n' ' ')
endif
ifeq (incopt,$(shell if ${TEST} -d /opt/local/include; then echo incopt; fi))
INCPATH += /opt/local/include
@ -946,7 +946,7 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin)
VIDEO_TTF_LDFLAGS += -lSDL2_ttf
VIDEO_FEATURES += with TrueType font support
# Retain support for explicitly supplying a preferred fontfile
ifneq (,$(FONTFILE))
ifneq (,$(and $(FONTFILE))
VIDEO_TTF_OPT += -DFONTFILE=${FONTFILE}
endif
else
@ -959,81 +959,25 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin)
endif
endif
ifneq (,$(NETWORK_USEFUL))
ifneq (,$(call find_include,pcap))
ifneq (,$(shell grep 'pcap/pcap.h' $(call find_include,pcap) | grep include))
PCAP_H_PATH = $(dir $(call find_include,pcap))pcap/pcap.h
ifeq (Darwin,$(OSTYPE)) # the macOS vmnet framework is only useful when the OS is 10.15 or later
macOSMajor = $(strip $(shell sw_vers 2>/dev/null | grep 'ProductVersion:' 2>/dev/null | awk '{ print $$2 }' | awk -F . '{ print $$1 }'))
macOSMinor = $(strip $(shell sw_vers 2>/dev/null | grep 'ProductVersion:' 2>/dev/null | awk '{ print $$2 }' | awk -F . '{ print $$2 }'))
ifeq (10,$(macOSMajor))
DONT_USE_VMNET = $(shell if ${TEST} $(macOSMinor) -lt 15; then echo DONT_USE_VMNET; fi)
else
PCAP_H_PATH = $(call find_include,pcap)
DONT_USE_VMNET = $(shell if ${TEST} $(macOSMajor) -lt 10; then echo DONT_USE_VMNET; fi)
endif
ifneq (,$(shell grep pcap_compile $(PCAP_H_PATH) | grep const))
BPF_CONST_STRING = -DBPF_CONST_STRING
endif
NETWORK_CCDEFS += -DHAVE_PCAP_NETWORK -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING)
NETWORK_LAN_FEATURES += PCAP
ifneq (,$(call find_lib,$(PCAPLIB)))
ifneq ($(USE_NETWORK),) # Network support specified on the GNU make command line
NETWORK_CCDEFS += -DUSE_NETWORK
ifeq (,$(findstring Linux,$(OSTYPE))$(findstring Darwin,$(OSTYPE)))
$(info *** Warning ***)
$(info *** Warning *** Directly linking against libpcap is provides no measurable)
$(info *** Warning *** benefits over dynamically linking libpcap.)
$(info *** Warning ***)
$(info *** Warning *** Support for linking this way is currently deprecated and may be removed)
$(info *** Warning *** in the future.)
$(info *** Warning ***)
else
$(info *** Error ***)
$(info *** Error *** Directly linking against libpcap is provides no measurable)
$(info *** Error *** benefits over dynamically linking libpcap.)
$(info *** Error ***)
$(info *** Error *** Support for linking directly has been removed on the $(OSTYPE))
$(info *** Error *** platform.)
$(info *** Error ***)
$(error Retry your build without specifying USE_NETWORK=1)
endif
ifeq (cygwin,$(OSTYPE))
# cygwin has no ldconfig so explicitly specify pcap object library
NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB)
else
NETWORK_LDFLAGS = -l$(PCAPLIB)
endif
$(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap))
NETWORK_FEATURES = - static networking support using $(OSNAME) provided libpcap components
else # default build uses dynamic libpcap
NETWORK_CCDEFS += -DUSE_SHARED
$(info using libpcap: $(call find_include,pcap))
NETWORK_FEATURES = - dynamic networking support using $(OSNAME) provided libpcap components
endif
else
LIBEXTSAVE := ${LIBEXT}
LIBEXT = a
ifneq (,$(call find_lib,$(PCAPLIB)))
NETWORK_CCDEFS += -DUSE_NETWORK
NETWORK_LDFLAGS := -L$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB)
NETWORK_FEATURES = - static networking support using $(OSNAME) provided libpcap components
$(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap))
endif
LIBEXT = $(LIBEXTSAVE)
ifeq (Darwin,$(OSTYPE)$(findstring USE_,$(NETWORK_CCDEFS)))
NETWORK_CCDEFS += -DUSE_SHARED
NETWORK_FEATURES = - dynamic networking support using $(OSNAME) provided libpcap components
$(info using macOS dynamic libpcap: $(call find_include,pcap))
endif
endif
else # pcap desired but pcap.h not found
ifneq (,$(call find_lib,$(PCAPLIB)))
PCAP_LIB_VERSION = $(shell strings $(call find_lib,$(PCAPLIB)) | grep 'libpcap version' | awk '{ print $$3}')
PCAP_LIB_BASE_VERSION = $(firstword $(subst ., ,$(PCAP_LIB_VERSION)))
endif
NEEDED_PKGS += DPKG_PCAP
# On non-Linux platforms, we'll still try to provide deprecated support for libpcap in /usr/local
INCPATHSAVE := ${INCPATH}
ifeq (,$(findstring Linux,$(OSTYPE)))
# Look for package built from tcpdump.org sources with default install target (or cygwin winpcap)
INCPATH += /usr/local/include
PCAP_H_FOUND = $(call find_include,pcap)
endif
ifneq (,$(strip $(PCAP_H_FOUND)))
endif
ifneq (,$(if $(DONT_USE_VMNET),,$(call find_include,vmnet.framework/Headers/vmnet)))
# sim_ether reduces network features to the appropriate minimal set
NETWORK_LAN_FEATURES += VMNET
NETWORK_CCDEFS += -DUSE_SHARED -I slirp -I slirp_glue -I slirp_glue/qemu -DHAVE_VMNET_NETWORK
NETWORK_DEPS += slirp/*.c slirp_glue/*.c
NETWORK_LDFLAGS += -framework vmnet
$(info using vmnet: $(call find_include,vmnet.framework/Headers/vmnet))
else
# Consider other network connections
ifneq (,$(call find_include,pcap))
ifneq (,$(shell grep 'pcap/pcap.h' $(call find_include,pcap) | grep include))
PCAP_H_PATH = $(dir $(call find_include,pcap))pcap/pcap.h
else
@ -1042,107 +986,181 @@ ifeq (${WIN32},) #*nix Environments (&& cygwin)
ifneq (,$(shell grep pcap_compile $(PCAP_H_PATH) | grep const))
BPF_CONST_STRING = -DBPF_CONST_STRING
endif
LIBEXTSAVE := ${LIBEXT}
# first check if binary - shared objects are available/installed in the linker known search paths
NETWORK_CCDEFS += -DHAVE_PCAP_NETWORK -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING)
NETWORK_LAN_FEATURES += PCAP
ifneq (,$(call find_lib,$(PCAPLIB)))
NETWORK_CCDEFS = -DUSE_SHARED -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING)
NETWORK_FEATURES = - dynamic networking support using libpcap components from www.tcpdump.org and locally installed libpcap.${LIBEXT}
$(info using libpcap: $(call find_include,pcap))
ifneq ($(USE_NETWORK),) # Network support specified on the GNU make command line
NETWORK_CCDEFS += -DUSE_NETWORK
ifeq (,$(findstring Linux,$(OSTYPE))$(findstring Darwin,$(OSTYPE)))
$(info *** Warning ***)
$(info *** Warning *** Directly linking against libpcap is provides no measurable)
$(info *** Warning *** benefits over dynamically linking libpcap.)
$(info *** Warning ***)
$(info *** Warning *** Support for linking this way is currently deprecated and may be removed)
$(info *** Warning *** in the future.)
$(info *** Warning ***)
else
$(info *** Error ***)
$(info *** Error *** Directly linking against libpcap is provides no measurable)
$(info *** Error *** benefits over dynamically linking libpcap.)
$(info *** Error ***)
$(info *** Error *** Support for linking directly has been removed on the $(OSTYPE))
$(info *** Error *** platform.)
$(info *** Error ***)
$(error Retry your build without specifying USE_NETWORK=1)
endif
ifeq (cygwin,$(OSTYPE))
# cygwin has no ldconfig so explicitly specify pcap object library
NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB)
else
NETWORK_LDFLAGS = -l$(PCAPLIB)
endif
$(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap))
NETWORK_FEATURES = - static networking support using $(OSNAME) provided libpcap components
else # default build uses dynamic libpcap
NETWORK_CCDEFS += -DUSE_SHARED
$(info using libpcap: $(call find_include,pcap))
NETWORK_FEATURES = - dynamic networking support using $(OSNAME) provided libpcap components
endif
else
LIBPATH += /usr/local/lib
LIBEXTSAVE := ${LIBEXT}
LIBEXT = a
ifneq (,$(call find_lib,$(PCAPLIB)))
$(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap))
ifeq (cygwin,$(OSTYPE))
NETWORK_CCDEFS = -DUSE_NETWORK -DHAVE_PCAP_NETWORK -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING)
NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB)
NETWORK_FEATURES = - static networking support using libpcap components located in the cygwin directories
else
NETWORK_CCDEFS := -DUSE_NETWORK -DHAVE_PCAP_NETWORK -isystem -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) $(call find_lib,$(PCAPLIB))
NETWORK_FEATURES = - networking support using libpcap components from www.tcpdump.org
$(info *** Warning ***)
$(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using)
$(info *** Warning *** libpcap components from www.tcpdump.org.)
$(info *** Warning *** Some users have had problems using the www.tcpdump.org libpcap)
$(info *** Warning *** components for simh networking. For best results, with)
$(info *** Warning *** simh networking, it is recommended that you install the)
$(info *** Warning *** libpcap-dev (or libpcap-devel) package from your $(OSNAME) distribution)
$(info *** Warning ***)
$(info *** Warning *** Building with the components manually installed from www.tcpdump.org)
$(info *** Warning *** is officially deprecated. Attempting to do so is unsupported.)
$(info *** Warning ***)
endif
else
$(error using libpcap: $(call find_include,pcap) missing $(PCAPLIB).${LIBEXT})
endif
NETWORK_LAN_FEATURES += PCAP
endif
LIBEXT = $(LIBEXTSAVE)
else
INCPATH = $(INCPATHSAVE)
ifeq (1,$(PCAP_LIB_BASE_VERSION))
$(info using libpcap $(PCAP_LIB_VERSION) without an available pcap.h)
NETWORK_CCDEFS = -DUSE_SHARED -DHAVE_PCAP_NETWORK -DPCAP_LIB_VERSION=$(PCAP_LIB_VERSION)
NETWORK_FEATURES = - dynamic networking support using libpcap components from www.tcpdump.org and locally installed libpcap.${LIBEXT}
NETWORK_LAN_FEATURES += PCAP
NEEDED_PKGS := $(filter-out DPKG_PCAP,$(NEEDED_PKGS))
else
$(info *** Warning ***)
$(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) $(BUILD_MULTIPLE_VERB) being built WITHOUT)
$(info *** Warning *** libpcap networking support)
$(info *** Warning ***)
$(info *** Warning *** To build simulator(s) with libpcap networking support you)
$(info *** Warning *** should install the libpcap development components for)
$(info *** Warning *** for your $(OSNAME) system.)
ifeq (,$(or $(findstring Linux,$(OSTYPE)),$(findstring OSX,$(OSNAME))))
$(info *** Warning *** You should read 0readme_ethernet.txt and follow the instructions)
$(info *** Warning *** regarding the needed libpcap development components for your)
$(info *** Warning *** $(OSNAME) platform.)
endif
$(info *** Warning ***)
endif
endif
endif
# Consider other network connections
ifneq (,$(call find_lib,vdeplug))
# libvdeplug requires the use of the OS provided libpcap
ifeq (,$(findstring usr/local,$(NETWORK_CCDEFS)))
ifneq (,$(call find_include,libvdeplug))
# Provide support for vde networking
NETWORK_CCDEFS += -DHAVE_VDE_NETWORK
NETWORK_LAN_FEATURES += VDE
ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS)))
NETWORK_CCDEFS += -DUSE_NETWORK
NETWORK_LDFLAGS := -L$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB)
NETWORK_FEATURES = - static networking support using $(OSNAME) provided libpcap components
$(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap))
endif
ifeq (Darwin,$(OSTYPE))
NETWORK_LDFLAGS += -lvdeplug -L$(dir $(call find_lib,vdeplug))
LIBEXT = $(LIBEXTSAVE)
ifeq (Darwin,$(OSTYPE)$(findstring USE_,$(NETWORK_CCDEFS)))
NETWORK_CCDEFS +=
NETWORK_FEATURES = - dynamic networking support using $(OSNAME) provided libpcap components
$(info using macOS dynamic libpcap: $(call find_include,pcap))
endif
endif
else # pcap desired but pcap.h not found
ifneq (,$(call find_lib,$(PCAPLIB)))
PCAP_LIB_VERSION = $(shell strings $(call find_lib,$(PCAPLIB)) | grep 'libpcap version' | awk '{ print $$3}')
PCAP_LIB_BASE_VERSION = $(firstword $(subst ., ,$(PCAP_LIB_VERSION)))
endif
NEEDED_PKGS += DPKG_PCAP
# On non-Linux platforms, we'll still try to provide deprecated support for libpcap in /usr/local
INCPATHSAVE := ${INCPATH}
ifeq (,$(findstring Linux,$(OSTYPE)))
# Look for package built from tcpdump.org sources with default install target (or cygwin winpcap)
INCPATH += /usr/local/include
PCAP_H_FOUND = $(call find_include,pcap)
endif
ifneq (,$(strip $(PCAP_H_FOUND)))
ifneq (,$(shell grep 'pcap/pcap.h' $(call find_include,pcap) | grep include))
PCAP_H_PATH = $(dir $(call find_include,pcap))pcap/pcap.h
else
NETWORK_LDFLAGS += -lvdeplug -Wl,-R,$(dir $(call find_lib,vdeplug)) -L$(dir $(call find_lib,vdeplug))
PCAP_H_PATH = $(call find_include,pcap)
endif
ifneq (,$(shell grep pcap_compile $(PCAP_H_PATH) | grep const))
BPF_CONST_STRING = -DBPF_CONST_STRING
endif
LIBEXTSAVE := ${LIBEXT}
# first check if binary - shared objects are available/installed in the linker known search paths
ifneq (,$(call find_lib,$(PCAPLIB)))
NETWORK_CCDEFS = -DUSE_SHARED -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING)
NETWORK_FEATURES = - dynamic networking support using libpcap components from www.tcpdump.org and locally installed libpcap.${LIBEXT}
$(info using libpcap: $(call find_include,pcap))
else
LIBPATH += /usr/local/lib
LIBEXT = a
ifneq (,$(call find_lib,$(PCAPLIB)))
$(info using libpcap: $(call find_lib,$(PCAPLIB)) $(call find_include,pcap))
ifeq (cygwin,$(OSTYPE))
NETWORK_CCDEFS = -DUSE_NETWORK -DHAVE_PCAP_NETWORK -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING)
NETWORK_LDFLAGS = -L$(dir $(call find_lib,$(PCAPLIB))) -Wl,-R,$(dir $(call find_lib,$(PCAPLIB))) -l$(PCAPLIB)
NETWORK_FEATURES = - static networking support using libpcap components located in the cygwin directories
else
NETWORK_CCDEFS := -DUSE_NETWORK -DHAVE_PCAP_NETWORK -isystem -I$(dir $(call find_include,pcap)) $(BPF_CONST_STRING) $(call find_lib,$(PCAPLIB))
NETWORK_FEATURES = - networking support using libpcap components from www.tcpdump.org
$(info *** Warning ***)
$(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) being built with networking support using)
$(info *** Warning *** libpcap components from www.tcpdump.org.)
$(info *** Warning *** Some users have had problems using the www.tcpdump.org libpcap)
$(info *** Warning *** components for simh networking. For best results, with)
$(info *** Warning *** simh networking, it is recommended that you install the)
$(info *** Warning *** libpcap-dev (or libpcap-devel) package from your $(OSNAME) distribution)
$(info *** Warning ***)
$(info *** Warning *** Building with the components manually installed from www.tcpdump.org)
$(info *** Warning *** is officially deprecated. Attempting to do so is unsupported.)
$(info *** Warning ***)
endif
else
$(error using libpcap: $(call find_include,pcap) missing $(PCAPLIB).${LIBEXT})
endif
NETWORK_LAN_FEATURES += PCAP
endif
LIBEXT = $(LIBEXTSAVE)
else
INCPATH = $(INCPATHSAVE)
ifeq (1,$(PCAP_LIB_BASE_VERSION))
$(info using libpcap $(PCAP_LIB_VERSION) without an available pcap.h)
NETWORK_CCDEFS = -DUSE_SHARED -DHAVE_PCAP_NETWORK -DPCAP_LIB_VERSION=$(PCAP_LIB_VERSION)
NETWORK_FEATURES = - dynamic networking support using libpcap components from www.tcpdump.org and locally installed libpcap.${LIBEXT}
NETWORK_LAN_FEATURES += PCAP
NEEDED_PKGS := $(filter-out DPKG_PCAP,$(NEEDED_PKGS))
else
$(info *** Warning ***)
$(info *** Warning *** $(BUILD_SINGLE)Simulator$(BUILD_MULTIPLE) $(BUILD_MULTIPLE_VERB) being built WITHOUT)
$(info *** Warning *** libpcap networking support)
$(info *** Warning ***)
$(info *** Warning *** To build simulator(s) with libpcap networking support you)
$(info *** Warning *** should install the libpcap development components for)
$(info *** Warning *** for your $(OSNAME) system.)
ifeq (,$(or $(findstring Linux,$(OSTYPE)),$(findstring OSX,$(OSNAME))))
$(info *** Warning *** You should read 0readme_ethernet.txt and follow the instructions)
$(info *** Warning *** regarding the needed libpcap development components for your)
$(info *** Warning *** $(OSNAME) platform.)
endif
$(info *** Warning ***)
endif
endif
endif
ifneq (,$(call find_lib,vdeplug))
# libvdeplug requires the use of the OS provided libpcap
ifeq (,$(findstring usr/local,$(NETWORK_CCDEFS)))
ifneq (,$(call find_include,libvdeplug))
# Provide support for vde networking
NETWORK_CCDEFS += -DHAVE_VDE_NETWORK
NETWORK_LAN_FEATURES += VDE
ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS)))
NETWORK_CCDEFS += -DUSE_SHARED
endif
ifeq (Darwin,$(OSTYPE))
NETWORK_LDFLAGS += -lvdeplug -L$(dir $(call find_lib,vdeplug))
else
NETWORK_LDFLAGS += -lvdeplug -Wl,-R,$(dir $(call find_lib,vdeplug)) -L$(dir $(call find_lib,vdeplug))
endif
$(info using libvdeplug: $(call find_lib,vdeplug) $(call find_include,libvdeplug))
endif
else
ifeq (,$(findstring PKG_PCAP, $(NEEDED_PKGS)))
NEEDED_PKGS += DPKG_PCAP
endif
$(info using libvdeplug: $(call find_lib,vdeplug) $(call find_include,libvdeplug))
endif
else
ifeq (,$(findstring PKG_PCAP, $(NEEDED_PKGS)))
NEEDED_PKGS += DPKG_PCAP
NEEDED_PKGS += DPKG_VDE
endif
ifneq (,$(call find_include,linux/if_tun))
# Provide support for Tap networking on Linux
NETWORK_CCDEFS += -DHAVE_TAP_NETWORK
NETWORK_LAN_FEATURES += TAP
ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS)))
NETWORK_CCDEFS += -DUSE_NETWORK
endif
endif
else
NEEDED_PKGS += DPKG_VDE
endif
ifneq (,$(call find_include,linux/if_tun))
# Provide support for Tap networking on Linux
NETWORK_CCDEFS += -DHAVE_TAP_NETWORK
NETWORK_LAN_FEATURES += TAP
ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS)))
NETWORK_CCDEFS += -DUSE_NETWORK
endif
endif
ifeq (bsdtuntap,$(shell if ${TEST} -e /usr/include/net/if_tun.h -o -e /Library/Extensions/tap.kext -o -e /Applications/Tunnelblick.app/Contents/Resources/tap-notarized.kext; then echo bsdtuntap; fi))
# Provide support for Tap networking on BSD platforms (including OS X)
NETWORK_CCDEFS += -DHAVE_TAP_NETWORK -DHAVE_BSDTUNTAP
NETWORK_LAN_FEATURES += TAP
ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS)))
NETWORK_CCDEFS += -DUSE_NETWORK
ifeq (bsdtuntap,$(shell if ${TEST} -e /usr/include/net/if_tun.h -o -e /Library/Extensions/tap.kext -o -e /Applications/Tunnelblick.app/Contents/Resources/tap-notarized.kext; then echo bsdtuntap; fi))
# Provide support for Tap networking on BSD platforms (including OS X)
NETWORK_CCDEFS += -DHAVE_TAP_NETWORK -DHAVE_BSDTUNTAP
NETWORK_LAN_FEATURES += TAP
ifeq (,$(findstring USE_NETWORK,$(NETWORK_CCDEFS))$(findstring USE_SHARED,$(NETWORK_CCDEFS)))
NETWORK_CCDEFS += -DUSE_NETWORK
endif
endif
endif
ifeq (slirp,$(shell if ${TEST} -e slirp_glue/sim_slirp.c; then echo slirp; fi))

File diff suppressed because it is too large Load Diff

View File

@ -129,26 +129,34 @@ extern "C" {
#undef USE_SHARED
#endif
/* USE_SHARED implies shared pcap, so force HAVE_PCAP_NETWORK */
#if defined(USE_SHARED) && !defined(HAVE_PCAP_NETWORK)
#define HAVE_PCAP_NETWORK 1
#endif
/*
USE_BPF is defined to let this code leverage the libpcap/OS kernel provided
BPF packet filtering. This generally will enhance performance. It may not
be available in some environments and/or it may not work correctly, so
undefining this will still provide working code here.
*/
#if defined(HAVE_PCAP_NETWORK)
#if defined(HAVE_PCAP_NETWORK) || defined(USE_SHARED)
#define USE_BPF 1
#if defined (_WIN32) && !defined (BPF_CONST_STRING)
#if !defined(HAVE_PCAP_NETWORK)
#define HAVE_PCAP_NETWORK 1
#endif
#define BPF_CONST_STRING 1
#endif
#else
#define DONT_USE_PCAP_FINDALLDEVS 1
#endif
/* Generally avoid pcap APIs when running with vmnet.framework */
#if defined(HAVE_VMNET_NETWORK)
#define DONT_USE_PCAP_FINDALLDEVS 1
#if defined(HAVE_TAP_NETWORK)
#undef HAVE_TAP_NETWORK
#endif
#if defined(HAVE_VDE_NETWORK)
#undef HAVE_VDE_NETWORK
#endif
#endif
/* structure declarations */
@ -157,6 +165,7 @@ extern "C" {
#define ETH_FILTER_MAX 20 /* maximum address filters */
#define ETH_DEV_NAME_MAX 256 /* maximum device name size */
#define ETH_DEV_DESC_MAX 256 /* maximum device description size */
#define ETH_DEV_INFO_MAX 256 /* maximum device info size */
#define ETH_MIN_PACKET 60 /* minimum ethernet packet size */
#define ETH_MAX_PACKET 1514 /* maximum ethernet packet size */
#define ETH_MAX_JUMBO_FRAME 65536 /* maximum ethernet jumbo frame size (or Offload Segment Size) */
@ -234,6 +243,8 @@ typedef unsigned char ETH_MAC[6];
struct eth_list {
char name[ETH_DEV_NAME_MAX];
char desc[ETH_DEV_DESC_MAX];
char info[ETH_DEV_INFO_MAX];
char connect[ETH_DEV_NAME_MAX];
int eth_api;
};
@ -256,12 +267,13 @@ struct eth_device {
SOCKET fd_handle; /* fd to kernel device (where needed) */
char* bpf_filter; /* bpf filter currently in effect */
int eth_api; /* Designator for which API is being used to move packets */
#define ETH_API_NONE 0 /* No API in use yet */
#define ETH_API_PCAP 1 /* Pcap API in use */
#define ETH_API_TAP 2 /* tun/tap API in use */
#define ETH_API_VDE 3 /* VDE API in use */
#define ETH_API_UDP 4 /* UDP API in use */
#define ETH_API_NAT 5 /* NAT (SLiRP) API in use */
#define ETH_API_NONE 0 /* No API in use yet */
#define ETH_API_PCAP 1 /* Pcap API in use */
#define ETH_API_TAP 2 /* tun/tap API in use */
#define ETH_API_VDE 3 /* VDE API in use */
#define ETH_API_UDP 4 /* UDP API in use */
#define ETH_API_NAT 5 /* NAT (SLiRP) API in use */
#define ETH_API_VMNET 6 /* Apple vmnet.framework in use */
ETH_PCALLBACK read_callback; /* read callback function */
ETH_PCALLBACK write_callback; /* write callback function */
ETH_PACK* read_packet; /* read packet */
@ -277,6 +289,7 @@ struct eth_device {
ETH_MAC physical_addr; /* physical address of interface */
int32 have_host_nic_phy_addr; /* flag indicating that the host_nic_phy_hw_addr is valid */
ETH_MAC host_nic_phy_hw_addr; /* MAC address of the attached NIC */
ETH_BOOL host_nic_is_wifi; /* Attached NIC is a WiFi device */
uint32 jumbo_fragmented; /* Giant IPv4 Frames Fragmented */
uint32 jumbo_dropped; /* Giant Frames Dropped */
uint32 jumbo_truncated; /* Giant Frames too big for capture buffer - Dropped */

View File

@ -42,6 +42,11 @@
#include "sim_slirp.h"
#include "sim_sock.h"
#include "libslirp.h"
#include "sim_ether.h"
#ifdef HAVE_VMNET_NETWORK
#include <vmnet/vmnet.h>
#endif
#if !defined (USE_READER_THREAD)
#define pthread_mutex_init(mtx, val)
@ -58,14 +63,6 @@ static const char *tcpudp[] = {
"UDP"
};
struct redir_tcp_udp {
struct in_addr inaddr;
int is_udp;
int port;
int lport;
struct redir_tcp_udp *next;
};
static int
_parse_redirect_port (struct redir_tcp_udp **head, const char *buff, int is_udp)
{
@ -115,7 +112,8 @@ else {
}
}
static int _do_redirects (Slirp *slirp, struct redir_tcp_udp *head)
static int
_do_redirects (Slirp *slirp, struct redir_tcp_udp *head)
{
struct in_addr host_addr;
int ret = 0;
@ -140,19 +138,7 @@ struct slirp_write_request {
struct sim_slirp {
Slirp *slirp;
char *args;
struct in_addr vnetwork;
struct in_addr vnetmask;
int maskbits;
struct in_addr vgateway;
int dhcpmgmt;
struct in_addr vdhcp_start;
struct in_addr vnameserver;
char *boot_file;
char *tftp_path;
char *dns_search;
char **dns_search_domains;
struct redir_tcp_udp *rtcp;
struct sim_net_attributes nat;
GArray *gpollfds;
SOCKET db_chime; /* write packet doorbell */
struct slirp_write_request *write_requests;
@ -164,6 +150,7 @@ struct sim_slirp {
uint32 dbit;
};
#if defined(__cplusplus)
extern "C" {
#endif
@ -173,164 +160,34 @@ uint32 slirp_dbit;
}
#endif
static int
sim_slirp_parse_args (SLIRP *slirp, const char *args, char *errbuf, size_t errbuf_size)
{
return sim_nat_parse_args (&slirp->nat, args, ETH_API_NAT, errbuf, errbuf_size);
}
SLIRP *sim_slirp_open (const char *args, void *opaque, packet_callback callback, DEVICE *dptr, uint32 dbit, char *errbuf, size_t errbuf_size)
{
SLIRP *slirp = (SLIRP *)g_malloc0(sizeof(*slirp));
char *targs = g_strdup (args);
const char *tptr = targs;
const char *cptr;
char tbuf[CBUFSIZE], gbuf[CBUFSIZE], abuf[CBUFSIZE];
int err;
slirp_dptr = dptr;
slirp_dbit = dbit;
slirp->args = (char *)g_malloc0(1 + strlen(args));
strcpy (slirp->args, args);
slirp->opaque = opaque;
slirp->callback = callback;
slirp->maskbits = 24;
slirp->dhcpmgmt = 1;
slirp->db_chime = INVALID_SOCKET;
inet_aton(DEFAULT_IP_ADDR,&slirp->vgateway);
pthread_mutex_init (&slirp->write_buffer_lock, NULL);
err = 0;
while (*tptr && !err) {
tptr = get_glyph_nc (tptr, tbuf, ',');
if (!tbuf[0])
break;
cptr = tbuf;
cptr = get_glyph (cptr, gbuf, '=');
if (0 == MATCH_CMD (gbuf, "DHCP")) {
slirp->dhcpmgmt = 1;
if (cptr && *cptr)
inet_aton (cptr, &slirp->vdhcp_start);
continue;
}
if (0 == MATCH_CMD (gbuf, "TFTP")) {
if (cptr && *cptr)
slirp->tftp_path = g_strdup (cptr);
else {
strlcpy (errbuf, "Missing TFTP Path", errbuf_size);
err = 1;
}
continue;
}
if (0 == MATCH_CMD (gbuf, "BOOTFILE")) {
if (cptr && *cptr)
slirp->boot_file = g_strdup (cptr);
else {
strlcpy (errbuf, "Missing DHCP Boot file name", errbuf_size);
err = 1;
}
continue;
}
if ((0 == MATCH_CMD (gbuf, "NAMESERVER")) ||
(0 == MATCH_CMD (gbuf, "DNS"))) {
if (cptr && *cptr)
inet_aton (cptr, &slirp->vnameserver);
else {
strlcpy (errbuf, "Missing nameserver", errbuf_size);
err = 1;
}
continue;
}
if (0 == MATCH_CMD (gbuf, "DNSSEARCH")) {
if (cptr && *cptr) {
int count = 0;
char *name;
slirp->dns_search = g_strdup (cptr);
name = slirp->dns_search;
do {
++count;
slirp->dns_search_domains = (char **)realloc (slirp->dns_search_domains, (count + 1)*sizeof(char *));
slirp->dns_search_domains[count] = NULL;
slirp->dns_search_domains[count-1] = name;
name = strchr (name, ':');
if (name) {
*name = '\0';
++name;
}
} while (name && *name);
}
else {
strlcpy (errbuf, "Missing DNS search list", errbuf_size);
err = 1;
}
continue;
}
if (0 == MATCH_CMD (gbuf, "GATEWAY")) {
if (cptr && *cptr) {
cptr = get_glyph (cptr, abuf, '/');
if (cptr && *cptr)
slirp->maskbits = atoi (cptr);
inet_aton (abuf, &slirp->vgateway);
}
else {
strlcpy (errbuf, "Missing host", errbuf_size);
err = 1;
}
continue;
}
if (0 == MATCH_CMD (gbuf, "NETWORK")) {
if (cptr && *cptr) {
cptr = get_glyph (cptr, abuf, '/');
if (cptr && *cptr)
slirp->maskbits = atoi (cptr);
inet_aton (abuf, &slirp->vnetwork);
}
else {
strlcpy (errbuf, "Missing network", errbuf_size);
err = 1;
}
continue;
}
if (0 == MATCH_CMD (gbuf, "NODHCP")) {
slirp->dhcpmgmt = 0;
continue;
}
if (0 == MATCH_CMD (gbuf, "UDP")) {
if (cptr && *cptr)
err = _parse_redirect_port (&slirp->rtcp, cptr, IS_UDP);
else {
strlcpy (errbuf, "Missing UDP port mapping", errbuf_size);
err = 1;
}
continue;
}
if (0 == MATCH_CMD (gbuf, "TCP")) {
if (cptr && *cptr)
err = _parse_redirect_port (&slirp->rtcp, cptr, IS_TCP);
else {
strlcpy (errbuf, "Missing TCP port mapping", errbuf_size);
err = 1;
}
continue;
}
snprintf (errbuf, errbuf_size - 1, "Unexpected NAT argument: %s", gbuf);
err = 1;
}
if (err) {
if (sim_slirp_parse_args(slirp, args, errbuf, errbuf_size)) {
sim_slirp_close (slirp);
g_free (targs);
return NULL;
}
slirp->vnetmask.s_addr = slirp->maskbits ? htonl(~((1 << (32-slirp->maskbits)) - 1)) : 0xFFFFFFFF;
slirp->vnetwork.s_addr = slirp->vgateway.s_addr & slirp->vnetmask.s_addr;
if ((slirp->vgateway.s_addr & ~slirp->vnetmask.s_addr) == 0)
slirp->vgateway.s_addr = htonl(ntohl(slirp->vnetwork.s_addr) | 2);
if ((slirp->vdhcp_start.s_addr == 0) && slirp->dhcpmgmt)
slirp->vdhcp_start.s_addr = htonl(ntohl(slirp->vnetwork.s_addr) | 15);
if (slirp->vnameserver.s_addr == 0)
slirp->vnameserver.s_addr = htonl(ntohl(slirp->vnetwork.s_addr) | 3);
slirp->slirp = slirp_init (0, slirp->vnetwork, slirp->vnetmask, slirp->vgateway,
NULL, slirp->tftp_path, slirp->boot_file,
slirp->vdhcp_start, slirp->vnameserver,
(const char **)(slirp->dns_search_domains), (void *)slirp);
slirp->slirp = slirp_init (0, slirp->nat.vnetwork, slirp->nat.vnetmask, slirp->nat.vgateway,
NULL, slirp->nat.tftp_path, slirp->nat.boot_file,
slirp->nat.vdhcp_start, slirp->nat.vnameserver,
(const char **)(slirp->nat.dns_search_domains), (void *)slirp);
if (_do_redirects (slirp->slirp, slirp->rtcp)) {
if (_do_redirects (slirp->slirp, slirp->nat.rtcp)) {
sim_slirp_close (slirp);
slirp = NULL;
}
@ -360,7 +217,6 @@ else {
if (sim_deb && (sim_deb != stdout) && (sim_deb != sim_log))
sim_slirp_show(slirp, sim_deb);
}
g_free (targs);
return slirp;
}
@ -369,14 +225,14 @@ void sim_slirp_close (SLIRP *slirp)
struct redir_tcp_udp *rtmp;
if (slirp) {
g_free (slirp->args);
g_free (slirp->tftp_path);
g_free (slirp->boot_file);
g_free (slirp->dns_search);
g_free (slirp->dns_search_domains);
while ((rtmp = slirp->rtcp)) {
g_free (slirp->nat.args);
g_free (slirp->nat.tftp_path);
g_free (slirp->nat.boot_file);
g_free (slirp->nat.dns_search);
g_free (slirp->nat.dns_search_domains);
while ((rtmp = slirp->nat.rtcp)) {
slirp_remove_hostfwd(slirp->slirp, rtmp->is_udp, rtmp->inaddr, rtmp->lport);
slirp->rtcp = rtmp->next;
slirp->nat.rtcp = rtmp->next;
g_free (rtmp);
}
g_array_free(slirp->gpollfds, true);
@ -401,57 +257,6 @@ if (slirp) {
g_free (slirp);
}
t_stat sim_slirp_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "%s",
"NAT options:\n"
" DHCP{=dhcp_start_address} Enables DHCP server and specifies\n"
" guest LAN DHCP start IP address\n"
" BOOTFILE=bootfilename specifies DHCP returned Boot Filename\n"
" TFTP=tftp-base-path Enables TFTP server and specifies\n"
" base file path\n"
" NAMESERVER=nameserver_ipaddres specifies DHCP nameserver IP address\n"
" DNS=nameserver_ipaddres specifies DHCP nameserver IP address\n"
" DNSSEARCH=domain{:domain{:domain}} specifies DNS Domains search suffixes\n"
" GATEWAY=host_ipaddress{/masklen} specifies LAN gateway IP address\n"
" NETWORK=network_ipaddress{/masklen} specifies LAN network address\n"
" UDP=port:address:address's-port maps host UDP port to guest port\n"
" TCP=port:address:address's-port maps host TCP port to guest port\n"
" NODHCP disables DHCP server\n\n"
"Default NAT Options: GATEWAY=10.0.2.2, masklen=24(netmask is 255.255.255.0)\n"
" DHCP=10.0.2.15, NAMESERVER=10.0.2.3\n"
" Nameserver defaults to proxy traffic to host system's active nameserver\n\n"
"The 'address' field in the UDP and TCP port mappings are the simulated\n"
"(guest) system's IP address which, if DHCP allocated would default to\n"
"10.0.2.15 or could be statically configured to any address including\n"
"10.0.2.4 thru 10.0.2.14.\n\n"
"NAT limitations\n\n"
"There are four limitations of NAT mode which users should be aware of:\n\n"
" 1) ICMP protocol limitations:\n"
" Some frequently used network debugging tools (e.g. ping or tracerouting)\n"
" rely on the ICMP protocol for sending/receiving messages. While some\n"
" ICMP support is available on some hosts (ping may or may not work),\n"
" some other tools may not work reliably.\n\n"
" 2) Receiving of UDP broadcasts is not reliable:\n"
" The guest does not reliably receive broadcasts, since, in order to save\n"
" resources, it only listens for a certain amount of time after the guest\n"
" has sent UDP data on a particular port.\n\n"
" 3) Protocols such as GRE, DECnet, LAT and Clustering are unsupported:\n"
" Protocols other than TCP and UDP are not supported.\n\n"
" 4) Forwarding host ports < 1024 impossible:\n"
" On Unix-based hosts (e.g. Linux, Solaris, Mac OS X) it is not possible\n"
" to bind to ports below 1024 from applications that are not run by root.\n"
" As a result, if you try to configure such a port forwarding, the attach\n"
" will fail.\n\n"
"These limitations normally don't affect standard network use. But the\n"
"presence of NAT has also subtle effects that may interfere with protocols\n"
"that are normally working. One example is NFS, where the server is often\n"
"configured to refuse connections from non-privileged ports (i.e. ports not\n"
" below 1024).\n"
);
return SCPE_OK;
}
int sim_slirp_send (SLIRP *slirp, const char *msg, size_t len, int flags)
{
struct slirp_write_request *request;
@ -503,41 +308,6 @@ SLIRP *slirp = (SLIRP *)opaque;
slirp->callback (slirp->opaque, pkt, pkt_len);
}
void sim_slirp_show (SLIRP *slirp, FILE *st)
{
struct redir_tcp_udp *rtmp;
if ((slirp == NULL) || (slirp->slirp == NULL))
return;
fprintf (st, "NAT args: %s\n", slirp->args);
fprintf (st, "NAT network setup:\n");
fprintf (st, " gateway =%s/%d", inet_ntoa(slirp->vgateway), slirp->maskbits);
fprintf (st, "(%s)\n", inet_ntoa(slirp->vnetmask));
fprintf (st, " DNS =%s\n", inet_ntoa(slirp->vnameserver));
if (slirp->vdhcp_start.s_addr != 0)
fprintf (st, " dhcp_start =%s\n", inet_ntoa(slirp->vdhcp_start));
if (slirp->boot_file)
fprintf (st, " dhcp bootfile =%s\n", slirp->boot_file);
if (slirp->dns_search_domains) {
char **domains = slirp->dns_search_domains;
fprintf (st, " DNS domains =");
while (*domains) {
fprintf (st, "%s%s", (domains != slirp->dns_search_domains) ? ", " : "", *domains);
++domains;
}
fprintf (st, "\n");
}
if (slirp->tftp_path)
fprintf (st, " tftp prefix =%s\n", slirp->tftp_path);
rtmp = slirp->rtcp;
while (rtmp) {
fprintf (st, " redir %3s =%d:%s:%d\n", tcpudp[rtmp->is_udp], rtmp->lport, inet_ntoa(rtmp->inaddr), rtmp->port);
rtmp = rtmp->next;
}
slirp_connection_info (slirp->slirp, (Monitor *)st);
}
#if !defined(MAX)
#define MAX(a,b) (((a)>(b)) ? (a) : (b))
#endif
@ -664,3 +434,282 @@ slirp_pollfds_poll(slirp->gpollfds, 0);
}
#if defined(HAVE_VMNET_NETWORK)
#define UNUSED_SETTING(arg) if (nat_type == ETH_API_VMNET) sim_messagef(SCPE_OK, "Ignoring unused %s setting which unavailable in vmnet\n", arg)
#else
#define UNUSED_SETTING(arg)
#endif
int
sim_nat_parse_args (NAT *nat, const char *args, int nat_type, char *errbuf, size_t errbuf_size)
{
char *targs = g_strdup (args);
const char *tptr = targs;
const char *cptr;
char tbuf[CBUFSIZE], gbuf[CBUFSIZE], abuf[CBUFSIZE];
int err;
nat->nat_type = nat_type;
nat->maskbits = 24;
nat->dhcpmgmt = 1;
if (nat->vgateway.s_addr == INADDR_ANY)
inet_aton(DEFAULT_IP_ADDR, &nat->vgateway);
if (nat->args == NULL) {
nat->args = (char *)g_malloc0(1 + strlen(args));
strcpy (nat->args, args);
}
else {
nat->args = (char *)g_realloc(nat->args, strlen(nat->args) + 2 + strlen(args));
strcat(nat->args, ",");
strcat(nat->args, args);
}
memset(errbuf, 0, errbuf_size);
err = 0;
while (*tptr && !err) {
tptr = get_glyph_nc (tptr, tbuf, ',');
if (!tbuf[0])
break;
cptr = tbuf;
cptr = get_glyph (cptr, gbuf, '=');
if (0 == MATCH_CMD (gbuf, "DHCP")) {
nat->dhcpmgmt = 1;
if (cptr && *cptr)
inet_aton (cptr, &nat->vdhcp_start);
continue;
}
if (0 == MATCH_CMD (gbuf, "STARTIP")) {
if (cptr && *cptr)
inet_aton (cptr, &nat->vdhcp_start);
else {
strlcpy (errbuf, "STARTIP Missing start ip address", errbuf_size);
err = 1;
}
continue;
}
if (0 == MATCH_CMD (gbuf, "ENDIP")) {
if (cptr && *cptr)
inet_aton (cptr, &nat->vdhcp_end);
else {
strlcpy (errbuf, "ENDIP Missing end ip address", errbuf_size);
err = 1;
}
continue;
}
if (0 == MATCH_CMD (gbuf, "TFTP")) {
if (cptr && *cptr)
nat->tftp_path = g_strdup (cptr);
else {
strlcpy (errbuf, "TFTP Missing TFTP Path", errbuf_size);
err = 1;
}
UNUSED_SETTING("TFTP");
continue;
}
if (0 == MATCH_CMD (gbuf, "BOOTFILE")) {
if (cptr && *cptr)
nat->boot_file = g_strdup (cptr);
else {
strlcpy (errbuf, "BOOTFILE Missing DHCP Boot file name", errbuf_size);
err = 1;
}
UNUSED_SETTING("BOOTFILE");
continue;
}
if ((0 == MATCH_CMD (gbuf, "NAMESERVER")) ||
(0 == MATCH_CMD (gbuf, "DNS"))) {
if (cptr && *cptr)
inet_aton (cptr, &nat->vnameserver);
else {
strlcpy (errbuf, "Missing nameserver", errbuf_size);
err = 1;
}
UNUSED_SETTING("NAMESERVER");
continue;
}
if (0 == MATCH_CMD (gbuf, "DNSSEARCH")) {
if (cptr && *cptr) {
int count = 0;
char *name;
nat->dns_search = g_strdup (cptr);
name = nat->dns_search;
do {
++count;
nat->dns_search_domains = (char **)realloc (nat->dns_search_domains, (count + 1)*sizeof(char *));
nat->dns_search_domains[count] = NULL;
nat->dns_search_domains[count-1] = name;
name = strchr (name, ':');
if (name) {
*name = '\0';
++name;
}
} while (name && *name);
}
else {
strlcpy (errbuf, "DNSSEARCH Missing DNS search list", errbuf_size);
err = 1;
}
UNUSED_SETTING("DNSSEARCH");
continue;
}
if ((0 == MATCH_CMD (gbuf, "GATEWAY")) ||
(0 == MATCH_CMD (gbuf, "HOSTIP"))) {
if (cptr && *cptr) {
cptr = get_glyph (cptr, abuf, '/');
if (cptr && *cptr)
nat->maskbits = atoi (cptr);
inet_aton (abuf, &nat->vgateway);
}
else {
strlcpy (errbuf, "GATEWAY Missing host ip address", errbuf_size);
err = 1;
}
continue;
}
if (0 == MATCH_CMD (gbuf, "NETWORK")) {
if (cptr && *cptr) {
cptr = get_glyph (cptr, abuf, '/');
if (cptr && *cptr)
nat->maskbits = atoi (cptr);
inet_aton (abuf, &nat->vnetwork);
}
else {
strlcpy (errbuf, "NETWORK Missing network", errbuf_size);
err = 1;
}
continue;
}
if (0 == MATCH_CMD (gbuf, "NODHCP")) {
nat->dhcpmgmt = 0;
continue;
}
if (0 == MATCH_CMD (gbuf, "UDP")) {
if (cptr && *cptr)
err = _parse_redirect_port (&nat->rtcp, cptr, IS_UDP);
else {
strlcpy (errbuf, "UDP Missing UDP port mapping", errbuf_size);
err = 1;
}
continue;
}
if (0 == MATCH_CMD (gbuf, "TCP")) {
if (cptr && *cptr)
err = _parse_redirect_port (&nat->rtcp, cptr, IS_TCP);
else {
strlcpy (errbuf, "TCP Missing TCP port mapping", errbuf_size);
err = 1;
}
continue;
}
snprintf (errbuf, errbuf_size, "Unexpected NAT argument: %s", gbuf);
err = 1;
}
g_free (targs);
if (err)
return err;
nat->vnetmask.s_addr = nat->maskbits ? htonl(~((1 << (32-nat->maskbits)) - 1)) : 0xFFFFFFFF;
nat->vnetwork.s_addr = nat->vgateway.s_addr & nat->vnetmask.s_addr;
if ((nat->vgateway.s_addr & ~nat->vnetmask.s_addr) == 0)
nat->vgateway.s_addr = htonl(ntohl(nat->vnetwork.s_addr) | 2);
if ((nat->vdhcp_start.s_addr == 0) && nat->dhcpmgmt)
nat->vdhcp_start.s_addr = htonl(ntohl(nat->vnetwork.s_addr) | 15);
if ((nat->vdhcp_end.s_addr == 0) && nat->dhcpmgmt)
nat->vdhcp_end.s_addr = htonl(ntohl(nat->vnetwork.s_addr) | ((0xffffffff >> nat->maskbits) - 1));
if (nat->vnameserver.s_addr == 0)
nat->vnameserver.s_addr = htonl(ntohl(nat->vnetwork.s_addr) | 3);
return err;
}
void sim_slirp_show (SLIRP *slirp, FILE *st)
{
sim_nat_show (&slirp->nat, st);
slirp_connection_info (slirp->slirp, (Monitor *)st);
}
void sim_nat_show (NAT *nat, FILE *st)
{
struct redir_tcp_udp *rtmp;
if (nat == NULL)
return;
fprintf (st, "NAT args: %s\n", nat->args);
fprintf (st, "NAT network setup:\n");
fprintf (st, " gateway =%s/%d", inet_ntoa(nat->vgateway), nat->maskbits);
fprintf (st, "(%s)\n", inet_ntoa(nat->vnetmask));
fprintf (st, " DNS =%s\n", inet_ntoa(nat->vnameserver));
if (nat->vdhcp_start.s_addr != 0)
fprintf (st, " dhcp_start =%s\n", inet_ntoa(nat->vdhcp_start));
if (nat->vdhcp_end.s_addr != 0)
fprintf (st, " dhcp_end =%s\n", inet_ntoa(nat->vdhcp_end));
if (nat->boot_file)
fprintf (st, " dhcp bootfile =%s\n", nat->boot_file);
if (nat->dns_search_domains) {
char **domains = nat->dns_search_domains;
fprintf (st, " DNS domains =");
while (*domains) {
fprintf (st, "%s%s", (domains != nat->dns_search_domains) ? ", " : "", *domains);
++domains;
}
fprintf (st, "\n");
}
if (nat->tftp_path)
fprintf (st, " tftp prefix =%s\n", nat->tftp_path);
rtmp = nat->rtcp;
while (rtmp) {
fprintf (st, " redir %3s =%d:%s:%d\n", tcpudp[rtmp->is_udp], rtmp->lport, inet_ntoa(rtmp->inaddr), rtmp->port);
rtmp = rtmp->next;
}
}
t_stat sim_nat_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "%s",
"NAT options:\n"
" DHCP{=dhcp_start_address} Enables DHCP server and specifies\n"
" guest LAN DHCP start IP address\n"
" BOOTFILE=bootfilename specifies DHCP returned Boot Filename\n"
" TFTP=tftp-base-path Enables TFTP server and specifies\n"
" base file path\n"
" NAMESERVER=nameserver_ipaddres specifies DHCP nameserver IP address\n"
" DNS=nameserver_ipaddres specifies DHCP nameserver IP address\n"
" DNSSEARCH=domain{:domain{:domain}} specifies DNS Domains search suffixes\n"
" GATEWAY=host_ipaddress{/masklen} specifies LAN gateway IP address\n"
" NETWORK=network_ipaddress{/masklen} specifies LAN network address\n"
" UDP=port:address:address's-port maps host UDP port to guest port\n"
" TCP=port:address:address's-port maps host TCP port to guest port\n"
" NODHCP disables DHCP server\n\n"
"Default NAT Options: GATEWAY=10.0.2.2, masklen=24(netmask is 255.255.255.0)\n"
" DHCP=10.0.2.15, NAMESERVER=10.0.2.3\n"
" Nameserver defaults to proxy traffic to host system's active nameserver\n\n"
"The 'address' field in the UDP and TCP port mappings are the simulated\n"
"(guest) system's IP address which, if DHCP allocated would default to\n"
"10.0.2.15 or could be statically configured to any address including\n"
"10.0.2.4 thru 10.0.2.14.\n\n"
"NAT limitations\n\n"
"There are four limitations of NAT mode which users should be aware of:\n\n"
" 1) ICMP protocol limitations:\n"
" Some frequently used network debugging tools (e.g. ping or tracerouting)\n"
" rely on the ICMP protocol for sending/receiving messages. While some\n"
" ICMP support is available on some hosts (ping may or may not work),\n"
" some other tools may not work reliably.\n\n"
" 2) Receiving of UDP broadcasts is not reliable:\n"
" The guest does not reliably receive broadcasts, since, in order to save\n"
" resources, it only listens for a certain amount of time after the guest\n"
" has sent UDP data on a particular port.\n\n"
" 3) Protocols such as GRE, DECnet, LAT and Clustering are unsupported:\n"
" Protocols other than TCP and UDP are not supported.\n\n"
" 4) Forwarding host ports < 1024 impossible:\n"
" On Unix-based hosts (e.g. Linux, Solaris, Mac OS X) it is not possible\n"
" to bind to ports below 1024 from applications that are not run by root.\n"
" As a result, if you try to configure such a port forwarding, the attach\n"
" will fail.\n\n"
"These limitations normally don't affect standard network use. But the\n"
"presence of NAT has also subtle effects that may interfere with protocols\n"
"that are normally working. One example is NFS, where the server is often\n"
"configured to refuse connections from non-privileged ports (i.e. ports not\n"
"below 1024).\n"
);
return SCPE_OK;
}

View File

@ -1,9 +1,38 @@
#ifndef SIM_SLIRP_H
#define SIM_SLIRP_H
#if defined(HAVE_SLIRP_NETWORK)
#if defined(HAVE_SLIRP_NETWORK) || defined(HAVE_VMNET_NETWORK)
#include "sim_defs.h"
struct redir_tcp_udp {
struct in_addr inaddr;
int is_udp;
int port;
int lport;
struct redir_tcp_udp *next;
};
struct sim_net_attributes {
char *args;
int nat_type;
struct in_addr vnetwork;
struct in_addr vnetmask;
int maskbits;
struct in_addr vgateway;
int dhcpmgmt;
struct in_addr vdhcp_start;
struct in_addr vdhcp_end;
struct in_addr vnameserver;
char *boot_file;
char *tftp_path;
char *dns_search;
char **dns_search_domains;
struct redir_tcp_udp *rtcp;
};
typedef struct sim_net_attributes NAT;
typedef struct sim_slirp SLIRP;
typedef void (*packet_callback)(void *opaque, const unsigned char *buf, int len);
@ -13,8 +42,10 @@ void sim_slirp_close (SLIRP *slirp);
int sim_slirp_send (SLIRP *slirp, const char *msg, size_t len, int flags);
int sim_slirp_select (SLIRP *slirp, int ms_timeout);
void sim_slirp_dispatch (SLIRP *slirp);
t_stat sim_slirp_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
void sim_slirp_show (SLIRP *slirp, FILE *st);
int sim_nat_parse_args (NAT *nat, const char *args, int nat_type, char *errbuf, size_t errbuf_size);
t_stat sim_nat_attach_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
void sim_nat_show (NAT *nat, FILE *st);
#endif /* HAVE_SLIRP_NETWORK */