]>
git.ipfire.org Git - people/dweismueller/ipfire-2.x.git/blob - src/misc-progs/captivectrl.c
1 /* This file is part of the IPFire Firewall.
3 * This program is distributed under the terms of the GNU General Public
4 * Licence. See the file COPYING for details. */
14 #include "libsmooth.h"
17 #define CAPTIVE_PORTAL_SETTINGS CONFIG_ROOT "/captive/settings"
18 #define ETHERNET_SETTINGS CONFIG_ROOT "/ethernet/settings"
20 #define CLIENTS CONFIG_ROOT "/captive/clients"
21 #define IPTABLES "/sbin/iptables --wait"
23 #define REDIRECT_PORT 1013
25 typedef struct client
{
26 char etheraddr
[STRING_SIZE
];
27 char ipaddr
[STRING_SIZE
];
34 static time_t parse_time(const char* s
) {
37 if (sscanf(s
, "%d", &t
) == 1) {
44 static char* format_time(const time_t* t
) {
45 char buffer
[STRING_SIZE
];
47 struct tm
* tm
= gmtime(t
);
51 strftime(buffer
, sizeof(buffer
), "%Y-%m-%dT%H:%M", tm
);
53 return strdup(buffer
);
56 static client_t
* read_clients(char* filename
) {
59 if (!(f
= fopen(filename
, "r"))) {
60 fprintf(stderr
, "Could not open configuration file: %s\n", filename
);
64 char line
[STRING_SIZE
];
66 client_t
* client_first
= NULL
;
67 client_t
* client_last
= NULL
;
68 client_t
* client_curr
;
70 while ((fgets(line
, STRING_SIZE
, f
) != NULL
)) {
71 if (line
[strlen(line
) - 1] == '\n')
72 line
[strlen(line
) - 1] = '\0';
74 // Skip all commented lines
78 client_curr
= (client_t
*)malloc(sizeof(client_t
));
79 memset(client_curr
, 0, sizeof(client_t
));
81 if (client_first
== NULL
)
82 client_first
= client_curr
;
84 client_last
->next
= client_curr
;
85 client_last
= client_curr
;
87 unsigned int count
= 0;
94 while (*lineptr
!= '\0') {
95 if (*lineptr
== ',') {
106 strcpy(client_curr
->etheraddr
, word
);
111 strcpy(client_curr
->ipaddr
, word
);
116 client_curr
->time_start
= parse_time(word
);
121 client_curr
->expires
= atoi(word
);
136 static void flush_chains() {
138 safe_system(IPTABLES
" -F CAPTIVE_PORTAL");
139 safe_system(IPTABLES
" -F CAPTIVE_PORTAL_CLIENTS");
142 safe_system(IPTABLES
" -t nat -F CAPTIVE_PORTAL");
145 static int setup_dns_filters() {
146 const char* protos
[] = { "udp", "tcp", NULL
};
148 // Limits the number of DNS requests to 3 kByte/s
149 // A burst of 1MB is permitted at the start
150 const char* limiter
= "-m hashlimit --hashlimit-name dns-filter"
151 " --hashlimit-mode srcip --hashlimit-upto 3kb/sec --hashlimit-burst 1024kb";
153 char command
[STRING_SIZE
];
155 const char** proto
= protos
;
157 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS -p %s"
158 " --dport 53 %s -j RETURN", *proto
, limiter
);
160 int r
= safe_system(command
);
170 static int add_client_rules(const client_t
* clients
) {
171 char command
[STRING_SIZE
];
172 char match
[STRING_SIZE
];
177 if (*clients
->ipaddr
&& clients
->expires
> 0) {
178 len
+= snprintf(match
+ len
, sizeof(match
) - len
,
179 "-s %s", clients
->ipaddr
);
182 len
+= snprintf(match
+ len
, sizeof(match
) - len
,
183 " -m mac --mac-source %s", clients
->etheraddr
);
185 if (clients
->expires
> 0) {
186 time_t expires
= clients
->time_start
+ clients
->expires
;
188 char* time_start
= format_time(&clients
->time_start
);
189 char* time_end
= format_time(&expires
);
191 len
+= snprintf(match
+ len
, sizeof(match
) - len
,
192 " -m time --datestart %s --datestop %s",
193 time_start
, time_end
);
200 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS"
201 " %s -j RETURN", match
);
202 safe_system(command
);
205 snprintf(command
, sizeof(command
), IPTABLES
" -t nat -A CAPTIVE_PORTAL"
206 " %s -j RETURN", match
);
207 safe_system(command
);
209 // Move on to the next client
210 clients
= clients
->next
;
216 static char* get_key(struct keyvalue
* settings
, char* key
) {
217 char value
[STRING_SIZE
];
219 if (!findkey(settings
, key
, value
))
222 return strdup(value
);
225 static int add_interface_rule(const char* intf
, int allow_webif_access
) {
227 char command
[STRING_SIZE
];
229 if ((intf
== NULL
) || (strlen(intf
) == 0)) {
230 fprintf(stderr
, "Empty interface given\n");
234 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL -i %s"
235 " -j CAPTIVE_PORTAL_CLIENTS", intf
);
236 r
= safe_system(command
);
241 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL -o %s"
242 " -j CAPTIVE_PORTAL_CLIENTS", intf
);
243 r
= safe_system(command
);
248 if (allow_webif_access
) {
249 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS"
250 " -i %s -p tcp --dport 444 -j RETURN", intf
);
251 r
= safe_system(command
);
256 // Redirect all unauthenticated clients
257 snprintf(command
, sizeof(command
), IPTABLES
" -t nat -A CAPTIVE_PORTAL -i %s"
258 " -p tcp --dport %d -j REDIRECT --to-ports %d", intf
, HTTP_PORT
, REDIRECT_PORT
);
259 r
= safe_system(command
);
263 // Allow access to captive portal site
264 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS"
265 " -d %s -p tcp --dport %d -j RETURN", intf
, REDIRECT_PORT
);
266 r
= safe_system(command
);
273 static int add_interface_rules(struct keyvalue
* captive_portal_settings
, struct keyvalue
* ethernet_settings
) {
278 setting
= get_key(captive_portal_settings
, "ENABLE_GREEN");
279 if (setting
&& (strcmp(setting
, "on") == 0)) {
282 intf
= get_key(ethernet_settings
, "GREEN_DEV");
283 r
= add_interface_rule(intf
, /* allow webif access from green */ 1);
288 setting
= get_key(captive_portal_settings
, "ENABLE_BLUE");
289 if (setting
&& (strcmp(setting
, "on") == 0)) {
292 intf
= get_key(ethernet_settings
, "BLUE_DEV");
293 r
= add_interface_rule(intf
, /* do not allow webif access */ 0);
298 // Always pass DNS packets through all firewall rules
299 r
= setup_dns_filters();
304 r
= safe_system(IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS -j DROP");
311 int main(int argc
, char** argv
) {
314 client_t
* clients
= NULL
;
316 struct keyvalue
* captive_portal_settings
= NULL
;
317 struct keyvalue
* ethernet_settings
= NULL
;
322 ethernet_settings
= initkeyvalues();
323 if (!readkeyvalues(ethernet_settings
, ETHERNET_SETTINGS
)) {
324 fprintf(stderr
, "Could not read %s\n", ETHERNET_SETTINGS
);
329 captive_portal_settings
= initkeyvalues();
330 if (!readkeyvalues(captive_portal_settings
, CAPTIVE_PORTAL_SETTINGS
)) {
331 fprintf(stderr
, "Could not read %s\n", CAPTIVE_PORTAL_SETTINGS
);
336 clients
= read_clients(CLIENTS
);
338 // Clean up all old rules
341 // Add all client rules
342 r
= add_client_rules(clients
);
346 // Add all interface rules
347 r
= add_interface_rules(captive_portal_settings
, ethernet_settings
);
353 client_t
* head
= clients
;
354 clients
= clients
->next
;
359 if (ethernet_settings
)
360 freekeyvalues(ethernet_settings
);
362 if (captive_portal_settings
)
363 freekeyvalues(captive_portal_settings
);