authsrv.c

Go to the documentation of this file.
00001 /*
00002  ** Copyright (C) 2002-2008 INL
00003  ** Written by Éric Leblond <eric@regit.org>
00004  **            Vincent Deffontaines <vincent@gryzor.com>
00005  ** INL http://www.inl.fr/
00006  **
00007  ** $Id: authsrv.c 5217 2008-11-19 14:07:08Z pollux $
00008  **
00009  ** This program is free software; you can redistribute it and/or modify
00010  ** it under the terms of the GNU General Public License as published by
00011  ** the Free Software Foundation, version 3 of the License.
00012  **
00013  ** This program is distributed in the hope that it will be useful,
00014  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  ** GNU General Public License for more details.
00017  **
00018  ** You should have received a copy of the GNU General Public License
00019  ** along with this program; if not, write to the Free Software
00020  ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00021  */
00022 
00023 #include "nufw.h"
00024 
00025 #include <nubase.h>
00026 
00027 /* Mutex used to lock acces to nfqueue or ipqueue (see strcture.h) */
00028 pthread_mutex_t ipq_mutex = PTHREAD_MUTEX_INITIALIZER;
00029 
00040 int auth_process_answer(char *dgram, int dgram_size)
00041 {
00042         nuv4_nuauth_decision_response_t *answer;
00043         uint32_t nfmark;
00044         int sandf;
00045         u_int32_t packet_id;
00046         int payload_len;
00047 
00048         /* check packet size */
00049         if (dgram_size < (int) sizeof(nuv4_nuauth_decision_response_t)) {
00050                 return -1;
00051         }
00052         answer = (nuv4_nuauth_decision_response_t *) dgram;
00053 
00054         /* check payload length */
00055         payload_len = ntohs(answer->payload_len);
00056         if (dgram_size <
00057             (int) (sizeof(nuv4_nuauth_decision_response_t) + payload_len)
00058             || ((payload_len != 0) && (payload_len != (20 + 8))
00059                 && (payload_len != (40 + 8)))) {
00060                 log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_WARNING,
00061                                 "[!] Packet with improper size");
00062                 return -1;
00063         }
00064 
00065         /* get packet id and user id */
00066         packet_id = ntohl(answer->packet_id);
00067 
00068         /* search and destroy packet by packet_id */
00069         pthread_mutex_lock(&packets_list.mutex);
00070         sandf = psearch_and_destroy(packet_id, &nfmark);
00071         pthread_mutex_unlock(&packets_list.mutex);
00072         if (!sandf) {
00073                 log_area_printf(DEBUG_AREA_GW | DEBUG_AREA_GW,
00074                                 DEBUG_LEVEL_WARNING,
00075                                 "[!] Packet without a known ID: %u",
00076                                 packet_id);
00077                 return -1;
00078         }
00079 
00080         switch (answer->decision) {
00081         case DECISION_ACCEPT:
00082                 /* accept packet */
00083                 debug_log_printf(DEBUG_AREA_PACKET,
00084                                  DEBUG_LEVEL_VERBOSE_DEBUG,
00085                                  "(*) Accepting packet with id=%u",
00086                                  packet_id);
00087 #if HAVE_LIBIPQ_MARK || USE_NFQUEUE
00088                 if (nufw_set_mark) {
00089                         debug_log_printf(DEBUG_AREA_PACKET,
00090                                          DEBUG_LEVEL_VERBOSE_DEBUG,
00091                                          "(*) Marking packet with %d",
00092                                          ntohl(answer->tcmark));
00093                         IPQ_SET_VWMARK(packet_id, NF_ACCEPT,
00094                                        answer->tcmark);
00095                 } else {
00096                         IPQ_SET_VERDICT(packet_id, NF_ACCEPT);
00097                 }
00098 #else
00099                 IPQ_SET_VERDICT(packet_id, NF_ACCEPT);
00100 #endif                          /* HAVE_LIBIPQ_MARK || USE_NFQUEUE */
00101                 pckt_tx++;
00102                 break;
00103 
00104         case DECISION_REJECT:
00105                 /* Packet is rejected, ie. dropped and ICMP signalized */
00106                 log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_VERBOSE_DEBUG,
00107                                 "(*) Rejecting %" PRIu32, packet_id);
00108                 IPQ_SET_VERDICT(packet_id, NF_DROP);
00109                 if (send_icmp_unreach(dgram +
00110                                   sizeof(nuv4_nuauth_decision_response_t)) == -1) {
00111                         log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_WARNING,
00112                                         "(*) Could not sent ICMP reject for %" PRIu32, packet_id);
00113                 }
00114                 break;
00115 
00116         default:
00117                 /* drop packet */
00118                 debug_log_printf(DEBUG_AREA_PACKET,
00119                                  DEBUG_LEVEL_VERBOSE_DEBUG,
00120                                  "(*) Drop packet %u", packet_id);
00121                 IPQ_SET_VERDICT(packet_id, NF_DROP);
00122         }
00123         return sizeof(nuv4_nuauth_decision_response_t) + payload_len;
00124 }
00125 
00126 #ifdef HAVE_LIBCONNTRACK
00127 
00128 int build_nfct_tuple_from_message(struct nfct_tuple *orig,
00129                                   struct nuv4_conntrack_message_t
00130                                   *packet_hdr)
00131 {
00132         orig->protonum = packet_hdr->ip_protocol;
00133         if (is_ipv4(&packet_hdr->ip_src) && is_ipv4(&packet_hdr->ip_dst)) {
00134                 orig->l3protonum = AF_INET;
00135                 orig->src.v4 = packet_hdr->ip_src.s6_addr32[3];
00136                 orig->dst.v4 = packet_hdr->ip_dst.s6_addr32[3];
00137         } else {
00138                 orig->l3protonum = AF_INET6;
00139                 memcpy(&orig->src.v6, &packet_hdr->ip_src,
00140                        sizeof(orig->src.v6));
00141                 memcpy(&orig->dst.v6, &packet_hdr->ip_dst,
00142                        sizeof(orig->dst.v6));
00143         }
00144 
00145         switch (packet_hdr->ip_protocol) {
00146         case IPPROTO_TCP:
00147                 orig->l4src.tcp.port = packet_hdr->src_port;
00148                 orig->l4dst.tcp.port = packet_hdr->dest_port;
00149                 break;
00150         case IPPROTO_UDP:
00151                 orig->l4src.udp.port = packet_hdr->src_port;
00152                 orig->l4dst.udp.port = packet_hdr->dest_port;
00153                 break;
00154         default:
00155                 return 0;
00156         }
00157         return 1;
00158 
00159 }
00160 
00164 int auth_process_conn_destroy(char *dgram, int dgram_size)
00165 {
00166         struct nuv4_conntrack_message_t *packet_hdr;
00167         struct nfct_tuple orig;
00168         int id = 0;
00169 
00170         /* check packet size */
00171         if (dgram_size < (int) sizeof(struct nuv4_conntrack_message_t)) {
00172                 return -1;
00173         }
00174 
00175         packet_hdr = (struct nuv4_conntrack_message_t *) dgram;
00176 
00177         if (ntohs(packet_hdr->msg_length) != sizeof(struct nuv4_conntrack_message_t)) {
00178                 return -1;
00179         }
00180 
00181         if (build_nfct_tuple_from_message(&orig, packet_hdr)) {
00182                 debug_log_printf(DEBUG_AREA_GW | DEBUG_AREA_PACKET,
00183                                  DEBUG_LEVEL_VERBOSE_DEBUG,
00184                                  "Deleting entry from conntrack after NuAuth request");
00185                 (void) nfct_delete_conntrack(cth, &orig, NFCT_DIR_ORIGINAL,
00186                                              id);
00187         }
00188         return ntohs(packet_hdr->msg_length);
00189 }
00190 
00194 int auth_process_conn_update(char *dgram, int dgram_size)
00195 {
00196         struct nuv4_conntrack_message_t *packet_hdr;
00197         struct nfct_conntrack *ct;
00198         struct nfct_tuple orig;
00199         struct nfct_tuple reply;
00200         union nfct_protoinfo proto;
00201 
00202 
00203         /* check packet size */
00204         if (dgram_size < (int) sizeof(struct nuv4_conntrack_message_t)) {
00205                 debug_log_printf(DEBUG_AREA_GW, DEBUG_LEVEL_DEBUG,
00206                                  "NuAuth sent too small message");
00207                 return -1;
00208         }
00209         packet_hdr = (struct nuv4_conntrack_message_t *) dgram;
00210 
00211         if (ntohs(packet_hdr->msg_length) != sizeof(struct nuv4_conntrack_message_t)) {
00212                 return -1;
00213         }
00214 
00215         if (build_nfct_tuple_from_message(&orig, packet_hdr)) {
00216                 /* generate reply : this is stupid but done by conntrack tool */
00217                 memset(&reply, 0, sizeof(reply));
00218                 reply.l3protonum = orig.l3protonum;
00219 #if 0
00220                 /* we set it to 0 to avoid problem  with NAT */
00221                 memset(&reply.src, 0, sizeof(reply.src));
00222                 memset(&reply.dst, 0, sizeof(reply.dst));
00223 
00224                 memset(&reply.l4src, 0, sizeof(reply.l4src));
00225                 memset(&reply.l4dst, 0, sizeof(reply.l4dst));
00226 #endif
00227 
00228 
00229                 proto.tcp.state = 3;
00230 
00231 #ifdef  HAVE_LIBCONNTRACK_FIXEDTIMEOUT
00232                 ct = nfct_conntrack_alloc(&orig, &reply, 0,
00233                                           &proto,
00234                                           IPS_ASSURED | IPS_SEEN_REPLY |
00235                                           IPS_FIXED_TIMEOUT, 0, 0, NULL);
00236 #else
00237                 ct = nfct_conntrack_alloc(&orig, &reply, 0,
00238                                           &proto,
00239                                           IPS_ASSURED | IPS_SEEN_REPLY, 0,
00240                                           0, NULL);
00241 #endif
00242 #ifdef HAVE_LIBCONNTRACK_FIXEDTIMEOUT
00243                 if (packet_hdr->timeout) {
00244                         debug_log_printf(DEBUG_AREA_GW,
00245                                          DEBUG_LEVEL_VERBOSE_DEBUG,
00246                                          "Setting timeout to %d after NuAuth request",
00247                                          ntohl(packet_hdr->timeout));
00248                         ct->timeout = ntohl(packet_hdr->timeout);
00249                 }
00250 #endif                          /* HAVE_LIBCONNTRACK_FIXEDTIMEOUT */
00251 
00252                 if (nfct_update_conntrack(cth, ct) != 0) {
00253                         log_area_printf(DEBUG_AREA_MAIN,
00254                                         DEBUG_LEVEL_WARNING,
00255                                         "Conntrack update was impossible");
00256 
00257                 }
00258                 nfct_conntrack_free(ct);
00259         }
00260         return ntohs(packet_hdr->msg_length);
00261 }
00262 #endif                          /* HAVE_LIBCONNTRACK */
00263 
00274 static int auth_packet_to_decision(char *dgram, int dgram_size)
00275 {
00276         if (dgram_size < 2) {
00277                 debug_log_printf(DEBUG_AREA_GW, DEBUG_LEVEL_DEBUG,
00278                                  "NuAuth sent too small message");
00279                 return -1;
00280         }
00281 
00282         if (dgram[0] != PROTO_NUFW_VERSION) {
00283                 debug_log_printf(DEBUG_AREA_GW, DEBUG_LEVEL_DEBUG,
00284                                  "Wrong protocol version from authentication server answer.");
00285                 return -1;
00286         }
00287 
00288         switch (dgram[1]) {
00289         case AUTH_ANSWER:
00290                 return auth_process_answer(dgram, dgram_size);
00291 #ifdef HAVE_LIBCONNTRACK
00292         case AUTH_CONN_DESTROY:
00293                 return auth_process_conn_destroy(dgram, dgram_size);
00294         case AUTH_CONN_UPDATE:
00295                 return auth_process_conn_update(dgram, dgram_size);
00296 #else
00297         case AUTH_CONN_DESTROY:
00298                 log_area_printf(DEBUG_AREA_MAIN | DEBUG_AREA_GW,
00299                                 DEBUG_LEVEL_WARNING,
00300                                 "Connection destroy message not supported");
00301                 break;
00302         case AUTH_CONN_UPDATE:
00303                 log_area_printf(DEBUG_AREA_MAIN | DEBUG_AREA_GW,
00304                                 DEBUG_LEVEL_WARNING,
00305                                 "Connection update message not supported");
00306                 break;
00307 #endif
00308         default:
00309                 log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_DEBUG,
00310                                 "NuAuth message type %d not for me",
00311                                 dgram[1]);
00312                 break;
00313         }
00314         return -1;
00315 }
00316 
00321 void *authsrv(void *data)
00322 {
00323         int ret;
00324         int read_size;
00325         char cdgram[512];
00326         char *dgram = cdgram;
00327 
00328         log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_VERBOSE_DEBUG,
00329                         "[+] Start auth server thread");
00330 
00331         while (pthread_mutex_trylock(&tls.auth_server_mutex) == 0) {
00332                 pthread_mutex_unlock(&tls.auth_server_mutex);
00333 
00334                 /* memset(dgram, 0, sizeof dgram); */
00335                 pthread_mutex_lock(&tls.mutex);
00336                 if (tls.session)
00337                         ret = nussl_read(tls.session, dgram, sizeof cdgram);
00338                 else
00339                         ret = 0;
00340                 pthread_mutex_unlock(&tls.mutex);
00341                 if (ret == NUSSL_SOCK_TIMEOUT)
00342                 {
00343                         usleep(10000); /* Without that, the other thread can't get the lock to tls.mutex */
00344                         continue;
00345                 }
00346                 if (ret <= 0) {
00347                         log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_VERBOSE_DEBUG,
00348                                         "Error during nussl_read: %s", nussl_get_error(tls.session));
00349                         break;
00350                 } else {
00351                         do {
00352                                 read_size = auth_packet_to_decision(dgram, ret);
00353                                 ret -= read_size;
00354                                 dgram = dgram + read_size;
00355                         } while (ret > 0 && (read_size != -1));
00356                 }
00357 
00358                 dgram = cdgram;
00359         }
00360 
00361         log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_VERBOSE_DEBUG,
00362                         "[+] Leave auth server thread");
00363 
00364         pthread_mutex_lock(&tls.mutex);
00365         /* warn sender thread that it will need to reconnect at next access */
00366         tls.auth_server_running = 0;
00367         pthread_mutex_unlock(&tls.mutex);
00368         pthread_exit(NULL);
00369 }

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