contrib/package: make relayd dependency conditional, else luci build will break brcm-2.4
[project/luci.git] / contrib / fwd / src / fwd.c
1 /*
2 * fwd - OpenWrt firewall daemon - main part
3 *
4 * Copyright (C) 2009 Jo-Philipp Wich <xm@subsignal.org>
5 *
6 * The fwd program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * The fwd program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with the fwd program. If not, see http://www.gnu.org/licenses/.
17 */
18
19
20 #include "fwd.h"
21 #include "fwd_addr.h"
22 #include "fwd_rules.h"
23 #include "fwd_config.h"
24 #include "fwd_xtables.h"
25 #include "fwd_ipc.h"
26 #include "fwd_utils.h"
27
28
29 static void fwd_foreach_network(
30 struct fwd_handle *h,
31 void (*cb)(struct fwd_handle *h, struct fwd_network *net)
32 ) {
33 struct fwd_data *data;
34 struct fwd_network *net;
35
36 for( data = h->conf; data; data = data->next )
37 {
38 if( data->type != FWD_S_ZONE )
39 continue;
40
41 for( net = data->section.zone.networks; net; net = net->next )
42 cb(h, net);
43 }
44 }
45
46 static void fwd_addif_all_cb(struct fwd_handle *h, struct fwd_network *net)
47 {
48 fwd_ipt_addif(h, net->name);
49 }
50
51 static void fwd_delif_all_cb(struct fwd_handle *h, struct fwd_network *net)
52 {
53 fwd_ipt_delif(h, net->name);
54 }
55
56 #define fwd_addif_all(h) fwd_foreach_network(h, fwd_addif_all_cb)
57 #define fwd_delif_all(h) fwd_foreach_network(h, fwd_delif_all_cb)
58
59
60 static int fwd_server_main(int argc, const char *argv[])
61 {
62 struct fwd_handle *h;
63 struct fwd_network *net;
64 struct fwd_addr *addrs;
65 struct fwd_data *data;
66 struct fwd_cidr *addr_old, *addr_new;
67 struct sigaction sa;
68 int unix_client;
69
70 sa.sa_handler = SIG_IGN;
71 sigaction(SIGPIPE, &sa, NULL);
72
73 if( getuid() > 0 )
74 fwd_fatal("Need root permissions!");
75
76 if( !(h = fwd_alloc_ptr(struct fwd_handle)) )
77 fwd_fatal("Out of memory");
78
79 if( (h->rtnl_socket = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1 )
80 fwd_fatal("Failed to create AF_NETLINK socket (%m)");
81
82 if( (h->unix_socket = fwd_ipc_listen()) == -1 )
83 fwd_fatal("Failed to create AF_UNIX socket (%m)");
84
85 if( !(h->conf = fwd_read_config(h)) )
86 fwd_fatal("Failed to read configuration");
87
88 fwd_log_init();
89
90 fwd_ipt_build_ruleset(h);
91 fwd_addif_all(h);
92
93 while(1)
94 {
95 if( (addrs = fwd_get_addrs(h->rtnl_socket, AF_INET)) != NULL )
96 {
97 for( data = h->conf; data; data = data->next )
98 {
99 if( data->type != FWD_S_ZONE )
100 continue;
101
102 for( net = data->section.zone.networks; net; net = net->next )
103 {
104 addr_new = fwd_lookup_addr(addrs, net->ifname);
105 addr_old = net->addr;
106
107 if( !fwd_empty_cidr(addr_new) && fwd_empty_cidr(addr_old) )
108 {
109 fwd_log_info(
110 "Interface %s brought up - adding rules",
111 net->ifname
112 );
113
114 fwd_update_cidr(addr_old, addr_new);
115 fwd_ipt_addif(h, net->name);
116 }
117 else if( fwd_empty_cidr(addr_new) && !fwd_empty_cidr(addr_old) )
118 {
119 fwd_log_info(
120 "Interface %s went down - removing rules",
121 net->ifname
122 );
123
124 fwd_update_cidr(addr_old, NULL);
125 fwd_ipt_delif(h, net->name);
126 }
127 else if( ! fwd_equal_cidr(addr_old, addr_new) )
128 {
129 fwd_log_info(
130 "Interface %s changed IP - rebuilding rules",
131 net->ifname
132 );
133
134 fwd_update_cidr(addr_old, addr_new);
135 fwd_ipt_chgif(h, net->name);
136 }
137 }
138 }
139
140 fwd_free_addrs(addrs);
141 }
142
143
144 if( (unix_client = fwd_ipc_accept(h->unix_socket)) > -1 )
145 {
146 struct fwd_ipc_msg msg;
147 memset(&msg, 0, sizeof(struct fwd_ipc_msg));
148
149 while( fwd_ipc_recvmsg(unix_client, &msg, sizeof(struct fwd_ipc_msg)) > 0 )
150 {
151 fwd_log_info("Got message [%i]", msg.type);
152
153 switch(msg.type)
154 {
155 case FWD_IPC_FLUSH:
156 fwd_log_info("Flushing rules ...");
157 fwd_ipt_clear_ruleset(h);
158 fwd_ipc_sendtype(unix_client, FWD_IPC_OK);
159 break;
160
161 case FWD_IPC_BUILD:
162 fwd_log_info("Building rules ...");
163 fwd_ipt_clear_ruleset(h);
164 fwd_ipt_build_ruleset(h);
165 fwd_addif_all(h);
166 fwd_ipc_sendtype(unix_client, FWD_IPC_OK);
167 break;
168
169 case FWD_IPC_RELOAD:
170 if( (data = fwd_read_config(h)) != NULL )
171 {
172 fwd_log_info("Flushing rules ...");
173 fwd_ipt_clear_ruleset(h);
174 fwd_free_config(h->conf);
175 h->conf = data;
176 fwd_log_info("Building rules ...");
177 fwd_ipt_build_ruleset(h);
178 fwd_addif_all(h);
179 fwd_ipc_sendtype(unix_client, FWD_IPC_OK);
180 }
181 else
182 {
183 fwd_log_err("Cannot reload configuration!");
184 fwd_ipc_sendtype(unix_client, FWD_IPC_ERROR);
185 }
186 break;
187
188 case FWD_IPC_ADDIF:
189 case FWD_IPC_DELIF:
190 if( strlen(msg.data.network) > 0 )
191 {
192 fwd_ipt_delif(h, msg.data.network);
193
194 if( msg.type == FWD_IPC_ADDIF )
195 fwd_ipt_addif(h, msg.data.network);
196
197 fwd_ipc_sendtype(unix_client, FWD_IPC_OK);
198 }
199 else
200 {
201 fwd_log_err("No network name provided!");
202 fwd_ipc_sendtype(unix_client, FWD_IPC_ERROR);
203 }
204 break;
205
206 case FWD_IPC_OK:
207 case FWD_IPC_ERROR:
208 break;
209 }
210 }
211
212 fwd_ipc_shutdown(unix_client);
213 }
214
215
216 sleep(1);
217 }
218
219 fwd_delif_all(h);
220 fwd_ipt_clear_ruleset(h);
221
222 close(h->rtnl_socket);
223 fwd_free_config(h->conf);
224 fwd_free_ptr(h);
225
226 return 0;
227 }
228
229 static void fwd_client_usage(const char *msg)
230 {
231 printf(
232 "%s\n\n"
233 "Usage:\n"
234 " fw flush\n"
235 " Flush all rules in the firewall and reset policy\n\n"
236 " fw build\n"
237 " Rebuild firewall rules\n\n"
238 " fw reload\n"
239 " Reload configuration and rebuild firewall rules\n\n"
240 " fw addif {network}\n"
241 " Add rules for given network\n\n"
242 " fw delif {network}\n"
243 " Remove rules for given network\n\n"
244 "", msg
245 );
246
247 exit(1);
248 }
249
250 static int fwd_client_main(int argc, const char *argv[])
251 {
252 int unix_server;
253 struct fwd_ipc_msg msg;
254 enum fwd_ipc_msgtype type;
255
256 if( argc < 2 )
257 fwd_client_usage("Command required");
258
259 if( (unix_server = fwd_ipc_connect()) < 0 )
260 fwd_fatal("Cannot connect to server instance (%m)");
261
262
263 memset(&msg, 0, sizeof(struct fwd_ipc_msg));
264
265 if( !strcmp(argv[1], "flush") )
266 type = FWD_IPC_FLUSH;
267
268 else if( !strcmp(argv[1], "build") )
269 type = FWD_IPC_BUILD;
270
271 else if( !strcmp(argv[1], "reload") )
272 type = FWD_IPC_RELOAD;
273
274 else if( !strcmp(argv[1], "addif") || !strcmp(argv[1], "delif") )
275 {
276 if( argc < 3 )
277 fwd_client_usage("The command requires a parameter.");
278
279 type = strcmp(argv[1], "addif") ? FWD_IPC_DELIF : FWD_IPC_ADDIF;
280 strncpy(msg.data.network, argv[2], sizeof(msg.data.network));
281 }
282
283 else
284 fwd_client_usage("Invalid command given.");
285
286 msg.type = type;
287 fwd_ipc_sendmsg(unix_server, &msg, sizeof(struct fwd_ipc_msg));
288
289 memset(&msg, 0, sizeof(struct fwd_ipc_msg));
290
291 while( fwd_ipc_recvmsg(unix_server, &msg, sizeof(struct fwd_ipc_msg)) == 0 )
292 continue;
293
294 switch(msg.type)
295 {
296 case FWD_IPC_OK:
297 printf("Success\n");
298 break;
299
300 case FWD_IPC_ERROR:
301 printf("The server reported an error, check logread!\n");
302 break;
303
304 default:
305 fwd_fatal("Unexpected response type %i", msg.type);
306 }
307
308 fwd_ipc_shutdown(unix_server);
309
310 return 0;
311 }
312
313 int main(int argc, const char *argv[])
314 {
315 if( strstr(argv[0], "fwd") )
316 return fwd_server_main(argc, argv);
317 else
318 return fwd_client_main(argc, argv);
319 }
320