Tuesday, December 23, 2008

Setting-up Basic PPPoE Server in Linux (x86_64 Platform)

Setting-up a basic PPPoE server in Linux seems to be
just another server setup task which amounts to just installing
package and then configuring some scripts and you're done.
The fact is, it's probably one of the most mundane server setup task
of your life if you're not careful.



Let's start with the terms itself PPPoE stands for
Point-to-Point Protocol over Ethernet. Which means a point-to-point
connection is made over ethernet. In reality, the physical and logical
connection is not just a simple point-to-point connection but
it usually transform to multipoint-to-point connection or
multipoint-to-multipoint connection. Depending on the "server(s)"
configuration implementation. The PPPoE connection becomes multipoint-to-point
connection because usually the "server" is only one, but the "client(s)" which
connects to it is more than one and it could become multipoint-to-multipoint
when the server itself is load-balanced to more than one machine.
It's important to note that PPPoE actually doesn't recognize the notion
of client and server because PPP is a peer-to-peer protocol.
However, most people and most PPPoE software refers to
the machine dialed-into as the server and the machine
which dial as the client.



In this article I will focus on a simple PPPoE server setup which
will be used to to test very simple point-to-point connection. The point
is the server is needed to test a new pppoe client implementation and
I need to have a well-tested PPPoE server. This article dwells on how I made
the PPPoE server works as intended.




1 System Configuration



In this section, I explain the configuration I used to setup and test the
PPPoE server.

1.1 Hardware Configuration



The following is the connectivity diagram of the systems I used as the testbed.


+-------------------+
+--------------| WLAN Access Point |
| +-------------------+
|
(ethernet cabling)
|
+------+----+------------+
| | eth0 |
| +-----------------+
| |
| PPPoE "server" machine |
| |
| +-----------------+
| | eth1 (PPPoE) |
+------+----+------------+
|
|
| +------+-----------------+
| | | wlan0 |
(ethernet cabling) | +-----------------+
| | |
| | PPPoE "client" machine |
| | |
| +---------------+ |
+--------------+ eth0 (PPPoE) | |
+---------------+--------+


In the diagram above, the PPPoE connection starts from the eth0 interface in
the PPPoE client machine and goes through the ethernet cabling and terminated
at the eth1 interface in the PPPoE server machine. The wireless connection
shown in the diagram is a normal wireless TCP/IP connection
I used to connect to the PPPoE server and to configure the PPPoE server.




1.2 Software Configuration



The software configuration for PPPoE is a bit complicated.
Please, follow through the explanation below very carefully.



These are the software that I used:


  • Operating System: Slamd64 Linux (x86_64 architecture) version 12.1.
    with custom compiled linux kernel based on kernel version 2.6.25.17 source code.
    These are the kernel compilation parameter that I modify to support kernel mode
    PPPoE:

    CONFIG_PPP=m
    CONFIG_PPP_ASYNC=m
    CONFIG_PPP_SYNC_TTY=m
    CONFIG_PPP_DEFLATE=m
    CONFIG_PPP_BSDCOMP=m
    CONFIG_PPPOE=m
    CONFIG_N_HDLC=m
    CONFIG_UNIX98_PTYS=y

    To load the kernel modules automatically at boot, I modify the /etc/rc.d/rc.modules
    script to include the following statements:

    ## Load PPP:
    # This module is for PPP support:
    /sbin/modprobe ppp_generic
    # This PPP plugin supports PPP over serial lines:
    /sbin/modprobe ppp_async
    # Use this plugin instead for HDLC (used for high-speed leased lines like T1/E1)
    /sbin/modprobe ppp_synctty

    ## This module provides compression for PPP (optional):
    /sbin/modprobe ppp_deflate

    ## This module provides PPPoE for PPP (needed for RP-PPPoE to function):
    /sbin/modprobe pppoe

    ## This module provides N_HDLC for PPP (needed for RP-PPPoE server to function):
    /sbin/modprobe n_hdlc



  • pppd version 2.4.4 from the Slamd64 package in the Slamd64 DVD. I didn't do
    any customization to this package. It's installed with installpkg as usual.

  • rp-pppoe version 3.10. I removed the original rp-pppoe 3.8 that comes by default
    with Slamd64 12.1 because I couldn't get it to work. Note that rp-pppoe 3.8 that comes
    with Slamd64 12.1 doesn't support kernel mode PPPoE which cause all sorts of troubles
    to me. Therefore, I downloaded rp-pppoe 3.10 source code from the net and build a
    package out of it with this script (rp-pppoe.PHBuild):

    #!/bin/sh
    PKGNAM=rp-pppoe
    VERSION=3.10
    BUILD=2

    . /etc/pkghelpers
    pkghelpers_env

    rm -rf $PKG
    mkdir -p $PKG
    cd $TMP
    rm -rf rp-pppoe-$VERSION

    tar xzvf $CWD/rp-pppoe-$VERSION.tar.gz
    cd rp-pppoe-$VERSION/src
    CFLAGS=$SLKCFLAGS \
    ./configure --prefix=/usr --enable-plugin
    make -j12 || exit 1
    make install docdir=/usr/doc/rp-pppoe-$VERSION DESTDIR=$PKG install
    ( cd $PKG/etc/ppp
    for config in firewall-masq firewall-standalone pppoe-server-options pppoe.conf ; do
    mv $config ${config}.new
    done
    )
    mkdir -p $PKG/install
    zcat $CWD/doinst.sh.gz > $PKG/install/doinst.sh
    cat $CWD/slack-desc > $PKG/install/slack-desc

    cd $PKG
    pkghelpers_fixup
    pkghelpers_makepkg

    The script above is a modified script from the source code of the rp-pppoe 3.8 package
    you can find in the Slamd64 12.1 DVD (in the source directory).
    I made a slight modification to it. I changed the VERSION to 3.10 and
    added --enable-plugin as a parameter to the configure
    script. This way, rp-pppoe will be built with kernel mode PPPoE support. I have tried to recompile
    the rp-pppoe v3.8 that comes with Slamd64 12.1 with the --enable-plugin parameter passed
    to the configure script, but I just couldn't make it work
    . On the other hand,
    rp-pppoe v3.10 compilation works flawlessly with this parameter. The result of this build script
    is a file named rp-pppoe-3.10-x86_64_slamd64-2.tgz located in /tmp directory.
    The build result can be installed directly with installpkg.



The next step after the needed packages installed and the needed kernel customization complete is to
configure rp-pppoe and pppd. This can easily become an error prone process.


In this setup, the authentication used is PAP. Therefore, the following explanation is focused
for PAP-based PPPoE authentication. For CHAP and EAP* authentication please refer to other
relevant articles on the net.

Let's proceed to configure the machines one by one.

  • For the pppoe server machine, the important configuration files are:

    1. /etc/ppp/options.

      asyncmap 0
      crtscts
      lock
      modem
      proxyarp
      lcp-echo-interval 30
      lcp-echo-failure 4

      This file stores the default options used
      by pppd when it starts.


    2. /etc/ppp/pppoe-server-options.

      debug
      plugin /etc/ppp/plugins/rp-pppoe.so
      require-pap
      mtu 1492
      mru 1492
      ktune
      proxyarp
      lcp-echo-interval 10
      lcp-echo-failure 2
      nobsdcomp
      noccp
      novj
      noipx

      This file stores the parameters to be
      passed to pppd when pppoe-server starts.

      You can override this pppoe-server configuration file
      by passing the -O parameter to pppoe-server
      when you invoke pppoe-server.

      Note the:

      plugin /etc/ppp/plugins/rp-pppoe.so

      This instructs the pppoe server to load the kernel mode pppoe plugin
      when the it runs.



    3. /etc/ppp/pap-secrets

      # Secrets for authentication using PAP
      # client server secret IP addresses
      indosatm2 * prabayar *
      zuruk * weiter *

      This file stores the PAP username and password to be used for PPP authentication.

      Note:


      The * in the fourth column is mandatory if you want to be able to let
      the client authenticate itself from any IP address.
      It's also important to note that if you fail to give a *
      in the fourth column in all of the lines/entries prior to the valid client entry,
      the authentication will fail
      .
      For example, once, I forgot to give a * in the last (the fourth) column
      of the indosatm2 client entry and what happens is the client which authenticate itself
      as user zuruk (in the second line) will always fail to authenticate with an
      "LCP Conf-Request timeout" error message even if the secret is right and the allowed IP address in
      the fourth column for this entry has been set to *.
      Another way to overcome the problem is to place the user zuruk entry
      as the first entry (i.e. in the first line) in /etc/ppp/pap-secrets
      and giving a * in the fourth column of this entry.
      Therefore, eliminating the need to give a * in the fourth column of
      other entries in /etc/ppp/pap-secrets. This is the related excerpt from pppd manual page:

      ...
      If there are only 3 words on the line, or if the first word is "-", then all
      IP addresses are disallowed. To allow any address, use "*"
      ...





  • For the pppoe client machine, the important configuration files are:

    1. /etc/ppp/options

      asyncmap 0
      crtscts
      lock
      modem
      proxyarp
      lcp-echo-interval 30
      lcp-echo-failure 4

      This file stores the default options used
      by pppd when it starts.


    2. /etc/ppp/pppoe.conf

      ETH=eth1
      USER=zuruk
      DEMAND=no
      DNSTYPE=SERVER
      PEERDNS=yes
      DNS1=
      DNS2=
      DEFAULTROUTE=yes
      CONNECT_TIMEOUT=30
      CONNECT_POLL=2
      ACNAME=
      SERVICENAME=
      PING="."
      CF_BASE=`basename $CONFIG`
      PIDFILE="/var/run/$CF_BASE-pppoe.pid"
      SYNCHRONOUS=no
      CLAMPMSS=1412
      LCP_INTERVAL=20
      LCP_FAILURE=3
      PPPOE_TIMEOUT=80
      FIREWALL=NONE
      LINUX_PLUGIN=/etc/ppp/plugins/rp-pppoe.so
      PPPOE_EXTRA=""
      PPPD_EXTRA=""

      This file stores the default configuration for the pppoe client scripts.
      It's parsed by pppoe-start, pppoe-stop and other pppoe client scripts
      when they run. Note the:

      LINUX_PLUGIN=/etc/ppp/plugins/rp-pppoe.so

      This instructs the pppoe client scripts to load the kernel mode pppoe plugin
      when the script runs.

    3. /etc/ppp/pap-secrets

      # Secrets for authentication using PAP
      # client server secret IP addresses
      zuruk * weiter *

      This file stores the PAP username and password to be used for PPP authentication.





It is important to remember to add the option to load the kernel mode pppoe plugin to
both the pppoe-server and client configuration files. Otherwise the kernel mode pppoe plugin
wouldn't be loaded and the PPPoE connection cannot established.



2 Running The PPPoE Server and Client




2.1 Configuring The Ethernet Interfaces



The ethernet should be without any IP address but it should be up.
You can do that with the following command.


root@opusera:~# ifconfig eth1 down
root@opusera:~# ifconfig eth1 0.0.0.0
root@opusera:~# ifconfig eth1 up

or in Slamd64 you can comment-out the IP setting in /etc/rc.d/rc.inet1.conf
like so:

# Config information for eth1:
#IPADDR[1]="192.168.2.1"
#NETMASK[1]="255.255.255.0"
#USE_DHCP[1]=""
#DHCP_HOSTNAME[1]=""
# Config information for eth1 (for PPPoE experiments) :
USE_DHCP[1]=""
DHCP_HOSTNAME[1]=""

The /etc/rc.d/rc.inet1.conf above will make the interface remains down
after boot completed and will prevent the system from assigning an IP address to
the interface. Therefore, if you modify /etc/rc.d/rc.inet1.conf as shown
above, you have to bring the interface up manually before running any pppoe application(s)
with:

root@opusera:~# ifconfig eth1 up

because the interface is still inactive after boot.



2.2 Running The PPPoE Server and Client Application



To execute the pppoe-client application, invoke the pppoe-start script
and pass the ethernet interface name as the first parameter and the username you wish
to use as the second parameter. For example:


root@opusera:~# pppoe-start eth1 zuruk
.. Connected!

In the pppoe-start invocation above, "eth1" is the ethernet interface to be used for PPPoE and
"zuruk" is the username.



You can run the pppoe-server application with the following command.


root@opunaga:darmawan # pppoe-server -k -I eth0 -F

The -k parameter is mandatory because we want to use the kernel mode pppoe plugin.
The -I eth0 parameter is used to inform pppoe-server to use eth0 as the interface
for PPPoE connection.
The -F parameter instructs pppoe-server to stay in the foreground because in normal
pppoe-server invocation (without -F), it will proceed to run as background process.



3 How to Debug and Fix Connectivity Problems



It's quite hard to get PPPoE connectivity works in the first try in the current state
of PPPoE support in Linux. Therefore, debugging the connectivity problem is important.
There are two application that can help debugging a lot, i.e. tcpdump and
the syslog facility. In Slamd64, the syslog facility can be used with the following command:


root@opunaga:~ # tail -f /var/log/messages



Now, let me start with the scenario of the failed authentication that made me lack of sleep.
In this scenario, the /etc/ppp/pap-secrets file in the machine that I use
as the pppoe-server is wrong. This is the contents of the file:


# Secrets for authentication using PAP
# client server secret IP addresses
indosatm2 * prabayar
zuruk * weiter *

From section 1.2, it's clear that the user "zuruk" must be placed as the first entry or
the "indosatm2" user should be given a * in the IP addresses column. But, this is not the
case, it will cause an "LCP Conf-Request timeout" as you will see shortly.



Now, let's see what tcpdump shows in the pppoe-server machine.


root@opunaga:darmawan # tcpdump -i eth0 -X
tcpdump: WARNING: eth0: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
18:33:08.234708 PPPoE [ses 0x1] LCP, Conf-Request (0x01), id 1, length 16
0x0000: 1100 0001 0010 c021 0101 000e 0104 05d4 .......!........
0x0010: 0506 015e 111e 0000 0000 0000 0000 0000 ...^............
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:33:11.235647 PPPoE [ses 0x1] LCP, Conf-Request (0x01), id 1, length 16
0x0000: 1100 0001 0010 c021 0101 000e 0104 05d4 .......!........
0x0010: 0506 015e 111e 0000 0000 0000 0000 0000 ...^............
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:33:14.236627 PPPoE [ses 0x1] LCP, Conf-Request (0x01), id 1, length 16
0x0000: 1100 0001 0010 c021 0101 000e 0104 05d4 .......!........
0x0010: 0506 015e 111e 0000 0000 0000 0000 0000 ...^............
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:33:17.237613 PPPoE [ses 0x1] LCP, Conf-Request (0x01), id 1, length 16
0x0000: 1100 0001 0010 c021 0101 000e 0104 05d4 .......!........
0x0010: 0506 015e 111e 0000 0000 0000 0000 0000 ...^............
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:33:20.238598 PPPoE [ses 0x1] LCP, Conf-Request (0x01), id 1, length 16
0x0000: 1100 0001 0010 c021 0101 000e 0104 05d4 .......!........
0x0010: 0506 015e 111e 0000 0000 0000 0000 0000 ...^............
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:33:23.239584 PPPoE [ses 0x1] LCP, Conf-Request (0x01), id 1, length 16
0x0000: 1100 0001 0010 c021 0101 000e 0104 05d4 .......!........
0x0010: 0506 015e 111e 0000 0000 0000 0000 0000 ...^............
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:33:26.240570 PPPoE [ses 0x1] LCP, Conf-Request (0x01), id 1, length 16
0x0000: 1100 0001 0010 c021 0101 000e 0104 05d4 .......!........
0x0010: 0506 015e 111e 0000 0000 0000 0000 0000 ...^............
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............

and let's proceed to see what is logged by the syslog.

root@opunaga:darmawan # tail -f /var/log/messages
Dec 23 18:32:59 opunaga pppoe-server[3380]: Session 1 created for client 00:0a:eb:28:62:57 (10.67.15.1) on eth0 using Service-Name ''
Dec 23 18:32:59 opunaga pppd[3380]: Plugin /etc/ppp/plugins/rp-pppoe.so loaded.
Dec 23 18:32:59 opunaga pppd[3380]: RP-PPPoE plugin version 3.10 compiled against pppd 2.4.4
Dec 23 18:32:59 opunaga pppd[3380]: Plugin /etc/ppp/plugins/rp-pppoe.so loaded.
Dec 23 18:32:59 opunaga pppd[3380]: RP-PPPoE plugin version 3.10 compiled against pppd 2.4.4
Dec 23 18:33:07 opunaga kernel: device eth0 entered promiscuous mode
Dec 23 18:33:42 opunaga kernel: device eth0 left promiscuous mode

As you can see, syslog shows nothing wrong with the pppoe-server because the kernel mode pppoe plugin
is loaded just fine, as expected. However, tcpdump shows there are "LCP Conf-Request"s which are not
serviced as they should, causing a timeout in the pppoe-client machine as shown below.

root@opusera:~# pppoe-start eth1 zuruk
................TIMED OUT
/usr/sbin/pppoe-start: line 193: 2851 Terminated $CONNECT "$@" >/dev/null 2>&1


Then, let me fix the PAP authentication file and let's see what tcpdump and syslog shows.
The fixed /etc/ppp/pap-secrets file is:


# Secrets for authentication using PAP
# client server secret IP addresses
zuruk * weiter *
indosatm2 * prabayar

In the fixed pap-secrets, user "zuruk" has been moved to the top-most place, i.e.
as the first entry. Now, run the pppoe-server:

root@opunaga:darmawan # pppoe-server -k -I eth0 -F

then, run the pppoe client in the client machine:

root@opusera:~# pppoe-start eth1 zuruk
.. Connected!

meanwhile, also invoke tcpdump:

root@opunaga:darmawan # tcpdump -i eth0 -X
tcpdump: WARNING: eth0: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
18:53:23.303249 PPPoE PADI [Service-Name] [Host-Uniq 0x7B0C0000]
0x0000: 1109 0000 000c 0101 0000 0103 0004 7b0c ..............{.
0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:23.303537 PPPoE PADO [AC-Name "opunaga"] [Service-Name] [AC-Cookie 0xECAA58162AC4B0B4F35E25BD7A7C07002B0E0000] [Host-Uniq 0x7B0C0000]
0x0000: 1107 0000 002f 0102 0007 6f70 756e 6167 ...../....opunag
0x0010: 6101 0100 0001 0400 14ec aa58 162a c4b0 a..........X.*..
0x0020: b4f3 5e25 bd7a 7c07 002b 0e00 0001 0300 ..^%.z|..+......
0x0030: 047b 0c00 00 .{...
18:53:23.303618 PPPoE PADR [Service-Name] [Host-Uniq 0x7B0C0000] [AC-Cookie 0xECAA58162AC4B0B4F35E25BD7A7C07002B0E0000]
0x0000: 1119 0000 0024 0101 0000 0103 0004 7b0c .....$........{.
0x0010: 0000 0104 0014 ecaa 5816 2ac4 b0b4 f35e ........X.*....^
0x0020: 25bd 7a7c 0700 2b0e 0000 0000 0000 %.z|..+.......
18:53:23.304159 PPPoE PADS [ses 0x1] [Service-Name] [Host-Uniq 0x7B0C0000]
0x0000: 1165 0001 000c 0101 0000 0103 0004 7b0c .e............{.
0x0010: 0000 ..
18:53:23.305978 PPPoE [ses 0x1] LCP, Conf-Request (0x01), id 1, length 16
0x0000: 1100 0001 0010 c021 0101 000e 0104 05d4 .......!........
0x0010: 0506 a9d3 c102 0000 0000 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:23.316172 PPPoE [ses 0x1] LCP, Conf-Request (0x01), id 1, length 20
0x0000: 1100 0001 0014 c021 0101 0012 0104 05d4 .......!........
0x0010: 0304 c023 0506 ac24 3a51 ...#...$:Q
18:53:23.316274 PPPoE [ses 0x1] LCP, Conf-Ack (0x02), id 1, length 20
0x0000: 1100 0001 0014 c021 0201 0012 0104 05d4 .......!........
0x0010: 0304 c023 0506 ac24 3a51 0000 0000 0000 ...#...$:Q......
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:26.307176 PPPoE [ses 0x1] LCP, Conf-Request (0x01), id 1, length 16
0x0000: 1100 0001 0010 c021 0101 000e 0104 05d4 .......!........
0x0010: 0506 a9d3 c102 0000 0000 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:26.307547 PPPoE [ses 0x1] LCP, Conf-Ack (0x02), id 1, length 16
0x0000: 1100 0001 0010 c021 0201 000e 0104 05d4 .......!........
0x0010: 0506 a9d3 c102 ......
18:53:26.307649 PPPoE [ses 0x1] LCP, Echo-Request (0x09), id 0, length 10
0x0000: 1100 0001 000a c021 0900 0008 a9d3 c102 .......!........
0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:26.307687 PPPoE [ses 0x1] LCP, Echo-Request (0x09), id 0, length 10
0x0000: 1100 0001 000a c021 0900 0008 ac24 3a51 .......!.....$:Q
18:53:26.307714 PPPoE [ses 0x1] PAP, Auth-Req (0x01), id 1, Peer zuruk, Name weiter
0x0000: 1100 0001 0013 c023 0101 0011 057a 7572 .......#.....zur
0x0010: 756b 0677 6569 7465 7200 0000 0000 0000 uk.weiter.......
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:26.307754 PPPoE [ses 0x1] LCP, Echo-Reply (0x0a), id 0, length 10
0x0000: 1100 0001 000a c021 0a00 0008 a9d3 c102 .......!........
0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:26.307842 PPPoE [ses 0x1] LCP, Echo-Reply (0x0a), id 0, length 10
0x0000: 1100 0001 000a c021 0a00 0008 ac24 3a51 .......!.....$:Q
18:53:26.308055 PPPoE [ses 0x1] PAP, Auth-ACK (0x02), id 1, Msg Login ok
0x0000: 1100 0001 000f c023 0201 000d 084c 6f67 .......#.....Log
0x0010: 696e 206f 6b in.ok
18:53:26.308211 PPPoE [ses 0x1] IPCP, Conf-Request (0x01), id 1, length 24
0x0000: 1100 0001 0018 8021 0101 0016 0306 0000 .......!........
0x0010: 0000 8106 0000 0000 8306 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:26.308333 PPPoE [ses 0x1] IPCP, Conf-Request (0x01), id 1, length 12
0x0000: 1100 0001 000c 8021 0101 000a 0306 0a00 .......!........
0x0010: 0001 ..
18:53:26.308402 PPPoE [ses 0x1] IPCP, Conf-Ack (0x02), id 1, length 12
0x0000: 1100 0001 000c 8021 0201 000a 0306 0a00 .......!........
0x0010: 0001 0000 0000 0000 0000 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:26.309598 PPPoE [ses 0x1] IPCP, Conf-Reject (0x04), id 1, length 18
0x0000: 1100 0001 0012 8021 0401 0010 8106 0000 .......!........
0x0010: 0000 8306 0000 0000 ........
18:53:26.309667 PPPoE [ses 0x1] IPCP, Conf-Request (0x01), id 2, length 12
0x0000: 1100 0001 000c 8021 0102 000a 0306 0000 .......!........
0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:26.309766 PPPoE [ses 0x1] IPCP, Conf-Nack (0x03), id 2, length 12
0x0000: 1100 0001 000c 8021 0302 000a 0306 0a43 .......!.......C
0x0010: 0f01 ..
18:53:26.309829 PPPoE [ses 0x1] IPCP, Conf-Request (0x01), id 3, length 12
0x0000: 1100 0001 000c 8021 0103 000a 0306 0a43 .......!.......C
0x0010: 0f01 0000 0000 0000 0000 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:26.310369 PPPoE [ses 0x1] IPCP, Conf-Ack (0x02), id 3, length 12
0x0000: 1100 0001 000c 8021 0203 000a 0306 0a43 .......!.......C
0x0010: 0f01 ..
18:53:36.308498 PPPoE [ses 0x1] LCP, Echo-Request (0x09), id 1, length 10
0x0000: 1100 0001 000a c021 0901 0008 ac24 3a51 .......!.....$:Q
18:53:36.308594 PPPoE [ses 0x1] LCP, Echo-Reply (0x0a), id 1, length 10
0x0000: 1100 0001 000a c021 0a01 0008 a9d3 c102 .......!........
0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:46.307816 PPPoE [ses 0x1] LCP, Echo-Request (0x09), id 1, length 10
0x0000: 1100 0001 000a c021 0901 0008 a9d3 c102 .......!........
0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:46.308018 PPPoE [ses 0x1] LCP, Echo-Reply (0x0a), id 1, length 10
0x0000: 1100 0001 000a c021 0a01 0008 ac24 3a51 .......!.....$:Q
18:53:46.309479 PPPoE [ses 0x1] LCP, Echo-Request (0x09), id 2, length 10
0x0000: 1100 0001 000a c021 0902 0008 ac24 3a51 .......!.....$:Q
18:53:46.309553 PPPoE [ses 0x1] LCP, Echo-Reply (0x0a), id 2, length 10
0x0000: 1100 0001 000a c021 0a02 0008 a9d3 c102 .......!........
0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............
18:53:56.309515 PPPoE [ses 0x1] LCP, Echo-Request (0x09), id 3, length 10
0x0000: 1100 0001 000a c021 0903 0008 ac24 3a51 .......!.....$:Q
18:53:56.309598 PPPoE [ses 0x1] LCP, Echo-Reply (0x0a), id 3, length 10
0x0000: 1100 0001 000a c021 0a03 0008 a9d3 c102 .......!........
0x0010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0x0020: 0000 0000 0000 0000 0000 0000 0000 ..............

and also invoke syslog utility:

root@opunaga:darmawan # tail -f /var/log/messages
Dec 23 18:53:23 opunaga pppoe-server[3628]: Session 1 created for client 00:0a:eb:28:62:57 (10.67.15.1) on eth0 using Service-Name ''
Dec 23 18:53:23 opunaga pppd[3628]: Plugin /etc/ppp/plugins/rp-pppoe.so loaded.
Dec 23 18:53:23 opunaga pppd[3628]: RP-PPPoE plugin version 3.10 compiled against pppd 2.4.4
Dec 23 18:53:23 opunaga pppd[3628]: Plugin /etc/ppp/plugins/rp-pppoe.so loaded.
Dec 23 18:53:23 opunaga pppd[3628]: RP-PPPoE plugin version 3.10 compiled against pppd 2.4.4
Dec 23 18:53:23 opunaga pppd[3628]: pppd 2.4.4 started by root, uid 0
Dec 23 18:53:23 opunaga pppd[3628]: Using interface ppp0
Dec 23 18:53:23 opunaga pppd[3628]: Connect: ppp0 <--> eth0
Dec 23 18:53:26 opunaga pppd[3628]: PAP peer authentication succeeded for zuruk
Dec 23 18:53:26 opunaga pppd[3628]: peer from calling number 00:0A:EB:28:62:57 authorized
Dec 23 18:53:26 opunaga pppd[3628]: local IP address 10.0.0.1
Dec 23 18:53:26 opunaga pppd[3628]: remote IP address 10.67.15.1
Dec 23 18:53:56 opunaga kernel: device eth0 left promiscuous mode

As you can see clearly, the "LCP Conf-Request" packets are replied with the right
"LCP Conf-Ack" packets in the tcpdump output and the PPPoE configuration sequence proceed to IP
setup stage. In the syslog output, you can see the ppp0 interface created
and given the appropriate IP addresses. This means the PPPoE connection has been created
successfully.




Note:


The "LCP Conf-Request" timeout symptoms are not particularly related to wrong
ppp secrets file (either /etc/ppp/pap-secrets or /etc/ppp/chap-secrets).
It can be also related to erratic user mode rp-pppoe plugin as described in numerous
mailing lists, bug reports and forums on the net. The particular case that
I describe in this article happens after I tried the "supposedly" working
kernel mode pppoe plugin. I found that the kernel mode plugin indeed works after
finding out my mistake in the /etc/ppp/pap-secrets configuration.
You have to be aware of these issues in order not to repeat the same mistake.


X. Closing



Greetz go to Armin van Buuren for the great composition which
made the debugging much less painful in the last 48 hours.

Thursday, December 11, 2008

Nokia E61 Bluetooth 3G/GPRS Connection With PPPD in Linux

Using pppd to connect using bluetooth 3G/GPRS in Linux is quite a challenge for
ordinary Linux user. In this post, I explain how I got it working on my system.




This is my system configuration:


  • OS: Slamd64 12.1. An x86_64 Unofficial Port of Slackware Linux Distribution
    with kernel 2.6.25.17 and pppd version 2.4.4


  • A Turion64 Laptop with 1GB RAM.


  • Broadcom BCM2045A Bluetooth USB adapter.


  • Nokia E61 acting as a modem.





As a test case in configuring the system, I will try to connect to the network
for UIM registration purposes.




The relevant configuration files are:


  • /etc/ppp/chap-secrets


  • /etc/ppp/pap-secrets


  • /etc/ppp/options


  • /etc/ppp/peers/_your_ppp_extra_config_


  • /etc/ppp/_your_chat_script_


  • /etc/ppp/ip-up


  • /etc/ppp/ip-down


The chap-secrets and pap-secrets contains the username and password to
authenticate yourself to the ppp peer/server. It has to be modified to suit your need.
The options file contains the default options for all connections which will
be made by pppd. You should place your connection specific options in a custom file
in /etc/ppp/peers directory and invoke it with:

pppd call _your_ppp_extra_config_

This will initiate the ppp connection to the peer.
You will need the chat script to talk to your modem. The ip-up and ip-down
scripts are optional. I am using it to update the nameserver configuration after the
IP connection through ppp established.




These are the options configured in my /etc/ppp/options file:


asyncmap 0
crtscts
lock
modem
proxyarp
lcp-echo-interval 30
lcp-echo-failure 4

Opening the pppd man pages should help you to understand those options.
Now, my ppp extra configuration file is /etc/ppp/peers/im2.
I'm using the following command to dial into my 3G/GPRS ISP using this file
(dialing should be done as root):

pppd call im2

The contents of /etc/ppp/peers/im2 as follows:

/dev/rfcomm0 crtscts 115200
connect 'chat -v -f /etc/ppp/chat/im2_chat'
defaultroute name indosatm2 noipdefault usepeerdns idle 0

Actually, this file contains commands and options passed to pppd when I call it
in the shell dump shown above. This is the breakdown:

  • /dev/rfcomm0 is the modem I'm using in this ppp session.


  • crtscts means use hardware flowcontrol in this ppp session.


  • 115200 is the baud rate at which I'm connecting.


  • 115200 is the baud rate at which I'm connecting.


  • The connect 'chat -v -f /etc/ppp/chat/im2_chat'
    means invoke the chat program with the /etc/ppp/chat/im2_chat
    as the chat file. The chat file is used to initialize the modem and
    waiting for connection string from the ISP.


  • defaultroute means add a default route to the system routing tables
    when the ppp connection established.


  • name indosatm2 directs pppd to find an entry in either /etc/ppp/chap-secrets
    or /etc/ppp/pap-secrets which corresponds to indosatm2 as the login/user
    name for the connection.


  • noipdefault enforce the peer/server to supply the IP address during IPCP negotiation when pppd
    tries to establish the connection.


  • usepeerdns asks the peer for upto two DNS server addresses.


  • idle 0 is an optional parameter which means pppd should disconnect if the ppp link is idle for the
    requested amount of time (in seconds).


At this point the file used to dial the ppp server is clear. To check the current status while you are dialling
the ppp server, you can use:

tail -f /var/log/messages

and then checking your network interface when the IP connection has been established with ifconfig.
If ifconfig shows something like:

root@konoha:~ # ifconfig
ppp0 Link encap:Point-to-Point Protocol
inet addr:114.58.67.148 P-t-P:10.6.6.6 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:229 errors:0 dropped:0 overruns:0 frame:0
TX packets:229 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:271660 (265.2 KiB) TX bytes:13892 (13.5 KiB)

Then the ppp connection has been established correctly.
Now, let's move to the chat script.
Read the chat man pages for the details. This is my chat script (/etc/ppp/chat/im2_chat).

ECHO ON
ABORT 'NO CARRIER'
ABORT 'NO DIALTONE'
ABORT 'ERROR'
ABORT 'NO ANSWER'
ABORT 'BUSY'
'' ATZ
OK 'ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0'
OK 'AT+IFC=2,2;+CVHU=1'
OK 'ATS7=60+DS=3,0;&K3'
OK 'AT+CGDCONT=1,"IP","indosatm2"'
OK 'ATS0=0'
OK 'ATDT*99#'
~

As you can see, Nokia E61 when used as modem requires quite a lot of initialization strings.
Again, read the chat man pages for the details.



The secrets files are shown below. I provided them here because the login is a universal way
to register the UIM of any user of the Indosat IM2 broom user which pose no security risks to me.
This is the /etc/ppp/chap-secrets file:


# Secrets for authentication using CHAP
# client server secret IP addresses
indosatm2 * prabayar

and this is the /etc/ppp/pap-secrets file:

# Secrets for authentication using PAP
# client server secret IP addresses
indosatm2 * prabayar

That's it, the secrets file needed to login to register an Indosat IM2 broom 3G/GPRS package.
Note that indosatm2 is the login and prabayar is the password.


I have added new (previously non-existent in default pppd installation) ip-up and ip-down
scripts to handle the name resolution chores once the IP connection through the ppp interface
established. This is the /etc/ppp/ip-up script:


#!/bin/sh
#
# Update /etc/resolv.conf pppd generated file.
# Backup the old /etc/resolv.conf
#

RESOLV_BACKUP="/etc/old_resolv.conf"
RESOLV="/etc/resolv.conf"
PPP_RESOLV="/etc/ppp/resolv.conf"

cp -v ${RESOLV} ${RESOLV_BACKUP}
cp -vf ${PPP_RESOLV} ${RESOLV}

unset RESOLV_BACKUP
unset RESOLV
unset PPP_RESOLV

The script above is pretty simple bash script. I think I don't need to explain it.
The /etc/ppp/ip-down script as follows:

#!/bin/sh
#
# Restore /etc/resolv.conf
#

RESOLV_BACKUP="/etc/old_resolv.conf"
RESOLV="/etc/resolv.conf"

cp -vf ${RESOLV_BACKUP} ${RESOLV}
rm -vf ${RESOLV_BACKUP}

unset RESOLV_BACKUP
unset RESOLV

Note that the variable values in both ip-up and ip-down scripts have to match each other,
otherwise you are deleting the wrong file(s) or non-existent file. It can be dangerous
because these scripts run under root privilege.



Now, let's try to connect to the ISP (Indosat IM2) to register the UIM.


pppd call im2

This is the log in /var/log/messages during the connection establishment:

root@opunaga: # tail -f /var/log/messages
Dec 11 12:09:59 opunaga pppd[6867]: pppd 2.4.4 started by root, uid 0
Dec 11 12:10:00 opunaga hcid[2000]: link_key_request (sba=4E:89:44:0C:46:14, dba=00:12:D1:85:E8:8F)
Dec 11 12:10:01 opunaga chat[6870]: abort on (NO CARRIER)
Dec 11 12:10:01 opunaga chat[6870]: abort on (NO DIALTONE)
Dec 11 12:10:01 opunaga chat[6870]: abort on (ERROR)
Dec 11 12:10:01 opunaga chat[6870]: abort on (NO ANSWER)
Dec 11 12:10:01 opunaga chat[6870]: abort on (BUSY)
Dec 11 12:10:01 opunaga chat[6870]: send (ATZ^M)
Dec 11 12:10:01 opunaga chat[6870]: expect (OK)
Dec 11 12:10:01 opunaga chat[6870]: ATZ^M^M
Dec 11 12:10:01 opunaga chat[6870]: OK
Dec 11 12:10:01 opunaga chat[6870]: -- got it
Dec 11 12:10:01 opunaga chat[6870]: send (ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0^M)
Dec 11 12:10:01 opunaga chat[6870]: expect (OK)
Dec 11 12:10:01 opunaga chat[6870]: ^M
Dec 11 12:10:01 opunaga chat[6870]: ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0^M^M
Dec 11 12:10:01 opunaga chat[6870]: OK
Dec 11 12:10:01 opunaga chat[6870]: -- got it
Dec 11 12:10:01 opunaga chat[6870]: send (AT+IFC=2,2;+CVHU=1^M)
Dec 11 12:10:01 opunaga chat[6870]: expect (OK)
Dec 11 12:10:01 opunaga chat[6870]: ^M
Dec 11 12:10:01 opunaga chat[6870]: AT+IFC=2,2;+CVHU=1^M^M
Dec 11 12:10:01 opunaga chat[6870]: OK
Dec 11 12:10:01 opunaga chat[6870]: -- got it
Dec 11 12:10:01 opunaga chat[6870]: send (ATS7=60+DS=3,0;&K3^M)
Dec 11 12:10:01 opunaga chat[6870]: expect (OK)
Dec 11 12:10:01 opunaga chat[6870]: ^M
Dec 11 12:10:01 opunaga chat[6870]: ATS7=60+DS=3,0;&K3^M^M
Dec 11 12:10:01 opunaga chat[6870]: OK
Dec 11 12:10:01 opunaga chat[6870]: -- got it
Dec 11 12:10:01 opunaga chat[6870]: send (AT+CGDCONT=1,"IP","indosatm2"^M)
Dec 11 12:10:02 opunaga chat[6870]: expect (OK)
Dec 11 12:10:02 opunaga chat[6870]: ^M
Dec 11 12:10:02 opunaga chat[6870]: AT+CGDCONT=1,"IP","indosatm2"^M^M
Dec 11 12:10:02 opunaga chat[6870]: OK
Dec 11 12:10:02 opunaga chat[6870]: -- got it
Dec 11 12:10:02 opunaga chat[6870]: send (ATS0=0^M)
Dec 11 12:10:02 opunaga chat[6870]: expect (OK)
Dec 11 12:10:02 opunaga chat[6870]: ^M
Dec 11 12:10:02 opunaga chat[6870]: ATS0=0^M^M
Dec 11 12:10:02 opunaga chat[6870]: OK
Dec 11 12:10:02 opunaga chat[6870]: -- got it
Dec 11 12:10:02 opunaga chat[6870]: send (ATDT*99#^M)
Dec 11 12:10:02 opunaga chat[6870]: expect (~)
Dec 11 12:10:02 opunaga chat[6870]: ^M
Dec 11 12:10:11 opunaga chat[6870]: ATDT*99#^M^M
Dec 11 12:10:11 opunaga chat[6870]: CONNECT^M
Dec 11 12:10:11 opunaga chat[6870]: ~
Dec 11 12:10:11 opunaga chat[6870]: -- got it
Dec 11 12:10:11 opunaga pppd[6867]: Serial connection established.
Dec 11 12:10:11 opunaga pppd[6867]: Using interface ppp0
Dec 11 12:10:11 opunaga pppd[6867]: Connect: ppp0 <--> /dev/rfcomm0
Dec 11 12:10:12 opunaga pppd[6867]: PAP authentication succeeded
Dec 11 12:10:16 opunaga pppd[6867]: local IP address 192.168.28.189
Dec 11 12:10:16 opunaga pppd[6867]: remote IP address 10.6.6.6
Dec 11 12:10:16 opunaga pppd[6867]: primary DNS address 202.155.47.130
Dec 11 12:10:16 opunaga pppd[6867]: secondary DNS address 202.155.0.10

and let's see our ppp interface:

root@opunaga:darmawan # ifconfig
ppp0 Link encap:Point-to-Point Protocol
inet addr:192.168.28.189 P-t-P:10.6.6.6 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:24 errors:0 dropped:0 overruns:0 frame:0
TX packets:29 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:5902 (5.7 KiB) TX bytes:2061 (2.0 KiB)

Now, we have everything working as expected ;).





That's it for the moment. I hope you can setup your 3G/GPRS connection with pppd as well.
I've come to not using wvdial for sometime because I prefer using pppd directly which I think more convenient.

Saturday, December 6, 2008

Controlling FSCK in Linux

It's annoying to have filesystem checks every once in a while when you boot your linux machine. I mean in the case everything is just fine, why run fsck? Now, how can you control the amount of mount before an fsck takes place? It's easy, if you are using Ext2 or Ext3 filesystem, just run tune2fs -c . This is the command:

me@machine $ tune2fs -c <number_of_mounts_before_fsck>

That's it. Just replace number_of_mounts_before_fsck with the value of your liking and it should be done.

Tuesday, December 2, 2008

Using find Utility Effectively in *NIX

Sometimes you need to find files with certain criterion as fast as possible. For example in task where you need to strip out files bigger than a predefined size. Say 50KB. This can be done efficiently using the find utility in *NIX with the following command:
 
darmawan@opunaga:AP $ find rootfs/bin -type f -size +50k -exec ls -lah \{} \;

The command above assumes you are searching in rootfs/bin directory. Note the backslashes in the command, they are used to escape the subsequent character(s) after them in order to prevent the shell from interpreting them.

Another rather often used combination is find, grep and awk. The following example shows how to find certain string and ignoring paths with .svn directory in it.
 
darmawan@opunaga:AP $ find rootfs -type f -exec grep -H -n 'iwcontrol' \{} \; | awk '$0 !~ /\.svn/ {print}'

I think long commands like above should be scripted for ease of use in the long-run.