| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- include_guard "pppoe"
- template pppoe {
- alias("_arg0") dev;
- alias("_arg1") username;
- alias("_arg2") password;
- alias("_arg3") pre_up_template;
- # Choose which NCD interpreter will be used for the pppd event scripts.
- var("/usr/local/badvpn/bin/badvpn-ncd") ncd_interpreter_path;
- # Retry point here.
- var("false") retrying;
- backtrack_point() retry_point;
- If (retrying) {
- sleep("5000");
- };
- retrying->set("true");
- # Create a temporary directory.
- concat("/run/ncd-pppoe-", dev) run_dir;
- run({"/bin/rm", "-rf", run_dir}, {});
- run({"/bin/mkdir", run_dir}, {"/bin/rm", "-rf", run_dir});
- # Build paths for pppd scripts and other files.
- concat(run_dir, "/ncd-request.socket") socket_path;
- concat(run_dir, "/pppoe.pid") pppoe_pid_path;
- concat(run_dir, "/pap-secrets") pap_secrets_path;
- concat(run_dir, "/chap-secrets") chap_secrets_path;
- concat(run_dir, "/pppd2.tdb") pppdb_path;
- concat(run_dir, "/resolv.conf") resolv_conf_path;
- concat(run_dir, "/script-auth-up") path_auth_up;
- concat(run_dir, "/script-auth-down") path_auth_down;
- concat(run_dir, "/script-auth-fail") path_auth_fail;
- concat(run_dir, "/script-ip-pre-up") path_ip_pre_up;
- concat(run_dir, "/script-ip-up") path_ip_up;
- concat(run_dir, "/script-ip-down") path_ip_down;
- concat(run_dir, "/script-ipv6-up") path_ipv6_up;
- concat(run_dir, "/script-ipv6-down") path_ipv6_down;
- concat(run_dir, "/script-ipx-up") path_ipx_up;
- concat(run_dir, "/script-ipx-down") path_ipx_down;
- # Write secrets files.
- call("pppoe__write_secrets", {pap_secrets_path, username, password});
- call("pppoe__write_secrets", {chap_secrets_path, username, password});
- # Write pppd scripts. These will contact us via the request socket.
- call("pppoe__write_script", {"ip-pre-up", path_ip_pre_up});
- call("pppoe__write_script", {"ip-up", path_ip_up});
- call("pppoe__write_script", {"ip-down", path_ip_down});
- # Build path arguments for pppd;
- concat("pid-dir=", run_dir) arg_pid_dir;
- concat("pap-secrets=", pap_secrets_path) arg_pap_secrets;
- concat("chap-secrets=", chap_secrets_path) arg_chap_secrets;
- concat("pppdb=", pppdb_path) arg_pppdb;
- concat("resolv.conf=", resolv_conf_path) arg_resolv_conf;
- concat("auth-up=", path_auth_up) arg_auth_up;
- concat("auth-down=", path_auth_down) arg_auth_down;
- concat("auth-fail=", path_auth_fail) arg_auth_fail;
- concat("ip-pre-up=", path_ip_pre_up) arg_ip_pre_up;
- concat("ip-up=", path_ip_up) arg_ip_up;
- concat("ip-down=", path_ip_down) arg_ip_down;
- concat("ipv6-up=", path_ipv6_up) arg_ipv6_up;
- concat("ipv6-down=", path_ipv6_down) arg_ipv6_down;
- concat("ipx-up=", path_ipx_up) arg_ipx_up;
- concat("ipx-down=", path_ipx_down) arg_ipx_down;
- # Create state variables and blockers. When the request server
- # receives requests it will update those variables and blockers.
- var("down") state;
- var("") current_ifname;
- var("") current_local_ip;
- var("") current_remote_ip;
- value({}) current_dns_servers;
- blocker() ip_pre_up_blocker;
- blocker() ip_pre_up_done_blocker;
- blocker() ip_up_blocker;
- # Start request server.
- sys.request_server({"unix", socket_path}, "pppoe__request_handler", {});
- # Start pppd.
- sys.start_process({
- "/usr/sbin/pppd", "nodetach", "plugin", "rp-pppoe.so", dev, "noipdefault", "hide-password",
- "usepeerdns", "user", username,
- "path", arg_pid_dir, "path", arg_pap_secrets, "path", arg_chap_secrets, "path", arg_pppdb,
- "path", arg_resolv_conf,
- "path", arg_auth_up, "path", arg_auth_down, "path", arg_auth_fail, "path", arg_ip_pre_up,
- "path", arg_ip_up, "path", arg_ip_down, "path", arg_ipv6_up, "path", arg_ipv6_down,
- "path", arg_ipx_up, "path", arg_ipx_down
- }, "", ["deinit_kill_time":"2000"]) pppd;
- # Start a process which will cause retrying when pppd dies.
- spawn("pppoe__pppd_wait", {});
- # Wait for ip-pre-up.
- ip_pre_up_blocker->use();
- # Grab the current state variables, so the user doesn't
- # see any unexpected changes.
- var(current_ifname) ifname;
- var(current_local_ip) local_ip;
- var(current_remote_ip) remote_ip;
- var(current_dns_servers) dns_servers;
- # Call pre-up callback template.
- call_with_caller_target(pre_up_template, {ifname, local_ip, remote_ip, dns_servers}, "_caller");
- # Allow pre-up script to terminate.
- ip_pre_up_done_blocker->up();
- # Wait for connection to go up.
- ip_up_blocker->use();
- }
- template pppoe__pppd_wait {
- # Wait for pppd to die.
- _caller.pppd->wait();
- # Retry.
- _caller.retry_point->go();
- }
- template pppoe__write_secrets {
- alias("_arg0") file_path;
- alias("_arg1") username;
- alias("_arg2") password;
- # Escape username and password.
- regex_replace(username, {"\""}, {"\\\""}) username_esc;
- regex_replace(password, {"\""}, {"\\\""}) password_esc;
- # Write empty file and chmod it.
- file_write(file_path, "");
- run({"/bin/chmod", "600", file_path}, {});
- # Build contents.
- concat("\"", username_esc, "\" * \"", password_esc, "\"\n") contents;
- # Write file.
- file_write(file_path, contents);
- }
- template pppoe__write_script {
- alias("_arg0") event;
- alias("_arg1") script_path;
- # This string is an NCD script which will be run by pppd.
- # When run, it will contact us via the request server,
- # and the requests will be processed in pppoe__request_handler.
- var("#!<NCD_INTERPRETER_PATH>
- process main {
- # Hardcoded strings.
- var(\"<EVENT>\") hardcoded_event;
- var(\"<SOCKET>\") hardcoded_socket;
- # Start timeout to kill us after some time if we don't manage
- # to contact the server.
- spawn(\"timeout_process\", {});
- # Build event data map.
- getargs() args;
- value([\"EVENT\":hardcoded_event, \"ARGS\":args]) msg_map;
- var({\"DEVICE\", \"IFNAME\", \"IPLOCAL\", \"IPREMOTE\", \"PEERNAME\", \"LOCALNAME\",
- \"SPEED\", \"ORIG_UID\", \"PPPLOGNAME\", \"CONNECT_TIME\", \"BYTES_SENT\",
- \"BYTES_RCVD\", \"LINKNAME\", \"DNS1\", \"DNS2\", \"WINS1\", \"WINS2\"}) var_names;
- Foreach (var_names As var_name) {
- getenv(var_name) env;
- If (env.exists) {
- msg_map->insert(var_name, env);
- };
- };
- # Connect to socket.
- sys.request_client({\"unix\", hardcoded_socket}) client;
- # Send request.
- client->request(msg_map, \"reply_handler\", \"finished_handler\", {});
- }
- template reply_handler {
- print();
- }
- template finished_handler {
- # Request was received by server, exit now.
- exit(\"0\");
- }
- template timeout_process {
- # Sleep some time.
- sleep(\"5000\");
- # Timed out, exit now.
- exit(\"1\");
- }
- " ) script_contents_template;
- # Replace some constants in the script with the right values.
- regex_replace(script_contents_template,
- {"<NCD_INTERPRETER_PATH>", "<EVENT>", "<SOCKET>"},
- {_caller.ncd_interpreter_path, event, _caller.socket_path}
- ) script_contents;
- # Write the script.
- file_write(script_path, script_contents);
- # Make it executable.
- run({"/bin/chmod", "+x", script_path}, {});
- }
- template pppoe__request_handler {
- alias("_caller") pppoe;
- # Get event type from request.
- value(_request.data) request;
- request->get("EVENT") event;
- # Match to known types.
- val_equal(event, "ip-down") is_ip_down;
- val_equal(event, "ip-pre-up") is_ip_pre_up;
- val_equal(event, "ip-up") is_ip_up;
- If (is_ip_down) {
- # Set state.
- pppoe.state->set("down");
- # Set blockers down.
- pppoe.ip_up_blocker->down();
- pppoe.ip_pre_up_done_blocker->down();
- pppoe.ip_pre_up_blocker->down();
- }
- Elif (is_ip_pre_up) {
- # Expecting to be in "down" state here.
- val_different(pppoe.state, "down") state_is_wrong;
- If (state_is_wrong) {
- pppoe.retry_point->go();
- _request->finish();
- };
- # Get variables from request.
- request->get("IFNAME") ifname;
- request->get("IPLOCAL") local_ip;
- request->get("IPREMOTE") remote_ip;
- request->try_get("DNS1") dns1;
- request->try_get("DNS2") dns2;
- # Write variables.
- pppoe.current_ifname->set(ifname);
- pppoe.current_local_ip->set(local_ip);
- pppoe.current_remote_ip->set(remote_ip);
- pppoe.current_dns_servers->reset({});
- If (dns1.exists) {
- pppoe.current_dns_servers->insert(pppoe.current_dns_servers.length, dns1);
- };
- If (dns2.exists) {
- pppoe.current_dns_servers->insert(pppoe.current_dns_servers.length, dns2);
- };
- # Set state.
- pppoe.state->set("pre-up");
- # Set ip-pre-up blocker up.
- pppoe.ip_pre_up_blocker->up();
- # Wait for pre-up to be finished. This causes the script contacting
- # us to not return until then, and effectively delays pppd in setting
- # the device up and calling the ip-up script.
- pppoe.ip_pre_up_done_blocker->use();
- }
- Elif(is_ip_up) {
- # Expecting to be in "pre-up" state here.
- val_different(pppoe.state, "pre-up") state_is_wrong;
- If (state_is_wrong) {
- pppoe.retry_point->go();
- _request->finish();
- };
- # Set state.
- pppoe.state->set("up");
- # Set ip-up blocker up.
- pppoe.ip_up_blocker->up();
- };
- # Finish request.
- _request->finish();
- }
- template pppoe__escapeshellarg {
- alias("_arg0") input;
- regex_replace(input, {"'"}, {"\\'"}) replaced;
- concat("'", replaced, "'") result;
- }
|