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