AB's Useful Box - Dial-in access using Linux, mgetty and pppd

Or better still, Linux as a Remotre Access Server ( RAS ).

Following is some of the notes made while configuring a Linux box to be a Dial-in access point for a private network.

The following was done using a pre-compiled install of Red Hat Linux release 7.3 with Kernel 2.4.18-3 on a i686.

 

Goal was to provide a remote dial-in access point for a small business' private network to allow select personnel to access their desktops via a dial up connection. The system should provide a medium to high level of security and not require any changes to the existing network configuration. Cost was an issue, budget $1000.

One solution could be to just attach a modem to specific computers requiring remote access. Cost would be reasonably low. However it was not centralized, required the remote access phone line to be run out to each of the PC's, security was questionable, certainly could not be restricted down to a TCP/IP port level.

Another solution was to spent +$10,000 on a commercial firewall and router. Just a little over budget. But would be protecting a couple of million dollars a year turnover.

Another was to produce a custom installation and configuration of Linux to provide, remote dial-in, user authentication, firewall and subsequent routing. PC = $500, Modem = $150 and O/S = Linux.


Ok, the Linux solution was chosen, and following is some of the stuff that was needed to make it happen.

Ensure the mgetty, pppd and ipchains where installed.

Mgetty
To enable mgetty to run during the machine boot and restart if died required an entry into the file /etc/inittab, using the following line:
S0:2345:respawn:/sbin/mgetty -x 4 -s 115200 /dev/ttyS0

a breakdown of the above:
S0 = must be a unique entry in the inittab file, in this case S0 was from ttyS0
2345 = the run levels that mgetty will be run in
respawn = if the process dies, restart it
/sbin/mgetty = was the mgetty process itself
-x 4 = was the mgetty 'debug' level used
-s 115200 = was the mgetty port speed to use
/dev/ttyS0 = was the device or port mgetty should monitor for incoming calls

Now onto the mgetty configuration files, which where located in /etc/mgetty+sendfax/ directory and ALL should have the file permissions of 600, or -rw------- if they don't they will not work.

mgetty.config
required very little in the end, other than three handy little entries "init-chat", "issue-file" and "login-prompt".

for example:

init-chat "" ATZ OK AT&FE0V1S0=0&C1&D2+MR=2;+DR=1;+ER=1;W2 OK
issue-file /etc/mgetty+sendfax/mgissue
login-prompt \C\n

There was some explanation for these in 'man mgetty' and 'info mgetty', but here is a little more explantion though:

"init-chat" is used to send specific initialization sequences to the modem and requires RESPONSE COMMAND RESPONSE and can be followed with more COMMAND RESPONSE sequences. A tip for finding the optimum sequence is to look in the Windows installation files that often come with new modems for a "something.inf" file. It is normally a text file that contains among many things an Initialization String. Following is an example from a D-Link DFM-560E+ modem, whose INF file on the accompanying CD was named "dlink.inf":

[Basic_Commands]
;------------root---------------
HKR,,ConfigDialog, ,modemui.dll
HKR,,DevLoader, ,*vcomm
HKR,,EnumPropPages, ,"modemui.dll,EnumPropPages"
HKR,,FriendlyDriver, ,Unimodem.VXD
HKR,,InactivityScale, 1, 0a,00,00,00
HKR,,PortSubClass, 1,02
HKR, Init, 1,, "ATZ<cr>"
HKR, Init, 2,, "AT&FE0V1S0=0&C1&D2+MR=2;+DR=1;+ER=1;W2<cr>"    
HKR, Monitor, 1,, "ATS0=0<cr>"
HKR, Monitor, 2,, "None"
HKR, Hangup, 1,, "ATH<cr>"
HKR, Answer, 1,, "ATA<cr>"
HKR,, Reset, , "ATZ<cr>"

The important lines are "HRK, Init, 1" and "HKR, Init 2", put these two strings in the init-chat line and it does make a difference to initialize the modem as per the manufactures specifications.

A couple more in the same INF file were:

;---------------------settings-------------------
HKR, Settings, Blind_Off, , "X4"
HKR, Settings, Blind_On, , "X3"
HKR, Settings, CallSetupFailTimer, , "S7=<#>"
HKR, Settings, Compression_Off, , "+DS=0;"
HKR, Settings, Compression_On, , "+DS=3;"
HKR, Settings, DialPrefix, , "D"
HKR, Settings, DialSuffix, , ";"
HKR, Settings, ErrorControl_Off, , "+ES=1,0,1;"
HKR, Settings, ErrorControl_On, , "+ES=3,0,2;"
HKR, Settings, ErrorControl_Forced, , "+ES=3,2,4;" 

However just using the modems init settings in the INF file will be the most effective:

init-chat "" ATZ OK AT&FV1S0=0&C1&D2+MR=2;+DR=1;+ER=1;W2 OK

Often it can be difficult to know if you have the correct driver or inf file for a modem, but there is a way. Connect to the modem using HyperTerminal or similar terminal program and enter the modem AT command ATI6, the response should be an indication of the chipset used inside. Try a search on the Net using the data string from the ATI6 command, and it generally returns good results. It is surprising how many of those little plastic boxes have the same chipsets inside.

 

"issue-file" this can point to a file that contains any message to users attempting a terminal logon connection without starting the PPP autologon. To centralize mgetty's configuration files, this one was placed in the /etc/mgetty+sendfax/ directory. Make sure the file permissions are 600 or "-rw-------" otherwise mgetty will ignor it. Must be root only read / write.

In this case the file mgissue contained, for example:

########################################
# This is a private network,           #
# un-authorized access is prohibited   #
# and punishable by Law.               #
########################################

Each line being 40 characters long, this will then fit nicely into Window's Modem terminal window.

"login-prompt" is the login prompt to present to any users attempting a terminal logon connection without starting the PPP autologon. The easiest way to test or see the last two is using a Window's box, in the Modem Properites, Options and place a tick in the "Bring up terminal window after dialing" box. Then use this modem to dial into your Linux box.

Playing around with the "issue-file" and "login-prompt" can be used to hide the fact that it is a humble Linux box keeping them out. This installation displays a message that they were attempting to access a Private Network and Unauthorized Access was Prohibited and punishable by Law. Basically, be warned.

login.config
This is where the PPP call is configured. After mgetty answers the incoming call and decides what to do with it, we want it to pass the call onto the PPP daemon. There are two choices for the PPP configuration, one is to place it in the PPP configuration files the other to place it in the mgetty's "login.config" file's PPP command line call. In this situation it is requiring very specific incoming connection configurations that if placed in the PPP configurations files would conflict with an outbound PPP connection. The following line being added to mgetty's "login.config" file:

/AutoPPP/ - a_ppp /usr/sbin/pppd -chap +pap 10.4.4.230:10.4.4.20 login auth debug proxyarp

-chap +pap = pap is the method used for the making the ppp connectivity

10.4.4.230:10.4.4.20 = the Local and Remote IP addresses that will be allocated during the connection. These are very different from those used inside the Private Network, which would be in the range 192.168.1.x

login auth = this installation is using the Local Linux user accounts to perform the username / password authentication against. Before that occurs the username has to also be found in PPP pap-secrects configuration file, more on that later.

another line in mgetty's login.config file not documented very often, is to change the last line from:
* - - /bin/login @

to the following:
* - - /bin/false

This stops dead any logons that are not strickly "AutoPPP". If the "issue-file" and "login-prompt" are not implented as described earlier, test method will produce a logon prompt, however after the username is entered the call is disconnected.

Just before moving on from mgetty, just one small point is the correct configuration of Logrotate's mgetty entry, if not done will comsume your new installation in a couple of days. The entry is located in the file "/etc/logrotated.d/mgetty" and the line should be corrected to be as follows:

/var/log/mgetty.log.ttyS0 {

Might not look much different, but, if it is left as "tty*", then on every rotation of the log files it rototates the rotated files, have seen a machine that had more than 200,000 of the little devils, instead of only 6.

 

PPP
Now onto ppp configuration, that in this installation, are found in the "/etc/ppp/" directory.

The generic installation of this verison of Linux has IP_FORWARDing turned OFF, which is a good, until you need it to forward selective packets based on Firewall rules. A test can easily be done and also turned on forwarding by the contents of:
/proc/sys/net/ipv4/ip_forward

A "0" = no forwarding and a "1" is do forwarding. So the following will read the contents:
cat /proc/sys/net/ipv4/ip_forward

and to turn it on, or off for that matter, just write a 1 or 0 to same file:
/bin/echo "1" > /proc/sys/net/ipv4/ip_forward
/bin/echo "0" > /proc/sys/net/ipv4/ip_forward

Why do you need to know this, well, after PPP has made an IP connnection, IP Forwarding needs to be selectively turned on, and off at completion of call. Also you do not, or may not want IP Forwarding turn on for any other connections. There is a way to do this, by placing a small test script in the PPP "ip-up.local" and "ip-down.local" script files.

ip-up.local
Following is an example of the script added to the ip-up.local file:

#!/bin/bash


LOC_IP=$4
REM_IP=$5
    
if ( [ "$LOC_IP" == 10.4.4.230 ] && [ "$REM_IP" == 10.4.4.20 ] ); then
	/bin/echo "1" > /proc/sys/net/ipv4/ip_forward;
else
	/bin/echo "0" > /proc/sys/net/ipv4/ip_forward;
fi
    
exit 0

When PPP calls the "ip-up.local" script it passes five parameters, among them are the Local and Remote IP Addresses used in the PPP connnection, being $4 = Local and $5 = Remote. A simple test that the current call of the scipt is for the specific remote dial-in connect, then enable IP_FORWARD-ing, all others "else" then disable IP_FORWARD-ing.

ip-down.local
The ip-down.local is a similar script, in this case is simply has only one line and that is to disable IP_FORWARD-ing:

#!/bin/bash
    
/bin/echo "0" > /proc/sys/net/ipv4/ip_forward
    
exit 0

pap-secrets
This file contains all the usernames used in making any PPP connections that use PAP in their authentication, there is also a complentary "chap-secrets" file that contains then same, this implementation only PAP was used. Red Hat has it's own section in this file which is possibly sectioned off with a note that "redhat-config-network will overwrite". Best to create own section for the perpose of this dial-in, as follows:

###### remote dial-in login (begin) ######
"remote"	*	""	*
###### remote dial-in login (end) ######

each of the four parameters should be separated by a TAB!

First is the Remote username or client name, in this case = remote.

Second is an * that is the Server which call is made from, just lazy putting an * really.

Third is "", that in some cases would contain the password or secret in plain text for all to see. Making the entry blank ensures that the authentication is passed straight on to the system, making a match with an account username and password.

And forth is the IP Address, in this case an *.

An example may have the following, if there are three dial-in user accounts for Fred, Mary and Joe;

###### remote dial-in login (begin) ######
"fred"	*	""	*
"mary"	*	""	*
"joe"	*	""	*
###### remote dial-in login (end) ######

It should also protect the root account, and any others for that matter, from being exposed to the dial-in process.

hosts.deny and hosts.allow
These are two other files that need a little attention. The file hosts.deny should have one and one only entry of:

ALL: ALL

The file hosts.allow will need a couple of entries, depending on where the machine will allowed to be accessed from. In this installation it had two entries:

ALL: 127.0.0.1
ALL: 192.168.1.

these allowing access from 127.0.0.1 = localhost and from other machines on the Internal Network, i.e. anything with an IP Address starting with 192.168.1.

Notice there is no entry for the External Network 10.4.4.x, this stops any connections by Telnet, FTP, SSH or any other service for that matter, being made from the External Network.

 

Firewall Configuration
Ok, I cheated a little on this one and just used the KDE Firewall Configuration GUI to manipulate the "ipchains" configuration. It did not mean any corners were cut, just made getting the formatting and syntax of the rules file right the first time, especially as it was mainly a set and forget configuration. Deny all and only allow Accept packets for remote access software on a selected tcp/ip port.

 

Files to monitor during testing
A couple of good files to monitor or "tail" during testing is "/var/log/mgetty.log.ttyS0", "/var/log/messages" and "/var/log/secure". During testing it proved very helpful to setup two terminal sessions, one with a "tail -f /var/log/mgetty.log.ttyS0" and the other with "tail -f /var/log/messages". Between these couple of files will provide a reseasonable amount of information for diagnosing incoming call problems.

 

Following is a diagram of the said installation:

Allowing connectivity to Exising PCs by the Remote PC
Ok, it seem to be all working, the Remote PC dials in, connects and authenticates with the RAS, and is allocated an the IP address 10.4.4.20, but the Remote PC appears to not be able to connect to any of the Existing PCs. The problem is the Existing PC do not know how to reply to even a simple ping from the Remote PC. To enable this to occur, any Existing PC that needs to provide Remote PC access, needs a "route" added to its routing table that is the network path or gateway back to the Remote PC.

So if the Existing PC's IP Address is 10.4.4.20 and the RAS's IP Address is 192.168.1.200, the RAS within the Existing Network is acting as a "gateway", so for Windows based machines the following "route" needs to be added. Using a windows "command prompt" enter the following command:

route add remote_pc_ip_address mask 255.255.255.255 gateway
route add 10.4.4.20 mask 255.255.255.255 192.168.1.200

or a network route

route add 10.4.4.0 mask 255.255.255.0 192.168.1.200

To make the route persistant across reboots of the Existing PC, add "-p"

route -p add 10.4.4.20 mask 255.255.255.255 192.168.1.200

The requirement to add the route to an Existing PC, does add another small level of security, and may be added and removed from then Existing PCs at anytime.

Also, versions of Windows, like WinXP, also have a Firewall, which will require some configuration to allow remote File access by the RAS/Remote PC.

So to test it all. After the Remote PC has dialed in and connected, setup a continuous ping on the Remote PC to one of the Existing PCs, which should fail at first. Then add the route to that same Existing PC, and the pings should start to be returned!

Backup The Configuration Files
Now you have it all working. Last thing is to ensure the files you set-up and modified are all backed up, so in the event the RAS crashes, it can all be easily recovered!

The following will need to be backed up when ever changes are made;

/etc/mgetty+sendfax/ (whole directory)
/etc/ppp/ (whole directory)
/etc/logrotated.d/mgetty

The following should be backed up daily;

/var/log/mgetty.log.ttyS0
/var/log/messages
/var/log/secure 

Another Method
Another variation on this could be, after the PPP session has been established, is to allow an SSH connection between the Remote PC and the Linux RAS, then setup an ssh tunnel through the SSH connection, then make the remote connections from the Remote PC to the PC on the internal network via the ssh tunnel.

A couple of advantages is that IP Forwarding is not needed and the PC's on the Internal Network do not need routes to the External Network. The PC's only see the connection as originating from the Linux RAS box. External and Internal network traffic stay on their respective networks, there is no forwarding.

Downside is that once the SSH connection has been made, a remote terminal session has been established. Also, it requires additional software on the Remote PC, a Windows SSH Client for a start, PuTTY being one of them.

It is however possible to setup SSH using authentication-keys that can all bar stop non-authentic connections being made, only allowing connections by hosts that have a public-key installed on the Linux RAS box. This does require considerable more work to setup and use. To automate the connection process for our client, it also required a couple more pieces of software to work along with PuTTY.

Putty is an excellent SSH Client and is available via:
www.chiark.greenend.org.uk/~sgtatham/putty/
also at this site is good documentation for setting up SSH Authentication Keys and SSH Tunnels.

The upside of using SSH, SSH Authentication Keys and SSH Tunnels, is that establishment of the connection and subsequent data over the connection has 1024 character encryption (1024 x 8 = 8192 bit encryption), to that into perspective, most internet banking uses 128 bit encryption. Another way of putting it is, that unlike just going to a door and supplying a username and password, which is still done to establish the PPP connection, to actually transfer any data over the connection, you have to go to the door with one half of the key, the other half of the key is on the other side of the door, unless both keys interlock with each other, the lock to the door can not be opened.

Another change required is to the /etc/hosts.allow file, need to add ssh access via the dial-in IP Addresses, add:

sshd: 10.4.4.

It is also possible to be more specific and only allow connections via the actual IP Address that we assigned to the remote dial-in, 10.4.4.20

And turn off or remove the IP Forwarding script from the /etc/ppp/ip-up.local file.

If you find IP Forwarding is still happening, you may like to check the following files that may be setting it on during boot time:

/etc/sysconfig/network
FORWARD_IPV4 = YES
/etc/sysctl.conf
net.ipv4.ip_forward = 1

It could also have been added into one of the following locations:

/etc/rc.d/rc.local
/etc/rc.d/rc.firewall

 

When setup and working it is necessary to edit the sshd configuration file on the host, the Linux RAS, and to not allow SSH password logons, which leaves access only via SSH Authentication Keys, edit the /etc/ssh/sshd_config file and the line:

PasswordAuthentication no

You may find this line was actually commented out at first, un-comment it and change the "yes" to a "no".

This method also allows for some remote administration, via ssh, via keys authentication.

Through the ssh tunnel it is possible to remotely connect the PC's on the Internal Network via remote access software like VNC, by making a call to the Localhost socket of the ssh tunnel.

I don't want to go into great detail about setting up using SSH Tunnel, as there is good documention that comes with Putty. But, if for example, if you now want to VNC from your remote PC to one of the Existing PC's:

Most non IT people and especially those doing their best to run a small business get a little nervous when people come along wanting to install additional software and get a very bad case of the jitters when you propose to alter their PC's network configuration. Fact is, the job does require the addition of some remote access software, but this method does avoid any changes to the Internal Network, in fact all that occurs is the addition of one extra node on the network, the Linux RAS. It also makes the Firewall a little simpler because traffic is not going or being forward any where, everything stops at the Linux RAS.

There are numerous other parameters in the /etc/ssh/sshd_config file that can be played with, for example:

AllowUsers - can contain a list of usernames that are allowed to go through ssh authentication be it by password or keys.

 

Following is a rough diagram of the above change.

Thanks to Luciano Codonesu testing and minor corrections.

terbut@sprint.net.au

Updated: 02-Jun-2007
index