PPP with CHAP authentication between two QNX Neutrino boxes

Updated: April 19, 2023

The following script starts the Point-to-Point Protocol daemon, pppd, with a chat script, waits for the modem to ring, answers it, and starts PPP services with CHAP (Challenge-Handshake Authentication Protocol) authentication. After PPP services have terminated, or an error on modem answer occurs, it restarts and waits for the next call.

#!/bin/sh

SERIAL_PORT=$1
DEFAULT_SERIAL_PORT=/dev/ser1
PPPD="/usr/sbin/pppd"
DO_CHAT="chat -v ABORT BUSY ABORT CARRIER ABORT ERROR \
 TIMEOUT 32000000 RING ATA TIMEOUT 60 CONNECT \d\d\d"
STTY="/bin/stty"
ECHO="/bin/echo"
LOCAL_IP=10.99.99.1
REMOTE_IP=10.99.99.2

if [ "$SERIAL_PORT" == "" ]; then
    SERIAL_PORT=$DEFAULT_SERIAL_PORT
fi

#do some initialization
$STTY +sane +raw < $SERIAL_PORT

while [ true ]; do
    $ECHO "Waiting on modem $SERIAL_PORT..."
    $ECHO "Starting PPP services..."    
    $PPPD connect "$DO_CHAT" debug nodetach auth +chap \
$LOCAL_IP:$REMOTE_IP $SERIAL_PORT
done;

The TIMEOUT is 32000000 because it's a long period of time before the timeout takes effect; chat doesn't allow an infinite wait. The /etc/ppp/chap-secrets is as follows:

# Client  Server  Secret    Addresses allowed
##############################################################
*  *  "password" *

You can also extend the chat script that answers the modem to be a little more robust with specific events that should restart the answering service other than the events given. You might want to add other features as well.

Here's the buildfile used to set up a machine to allow telnet connections (to log in for shell access) and tftp access (for file transfer) over PPP:

[virtual=x86_64,bios +compress] .bootstrap = {
    startup-x86 -K8250.2f8^0.57600.1843200.16 -v
    PATH=/proc/boot procnto-smp-instr -vvv
}
[+script] startup-script = {
    pci-server &
    waitfor /dev/pci
    # Start 1 keyboard console
    devc-con -n8 &
    # Start serial A driver
    waitfor /dev/con1
    reopen /dev/con1
    devc-ser8250 -e -b38400
    waitfor /dev/ser1
    pipe
    touch /tmp/syslog
    syslogd
    devc-pty
    io-pkt-v4-hc -pabc100
    if_up -p abc0
    inetd &

    display_msg "[Shell]"
    [+session] PATH=/bin:/proc/boot /bin/sh &
}

# Make /tmp point to the shared memory area...
[type=link] /tmp=/dev/shmem

[type=link] /bin/sh=/bin/ksh

# We use the "C" shared lib
libc.so
libgcc_s.so.1
/usr/lib/ldqnx-64.so.2=ldqnx-64.so.2
libsocket.so

devc-con
devc-ser8250
devc-pty
pci-server
pipe
io-pkt-v4-hc
/bin/echo=echo
/bin/stty=stty
tail
pci
chat
ifconfig
ping
syslogd
touch
./modem_ans_ppp.sh

#Services (telnetd etc) config
inetd
/usr/sbin/telnetd=telnetd
/usr/sbin/tftpd=tftpd
/usr/sbin/pppd=pppd
/bin/login=login
/bin/ksh=ksh

/etc/ppp/chap-secrets = {
# Client    Server     Secret     Addrs
#########################################
*           *           "password"  *
}
/etc/syslog.conf = {
*.*     /tmp/syslog
}

# Inetd config Files
/etc/services= /etc/services
/etc/protocols= /etc/protocols
/etc/termcap= /etc/termcap
/etc/passwd= /etc/passwd
/etc/default/login= /etc/default/login
/etc/resolv.conf= /etc/resolv.conf
/etc/nsswitch.conf= /etc/nsswitch.conf
/etc/shadow = /etc/shadow

/etc/inetd.conf = {
telnet      stream  tcp nowait  root    /usr/sbin/telnetd   in.telnetd
tftp        dgram   udp wait    root    /usr/sbin/tftpd     in.tftpd
}

/etc/hosts = {
127.1   localhost.localdomain   localhost
10.99.99.1  server  server
10.99.99.2  client  client
}
Note: To build the image using this buildfile, you'll need to be root, because it takes a copy of /etc/passwd and /etc/shadow (which make passwords easy to remember) but you can also put your own version of them into the buildfile as inline files.

Using two computers with modems, you can have one automatically answer, establish PPP services, and authenticate. You can then telnet and tftp to the server from a client. Use these client pppd parameters (in addition to the same chap-secrets file):

pppd connect "chat -v -f/tmp/dial_modem" auth +chap /dev/ser3

but use the appropriate serial port for the client-side modem instead of /dev/ser3. Make sure you use the full path to your modem script. The chat script, dial_modem, is fairly simple:

ABORT 'NO CARRIER'
ABORT 'ERROR'
ABORT 'BUSY'

'' ATDTxxxxxxx
CONNECT ''