common.c

Go to the documentation of this file.
00001 /*
00002 **
00003 ** Copyright 2002 - 2007 INL
00004 ** Written by Eric Leblond <eric@regit.org>
00005 **            Vincent Deffontaines <vincent@gryzor.com>
00006 ** INL http://www.inl.fr/
00007 **
00008 ** $Id: common.c 5287 2008-11-21 16:09:26Z pollux $
00009 **
00010 ** This program is free software; you can redistribute it and/or modify
00011 ** it under the terms of the GNU General Public License as published by
00012 ** the Free Software Foundation, version 3 of the License.
00013 **
00014 ** This program is distributed in the hope that it will be useful,
00015 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 ** GNU General Public License for more details.
00018 **
00019 ** You should have received a copy of the GNU General Public License
00020 ** along with this program; if not, write to the Free Software
00021 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00022 */
00023 
00031 #include "nufw.h"
00032 
00033 #include <stdlib.h>
00034 #include <time.h>
00035 #include <linux/icmp.h>         /* icmphdr */
00036 #include <netinet/icmp6.h>      /* icmp6_hdr */
00037 #include <netinet/ip.h>         /* iphdr */
00038 #include <netinet/ip6.h>        /* ip6_hdr */
00039 
00040 #include <nubase.h>
00041 
00042 
00043 /* data stuff */
00044 
00045 #ifdef PERF_DISPLAY_ENABLE
00046 
00051 int timeval_substract(struct timeval *result, struct timeval *x,
00052                       struct timeval *y)
00053 {
00054         /* Perform the carry for the later subtraction by updating y. */
00055         if (x->tv_usec < y->tv_usec) {
00056                 int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
00057                 y->tv_usec -= 1000000 * nsec;
00058                 y->tv_sec += nsec;
00059         }
00060         if (x->tv_usec - y->tv_usec > 1000000) {
00061                 int nsec = (x->tv_usec - y->tv_usec) / 1000000;
00062                 y->tv_usec += 1000000 * nsec;
00063                 y->tv_sec -= nsec;
00064         }
00065 
00066         /* Compute the time remaining to wait.
00067          *           tv_usec is certainly positive. */
00068         result->tv_sec = x->tv_sec - y->tv_sec;
00069         result->tv_usec = x->tv_usec - y->tv_usec;
00070 
00071         /* Return 1 if result is negative. */
00072         return x->tv_sec < y->tv_sec;
00073 }
00074 #endif
00075 
00079 void close_tls_session()
00080 {
00081         if (tls.session == NULL)
00082                 return;
00083 
00084         pthread_mutex_destroy(&tls.auth_server_mutex);
00085         nussl_session_destroy(tls.session);
00086         tls.session = NULL;
00087 }
00088 
00095 void psuppress(packet_idl * previous, packet_idl * current)
00096 {
00097         if (previous != NULL)
00098                 previous->next = current->next;
00099         else
00100                 packets_list.start = current->next;
00101         if (current->next == NULL) {
00102                 packets_list.end = previous;
00103         }
00104         free(current);
00105         packets_list.length--;
00106 }
00107 
00114 unsigned long padd(packet_idl * current)
00115 {
00116         if (track_size <= packets_list.length) {
00117                 log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_WARNING,
00118                                 "Warning: queue is full, dropping element");
00119                 IPQ_SET_VERDICT(current->id, NF_DROP);
00120                 return 0;
00121         }
00122 
00123         packets_list.length++;
00124         current->next = NULL;
00125 
00126         if (current->timestamp == 0) {
00127                 current->timestamp = time(NULL);
00128         }
00129 
00130         if (packets_list.end != NULL)
00131                 packets_list.end->next = current;
00132         packets_list.end = current;
00133         if (packets_list.start == NULL)
00134                 packets_list.start = current;
00135         return current->id;
00136 }
00137 
00138 
00139 /* called by authsrv */
00140 
00148 int psearch_and_destroy(uint32_t packet_id, uint32_t * nfmark)
00149 {
00150         packet_idl *current = packets_list.start, *previous = NULL;
00151         int timestamp = time(NULL);
00152 
00155         while (current != NULL) {
00156                 if (current->id == packet_id) {
00157 #if HAVE_LIBIPQ_MARK || USE_NFQUEUE
00158                         *nfmark = current->nfmark;
00159 #endif
00160 
00161 #ifdef PERF_DISPLAY_ENABLE
00162                         {
00163                                 struct timeval elapsed_time, leave_time;
00164                                 double ms;
00165                                 gettimeofday(&leave_time, NULL);
00166                                 timeval_substract(&elapsed_time,
00167                                                   &leave_time,
00168                                                   &(current->
00169                                                     arrival_time));
00170                                 ms = (double) elapsed_time.tv_sec * 1000 +
00171                                     (double) elapsed_time.tv_usec / 1000;
00172                                 log_area_printf(DEBUG_AREA_PACKET,
00173                                                 DEBUG_LEVEL_INFO,
00174                                                 "Treatment time for connection: %.1f ms",
00175                                                 ms);
00176                         }
00177 #endif
00178 
00179 
00180                         psuppress(previous, current);
00181                         return 1;
00182 
00183                         /* we want to suppress first element if it is too old */
00184                 } else if (timestamp - current->timestamp > packet_timeout) {
00185                         IPQ_SET_VERDICT(current->id, NF_DROP);
00186                         debug_log_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_INFO,
00187                                          "Dropped: %lu", current->id);
00188                         psuppress(previous, current);
00189                         current = packets_list.start;
00190                         previous = NULL;
00191                 } else {
00192                         previous = current;
00193                         current = current->next;
00194                 }
00195         }
00196         return 0;
00197 }
00198 
00202 void clear_packet_list()
00203 {
00204         packet_idl *current = packets_list.start, *next;
00205         while (current != NULL) {
00206                 next = current->next;
00207                 free(current);
00208                 current = next;
00209         }
00210         packets_list.start = NULL;
00211         packets_list.end = NULL;
00212         packets_list.length = 0;
00213 }
00214 
00218 void clean_old_packets()
00219 {
00220         packet_idl *current = packets_list.start, *previous = NULL;
00221         int timestamp = time(NULL);
00222 
00223         while (current != NULL) {
00224                 /* we want to suppress first element if it is too old */
00225                 if (timestamp - current->timestamp > packet_timeout) {
00226                         IPQ_SET_VERDICT(current->id, NF_DROP);
00227                         debug_log_printf(DEBUG_AREA_PACKET,
00228                                          DEBUG_LEVEL_DEBUG, "Dropped: %lu",
00229                                          current->id);
00230                         psuppress(previous, current);
00231                         current = packets_list.start;
00232                         previous = NULL;
00233                 } else {
00234                         current = NULL;
00235                 }
00236         }
00237 }
00238 
00239 
00240 /*
00241  * Copy taken from hping2 project, original comment was:
00242  * "from R. Stevens's Network Programming"
00243  */
00244 __u16 icmp_cksum(__u16 * buf, int nbytes)
00245 {
00246         __u32 sum;
00247         __u16 oddbyte;
00248 
00249         sum = 0;
00250         while (nbytes > 1) {
00251                 sum += *buf++;
00252                 nbytes -= 2;
00253         }
00254 
00255         if (nbytes == 1) {
00256                 oddbyte = 0;
00257                 *((__u16 *) & oddbyte) = *(__u16 *) buf;
00258                 sum += oddbyte;
00259         }
00260 
00261         sum = (sum >> 16) + (sum & 0xffff);
00262         sum += (sum >> 16);
00263 
00264         return (__u16) ~ sum;
00265 }
00266 
00267 int send_icmp_ipv4_unreach(char *payload)
00268 {
00269         struct sockaddr_in to;
00270         char buffer[sizeof(struct icmphdr) + 20 + 8];
00271         struct iphdr *ip = (struct iphdr *) payload;
00272         struct icmphdr *icmp = (struct icmphdr *) buffer;
00273 
00274         /* write ICMP header */
00275         icmp->type = 3;
00276         icmp->code = 0;
00277         icmp->checksum = 0x0000;
00278         icmp->un.frag.__unused = 0;
00279         icmp->un.frag.mtu = 0;
00280 
00281         /* copy old packet header */
00282         memcpy(buffer + sizeof(struct icmphdr), payload, 20 + 8);
00283 
00284         /* get destination IPv4 address */
00285         memset(&to, 0, sizeof(to));
00286         to.sin_family = AF_INET;
00287         to.sin_addr.s_addr = ip->saddr;
00288 
00289         /* compute icmp checksum */
00290         icmp->checksum = icmp_cksum((__u16 *) buffer, sizeof(buffer));
00291 
00292         /* send packet */
00293         return sendto(raw_sock4, buffer, sizeof(buffer), 0,
00294                       (struct sockaddr *) &to, sizeof(to));
00295 }
00296 
00297 int send_icmp_ipv6_unreach(char *payload)
00298 {
00299         struct sockaddr_in6 to;
00300         char buffer[sizeof(struct icmp6_hdr) + 40 + 8];
00301         struct ip6_hdr *ip = (struct ip6_hdr *) payload;
00302         struct icmp6_hdr *icmp = (struct icmp6_hdr *) buffer;
00303 
00304         /* write ICMP header */
00305         memset(icmp, 0, sizeof(*icmp));
00306         icmp->icmp6_type = 1;
00307         icmp->icmp6_code = 0;
00308         /* checksum and data are nul */
00309 
00310         /* copy old packet header */
00311         memcpy(buffer + sizeof(*icmp), payload, 40 + 8);
00312 
00313         /* get destination IPv6 address */
00314         memset(&to, 0, sizeof(to));
00315         to.sin6_family = AF_INET6;
00316         to.sin6_addr = ip->ip6_src;
00317 
00318 #ifdef LINUX
00319         /* don't compute icmp checksum, Linux do it for us */
00320 #else
00321 #  error "You may compute the checksum!"
00322 #endif
00323 
00324         if (raw_sock6 > 0) {
00325                 /* send packet */
00326                 return sendto(raw_sock6, buffer, sizeof(buffer), 0,
00327                               (struct sockaddr *) &to, sizeof(to));
00328         } else {
00329                 return 0;
00330         }
00331 }
00332 
00333 int send_icmp_unreach(char *payload)
00334 {
00335         struct iphdr *ip4 = (struct iphdr *) payload;
00336         if (ip4->version == AF_INET) {
00337                 return send_icmp_ipv4_unreach(payload);
00338         } else {
00339                 return send_icmp_ipv6_unreach(payload);
00340         }
00341 }

Generated on Sat Nov 22 04:00:38 2008 for NuFW by  doxygen 1.4.7