The idea of plugins is to provide a way for people to customize the behaviour of pppd without having to either apply local patches to each version or get their patches accepted into the standard distribution.
A plugin is a standard shared library object, typically with a name ending in .so. They are loaded using the standard dlopen() library
call, so plugins are only supported on systems which support shared libraries and the dlopen call. At present pppd is compiled with
plugin support only under Linux and Solaris.
Using gcc under Linux, a plugin called `xyz' could be compiled and linked with the following commands:
gcc -c -O xyz.c
gcc -shared -o xyz.so xyz.o
Plugins can access global variables within pppd, so it is useful for them to #include "pppd.h" from the pppd source directory.
Plugins can affect the behaviour of pppd in at least three ways:
1. They can add extra options which pppd will then recognize. This is done by calling the add_options() procedure with a pointer to an array of option_t structures. The last entry in the array must have its name field set to NULL.
2. Pppd contains `hook' variables which are procedure pointers. If a given hook is not NULL, pppd will call the procedure it points to
at the appropriate point in its processing. The plugin can set any of these hooks to point to its own procedures. See below for a
description of the hooks which are currently implemented.
3. Plugin code can call any global procedures and access any global variables in pppd.
int (*pap_check_hook)(void);
int (*pap_passwd_hook)(char *user, char *passwd);
int (*pap_auth_hook)(char *user, int userlen,
char *passwd, int passlen,
char **msgp, int *msglenp,
struct wordlist **paddrs,
struct wordlist **popts);
These hooks are designed to allow a plugin to replace the normal PAP password processing in pppd with something different (e.g. contacting an external server).
The pap_check_hook is called to check whether there is any possibility that the peer could authenticate itself to us. If it returns 1, pppd will ask the peer to authenticate itself. If it returns 0, pppd will not ask the peer to authenticate itself (but if authentication is
required, pppd may exit, or terminate the link before network protocol negotiation). If it returns -1, pppd will look in the pap-secrets
file as it would normally.
The pap_passwd_hook is called to determine what username and password pppd should use in authenticating itself to the peer with PAP. The user string will already be initialized, by the `user' option, the `name' option, or from the hostname, but can be changed if necessary. MAXNAMELEN bytes of space are available at *user, and MAXSECRETLEN bytes of space at *passwd. If this hook returns 0, pppd will use the values at *user and *passwd; if it returns -1, pppd will look in the pap-secrets file, or use the value from the +ua or password option, as it would normally.
The pap_auth_hook is called to determine whether the username and password supplied by the peer are valid. user and passwd point to null-terminated strings containing the username and password supplied by the peer, with non-printable characters converted to a printable form. The pap_auth_hook function should set msg to a string to be returned to the peer and return 1 if the username/password was valid and 0 if not. If the hook returns -1, pppd will look in the pap-secrets file as usual.
If the username/password was valid, the hook can set *paddrs to point to a wordlist containing the IP address(es) which the peer is
permitted to use, formatted as in the pap-secrets file. It can also set *popts to a wordlist containing any extra options for this user
which pppd should apply at this point.
现以我们学校的电信拨号为例详解plugin的创建步骤。中国电信上网真正的密码是他提供给我们的密码经过几种加密算法得到的新的密码。因此我们直接用电信提供的密码无法上网,而每次输入加密后的密码又太麻烦,所以我们可以制作plugin将加密密码传给pppd。
首先来看pppd.h中定义的struct option_t
typedef struct { char *name; /* name of the option */ enum opt_type type;//见下面enum opt_type void *addr;//optin的地址 char *description;//描述 int flags;//常用的flags就是OPT_STATIC void *addr2;//NULL int upper_limit;//optin最大长度 int lower_limit; const char *source;//此三项可填NULL short int priority; short int winner; } option_t;
enum opt_type { o_special_noarg = 0, o_special = 1, o_bool, o_int, o_uint32, o_string, o_wild, };
/* Values for flags */ #define OPT_STATIC 0x2000 /* string option goes into static array */我的plugin开始部分就是
#include <string.h> #include <pppd/pppd.h> #include "dialcrypt.h" #include "pap-secrets.h" char pppd_version[] = VERSION; static char pwd[MAXSECRETLEN] = {0};//电信提供的密码 static char modefied_pwd[MAXSECRETLEN] = {0};//经过加密后的密码 static int is_passwd_modified = 0; static option_t options[] = { { "pwd", o_string, pwd, "the given password", OPT_STATIC, NULL, MAXSECRETLEN-1 }, { NULL } };然后是得出加密密码,由于电信密码的加密算法不是相关内容,此处就不列出。
static int pap_modifypasswd(char *user, char* passwd) { if( is_passwd_modified == 0) { int n; if(user[0] == 0) { info("cumtdial : pppd!!!!no user"); return 0; } info("cumtdial : username %s\n",user); if(pwd[0] == 0) { info("cumtdial :load passwd from secret file"); n = get_pap_passwd(user,pwd);//若没有输入密码,则从pap-secret文件中读取默认密码,若电信密码固定,可写入此文件 if(!n) { info("cumtdial :load passwd from pap-secret file fail!!!!"); return 0; } } info("cumtdial : load passwd success. passwd:<hidden>"); cumt_dial_get_entire_cipher(pwd,modefied_pwd);//得出加密密码 is_passwd_modified = 1; } if(passwd != NULL) strcpy(passwd,modefied_pwd);//将加密后的密码写入pppd要读取的密码passwd return 1; }然后是pppd要调用的plugin_init()函数
void plugin_init(void) { add_options(options); pap_passwd_hook=pap_modifypasswd; }用前文讲到的步骤将它编译成动态链接库,复制到/usr/lib/pppd/2.4.5/,然后在/etc/ppp/peers下创建文件cumtdial
noipdefault defaultroute replacedefaultroute noauth persist usepeerdns plugin rp-pppoe.so eth0 plugin cumtdial.sorp-pppoe.so用于通过网线上网,还有其他方式比如无线,3g。
之后上网就可以用命令pppd call cumtdial user "***" pwd "***",这个pwd就是电信给你的密码。