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