Win3x.Org

Windows & DOS Community

Use a rooted Android smartphone as a "serial modem" with DOS

Post Reply   Page 1 of 1  [ 3 posts ]
Author Message
PluMGMK
Post subject: Use a rooted Android smartphone as a "serial modem" with DOS
Posted: 27 November, 14:04
Membre inscrit
User avatar
Offline
 
Posts: 146
 
Hello! :wave: Several months ago, I had this crazy idea to "tether" my PC to my smartphone when running DOS, using a serial null-modem. Eventually I got it working, so I'd like to share what I did, in case anybody else might find it interesting! My starting point was this, but I had to make a lot of adjustments due to running on Android.

Materials required

To get this "tethering" setup working, you will need:
  • A PC with a serial port running DOS
  • The epppd packet driver (it comes with, e.g., Arachne)
  • A serial null-modem cable
  • A USB-C to serial adapter (or whatever type of USB port your phone has) – this is the one I'm using: http://www.amazon.com/Serial-Adapter-Ch ... rd_w=p3Aah
  • A rooted Android (preferably LineageOS) smartphone (I guess it would be easier on a Librem, and conversely impossible on an iPhone!), running a kernel to which one of the following applies:
    • The kernel has built-in support for your serial adapter (unlikely I'd say…)
    • The kernel supports modules so you can build the module for your serial adapter and insmod it (that's what I had to do)
    • You can flash your own kernel, after building one with the serial adapter driver built in
  • Termux with the tsu package installed (pkg install tsu)
Checking the kernel

Before investing any time or money in this project (assuming you're starting with a rooted phone), you can check if your kernel satisfies one of the conditions listed above. To check if it has built-in support for the serial adapter, you can run this command from Termux (you may need to "pkg install gzip" first):
sudo zgrep CONFIG_USB_SERIAL_ /proc/config.gz
If it tells you there is no such file or directory, then unfortunately these checks can't be performed. If you get a bunch of lines ending in "=y", then your kernel is fine, and you can skip the rest of this section and the next. If you get "is not set", then that means the support is not built-in.

If the support is not built-in, the next step is to check if your kernel has module support:
sudo zgrep CONFIG_MODULES /proc/config.gz
If you get "CONFIG_MODULES=y", then modules are supported, and you can build the one for your serial adapter. This requires patience, but shouldn't be intractible.

If CONFIG_MODULES is "n" or "not set", then you'll have to build a new kernel and flash it. Again, this requires patience, and (depending on your device) may be impossible :(
I don't have any experience of doing this, so I can't really advise on how to proceed…

Compiling the kernel module

I'm going to recount here what I did, even though I'm almost certain that there are better ways. It's very hard to find tutorials on this, and any I could find seemed to be out of date. If anyone has any better methods, please suggest them and I'll update the tutorial!

To compile a kernel module you need to get the kernel source, adjust the config file, and compile it. Given my experience compiling Linux kernels for PCs, I expected this to be straightforward, but in the Android ecosystem everything seems to be extra-complicated… Unfortunately all I can talk about is my own experience, which is with LineageOS on a FairPhone 3.

Basically I followed the instructions for building LineageOS, as far as running "./extract-files.sh". (If you're running LineageOS on something other than FP3, you can find the equivalent instructions for your device on the same wiki. If you're running a different Android distribution, or the stock ROM for your device, again I'm unfortunately unsure as to the best course of action…) Then instead of doing "brunch FP3", I did the following:
croot
sed 's/# CONFIG_USB_SERIAL_FTDI_SIO is not set/CONFIG_USB_SERIAL_FTDI_SIO=m/' -i kernel/fairphone/sdm632/arch/arm64/configs/lineageos_FP3_defconfig
mka kernel
Here, FTDI_SIO is the chip in that serial adapter I recommended. I think it's the same chip you'll find in most adapters sold today, but there are other chips you can build drivers for if needed. The path and name of the defconfig file will obviously change if you are building for something other than the FairPhone 3.

The whole process takes ages, since it needs to sync up the entire Android source tree. It is highly wasteful since we only want to compile a little module, but it's the only way I could make it work. Again, if anybody has any better instructions, please post them and I'll happily update the tutorial!

Anyway, at the end of this I had a file "out/target/product/FP3/obj/KERNEL_OBJ/drivers/usb/serial/ftdi_sio.ko" (again replace FP3 with your device). You can copy this ko file to your phone and place it in Termux's home directory. Once this ordeal is over, be sure not to delete anything – you'll need to resync the source and recompile the kernel if any OTA update makes a breaking change!

Setting up Termux scripts

Once you have the kernel module handy (if needed), you can get onto the fun stuff – actually setting up the null modem link from the phone side. All commands in this section are to be run on your phone in the Termux terminal. You can create the scripts as follows:
cat > nullmodem.sh <<EOF
cd /data/data/com.termux/files/home

# Install the kernel module if needed
lsmod|grep ftdi || insmod ftdi_sio.ko

# Verify the yoke is plugged in
stat /dev/ttyUSB0 || exit "Looks like the serial adapter is not plugged in!"

# Setup the actual connection
# Based on http://medium.com/swlh/connecting-a-286-dos-pc-to-the-internet-through-a-serial-connection-in-2019-b93a422ff094
# No lock since Android doesn't have "/var/lock" as a location
proot -b ppp_scripts:/etc/ppp pppd ttyUSB0 115200 local debug noccp passive proxyarp defaultroute noauth mtu 1500 192.168.122.1:192.168.122.2
EOF

mkdir -p ppp_scripts
cat > ppp_scripts/ip-down <<EOF
#!/system/bin/sh

# Clean up the firewall and routing stuff
ROUTETABLE=$(/data/data/com.termux/files/usr/bin/ip route get $IPREMOTE | grep table | sed 's/.*table \([0-9]*\) .*/\1/')
UPSTREAM=$(/data/data/com.termux/files/usr/bin/ip rule | grep "from all iif lo oif [^ ]* lookup $ROUTETABLE" | sed 's/.*oif \([^ ]*\).*/\1/')
/data/data/com.termux/files/usr/bin/iptables -D tetherctrl_FORWARD -i $UPSTREAM -o $IFNAME -m state --state RELATED,ESTABLISHED -g tetherctrl_counters
/data/data/com.termux/files/usr/bin/iptables -D tetherctrl_FORWARD -i $IFNAME -o $UPSTREAM -m state --state INVALID -j DROP
/data/data/com.termux/files/usr/bin/iptables -D tetherctrl_FORWARD -i $IFNAME -o $UPSTREAM -g tetherctrl_counters
/data/data/com.termux/files/usr/bin/iptables -D tetherctrl_counters -i $IFNAME -o $UPSTREAM -j RETURN
/data/data/com.termux/files/usr/bin/iptables -D tetherctrl_counters -i $UPSTREAM -o $IFNAME -j RETURN

/data/data/com.termux/files/usr/bin/ip rule del from all iif $IFNAME lookup $ROUTETABLE
/data/data/com.termux/files/usr/bin/ip rule del to $IPREMOTE lookup $ROUTETABLE
EOF

cat > ppp_scripts/ip-up <<EOF
#!/system/bin/sh

# This will resolve to "ip route add $IPREMOTE <BLAH> table <CORRECTNUMBER>"
ROUTETABLE=$(/data/data/com.termux/files/usr/bin/ip route get $IPREMOTE | grep table | sed 's/.*table \([0-9]*\) .*/\1/')
/data/data/com.termux/files/usr/bin/ip route add $(/data/data/com.termux/files/usr/bin/ip route|grep $IPREMOTE) table $ROUTETABLE

# Set up the appropriate forwarding rules in the firewall
UPSTREAM=$(/data/data/com.termux/files/usr/bin/ip rule | grep "from all iif lo oif [^ ]* lookup $ROUTETABLE" | sed 's/.*oif \([^ ]*\).*/\1/')
/data/data/com.termux/files/usr/bin/iptables -t nat -A tetherctrl_nat_POSTROUTING -o $UPSTREAM -j MASQUERADE
/data/data/com.termux/files/usr/bin/iptables -D tetherctrl_FORWARD -j bw_global_alert || true # Remove it if it's already there so we don't duplicate it…
/data/data/com.termux/files/usr/bin/iptables -I tetherctrl_FORWARD 1 -j bw_global_alert
/data/data/com.termux/files/usr/bin/iptables -I tetherctrl_FORWARD 2 -i $UPSTREAM -o $IFNAME -m state --state RELATED,ESTABLISHED -g tetherctrl_counters
/data/data/com.termux/files/usr/bin/iptables -I tetherctrl_FORWARD 3 -i $IFNAME -o $UPSTREAM -m state --state INVALID -j DROP
/data/data/com.termux/files/usr/bin/iptables -I tetherctrl_FORWARD 4 -i $IFNAME -o $UPSTREAM -g tetherctrl_counters
/data/data/com.termux/files/usr/bin/iptables -A tetherctrl_counters -i $IFNAME -o $UPSTREAM -j RETURN
/data/data/com.termux/files/usr/bin/iptables -A tetherctrl_counters -i $UPSTREAM -o $IFNAME -j RETURN

# And finally make sure that packets get routed properly from/to the client
RULEPRIO=$(/data/data/com.termux/files/usr/bin/ip rule | grep -m 1 "from all iif [^ ]* lookup $ROUTETABLE" | sed 's/^\([0-9]*\):.*/\1/')
/data/data/com.termux/files/usr/bin/ip rule add from all iif $IFNAME lookup $ROUTETABLE priority $RULEPRIO
/data/data/com.termux/files/usr/bin/ip rule add to $IPREMOTE lookup $ROUTETABLE priority $RULEPRIO
EOF
Again, there may be some LineageOS-specific stuff in here, I'm not sure how well these scripts will work on other Android distributions…

If your kernel has the support for the serial adapter built-in (i.e. you don't need the module) then remove the lsmod/insmod line in "~/nullmodem.sh". You can also install the Termux:Widget app and create a friendly wrapper script:
cat > ~/.shortcuts/Setup\ Null\ Modem <<EOF
termux-wake-lock
sudo ~/nullmodem.sh
termux-wake-unlock
EOF
To make sure all these scripts work, you'll need to install some packages:
pkg install termux-tools iptables iproute2
All going well, it should be possible to plug in the serial adapter to your phone's USB port, and run the "Setup Null Modem" script from the Termux widget on your home screen, and it will start listening on the serial port for PPP connections. Once a device on the other end of the null-modem (i.e. your DOS PC) makes this connection, pppd will establish an IP link where the phone has address 192.168.122.1 and the DOS PC has address 192.168.122.2 (if these addresses are unsuitable for some reason, you can change them in ~/nullmodem.sh – you can also change the baud rate from 115200 to something lower, and the MTU from 1500 to something lower, if needed). Once this link is set up, it will run the script ~/ppp_scripts/ip-up, which does the following:
  • Finds the ip routing table for Android's current default network connection (e.g. WiFi) and adds an entry that tells it to send any packets destined for 192.168.122.1 over the PPP link (instead of trying to send them over WiFi). Note that because of the hacky way I've done this, the link will probably stop working if you switch between WiFi and mobile data, or enable/disable a VPN, while the connection is up…
  • Adds a "masquerade" iptables entry, so that any packets originating from the DOS PC are "masqueraded" as coming from the phone itself, when they are sent out to the external network.
  • Adds several iptables entries to the "tetherctrl" chains, to ensure that packets to/from the DOS PC are routed through instead of being dropped.
  • Adds some "rules" to the kernel's list to make sure that the correct routing tables are looked up for packets coming from the DOS PC can be sent to the external network, and that any packets coming in response are routed back to the DOS PC. Without this, you'd get "Destination Net Unreachable" errors…
You can take down the link by simply unplugging the serial adapter. Then pppd will run ~/ppp_scripts/ip-down, which reverses all the configuration changes made by ip-up, and then shut itself down.

Connecting the DOS PC

Once pppd is running on the phone, and the null-modem is connected to the DOS PC's serial port, you can start epppd from the DOS prompt:
epppd com1 115200
If you changed the baud rate in the pppd invocation on the phone, change it here too. Obviously change com1 to a different port if needed, also. All going well, it should install the packet driver at vector 0x60, and you'll have a working network connection! If you're using wattcp-based programs, e.g. Lynx, you can put the following in your wattcp.cfg file:
my_ip=192.168.122.2
nameserver=192.168.1.1
netmask=255.255.255.0
domain.suffix=""
gateway=192.168.122.1
Change your "nameserver" if needed, this is what it is for me. You can use your WiFi router, or the servers provided by your ISP. If you're not sure what to use, there are some free public ones suggested here. The configuration for Arachne should be similar.

If running Windows 3.1 (like me), you can also install Trumpet. One way to use it is to run "winpkt 0x60" after starting epppd, then start Windows. You can then configure Trumpet with the IP and DNS settings given above. I use Trumpet 2.0 (rather than the 3.0 offered here) since it doesn't impose a 30-day trial period. Apparently it is still possible to "register" the newer versions to support the author financially, but I have not succeeded in getting a registration code by doing so :?

It is also possible (and seems to work a bit better) to bypass epppd by using Trumpet's "Internal PPP", which involves a few different settings. In this case, you don't run epppd at all, but just start Windows. My settings currently look something like this (again, change your "Name server" if needed):
My Trumpet settings, with only relevant fields filled in
But either way, it's unfortunately quite dodgy. Attempting to download a file from win3x.org from any Windows-based browser seems to lock up the entire connection, while downloading files using Lynx from DOS doesn't cause any problems. I'm not sure if this can be overcome with the correct choice of MTU/MSS/RWIN – again, any guidance would be welcome!

Setting up a HTTP Proxy

Now that you've got Windows 3.1 accessing the internet through your phone, you may wish to set up a WebOne instance on the latter, so that the former can access more of the modern web. There is no "good" way to do this in Termux (proot-distro worked until Android 13 but even then it didn't make sense to use proot when you have root access).

To do this on Android 13, I use Linux Deploy, which allows you to install a Linux distro within Android. I used Debian for this, by following more or less the instructions here. But I used SSH instead of VNC to access the container. I was able to do this by choosing "Enable" under the "SSH" section of the profile properties.

Once I had my Debian container up and running under Linux Deploy, I accessed it this way from Termux:
ssh android@127.0.0.1
And entered the password set in Linux Deploy's profile properties. Note that by default the username and password are "android" and a randomly-generated eight characters, but you may have changed these, in which case you should also adjust the above command appropriately.

To get things ready, execute the following commands from the ssh session:
sudo apt update
sudo apt upgrade
sudo apt install wget daemonize

wget http://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb9# May need to change depending on the version of Debian you have installed
wget http://github.com/atauenis/webone/releases/download/v0.15.3/webone.0.15.3.linux-arm64.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt update
sudo apt install ./webone.0.15.3.linux-amd64.deb
You may start getting warnings about how systemd isn't running, but these seem to be harmless (unless you try upgrading WebOne at a later date!).

For security, you might want to disable password logons to the SSH server. To do this, I ran the following commands from Termux:
ssh-keygen -b 4096 -f .ssh/linux-deploy-access # I left the passphrase blank
ssh-copy-id -i .ssh/linux-deploy-access.pub android@127.0.0.1
ssh -i .ssh/linux-deploy-access android@127.0.0.1
The third command should get you into your Debian session without asking for the password, in which case you can go ahead and disable password authentication. You can do this by launching the editor:
nano /etc/ssh/sshd_config
And changing PasswordAuthentication yes to PasswordAuthentication no. Then you can go back to the Linux Deploy app, and stop and restart the container.

Finally, here's what you can do to make sure WebOne automatically starts when you establish a PPP connection, and stops when the connection ends.
First, go into Linux Deploy's settings, and set the "Autostart" option so that Debian starts as soon as you turn on your phone.
Then you need to add this to the end of ~/ppp_scripts/ip-up:
# Setup our HTTP proxy
/data/data/com.termux/files/usr/bin/ssh -i /data/data/com.termux/files/home/.ssh/linux-deploy-access android@127.0.0.1 sudo daemonize /usr/local/bin/webone -- --daemon
And this to the end of ~/ppp_scripts/ip-down:
# Shut down HTTP proxy
killall webone
Then you can configure your browser under Windows 3.1 to use 192.168.122.1 port 8080 as its proxy server! :)

Conclusion

So there you have it! It is possible, with a bit of patience and hacking, to use a modern smartphone as a serial modem and connect DOS to the internet over WiFi/mobile! Naturally, this being serial, the connection is very slow, but I guess that adds to the nostalgia factor. In fact, maybe a bit of tweaking to the PPP scripts (an ip-pre-up script?) could be used to make the phone play a recording of the traditional dial-up sound to complete the experience! :lol:

Any feedback welcome! :D (especially suggestions for improving the kernel module compilation and Trumpet settings…)

Last edited by PluMGMK on 01 May, 20:23, edited 1 time in total.

Top
Quote
PluMGMK
Post subject: Re: Use a rooted Android smartphone as a "serial modem" with DOS
Posted: 18 February, 22:09
Membre inscrit
User avatar
Offline
 
Posts: 146
 
Apologies for the double-post, but I just want to note that I've updated the tutorial slightly with some more instructions for using Trumpet's Internal PPP, and instructions for setting up WebOne as part of the tethering!


Top
Quote
PluMGMK
Post subject: Re: Use a rooted Android smartphone as a "serial modem" with DOS
Posted: 01 May 2023 20:26
Membre inscrit
User avatar
Offline
 
Posts: 146
 
Apologies for yet another sequential post, but I've updated it again to use Linux Deploy, since WebOne no longer works under proot-distro as of Android 13.

(If you're interested, it's because of new stricter policies on the bind syscall, manifesting as an issue like this one :?)


Top
Display: Sort by: Direction:
Post Reply   Page 1 of 1  [ 3 posts ]
Return to “Resources”
Jump to: