BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | # This file contains some examples of using NCD, the Network Configuration Daemon. |
2 | # |
||
3 | # A short introduction to NCD follows. |
||
4 | # |
||
5 | # NCD is a general-purpose system configuration system, operated with a unique programming language. |
||
6 | # The configuration consists of one or more so-called processes that can be considered executing in |
||
7 | # parallel. Further, each process consists of one or more statements, representing the individual |
||
8 | # actions. Statements are implemented as modules built into NCD. |
||
9 | # |
||
10 | # Inside a process, statements can be considered "executed" one after another. That is, when NCD |
||
11 | # starts up, it initializes the first statement, putting it in the DOWN state. When the statement |
||
12 | # reports having transitioned into the UP state, it initializes the next statement in the DOWN state, |
||
13 | # and so on. |
||
14 | # |
||
15 | # However, execution can go in the other direction too. A statement in the UP state can, at any time, |
||
16 | # report having transitioned into the DOWN state. At this point, any statements after that one will |
||
17 | # automatically be de-initialized. The de-initiazation is done from the bottom up. First the last |
||
18 | # initialized statement after the problematic statement is requested to terminate and enters the |
||
19 | # DYING state. After it terminates, its preceding statement enters the DYING state, and so on, until |
||
20 | # all statements following the problematic statement have been de-initiazed. |
||
21 | # |
||
22 | # The backward-execution is the key feature of NCD, and is particularly well suited for programming |
||
23 | # system configurations. Read on to see why. |
||
24 | # |
||
25 | # Statements in NCD can be divided into two categories: |
||
26 | # - Statements that configure something. These statements transition into the UP state "immediately". |
||
27 | # On de-initialization, such statements perform the reverse operation of what they did when initialized. |
||
28 | # Imaginary example: a statement that turn a light on intialization, and turns if off on de-initialization. |
||
29 | # - Statements that wait for something. These statements may remain in the DOWN state indefinitely. |
||
30 | # They enter the UP state when the waited-for condition is satisfied, and also go back into the DOWN |
||
31 | # state when it is no longer satisfied. |
||
32 | # Imaginary example: a statement that is UP when a switch is turned on, and DOWN when it is turned off. |
||
33 | # |
||
34 | # Using the two example statements, we can constuct a process that controls the light based on the switch: |
||
35 | # (these are not really implemented in NCD :) |
||
36 | # |
||
37 | # process light { |
||
38 | # wait_switch(); |
||
39 | # turn_light(); |
||
40 | # } |
||
41 | # |
||
42 | # When the switch is turned on, wait_switch() will transition to UP, initializing turn_light(), turning the |
||
43 | # light on. When the switch is turned off, wait_switch() will transition to DOWN, causing the de-initialization |
||
44 | # of turn_light(), turning the light off. |
||
45 | # We can add another turn_light() at the end to make the switch control two lights. |
||
46 | # |
||
47 | # A more complex example: We have a christmas three with lights on it. There are multiple "regular" lights, |
||
48 | # controlled with switches, and a special "top" light. The regular lights take a long time to turn on, and |
||
49 | # each takes a different, unpredictable time. We want the top light to be turned on if and only if all the regular |
||
50 | # lights are completely on. |
||
51 | # |
||
52 | # This problem can easily be solved using dependencies. NCD has built-in support for dependencies, provided |
||
53 | # in the form of provide() and depend() statements. A depend() statement is DOWN when its corresponding |
||
54 | # provide() statement is not initialized, and UP when it is. When a provide() is requested to de-initialize, it |
||
55 | # transitions the depend() statements back into the DOWN state, and, before actually dying, waits for any |
||
56 | # statements following them to de-initialize. |
||
57 | # |
||
58 | # The christmas three problem can then be programmed as follows: |
||
59 | # |
||
60 | # process light1 { |
||
61 | # wait_switch1(); |
||
62 | # turn_light1(); |
||
63 | # provide("L1"); |
||
64 | # } |
||
65 | # |
||
66 | # process light2 { |
||
67 | # wait_switch2(); |
||
68 | # turn_light2(); |
||
69 | # provide("L2"); |
||
70 | # } |
||
71 | # |
||
72 | # process top_light { |
||
73 | # depend("L1"); |
||
74 | # depend("L2"); |
||
75 | # turn_top_light(); |
||
76 | # } |
||
77 | # |
||
78 | # Follow some real examples of network configuration using NCD. |
||
79 | # For a list of implemented statements and their descriptions, take a look at the BadVPN source code, in |
||
80 | # the ncd/modules/ folder. |
||
81 | # |
||
82 | |||
83 | # |
||
84 | # Network card using DHCP. |
||
85 | # |
||
86 | |||
87 | process lan { |
||
88 | # Make the interface name a variable so we can refer to it. |
||
89 | # The NCD language has no notion of assigning a variable. Instead variables are |
||
90 | # provided by statements preceding the statement where they are used. |
||
91 | # The built-in var() statement can be used to make an alias. |
||
92 | var("eth0") dev; |
||
93 | |||
94 | # Wait for the network card to appear, set it up and wait for the cable to be |
||
95 | # plugged it. |
||
96 | net.backend.waitdevice(dev); |
||
97 | net.up(dev); |
||
98 | net.backend.waitlink(dev); |
||
99 | |||
100 | # Start DHCP. |
||
101 | net.ipv4.dhcp(dev) dhcp; |
||
102 | |||
103 | # DHCP has obtained an address. |
||
104 | # Because net.ipv4.dhcp does no checks of the IP address, as a safety measure, do not proceed |
||
105 | # if the address is local. |
||
106 | ip_in_network(dhcp.addr, "127.0.0.0", "8") test_local; |
||
107 | ifnot(test_local); |
||
108 | |||
109 | # Assign the obtained address to the interface. |
||
110 | net.ipv4.addr(dev, dhcp.addr, dhcp.prefix); |
||
111 | |||
112 | # Add a default route. |
||
113 | # <dest> <dest_prefix> <gateway/"none"> <metric> <device> |
||
114 | net.ipv4.route("0.0.0.0", "0", dhcp.gateway, "20", dev); |
||
115 | |||
116 | # Add DNS servers, as provided by DHCP. |
||
117 | # "20" is the priority of the servers. When applying DNS servers, NCD collects the servers |
||
118 | # from all active net.dns() statements, sorts them by priority ascending (stable), and writes |
||
119 | # them to /etc/resolv.conf, overwriting anything that was previously there. |
||
120 | net.dns(dhcp.dns_servers, "20"); |
||
121 | } |
||
122 | |||
123 | # |
||
124 | # Network card with static configuration. |
||
125 | # |
||
126 | |||
127 | process lan2 { |
||
128 | # Make the interface name a variable so we can refer to it. |
||
129 | var("eth1") dev; |
||
130 | |||
131 | # Wait for the network card to appear, set it up and wait for the cable to be |
||
132 | # plugged it. |
||
133 | net.backend.waitdevice(dev); |
||
134 | net.up(dev); |
||
135 | net.backend.waitlink(dev); |
||
136 | |||
137 | # Assign an IP address. |
||
138 | # "24" is prefix length, i.e. subnet mask 255.255.255.0 |
||
139 | net.ipv4.addr(dev, "192.168.62.3", "24"); |
||
140 | |||
141 | # Add a default route. |
||
142 | net.ipv4.route("0.0.0.0", "0", "192.168.62.3", "20", dev); |
||
143 | |||
144 | # Build a list of DNS servers. |
||
145 | # The NCD language does not support "expressions" - statement arguments must be |
||
146 | # constant strings or variables referring to preceding statements. |
||
147 | # A list can be constructed using the built-in list() statement. |
||
148 | list("192.168.62.5", "192.168.62.6") dns_servers; |
||
149 | |||
150 | # Add the DNS servers. |
||
151 | net.dns(dns_servers, "20"); |
||
152 | } |
||
153 | |||
154 | # |
||
155 | # Wireless network interface using wpa_supplicant. |
||
156 | # |
||
157 | |||
158 | process WLAN { |
||
159 | # Set device. |
||
160 | var("wlan0") dev; |
||
161 | |||
162 | # Wait for device and rfkill switch. |
||
163 | net.backend.waitdevice(dev); |
||
164 | net.backend.rfkill("wlan", dev); |
||
165 | |||
166 | # Start wpa_supplicant on this interface, using configuration in /etc/wpa_supplicant/all.conf . |
||
167 | list() args; |
||
168 | net.backend.wpa_supplicant(dev, "/etc/wpa_supplicant/all.conf", "/usr/sbin/wpa_supplicant", args) sup; |
||
169 | |||
170 | # wpa_supplicant tells us what network we connected to. Look below for how this can be used to |
||
171 | # have different configurations, "BadVPN, but configured differently based on what network we're in". |
||
172 | println("connected to wireless network: bssid=", sup.bssid, " ssid=", sup.ssid); |
||
173 | |||
174 | # Wireless connection successful, here comes network config (DHCP/static/whatever) ... |
||
175 | } |
||
176 | |||
177 | # |
||
178 | # A BadVPN VPN interface for access to the virtual network (only). |
||
179 | # |
||
180 | |||
181 | process lan { |
||
182 | ... (something like above) ... |
||
183 | |||
184 | # Alias our IP address for easy access from the "vpn" process (or, for a static address, alias |
||
185 | # it before assigning it, and assign it using the alias). |
||
186 | var(dhcp.addr) ipaddr; |
||
187 | |||
188 | # Allow VPN to start at this point. |
||
189 | # (and require it to stop before deconfiguring the interface if e.g. the cable is plugged out) |
||
190 | provide("LAN"); |
||
191 | } |
||
192 | |||
193 | process vpn { |
||
194 | # Need the local interface to be working in order start VPN. |
||
195 | depend("LAN") landep; |
||
196 | |||
197 | # Choose the name of the network interface. |
||
198 | var("tap3") dev; |
||
199 | |||
200 | # Construct command line arguments for badvpn-client. Adapt according to your setup. |
||
201 | # "--tapdev" will be provided automatically. |
||
202 | |||
203 | # Alias the port number that the VPN process will bind to. |
||
204 | var("6000") port; |
||
205 | |||
206 | # Construct dynamic parts of command line options. |
||
207 | # The VPN client program needs to know some IP addresses in order to tell other peers where to connect to. |
||
208 | # Obtain this informations from variables in the "lan" process through the depend() statement. |
||
209 | |||
210 | # Construct the local address (addr + port). |
||
211 | concat(landep.ipaddr, ":", port) local_addr_arg; |
||
212 | |||
213 | # Construct the Internet address (assuming we are behind a NAT). |
||
214 | # Need to know the NAT's external address here. But we could queried it somehow. |
||
215 | # That is if we have preconfigured the NAT router to forward ports. But we could implement a statement |
||
216 | # that obtains the mappings dynamically with UPnP! |
||
217 | concat("1.2.3.4", ":", port) internet_addr_arg; |
||
218 | |||
219 | # Finally construct the complete arguments, using the above address arguments. |
||
220 | list( |
||
221 | "--logger", "syslog", "--syslog-ident", "badvpn", |
||
222 | "--server-addr", "badvpn.example.com:7000", |
||
223 | "--ssl", "--nssdb", "sql:/home/badvpn/nssdb", "--client-cert-name", "peer-someone", |
||
224 | "--transport-mode", "udp", "--encryption-mode", "blowfish", "--hash-mode", "md5", "--otp", "blowfish", "3000", "2000", |
||
225 | "--scope", "mylan", "--scope", "internet", |
||
226 | "--bind-addr", "0.0.0.0:6000", "--num-ports", "20", |
||
227 | "--ext-addr", local_addr_arg, "mylan", |
||
228 | "--ext-addr", internet_addr_arg, "internet" |
||
229 | ) args; |
||
230 | |||
231 | # Start the BadVPN backend. |
||
232 | # "badvpn" is the user account which the VPN client will run as. |
||
233 | # If you use SSL, the NSS database must be accessible to this user. |
||
234 | net.backend.badvpn(dev, "badvpn", "/usr/bin/badvpn-client-26", args); |
||
235 | |||
236 | # Assign an IP address to the VPN interface. |
||
237 | # (we could easily use DHCP here!) |
||
238 | net.ipv4.addr(dev, "10.0.0.1", "24"); |
||
239 | } |
||
240 | |||
241 | # |
||
242 | # BadVPN, but configured differently based on what network we're in. |
||
243 | # The network is identified based on the IP address we were assigned by DHCP. |
||
244 | # The different configuration provide specific arguents to badvpn-client. |
||
245 | # |
||
246 | |||
247 | process lan { |
||
248 | ... (interface config stuff using DHCP, see above) ... |
||
249 | ... (the 'ipaddr' variable holds the local IP address) ... |
||
250 | |||
251 | # Match the address to various known networks. |
||
252 | ip_in_network(ipaddr, "192.168.4.0", "24") is_lan1; |
||
253 | ip_in_network(ipaddr, "192.168.7.0", "24") is_lan2; |
||
254 | |||
255 | # Allow VPN to start at this point. |
||
256 | provide("LAN"); |
||
257 | } |
||
258 | |||
259 | process vpn { |
||
260 | ... |
||
261 | |||
262 | # Construct common arguments here ... |
||
263 | list( ... ) common_args; |
||
264 | |||
265 | # Choose appropriate configuration by waking up the configuration processes |
||
266 | # and waiting for one to complete. |
||
267 | provide("VPN_CONF_START"); |
||
268 | depend("VPN_CONF_END") config; |
||
269 | |||
270 | # Concatenate common and configuration-specific arguments. |
||
271 | concatlist(common_args, config.args) args; |
||
272 | |||
273 | ... |
||
274 | } |
||
275 | |||
276 | process vpn_config_lan1 { |
||
277 | depend("VPN_CONF_START") dep; |
||
278 | |||
279 | # Proceed only if we're in lan1. |
||
280 | if(dep.landep.is_lan1); |
||
281 | |||
282 | list( |
||
283 | ... |
||
284 | ) args; |
||
285 | |||
286 | provide("VPN_CONF_END"); |
||
287 | } |
||
288 | |||
289 | process vpn_config_lan2 { |
||
290 | depend("VPN_CONF_START") dep; |
||
291 | |||
292 | # Proceed only if we're in lan2. |
||
293 | if(dep.landep.is_lan2); |
||
294 | |||
295 | list( |
||
296 | ... |
||
297 | ) args; |
||
298 | |||
299 | provide("VPN_CONF_END"); |
||
300 | } |
||
301 | |||
302 | process vpn_config_inet { |
||
303 | depend("VPN_CONF_START") dep; |
||
304 | |||
305 | # Proceed only if we're not in any known network. |
||
306 | ifnot(dep.landep.is_lan1); |
||
307 | ifnot(dep.landep.is_lan2); |
||
308 | |||
309 | list( |
||
310 | ... |
||
311 | ) args; |
||
312 | |||
313 | provide("VPN_CONF_END"); |
||
314 | } |
||
315 | |||
316 | # |
||
317 | # Two wired network interfaces (eth0, eth1), both of which may be used for Internet access. |
||
318 | # When both are working, give priority to eth1 (e.g. if eth0 is up, but later eth1 also comes |
||
319 | # up, the configuration will be changed to use eth1 for Internet access). |
||
320 | # |
||
321 | |||
322 | process eth0 { |
||
323 | # Set device. |
||
324 | var("eth0") dev; |
||
325 | |||
326 | # Wait for device. |
||
327 | net.backend.waitdevice(dev); |
||
328 | net.up(dev); |
||
329 | net.backend.waitlink(dev); |
||
330 | |||
331 | # DHCP configuration. |
||
332 | net.ipv4.dhcp(dev) dhcp; |
||
333 | ip_in_network(dhcp.addr, "127.0.0.0", "8") test_local; |
||
334 | ifnot(test_local); |
||
335 | var(dhcp.addr) addr; |
||
336 | var(dhcp.prefix) addr_prefix; |
||
337 | var(dhcp.gateway) gateway; |
||
338 | var(dhcp.dns_servers) dns_servers; |
||
339 | |||
340 | # Assign IP address. |
||
341 | net.ipv4.addr(dev, addr, addr_prefix); |
||
342 | |||
343 | # Go on configuring the network. |
||
344 | multiprovide("NET-eth0"); |
||
345 | } |
||
346 | |||
347 | process eth1 { |
||
348 | # Set device. |
||
349 | var("eth1") dev; |
||
350 | |||
351 | # Wait for device. |
||
352 | net.backend.waitdevice(dev); |
||
353 | net.up(dev); |
||
354 | net.backend.waitlink(dev); |
||
355 | |||
356 | # Static configuration. |
||
357 | var("192.168.111.116") addr; |
||
358 | var("24") addr_prefix; |
||
359 | var("192.168.111.1") gateway; |
||
360 | list("192.168.111.14", "193.2.1.66") dns_servers; |
||
361 | |||
362 | # Assign IP address. |
||
363 | net.ipv4.addr(dev, addr, addr_prefix); |
||
364 | |||
365 | # Go on configuring the network. |
||
366 | multiprovide("NET-eth1"); |
||
367 | } |
||
368 | |||
369 | process NETCONF { |
||
370 | # Wait for some network connection. Prefer eth1 by putting it in front of eth0. |
||
371 | list("NET-eth1", "NET-eth0") pnames; |
||
372 | multidepend(pnames) ifdep; |
||
373 | |||
374 | # Alias device values. |
||
375 | var(ifdep.dev) dev; |
||
376 | var(ifdep.addr) addr; |
||
377 | var(ifdep.addr_prefix) addr_prefix; |
||
378 | var(ifdep.gateway) gateway; |
||
379 | var(ifdep.dns_servers) dns_servers; |
||
380 | |||
381 | # Add default route. |
||
382 | net.ipv4.route("0.0.0.0", "0", gateway, "20", dev); |
||
383 | |||
384 | # Configure DNS servers. |
||
385 | net.dns(dns_servers, "20"); |
||
386 | } |