Forward Firewall: support for SNAT/DNAT in GUI and rules.pl
[people/teissler/ipfire-2.x.git] / src / misc-progs / setportfw.c
CommitLineData
cd1a2927
MT
1/* SmoothWall helper program - setportfw\r
2 *\r
3 * This program is distributed under the terms of the GNU General Public\r
4 * Licence. See the file COPYING for details.\r
5 *\r
6 * (c) Daniel Goscomb, 2001\r
7 * Copyright (c) 2002/04/13 Steve Bootes - Added source ip support for aliases\r
8 * \r
9 * Modifications and improvements by Lawrence Manning.\r
10 *\r
11 * 10/04/01 Aslak added protocol support\r
12 * This program reads the list of ports to forward and setups iptables\r
13 * and rules in ipmasqadm to enable them.\r
14 *\r
15 * 02/11/03 Darren Critchley modifications to allow it to open multiple\r
16 * source ip addresses\r
17 * 02/25/03 Darren Critchley modifications to allow port ranges\r
18 * 04/01/03 Darren Critchley modifications to allow gre protocol\r
19 * 20/04/03 Robert Kerr Fixed root exploit, validated all variables properly,\r
20 * tidied up the iptables logic, killed duplicated code,\r
21 * removed srciptmp (unecessary)\r
22 *\r
23 * $Id: setportfw.c,v 1.3.2.6 2005/08/24 18:44:19 gespinasse Exp $\r
24 * \r
25 */\r
26\r
27#include <stdio.h>\r
28#include <string.h>\r
29#include <stdlib.h>\r
30#include "libsmooth.h"\r
31#include "setuid.h"\r
32\r
33struct keyvalue *kv = NULL;\r
34FILE *fwdfile = NULL;\r
35\r
36void exithandler(void)\r
37{\r
38 if(kv)\r
39 freekeyvalues(kv);\r
40 if (fwdfile)\r
41 fclose(fwdfile);\r
42}\r
43\r
44int main(void)\r
45{\r
46 FILE *ipfile = NULL, *ifacefile = NULL;\r
47 int count;\r
6bd5e314
AF
48 char iface[STRING_SIZE] ="";
49 char locip[STRING_SIZE] ="";
50 char greenip[STRING_SIZE] ="", greenmask[STRING_SIZE] ="";
51 char bluedev[STRING_SIZE] ="", blueip[STRING_SIZE] ="", bluemask[STRING_SIZE] ="";
52 char orangedev[STRING_SIZE] ="", orangeip[STRING_SIZE] ="", orangemask[STRING_SIZE] ="";
cd1a2927
MT
53 char *protocol;\r
54 char *srcip;\r
55 char *locport;\r
56 char *remip;\r
57 char *remport;\r
58 char *origip;\r
59 char *enabled;\r
60 char s[STRING_SIZE];\r
61 char *result;\r
62 char *key1;\r
63 char *key2;\r
64 char command[STRING_SIZE];\r
65\r
66 if (!(initsetuid()))\r
67 exit(1);\r
68\r
69 atexit(exithandler);\r
70\r
71 /* Read in and verify config */\r
72 kv=initkeyvalues();\r
73\r
74 if (!readkeyvalues(kv, CONFIG_ROOT "/ethernet/settings"))\r
75 {\r
76 fprintf(stderr, "Cannot read ethernet settings\n");\r
77 exit(1);\r
78 }\r
79\r
80 if (!findkey(kv, "GREEN_ADDRESS", greenip))\r
81 {\r
82 fprintf(stderr, "Cannot read GREEN_ADDRESS\n");\r
83 exit(1);\r
84 }\r
85\r
86 if (!VALID_IP(greenip))\r
87 {\r
88 fprintf(stderr, "Bad GREEN_ADDRESS: %s\n", greenip);\r
89 exit(1);\r
90 }\r
91\r
92 if (!findkey(kv, "GREEN_NETMASK", greenmask))\r
93 {\r
94 fprintf(stderr, "Cannot read GREEN_NETMASK\n");\r
95 exit(1);\r
96 }\r
97\r
98 if (!VALID_IP(greenmask))\r
99 {\r
100 fprintf(stderr, "Bad GREEN_NETMASK: %s\n", greenmask);\r
101 exit(1);\r
102 }\r
103\r
104 /* Get the BLUE interface details */\r
105 findkey(kv, "BLUE_DEV", bluedev);\r
106\r
107 if (strlen(bluedev))\r
108 {\r
109\r
110 if (!VALID_DEVICE(bluedev))\r
111 {\r
112 fprintf(stderr, "Bad BLUE_DEV: %s\n", bluedev);\r
113 exit(1);\r
114 }\r
115\r
116 if (!findkey(kv, "BLUE_ADDRESS", blueip))\r
117 {\r
118 fprintf(stderr, "Cannot read BLUE_ADDRESS\n");\r
119 exit(1);\r
120 }\r
121\r
122 if (!VALID_IP(blueip))\r
123 {\r
124 fprintf(stderr, "Bad BLUE_ADDRESS: %s\n", blueip);\r
125 exit(1);\r
126 }\r
127\r
128 if (!findkey(kv, "BLUE_NETMASK", bluemask))\r
129 {\r
130 fprintf(stderr, "Cannot read BLUE_NETMASK\n");\r
131 exit(1);\r
132 }\r
133\r
134 if (!VALID_IP(bluemask))\r
135 {\r
136 fprintf(stderr, "Bad BLUE_NETMASK: %s\n", bluemask);\r
137 exit(1);\r
138 }\r
139\r
140 }\r
141\r
142 /* Get the ORANGE interface details */\r
143 findkey(kv, "ORANGE_DEV", orangedev);\r
144\r
145 if (strlen(orangedev))\r
146 {\r
147\r
148 if (!VALID_DEVICE(orangedev))\r
149 {\r
150 fprintf(stderr, "Bad ORANGE_DEV: %s\n", orangedev);\r
151 exit(1);\r
152 }\r
153\r
154 if (!findkey(kv, "ORANGE_ADDRESS", orangeip))\r
155 {\r
156 fprintf(stderr, "Cannot read ORANGE_ADDRESS\n");\r
157 exit(1);\r
158 }\r
159\r
160 if (!VALID_IP(orangeip))\r
161 {\r
162 fprintf(stderr, "Bad ORANGE_ADDRESS: %s\n", orangeip);\r
163 exit(1);\r
164 }\r
165\r
166 if (!findkey(kv, "ORANGE_NETMASK", orangemask))\r
167 {\r
168 fprintf(stderr, "Cannot read ORANGE_NETMASK\n");\r
169 exit(1);\r
170 }\r
171\r
172 if (!VALID_IP(orangemask))\r
173 {\r
174 fprintf(stderr, "Bad ORANGE_NETMASK: %s\n", orangemask);\r
175 exit(1);\r
176 }\r
177\r
178 }\r
179\r
180\r
181 if (!(ipfile = fopen(CONFIG_ROOT "/red/local-ipaddress", "r")))\r
182 {\r
183 fprintf(stderr, "Couldn't open local ip file\n");\r
184 exit(1);\r
185 }\r
186 fgets(locip, STRING_SIZE, ipfile);\r
187 if (locip[strlen(locip) - 1] == '\n')\r
188 locip[strlen(locip) - 1] = '\0';\r
189 fclose (ipfile);\r
190 if (!VALID_IP(locip))\r
191 {\r
192 fprintf(stderr, "Bad local IP: %s\n", locip);\r
193 exit(1);\r
194 }\r
195 \r
196 if (!(ifacefile = fopen(CONFIG_ROOT "/red/iface", "r")))\r
197 {\r
198 fprintf(stderr, "Couldn't open iface file\n");\r
199 exit(1);\r
200 }\r
201 fgets(iface, STRING_SIZE, ifacefile);\r
202 if (iface[strlen(iface) - 1] == '\n')\r
203 iface[strlen(iface) - 1] = '\0';\r
204 fclose (ifacefile);\r
205 if (!VALID_DEVICE(iface))\r
206 {\r
207 fprintf(stderr, "Bad iface: %s\n", iface);\r
208 exit(1);\r
209 }\r
210 \r
211 if (!(fwdfile = fopen(CONFIG_ROOT "/portfw/config", "r")))\r
212 {\r
213 fprintf(stderr, "Couldn't open portfw settings file\n");\r
214 exit(1);\r
215 }\r
216\r
217 safe_system("/sbin/iptables -t nat -F PORTFW");\r
218 safe_system("/sbin/iptables -t mangle -F PORTFWMANGLE");\r
219 safe_system("/sbin/iptables -F PORTFWACCESS");\r
220\r
221 while (fgets(s, STRING_SIZE, fwdfile) != NULL)\r
222 {\r
223 if (s[strlen(s) - 1] == '\n')\r
224 s[strlen(s) - 1] = '\0';\r
225 result = strtok(s, ",");\r
226\r
227 count = 0;\r
228 key1 = NULL;\r
229 key2 = NULL;\r
230 protocol = NULL;\r
231 srcip = NULL;\r
232 locport = NULL;\r
233 remip = NULL;\r
234 origip = NULL;\r
235 remport = NULL;\r
236 enabled = NULL;\r
237 while (result)\r
238 {\r
239 if (count == 0)\r
240 key1 = result;\r
241 else if (count == 1)\r
242 key2 = result;\r
243 else if (count == 2)\r
244 protocol = result;\r
245 else if (count == 3)\r
246 locport = result;\r
247 else if (count == 4)\r
248 remip = result;\r
249 else if (count == 5)\r
250 remport = result;\r
251 else if (count == 6)\r
252 enabled = result;\r
253 else if (count == 7)\r
254 srcip = result;\r
255 else if (count == 8)\r
256 origip = result;\r
257 count++;\r
258 result = strtok(NULL, ",");\r
259 }\r
260 \r
261 if (!(key1 && key2 && protocol && locport && remip && remport && enabled\r
262 && srcip && origip))\r
263 break;\r
264 \r
265 if (!VALID_PROTOCOL(protocol))\r
266 {\r
267 fprintf(stderr, "Bad protocol: %s\n", protocol);\r
268 exit(1);\r
269 }\r
270 if (strcmp(protocol, "gre") == 0)\r
271 {\r
272 locport = "0";\r
273 remport = "0";\r
274 }\r
275 if (strcmp(origip,"0") && !VALID_IP_AND_MASK(origip))\r
276 {\r
277 fprintf(stderr, "Bad IP: %s\n", origip);\r
278 exit(1);\r
279 }\r
280 if (!VALID_PORT_RANGE(locport))\r
281 {\r
282 fprintf(stderr, "Bad local port: %s\n", locport);\r
283 exit(1);\r
284 }\r
285 if (!VALID_IP(remip))\r
286 {\r
287 fprintf(stderr, "Bad remote IP: %s\n", remip);\r
288 exit(1);\r
289 }\r
290 if (!VALID_PORT_RANGE(remport))\r
291 {\r
292 fprintf(stderr, "Bad remote port: %s\n", remport);\r
293 exit(1);\r
294 }\r
295\r
296 /* check for source ip in config file. If it's there\r
297 * and it's not 0.0.0.0, use it; else use the\r
298 * local ip address. (This makes sure we can use old-style\r
299 * config files without the source ip) */\r
300 if (!srcip || !strcmp(srcip, "0.0.0.0"))\r
301 srcip = locip;\r
302 if (strcmp(srcip,"0") && !VALID_IP(srcip))\r
303 {\r
304 fprintf(stderr, "Bad source IP: %s\n", srcip);\r
305 exit(1);\r
306 }\r
307\r
308 /* This may seem complicated... refer to portfw.pl for an explanation of\r
309 * the keys and their meaning in certain circumstances */\r
310 \r
311 if (strcmp(enabled, "on") == 0)\r
312 {\r
313\r
314 /* If key2 is a zero, then it is a portfw command, otherwise it is an\r
315 * external access command */\r
316 if (strcmp(key2, "0") == 0) \r
317 {\r
318 memset(command, 0, STRING_SIZE);\r
319 if (strcmp(protocol, "gre") == 0)\r
320 snprintf(command, STRING_SIZE - 1, "/sbin/iptables -t nat -A PORTFW -p %s -d %s -j DNAT --to %s", protocol, srcip, remip);\r
321 else \r
322 {\r
323 char *ctr;\r
324 /* If locport contains a - we need to change it to a : */\r
325 if ((ctr = strchr(locport, '-')) != NULL) {*ctr = ':';}\r
326 /* If remport contains a : we need to change it to a - */\r
327 if ((ctr = strchr(remport,':')) != NULL){*ctr = '-';}\r
328 snprintf(command, STRING_SIZE - 1, "/sbin/iptables -t nat -A PORTFW -p %s -d %s --dport %s -j DNAT --to %s:%s", protocol, srcip, locport, remip, remport);\r
329 safe_system(command);\r
330 /* Now if remport contains a - we need to change it to a : */\r
331 if ((ctr = strchr(remport,'-')) != NULL){*ctr = ':';}\r
332 snprintf(command, STRING_SIZE - 1, "/sbin/iptables -t mangle -A PORTFWMANGLE -p %s -s %s/%s -d %s --dport %s -j MARK --set-mark 1", protocol, greenip, greenmask, srcip, locport);\r
333 if (strlen(bluedev))\r
334 {\r
335 safe_system(command);\r
336 snprintf(command, STRING_SIZE - 1, "/sbin/iptables -t mangle -A PORTFWMANGLE -p %s -s %s/%s -d %s --dport %s -j MARK --set-mark 2", protocol, blueip, bluemask, srcip, locport);\r
337 }\r
338 if (strlen(orangedev))\r
339 {\r
340 safe_system(command);\r
341 snprintf(command, STRING_SIZE - 1, "/sbin/iptables -t mangle -A PORTFWMANGLE -p %s -s %s/%s -d %s --dport %s -j MARK --set-mark 3", protocol, orangeip, orangemask, srcip, locport);\r
342 }\r
343 }\r
344 safe_system(command);\r
345 }\r
346\r
347 /* if key2 is not "0" then it's an external access rule, if key2 is "0"\r
348 * then the portfw rule may contain external access information if origip\r
349 * is not "0" (the only defined not 0 value seems to be 0.0.0.0 - open\r
350 * to all; again, check portfw.pl for more details) */\r
351 if(strcmp(key2, "0") || strcmp(origip,"0") )\r
352 {\r
353 memset(command, 0, STRING_SIZE);\r
354 if (strcmp(protocol, "gre") == 0)\r
355 snprintf(command, STRING_SIZE - 1, "/sbin/iptables -A PORTFWACCESS -i %s -p %s -s %s -d %s -j ACCEPT", iface, protocol, origip, remip);\r
356 else\r
357 {\r
358 char *ctr;\r
359 /* If remport contains a - we need to change it to a : */\r
360 if ((ctr = strchr(remport,'-')) != NULL){*ctr = ':';}\r
361 snprintf(command, STRING_SIZE - 1, "/sbin/iptables -A PORTFWACCESS -i %s -p %s -s %s -d %s --dport %s -j ACCEPT", iface, protocol, origip, remip, remport);\r
362 }\r
363 safe_system(command);\r
364 }\r
365 }\r
366 }\r
367\r
368 return 0;\r
369}\r