00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00031 #define _GNU_SOURCE
00032
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <syslog.h>
00036 #include <errno.h>
00037 #include <pthread.h>
00038 #include <sys/wait.h>
00039 #include <sys/types.h>
00040 #include <sys/unistd.h>
00041
00042 #include <string.h>
00043
00044 #include <sys/socket.h>
00045 #include <netinet/in.h>
00046 #include <arpa/inet.h>
00047 #include <unistd.h>
00048 #include <sys/uio.h>
00049 #include <fcntl.h>
00050 #include <netdb.h>
00051 #include <sys/time.h>
00052
00053 #ifdef __linux__
00054 #include <net/ethernet.h>
00055 #include <netinet/ip.h>
00056 #include <netinet/ip_icmp.h>
00057 #include <netpacket/packet.h>
00058 #endif
00059
00060 #include "httpd.h"
00061 #include "safe.h"
00062 #include "debug.h"
00063 #include "conf.h"
00064 #include "firewall.h"
00065 #include "fw_iptables.h"
00066 #include "auth.h"
00067 #include "centralserver.h"
00068 #include "client_list.h"
00069
00070 extern pthread_mutex_t client_list_mutex;
00071
00072
00073 extern pid_t restart_orig_pid;
00074
00075
00076
00085 int
00086 fw_allow(char *ip, char *mac, int fw_connection_state)
00087 {
00088 debug(LOG_DEBUG, "Allowing %s %s with fw_connection_state %d", ip, mac, fw_connection_state);
00089
00090 return iptables_fw_access(FW_ACCESS_ALLOW, ip, mac, fw_connection_state);
00091 }
00092
00100 int
00101 fw_deny(char *ip, char *mac, int fw_connection_state)
00102 {
00103 debug(LOG_DEBUG, "Denying %s %s with fw_connection_state %d", ip, mac, fw_connection_state);
00104
00105 return iptables_fw_access(FW_ACCESS_DENY, ip, mac, fw_connection_state);
00106 }
00107
00114 char *
00115 arp_get(char *req_ip)
00116 {
00117 FILE *proc;
00118 char ip[16];
00119 char mac[18];
00120 char * reply = NULL;
00121
00122 if (!(proc = fopen("/proc/net/arp", "r"))) {
00123 return NULL;
00124 }
00125
00126
00127 while (!feof(proc) && fgetc(proc) != '\n');
00128
00129
00130 reply = NULL;
00131 while (!feof(proc) && (fscanf(proc, " %15[0-9.] %*s %*s %17[A-F0-9:] %*s %*s", ip, mac) == 2)) {
00132 if (strcmp(ip, req_ip) == 0) {
00133 reply = safe_strdup(mac);
00134 break;
00135 }
00136 }
00137
00138 fclose(proc);
00139
00140 return reply;
00141 }
00142
00145 int
00146 fw_init(void)
00147 {
00148 int flags, oneopt = 1, zeroopt = 0;
00149 int result = 0;
00150 t_client * client = NULL;
00151
00152 debug(LOG_INFO, "Creating ICMP socket");
00153 if ((icmp_fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1 ||
00154 (flags = fcntl(icmp_fd, F_GETFL, 0)) == -1 ||
00155 fcntl(icmp_fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
00156 setsockopt(icmp_fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) ||
00157 setsockopt(icmp_fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1) {
00158 debug(LOG_ERR, "Cannot create ICMP raw socket.");
00159 return;
00160 }
00161
00162 debug(LOG_INFO, "Initializing Firewall");
00163 result = iptables_fw_init();
00164
00165 if (restart_orig_pid) {
00166 debug(LOG_INFO, "Restoring firewall rules for clients inherited from parent");
00167 LOCK_CLIENT_LIST();
00168 client = client_get_first_client();
00169 while (client) {
00170 fw_allow(client->ip, client->mac, client->fw_connection_state);
00171 client = client->next;
00172 }
00173 UNLOCK_CLIENT_LIST();
00174 }
00175
00176 return result;
00177 }
00178
00181 void
00182 fw_clear_authservers(void)
00183 {
00184 debug(LOG_INFO, "Clearing the authservers list");
00185 iptables_fw_clear_authservers();
00186 }
00187
00190 void
00191 fw_set_authservers(void)
00192 {
00193 debug(LOG_INFO, "Setting the authservers list");
00194 iptables_fw_set_authservers();
00195 }
00196
00201 int
00202 fw_destroy(void)
00203 {
00204 if (icmp_fd != 0) {
00205 debug(LOG_INFO, "Closing ICMP socket");
00206 close(icmp_fd);
00207 }
00208
00209 debug(LOG_INFO, "Removing Firewall rules");
00210 return iptables_fw_destroy();
00211 }
00212
00216 void
00217 fw_sync_with_authserver(void)
00218 {
00219 t_authresponse authresponse;
00220 char *token, *ip, *mac;
00221 t_client *p1, *p2;
00222 unsigned long long incoming, outgoing;
00223 s_config *config = config_get_config();
00224
00225 if (-1 == iptables_fw_counters_update()) {
00226 debug(LOG_ERR, "Could not get counters from firewall!");
00227 return;
00228 }
00229
00230 LOCK_CLIENT_LIST();
00231
00232 for (p1 = p2 = client_get_first_client(); NULL != p1; p1 = p2) {
00233 p2 = p1->next;
00234
00235 ip = safe_strdup(p1->ip);
00236 token = safe_strdup(p1->token);
00237 mac = safe_strdup(p1->mac);
00238 outgoing = p1->counters.outgoing;
00239 incoming = p1->counters.incoming;
00240
00241 UNLOCK_CLIENT_LIST();
00242
00243
00244
00245
00246 icmp_ping(ip);
00247
00248 if (config->auth_servers != NULL) {
00249 auth_server_request(&authresponse, REQUEST_TYPE_COUNTERS, ip, mac, token, incoming, outgoing);
00250 }
00251 LOCK_CLIENT_LIST();
00252
00253 if (!(p1 = client_list_find(ip, mac))) {
00254 debug(LOG_ERR, "Node %s was freed while being re-validated!", ip);
00255 } else {
00256 time_t current_time=time(NULL);
00257 debug(LOG_INFO, "Checking client %s for timeout: Last updated %ld (%ld seconds ago), timeout delay %ld seconds, current time %ld, ",
00258 p1->ip, p1->counters.last_updated, current_time-p1->counters.last_updated, config->checkinterval * config->clienttimeout, current_time);
00259 if (p1->counters.last_updated +
00260 (config->checkinterval * config->clienttimeout)
00261 <= current_time) {
00262
00263 debug(LOG_INFO, "%s - Inactive for more than %ld seconds, removing client and denying in firewall",
00264 p1->ip, config->checkinterval * config->clienttimeout);
00265 fw_deny(p1->ip, p1->mac, p1->fw_connection_state);
00266 client_list_delete(p1);
00267
00268
00269 if (config->auth_servers != NULL) {
00270 UNLOCK_CLIENT_LIST();
00271 auth_server_request(&authresponse, REQUEST_TYPE_LOGOUT, ip, mac, token, 0, 0);
00272 LOCK_CLIENT_LIST();
00273 }
00274 } else {
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284 if (config->auth_servers != NULL) {
00285 switch (authresponse.authcode) {
00286 case AUTH_DENIED:
00287 debug(LOG_NOTICE, "%s - Denied. Removing client and firewall rules", p1->ip);
00288 fw_deny(p1->ip, p1->mac, p1->fw_connection_state);
00289 client_list_delete(p1);
00290 break;
00291
00292 case AUTH_VALIDATION_FAILED:
00293 debug(LOG_NOTICE, "%s - Validation timeout, now denied. Removing client and firewall rules", p1->ip);
00294 fw_deny(p1->ip, p1->mac, p1->fw_connection_state);
00295 client_list_delete(p1);
00296 break;
00297
00298 case AUTH_ALLOWED:
00299 if (p1->fw_connection_state != FW_MARK_KNOWN) {
00300 debug(LOG_INFO, "%s - Access has changed to allowed, refreshing firewall and clearing counters", p1->ip);
00301
00302
00303
00304 if (p1->fw_connection_state != FW_MARK_PROBATION) {
00305 p1->counters.incoming = p1->counters.outgoing = 0;
00306 }
00307 else {
00308
00309 debug(LOG_INFO, "%s - Skipped clearing counters after all, the user was previously in validation", p1->ip);
00310 }
00311 p1->fw_connection_state = FW_MARK_KNOWN;
00312 fw_allow(p1->ip, p1->mac, p1->fw_connection_state);
00313 }
00314 break;
00315
00316 case AUTH_VALIDATION:
00317
00318
00319
00320
00321
00322 debug(LOG_INFO, "%s - User in validation period", p1->ip);
00323 break;
00324
00325 case AUTH_ERROR:
00326 debug(LOG_WARNING, "Error communicating with auth server - leaving %s as-is for now", p1->ip);
00327 break;
00328
00329 default:
00330 debug(LOG_ERR, "I do not know about authentication code %d", authresponse.authcode);
00331 break;
00332 }
00333 }
00334 }
00335 }
00336
00337 free(token);
00338 free(ip);
00339 free(mac);
00340 }
00341 UNLOCK_CLIENT_LIST();
00342 }
00343
00344 void icmp_ping(char *host) {
00345 struct sockaddr_in saddr;
00346 #ifdef __linux__
00347 struct {
00348 struct ip ip;
00349 struct icmp icmp;
00350 } packet;
00351 #endif
00352 unsigned int i, j;
00353 int opt = 2000;
00354 unsigned short id = rand16();
00355
00356 saddr.sin_family = AF_INET;
00357 saddr.sin_port = 0;
00358 inet_aton(host, &saddr.sin_addr);
00359 #ifdef HAVE_SOCKADDR_SA_LEN
00360 saddr.sin_len = sizeof(struct sockaddr_in);
00361 #endif
00362
00363 memset(&(saddr.sin_zero), '\0', sizeof(saddr.sin_zero));
00364
00365 #ifdef __linux__
00366 memset(&packet.icmp, 0, sizeof(packet.icmp));
00367 packet.icmp.icmp_type = ICMP_ECHO;
00368 packet.icmp.icmp_id = id;
00369 for (j = 0, i = 0; i < sizeof(struct icmp) / 2; i++)
00370 j += ((unsigned short *)&packet.icmp)[i];
00371 while (j>>16)
00372 j = (j & 0xffff) + (j >> 16);
00373 packet.icmp.icmp_cksum = (j == 0xffff) ? j : ~j;
00374
00375 if (setsockopt(icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) == -1) {
00376 debug(LOG_ERR, "setsockopt(): %s", strerror(errno));
00377 }
00378 if (sendto(icmp_fd, (char *)&packet.icmp, sizeof(struct icmp), 0, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
00379 debug(LOG_ERR, "sendto(): %s", strerror(errno));
00380 }
00381 opt = 1;
00382 if (setsockopt(icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) == -1) {
00383 debug(LOG_ERR, "setsockopt(): %s", strerror(errno));
00384 }
00385 #endif
00386
00387 return;
00388 }
00389
00390 unsigned short rand16(void) {
00391 static int been_seeded = 0;
00392
00393 if (!been_seeded) {
00394 int fd, n = 0;
00395 unsigned int c = 0, seed = 0;
00396 char sbuf[sizeof(seed)];
00397 char *s;
00398 struct timeval now;
00399
00400
00401 gettimeofday(&now, NULL);
00402 seed = now.tv_sec ^ now.tv_usec ^ (getpid() << 16);
00403
00404 srand(seed);
00405 been_seeded = 1;
00406 }
00407
00408
00409
00410
00411
00412
00413 return( (unsigned short) (rand() >> 15) );
00414 }