]>
git.ipfire.org Git - ipfire-2.x.git/blob - src/misc-progs/captivectrl.c
1ca2a59117d110ba4843a93af0fd4b0768688303
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
];
148 if (*clients
->ipaddr
&& clients
->expires
> 0) {
149 len
+= snprintf(match
+ len
, sizeof(match
) - len
,
150 "-s %s", clients
->ipaddr
);
153 len
+= snprintf(match
+ len
, sizeof(match
) - len
,
154 " -m mac --mac-source %s", clients
->etheraddr
);
156 if (clients
->expires
> 0) {
157 time_t expires
= clients
->time_start
+ clients
->expires
;
159 char* time_start
= format_time(&clients
->time_start
);
160 char* time_end
= format_time(&expires
);
162 len
+= snprintf(match
+ len
, sizeof(match
) - len
,
163 " -m time --datestart %s --datestop %s",
164 time_start
, time_end
);
171 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS"
172 " %s -j RETURN", match
);
173 safe_system(command
);
176 snprintf(command
, sizeof(command
), IPTABLES
" -t nat -A CAPTIVE_PORTAL"
177 " %s -j RETURN", match
);
178 safe_system(command
);
180 // Move on to the next client
181 clients
= clients
->next
;
187 static char* get_key(struct keyvalue
* settings
, char* key
) {
188 char value
[STRING_SIZE
];
190 if (!findkey(settings
, key
, value
))
193 return strdup(value
);
196 static int add_interface_rule(const char* intf
, int allow_webif_access
) {
198 char command
[STRING_SIZE
];
200 if ((intf
== NULL
) || (strlen(intf
) == 0)) {
201 fprintf(stderr
, "Empty interface given\n");
205 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL -i %s"
206 " -j CAPTIVE_PORTAL_CLIENTS", intf
);
207 r
= safe_system(command
);
212 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL -o %s"
213 " -j CAPTIVE_PORTAL_CLIENTS", intf
);
214 r
= safe_system(command
);
219 if (allow_webif_access
) {
220 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS"
221 " -i %s -p tcp --dport 444 -j RETURN", intf
);
222 r
= safe_system(command
);
227 // Redirect all unauthenticated clients
228 snprintf(command
, sizeof(command
), IPTABLES
" -t nat -A CAPTIVE_PORTAL -i %s"
229 " -p tcp --dport %d -j REDIRECT --to-ports %d", intf
, HTTP_PORT
, REDIRECT_PORT
);
230 r
= safe_system(command
);
237 static int add_interface_rules(struct keyvalue
* captive_portal_settings
, struct keyvalue
* ethernet_settings
) {
242 setting
= get_key(captive_portal_settings
, "ENABLE_GREEN");
243 if (setting
&& (strcmp(setting
, "on") == 0)) {
246 intf
= get_key(ethernet_settings
, "GREEN_DEV");
247 r
= add_interface_rule(intf
, /* allow webif access from green */ 1);
252 setting
= get_key(captive_portal_settings
, "ENABLE_BLUE");
253 if (setting
&& (strcmp(setting
, "on") == 0)) {
256 intf
= get_key(ethernet_settings
, "BLUE_DEV");
257 r
= add_interface_rule(intf
, /* do not allow webif access */ 0);
262 // Always pass DNS packets through all firewall rules
263 r
= safe_system(IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS -p udp --dport 53 -j RETURN");
267 r
= safe_system(IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS -p tcp --dport 53 -j RETURN");
271 char command
[STRING_SIZE
];
272 snprintf(command
, sizeof(command
), IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS"
273 " -p tcp --dport %d -j RETURN", REDIRECT_PORT
);
274 r
= safe_system(command
);
279 r
= safe_system(IPTABLES
" -A CAPTIVE_PORTAL_CLIENTS -j DROP");
286 int main(int argc
, char** argv
) {
289 client_t
* clients
= NULL
;
294 struct keyvalue
* ethernet_settings
= initkeyvalues();
295 if (!readkeyvalues(ethernet_settings
, ETHERNET_SETTINGS
)) {
296 fprintf(stderr
, "Could not read %s\n", ETHERNET_SETTINGS
);
301 struct keyvalue
* captive_portal_settings
= initkeyvalues();
302 if (!readkeyvalues(captive_portal_settings
, CAPTIVE_PORTAL_SETTINGS
)) {
303 fprintf(stderr
, "Could not read %s\n", CAPTIVE_PORTAL_SETTINGS
);
308 clients
= read_clients(CLIENTS
);
310 // Clean up all old rules
313 // Add all client rules
314 r
= add_client_rules(clients
);
318 // Add all interface rules
319 r
= add_interface_rules(captive_portal_settings
, ethernet_settings
);
325 client_t
* head
= clients
;
326 clients
= clients
->next
;
331 if (ethernet_settings
)
332 freekeyvalues(ethernet_settings
);
334 if (captive_portal_settings
)
335 freekeyvalues(captive_portal_settings
);