Try   HackMD

pppd, pppoe 與 chroot , busybox 使用

Author: WhoAmI
Date: 20220801
E-mail: kccddb@gmail.com
Copyright: CC BY-NC-SA

這裡寫的是非標準 Fedo***, Deb***, Ubun***, 用法
你要看他們的標準用法, 那請別看這裡, 請離開別浪費時間, 這裡只有簡單但複雜的東西


這裡的 ppp, rp-pppoe 都是自己 source compile, 沒有那些
adsl-start, adsl-stop, 那些東西
連 /etc/ppp/pap-secrets, /etc/ppp/chap-secret 都沒有

因此如要看他們的標準用法, 那也別看這裡了, 也請離開, 不用浪費時間


以下 是 pppd 與 pppoe 的 DIY, 相信能看懂以下內容者的能力. 若想看Protocol 可以找其它資料. pppoe 事實上昰透過 Ethernet 進行 PPP 連線

/*
pppd, pppoe

*/

這裡用的是很小的 Linux系統 (pppd, pppoe DIY)


pppd 很麻煩, 若不想改原來 HOST 設定需要 chroot 一起配合

以下是x86 版, 改成 Beaglebone, Sitara, Raspberry Pi不是問題

編譯好 rp-pppoe, pppd , 其中 pppd pppoe也加入 PATH 中

laikc@laikc-virtual:~/x86/rp-pppoe-3.11$ pppd pty 'pppoe -I eth0 -T 100 -U -m 1412' linkname adsl0 user xxxxxx@hinet.net password xxxxxxxl default-asyncmap hide-password nodetach mtu 1492

上面xxxxxx部分自己改
Advanced user: linkname 也請看 Multiple PPPoE connections

[sudo] password for laikc:
Using interface ppp0
Connect: ppp0 <> /dev/pts/5
PAP authentication succeeded
local IP address 114.26.44.207
remote IP address 168.95.98.254

沒 DNS 因此再來

laikc@laikc-virtual:~/x86/rp-pppoe-3.11$ pppd pty 'pppoe -I eth0 -T 100 -U -m 1412' linkname adsl0 user xxxxxx@hinet.net password xxxxxxx default-asyncmap hide-password nodetach mtu 1492 usepeerdns

Using interface ppp0
Connect: ppp0 <> /dev/pts/5
PAP authentication succeeded
local IP address 111.246.97.7
remote IP address 168.95.98.254
primary DNS address 168.95.192.1
secondary DNS address 168.95.1.1

但是這樣 route, 與 NAT 還不能動, 還有MTU 問題, MTU 以後再談, MTU 是可能的大問題
route, nat 是小問題, 除了多路 VPN bonding 與 load balancing


您當然可以依照 pppd 的結果自己手動設定 routing, NAT 的問題, 但是

pppd 會始用 /etc/ppp/ip-up 幫忙設定, ppp-2.4.6 為例 source code


static void
ipcp_script(script, wait)
char *script;
int wait;
{
char strspeed[32], strlocal[32], strremote[32];
char *argv[8];

​​​​slprintf(strspeed, sizeof(strspeed), "%d", baud_rate);
​​​​slprintf(strlocal, sizeof(strlocal), "%I", ipcp_gotoptions[0].ouraddr);
​​​​slprintf(strremote, sizeof(strremote), "%I", ipcp_hisoptions[0].hisaddr);

​​​​argv[0] = script;
​​​​argv[1] = ifname;
​​​​argv[2] = devnam;
​​​​argv[3] = strspeed;
​​​​argv[4] = strlocal;
​​​​argv[5] = strremote;
​​​​argv[6] = ipparam;
​​​​argv[7] = NULL;
​​​​if (wait)

run_program(script, argv, 0, NULL, NULL, 1);
else
ipcp_script_pid = run_program(script, argv, 0, ipcp_script_done,
NULL, 0);
}

內定使用 script

#define _PATH_UPAPFILE _ROOT_PATH "/etc/ppp/pap-secrets"
#define _PATH_CHAPFILE _ROOT_PATH "/etc/ppp/chap-secrets"
#define _PATH_SRPFILE _ROOT_PATH "/etc/ppp/srp-secrets"
#define _PATH_SYSOPTIONS _ROOT_PATH "/etc/ppp/options"
#define _PATH_IPUP _ROOT_PATH "/etc/ppp/ip-up"
#define _PATH_IPDOWN _ROOT_PATH "/etc/ppp/ip-down"

#define _PATH_IPPREUP _ROOT_PATH "/etc/ppp/ip-pre-up"
#define _PATH_AUTHUP _ROOT_PATH "/etc/ppp/auth-up"
#define _PATH_AUTHDOWN _ROOT_PATH "/etc/ppp/auth-down"
#define _PATH_TTYOPT _ROOT_PATH "/etc/ppp/options."
#define _PATH_CONNERRS _ROOT_PATH "/etc/ppp/connect-errors"
#define _PATH_PEERFILES _ROOT_PATH "/etc/ppp/peers/"
#define _PATH_RESOLV _ROOT_PATH "/etc/ppp/resolv.conf"

pppd 啟動的環境變數 (當然正常只有 child process 可以用)

Search for "script_setenv", 我用 Windows Jens' File Editor 找出來
E:\src\ppp-2.4.6\pppd\auth.c(974,5): script_setenv("PEERNAME", peer_authname, 0);
E:\src\ppp-2.4.6\pppd\ipcp.c(1816,5): script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0);
E:\src\ppp-2.4.6\pppd\ipcp.c(1818,2): script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1);
E:\src\ppp-2.4.6\pppd\ipcp.c(1825,2): script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0);
E:\src\ppp-2.4.6\pppd\ipcp.c(1827,2): script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0);
E:\src\ppp-2.4.6\pppd\ipcp.c(1829,2): script_setenv("USEPEERDNS", "1", 0);
E:\src\ppp-2.4.6\pppd\ipcp.c(1855,3): script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0);
E:\src\ppp-2.4.6\pppd\ipcp.c(1861,3): script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0);
E:\src\ppp-2.4.6\pppd\ipv6cp.c(1213,5): script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
E:\src\ppp-2.4.6\pppd\ipv6cp.c(1214,5): script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
E:\src\ppp-2.4.6\pppd\main.c(339,5): script_setenv("ORIG_UID", numbuf, 0);
E:\src\ppp-2.4.6\pppd\main.c(467,5): script_setenv("PPPLOGNAME", p, 0);
E:\src\ppp-2.4.6\pppd\main.c(470,2): script_setenv("DEVICE", devnam, 1);
E:\src\ppp-2.4.6\pppd\main.c(472,5): script_setenv("PPPD_PID", numbuf, 1);
E:\src\ppp-2.4.6\pppd\main.c(742,5): script_setenv("IFNAME", ifname, iskey);
E:\src\ppp-2.4.6\pppd\main.c(786,5): script_setenv("PPPD_PID", numbuf, 1);
E:\src\ppp-2.4.6\pppd\main.c(832,5): script_setenv("LINKNAME", linkname, 1);
E:\src\ppp-2.4.6\pppd\main.c(1249,5): script_setenv("CONNECT_TIME", numbuf, 0);
E:\src\ppp-2.4.6\pppd\main.c(1251,5): script_setenv("BYTES_SENT", numbuf, 0);
E:\src\ppp-2.4.6\pppd\main.c(1253,5): script_setenv("BYTES_RCVD", numbuf, 0);
E:\src\ppp-2.4.6\pppd\main.c(1731,37): * exec. It is not possible to use script_setenv() or
E:\src\ppp-2.4.6\pppd\main.c(2016,4): * script_setenv - set an environment variable value to be used
E:\src\ppp-2.4.6\pppd\main.c(2020,1):script_setenv(var, value, iskey)
E:\src\ppp-2.4.6\pppd\multilink.c(188,3): script_setenv("BUNDLE", bundle_id + 7, 1);
E:\src\ppp-2.4.6\pppd\multilink.c(222,4): script_setenv("BUNDLE", bundle_id + 7, 0);
E:\src\ppp-2.4.6\pppd\multilink.c(235,2): script_setenv("BUNDLE", bundle_id + 7, 1);
E:\src\ppp-2.4.6\pppd\plugins\radius\radius.c(596,16): script_setenv("RADIUS_FILTER_ID", vp->strvalue, 1);
E:\src\ppp-2.4.6\pppd\plugins\radius\radius.c(600,16): script_setenv("RADIUS_FRAMED_ROUTE", vp->strvalue, 1);
E:\src\ppp-2.4.6\pppd\plugins\rp-pppoe\plugin.c(221,5): script_setenv("MACREMOTE", remote_number, 0);

E:\src\ppp-2.4.6\pppd\tty.c(739,2): script_setenv("SPEED", numbuf, 0);


重要的就是上面紅色這兩個, 其餘沒有也沒關係, 直接用 pppd command

#define _PATH_IPUP _ROOT_PATH "/etc/ppp/ip-up"
#define _PATH_IPDOWN _ROOT_PATH "/etc/ppp/ip-down"

可以來設定 route, 與 NAT, 等, 其餘再說, 很煩的
設計網路設備的 BUNDLE 應該很有興趣吧? 哈, 其實還有很多要寫程式要配合沒那麼簡單

真正實用也非 如此簡單 up ,down

為了打造與原來 Host Linux 無關的 rootfs
我們用了最簡單的 busybox, 放在 home/x86 中, tftpboot 不用理, 那是我 pxe, 與 tftp 用的

root@laikc-virtual:/home/laikc/x86# chroot . bin/sh
/ # ls
ib tftp.sh usr linuxrc
bin sbin tftpboot
etc src tmp

exit 後

src 都是放該 cpu arch 的 source, 有些要改makefile

root@laikc-virtual:/home/laikc/x86# mkdir proc sys dev var

因為用 host 的系統, 因此 mount 原來 3 個主要系統, 若是真正版子, 要自己來, 不是用以下的 command, 也就是proc, dev, sys 要自己來

chroot pppd 注意事項: 因為pppd 用了一堆kernel device 功能, 因此須要額外 proc, sys, dev
請看 ppp source code


設定 dev, proc, sys


root@laikc-virtual:/home/laikc/x86# mount -t proc proc proc/
root@laikc-virtual:/home/laikc/x86# mount rbind /sys sys/
root@laikc-virtual:/home/laikc/x86# mount rbind /dev dev/


rbind "Bind Mounts" recursive bind mount. Please see wiki.
Maybe you must know this problem in detail.



看 pppd source 也需要 var/run

root@laikc-virtual:/home/laikc/x86# mkdir var/run

因為 pppd 需要 proc, dev, sys (kernel modules), var, var/run

很多程式需要 /var, /var/run , embedded system 可用 ramdisk mount /var, /tmp

我把 pppd pppoe dynamic lib 都cp 至 root@laikc-virtual:/home/laikc/x86/lib

還有 linux-gate.so.1是 kernel 的, 不用 cp

laikc@laikc-virtual:~/x86$ ldd bin/pppoe
linux-gate.so.1 => (0x00634000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x0072e000)
/lib/ld-linux.so.2 (0x00bfb000)
laikc@laikc-virtual:~/x86$ ldd bin/pppd
linux-gate.so.1 => (0x00bbb000)
libcrypt.so.1 => /lib/i386-linux-gnu/libcrypt.so.1 (0x00d2e000)
libutil.so.1 => /lib/i386-linux-gnu/libutil.so.1 (0x002ce000)
libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0x00ff5000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0x008b6000)
/lib/ld-linux.so.2 (0x0081f000)
laikc@laikc-virtual:~/x86$


chroot . bin/sh

(因為我的busybox 沒有 bash, lubutu12.04 chroot 內定 /bin/bash 因此要加 shell, 如果您只用
chroot . 會出問題, 沒有shell )

這樣您的root 就是/home/laikc-virtual:/home/laikc/x86
您的/home/laikc-virtual:/home/laikc/x86/bin 要有 sh

沒設 PATH 就要完整 path

/bin/pppd pty '/bin/pppoe -I eth0 -T 30 -U -m 1412' linkname adsl2 user xxxxxxxxx password xxxxxxx default-asyncmap hide-password nodetach mtu 1492 usepeerdns

Connect: ppp0 <> /dev/pts/5
PAP authentication succeeded
local IP address 111.246.97.7
remote IP address 168.95.98.254
primary DNS address 168.95.192.1
secondary DNS address 168.95.1.1

這樣您就可以寫自己的 ip-up 與 ip-down 與原HOST Linux 沒有衝突

其實您看 ppp source, 沒有那些 script 也可以自己改


做這個不是很無聊嗎? 不是的! 因為與網路相關先用 x86 測完再移植 別的 CPU 比較方便, 實際不是每人手有一片版子, 真正最跨平台的是 C. Java 只是應用層, import LIB 不一樣, java 能跨平台嗎? 累死人, 您把 C# 移植Android 看看? 但是 C 很好移植.

簡單原則: 與UI 無關用 C, 與UI 有關可用 Java等


還有 Linux IEEE80211 wifi 也可以如此使用來測試, 沒有udev, 就要手動 insmod


ip-up , ip-down 寫法請看

http://wiki.openwrt.org/doc/howto/vpn.client.pptp

很好資料, 這就不提了, 上面寫的很好, 雖然非PPPoE, 原理一樣

pppd 有點複雜的這老的好東西, 可以用到現在

但是 route 請改 ip route (check replace parameters ), 不要用 route 了

正常檢察網路通不通不是用ping 固定IP方法, 檢察WAN網路斷線也不是只用 ifconfig 方法

其中有用的方法 AF_PACKET (不是用ping) 與 Netlink Socket 判斷 route change