When it comes to internet connectivity in Switzerland, you might stumble across ADSL or VDSL. Most of the time you’ll end up with a router provided by the provider, which is already pre-configured with the connection information. This setup might work for the majority of users, but if you’re a pro-user or enterprise with special needs, you want more.
In our case, we were looking for a much more “dynamic” way to configure the internet access, and of course we wanted to route and filter the traffic on a Linux machine. So we ended up with a dial-up account (not that shitty 56k dial-up connection) and a PPPoE modem.
What is PPPoE?
PPPoE is the abbreviation for Point-to-Point protocol over Ethernet. Basically it’s a network protocol to encapsulate PPP frames inside Ethernet frames. There’s a really nice Wikipedia Article for PPPoE:
The Point-to-Point Protocol over Ethernet (PPPoE) is a network protocol for encapsulating PPP frames inside Ethernet frames. It appeared shortly after the year 2000, in the context of the boom of the DSL as the solution for tunneling packets over the DSL connection to the ISP’s IP network, and from there to the rest of the Internet. A 2005 networking book noted that “Most DSL providers use PPPoE, which provides authentication, encryption, and compression.” Typical use of PPPoE involves leveraging the PPP facilities for authenticating the user with a username and password, predominately via the PAP protocol and less often via CHAP.
Install & configure pppd for a PPPoE connection
To use PPPoE connections on Linux, we need some additional software. On Debian-based systems, we’re looking for pppd and pppoeconf:
apt-get update apt-get install pppd pppoeconf
As we now have installed the required software, we need to configure it. The configuration of a provider (aka peer) is stored in the /etc/ppp/peers directory, and there’s already a default provider configuration file. Just have a look at it:
cat /etc/ppp/peers/provider
As we know exactly what kind of configuration parameters are required, we can create a new configuration file:
cat <<EOF >/etc/ppp/peers/example # Use Roaring Penguin's PPPoE implementation. plugin rp-pppoe.so eth0 # Login settigns. user "foobar@example.com" noauth hide-password # Connection settings. persist maxfail 0 holdoff 5 # LCP settings. lcp-echo-interval 10 lcp-echo-failure 3 # PPPoE compliant settings. noaccomp default-asyncmap mtu 1492 # IP settings. noipdefault defaultroute EOF
With this configuration, we make sure that the PPPoE connection is always up (aka persist ), and that it is reopened automatically (aka maxfail & holdoff) in case it unexpectedly disconnects.The user has to match the username you’ll get from your provider. Since we get our IP address dynamically (DHCP), we set the parameter noipdefault . Of course this is our main interface for the internet connection, so we want to have a defaultroute in place.
Of course you still need a password for your PPPoE connection, so add one more line to the /etc/ppp/chap-secrets file:
cat <<EOF >/etc/ppp/chap-secrets foobar@example.com * my-secret-password * EOF
Open the PPPoE connection
Now that you’ve everything configured, you should be able to open the PPPoE connection by calling:
pon example
Wait for a few seconds and then you should see a new interface:
# Show all interfaces ip link show # Show only PPPoE interface ip link show ppp0
To stop the connection, you can execute:
poff -a
Hint: The command pon can also be called without the peer argument, but then it looks for the default provider in /etc/ppp/peers/provider . If you want your connection to be the default provider, you can symlink your peer configuration to it:
cd /etc/ppp/peers rm -f provider ln -s example provider
Make the PPPoE connection coming up automatically
If you want the PPPoE connection come up automatically, you’ve several options. The good old fashioned way is an interfaces entry, at least on Debian-based systems.
# On Debian >= 8 via separate interfaces file in interfaces.d: cat <<EOF >/etc/network/interfaces.d/example auto example iface example inet ppp pre-up /sbin/ip link set dev eth0 up provider example EOF # On Debian <8 via common interfaces file: cat <<EOF >>/etc/network/interfaces auto example iface example inet ppp pre-up /sbin/ip link set dev eth0 up provider example EOF
This works fine when you’re rebooting your machine. But if you’ve a system with systemd enabled, you might want to start / stop your connection via systemd / systemctl , instead of the interfaces file:
cat <<EOF >/etc/systemd/system/pppoe.service [Unit] Description=PPPoE connection [Service] Type=oneshot RemainAfterExit=true ExecStart=/usr/bin/pon example ExecStop=/usr/bin/poff -a [Install] WantedBy=default.target EOF systemctl daemon-reload
Now you’re able to manage the connection via systemctl :
# Open connection systemctl start pppoe # Close connection systemctl stop pppoe # See connection / pppd logs systemctl logs pppoe
Routing & Firewalling
If you want to use your Linux machine as a router and firewall, you’ve to enable IP(v4) forwarding and add some iptables rules.
# Make IP forwarding persistent cat <<EOF >/etc/sysctl.d/ip-forward.conf net.ipv4.ip_forward=1 EOF # Reload sysctl to enable IP forwarding sysctl -p # Add iptables rules for masquerading and MSS clamping iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE iptables -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
IP(v4) forwarding enables Linux to forward packages from one interface (network) to another.
With iptables we need to setup IP masquerading, which is done via NAT table. IP masquerading helps us do “hide” the client on the remote host, by rewriting the source address of the package after routing. The remote system will only see the IP address of our Linux router, and not the IP address of the client behind. While this is required for the PPPoE connection, it can also be a security enhancement in routing of private networks.
The second iptables rule helps us to solve a PPP “issue”. Ethernet packages have a fixed size and they will define the amount of payload the can carry via MTU (maximum transmission unit). By default, Ethernet packages have a MTU size of 1500 bytes, which is fine. However, PPPoE packages have to define an additional header of 6 bytes, and a PPP ID of 2 bytes. This means in PPPoE packages, we “lose” 8 bytes and so the MTU size is reduced to 1492. This isn’t a problem in the first place, but it will become one when a client (e.g. browser / surfing the internet) connects to a server (e.g. webserver). They negotiate a MTU size of 1500 bytes, and the server starts sending data with 1500 bytes chunks, while the PPPoE package can only hold 1492 bytes. There’s a technique called MSS clamping which will fix this issue. Cisco has a really nice white paper which describes exactly that.
IMPORTANT: While the IP(v4) forwarding is persistent, the iptables rules aren’t. So you might want to do a iptables save or simply create a file with the iptables rules in /etc/ppp/ip-up.d/ , which will automatically be loaded as soon as the PPPoE connection is up.
13 Comments