BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
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 }