Dial up server
Contents
Prerequisites
Required hardware:
- A hardware modem (not a software modem/winmodem, must be the real deal)
- A computer to install Linux on to talk to the a modem (Can be anything that a modern Linux distribution will run on. Raspberry Pi, Pi clone, x86 machine, etc)
- A client device (windows 9x PC for example) with a modem
- Some form of PSTN to connect the two modems
The exact hardware I’ve used
- Generic x86_64 PC running Ubuntu Server 18.04
- Matrix “MX Modem” (more on this later)
- USB to RS-232 serial adapter (DE-9) to connect to the modem (Must support hardware flow control)
- DE-9 to DB-25 serial adapter
- Linksys PAP2T analog telephone adapter (ATA)
- x86 based Windows 95 PC with a US Robotics Sportster 28800 ISA modem
Software used
- Ubuntu server 18.04
- PPP
- getty
- Asterisk
Choose your modem hardware
Modem hardware varies greatly but thankfully nothing special is required beyond compatible protocols between your 'ISP' and 'client' modems such as V.22, V.32, etc.
This tutorial should work with any dial-up modem that presents itself as a serial device to the operating system including cheap USB modems, ISA modems, PCI modems and of course external rs232 serial modems.
Note: You will have a lot of trouble using a 'Softmodem\winmodem'! You are much better off using a 'real' hardware based modem.
I'll be using an external serial modem + USB to RS-232 adapter for this tutorial. Using dedicated serial hardware has the advantage of being easy to troubleshoot and can also scale up to dozens of lines if you have enough desk space and USB ports.
My modem is a "MX Modem" made by MATRIX but I was unable to find any information about it. Obviously the next step was to crack it open to try and figure out its capabilities.
Inside is a XECOM XE1414C 14.4 Kbps modem in a single component package. PDF manual is here.
To connect the modem to the computer running the ISP side of things I'm using a generic USB to RS-232 adapter and a DE-9 to DB-25 adapter.
The PSTN
We need a way to connect our modem (serving as an ISP) to clients. There are many ways to approach this:
- Use the actual PSTN via real phone lines
- Use a PBX to provide local connectivity
- Build your own circuity (not covered here, would require extra config as you would not have dial tone)
- Fake PSTN using VoIP ATAs and a software PBX
I've gone with the fourth option. Here's the breakdown:
- Asterisk, a VoIP PBX, is configured on the dial-in server to accept connections from two SIP client accounts and route calls between them.
- A Linksys PAP2T ATA, which supports two phone lines, is set up as both of those SIP clients connected to the PBX.
- The ISP side modem is connected to the first line and the client device is on the second line.
Asterisk set up
- Install asterisk
- Append configuration for the two SIP clients to the end of
/etc/asterisk/sip.conf
[pap2t-ispmodem] context=default type=friend secret=password qualify=200 ; Qualify peer is no more than 200ms away host=dynamic ; This device registers with us directmedia=yes ; Send RTP directly to the peer to reduce latency and jitter regexten=881 nat=no [pap2t-client] context=default type=friend secret=password qualify=200 ; Qualify peer is no more than 200ms away host=dynamic ; This device registers with us directmedia=yes ; Send RTP directly to the peer to reduce latency and jitter regexten=882 nat=no
- Edit
/etc/asterisk/extensions.conf
and make two changes:
Search for[default]
(should be around line 672) and comment outinclude => demo
After that commented out line add a new line withexten => _X!,1,Dial(SIP/pap2t-ispmodem, 20)
The _X! tells this dial plan rule to match any number a client dials and send the call to the pap2t-ispmodem client - Enable the asterisk service so it starts on boot
sudo systemctl enable asterisk
-
Start asterisk
sudo systemctl start asterisk
- Open the asterisk console to confirm your ATA lines are registered
sudo asterisk -rvvvv
dialupserver*CLI> sip show peers Name/username Host Dyn Forcerport Comedia ACL Port Status Description pap2t-client/pap2t-client 10.1.8.112 D No No 5061 OK (7 ms) pap2t-ispmodem/pap2t-ispm 10.1.8.112 D No No 5060 OK (6 ms) 2 sip peers [Monitored: 2 online, 0 offline Unmonitored: 0 online, 0 offline]
If you make changes to your configuration after starting asterisk you can use the
reload
command in the console to reload the configuration.
sudo apt-get install asterisk
ATA SIP Registration example:
-- Registered SIP 'pap2t-ispmodem' at 10.1.8.112:5060 > Saved useragent "Linksys/SPA2102-5.2.5" for peer pap2t-ispmodem NOTICE[4253]: chan_sip.c:24592 handle_response_peerpoke: Peer 'pap2t-ispmodem' is now Reachable. (7ms / 200ms) -- Registered SIP 'pap2t-client' at 10.1.8.112:5061 > Saved useragent "Linksys/SPA2102-5.2.5" for peer pap2t-client NOTICE[4253]: chan_sip.c:24592 handle_response_peerpoke: Peer 'pap2t-client' is now Reachable. (5ms / 200ms)
Successful call example:
== Using SIP RTP CoS mark 5 > 0x7fa234059e30 -- Strict RTP learning after remote address set to: 10.1.8.112:16482 -- Executing [88567682@default:1] Dial("SIP/pap2t-client-00000002", "SIP/pap2t-ispmodem, 20") in new stack == Using SIP RTP CoS mark 5 -- Called SIP/pap2t-ispmodem -- SIP/pap2t-ispmodem-00000003 is ringing > 0x7fa1f8252350 -- Strict RTP learning after remote address set to: 10.1.8.112:16384 -- SIP/pap2t-ispmodem-00000003 answered SIP/pap2t-client-00000002 -- Channel SIP/pap2t-ispmodem-00000003 joined 'simple_bridge' basic-bridge <5f9983eb-3f93-49d1-90b3-c91c545c2d38> -- Channel SIP/pap2t-client-00000002 joined 'simple_bridge' basic-bridge <5f9983eb-3f93-49d1-90b3-c91c545c2d38> > Bridge 5f9983eb-3f93-49d1-90b3-c91c545c2d38: switching from simple_bridge technology to native_rtp > Remotely bridged 'SIP/pap2t-client-00000002' and 'SIP/pap2t-ispmodem-00000003' - media will flow directly between them > 0x7fa1f8252350 -- Strict RTP learning after remote address set to: 10.1.8.112:16384 > 0x7fa234059e30 -- Strict RTP learning after remote address set to: 10.1.8.112:16482 -- Channel SIP/pap2t-client-00000002 left 'native_rtp' basic-bridge <5f9983eb-3f93-49d1-90b3-c91c545c2d38> -- Channel SIP/pap2t-ispmodem-00000003 left 'native_rtp' basic-bridge <5f9983eb-3f93-49d1-90b3-c91c545c2d38> == Spawn extension (default, 88567682, 1) exited non-zero on 'SIP/pap2t-client-00000002' > 0x7fa1f8252350 -- Strict RTP learning after remote address set to: 10.1.8.112:16384
ATA Configuration
I wont go into much detail on ATA configuration since the topic has been beat to death on various forums but for modem communications here is the gist:
- Set up both lines on the ATA to register with the PBX with the usernames 'pap2t-ispmodem' and 'pap2t-client' with the password 'password' (so secure)
- Use g711u codec
- Disable every echo cancellation option in your ATA (see https://www.voip-info.org/linksys-pap2t)
- Set the jitter buffer to be as small as possible (you want voice data on the wire ASAP)
Congrats! You now have your own voice network!
The dial-in-server
- Install Debian/Ubuntu/Raspbian per the usual methods (not covered here)
- Update to latest packages and reboot if required
- Connect USB to RS-232 adapter and confirm it shows up as /dev/ttyUSBXXX (
ls /dev/
to check) In my case it presents as/dev/ttyUSB0
My serial adapter is a "ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adaptor
" - Install ppp (and getty if your distro doesn’t have it by default)
sudo apt-get install ppp mgetty
- Many of the old guides were written when inittab was still around but its 2019 and systemd has taken over.
We need to create a systemd service for mgetty so edit/lib/systemd/system/mgetty.service
with your text editor of choice with elevated privileges (sudo)[Unit] Description=External Modem Documentation=man:mgetty(8) Requires=systemd-udev-settle.service After=systemd-udev-settle.service [Service] Type=simple ExecStart=/sbin/mgetty /dev/ttyUSB0 Restart=always PIDFile=/var/run/mgetty.pid.ttyUSB0 [Install] WantedBy=multi-user.target
-
Configure mgetty by editing
/etc/mgetty/mgetty.config
with your text editor of choice with elevated privileges (sudo)
Comment out everything except the debug level and append the section for configuring the serial devicedebug 9 port ttyUSB0 port-owner root port-group dialout port-mode 0660 data-only yes ignore-carrier no toggle-dtr yes toggle-dtr-waittime 500 rings 2 #autobauding yes speed 9600
- Enable the mgetty service so it starts on boot
sudo systemctl enable mgetty.service
-
Start mgetty
sudo systemctl start mgetty.service
- Configure ppp by editing
/etc/ppp/options
Like above comment out everything except these settings# Define the DNS server for the client to use ms-dns 8.8.8.8 # async character map should be 0 asyncmap 0 # Require authentication auth # Use hardware flow control crtscts # We want exclusive access to the modem device lock # Show pap passwords in log files to help with debugging show-password # Require the client to authenticate with pap +pap # If you are having trouble with auth enable debugging debug # Heartbeat for control messages, used to determine if the client connection has dropped lcp-echo-interval 30 lcp-echo-failure 4 # Cache the client mac address in the arp system table proxyarp # Disable the IPXCP and IPX protocols. noipx
- Create a device option file by editing
/etc/ppp/options.ttyUSB0
local lock nocrtscts 192.168.32.1:192.168.32.105 netmask 255.255.255.0 noauth proxyarp lcp-echo-failure 60
- Create the user used for PAP authentication
sudo useradd -G dialout,dip,users -m -g users -s /usr/sbin/pppd dial
- Change the password (I set it to dial)
sudo passwd dial
- Edit
/etc/ppp/pap-secrets
and append the username and password (quotes included)
dial * "dial" *
- Enable packet forwarding for IP4 by editing
/etc/sysctl.conf
net.ipv4.ip_forward=1
-
Last step for the dial-up server is to configure the firewall to allow forwarding of traffic from PPP out onto the network (and off to the internet)
- On Linux distributions with iptables you need to add a line to
/etc/rc.local
to enable masquerading. If your ethernet interface is named eth0 you would add this line:iptables -t nat -A POSTROUTING -s 192.168.32.0/24 -o eth0 -j MASQUERADE
-
On modern Ubuntu installs ufw is used instead of iptables so the procedure is a bit different. Follow this guide but you can omit
-o eth0
and use-s 192.168.32.0/24
https://help.ubuntu.com/lts/serverguide/firewall.html.en#ip-masquerading
- On Linux distributions with iptables you need to add a line to
sudo apt-get update sudo apt-get upgrade sudo reboot
Troubleshooting
When using an external modem the choice of USB to RS-232 adapter seems to be crucial. There aren't many requirements but you must use an adapter that supports hardware flow control.
If you need to purchase an adapter you can either get one that explicitly says it supports hardware flow control ($$$$) or play the eBay lottery and buy a half dozen different models and hope one of them works.
I ran into a bug in Debian 9.5 with my ch341 driver based USB to serial adapter where setting the baud rate was not working on some Linux kernels. (Seems to be this: https://bugzilla.redhat.com/show_bug.cgi?id=1235715)
To troubleshoot modem communication and baud rate settings use minicom (or screen) to open a session over serial and try different settings (or read your modem's manual!). Sending the command 'AT' followed by a new line should result in your modem replying 'OK'
If you're getting nothing at all out of your modem perform a serial loopback test
If mgetty is not answering incoming calls it may be having trouble communicating with your modem. Check the logs in /var/log/mgetty/
to determine the problem. You may need to set a modem initialization string in the mgetty device config file so check your modem's manual for help on this. (If this happens you're in for a rough time)