]>
git.ipfire.org Git - 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 client_curr
= (client_t
*)malloc(sizeof(client_t
));
75 memset(client_curr
, 0, sizeof(client_t
));
77 if (client_first
== NULL
)
78 client_first
= client_curr
;
80 client_last
->next
= client_curr
;
81 client_last
= client_curr
;
83 unsigned int count
= 0;
90 while (*lineptr
!= '\0') {
91 if (*lineptr
== ',') {
102 strcpy(client_curr
->etheraddr
, word
);
107 strcpy(client_curr
->ipaddr
, word
);
112 client_curr
->time_start
= parse_time(word
);
117 client_curr
->expires
= atoi(word
);
132 static void flush_chains() {
134 safe_system(IPTABLES
" -F CAPTIVE_PORTAL");
135 safe_system(IPTABLES
" -F CAPTIVE_PORTAL_CLIENTS");
138 safe_system(IPTABLES
" -t nat -F CAPTIVE_PORTAL");
141 static int add_client_rules(const client_t
* clients
) {
142 char command
[STRING_SIZE
];
143 char match
[STRING_SIZE
];
146 time_t expires
= clients
->time_start
+ clients
->expires
;
148 char* time_start
= format_time(&clients
->time_start
);
149 char* time_end
= format_time(&expires
);
153 if (*clients
->ipaddr
) {
154 len
+= snprintf(match
+ len
, sizeof(match
) - len
,
155 "-s %s", clients
->ipaddr
);
158 len
+= snprintf(match
+ len
, sizeof(match
) - len
,
159 " -m mac --mac-source %s -m time --datestart %s --datestop %s",
160 clients
->etheraddr
, time_start
, time_end
);
166 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS"
167 " %s -j RETURN", match
);
168 safe_system(command
);
171 snprintf(command
, sizeof(command
), IPTABLES
" -t nat -A CAPTIVE_PORTAL"
172 " %s -j RETURN", match
);
173 safe_system(command
);
175 // Move on to the next client
176 clients
= clients
->next
;
182 static char* get_key(struct keyvalue
* settings
, char* key
) {
183 char value
[STRING_SIZE
];
185 if (!findkey(settings
, key
, value
))
188 return strdup(value
);
191 static int add_interface_rule(const char* intf
, int allow_webif_access
) {
193 char command
[STRING_SIZE
];
195 if ((intf
== NULL
) || (strlen(intf
) == 0)) {
196 fprintf(stderr
, "Empty interface given\n");
200 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL -i %s"
201 " -j CAPTIVE_PORTAL_CLIENTS", intf
);
202 r
= safe_system(command
);
207 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL -o %s"
208 " -j CAPTIVE_PORTAL_CLIENTS", intf
);
209 r
= safe_system(command
);
214 if (allow_webif_access
) {
215 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS"
216 " -i %s -p tcp --dport 444 -j RETURN", intf
);
217 r
= safe_system(command
);
222 // Redirect all unauthenticated clients
223 snprintf(command
, sizeof(command
), IPTABLES
" -t nat -A CAPTIVE_PORTAL -i %s"
224 " -p tcp --dport %d -j REDIRECT --to-ports %d", intf
, HTTP_PORT
, REDIRECT_PORT
);
225 r
= safe_system(command
);
232 static int add_interface_rules(struct keyvalue
* captive_portal_settings
, struct keyvalue
* ethernet_settings
) {
237 setting
= get_key(captive_portal_settings
, "ENABLE_GREEN");
238 if (setting
&& (strcmp(setting
, "on") == 0)) {
241 intf
= get_key(ethernet_settings
, "GREEN_DEV");
242 r
= add_interface_rule(intf
, /* allow webif access from green */ 1);
247 setting
= get_key(captive_portal_settings
, "ENABLE_BLUE");
248 if (setting
&& (strcmp(setting
, "on") == 0)) {
251 intf
= get_key(ethernet_settings
, "BLUE_DEV");
252 r
= add_interface_rule(intf
, /* do not allow webif access */ 0);
257 // Always pass DNS packets through all firewall rules
258 r
= safe_system(IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS -p udp --dport 53 -j RETURN");
262 r
= safe_system(IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS -p tcp --dport 53 -j RETURN");
266 char command
[STRING_SIZE
];
267 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS"
268 " -p tcp --dport %d -j RETURN", REDIRECT_PORT
);
269 r
= safe_system(command
);
274 r
= safe_system(IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS -j DROP");
281 int main(int argc
, char** argv
) {
284 client_t
* clients
= NULL
;
289 struct keyvalue
* ethernet_settings
= initkeyvalues();
290 if (!readkeyvalues(ethernet_settings
, ETHERNET_SETTINGS
)) {
291 fprintf(stderr
, "Could not read %s\n", ETHERNET_SETTINGS
);
296 struct keyvalue
* captive_portal_settings
= initkeyvalues();
297 if (!readkeyvalues(captive_portal_settings
, CAPTIVE_PORTAL_SETTINGS
)) {
298 fprintf(stderr
, "Could not read %s\n", CAPTIVE_PORTAL_SETTINGS
);
303 clients
= read_clients(CLIENTS
);
305 // Clean up all old rules
308 // Add all client rules
309 r
= add_client_rules(clients
);
313 // Add all interface rules
314 r
= add_interface_rules(captive_portal_settings
, ethernet_settings
);
320 client_t
* head
= clients
;
321 clients
= clients
->next
;
326 if (ethernet_settings
)
327 freekeyvalues(ethernet_settings
);
329 if (captive_portal_settings
)
330 freekeyvalues(captive_portal_settings
);