BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | include_guard "pppoe" |
2 | |||
3 | template pppoe { |
||
4 | alias("_arg0") dev; |
||
5 | alias("_arg1") username; |
||
6 | alias("_arg2") password; |
||
7 | alias("_arg3") pre_up_template; |
||
8 | |||
9 | # Choose which NCD interpreter will be used for the pppd event scripts. |
||
10 | var("/usr/local/badvpn/bin/badvpn-ncd") ncd_interpreter_path; |
||
11 | |||
12 | # Retry point here. |
||
13 | var("false") retrying; |
||
14 | backtrack_point() retry_point; |
||
15 | If (retrying) { |
||
16 | sleep("5000"); |
||
17 | }; |
||
18 | retrying->set("true"); |
||
19 | |||
20 | # Create a temporary directory. |
||
21 | concat("/run/ncd-pppoe-", dev) run_dir; |
||
22 | run({"/bin/rm", "-rf", run_dir}, {}); |
||
23 | run({"/bin/mkdir", run_dir}, {"/bin/rm", "-rf", run_dir}); |
||
24 | |||
25 | # Build paths for pppd scripts and other files. |
||
26 | concat(run_dir, "/ncd-request.socket") socket_path; |
||
27 | concat(run_dir, "/pppoe.pid") pppoe_pid_path; |
||
28 | concat(run_dir, "/pap-secrets") pap_secrets_path; |
||
29 | concat(run_dir, "/chap-secrets") chap_secrets_path; |
||
30 | concat(run_dir, "/pppd2.tdb") pppdb_path; |
||
31 | concat(run_dir, "/resolv.conf") resolv_conf_path; |
||
32 | concat(run_dir, "/script-auth-up") path_auth_up; |
||
33 | concat(run_dir, "/script-auth-down") path_auth_down; |
||
34 | concat(run_dir, "/script-auth-fail") path_auth_fail; |
||
35 | concat(run_dir, "/script-ip-pre-up") path_ip_pre_up; |
||
36 | concat(run_dir, "/script-ip-up") path_ip_up; |
||
37 | concat(run_dir, "/script-ip-down") path_ip_down; |
||
38 | concat(run_dir, "/script-ipv6-up") path_ipv6_up; |
||
39 | concat(run_dir, "/script-ipv6-down") path_ipv6_down; |
||
40 | concat(run_dir, "/script-ipx-up") path_ipx_up; |
||
41 | concat(run_dir, "/script-ipx-down") path_ipx_down; |
||
42 | |||
43 | # Write secrets files. |
||
44 | call("pppoe__write_secrets", {pap_secrets_path, username, password}); |
||
45 | call("pppoe__write_secrets", {chap_secrets_path, username, password}); |
||
46 | |||
47 | # Write pppd scripts. These will contact us via the request socket. |
||
48 | call("pppoe__write_script", {"ip-pre-up", path_ip_pre_up}); |
||
49 | call("pppoe__write_script", {"ip-up", path_ip_up}); |
||
50 | call("pppoe__write_script", {"ip-down", path_ip_down}); |
||
51 | |||
52 | # Build path arguments for pppd; |
||
53 | concat("pid-dir=", run_dir) arg_pid_dir; |
||
54 | concat("pap-secrets=", pap_secrets_path) arg_pap_secrets; |
||
55 | concat("chap-secrets=", chap_secrets_path) arg_chap_secrets; |
||
56 | concat("pppdb=", pppdb_path) arg_pppdb; |
||
57 | concat("resolv.conf=", resolv_conf_path) arg_resolv_conf; |
||
58 | concat("auth-up=", path_auth_up) arg_auth_up; |
||
59 | concat("auth-down=", path_auth_down) arg_auth_down; |
||
60 | concat("auth-fail=", path_auth_fail) arg_auth_fail; |
||
61 | concat("ip-pre-up=", path_ip_pre_up) arg_ip_pre_up; |
||
62 | concat("ip-up=", path_ip_up) arg_ip_up; |
||
63 | concat("ip-down=", path_ip_down) arg_ip_down; |
||
64 | concat("ipv6-up=", path_ipv6_up) arg_ipv6_up; |
||
65 | concat("ipv6-down=", path_ipv6_down) arg_ipv6_down; |
||
66 | concat("ipx-up=", path_ipx_up) arg_ipx_up; |
||
67 | concat("ipx-down=", path_ipx_down) arg_ipx_down; |
||
68 | |||
69 | # Create state variables and blockers. When the request server |
||
70 | # receives requests it will update those variables and blockers. |
||
71 | var("down") state; |
||
72 | var("") current_ifname; |
||
73 | var("") current_local_ip; |
||
74 | var("") current_remote_ip; |
||
75 | value({}) current_dns_servers; |
||
76 | blocker() ip_pre_up_blocker; |
||
77 | blocker() ip_pre_up_done_blocker; |
||
78 | blocker() ip_up_blocker; |
||
79 | |||
80 | # Start request server. |
||
81 | sys.request_server({"unix", socket_path}, "pppoe__request_handler", {}); |
||
82 | |||
83 | # Start pppd. |
||
84 | sys.start_process({ |
||
85 | "/usr/sbin/pppd", "nodetach", "plugin", "rp-pppoe.so", dev, "noipdefault", "hide-password", |
||
86 | "usepeerdns", "user", username, |
||
87 | "path", arg_pid_dir, "path", arg_pap_secrets, "path", arg_chap_secrets, "path", arg_pppdb, |
||
88 | "path", arg_resolv_conf, |
||
89 | "path", arg_auth_up, "path", arg_auth_down, "path", arg_auth_fail, "path", arg_ip_pre_up, |
||
90 | "path", arg_ip_up, "path", arg_ip_down, "path", arg_ipv6_up, "path", arg_ipv6_down, |
||
91 | "path", arg_ipx_up, "path", arg_ipx_down |
||
92 | }, "", ["deinit_kill_time":"2000"]) pppd; |
||
93 | |||
94 | # Start a process which will cause retrying when pppd dies. |
||
95 | spawn("pppoe__pppd_wait", {}); |
||
96 | |||
97 | # Wait for ip-pre-up. |
||
98 | ip_pre_up_blocker->use(); |
||
99 | |||
100 | # Grab the current state variables, so the user doesn't |
||
101 | # see any unexpected changes. |
||
102 | var(current_ifname) ifname; |
||
103 | var(current_local_ip) local_ip; |
||
104 | var(current_remote_ip) remote_ip; |
||
105 | var(current_dns_servers) dns_servers; |
||
106 | |||
107 | # Call pre-up callback template. |
||
108 | call_with_caller_target(pre_up_template, {ifname, local_ip, remote_ip, dns_servers}, "_caller"); |
||
109 | |||
110 | # Allow pre-up script to terminate. |
||
111 | ip_pre_up_done_blocker->up(); |
||
112 | |||
113 | # Wait for connection to go up. |
||
114 | ip_up_blocker->use(); |
||
115 | } |
||
116 | |||
117 | template pppoe__pppd_wait { |
||
118 | # Wait for pppd to die. |
||
119 | _caller.pppd->wait(); |
||
120 | |||
121 | # Retry. |
||
122 | _caller.retry_point->go(); |
||
123 | } |
||
124 | |||
125 | template pppoe__write_secrets { |
||
126 | alias("_arg0") file_path; |
||
127 | alias("_arg1") username; |
||
128 | alias("_arg2") password; |
||
129 | |||
130 | # Escape username and password. |
||
131 | regex_replace(username, {"\""}, {"\\\""}) username_esc; |
||
132 | regex_replace(password, {"\""}, {"\\\""}) password_esc; |
||
133 | |||
134 | # Write empty file and chmod it. |
||
135 | file_write(file_path, ""); |
||
136 | run({"/bin/chmod", "600", file_path}, {}); |
||
137 | |||
138 | # Build contents. |
||
139 | concat("\"", username_esc, "\" * \"", password_esc, "\"\n") contents; |
||
140 | |||
141 | # Write file. |
||
142 | file_write(file_path, contents); |
||
143 | } |
||
144 | |||
145 | template pppoe__write_script { |
||
146 | alias("_arg0") event; |
||
147 | alias("_arg1") script_path; |
||
148 | |||
149 | # This string is an NCD script which will be run by pppd. |
||
150 | # When run, it will contact us via the request server, |
||
151 | # and the requests will be processed in pppoe__request_handler. |
||
152 | var("#!<NCD_INTERPRETER_PATH> |
||
153 | |||
154 | process main { |
||
155 | # Hardcoded strings. |
||
156 | var(\"<EVENT>\") hardcoded_event; |
||
157 | var(\"<SOCKET>\") hardcoded_socket; |
||
158 | |||
159 | # Start timeout to kill us after some time if we don't manage |
||
160 | # to contact the server. |
||
161 | spawn(\"timeout_process\", {}); |
||
162 | |||
163 | # Build event data map. |
||
164 | getargs() args; |
||
165 | value([\"EVENT\":hardcoded_event, \"ARGS\":args]) msg_map; |
||
166 | var({\"DEVICE\", \"IFNAME\", \"IPLOCAL\", \"IPREMOTE\", \"PEERNAME\", \"LOCALNAME\", |
||
167 | \"SPEED\", \"ORIG_UID\", \"PPPLOGNAME\", \"CONNECT_TIME\", \"BYTES_SENT\", |
||
168 | \"BYTES_RCVD\", \"LINKNAME\", \"DNS1\", \"DNS2\", \"WINS1\", \"WINS2\"}) var_names; |
||
169 | Foreach (var_names As var_name) { |
||
170 | getenv(var_name) env; |
||
171 | If (env.exists) { |
||
172 | msg_map->insert(var_name, env); |
||
173 | }; |
||
174 | }; |
||
175 | |||
176 | # Connect to socket. |
||
177 | sys.request_client({\"unix\", hardcoded_socket}) client; |
||
178 | |||
179 | # Send request. |
||
180 | client->request(msg_map, \"reply_handler\", \"finished_handler\", {}); |
||
181 | } |
||
182 | |||
183 | template reply_handler { |
||
184 | print(); |
||
185 | } |
||
186 | |||
187 | template finished_handler { |
||
188 | # Request was received by server, exit now. |
||
189 | exit(\"0\"); |
||
190 | } |
||
191 | |||
192 | template timeout_process { |
||
193 | # Sleep some time. |
||
194 | sleep(\"5000\"); |
||
195 | # Timed out, exit now. |
||
196 | exit(\"1\"); |
||
197 | } |
||
198 | |||
199 | " ) script_contents_template; |
||
200 | |||
201 | # Replace some constants in the script with the right values. |
||
202 | regex_replace(script_contents_template, |
||
203 | {"<NCD_INTERPRETER_PATH>", "<EVENT>", "<SOCKET>"}, |
||
204 | {_caller.ncd_interpreter_path, event, _caller.socket_path} |
||
205 | ) script_contents; |
||
206 | |||
207 | # Write the script. |
||
208 | file_write(script_path, script_contents); |
||
209 | |||
210 | # Make it executable. |
||
211 | run({"/bin/chmod", "+x", script_path}, {}); |
||
212 | } |
||
213 | |||
214 | template pppoe__request_handler { |
||
215 | alias("_caller") pppoe; |
||
216 | |||
217 | # Get event type from request. |
||
218 | value(_request.data) request; |
||
219 | request->get("EVENT") event; |
||
220 | |||
221 | # Match to known types. |
||
222 | val_equal(event, "ip-down") is_ip_down; |
||
223 | val_equal(event, "ip-pre-up") is_ip_pre_up; |
||
224 | val_equal(event, "ip-up") is_ip_up; |
||
225 | |||
226 | If (is_ip_down) { |
||
227 | # Set state. |
||
228 | pppoe.state->set("down"); |
||
229 | |||
230 | # Set blockers down. |
||
231 | pppoe.ip_up_blocker->down(); |
||
232 | pppoe.ip_pre_up_done_blocker->down(); |
||
233 | pppoe.ip_pre_up_blocker->down(); |
||
234 | } |
||
235 | Elif (is_ip_pre_up) { |
||
236 | # Expecting to be in "down" state here. |
||
237 | val_different(pppoe.state, "down") state_is_wrong; |
||
238 | If (state_is_wrong) { |
||
239 | pppoe.retry_point->go(); |
||
240 | _request->finish(); |
||
241 | }; |
||
242 | |||
243 | # Get variables from request. |
||
244 | request->get("IFNAME") ifname; |
||
245 | request->get("IPLOCAL") local_ip; |
||
246 | request->get("IPREMOTE") remote_ip; |
||
247 | request->try_get("DNS1") dns1; |
||
248 | request->try_get("DNS2") dns2; |
||
249 | |||
250 | # Write variables. |
||
251 | pppoe.current_ifname->set(ifname); |
||
252 | pppoe.current_local_ip->set(local_ip); |
||
253 | pppoe.current_remote_ip->set(remote_ip); |
||
254 | pppoe.current_dns_servers->reset({}); |
||
255 | If (dns1.exists) { |
||
256 | pppoe.current_dns_servers->insert(pppoe.current_dns_servers.length, dns1); |
||
257 | }; |
||
258 | If (dns2.exists) { |
||
259 | pppoe.current_dns_servers->insert(pppoe.current_dns_servers.length, dns2); |
||
260 | }; |
||
261 | |||
262 | # Set state. |
||
263 | pppoe.state->set("pre-up"); |
||
264 | |||
265 | # Set ip-pre-up blocker up. |
||
266 | pppoe.ip_pre_up_blocker->up(); |
||
267 | |||
268 | # Wait for pre-up to be finished. This causes the script contacting |
||
269 | # us to not return until then, and effectively delays pppd in setting |
||
270 | # the device up and calling the ip-up script. |
||
271 | pppoe.ip_pre_up_done_blocker->use(); |
||
272 | } |
||
273 | Elif(is_ip_up) { |
||
274 | # Expecting to be in "pre-up" state here. |
||
275 | val_different(pppoe.state, "pre-up") state_is_wrong; |
||
276 | If (state_is_wrong) { |
||
277 | pppoe.retry_point->go(); |
||
278 | _request->finish(); |
||
279 | }; |
||
280 | |||
281 | # Set state. |
||
282 | pppoe.state->set("up"); |
||
283 | |||
284 | # Set ip-up blocker up. |
||
285 | pppoe.ip_up_blocker->up(); |
||
286 | }; |
||
287 | |||
288 | # Finish request. |
||
289 | _request->finish(); |
||
290 | } |
||
291 | |||
292 | template pppoe__escapeshellarg { |
||
293 | alias("_arg0") input; |
||
294 | regex_replace(input, {"'"}, {"\\'"}) replaced; |
||
295 | concat("'", replaced, "'") result; |
||
296 | } |