applications/siitwizard: also setup v4 routes and firewall
[project/luci.git] / applications / luci-siitwizard / luasrc / model / cbi / siitwizard.lua
1 --[[
2 LuCI - Lua Configuration Interface
3
4 Copyright 2008 Steven Barth <steven@midlink.org>
5 Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 $Id$
14
15 ]]--
16
17 local uci = require "luci.model.uci".cursor()
18
19 -------------------- View --------------------
20 f = SimpleForm("siitwizward", "4over6-Assistent",
21  "Dieser Assistent unterstüzt bei der Einrichtung von IPv4-over-IPv6 Translation.")
22
23 mode = f:field(ListValue, "mode", "Betriebsmodus")
24 mode:value("client", "Client")
25 mode:value("gateway", "Gateway")
26
27 dev = f:field(ListValue, "device", "WLAN-Gerät")
28 uci:foreach("wireless", "wifi-device",
29         function(section)
30                 dev:value(section[".name"])
31         end)
32
33 lanip = f:field(Value, "ipaddr", "LAN IP Adresse")
34 lanip.value = "172.23.1.1"
35 lanip:depends("mode", "client")
36
37 lanmsk = f:field(Value, "netmask", "LAN Netzmaske")
38 lanmsk.value = "255.255.0.0"
39 lanmsk:depends("mode", "client")
40
41
42 -------------------- Control --------------------
43 LL_PREFIX = luci.ip.IPv6("fe80::/64")
44
45 --
46 -- find link-local address
47 --
48 function find_ll()
49         for _, r in ipairs(luci.sys.net.routes6()) do
50                 if LL_PREFIX:contains(r.dest) and r.dest:higher(LL_PREFIX) then
51                         return r.dest:sub(LL_PREFIX)
52                 end
53         end
54         return luci.ip.IPv6("::")
55 end
56
57
58
59 function f.handle(self, state, data)
60         if state == FORM_VALID then
61                 luci.http.redirect(luci.dispatcher.build_url("admin", "uci", "changes"))
62                 return false
63         elseif state == FORM_INVALID then
64                 self.errmessage = "Ungültige Eingabe: Bitte die Formularfelder auf Fehler prüfen."
65         end
66         return true
67 end
68
69 function mode.write(self, section, value)
70
71         --
72         -- Configure wifi device
73         --
74         local wifi_device  = dev:formvalue(section)
75         local wifi_essid   = uci:get("siit", "wifi", "essid")   or "6mesh.freifunk.net"
76         local wifi_bssid   = uci:get("siit", "wifi", "bssid")   or "02:ca:ff:ee:ba:be"
77         local wifi_channel = uci:get("siit", "wifi", "channel") or "1"
78
79         -- nuke old device definition
80         uci:delete_all("wireless", "wifi-iface",
81                 function(s) return s.device == wifi_device end )
82
83         uci:delete_all("network", "interface",
84                 function(s) return s['.name'] == wifi_device end )
85
86         -- create wifi device definition
87         uci:tset("wireless", wifi_device, {
88                 disabled  = 0,
89                 channel   = wifi_channel,
90 --              txantenna = 1,
91 --              rxantenna = 1,
92 --              diversity = 0
93         })
94
95         uci:section("wireless", "wifi-iface", nil, {
96                 encryption = "none",
97                 mode       = "adhoc",
98                 network    = wifi_device,
99                 device     = wifi_device,
100                 ssid       = wifi_essid,
101                 bssid      = wifi_bssid,
102         })
103
104
105         --
106         -- Determine defaults
107         --
108         local ula_prefix  = uci:get("siit", "ipv6", "ula_prefix")  or "fd00::"
109         local ula_global  = uci:get("siit", "ipv6", "ula_global")  or "00ca:ffee:babe::"                -- = Freifunk
110         local ula_subnet  = uci:get("siit", "ipv6", "ula_subnet")  or "0000:0000:0000:4223::"   -- = Berlin
111         local siit_prefix = uci:get("siit", "ipv6", "siit_prefix") or "::ffff:0000:0000"
112
113         -- Find wifi interface
114         local device = dev:formvalue(section)
115
116         --
117         -- Generate ULA
118         --
119         local ula = luci.ip.IPv6("::/64")
120
121         for _, prefix in ipairs({ ula_prefix, ula_global, ula_subnet }) do
122                 ula = ula:add(luci.ip.IPv6(prefix))
123         end
124
125         ula = ula:add(find_ll())
126
127
128         --
129         -- Gateway mode
130         --
131         --      * wan port is dhcp, lan port is 172.23.1.1/24
132         --      * siit0 gets a dummy address: 169.254.42.42
133         --      * wl0 gets an ipv6 address, in this case the fdca:ffee:babe::1:1/64
134         --      * we do a ::ffff:ffff:0/96 route into siit0, so everything from 6mesh goes into translation.
135         --      * an HNA6 of ::ffff:ffff:0:0/96 announces the mapped 0.0.0.0/0 ipv4 space.
136         --      * MTU on WAN, LAN down to 1400, ipv6 headers are slighly larger.
137
138         if value == "gateway" then
139
140                 uci:set("network", "wan", "mtu", 1400)
141
142                 -- use full siit subnet
143                 siit_route = luci.ip.IPv6(siit_prefix .. "/96")
144
145         --
146         -- Client mode
147         --
148         --      * 172.23.2.1/24 on its lan, fdca:ffee:babe::1:2 on wl0 and the usual dummy address on siit0.
149         --      * we do a ::ffff:ffff:172.13.2.0/120 to siit0, because in this case, only traffic directed to clients needs to go into translation.
150         --      * same route as HNA6 announcement to catch the traffic out of the mesh.
151         --      * Also, MTU on LAN reduced to 1400.
152
153         else
154                 -- lan interface
155                 local lan_net = luci.ip.IPv4(
156                         lanip:formvalue(section) or "192.168.1.1",
157                         lanmsk:formvalue(section) or "255.255.255.0"
158                 )
159
160                 uci:tset("network", "lan", {
161                         mtu     = 1400,
162                         ipaddr  = lan_net:host():string(),
163                         netmask = lan_net:mask():string()
164                 })
165
166                 -- derive siit subnet from lan config
167                 siit_route = luci.ip.IPv6(
168                         siit_prefix .. "/" .. (96 + lan_net:prefix())
169                 ):add(lan_net[2])
170
171                 -- ipv4 <-> siit route
172                 uci:delete_all("network", "route",
173                         function(s) return s.interface == "siit0" end)
174
175                 uci:section("network", "route", nil, {
176                         interface = "siit0",
177                         target    = "0.0.0.0",
178                         netmask   = "0.0.0.0"
179                 })
180         end
181
182         -- setup the firewall
183         uci:delete_all("firewall", "zone",
184                 function(s) return (
185                         s['.name'] == "siit0" or s.name == "siit0" or
186                         s.network == "siit0" or s['.name'] == wifi_device or
187                         s.name == wifi_device or s.network == wifi_device
188                 ) end)
189
190         uci:delete_all("firewall", "forwarding",
191                 function(s) return (
192                         s.src == wifi_device and s.dest == "siit0" or
193                         s.dest == wifi_device and s.src == "siit0"
194                 ) end)
195
196         uci:section("firewall", "zone", "siit0", {
197                 name    = "siit0",
198                 network = "siit0",
199                 input   = "ACCEPT",
200                 output  = "ACCEPT",
201                 forward = "ACCEPT"
202         })
203
204         uci:section("firewall", "zone", wifi_device, {
205                 name    = wifi_device,
206                 network = wifi_device,
207                 input   = "ACCEPT",
208                 output  = "ACCEPT",
209                 forward = "ACCEPT"
210         })
211
212         uci:section("firewall", "forwarding", nil, {
213                 src  = wifi_device,
214                 dest = "siit0"
215         })
216
217         uci:section("firewall", "forwarding", nil, {
218                 src  = "siit0",
219                 dest = wifi_device
220         })
221
222         -- siit0 interface
223         uci:delete_all("network", "interface",
224                 function(s) return ( s.ifname == "siit0" ) end)
225
226         uci:section("network", "interface", "siit0", {
227                 ifname  = "siit0",
228                 proto   = "static",
229                 ipaddr  = "169.254.42.42",
230                 netmask = "255.255.255.0"
231         })
232
233         -- siit0 route
234         uci:delete_all("network", "route6",
235                 function(s) return siit_route:contains(luci.ip.IPv6(s.target)) end)
236
237         uci:section("network", "route6", nil, {
238                 interface = "siit0",
239                 target    = siit_route:string()
240         })
241
242         -- create wifi network interface
243         uci:section("network", "interface", wifi_device, {
244                 proto   = "static",
245                 mtu     = 1400,
246                 ip6addr = ula:string()
247         })
248
249         -- nuke old olsrd interfaces
250         uci:delete_all("olsrd", "Interface",
251                 function(s) return s.interface == wifi_device end)
252
253         -- configure olsrd interface
254         uci:foreach("olsrd", "olsrd",
255                 function(s) uci:set("olsrd", s['.name'], "IpVersion", 6) end)
256
257         uci:section("olsrd", "Interface", nil, {
258                 ignore      = 0,
259                 interface   = wifi_device,
260                 Ip6AddrType = "global"
261         })
262
263         -- hna6
264         uci:delete_all("olsrd", "Hna6",
265                 function(s)
266                         if s.netaddr and s.prefix then
267                                 return siit_route:contains(luci.ip.IPv6(s.netaddr.."/"..s.prefix))
268                         end
269                 end)
270
271         uci:section("olsrd", "Hna6", nil, {
272                 netaddr = siit_route:host():string(),
273                 prefix  = siit_route:prefix()
274         })
275
276         uci:save("wireless")
277         uci:save("firewall")
278         uci:save("network")
279         uci:save("olsrd")
280 end
281
282 return f