ha.c

Go to the documentation of this file.
00001 /* 
00002  * Dynamic hierarchial IP tunnel
00003  *
00004  * Copyright (C) 1998-2001, Dynamics group, Russ Dill (UDHCP),Tero 
00005  * Hätinen, Joni Purojärvi & Antti Pyykkönen (DYNAMO GPOUP) 
00006  *
00007  * Home Agent daemon with udhcp-client and dhcp-support UDHCP implied 
00008  * on November 2007 by Tero Hätinen, Joni Purojärvi & Antti Pyykkönen
00009  * (DYNAMO GPOUP)
00010  *
00011  * udhcp DHCP client partially implied and modified by Tero Hätinen, 
00012  * Joni Purojärvi, Antti Pyykkönen November 2007
00013  * Original source by Russ Dill <Russ.Dill@asu.edu> in July 2001
00014  * 
00015  *
00016  * This program is free software; you can redistribute it and/or modify
00017  * it under the terms of the GNU General Public License as published by
00018  * the Free Software Foundation; either version 2 of the License, or
00019  * (at your option) any later version.
00020  *
00021  * This program is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  * GNU General Public License for more details.
00025  *
00026  * You should have received a copy of the GNU General Public License
00027  * along with this program; if not, write to the Free Software
00028  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00029  */
00030 
00031 
00032 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035 
00036 #define DEBUG_FLAG 'H'
00037 
00038 #include <sys/types.h>
00039 #include <sys/socket.h>
00040 #include <netinet/in.h>
00041 #include <string.h>
00042 #include <stdio.h>
00043 #include <arpa/inet.h>
00044 #include <sys/un.h>
00045 #include <net/if.h>
00046 
00047 #include <pthread.h>
00048 
00049 #include <sys/time.h>
00050 #include <unistd.h>
00051 #include <syslog.h>
00052 #ifndef __USE_BSD
00053 #define __USE_BSD /* for sigblock et al. */
00054 #endif
00055 #include <signal.h>
00056 #include <time.h>
00057 #include <stdlib.h>
00058 #include <assert.h>
00059 #include <errno.h>
00060 #include <getopt.h>
00061 #include <sys/uio.h>
00062 
00063 #include "ha.h"
00064 #include "list.h"
00065 #include "hashtable.h"
00066 #include "fileio.h"
00067 #include "msgparser.h"
00068 #include "agentadv.h"
00069 #include "proxyarp.h"
00070 #include "binding.h"
00071 #include "auth.h"
00072 #include "tunnel.h"
00073 #include "debug.h"
00074 #include "agentapi.h"
00075 #include "util.h"
00076 #include "fixed_fd_zero.h"
00077 #include "dyn_ip.h"
00078 #include "ha_config.h"
00079 #include "agent_utils.h"
00080 #include "md5_mac.h"
00081 /*UDHCP files to include*/
00082 
00083 #include "clientpacket.h"
00084 #include "packet.h"
00085 #include "script.h"
00086 #include "socket.h"
00087 #include "pidfile.h"
00088 
00089 
00090 #define DEFAULT_SCRIPT  "/usr/share/udhcpc/default.script" 
00091 /*UDHCP-clients config*/
00092 struct client_config_t client_config = {
00093         /* Default options. */
00094         abort_if_no_lease: 0,
00095         foreground: 0,
00096         quit_after_lease: 0,
00097         background_if_no_lease: 0,
00098         interface: "eth2", //read and set on dynhad.conf, set on main!
00099         pidfile: NULL,
00100         script: DEFAULT_SCRIPT,
00101         clientid: NULL, 
00102         hostname: NULL,
00103         ifindex: 0,
00104         arp: "\0\0\0\0\0\0",            /* appease gcc-3.0 */
00105 };
00106 
00107 #define LISTEN_NONE 0
00108 #define LISTEN_KERNEL 1
00109 #define LISTEN_RAW 2
00110 static int listen_mode;
00111 
00112 /* util.c - common command line arguments */
00113 extern int opt_foreground;
00114 extern char *opt_config;
00115 
00116 /* DYNAMO: Struct for mobilenodes with home address from DHCP etc.*/
00117 struct dhcp_mobile {
00118  unsigned char *nai;
00119  int state;
00120  unsigned long requested_ip; /* = 0 */
00121  unsigned long server_addr;
00122  unsigned long timeout;
00123  int packet_num; /* = 0 */
00124  int fd;
00125  int signal_pipe[2];
00126  int nai_length;
00127  int lease; //lease time
00128  int spi; //prolly not needed
00129  };
00130 
00131 struct dhcp_mobile dhcp_mobile_array[HA_DEFAULT_MAX_BINDINGS]; 
00132 
00133 int cur_mobiles=0; //how many mobile nodes are in the array
00134 int maxmobiles=HA_DEFAULT_MAX_BINDINGS; //max mobiles to place in array
00135 
00136 
00137 
00138 /*dynamics defines */
00139 
00140 #define ASSERT assert
00141 #define MIN(x, y) ( (x) < (y) ? (x) : (y))
00142 
00143 #define LOG2(lev, fmt, args...) { DEBUG(DEBUG_FLAG, fmt, ## args); \
00144   syslog(lev, fmt, ## args); }
00145 
00146 #define MAX_ADV_DELAY 200000.0 /* wait random 0 - MAX_ADV_DELAY microseconds 
00147                                   befora sending agent advertisement (either 
00148                                   broadcast or unicast, answer to agent 
00149                                   solicitation */
00150 
00151 
00152 /* dynamics function prototypes */
00153 
00154 /* called before the home agent terminates to do some cleaning */
00155 static void clean_up();
00156 
00157 /* functions for handling requests, creating and destroying
00158  * tunnels (bindings) */
00159 static void remove_tunnel(struct bindingentry *binding);
00160 static void destroy_binding(struct bindingentry *binding);
00161 static struct fa_spi_entry* get_fa_spi(int spi, struct in_addr addr);
00162 static struct spi_entry* get_mn_spi(int spi);
00163 static void init_interfaces(void);
00164 
00165 /* dynamics global variables */
00166 
00167 static struct ha_config config;
00168 struct fa_nai_ext *ha_nai = NULL;
00169 static HASH *tunnels;
00170 static struct bindingtable *bindings;
00171 static int bindingcount = 0;
00172 static char *program_name; /* the name this program was run with */
00173 static struct dynamics_ha_status stats;
00174 
00175 
00176 
00177 /***************************************************************************************************************/
00178 
00179 
00180 /**************************
00181 * DYNAMO: DHCP-Mobile array handling
00182 ***************************/
00183 
00184 
00193 int find_dhcp_mobile(unsigned char *nai, int nai_length)
00194 {
00195 int i, n, found;
00196         found=-1;
00197         for(i=0;i<cur_mobiles;i++)
00198         {       
00199                 if(nai_length==dhcp_mobile_array[i].nai_length)
00200                 {
00201                         n=memcmp(nai, dhcp_mobile_array[i].nai,nai_length);
00202                         if( n==0 )
00203                         {
00204                          found=i; 
00205                          break;
00206                         }
00207                 }       
00208                                 
00209         }
00210         
00211 return found;
00212 
00213 }
00214 
00215 
00225 int add_dhcp_mobile(unsigned long ip, unsigned char *nai, int nai_length)
00226 {
00227         if (cur_mobiles==maxmobiles) return 0;
00228         dhcp_mobile_array[cur_mobiles].requested_ip=ip;
00229         dhcp_mobile_array[cur_mobiles].timeout=0;
00230         dhcp_mobile_array[cur_mobiles].state=DHCPDISCOVER; 
00231         dhcp_mobile_array[cur_mobiles].nai= xmalloc(nai_length); 
00232         memcpy(dhcp_mobile_array[cur_mobiles].nai, nai, nai_length); 
00233         dhcp_mobile_array[cur_mobiles].nai_length=nai_length;
00234         cur_mobiles=cur_mobiles+1;
00235         return 1;
00236 }
00237 
00238 
00247 int del_dhcp_mobile(int i)
00248 {
00249 if(cur_mobiles <= i || i<0) return 0; //index out of array 
00250         free(dhcp_mobile_array[i].nai);
00251   dhcp_mobile_array[i].state=0;
00252         dhcp_mobile_array[i].requested_ip=0; 
00253         dhcp_mobile_array[i].server_addr=0;
00254         dhcp_mobile_array[i].timeout=0;
00255         dhcp_mobile_array[i].packet_num=0; 
00256         dhcp_mobile_array[i].fd=0;
00257         dhcp_mobile_array[i].signal_pipe[0]=0; 
00258   dhcp_mobile_array[i].signal_pipe[1]=0; 
00259         dhcp_mobile_array[i].nai_length=0;
00260         dhcp_mobile_array[i].lease=0; 
00261         dhcp_mobile_array[i].spi=0; 
00262         dhcp_mobile_array[i]=dhcp_mobile_array[cur_mobiles-1];
00263         cur_mobiles=cur_mobiles-1;
00264   return 1;
00265 
00266 }
00267 
00268 
00269 /*****************************
00270 * UDHCP Client starts here
00271 * DYNAMO: changed old global variables into dhcp_mobile_array
00272 ******************************/
00273 
00274 /* just a little helper  */
00275 static void change_mode(int new_mode, int selected_mobile)
00276 {
00277         DEBUG(LOG_INFO, "entering %s listen mode",
00278         new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
00279         close(dhcp_mobile_array[selected_mobile].fd);
00280         dhcp_mobile_array[selected_mobile].fd = -1;
00281         listen_mode = new_mode;
00282 }
00283 /* Exit and cleanup */
00284 static void exit_client(int retval)
00285 {
00286         pidfile_delete(client_config.pidfile);
00287         CLOSE_LOG();
00288         exit(retval);
00289 }
00290 
00291 
00292 /* Signal handler */
00293 static void signal_handler(int sig, int selected_mobile)
00294 {
00295         if (send(dhcp_mobile_array[selected_mobile].signal_pipe[1], &sig, sizeof(sig), MSG_DONTWAIT) < 0) {
00296                 LOG(LOG_ERR, "Could not send signal: %s",
00297                         strerror(errno));
00298         }
00299 }
00300 
00301 /* perform a renew */
00302 static void perform_renew(int selected_mobile)
00303 {       
00304 
00305         LOG(LOG_INFO, "Performing a DHCP renew");
00306         switch (dhcp_mobile_array[selected_mobile].state) {
00307         case BOUND:
00308                 change_mode(LISTEN_KERNEL, selected_mobile);
00309         case RENEWING:
00310         case REBINDING:
00311                 dhcp_mobile_array[selected_mobile].state = RENEW_REQUESTED;
00312                 break;
00313         case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
00314                 run_script(NULL, "deconfig");
00315         case REQUESTING:
00316         case RELEASED:
00317                 change_mode(LISTEN_RAW, selected_mobile);
00318                 dhcp_mobile_array[selected_mobile].state = INIT_SELECTING;
00319                 break;
00320         case INIT_SELECTING: NULL;
00321         }
00322 
00323         /* start things over */
00324         dhcp_mobile_array[selected_mobile].packet_num = 0;
00325 
00326         /* Kill any timeouts because the user wants this to hurry along */
00327         dhcp_mobile_array[selected_mobile].timeout = 0;
00328 }
00329 
00330 
00331 /* perform a release */
00332 static void perform_release(int selected_mobile)
00333 {
00334         char buffer[16];
00335         
00336         struct in_addr temp_addr;
00337 
00338         /* send release packet */
00339         if (dhcp_mobile_array[selected_mobile].state == BOUND || dhcp_mobile_array[selected_mobile].state == RENEWING || dhcp_mobile_array[selected_mobile].state == REBINDING) {
00340                 temp_addr.s_addr = dhcp_mobile_array[selected_mobile].server_addr;
00341                 sprintf(buffer, "%s", inet_ntoa(temp_addr));
00342                 temp_addr.s_addr = dhcp_mobile_array[selected_mobile].requested_ip; 
00343                 LOG(LOG_INFO, "Unicasting a release of %s to %s", 
00344                                 inet_ntoa(temp_addr), buffer);
00345                 send_release(dhcp_mobile_array[selected_mobile].server_addr, dhcp_mobile_array[selected_mobile].requested_ip); /* unicast */
00346                 run_script(NULL, "deconfig");
00347         }
00348         LOG(LOG_INFO, "Entering released state");
00349 
00350         change_mode(LISTEN_NONE, selected_mobile);
00351         dhcp_mobile_array[selected_mobile].state = RELEASED;
00352         dhcp_mobile_array[selected_mobile].timeout = 0;
00353 }
00354 
00355 /* Never called*/
00356 static void background(void)
00357 {
00358         int pid_fd;
00359 
00360         pid_fd = pidfile_acquire(client_config.pidfile); /* hold lock during fork. */
00361         while (pid_fd >= 0 && pid_fd < 3) pid_fd = dup(pid_fd); /* don't let daemon close it */
00362         if (daemon(0, 0) == -1) {
00363                 perror("fork");
00364                 exit_client(1);
00365         }
00366         client_config.foreground = 1; /* Do not fork again. */
00367         pidfile_write_release(pid_fd);
00368 }
00369 
00379 unsigned long udhcp(int selected_mobile, int flag)
00380 {
00381         
00382         unsigned char *temp, *message;
00383         unsigned long t1 = 0, t2 = 0, xid = 0;
00384         unsigned long start = 0, lease;
00385         fd_set rfds;
00386         int retval;
00387         struct timeval tv;
00388         int c, len;
00389         struct dhcpMessage packet;
00390         struct in_addr temp_addr;
00391         int pid_fd;
00392         time_t now;
00393         int max_fd;
00394         int sig;
00395         
00396 
00397         if (flag == REQUESTIP)
00398         {
00399         if(dhcp_mobile_array[selected_mobile].state==2) return 0;       
00400          listen_mode = 0;
00401          dhcp_mobile_array[selected_mobile].state=1;    
00402         }
00403 
00404 
00405         if (flag == RELEASEIP)
00406         {
00407         perform_release(selected_mobile); 
00408         return 0;
00409         }
00410 
00411         if(flag == RENEWIP)
00412         {       
00413         perform_renew(selected_mobile);
00414         return dhcp_mobile_array[selected_mobile].requested_ip;
00415         }
00416                 
00417         OPEN_LOG("udhcpc");
00418         
00419         pid_fd = pidfile_acquire(client_config.pidfile);
00420         pidfile_write_release(pid_fd);
00421         if (read_interface(client_config.interface, &client_config.ifindex, 
00422                            NULL, client_config.arp) < 0)
00423                 exit_client(1); //should never exit in this version!
00424 
00425         /* 
00426         DYNAMO:Set NAI into client_id field     
00427         */
00428         
00429         int mal_big = dhcp_mobile_array[selected_mobile].nai_length+2;
00430         client_config.clientid = xmalloc(mal_big); 
00431         client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
00432         client_config.clientid[OPT_LEN] = dhcp_mobile_array[selected_mobile].nai_length; 
00433         client_config.clientid[OPT_DATA] = 1; 
00434         memcpy(client_config.clientid + 2, dhcp_mobile_array[selected_mobile].nai, dhcp_mobile_array[selected_mobile].nai_length); 
00435 
00436         /* setup signal handlers */
00437         socketpair(AF_UNIX, SOCK_STREAM, 0, dhcp_mobile_array[selected_mobile].signal_pipe);
00438         signal(SIGUSR1, signal_handler);
00439         signal(SIGUSR2, signal_handler);
00440         signal(SIGTERM, signal_handler);
00441         
00442         dhcp_mobile_array[selected_mobile].state = INIT_SELECTING;
00443         
00444         change_mode(LISTEN_RAW, selected_mobile);
00445 
00446         for (;;) {
00447 
00448                 tv.tv_sec = dhcp_mobile_array[selected_mobile].timeout - time(0);
00449                 tv.tv_usec = 0;
00450                 FD_ZERO(&rfds);
00451 
00452                 if (listen_mode != LISTEN_NONE && dhcp_mobile_array[selected_mobile].fd < 0) {
00453                         if (listen_mode == LISTEN_KERNEL)
00454                                 dhcp_mobile_array[selected_mobile].fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface);
00455                         else
00456                                 dhcp_mobile_array[selected_mobile].fd = raw_socket(client_config.ifindex);
00457                         if (dhcp_mobile_array[selected_mobile].fd < 0) {
00458                                 LOG(LOG_ERR, "FATAL: couldn't listen on socket, %s", strerror(errno));
00459                                 exit_client(0);
00460                         }
00461                 }
00462                 if (dhcp_mobile_array[selected_mobile].fd >= 0) FD_SET(dhcp_mobile_array[selected_mobile].fd, &rfds);
00463                 FD_SET(dhcp_mobile_array[selected_mobile].signal_pipe[0], &rfds);               
00464 
00465                 if (tv.tv_sec > 0) {
00466                         DEBUG(LOG_INFO, "Waiting on select...\n");
00467                         max_fd = dhcp_mobile_array[selected_mobile].signal_pipe[0] > dhcp_mobile_array[selected_mobile].fd ? dhcp_mobile_array[selected_mobile].signal_pipe[0] : dhcp_mobile_array[selected_mobile].fd;
00468                         retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
00469                 } else retval = 0; /* If we already timed out, fall through */
00470 
00471                 now = time(0);
00472                 if (retval == 0) {
00473                         /* timeout dropped to zero */
00474                         switch (dhcp_mobile_array[selected_mobile].state) {
00475                         case INIT_SELECTING:
00476                                 if (dhcp_mobile_array[selected_mobile].packet_num < 3) {
00477                                         if (dhcp_mobile_array[selected_mobile].packet_num == 0)
00478                                                 xid = random_xid();
00479 
00480                                         /* send discover packet */
00481         
00482                                         send_discover(xid, dhcp_mobile_array[selected_mobile].requested_ip); /* broadcast */
00483         
00484                                         dhcp_mobile_array[selected_mobile].timeout = now + ((dhcp_mobile_array[selected_mobile].packet_num == 2) ? 4 : 2);
00485                                         dhcp_mobile_array[selected_mobile].packet_num++;
00486                                 } else {
00487 /*
00488                                         if (client_config.background_if_no_lease) {
00489                                                 LOG(LOG_INFO, "No lease, forking to background.");
00490                                                 background();
00491                                         } else if (client_config.abort_if_no_lease) {
00492                                                 LOG(LOG_INFO, "No lease, failing.");
00493                                                 exit_client(1);
00494                                         }
00495 */
00496                                         /* wait to try again */
00497                                         dhcp_mobile_array[selected_mobile].packet_num = 0;
00498                                         dhcp_mobile_array[selected_mobile].timeout = 0;
00499           LOG(LOG_INFO, "DHCP-server did not answer after 3 DHCPDISCOVERs");
00500           return -1; //failed after 3 discovers!
00501                                 }
00502         
00503                                 break;
00504                         case RENEW_REQUESTED:
00505                         case REQUESTING:
00506                                 if (dhcp_mobile_array[selected_mobile].packet_num < 3) {
00507                                         /* send request packet */
00508         
00509                                         if (dhcp_mobile_array[selected_mobile].state == RENEW_REQUESTED)
00510                                                 send_renew(xid, dhcp_mobile_array[selected_mobile].server_addr, dhcp_mobile_array[selected_mobile].requested_ip); /* unicast */
00511                                         else send_selecting(xid, dhcp_mobile_array[selected_mobile].server_addr, dhcp_mobile_array[selected_mobile].requested_ip); /* broadcast */
00512                                         
00513                                         dhcp_mobile_array[selected_mobile].timeout = now + ((dhcp_mobile_array[selected_mobile].packet_num == 2) ? 10 : 2);
00514                                         dhcp_mobile_array[selected_mobile].packet_num++;
00515                                 } else {
00516 
00517                                         /* timed out, go back to init state */
00518                                         if (dhcp_mobile_array[selected_mobile].state == RENEW_REQUESTED) run_script(NULL, "deconfig");
00519                                         dhcp_mobile_array[selected_mobile].state = INIT_SELECTING;
00520                                         dhcp_mobile_array[selected_mobile].timeout = now;
00521                                         dhcp_mobile_array[selected_mobile].packet_num = 0;
00522                                         change_mode(LISTEN_RAW, selected_mobile);
00523                                 }
00524                                 break;
00525                         case BOUND:
00526                                 /* Lease is starting to run out, time to enter renewing state */
00527                                 dhcp_mobile_array[selected_mobile].state = RENEWING;
00528                                 change_mode(LISTEN_KERNEL, selected_mobile);
00529         
00530                                 DEBUG(LOG_INFO, "Entering renew state");
00531                                 /* fall right through */
00532                         case RENEWING:
00533                                 /* Either set a new T1, or enter REBINDING state */
00534                                 if ((t2 - t1) <= (lease / 14400 + 1)) {
00535                                         /* timed out, enter rebinding state */
00536                                         dhcp_mobile_array[selected_mobile].state = REBINDING;
00537                                         dhcp_mobile_array[selected_mobile].timeout = now + (t2 - t1);
00538                                         DEBUG(LOG_INFO, "Entering rebinding state");
00539                                 } else {
00540                                         /* send a request packet */
00541                                         send_renew(xid, dhcp_mobile_array[selected_mobile].server_addr, dhcp_mobile_array[selected_mobile].requested_ip); /* unicast */
00542                                         
00543                                         t1 = (t2 - t1) / 2 + t1;
00544                                         dhcp_mobile_array[selected_mobile].timeout = t1 + start;
00545                                 }
00546                                 break;
00547                         case REBINDING:
00548                                 /* Either set a new T2, or enter INIT state */
00549                                 if ((lease - t2) <= (lease / 14400 + 1)) {
00550                                         /* timed out, enter init state */
00551                                         dhcp_mobile_array[selected_mobile].state = INIT_SELECTING;
00552                                         LOG(LOG_INFO, "Lease lost, entering init state");
00553                                         run_script(NULL, "deconfig");
00554                                         dhcp_mobile_array[selected_mobile].timeout = now;
00555                                         dhcp_mobile_array[selected_mobile].packet_num = 0;
00556                                         change_mode(LISTEN_RAW, selected_mobile);
00557                                 } else {
00558                                         /* send a request packet */
00559                                         send_renew(xid, 0, dhcp_mobile_array[selected_mobile].requested_ip); /* broadcast */
00560 
00561                                         t2 = (lease - t2) / 2 + t2;
00562                                         dhcp_mobile_array[selected_mobile].timeout = t2 + start;
00563                                 }
00564                                 break;
00565                         case RELEASED:
00566                                 /* yah, I know, *you* say it would never happen */
00567                                 dhcp_mobile_array[selected_mobile].timeout = 0;
00568                                 break;
00569                         }
00570 
00571         
00572                 } else if (retval > 0 && listen_mode != LISTEN_NONE && FD_ISSET(dhcp_mobile_array[selected_mobile].fd, &rfds)) {
00573                         /* a packet is ready, read it */
00574         
00575                         if (listen_mode == LISTEN_KERNEL)
00576                                 len = get_packet(&packet, dhcp_mobile_array[selected_mobile].fd);
00577                         else len = get_raw_packet(&packet, dhcp_mobile_array[selected_mobile].fd);
00578                         
00579                         if (len == -1 && errno != EINTR) {
00580                                 DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno));
00581                                 change_mode(listen_mode, selected_mobile); /* just close and reopen */
00582                         }
00583                         if (len < 0) continue;
00584 
00585                         
00586                         if (packet.xid != xid) {
00587                                 DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)",
00588                                         (unsigned long) packet.xid, xid);
00589                                 continue;
00590                         }
00591                         
00592                         if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
00593                                 DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring");
00594                                 continue;
00595                         }
00596                         
00597                         switch (dhcp_mobile_array[selected_mobile].state) {
00598                         case INIT_SELECTING:
00599                                 /* Must be a DHCPOFFER to one of our xid's */
00600                                 if (*message == DHCPOFFER) {
00601                                         if ((temp = get_option(&packet, DHCP_SERVER_ID))) {
00602                                                 memcpy(&dhcp_mobile_array[selected_mobile].server_addr, temp, 4);
00603                                                 xid = packet.xid;
00604                                                 dhcp_mobile_array[selected_mobile].requested_ip = packet.yiaddr; //ip in data struct
00605                                                 
00606                                                 /* enter requesting state */
00607                                                 dhcp_mobile_array[selected_mobile].state = REQUESTING;
00608                                                 dhcp_mobile_array[selected_mobile].timeout = now;
00609                                                 dhcp_mobile_array[selected_mobile].packet_num = 0;
00610                                         } else {
00611                                                 DEBUG(LOG_ERR, "No server ID in message");
00612                                         }
00613                                 }
00614                                 break;
00615                         case RENEW_REQUESTED:
00616                         case REQUESTING:
00617                         case RENEWING:
00618                         case REBINDING:
00619                                 if (*message == DHCPACK) {
00620                                         if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) {
00621                                                 LOG(LOG_ERR, "No lease time with ACK, using 1 hour lease");
00622                                                 lease = 60 * 60;
00623                                         } else {
00624                                                 memcpy(&lease, temp, 4);
00625                                                 lease = ntohl(lease);
00626                                         }
00627                                                 
00628                                         /* enter bound state */
00629                                         t1 = lease / 2;
00630                                         
00631                                         /* little fixed point for n * .875 */
00632                                         t2 = (lease * 0x7) >> 3;
00633                                         temp_addr.s_addr = packet.yiaddr;
00634                                         LOG(LOG_INFO, "Lease of %s obtained, lease time %ld", 
00635                                                 inet_ntoa(temp_addr), lease);
00636                                         start = now;
00637                                         dhcp_mobile_array[selected_mobile].timeout = t1 + start;
00638                                         dhcp_mobile_array[selected_mobile].requested_ip = packet.yiaddr;
00639                                         run_script(&packet,
00640                                                    ((dhcp_mobile_array[selected_mobile].state == RENEWING || dhcp_mobile_array[selected_mobile].state == REBINDING) ? "renew" : "bound"));
00641 
00642                                         dhcp_mobile_array[selected_mobile].state = BOUND;
00643                                         change_mode(LISTEN_NONE, selected_mobile);
00644                                         if (client_config.quit_after_lease){                    
00645                                                 return dhcp_mobile_array[selected_mobile].requested_ip; 
00646                                                 }
00647                                         if (!client_config.foreground){
00648                         
00649                                                 return dhcp_mobile_array[selected_mobile].requested_ip;
00650                                                 }
00651 
00652                                 } else if (*message == DHCPNAK) {
00653                                         /* return to init state */
00654                                         LOG(LOG_INFO, "Received DHCP NAK");
00655                                         run_script(&packet, "nak");
00656                                         if (dhcp_mobile_array[selected_mobile].state != REQUESTING)
00657                                                 run_script(NULL, "deconfig");
00658                                         dhcp_mobile_array[selected_mobile].state = INIT_SELECTING;
00659                                         dhcp_mobile_array[selected_mobile].timeout = now;
00660                                         dhcp_mobile_array[selected_mobile].requested_ip = 0;
00661                                         dhcp_mobile_array[selected_mobile].packet_num = 0;
00662                                         change_mode(LISTEN_RAW, selected_mobile);
00663                                         sleep(3); /* avoid excessive network traffic */
00664                                 }
00665                                 break;
00666                         /* case BOUND, RELEASED: - ignore all packets */
00667                         }       
00668                 } else if (retval > 0 && FD_ISSET(dhcp_mobile_array[selected_mobile].signal_pipe[0], &rfds)) {
00669                         if (read(dhcp_mobile_array[selected_mobile].signal_pipe[0], &sig, sizeof(signal)) < 0) {
00670                                 DEBUG(LOG_ERR, "Could not read signal: %s", 
00671                                         strerror(errno));
00672                                 continue; /* probably just EINTR */
00673                         }
00674                         switch (sig) {
00675                         case SIGUSR1: 
00676                                 perform_renew(selected_mobile);
00677                                 break;
00678                         case SIGUSR2:
00679                                 perform_release(selected_mobile);
00680                                 break;
00681                         case SIGTERM:
00682                                 LOG(LOG_INFO, "Received SIGTERM");
00683                                 exit_client(0);
00684                         }
00685                 } else if (retval == -1 && errno == EINTR) {
00686                         /* a signal was caught */               
00687                 } else {
00688                         /* An error occured */
00689                         DEBUG(LOG_ERR, "Error on select");
00690                 }
00691                 
00692         }
00693         
00694         return 0;
00695 }
00696 
00697 
00698 /*****************************************
00699 * Dynamics HA starts here
00700 ******************************************/
00701 
00709 static void
00710 set_ha_nai(void)
00711 {
00712         if (ha_nai != NULL) {
00713                 free(ha_nai);
00714                 ha_nai = NULL;
00715         }
00716         if (config.ha_nai[0] != '\0') {
00717                 ha_nai = (struct fa_nai_ext *)
00718                         malloc(sizeof(struct fa_nai_ext) +
00719                                strlen(config.ha_nai));
00720                 if (ha_nai == NULL) {
00721                         DEBUG(DEBUG_FLAG, "Not enough memory for ha_nai\n");
00722                         clean_up(1);
00723                 }
00724                 ha_nai->type = VENDOR_EXT_TYPE2;
00725                 ha_nai->reserved = 0;
00726                 ha_nai->length = sizeof(struct fa_nai_ext) - 2 +
00727                         strlen(config.ha_nai);
00728                 ha_nai->vendor_id = htonl(VENDOR_ID_DYNAMICS);
00729                 ha_nai->sub_type = htons(VENDOR_EXT_DYNAMICS_FA_NAI);
00730                 memcpy(ha_nai + 1, config.ha_nai, strlen(config.ha_nai));
00731         }
00732 }
00733 
00734 
00740 static void
00741 reload_config(int sig)
00742 {
00743         LOG2(LOG_INFO, "Received signal %d, rereading configuration\n", sig);
00744         cleanup_config(&config);
00745 
00746         if (load_config(&config, program_name,
00747                         opt_config == NULL ? HA_GLOBAL_CONF_FILE : opt_config)
00748             == FALSE) {
00749                 LOG2(LOG_ALERT, "Reloading configuration file failed\n");
00750                 clean_up(1);
00751         }
00752         init_interfaces();
00753         set_ha_nai();
00754         /* If the Port configuration is changed in the configuration
00755          * file, it will have no effect on a reload. If this functionality
00756          * is needed, the code should close the old sockets and reopen them
00757          * here. */
00758 }
00759 
00760 
00761 /**********************************************************************
00762  * clean up stuff
00763  **********************************************************************/
00764 
00776 static int
00777 binding_cleanup_iterator(struct node *node, void *dummy)
00778 {
00779         struct bindingentry *data = (struct bindingentry *) node;
00780 
00781         ASSERT(data != NULL);
00782         
00783         binding_remove(data);
00784         remove_tunnel(data);
00785         destroy_binding(data);
00786 
00787         return 1;
00788 }
00789 
00790 
00796 static void
00797 sig_handler(int sig)
00798 {
00799         LOG2(LOG_INFO, "signal %d received, cleaning up\n", sig);
00800         clean_up(sig); /* calls clean_up */
00801 }       
00802 
00803 
00809 static void
00810 clean_up(int value)
00811 {
00812         /* destroy all hashes and finish nicely */
00813 
00814         if (bindings != NULL) {
00815                 binding_iterator(bindings, binding_cleanup_iterator, NULL);
00816                 binding_destroy(bindings);
00817         }
00818         if (tunnels != NULL)
00819                 tunnel_destroy_hash(tunnels);
00820 
00821         /* remove old unix sockets */
00822         if (config.ha_api_read_socket_path[0] != '\0')
00823                 unlink(config.ha_api_read_socket_path);
00824         if (config.ha_api_admin_socket_path[0] != '\0')
00825                 unlink(config.ha_api_admin_socket_path);
00826 
00827         if (unlink(HA_PID_FILE) < 0) {
00828                 LOG2(LOG_INFO, "clean_up() could not remove PID file ("
00829                      HA_PID_FILE "): %s\n", strerror(errno));
00830         }
00831 
00832         cleanup_config(&config);
00833         if (ha_nai != NULL) {
00834                 free(ha_nai);
00835                 ha_nai = NULL;
00836         }
00837 
00838         syslog(LOG_INFO, "%s home agent daemon version %s stopped\n",
00839                PACKAGE, VERSION);
00840 
00841         closelog();
00842         exit(value);
00843 }
00844 
00845 /**********************************************************************
00846  * API handling
00847  **********************************************************************/
00848 
00860 static int
00861 binding_get_tunnels_iter(struct node *node, void *data)
00862 {
00863         struct bindingentry *binding = (struct bindingentry *) node;
00864         struct api_msg *api_msg = (struct api_msg *) data;
00865         dyn_tunnel_id id;
00866 
00867         if (api_msg->length + sizeof(dyn_tunnel_id) > API_DATA_SIZE) {
00868                 DEBUG(DEBUG_FLAG, "API message overflow - skipping rest of "
00869                       "the bindings\n");
00870                 return 0;
00871         }
00872 
00873         id.mn_addr.s_addr = binding->mn_addr.s_addr;
00874         id.ha_addr.s_addr = binding->ha_addr.s_addr;
00875         id.priv_ha = 0;
00876 
00877         memcpy((char *) api_msg->params + api_msg->length, &id,
00878                sizeof(dyn_tunnel_id));
00879 
00880         api_msg->length += sizeof(dyn_tunnel_id);
00881 
00882         return 1;
00883 }
00884 
00885 
00896 static struct bindingentry*
00897 api_fetch_binding(struct api_msg *msg)
00898 {
00899         dyn_tunnel_id *tid;
00900         struct bindingkey bkey;
00901         struct bindingentry *binding;
00902 
00903         if (msg->length != sizeof(dyn_tunnel_id)) {
00904                 LOG2(LOG_ERR, "API message has wrong length (%i, expected %i)"
00905                      "\n", msg->length, sizeof(dyn_tunnel_id));
00906                 return NULL;
00907         }
00908         tid = (dyn_tunnel_id *) msg->params;
00909         bkey.mn_addr = tid->mn_addr;
00910         if (config.sha_addr.s_addr != 0)
00911                 bkey.ha_addr = config.sha_addr;
00912         else if (tid->ha_addr.s_addr != 0)
00913                 bkey.ha_addr = tid->ha_addr;
00914         else {
00915                 struct interface_entry *iface;
00916                 iface = (struct interface_entry *)
00917                         list_get_first(&config.interfaces);
00918                 if (iface == NULL)
00919                         return NULL;
00920                 bkey.ha_addr = iface->addr;
00921         }
00922         bkey.priv_ha = config.priv_ha;
00923         binding = binding_fetch(bindings, &bkey);
00924         if (!binding) {
00925                 DEBUG(DEBUG_FLAG, "   API call could not find the request "
00926                       "binding\n");
00927         }
00928         return binding;
00929 }
00930 
00931 
00942 static int
00943 handle_api(int socket, int priv)
00944 {
00945         struct sockaddr_un cli_addr;
00946         socklen_t cli_len;
00947         int n;
00948         struct api_msg recv_msg;
00949         struct api_msg send_msg;
00950         struct bindingentry *binding;
00951         struct dynamics_tunnel_info *info;
00952         struct dynamics_ha_status *status;
00953 
00954         memset(&cli_addr, 0, sizeof(cli_addr));
00955         cli_len = sizeof(cli_addr);
00956 
00957         n = recvfrom(socket, &recv_msg, sizeof(struct api_msg), 0,
00958                      (struct sockaddr*)&cli_addr,
00959                      &cli_len);
00960 
00961         LOG2(LOG_DEBUG, "API: received %d bytes from %s\n", n,
00962              cli_addr.sun_path);
00963 
00964         if (n < 0) {
00965                 LOG2(LOG_ERR, "handle_api - recvfrom failed - %s\n",
00966                      strerror(errno));
00967                 return -1;
00968         }
00969 
00970         if (priv)
00971                 stats.apicalls_admin++;
00972         else
00973                 stats.apicalls_read++;
00974 
00975         memset(&send_msg, 0, sizeof(struct api_msg));
00976         send_msg.type = API_REPLY_MSG;
00977         send_msg.code = API_UNDEFINED;
00978         send_msg.length = 0;
00979 
00980         switch (recv_msg.code) {
00981         case API_GET_TUNNELS:
00982                 DEBUG(DEBUG_FLAG, "Received API_GET_TUNNELS\n");
00983                 if (recv_msg.length != 0) {
00984                         LOG2(LOG_ERR,
00985                              "API_GET_TUNNELS message has wrong length\n");
00986                         send_msg.code = API_ILLEGAL_PARAMETERS;
00987                         break;
00988                 }
00989 
00990                 /* get the list of bindings into send_msg */
00991                 if (binding_iterator(bindings, binding_get_tunnels_iter,
00992                                      &send_msg))
00993                         send_msg.code = API_SUCCESS;
00994                 else
00995                         send_msg.code = API_INSUFFICIENT_SPACE;
00996                 break;
00997 
00998         case API_GET_TUNNEL_INFO:
00999                 DEBUG(DEBUG_FLAG, "Received API_GET_TUNNEL_INFO\n");
01000                 binding = api_fetch_binding(&recv_msg);
01001                 if (!binding) {
01002                         send_msg.code = API_FAILED;
01003                         break;
01004                 }
01005                 info = (struct dynamics_tunnel_info *) send_msg.params;
01006                 memset(info, 0, sizeof(struct dynamics_tunnel_info));
01007                 info->id.mn_addr.s_addr = binding->mn_addr.s_addr;
01008                 info->id.ha_addr.s_addr = binding->ha_addr.s_addr;
01009                 info->mn_addr.s_addr = binding->mn_addr.s_addr;
01010                 info->co_addr.s_addr = binding->lower_addr.s_addr;
01011                 info->ha_addr.s_addr = binding->ha_addr.s_addr;
01012                 info->expiration_time = binding->exp_time;
01013                 info->creation_time = binding->create_time;
01014                 info->refresh_time = binding->mod_time;
01015                 info->last_timestamp[0] = ntohl(binding->id[0]);
01016                 info->last_timestamp[1] = ntohl(binding->id[1]);
01017                 info->spi = binding->spi;
01018                 info->confirmed = 1;
01019                 info->timeout = binding->timeout;
01020                 send_msg.code = API_SUCCESS;
01021                 send_msg.length = sizeof(struct dynamics_tunnel_info);
01022                 break;
01023 
01024         case API_DESTROY_TUNNEL:
01025                 DEBUG(DEBUG_FLAG, "Received API_DESTROY_TUNNEL\n");
01026                 if (!priv) {
01027                         send_msg.code = API_NOT_PERMITTED;
01028                         break;
01029                 }
01030                 binding = api_fetch_binding(&recv_msg);
01031                 if (!binding) {
01032                         send_msg.code = API_FAILED;
01033                         break;
01034                 }
01035                 binding_remove(binding);
01036                 remove_tunnel(binding);
01037                 destroy_binding(binding);
01038                 send_msg.length = 0;
01039                 send_msg.code = API_SUCCESS;
01040                 LOG2(LOG_NOTICE, "API call removed binding for MN %s\n",
01041                      inet_ntoa(binding->mn_addr));
01042                 break;
01043 
01044         case API_GET_STATUS:
01045                 DEBUG(DEBUG_FLAG, "Received API_GET_STATUS\n");
01046                 if (recv_msg.length != 0) {
01047                         LOG2(LOG_ERR, "API_GET_STATUS message has wrong "
01048                              "length\n");
01049                         break;
01050                 }
01051                 status = (struct dynamics_ha_status *) send_msg.params;
01052                 memcpy(status, &stats, sizeof(struct dynamics_ha_status));
01053                 UNALIGNED_(&status->tunnel_count, &bindingcount);
01054                 send_msg.length = sizeof(struct dynamics_ha_status);
01055                 send_msg.code = API_SUCCESS;
01056                 break;
01057 
01058         case API_RELOAD_CONFIG:
01059                 /* Force a reload of the configuration */
01060                 DEBUG(DEBUG_FLAG, "Received API_RELOAD_CONFIG\n");
01061                 if (!priv) {
01062                         send_msg.code = API_NOT_PERMITTED;
01063                         break;
01064                 }
01065                 reload_config(1);
01066                 DEBUG(DEBUG_FLAG, "Configuration_reloaded\n");
01067                 send_msg.code = API_SUCCESS;
01068                 break;
01069 
01070         default:
01071                 LOG2(LOG_ERR, "Received unknown API command: %d\n",
01072                      recv_msg.code);
01073                 send_msg.code = API_NOT_SUPPORTED;
01074                 break;
01075         }
01076 
01077         return api_send(socket, &cli_addr, cli_len, &send_msg);
01078 }
01079 
01080 /**********************************************************************
01081  * Registration request handling
01082  **********************************************************************/
01083 
01094 static int
01095 pubkey_hash_ok(struct msg_key *pubkey, struct msg_key *hash)
01096 {
01097         unsigned char mac[MD5_MAC_LEN];
01098 
01099         if (GET_KEY_LEN(hash) != MD5_MAC_LEN) {
01100                 DEBUG(DEBUG_FLAG, "pubkey_hash_ok: invalid hash length: %i, "
01101                       "expected %i\n", GET_KEY_LEN(hash), MD5_MAC_LEN);
01102                 return 0;
01103         }
01104 
01105         md5_mac((unsigned char *) "", 0, (unsigned char *) pubkey,
01106                 GET_KEY_EXT_LEN(pubkey), mac);
01107         return (memcmp(mac, MSG_KEY_DATA(hash), MD5_MAC_LEN) == 0);
01108 }
01109 
01110 
01121 static int
01122 check_fa_auth_ext(struct in_addr addr, const struct msg_extensions *ext)
01123 {
01124 
01125         struct fa_spi_entry *fa_spi;
01126 
01127         fa_spi = get_fa_spi(0, addr);
01128         if (fa_spi == NULL) {
01129                 /* no security association with the sender - authentication
01130                  * extension not required */
01131                 if (ext->fh_auth != NULL) {
01132                         DEBUG(DEBUG_FLAG, "No FA-HA security association, but "
01133                               "request had FA-HA authentication extension\n");
01134                         return 1;
01135                 }
01136                 return 0;
01137         }
01138 
01139         if (ext->fh_auth == NULL && ext->sha_ha_auth != NULL &&
01140             config.sha_addr.s_addr != 0) {
01141                 DEBUG(DEBUG_FLAG, "Checking sha_ha_auth\n");
01142                 if (auth_check_vendor(fa_spi->alg, fa_spi->shared_secret,
01143                                       fa_spi->shared_secret_len,
01144                                       (unsigned char *) ext->req,
01145                                       ext->sha_ha_auth))
01146                         return 0;
01147                 return 1;
01148         }
01149 
01150         DEBUG(DEBUG_FLAG, "Checking fh_auth\n");
01151         if (ext->fh_auth == NULL ||
01152             !auth_check(fa_spi->alg, fa_spi->shared_secret,
01153                         fa_spi->shared_secret_len, (unsigned char *) ext->req,
01154                         ext->fh_auth))
01155                 return 1;
01156         else
01157                 return 0;
01158 }
01159 
01160 
01190 #define AUTH_MAC_RFC2002 -100
01191 
01192 static struct spi_entry *
01193 validate_request(struct bindingentry *binding, struct in_addr faaddr,
01194                  const char *msg, int msg_len,
01195                  const struct msg_extensions *ext, int *code, int *auth_type)
01196 {
01197         struct node *node;
01198         struct spi_entry *spi = NULL;
01199         time_t current_time;
01200         enum { NOT_FOUND, UNICAST_FOUND, BROADCAST_FOUND } own_addr_found;
01201         struct authorized_entry *auth = NULL;
01202         char faaddrstr[16];
01203         char mnaddrstr[16];
01204         struct ha_tunnel_data *t_data = NULL;
01205 
01206         if (binding != NULL)
01207                 t_data = (struct ha_tunnel_data *) binding->data;
01208         dynamics_strlcpy(faaddrstr, inet_ntoa(faaddr), sizeof(faaddrstr));
01209 
01210 
01211         *code = REGREP_ACCEPTED;
01212         *auth_type = 0;
01213 
01214         /* check that it has the right extensions */
01215         if (ext->req == NULL || ext->mh_auth == NULL) {
01216                 LOG2(LOG_WARNING,
01217                      "FA %s: message does not contain either request "
01218                      "and/or message authentication\n", faaddrstr);
01219                 if (ext->mh_auth == NULL)
01220                         *code = REGREP_MN_FAILED_AUTH_HA;
01221                 else
01222                         *code = REGREP_BAD_REQUEST_HA;
01223                 return NULL;
01224         }
01225         
01226         dynamics_strlcpy(mnaddrstr, inet_ntoa(ext->req->home_addr),
01227                          sizeof(mnaddrstr));
01228 
01229 
01230         /***********************
01231         * DYNAMO: New check for MN auth without IP check
01232         * - Need to approve 0.0.0.0 ip with any spi
01233         ************************/
01234         for (node = list_get_first(&config.authorized_list); node != NULL;
01235              node = list_get_next(node)) {
01236                 auth = (struct authorized_entry *) node;
01237                 if (ntohl(ext->mh_auth->spi) >= auth->spi_low &&
01238                     ntohl(ext->mh_auth->spi) <= auth->spi_high) {
01239                         break;
01240                 }
01241         }
01242 
01243         if (node == NULL) {
01244                 LOG2(LOG_WARNING, "FA %s, MN %s: Not authorized\n", 
01245                      faaddrstr, mnaddrstr);
01246                 *code = REGREP_ADMIN_PROHIBITED_HA;
01247                 return NULL;
01248         }
01249 
01250         /* check MAC (MN-HA authentication extension) */
01251         spi = get_mn_spi(ntohl(ext->mh_auth->spi));
01252         if (spi == NULL) {
01253                 LOG2(LOG_WARNING, "FA %s, MN %s: SPI %d not found\n", 
01254                      faaddrstr, mnaddrstr, ntohl(ext->mh_auth->spi));
01255                 *code = REGREP_MN_FAILED_AUTH_HA;
01256                 return NULL;
01257         }
01258 
01259         if (!auth_check(spi->auth_alg, spi->shared_secret,
01260                         spi->shared_secret_len,
01261                         (unsigned char *) msg, ext->mh_auth)) {
01262                 if (spi->auth_alg != AUTH_ALG_MD5 ||
01263                     !auth_check(AUTH_ALG_MD5_RFC2002, spi->shared_secret,
01264                                 spi->shared_secret_len,
01265                                 (unsigned char *) msg, ext->mh_auth)) {
01266                         LOG2(LOG_WARNING, "FA %s, MN %s, SPI %d: Invalid MN-HA"
01267                              " authentication extension\n",
01268                              faaddrstr, mnaddrstr, spi->spi);
01269                         *code = REGREP_MN_FAILED_AUTH_HA;
01270                         return spi;
01271                 } else {
01272                         /* non-standard authentication method used */
01273                         DEBUG(DEBUG_FLAG, "RFC 2002 MAC calculation "
01274                               "detected - trying to use the same method\n");
01275                         *auth_type = AUTH_MAC_RFC2002;
01276                 }
01277         }
01278 
01279         if (ext->double_auth_ext > 0) {
01280                 LOG2(LOG_WARNING, "FA %s, MN %s: duplicate authentication "
01281                      "extension\n", faaddrstr, mnaddrstr);
01282                 if (ext->double_auth_ext & DOUBLE_MH_AUTH)
01283                         *code = REGREP_MN_FAILED_AUTH_HA;
01284                 else if (ext->double_auth_ext & DOUBLE_FH_AUTH)
01285                         *code = REGREP_FA_FAILED_AUTH_HA;
01286                 else
01287                         *code = REGREP_REASON_UNSPEC_HA;
01288                 return spi;
01289         }
01290 
01291         /* check possible Foreign-Home Authentication Extension */
01292         if (check_fa_auth_ext(faaddr, ext) != 0) {
01293                 LOG2(LOG_WARNING, "FA %s, MN %s: invalid/missing fh_auth\n",
01294                      faaddrstr, mnaddrstr);
01295                 *code = REGREP_FA_FAILED_AUTH_HA;
01296                 return spi;
01297         }
01298 
01299         /* check that MN-HA auth. ext. protects correct extensions */
01300         if (!auth_is_protected(ext->pubkey_hash, ext->mh_auth) ||
01301             !auth_is_protected(ext->priv_ha, ext->mh_auth) ||
01302             !auth_is_protected(ext->mn_keyreq, ext->mh_auth) ||
01303             !auth_is_protected(ext->mn_nai, ext->mh_auth)) {
01304                 LOG2(LOG_WARNING, "FA %s, MN %s: MN-HA auth. ext. does not "
01305                      "protect all the required extensions\n",
01306                      faaddrstr, mnaddrstr);
01307                 *code = REGREP_MN_FAILED_AUTH_HA;
01308         }
01309 
01310         /* check that MN-AAA auth. ext. protects correct extensions */
01311         if (ext->mn_fa_key_req_aaa != NULL &&
01312             (ext->mn_aaa_auth == NULL ||
01313              !auth_is_protected(ext->mn_fa_key_req_aaa, ext->mn_aaa_auth))) {
01314                 LOG2(LOG_WARNING, "FA %s, MN %s: MN-AAA auth. ext. does not "
01315                      "protect MN-FA keyreq from AAA extensions\n",
01316                      faaddrstr, mnaddrstr);
01317                 *code = REGREP_MN_FAILED_AUTH_HA;
01318         }
01319         if (ext->mn_ha_key_req_aaa != NULL &&
01320             (ext->mn_aaa_auth == NULL ||
01321              !auth_is_protected(ext->mn_ha_key_req_aaa, ext->mn_aaa_auth))) {
01322                 LOG2(LOG_WARNING, "FA %s, MN %s: MN-AAA auth. ext. does not "
01323                      "protect MN-HA keyreq from AAA extensions\n",
01324                      faaddrstr, mnaddrstr);
01325                 *code = REGREP_MN_FAILED_AUTH_HA;
01326         }
01327 
01328         if (ext->fh_auth != NULL &&
01329             !auth_is_protected(ext->challenge, ext->fh_auth)) {
01330                 LOG2(LOG_WARNING, "FA %s, MN %s: FA-HA auth. ext. does not "
01331                      "protect all the required extensions\n",
01332                      faaddrstr, mnaddrstr);
01333                 *code = REGREP_FA_FAILED_AUTH_HA;
01334         }
01335 
01336         /* check own (HA) address */
01337         own_addr_found = NOT_FOUND;
01338         for (node = list_get_first(&config.interfaces); node != NULL;
01339              node = list_get_next(node)) {
01340                 struct interface_entry *iface =
01341                         (struct interface_entry *) node;
01342                 if (iface->addr.s_addr == ext->req->ha_addr.s_addr) {
01343                         own_addr_found = UNICAST_FOUND;
01344                         break;
01345                 }
01346                 if (iface->ha_disc &&
01347                     iface->bcaddr.s_addr == ext->req->ha_addr.s_addr) {
01348                         own_addr_found = BROADCAST_FOUND;
01349                         break;
01350                 }
01351         }
01352 
01353         if (own_addr_found != 1 &&
01354             (config.sha_addr.s_addr == 0 ||
01355              ext->req->ha_addr.s_addr != config.sha_addr.s_addr)) {
01356                 if (own_addr_found == BROADCAST_FOUND)
01357                         DEBUG(DEBUG_FLAG,
01358                               "==> HA discovery, deny with unknown HA\n");
01359                 else
01360                         LOG2(LOG_WARNING, "FA %s, MN %s: HA address does not "
01361                              "match\n", faaddrstr, mnaddrstr);
01362                 *code = REGREP_UNKNOWN_HA_HA;
01363                 return spi;
01364         }
01365 
01366         /* check option bits */
01367         if (ext->req->opts & REGREQ_SIMULTANEOUS_BINDINGS) {
01368                 LOG2(LOG_INFO,
01369                      "FA %s, MN %s: Received request for unsupported "
01370                     "simultaneous_bindings\n", faaddrstr, mnaddrstr);
01371                 /* this is ok, but inform the MN */
01372                 *code = REGREP_ACCEPTED_NO_SB;
01373         }
01374 
01375         current_time = time(NULL);
01376         if (spi->replay_method == REPLAY_PROTECTION_TIMESTAMP &&
01377             (ntohl(ext->req->id[0]) < current_time + UNIX_NTP_DIFF -
01378              spi->timestamp_tolerance ||
01379              ntohl(ext->req->id[0]) > current_time + UNIX_NTP_DIFF +
01380              spi->timestamp_tolerance)) {
01381                 time_t t;
01382                 t = ntohl(ext->req->id[0]) - UNIX_NTP_DIFF;
01383                 LOG2(LOG_WARNING, "ID mismatch - timestamp difference=%i, "
01384                      "tolerance=%i\n", abs(t - current_time),
01385                      spi->timestamp_tolerance);
01386                 *code = REGREP_ID_MISMATCH_HA;
01387         } else if (spi->replay_method == REPLAY_PROTECTION_NONCE &&
01388                    t_data != NULL && ext->req->id[0] != t_data->nonce) {
01389                 LOG2(LOG_WARNING, "ID mismatch (nonce)\n");
01390                 DEBUG(DEBUG_FLAG, "\treq->id: %08x, expected nonce %08x\n",
01391                       ext->req->id[0], t_data->nonce);
01392                 *code = REGREP_ID_MISMATCH_HA;
01393         }
01394 
01395         if (ext->req->opts & REGREQ_BROADCAST_DATAGRAMS) {
01396                 DEBUG(LOG_INFO,
01397                       "FA %s, MN %s: Received request for unsupported "
01398                     "broadcast message forwarding\n", faaddrstr, mnaddrstr);
01399                 /* this is not yet implemented in Dynamics HA, but accept the
01400                  * connection anyway; there is no accepted reply code that
01401                  * would indicate this situation, so MN will think that the
01402                  * request was accepted.. */
01403         }
01404 
01405         /* REGREQ_VJ_HC is ignored in HA, see RFC 2002, 3.8.2 */
01406         if (ext->req->opts & (REGREQ_MINIMAL_ENCAPS | REGREQ_GRE_ENCAPS)) {
01407                 LOG2(LOG_INFO, "FA %s, MN %s: Received unsupported option "
01408                      "request (opts=0x%02x)\n", faaddrstr, mnaddrstr,
01409                      ext->req->opts);
01410                 /* RFC 2344 defines new denial code for unavailable
01411                  * encapsulation */
01412                 if ((ext->req->opts & REGREQ_REVERSE_TUNNEL) != 0)
01413                         *code = REGREP_ENCAP_UNAVAIL_HA;
01414                 else
01415                         *code = REGREP_REASON_UNSPEC_HA;
01416                 return spi;
01417         }
01418 
01419         if (!config.enable_reverse_tunneling &&
01420             (ext->req->opts & REGREQ_REVERSE_TUNNEL) != 0) {
01421                 LOG2(LOG_INFO,
01422                      "FA %s, MN %s: Asked forbidden reverse tunneling\n",
01423                      faaddrstr, mnaddrstr);
01424                 *code = REGREP_REVERSE_TUNNEL_UNAVAIL_HA;
01425                 return spi;
01426         }
01427 
01428         if (!config.enable_triangle_tunneling &&
01429             (ext->req->opts & REGREQ_REVERSE_TUNNEL) == 0) {
01430                 LOG2(LOG_INFO,
01431                      "FA %s, MN %s: Reverse tunneling mandatory\n",
01432                      faaddrstr, mnaddrstr);
01433                 *code = REGREP_REVERSE_TUNNEL_MANDATORY_HA;
01434                 return spi;
01435         }
01436 
01437         if (ext->req->opts & REGREQ_RESERVED) {
01438                 LOG2(LOG_INFO, "FA %s, MN %s: Received a request with non-zero"
01439                      " reserved field\n", faaddrstr, mnaddrstr);
01440                 *code = REGREP_BAD_REQUEST_HA;
01441                 return spi;
01442         }
01443 
01444         if (config.pubkey_hash_method == HASH_METHOD_REQUIRE &&
01445             ext->fa_pubkey != NULL && ext->pubkey_hash == NULL) {
01446                 LOG2(LOG_INFO, "FA %s, MN %s: Received a request with public "
01447                      "key, but without public key hash extension\n",
01448                      faaddrstr, mnaddrstr);
01449                 *code = REGREP_ADMIN_PROHIBITED_HA;
01450                 return spi;
01451         }
01452 
01453         if (config.pubkey_hash_method != HASH_METHOD_NONE &&
01454             ext->fa_pubkey != NULL &&
01455             ext->pubkey_hash != NULL &&
01456             !pubkey_hash_ok(ext->fa_pubkey, ext->pubkey_hash)) {
01457                 LOG2(LOG_INFO, "FA %s, MN %s: Received a request with public "
01458                      "key and mismatching public key hash extension\n",
01459                      faaddrstr, mnaddrstr);
01460                 *code = REGREP_ADMIN_PROHIBITED_HA;
01461                 return spi;
01462         }
01463 
01464         /* request is OK */
01465         return spi;
01466 }
01467 
01468 
01479 static int
01480 new_session_key(struct bindingentry *binding, struct spi_entry *mn_spi)
01481 {
01482 #ifndef NODEBUGMODE
01483         int i;
01484 #endif
01485 
01486         /* remove the (possibly) cached previous key reply using FA's public
01487          * key, because the session key changes */
01488         if (binding->last_sent_fa_pubkeyrep)
01489                 free(binding->last_sent_fa_pubkeyrep);
01490         binding->last_sent_fa_pubkeyrep = NULL;
01491 
01492         /* generate a new session key */
01493         binding->keylen =
01494                 generate_session_key(mn_spi->auth_alg, mn_spi->shared_secret,
01495                                      mn_spi->shared_secret_len, binding->key);
01496         if (binding->keylen == -1) {
01497                 LOG2(LOG_ERR, "Could not generate session key\n");
01498                 return -1;
01499         }
01500 
01501 #ifndef NODEBUGMODE
01502         DEBUG(DEBUG_FLAG, "Session key: ");
01503         for (i = 0; i < binding->keylen; i++)
01504                 DEBUG(DEBUG_FLAG, "%02x", binding->key[i]);
01505         DEBUG(DEBUG_FLAG, "\n");
01506 #endif
01507 
01508         return 0;
01509 }
01510 
01511 
01512 struct gratuitous_arp_data {
01513         struct gratuitous_arp_data *next;
01514         struct timeval tv;
01515         struct in_addr addr;
01516         char interface[IFNAMSIZ + 1];
01517 };
01518 
01519 static struct gratuitous_arp_data *gratuitous_arp_queue = NULL;
01520 
01521 
01529 static void
01530 send_gratuitous_arp(struct in_addr addr, char *interface)
01531 {
01532         struct gratuitous_arp_data *arp2, *arp3, *arp;
01533 
01534         /* HW broadcast is not usually guaranteed, so the gratuitous ARP is
01535          * transmitted a small number of times (see RFC2002, sec. 4.6) */
01536 
01537         /* send first packet immediately */
01538         proxyarp_gratuitous(addr, interface);
01539 
01540         arp2 = (struct gratuitous_arp_data *)
01541                 malloc(sizeof(struct gratuitous_arp_data));
01542         arp3 = (struct gratuitous_arp_data *)
01543                 malloc(sizeof(struct gratuitous_arp_data));
01544         if (arp2 == NULL || arp3 == NULL) {
01545                 DEBUG(DEBUG_FLAG, "send_gratuitous_arp: malloc() failed\n");
01546                 if (arp2 != NULL)
01547                         free(arp2);
01548                 if (arp3 != NULL)
01549                         free(arp3);
01550                 return;
01551         }
01552 
01553         /* send second packet after 100 ms delay */
01554         memset(arp2, 0, sizeof(struct gratuitous_arp_data));
01555         gettimeofday(&arp2->tv, NULL);
01556         add_usecs(&arp2->tv, 100000);
01557         arp2->addr.s_addr = addr.s_addr;
01558         dynamics_strlcpy(arp2->interface, interface, sizeof(arp2->interface));
01559 
01560         /* send third packet after 200 ms delay */
01561         memcpy(arp3, arp2, sizeof(struct gratuitous_arp_data));
01562         add_usecs(&arp3->tv, 100000);
01563 
01564         DEBUG(DEBUG_FLAG, "send_gratuitous_arp - adding packet to queue at "
01565               "%li.%06li and %li.%06li\n", arp2->tv.tv_sec, arp2->tv.tv_usec,
01566               arp3->tv.tv_sec, arp3->tv.tv_usec);
01567 
01568         if (gratuitous_arp_queue == NULL) {
01569                 /* empty queue - make new queue of the new items */
01570                 gratuitous_arp_queue = arp2;
01571                 arp2->next = arp3;
01572                 arp3->next = NULL;
01573                 return;
01574         }
01575 
01576         if (cmp_timeval(&gratuitous_arp_queue->tv, &arp2->tv) > 0) {
01577                 /* arp2 goes before the old head of the queue */
01578                 arp2->next = gratuitous_arp_queue;
01579                 gratuitous_arp_queue = arp2;
01580         } else {
01581                 /* insert arp2 into queue */
01582                 arp = gratuitous_arp_queue;
01583                 while (arp->next != NULL &&
01584                        cmp_timeval(&arp->next->tv, &arp2->tv) <= 0)
01585                         arp = arp->next;
01586                 arp2->next = arp->next;
01587                 arp->next = arp2;
01588         }
01589 
01590         /* insert arp3 into queue */
01591         arp = arp2;
01592         while (arp->next != NULL &&
01593                cmp_timeval(&arp->next->tv, &arp3->tv) <= 0)
01594                 arp = arp->next;
01595         arp3->next = arp->next;
01596         arp->next = arp3;
01597 }
01598 
01599 
01605 static void
01606 check_queued_gratuitous_arp(void)
01607 {
01608         struct timeval now;
01609         struct gratuitous_arp_data *arp;
01610 
01611         if (gratuitous_arp_queue == NULL)
01612                 return;
01613 
01614         gettimeofday(&now, NULL);
01615         while (gratuitous_arp_queue != NULL &&
01616                cmp_timeval(&gratuitous_arp_queue->tv, &now) <= 0) {
01617                 arp = gratuitous_arp_queue;
01618                 DEBUG(DEBUG_FLAG, "Sending queued gratuitous ARP "
01619                       "(tv=%li.%06li addr=%s interface=%s)\n",
01620                       arp->tv.tv_sec, arp->tv.tv_usec, inet_ntoa(arp->addr),
01621                       arp->interface);
01622                 proxyarp_gratuitous(arp->addr, arp->interface);
01623                 gratuitous_arp_queue = arp->next;
01624                 free(arp);
01625         }
01626         if (gratuitous_arp_queue == NULL)
01627                 DEBUG(DEBUG_FLAG, "Gratuitous ARP queue empty.\n");
01628         else
01629                 DEBUG(DEBUG_FLAG, "Entries remaining in gratuitous ARP queue "
01630                       "(next at %li.%06li)\n",
01631                       gratuitous_arp_queue->tv.tv_sec,
01632                       gratuitous_arp_queue->tv.tv_usec);
01633 }
01634 
01635 
01648 static struct bindingentry *
01649 create_binding(struct msg_extensions *ext, struct spi_entry *mn_spi,
01650                int create_tunnels)
01651 {
01652         struct bindingentry *binding;
01653         struct ha_tunnel_data *t_data;
01654         char mn_addrstr[17];
01655         char co_addrstr[17];
01656         int ok = TRUE;
01657 
01658         DEBUG(DEBUG_FLAG, "Creating a new binding for MN\n");
01659 
01660         ASSERT(ext != NULL && ext->req != NULL);
01661         ASSERT(mn_spi != NULL);
01662         if (bindingcount >= config.max_bindings) {
01663                 LOG2(LOG_WARNING, "max bindings reached\n");
01664                 return NULL;
01665         }
01666 
01667         /* create the binding */
01668         binding = malloc(sizeof(struct bindingentry));
01669         if (binding == NULL) {
01670                 LOG2(LOG_ERR, "malloc[binding] - %s\n", strerror(errno));
01671                 return NULL;
01672         }
01673         memset(binding, 0, sizeof(struct bindingentry));
01674         binding->data = malloc(sizeof(struct ha_tunnel_data));
01675         if (binding->data == NULL) {
01676                 LOG2(LOG_ERR, "malloc[ha_tunnel_data] - %s\n",
01677                      strerror(errno));
01678                 free(binding);
01679                 return NULL;
01680         }
01681         memset(binding->data, 0, sizeof(struct ha_tunnel_data));
01682         t_data = (struct ha_tunnel_data *) binding->data;
01683 
01684         binding->spi = mn_spi->spi;
01685 
01686         if ((ext->fa_keyreq || ext->fa_pubkey || ext->mn_keyreq) &&
01687             new_session_key(binding, mn_spi) < 0)
01688                 ok = FALSE;
01689 
01690         binding->mn_addr.s_addr = ext->req->home_addr.s_addr;
01691         binding->ha_addr.s_addr = ext->req->ha_addr.s_addr;
01692         binding->priv_ha = config.priv_ha;
01693         binding->lower_addr.s_addr = config.sha_addr.s_addr != 0 ?
01694                 config.sha_addr.s_addr : ext->req->co_addr.s_addr;
01695         dynamics_strlcpy(mn_addrstr, inet_ntoa(ext->req->home_addr),
01696                          sizeof(mn_addrstr));
01697         dynamics_strlcpy(co_addrstr, inet_ntoa(ext->req->co_addr),
01698                          sizeof(co_addrstr));
01699         memcpy(&binding->id, ext->req->id, REG_REQ_ID_LEN);
01700         binding->create_time = time(NULL);
01701 
01702         if (ok && create_tunnels &&
01703             tunnel_add(tunnels, binding->lower_addr, binding->tun_dev,
01704                        ext->req->ha_addr, 1, TUNNEL_IPIP, 0) == NULL) {
01705                 LOG2(LOG_ERR, "Could not add tunnel to FA %s (COA=%s) for "
01706                      "MN %s\n", inet_ntoa(binding->lower_addr), co_addrstr,
01707                      mn_addrstr);
01708                 ok = FALSE;
01709         }
01710 
01711         if (ok && create_tunnels &&
01712             dyn_ip_route_get(binding->mn_addr, t_data->arp_if, IFNAMSIZ)
01713             != 0) {
01714                 LOG2(LOG_ERR, "Could not get arp interface for MN %s\n",
01715                      mn_addrstr);
01716                 ok = FALSE;
01717         }
01718 
01719         if (ok && create_tunnels &&
01720             dyn_ip_route_replace(binding->mn_addr, binding->tun_dev) != 0) {
01721                 LOG2(LOG_ERR, "Could not add route to MN %s\n",
01722                      mn_addrstr);
01723                 ok = FALSE;
01724         }
01725 
01726         if (!ok) {
01727                 free(binding->data);
01728                 free(binding);
01729                 return NULL;
01730         }
01731 
01732         if (create_tunnels) {
01733                 DEBUG(DEBUG_FLAG, "tunnel_add => tun_dev=[%s]\n",
01734                       binding->tun_dev);
01735                 DEBUG(DEBUG_FLAG, "dyn_ip_route_get: %s => %s\n",
01736                       inet_ntoa(binding->mn_addr), t_data->arp_if);
01737                 proxyarp_add_item(binding->mn_addr, t_data->arp_if);
01738                 send_gratuitous_arp(binding->mn_addr, t_data->arp_if);
01739         }
01740 
01741         bindingcount++;
01742         return binding;
01743 }
01744 
01745 
01753 static void
01754 remove_tunnel(struct bindingentry *binding)
01755 {
01756         struct ha_tunnel_data *t_data;
01757 
01758         ASSERT(binding != NULL && binding->data != NULL);
01759 
01760         t_data = (struct ha_tunnel_data *) binding->data;
01761         if (dyn_ip_route_del(binding->mn_addr, binding->tun_dev) < 0)
01762                 LOG2(LOG_WARNING, "remove_tunnel: dyn_ip_route_del failed\n");
01763         if (tunnel_delete(tunnels, binding->lower_addr, 0, TUNNEL_IPIP, 0) < 0)
01764                 LOG2(LOG_WARNING, "remove_tunnel: tunnel_delete failed\n");
01765         if (proxyarp_del_item(binding->mn_addr, t_data->arp_if) < 0)
01766                 LOG2(LOG_WARNING, "remove_tunnel: proxyarp_del_item failed\n");
01767 }
01768 
01769 
01781 static int
01782 switch_tunnel(struct bindingentry *binding, struct msg_extensions *ext,
01783               struct spi_entry *mn_spi)
01784 {
01785         char mn_addrstr[17];
01786         char co_addrstr[17];
01787         char old_lower_tunl[IFNAMSIZ];
01788 
01789         ASSERT(binding != NULL && ext != NULL && ext->req != NULL);
01790 
01791         dynamics_strlcpy(mn_addrstr, inet_ntoa(ext->req->home_addr),
01792                          sizeof(mn_addrstr));
01793         dynamics_strlcpy(co_addrstr, inet_ntoa(ext->req->co_addr),
01794                          sizeof(co_addrstr));
01795         memcpy(old_lower_tunl, binding->tun_dev, IFNAMSIZ);
01796 
01797         /* remove old tunnel (delayed deletion) */
01798         if (tunnel_delete(tunnels, binding->lower_addr, 0, TUNNEL_IPIP, 0) < 0)
01799         {
01800                 LOG2(LOG_ERR,
01801                      "Could not delete old tunnel to FA %s for MN %s\n",
01802                      co_addrstr, mn_addrstr);
01803         }
01804 
01805         binding->lower_addr = config.sha_addr.s_addr != 0 ?
01806                 config.sha_addr : ext->req->co_addr;
01807 
01808         /* add the new tunnel */
01809         if (tunnel_add(tunnels, binding->lower_addr, binding->tun_dev,
01810                        ext->req->ha_addr, 1, TUNNEL_IPIP, 0) == NULL) {
01811                 LOG2(LOG_ERR, "Could not add tunnel to FA %s (COA=%s) for "
01812                      "MN %s\n", inet_ntoa(binding->lower_addr), co_addrstr,
01813                      mn_addrstr);
01814                 destroy_binding(binding);
01815                 return -1;
01816         }
01817         DEBUG(DEBUG_FLAG, "tunnel_add => tun_dev=[%s]\n", binding->tun_dev);
01818 
01819         if (dyn_ip_route_replace(binding->mn_addr, binding->tun_dev) != 0) {
01820                 LOG2(LOG_WARNING,
01821                      "Route replace failed (COA=%s, MN=%s, dev=%s)\n",
01822                      co_addrstr, mn_addrstr, binding->tun_dev)
01823         }
01824 
01825         if ((ext->fa_keyreq || ext->fa_pubkey || ext->mn_keyreq) &&
01826             new_session_key(binding, mn_spi) < 0) {
01827                 destroy_binding(binding);
01828                 return -1;
01829         }
01830 
01831         return 0;
01832 }
01833 
01834 
01842 static void
01843 destroy_binding(struct bindingentry *binding)
01844 {
01845         if (binding->data) /* ccmalloc needs this */
01846                 free(binding->data);
01847         if (binding->fa_pubkey)
01848                 free(binding->fa_pubkey);
01849         if (binding->last_sent_fa_pubkeyrep)
01850                 free(binding->last_sent_fa_pubkeyrep);
01851         free(binding);
01852         bindingcount--;
01853 }
01854 
01855 
01862 static void
01863 check_bindings(void)
01864 {
01865         struct bindingentry *binding;
01866         time_t diff;
01867         static int first_time = 1;
01868         static time_t advance_expire_time;
01869         time_t time2;
01870 
01871         if (first_time) {
01872                 advance_expire_time = time(NULL);
01873                 first_time = 0;
01874         }
01875         time2 = time(NULL);
01876         diff = time2 - advance_expire_time;
01877         advance_expire_time = time2;
01878         if (diff < 0) {
01879                 DEBUG(DEBUG_FLAG,
01880                       "check_bindings: diff(%li) < 0 - system time changed?\n",
01881                       diff);
01882                 diff = 0;
01883         }
01884         binding = binding_getexpired(bindings, diff);
01885         while (binding != NULL) {
01886                 DEBUG(DEBUG_FLAG, "Binding to MN %s expired\n",
01887                       inet_ntoa(binding->mn_addr));
01888                 remove_tunnel(binding);
01889                 destroy_binding(binding);
01890                 binding = binding_getexpired(bindings, 0);
01891         }
01892 }
01893 
01894 
01907 static struct fa_spi_entry *
01908 get_fa_spi(int spi, struct in_addr addr)
01909 {
01910         struct fa_spi_entry *s;
01911         struct node *node;
01912 
01913         for (node = list_get_first(&config.fa_spi_list); node != NULL;
01914              node = list_get_next(node)) {
01915                 s = (struct fa_spi_entry *) node;
01916                 if ((spi == 0 || s->spi == spi) &&
01917                     s->addr.s_addr == addr.s_addr) {
01918                         return s;
01919                 }
01920         }
01921         return NULL;
01922 }
01923 
01924 
01934 static struct spi_entry *
01935 get_mn_spi(int spi)
01936 {
01937         struct spi_entry *s;
01938         struct node *node;
01939 
01940         for (node = list_get_first(&config.spi_list); node != NULL;
01941              node = list_get_next(node)) {
01942                 s = (struct spi_entry *) node;
01943                 if (s->spi == spi)
01944                         return s;
01945         }
01946         return NULL;
01947 }
01948 
01949 
01968 static int
01969 ha_add_ext_start(unsigned char *start, unsigned char *pos, int left,
01970                  struct msg_extensions *ext, int lifetime,
01971                  struct spi_entry *mn_spi, struct bindingentry *binding,
01972                  int auth_type)
01973 {
01974         int used = 0, n;
01975 
01976         if (config.priv_ha > 0) {
01977                 struct priv_ha_ext *priv = (struct priv_ha_ext *) (pos + used);
01978                 DEBUG(DEBUG_FLAG, " * priv_ha\n");
01979                 if (left < sizeof(struct priv_ha_ext))
01980                         return -1;
01981                 memset(priv, 0, sizeof(struct priv_ha_ext));
01982                 priv->type = VENDOR_EXT_TYPE2;
01983                 priv->length = sizeof(struct priv_ha_ext) - 2;
01984                 priv->vendor_id = htonl(VENDOR_ID_DYNAMICS);
01985                 priv->sub_type = htons(VENDOR_EXT_DYNAMICS_PRIV_HA);
01986                 priv->priv_ha = htonl(config.priv_ha);
01987                 used += GET_PRIV_HA_EXT_LEN(priv);
01988                 left -= GET_PRIV_HA_EXT_LEN(priv);
01989         }
01990 
01991         /* RFC 2794 requires that HA copies MN NAI extension to the reply */
01992         if (ext != NULL && ext->mn_nai != NULL) {
01993                 DEBUG(DEBUG_FLAG, " * mn_nai\n");
01994                 if (left < GET_MN_NAI_EXT_LEN(ext->mn_nai))
01995                         return -1;
01996                 memcpy(pos + used, ext->mn_nai,
01997                        GET_MN_NAI_EXT_LEN(ext->mn_nai));
01998                 used += GET_MN_NAI_EXT_LEN(ext->mn_nai);
01999                 left -= GET_MN_NAI_EXT_LEN(ext->mn_nai);
02000         }
02001 
02002         /* Add the session key to mobile node, if it requested for a key and
02003          * the reply is not a deregistration or failure reply */
02004         if (ext && ext->mn_keyreq != NULL && mn_spi && lifetime != 0) {
02005                 struct msg_key *key;
02006                 DEBUG(DEBUG_FLAG, " * mn_keyrep\n");
02007                 if (left < sizeof(struct msg_key) + MAX_SK_LEN)
02008                         return -1;
02009                 key = (struct msg_key *) (pos + used);
02010                 n = auth_encrypt(mn_spi->auth_alg, mn_spi->shared_secret,
02011                                  mn_spi->shared_secret_len, binding->key,
02012                                  key, (struct reg_rep *) start,
02013                                  VENDOR_EXT_DYNAMICS_MN_KEYREP,
02014                                  htonl(mn_spi->spi));
02015                 used += n;
02016                 left -= n;
02017         }
02018 
02019         if (ext && mn_spi) {
02020                 struct msg_auth *auth;
02021                 DEBUG(DEBUG_FLAG, " * mh_auth\n");
02022                 if (left < sizeof(struct msg_auth) + MAX_SK_LEN)
02023                         return -1;
02024                 /* Add message authentication for MN */
02025                 auth = (struct msg_auth *) (pos + used);
02026                 n = auth_add((auth_type == AUTH_RFC2002BIS ?
02027                               AUTH_ALG_MD5_RFC2002 : mn_spi->auth_alg),
02028                              mn_spi->shared_secret,
02029                              mn_spi->shared_secret_len, start,
02030                              (struct msg_auth *) (pos + used), MH_AUTH,
02031                              htonl(mn_spi->spi));
02032                 used += n;
02033                 left -= n;
02034         }
02035 
02036         /* RFC 3012 requires that HA copies challenge extension to the reply
02037          * after Mobile-Home auth. ext.; this will be authenticated with
02038          * FA-HA auth. ext. if security association for this is available */
02039         if (ext != NULL && ext->challenge != NULL) {
02040                 DEBUG(DEBUG_FLAG, " * challenge\n");
02041                 n = GET_CHALLENGE_EXT_LEN(ext->challenge);
02042                 if (left < n)
02043                         return -1;
02044                 memcpy(pos + used, ext->challenge, n);
02045                 used += n;
02046                 left -= n;
02047         }
02048 
02049         return used;
02050 }
02051 
02052 
02068 static int
02069 ha_add_ext_end(unsigned char *start, unsigned char *pos, struct in_addr addr,
02070                int left, struct msg_extensions *ext)
02071 {
02072         struct fa_spi_entry *fa_spi;
02073         int used = 0;
02074 
02075         if (config.priv_ha && ext && ext->nonce) {
02076                 if (ext->nonce->length != sizeof(struct nonce_ext) - 2) {
02077                         DEBUG(DEBUG_FLAG, " - invalid nonce ext len\n");
02078                 } else {
02079                         DEBUG(DEBUG_FLAG, " * nonce\n");
02080                         if (left < GET_NONCE_EXT_LEN(ext->nonce))
02081                                 return -1;
02082                         memcpy(pos + used, ext->nonce,
02083                                GET_NONCE_EXT_LEN(ext->nonce));
02084                         used += GET_NONCE_EXT_LEN(ext->nonce);
02085                         left -= GET_NONCE_EXT_LEN(ext->nonce);
02086                 }
02087         }
02088 
02089         fa_spi = get_fa_spi(0, addr);
02090         if (fa_spi != NULL && config.priv_ha > 0) {
02091                 DEBUG(DEBUG_FLAG, " * sha_ha_auth\n");
02092                 if (left < sizeof(struct vendor_msg_auth) + MAX_SK_LEN)
02093                         return -1;
02094                 used += auth_add_vendor(
02095                         AUTH_ALG_MD5, fa_spi->shared_secret,
02096                         fa_spi->shared_secret_len, start,
02097                         (struct vendor_msg_auth *) (pos + used),
02098                         VENDOR_EXT_DYNAMICS_SHA_HA_AUTH, htonl(fa_spi->spi));
02099         } else if (fa_spi != NULL) {
02100                 DEBUG(DEBUG_FLAG, " * fh_auth\n");
02101                 if (left < sizeof(struct msg_auth) + MAX_SK_LEN)
02102                         return -1;
02103                 used += auth_add(fa_spi->alg, fa_spi->shared_secret,
02104                                  fa_spi->shared_secret_len, start,
02105                                  (struct msg_auth *) (pos + used), FH_AUTH,
02106                                  htonl(fa_spi->spi));
02107         }
02108 
02109         return used;
02110 }
02111 
02112 
02129 static int
02130 send_reg_repl(int s, struct bindingentry *binding, struct spi_entry *mn_spi,
02131               struct msg_extensions *ext, struct interface_entry *forced_iface,
02132               int code)
02133 {
02134         unsigned char msg[MAXMSG];
02135         unsigned char *msgpos = msg;
02136         struct reg_rep *reply;
02137         struct msg_key *key;
02138         struct sockaddr_in dest_addr;
02139         struct fa_spi_entry *fa_spi;
02140 #ifdef USE_TEARDOWN
02141         struct registration_ext_dynamics *dyn_ext;
02142 #endif
02143         int msglen, result, key_to_fa, left = MAXMSG, n;
02144         struct ha_tunnel_data *t_data;
02145 
02146         ASSERT(s >= 0 && binding != NULL && binding->data != NULL &&
02147                mn_spi != NULL);
02148 
02149         t_data = (struct ha_tunnel_data *) binding->data;
02150 
02151         /* Create the reply extension */
02152         DEBUG(DEBUG_FLAG, "Reply\n");
02153         reply = (struct reg_rep *) msg;
02154         memset(reply, 0, sizeof(struct reg_rep));
02155         reply->lifetime = htons(binding->timeout);
02156         reply->type = REG_REP;
02157         reply->code = code;
02158         reply->home_addr.s_addr = binding->mn_addr.s_addr;
02159         reply->ha_addr.s_addr = config.sha_addr.s_addr != 0 ?
02160                 config.sha_addr.s_addr : binding->ha_addr.s_addr;
02161         memcpy(reply->id, binding->id, REG_REQ_ID_LEN);
02162         if (mn_spi->replay_method == REPLAY_PROTECTION_NONCE)
02163                 t_data->nonce = reply->id[0] = get_rand32();
02164         msgpos += sizeof(struct reg_rep);
02165         left -= sizeof(struct reg_rep);
02166 
02167         n = ha_add_ext_start(msg, msgpos, left, ext, binding->timeout,
02168                              mn_spi, binding, t_data->auth_type);
02169         if (n < 0)
02170                 return -1;
02171         msgpos += n;
02172         left -= n;
02173 
02174         /* Encrypt the session key for the FA if it requested the key with
02175          * fa_keyreq (use shared secret and MD5) or fa_pubkey (use RSA) */
02176         key_to_fa = 0;
02177         if (binding->fa_spi != 0 && ntohs(reply->lifetime) != 0) {
02178                 fa_spi = get_fa_spi(binding->fa_spi, t_data->lower_saddr);
02179                 if (fa_spi == NULL) {
02180                         LOG2(LOG_ERR, "unknown FA SPI %i\n", binding->fa_spi);
02181                         return -1;
02182                 }
02183                 DEBUG(DEBUG_FLAG, " * fa_keyrep\n");
02184                 if (left < sizeof(struct msg_key) + MAX_SK_LEN)
02185                         return -1;
02186                 key = (struct msg_key *) msgpos;
02187                 n = auth_encrypt(fa_spi->alg, fa_spi->shared_secret,
02188                                  fa_spi->shared_secret_len, binding->key,
02189                                  key, reply, VENDOR_EXT_DYNAMICS_FA_KEYREP,
02190                                  htonl(fa_spi->spi));
02191                 msgpos += n;
02192                 left -= n;
02193                 key_to_fa = 1;
02194         } else if (binding->fa_pubkey && ntohs(reply->lifetime) != 0 &&
02195                    binding->last_sent_fa_pubkeyrep) {
02196                 DEBUG(DEBUG_FLAG, " * fa_pubkeyrep\n");
02197                 n = GET_KEY_EXT_LEN(binding->last_sent_fa_pubkeyrep);
02198                 if (left < n)
02199                         return -1;
02200                 /* If the foreign agent included a public key, add an RSA
02201                  * encrypted session key to the FA */
02202                 key = (struct msg_key *) msgpos;
02203                 memcpy(key, binding->last_sent_fa_pubkeyrep, n);
02204                 msgpos += n;
02205                 left -= n;
02206                 key_to_fa = 1;
02207         }
02208 
02209 #ifdef USE_TEARDOWN
02210         if (teardown) {
02211                 DEBUG(DEBUG_FLAG, " * ext_dynamics (teardown)\n");
02212                 if (left < sizeof(struct registration_ext_dynamics))
02213                         return -1;
02214                 dyn_ext = (struct registration_ext_dynamics *) msgpos;
02215                 dyn_ext->type = VENDOR_EXT_TYPE2;
02216                 dyn_ext->reserved = 0;
02217                 dyn_ext->length = sizeof(struct registration_ext_dynamics) - 2;
02218                 dyn_ext->vendor_id = htonl(VENDOR_ID_DYNAMICS);
02219                 dyn_ext->sub_type = htons(VENDOR_EXT_DYNAMICS_OPTIONS);
02220                 dyn_ext->version = VENDOR_EXT_VERSION;
02221                 dyn_ext->opts = REG_EXT_OWN_TEAR_DOWN;
02222                 dyn_ext->seq = 0;
02223                 msgpos += sizeof(struct registration_ext_dynamics);
02224                 left -= sizeof(struct registration_ext_dynamics);
02225         }
02226 #endif
02227 
02228         if (key_to_fa) {
02229                 DEBUG(DEBUG_FLAG, " * sk_auth\n");
02230                 if (left < sizeof(struct vendor_msg_auth) + MAX_SK_LEN)
02231                         return -1;
02232                 /* Add session key-based message authentication for FA */
02233                 n = auth_add_vendor(AUTH_ALG_MD5, binding->key,
02234                                     binding->keylen, msg,
02235                                     (struct vendor_msg_auth *) msgpos,
02236                                     VENDOR_EXT_DYNAMICS_SK_AUTH,
02237                                     htonl(mn_spi->spi));
02238                 msgpos += n;
02239                 left -= n;
02240         }
02241 
02242         n = ha_add_ext_end(msg, msgpos, t_data->lower_saddr, left, ext);
02243         if (n < 0)
02244                 return -1;
02245         msgpos += n;
02246         left -= n;
02247 
02248         msglen = msgpos - msg;
02249 
02250         dest_addr.sin_family = AF_INET;
02251         dest_addr.sin_addr.s_addr = t_data->lower_saddr.s_addr;
02252         dest_addr.sin_port = binding->lower_port;
02253 
02254         if (forced_iface != NULL &&
02255             setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, forced_iface->dev,
02256                        IFNAMSIZ)) {
02257                 DEBUG(DEBUG_FLAG, "setsockopt(SOL_SOCKET, SO_BINDTODEVICE): "
02258                       "%s\n", strerror(errno));
02259         }
02260 
02261         DEBUG(DEBUG_FLAG, " * total %i bytes to %s:%i\n", msglen,
02262               inet_ntoa(dest_addr.sin_addr), ntohs(dest_addr.sin_port));
02263         result = sendto(s, msg, msglen, 0,
02264                         (struct sockaddr *) &dest_addr,
02265                         sizeof(struct sockaddr_in));
02266 
02267         if (forced_iface != NULL) {
02268                 /* kernel seems to require optlen >= sizeof(int) */
02269                 char dummy[sizeof(int)];
02270                 memset(dummy, 0, sizeof(dummy));
02271                 if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, dummy,
02272                                sizeof(dummy)))
02273                         DEBUG(DEBUG_FLAG, "setsockopt(SOL_SOCKET, "
02274                               "SO_BINDTODEVICE): %s\n", strerror(errno));
02275         }
02276 
02277         return dynamics_check_sendto(result, msglen, "send_reg_repl");
02278 }
02279 
02280 
02300 static int
02301 send_reg_failure(int s, struct sockaddr_in *sock_addr,
02302                  struct spi_entry *mn_spi, int auth_type,
02303                  int code, __u32 *nonce, struct msg_extensions *ext,
02304                  struct interface_entry *forced_iface,
02305                  struct bindingentry *binding,
02306                  struct interface_entry *from_iface)
02307 {
02308         unsigned char msg[MAXMSG];
02309         unsigned char *msgpos = msg;
02310         struct reg_rep *reply;
02311         int msglen, result, n, left = MAXMSG;
02312         struct ha_tunnel_data *t_data = NULL;
02313         static time_t last_failure_time = 0;
02314         time_t *timer, now;
02315 
02316         ASSERT(s >= 0 && sock_addr && ext && ext->req && code > 2);
02317 
02318         if (binding) {
02319                 /* known binding - use MN's own timer */
02320                 t_data = (struct ha_tunnel_data *) binding->data;
02321                 timer = &t_data->last_failure_time;
02322         } else {
02323                 /* no binding - use general timer */
02324                 timer = &last_failure_time;
02325         }
02326 
02327         /* do not send failure replys too often */
02328         time(&now);
02329         if (*timer > now) {
02330                 DEBUG(DEBUG_FLAG, "send_reg_failure: timed failure in the "
02331                       "future - host time changed?\n");
02332                 *timer = now;
02333         } else if (now - *timer < config.reg_error_reply_interval) {
02334                 DEBUG(DEBUG_FLAG, "Too frequent error message - skipping\n");
02335                 return 0;
02336         }
02337         *timer = now;
02338 
02339         if (mn_spi == NULL && ext->mh_auth != NULL)
02340                 mn_spi = get_mn_spi(ntohl(ext->mh_auth->spi));
02341         
02342         /* Create the reply extension */
02343         DEBUG(DEBUG_FLAG, "Failure reply\n");
02344         reply = (struct reg_rep *) msg;
02345         memset(reply, 0, sizeof(struct reg_rep));
02346         reply->lifetime = 0;
02347         reply->type = REG_REP;
02348         reply->code = code;
02349         reply->home_addr.s_addr = ext->req->home_addr.s_addr;
02350         reply->ha_addr.s_addr = ext->req->ha_addr.s_addr;
02351         if (config.sha_addr.s_addr != 0)
02352                 reply->ha_addr.s_addr = config.sha_addr.s_addr;
02353         else if (code == REGREP_UNKNOWN_HA_HA) {
02354                 /* use the HA's unicast IP address in case of HA discovery */
02355                 struct node *node;
02356                 int found = 0;
02357                 for (node = list_get_first(&config.interfaces); node != NULL;
02358                      node = list_get_next(node)) {
02359                         struct interface_entry *iface =
02360                                 (struct interface_entry *) node;
02361                         if (iface->ha_disc &&
02362                             iface->bcaddr.s_addr == ext->req->ha_addr.s_addr) {
02363                                 reply->ha_addr.s_addr = iface->addr.s_addr;
02364                                 found = 1;
02365                                 break;
02366                         }
02367                 }
02368                 if (!found && from_iface != NULL)
02369                         reply->ha_addr.s_addr = from_iface->addr.s_addr;
02370         }
02371         memcpy(reply->id, ext->req->id, REG_REQ_ID_LEN);
02372         if (mn_spi) {
02373                 if (mn_spi->replay_method == REPLAY_PROTECTION_TIMESTAMP &&
02374                     code == REGREP_ID_MISMATCH_HA) {
02375                         reply->id[0] = htonl(time(NULL) + UNIX_NTP_DIFF);
02376                 } else if (mn_spi->replay_method == REPLAY_PROTECTION_NONCE) {
02377                         reply->id[0] = get_rand32();
02378                         if (nonce != NULL)
02379                                 *nonce = reply->id[0];
02380                 }
02381         }
02382         msgpos += sizeof(struct reg_rep);
02383         left -= sizeof(struct reg_rep);
02384 
02385         n = ha_add_ext_start(msg, msgpos, left, ext, 0, mn_spi, NULL,
02386                              auth_type);
02387         if (n < 0)
02388                 return -1;
02389         msgpos += n;
02390         left -= n;
02391 
02392         n = ha_add_ext_end(msg, msgpos, sock_addr->sin_addr, left, ext);
02393         if (n < 0)
02394                 return -1;
02395         msgpos += n;
02396         left -= n;
02397 
02398         msglen = msgpos - msg;
02399 
02400         if (forced_iface != NULL &&
02401             setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, forced_iface->dev,
02402                        IFNAMSIZ)) {
02403                 DEBUG(DEBUG_FLAG, "setsockopt(SOL_SOCKET, SO_BINDTODEVICE): "
02404                       "%s\n", strerror(errno));
02405         }
02406 
02407         DEBUG(DEBUG_FLAG, "send_reg_failure(code=%i): "
02408               "sending %i bytes to %s:%i (forced_iface=%s)\n", code, msglen,
02409               inet_ntoa(sock_addr->sin_addr), ntohs(sock_addr->sin_port),
02410               forced_iface != NULL ? forced_iface->dev : "N/A");
02411         result = sendto(s, msg, msglen, 0,
02412                         (struct sockaddr *)sock_addr,
02413                         sizeof(struct sockaddr_in));
02414 
02415         if (forced_iface != NULL) {
02416                 /* kernel seems to require optlen >= sizeof(int); in addition,
02417                  * 2.2 kernels seem to report error (Invalid argument) even
02418                  * when this unbinding success.. */
02419                 char dummy[sizeof(int)];
02420                 memset(dummy, 0, sizeof(dummy));
02421                 if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, dummy,
02422                                sizeof(dummy)) < 0 &&
02423                     setsockopt(s, SOL_PACKET, SO_BINDTODEVICE, NULL, 0) < 0)
02424                         DEBUG(DEBUG_FLAG, "setsockopt(SOL_SOCKET, "
02425                               "SO_BINDTODEVICE): %s (this is probably "
02426                               "bogus)\n", strerror(errno));
02427         }
02428 
02429         return dynamics_check_sendto(result, msglen, "send_reg_failure");
02430 }
02431 
02432 
02433 
02434 
02435 
02445 static int
02446 handle_reg_msg(struct interface_entry *from_iface, int s)
02447 {
02448         char msg[MAXMSG];
02449         struct sockaddr_in cli_addr;
02450         struct in_addr dst_addr;
02451         struct msghdr mh;
02452         char cdata[256];
02453         struct iovec iov;
02454         struct cmsghdr *cmsg;
02455         struct bindingentry *binding;
02456         struct spi_entry *mn_spi;
02457         int n, res, rsock;
02458         struct msg_extensions ext;
02459         int killbinding;
02460         int code, auth_type;
02461         char mn_addrstr[17]; 
02462         char fa_addrstr[17];
02463         struct ha_tunnel_data *t_data = NULL;
02464         struct bindingkey bkey;
02465         struct node *node;
02466         struct interface_entry *force_iface = NULL;
02467         int selected_mobile; //what mobile node we're handling in the array
02468 
02469 
02470         memset(&cli_addr, 0, sizeof(cli_addr));
02471         dst_addr.s_addr = 0;
02472         memset(&mh, 0, sizeof(mh));
02473         iov.iov_base = msg;
02474         iov.iov_len = MAXMSG;
02475         mh.msg_name = &cli_addr;
02476         mh.msg_namelen = sizeof(cli_addr);
02477         mh.msg_iov = &iov;
02478         mh.msg_iovlen = 1;
02479         mh.msg_control = &cdata;
02480         mh.msg_controllen = sizeof(cdata);
02481 
02482         n = recvmsg(s, &mh, 0);
02483         
02484         LOG(LOG_INFO, "Received %d bytes from %s:%d\n", n,
02485               inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
02486 
02487         if (n < 0) {
02488                 LOG(LOG_INFO "handle_reg_msg - recvfrom failed - %s\n",
02489                      strerror(errno));
02490                 return -1;
02491         }
02492         
02493 
02494         for (cmsg = CMSG_FIRSTHDR(&mh); cmsg != NULL;
02495              cmsg = DYNAMICS_CMSG_NXTHDR(&mh, cmsg)) {
02496                 if (cmsg->cmsg_level == SOL_IP &&
02497                     cmsg->cmsg_type == IP_PKTINFO) {
02498                         struct _in_pktinfo *pkt;
02499                         pkt = (struct _in_pktinfo *) CMSG_DATA(cmsg);
02500                         dst_addr = pkt->ipi_addr;
02501                         DEBUG(DEBUG_FLAG, "\tIP_PKTINFO: ipi_ifindex=%i "
02502                               "ipi_spec_dst=%s ", pkt->ipi_ifindex,
02503                               inet_ntoa(pkt->ipi_spec_dst));
02504                         DEBUG(DEBUG_FLAG, "ipi_addr=%s\n",
02505                               inet_ntoa(pkt->ipi_addr));
02506                 }
02507         }
02508 
02509         /* use the matching UDP socket for the registration reply */
02510         rsock = -1;
02511         for (node = list_get_first(&config.interfaces); node != NULL;
02512              node = list_get_next(node)) {
02513                 struct interface_entry *iface =
02514                         (struct interface_entry *) node;
02515                 if (iface->addr.s_addr == dst_addr.s_addr ||
02516                         (iface->ha_disc &&
02517                          iface->bcaddr.s_addr == dst_addr.s_addr)) {
02518                         rsock = iface->udp_sock;
02519                 }
02520         }
02521         if (rsock < 0 && from_iface != NULL &&
02522             dst_addr.s_addr == (unsigned int) -1) {
02523                 DEBUG(DEBUG_FLAG, "Broadcast 255.255.255.255 destination - "
02524                       "using interface[%s] UDP socket[%i]\n", from_iface->dev,
02525                       from_iface->udp_sock);
02526                 rsock = from_iface->udp_sock;
02527         }
02528         if (rsock < 0) {
02529                 LOG2(LOG_WARNING, "Could not find UDP socket for "
02530                      "registration reply - trying recv. socket\n");
02531                 rsock = s;
02532         }
02533         //pthread_mutex_unlock(&reg_mutex);     
02534         res = parse_msg(msg, n, &ext);
02535 
02536 
02537 
02538         if (ext.req != NULL && ntohs(ext.req->lifetime) == 0 &&
02539             ext.req->home_addr.s_addr == cli_addr.sin_addr.s_addr &&
02540             ext.req->home_addr.s_addr == ext.req->co_addr.s_addr) {
02541                 /* RFC 2002, Ch. 3.8.3.1:
02542                  * When HA is replying to deregistration (lifetime == 0 &&
02543                  * COA == home addr) whose srcIP is MN's home address, the
02544                  * reply must be send directly to home network bypassing any
02545                  * mobility bindings */
02546                 DEBUG(DEBUG_FLAG, "Dereg. from home => bypassing mobility "
02547                       "bindings in routing\n");
02548                 force_iface = from_iface;
02549         }
02550 
02551         if (res == -3 || res == -4) {
02552                 LOG2(LOG_WARNING, "Unknown critical vendor extension in a "
02553                      "request from %s:%i\n", inet_ntoa(cli_addr.sin_addr),
02554                      ntohs(cli_addr.sin_port));
02555                 send_reg_failure(rsock, &cli_addr, NULL, 0,
02556                                  res == -3 ? REGREP_UNSUPP_VENDOR_ID_MN_HA :
02557                                  REGREP_UNSUPP_VENDOR_ID_FA_HA, NULL, &ext,
02558                                  force_iface, NULL, from_iface);
02559                 stats.discarded_vendor_ext++;
02560                 report_discarded_msg(msg, n, &cli_addr,
02561                                      "unknown vendor extension");
02562                 return -1;
02563         } else if (res != 0 || ext.req == NULL) {
02564                 char *reason = "N/A";
02565                 if (res == -1) {
02566                         reason = "unknown extension";
02567                         stats.discarded_unknown_ext++;
02568                 } else if (res == -2) {
02569                         reason = "malformed message";
02570                         stats.discarded_malformed_msg++;
02571                 } else if (ext.req == NULL) {
02572                         reason = "not a request";
02573                         stats.discarded_not_request++;
02574                 }
02575                 LOG2(LOG_WARNING, "Message parser failed or not a request "
02576                      "(from %s:%i): %s\n", inet_ntoa(cli_addr.sin_addr),
02577                      ntohs(cli_addr.sin_port), reason);
02578                 report_discarded_msg(msg, n, &cli_addr, reason);
02579                 return -1;
02580         }
02581 
02582         memcpy(&bkey.mn_addr, &ext.req->home_addr, sizeof(bkey.mn_addr));
02583         bkey.ha_addr = config.sha_addr.s_addr != 0 ? config.sha_addr :
02584                 ext.req->ha_addr;
02585         bkey.priv_ha = config.priv_ha;
02586         binding = binding_fetch(bindings, &bkey);
02587         if (binding != NULL)
02588                 t_data = (struct ha_tunnel_data *) binding->data;
02589         mn_spi = validate_request(binding, cli_addr.sin_addr, msg, n, &ext,
02590                                   &code, &auth_type);
02591         if (code > 2) {
02592                 send_reg_failure(rsock, &cli_addr, mn_spi, 0, code,
02593                                  (t_data != NULL ? &t_data->nonce : NULL),
02594                                  &ext, force_iface, binding, from_iface);
02595                 stats.req_rejected++;
02596                 report_discarded_msg(msg, n, &cli_addr, "invalid message");
02597                 return -1;
02598         }
02599         if (mn_spi == NULL) {
02600                 stats.req_rejected++;
02601                 report_discarded_msg(msg, n, &cli_addr, "MN SPI not found");
02602                 return -1;
02603         }
02604 
02605         dynamics_strlcpy(mn_addrstr, inet_ntoa(ext.req->home_addr),
02606                          sizeof(mn_addrstr));
02607         dynamics_strlcpy(fa_addrstr, inet_ntoa(ext.req->co_addr),
02608                          sizeof(fa_addrstr));
02609 
02610         if (binding != NULL) {
02611                 t_data->auth_type = (auth_type == AUTH_MAC_RFC2002 ?
02612                                      AUTH_RFC2002BIS : AUTH_RFC2002);
02613 
02614                 /* If the id field is identical the message was a duplicate.
02615                  * In order to avoid breaking the tunnel drop this message as
02616                  * a special case without sending a failure reply if the replay
02617                  * protection is used
02618                  */
02619                 if (mn_spi->replay_method != REPLAY_PROTECTION_NONE &&
02620                     binding->id[0] == ext.req->id[0] &&
02621                     binding->id[1] == ext.req->id[1]) {
02622                         DEBUG(DEBUG_FLAG,
02623                               "Received duplicate request - dropping it\n");
02624                         stats.req_rejected++;
02625                         return -1;
02626                 }
02627 
02628                 /* Make sure that the id field is incremented if the timestamp
02629                  * protection is used */
02630                 if (mn_spi->replay_method == REPLAY_PROTECTION_TIMESTAMP &&
02631                     (ntohl(binding->id[0]) > ntohl(ext.req->id[0]) ||
02632                      (ntohl(binding->id[0]) == ntohl(ext.req->id[0]) &&
02633                       ntohl(binding->id[1]) >= ntohl(ext.req->id[1])))) {
02634                         LOG2(LOG_NOTICE, "Timestamp did not increase "
02635                              "(MN=%s, FA=%s)\n", mn_addrstr, fa_addrstr);
02636                         send_reg_failure(rsock, &cli_addr, mn_spi,
02637                                          t_data->auth_type,
02638                                          REGREP_ID_MISMATCH_HA,
02639                                          &t_data->nonce, &ext, force_iface,
02640                                          binding, from_iface);
02641                         stats.req_rejected++;
02642                         return -1;
02643                 }
02644 
02645                 /* remove binding from list (does not remove tunnels etc.) */
02646                 binding_remove(binding);
02647         } else {
02648                 LOG2(LOG_NOTICE, "MN %s registers, FA is %s\n", 
02649                      mn_addrstr, fa_addrstr);
02650         }
02651 
02652         stats.req_accepted++;
02653 
02654         killbinding = 0;
02655 
02656         if (binding &&
02657             (binding->lower_addr.s_addr != (config.sha_addr.s_addr != 0 ?
02658                                             config.sha_addr.s_addr :
02659                                             ext.req->co_addr.s_addr) ||
02660              ext.req->lifetime == 0)) {
02661                 DEBUG(DEBUG_FLAG, "Found existing binding for MN %s\n",
02662                       mn_addrstr);
02663 
02664                 if (ext.req->co_addr.s_addr == ext.req->home_addr.s_addr &&
02665                     ext.req->lifetime == 0) {
02666                         DEBUG(DEBUG_FLAG, "MN is deregistering all its "
02667                               "simultaneous bindings\n");
02668                         /* Note: RFC 2002, 3.6.1.2, special case
02669                          * This should be taken into account if the
02670                          * simultaneous bindings are implemented.
02671                          * At the moment we just deregister the only possible
02672                          * binding below. */
02673                 }
02674 
02675 #ifdef USE_TEARDOWN
02676                 /* if co_addr differs in request, send reply to old
02677                  * co_addr to purge old tunnel segment */
02678                 if (config.sha_addr.s_addr == 0 &&
02679                     binding->lower_addr.s_addr != ext.req->co_addr.s_addr) {
02680                         binding->timeout = 0;
02681                         DEBUG(DEBUG_FLAG, "Sending purge msg to %s\n",
02682                               inet_ntoa(binding->lower_addr));
02683                         send_reg_repl(s, binding, mn_spi, NULL, force_iface,
02684                                       REGREP_ACCEPTED);
02685                 }
02686 #endif
02687 
02688                 if (ext.req->lifetime > 0) {
02689                         /*
02690                         * It was a location update, 
02691                         * DYNAMO: renew IP from DHCP-server
02692                         */
02693                         udhcp(find_dhcp_mobile(MSG_MN_NAI_DATA(ext.mn_nai), ext.mn_nai->length),RENEWIP);
02694                         
02695                         LOG2(LOG_INFO, "MN %s updating tunnel to FA %s\n", 
02696                              mn_addrstr, fa_addrstr);
02697                         if (switch_tunnel(binding, &ext, mn_spi) < 0)
02698                                 return -1;
02699                 } else {
02700                         /* if it is a deregistration request,
02701                          * destroy the binding after the reply is sent,
02702                          * since the binding is needed when sending the
02703                          * reply */
02704                         LOG2(LOG_NOTICE, "MN %s deregisters\n", mn_addrstr);
02705                         remove_tunnel(binding);
02706                         /*
02707                         * DYNAMO: Deregister, send DHCPRELEASE and delete from dhcp_mobile_array
02708                         */
02709                         udhcp(find_dhcp_mobile(MSG_MN_NAI_DATA(ext.mn_nai), ext.mn_nai->length),RELEASEIP); 
02710                         /*Check if find returns -1? Should never happen in this case tho*/
02711                         del_dhcp_mobile(find_dhcp_mobile(MSG_MN_NAI_DATA(ext.mn_nai), ext.mn_nai->length)); 
02712                                                 
02713                         if (cli_addr.sin_addr.s_addr == binding->mn_addr.s_addr
02714                             && ext.req->co_addr.s_addr ==
02715                             ext.req->home_addr.s_addr) {
02716                                 DEBUG(DEBUG_FLAG, "MN returned home and "
02717                                       "deregistered all care-of addresses\n");
02718                                 /* FIX: also HA should send gratuitous ARP
02719                                  * telling that MN takes care of its own
02720                                  * packets from now on;
02721                                  * draft-ietf-mobileip-rfc2002-bis-03.txt, 4.6;
02722                                  * This would require that HA would get the
02723                                  * link-layer address of the MN from the
02724                                  * deregistration message and use it in the
02725                                  * gratuitous ARP packet */
02726                         }
02727                         killbinding = 1;
02728                 }
02729         } 
02730 
02731     if(ext.mn_nai == NULL) return -1; //TODO send regreply with error code 97 (missing nai, this is FA's error msg tho) or code 134 (failed auth).
02732     if(ext.mn_nai->length==0) return -1;
02733 
02734 
02735         if (binding == NULL) {
02736 
02737                 if (ntohs(ext.req->lifetime) == 0) {
02738                         DEBUG(DEBUG_FLAG, "Deregistration attempt, but binding"
02739                               " not found - creating temporary binding\n");
02740                         binding = create_binding(&ext, mn_spi, 0);
02741                         killbinding = 1;
02742                 } else {
02743 
02744 
02745 /**************************************
02746 * DYNAMO: Get MN NAI and NAI lenght for dhcp_mobile struct and dhcp-call
02747 **************************************/
02748 
02749         /*
02750          DYNAMO: Check if mobile node with current nai already exists on array
02751                  find returns -1 if already added!
02752         */
02753         
02754         if (find_dhcp_mobile(MSG_MN_NAI_DATA(ext.mn_nai), ext.mn_nai->length)>=0) //-1 == not found
02755         {
02756          LOG(LOG_INFO, "Mobile node was already added in the data structure");  
02757          //return -1; //We dont want to exit even if the mobile is in dhcp_mobile array, we just write in the same place then
02758         
02759         }
02760         
02761         add_dhcp_mobile(0, MSG_MN_NAI_DATA(ext.mn_nai), ext.mn_nai->length); 
02762         
02763         LOG(LOG_INFO, "Preparing for DHCP call for registering mobile node");
02764         
02765         /* Lets find mobile's place in array for DHCP call */
02766         selected_mobile=find_dhcp_mobile(MSG_MN_NAI_DATA(ext.mn_nai), ext.mn_nai->length);
02767         if (selected_mobile <0) return -1; //nai wasnt found, should never happen!!
02768         
02769         /* Get IP for Mobile node from DHCP with NAI as client id*/
02770                 
02771         if(udhcp(selected_mobile,REQUESTIP)==-1) return -1;  //DHCP-server time-out or NAK
02772         
02773         ext.req->home_addr.s_addr=dhcp_mobile_array[selected_mobile].requested_ip; //set the IP-address to regreply extions
02774 
02775 /**************************************
02776 *Dynamics reg_reg handling continues
02777 **************************************/
02778 
02779                         binding = create_binding(&ext, mn_spi, 1);
02780                 }
02781 
02782                 if (binding == NULL) {
02783                         LOG2(LOG_ERR, "Failed to create binding for MN: %s, "
02784                              "FA: %s\n", mn_addrstr, fa_addrstr);
02785                         send_reg_failure(rsock, &cli_addr, mn_spi,
02786                                          (auth_type == AUTH_MAC_RFC2002 ?
02787                                           1 : 0),
02788                                          REGREP_NO_RESOURCES_HA, NULL, &ext,
02789                                          force_iface, binding, from_iface);
02790                         return -1;
02791                 }
02792                 t_data = (struct ha_tunnel_data *) binding->data;
02793                 t_data->auth_type = (auth_type == AUTH_MAC_RFC2002 ?
02794                                      AUTH_RFC2002BIS : AUTH_RFC2002);
02795         }
02796         ASSERT(binding != NULL);
02797         t_data = (struct ha_tunnel_data *) binding->data;
02798         ASSERT(t_data != NULL);
02799 
02800         binding->mod_time = time(NULL);
02801         t_data->reverse_tunnel = (ext.req->opts & REGREQ_REVERSE_TUNNEL) != 0;
02802         if (ext.req->opts & REGREQ_MINIMAL_ENCAPS)
02803                 t_data->encapsulation = ENCAPS_MINIMAL;
02804         else if (ext.req->opts & REGREQ_GRE_ENCAPS)
02805                 t_data->encapsulation = ENCAPS_GRE;
02806         else
02807                 t_data->encapsulation = ENCAPS_IPIP;
02808 
02809         if (ext.fa_keyreq)
02810                 binding->fa_spi = ntohl(ext.fa_keyreq->spi);
02811         else
02812                 binding->fa_spi = 0;
02813 
02814         /* If the request has a public key add it to the binding */
02815         if (ext.fa_pubkey) {
02816                 /* binding->fa_pubkey is NULL if we have generated a
02817                  * new SK. If the public key sent by the FA is the same 
02818                  * as in a previous binding, we can reuse the encrypted
02819                  * SK and save some CPU cycles */
02820                 if (binding->fa_pubkey &&
02821                     binding->last_sent_fa_pubkeyrep != NULL &&
02822                     (memcmp(binding->fa_pubkey, 
02823                             ext.fa_pubkey, 
02824                             GET_KEY_EXT_LEN(ext.fa_pubkey)) == 0))
02825                 {
02826                         DEBUG(DEBUG_FLAG, "Reusing encrypted SK for FA %s\n",
02827                               fa_addrstr);
02828                 } else {
02829                         if (binding->fa_pubkey)
02830                                 free(binding->fa_pubkey);
02831                         if (binding->last_sent_fa_pubkeyrep)
02832                                 free(binding->last_sent_fa_pubkeyrep);
02833                         binding->last_sent_fa_pubkeyrep = NULL;
02834                         binding->fa_pubkey = (struct msg_key *)
02835                                 malloc(GET_KEY_EXT_LEN(ext.fa_pubkey));
02836                         if (binding->fa_pubkey != NULL) {
02837                                 memcpy(binding->fa_pubkey, ext.fa_pubkey,
02838                                        GET_KEY_EXT_LEN(ext.fa_pubkey));
02839                         } else {
02840                                 LOG2(LOG_ERR, "Not enough memory "
02841                                      "for fa_pubkey\n");
02842                                 return -1;
02843                         }
02844                         binding->last_sent_fa_pubkeyrep =
02845                                 dynamics_do_rsa_encrypt(binding->key,
02846                                                         binding->keylen,
02847                                                         binding->fa_pubkey);
02848                         if (binding->last_sent_fa_pubkeyrep == NULL) {
02849                                 LOG2(LOG_ERR, "RSA encryption failed (MN=%s, "
02850                                      "FA=%s)\n", mn_addrstr, fa_addrstr);
02851                         }
02852                 }
02853 
02854         } else {
02855                 /* remove the (possible) old FA pubkey from the binding to make
02856                  * sure that the next FA using RSA will get the correct key */
02857                 if (binding->fa_pubkey)
02858                         free(binding->fa_pubkey);
02859                 binding->fa_pubkey = NULL;
02860 
02861                 if (binding->last_sent_fa_pubkeyrep)
02862                         free(binding->last_sent_fa_pubkeyrep);
02863                 binding->last_sent_fa_pubkeyrep = NULL;
02864         }
02865 
02866         memcpy(&binding->id, ext.req->id, REG_REQ_ID_LEN);
02867 
02868         /* store where the request came from */
02869         t_data->lower_saddr.s_addr = cli_addr.sin_addr.s_addr;
02870         binding->lower_port = cli_addr.sin_port;
02871 
02872         binding->timeout = MIN(ntohs(ext.req->lifetime), mn_spi->max_lifetime);
02873         binding->exp_time = time(NULL) + binding->timeout;
02874 
02875         if (send_reg_repl(rsock, binding, mn_spi, &ext, force_iface,
02876                           code == REGREP_ACCEPTED_NO_SB ?
02877                           REGREP_ACCEPTED_NO_SB : REGREP_ACCEPTED) != 0) {
02878                 LOG2(LOG_ERR, "sending of registration reply to MN: %s, "
02879                      "FA: %s failed\n", mn_addrstr, fa_addrstr);
02880                 remove_tunnel(binding);
02881                 destroy_binding(binding);
02882                 return -1;
02883         }
02884 
02885         if (killbinding) { //del_mobile_dhcp could also be called from here...
02886                 destroy_binding(binding);
02887         } else {
02888                 /* increase timeout with one second so that the one second
02889                  * timer resolution doesn't cause too early expirations */
02890                 binding->timeout++;
02891 
02892                 /* make sure that the bindings module gets timer update just
02893                  * before adding the binding */
02894                 check_bindings();
02895                 binding_add(bindings, binding);
02896         }
02897 
02898  return 0;
02899 }
02900 
02901 
02913 static int
02914 ha_send_agent_adv(struct interface_entry *iface, struct sockaddr_ll *to,
02915                   struct in_addr *dest)
02916 {
02917         /* Set Agent Advertisement data */
02918         set_agent_adv_data(
02919                 config.ha_default_tunnel_lifetime,
02920                 iface->addr,
02921                 iface->addr, AGENT_ADV_HOME_AGENT, 0,
02922                 iface->interval > 21845 ?
02923                 65535 : iface->interval * 3, NULL, 0);
02924         set_agent_adv_nai(ha_nai);
02925 
02926         return send_agent_advertisement(iface->icmp_sock,
02927                                         (struct sockaddr *) to, dest,
02928                                         iface->if_index);
02929 }
02930 
02931 
02943 static void
02944 send_agent_advs(struct timeval *next_agentadv)
02945 {
02946         struct interface_entry *iface;
02947         struct node *node;
02948         struct timeval now, next;
02949         unsigned int diff;
02950         int first = 1;
02951 
02952         /* Send ICMP Agent Advertisement message and save the timestamp */
02953         gettimeofday(&now, NULL);
02954         next.tv_sec = 0;
02955         next.tv_usec = 0;
02956         for (node = list_get_first(&config.interfaces); node != NULL;
02957              node = list_get_next(node)) {
02958                 iface = (struct interface_entry *) node;
02959                 if (iface->agentadv != INTERFACE_AGENTADV_ALL)
02960                         continue;
02961 
02962                 if (now.tv_sec >= iface->last_adv.tv_sec + iface->interval) {
02963                         if (!ha_send_agent_adv(iface, NULL, NULL))
02964                                 stats.adv_sent++;
02965                         else {
02966                                 DEBUG(DEBUG_FLAG, "send_agent_advs: "
02967                                       "advertisement sending to iface[%s] "
02968                                       "failed\n", iface->dev);
02969                         }
02970                         iface->last_adv.tv_sec = now.tv_sec;
02971                         iface->last_adv.tv_usec = now.tv_usec;
02972                 }
02973 
02974                 next.tv_sec = iface->last_adv.tv_sec + iface->interval;
02975                 /* Add random delay */
02976                 next.tv_usec = iface->last_adv.tv_usec +
02977                         (int) (MAX_ADV_DELAY * rand() / (RAND_MAX + 1.0));
02978                 if (next.tv_usec > 999999) {
02979                         next.tv_sec++;
02980                         next.tv_usec -= 1000000;
02981                 }
02982                 if (first || next.tv_sec < next_agentadv->tv_sec) {
02983                         DEBUG(DEBUG_FLAG, "** ");
02984                         *next_agentadv = next;
02985                 }
02986                 first = 0;
02987 
02988                 /* for debuging */
02989                 diff = ((next.tv_sec - now.tv_sec) * 1000000 + 
02990                         next.tv_usec - now.tv_usec) / 1000; 
02991                 DEBUG(DEBUG_FLAG, "send_agent_advs: next agentadv: "
02992                       "%ld.%ld diff = %u msec\n", 
02993                       next.tv_sec, next.tv_usec, diff);
02994         }
02995 }
02996 
02997 
02998 static void
02999 handle_icmp(struct interface_entry *iface)
03000 {
03001         int r;
03002         struct sockaddr_ll from;
03003         struct in_addr to, fromaddr;
03004 
03005         r = check_icmp_sol(iface->icmp_sock, &from, &to, &fromaddr);
03006 
03007         if (r == 0 && iface->agentadv != INTERFACE_AGENTADV_NONE) {
03008                 /* Agent solicitation */
03009                 DEBUG(DEBUG_FLAG,
03010                       "\tagent solicitation => reply with agent adv\n");
03011                 send_agent_advertisement(iface->icmp_sock,
03012                                          (struct sockaddr *) &from, &fromaddr,
03013                                          from.sll_ifindex);
03014         }
03015 }
03016 
03017 
03029 static void
03030 set_expr_timer(struct timeval *tv, struct timeval next_agentadv)
03031 {
03032         int expire_time;
03033         struct timeval now;
03034 
03035         gettimeofday(&now, NULL);
03036         DEBUG(DEBUG_FLAG, "set_expr_timer (now=%li.%06li)\n",
03037               now.tv_sec, now.tv_usec);
03038 
03039         if (timerisset(&next_agentadv)) {
03040                 tv->tv_sec = next_agentadv.tv_sec - now.tv_sec;
03041                 tv->tv_usec = next_agentadv.tv_usec - now.tv_usec;
03042                 if (tv->tv_usec < 0) {
03043                         tv->tv_sec--;
03044                         tv->tv_usec += 1000000;
03045                 }
03046                 if (tv->tv_sec < 0) {
03047                         tv->tv_sec = 0;
03048                         tv->tv_usec = 0;
03049                 }
03050                 DEBUG(DEBUG_FLAG, "\tnext_agentadv in %li.%06li sec\n",
03051                       tv->tv_sec, tv->tv_usec);
03052         } else {
03053                 tv->tv_sec = -1;
03054                 tv->tv_usec = 0;
03055         }
03056 
03057         if ((expire_time = binding_nextexpiretime(bindings)) >= 0) {
03058                 DEBUG(DEBUG_FLAG, "\tbinding next expire in %i sec\n",
03059                       expire_time);
03060                 if (tv->tv_sec < 0 || expire_time < tv->tv_sec) {
03061                         DEBUG(DEBUG_FLAG, "\tsetting expire time to %i sec\n",
03062                               expire_time);
03063                         tv->tv_sec = (time_t)expire_time;
03064                         tv->tv_usec = 0;
03065                 }
03066         }
03067 
03068         if (tv->tv_sec == -1 && tunnel_delayed_exists(tunnels)) {
03069                 DEBUG(DEBUG_FLAG, "\tsetting expire time to %i sec (tunnel "
03070                       "check)\n", TUNNEL_DELAYED_CHECK_INTERVAL);
03071                 tv->tv_sec = TUNNEL_DELAYED_CHECK_INTERVAL;
03072         }
03073 
03074         if (gratuitous_arp_queue != NULL) {
03075                 struct timeval next;
03076 
03077                 next.tv_sec = gratuitous_arp_queue->tv.tv_sec - now.tv_sec;
03078                 next.tv_usec = gratuitous_arp_queue->tv.tv_usec - now.tv_usec;
03079                 if (next.tv_usec < 0) {
03080                         next.tv_sec--;
03081                         next.tv_usec += 1000000;
03082                 }
03083                 if (next.tv_sec < 0) {
03084                         next.tv_sec = 0;
03085                         next.tv_usec = 0;
03086                 }
03087 
03088                 if (tv->tv_sec == -1 || cmp_timeval(tv, &next) > 0) {
03089                         tv->tv_sec = next.tv_sec;
03090                         tv->tv_usec = next.tv_usec;
03091                         DEBUG(DEBUG_FLAG, "\tnext gratuitous ARP in %li.%06li "
03092                               "sec\n", tv->tv_sec, tv->tv_usec);
03093                 }
03094         }
03095 }
03096 
03097 
03105 static void
03106 init_interfaces(void)
03107 {
03108         struct interface_entry *iface;
03109         struct in_addr bc;
03110 
03111         DEBUG(DEBUG_FLAG, "Initializing interfaces\n");
03112         inet_aton("255.255.255.255", &bc);
03113         iface = (struct interface_entry *) list_get_first(&config.interfaces);
03114         if (iface == NULL) {
03115                 LOG2(LOG_ALERT, "No interfaces defined\n");
03116                 clean_up(-1);
03117         }
03118         while (iface != NULL) {
03119                 DEBUG(DEBUG_FLAG, "\t%s: ", iface->dev);
03120                 iface->if_index = dyn_ip_get_ifindex(iface->dev);
03121                 if (iface->if_index < 0) {
03122                         LOG2(LOG_ALERT,
03123                              "Could not get ifindex for interface %s\n",
03124                              iface->dev);
03125                         clean_up(-1);
03126                 }
03127                 DEBUG(DEBUG_FLAG, "ifindex=%i ", iface->if_index);
03128 
03129                 if (iface->force_addr.s_addr != 0) {
03130                         DEBUG(DEBUG_FLAG, "forcing address ");
03131                         iface->addr = iface->force_addr;
03132                 } else {
03133                         if (dyn_ip_get_ifaddr(iface->dev, &iface->addr) != 0) {
03134                                 LOG2(LOG_ALERT, "could not get interface[%s] "
03135                                      "address\n", iface->dev);
03136                                 clean_up(-1);
03137                         }
03138                 }
03139 
03140                 /* bind unicast UDP socket into local IP address, but not
03141                  * interface */
03142                 iface->udp_sock = dynamics_open_udp_socket(
03143                         config.socket_priority, 
03144                         iface->force_addr.s_addr != 0 ? iface->force_addr :
03145                         iface->addr, config.udpport, NULL);
03146                 if (iface->udp_sock < 0) {
03147                         LOG2(LOG_ALERT, "UDP socket opening failed\n");
03148                         clean_up(-1);
03149                 }
03150 
03151                 if (iface->ha_disc) {
03152                         /* bind broadcast UDP sockets into broadcast IP address
03153                          * and interface */
03154                         if (dyn_ip_get_bcaddr(iface->dev, &iface->bcaddr) != 0)
03155                         {
03156                                 LOG2(LOG_ALERT, "could not get interface[%s] "
03157                                      "broadcast address\n", iface->dev);
03158                                 clean_up(-1);
03159                         }
03160                         iface->udp_bc_sock = dynamics_open_udp_socket(
03161                                 config.socket_priority, iface->bcaddr,
03162                                 config.udpport, iface->dev);
03163                         if (iface->udp_bc_sock < 0) {
03164                                 LOG2(LOG_ALERT, "UDP broadcast socket opening "
03165                                      "failed for interface[%s]\n", iface->dev);
03166                                 clean_up(-1);
03167                         }
03168 
03169                         iface->udp_bc_sock2 = dynamics_open_udp_socket(
03170                                 config.socket_priority, bc, config.udpport,
03171                                 iface->dev);
03172                         if (iface->udp_bc_sock2 < 0) {
03173                                 LOG2(LOG_ALERT, "UDP broadcast "
03174                                      "(255.255.255.255) socket opening "
03175                                      "failed for interface[%s]\n", iface->dev);
03176                                 clean_up(-1);
03177                         }
03178                 }
03179 
03180                 iface->icmp_sock =
03181                         open_agent_icmp_adv_socket(iface->dev,
03182                                                    AGENTADV_FILTER_SOL);
03183                 if (iface->icmp_sock < 0) {
03184                         LOG2(LOG_ALERT, "could not open ICMP socket\n");
03185                         clean_up(-1);
03186                 }
03187 
03188                 DEBUG(DEBUG_FLAG, "%s => socket=%i\n", inet_ntoa(iface->addr),
03189                       iface->icmp_sock);
03190 
03191                 iface = (struct interface_entry *) list_get_next(&iface->node);
03192         }
03193 }
03194 
03195 
03203 static void
03204 ha_parse_command_line(int argc, char *argv[])
03205 {
03206         int c, oindex = 0;
03207         static struct option long_options[] = {
03208                 /* common arguments */
03209                 {"help", no_argument, NULL, 'h'},
03210                 {"version", no_argument, NULL, 'v'},
03211                 {"debug", no_argument, NULL, 0},
03212                 {"fg", no_argument, NULL, 0},
03213                 {"config", required_argument, NULL, 'c'},
03214                 /* HA specific arguments */
03215                 /* end of arguments */
03216                 {0, 0, 0, 0}
03217         };
03218 
03219         DEBUG(DEBUG_FLAG, "HA command line parsing\n");
03220 
03221         while ((c = getopt_long(argc, argv, "+hv", long_options, &oindex)) !=
03222                EOF) {
03223                 
03224                 switch (c) {
03225                 case 'h':
03226                         /* show HA specific parameters */
03227                         /* N/A */
03228                         exit(1);
03229                         break;
03230                         
03231                 case '?':
03232                         printf("Command line parsing failed - aborting\n");
03233                         exit(1);
03234 
03235                 case 'v':
03236                 case 'c':
03237                 case 0:
03238                         break;
03239                         
03240                 default:
03241                         printf("?? getopt returned character code 0%o ??\n",
03242                                c);
03243                         exit(1);
03244                 }
03245         }
03246 }
03247 
03248 
03256 int
03257 main(int argc, char *argv[])
03258 {
03259         int api_rw_sock; /* unix socket for privileged (may modify data)
03260                             API calls */
03261         int api_ro_sock; /* unix socket for unprivileged (read only)
03262                             API calls */
03263         struct timeval next_agentadv;
03264         struct interface_entry *iface;
03265 
03266         program_name = parse_long_options(argc, argv, "home agent", PACKAGE,
03267                                           VERSION, dynamics_usage);
03268 
03269         ha_parse_command_line(argc, argv);
03270 
03271         memset(&config, 0, sizeof(struct ha_config));
03272 
03273         if (load_config(&config, program_name,
03274                         opt_config == NULL ? HA_GLOBAL_CONF_FILE : opt_config)
03275             == FALSE) {
03276                 clean_up(1);
03277         }
03278         set_ha_nai();
03279         client_config.interface=config.dhcp_if; //set ethernet interface from HAs config to udhcps config
03280         LOG(LOG_INFO, "Sending DHCP-packets to interface: %s.\n", client_config.interface);
03281 
03282 
03283         check_kernel_support(CHECK_KERNEL_IPIP | CHECK_KERNEL_NETLINK);
03284 
03285         if (getuid() || geteuid()) {
03286                 fprintf(stderr, "%s: This program must be run by root.\n",
03287                         program_name);
03288                 exit(1);
03289         }
03290 
03291         iface = (struct interface_entry *) list_get_first(&config.interfaces);
03292         srand(time(NULL) ^ (iface ? iface->addr.s_addr : 0));
03293 
03294         allow_ipv4_forwarding();
03295 
03296         /* init tables */
03297         bindings = binding_init(config.max_bindings,
03298                                 config.ha_default_tunnel_lifetime);
03299         if (bindings == NULL) {
03300                 LOG2(LOG_ERR, "binding_init failed\n");
03301                 clean_up(1);
03302         }
03303 
03304         init_interfaces();
03305 
03306         tunnels = tunnel_init("TUNL", 1, 253);
03307         if (tunnels == NULL) {
03308                 LOG2(LOG_ERR, "tunnel_init failed\n");
03309                 clean_up(1);
03310         }
03311 
03312         api_rw_sock = api_open_socket(config.ha_api_admin_socket_path,
03313                                       config.ha_api_admin_socket_group,
03314                                       config.ha_api_admin_socket_owner,
03315                                       config.ha_api_admin_socket_permissions);
03316         if (api_rw_sock < 0) {
03317                 LOG2(LOG_ERR, "Could not create API rw-socket\n");
03318                 clean_up(1);
03319         }
03320 
03321         api_ro_sock = api_open_socket(config.ha_api_read_socket_path,
03322                                       config.ha_api_read_socket_group,
03323                                       config.ha_api_read_socket_owner,
03324                                       config.ha_api_read_socket_permissions);
03325         if (api_ro_sock < 0) {
03326                 LOG2(LOG_ERR, "Could not create API ro-socket\n");
03327                 clean_up(1);
03328         }
03329 
03330         if (!opt_foreground && dynamics_fork_daemon() == -1)
03331                 clean_up(1);
03332         dynamics_write_pid_file(HA_PID_FILE);
03333 
03334         memset(&stats, 0, sizeof(stats));
03335         dynamics_strlcpy(stats.version, VERSION, sizeof(stats.version));
03336 
03337         /* set up signal actions */
03338         signal(SIGTERM, sig_handler);            /* clean death */
03339         signal(SIGINT, sig_handler);             /* clean death */
03340         signal(SIGHUP, reload_config);
03341 
03342         syslog(LOG_INFO, "%s home agent daemon version %s started\n",
03343                PACKAGE, VERSION);
03344 
03345         next_agentadv.tv_sec = 0;
03346         next_agentadv.tv_usec = 0;
03347         send_agent_advs(&next_agentadv);
03348 
03349         /* loop forever waiting for messages */
03350         for (;;) {
03351 
03352         
03353                 fd_set set;
03354                 int oldmask;
03355                 struct node *node;
03356                 struct timeval tv;
03357 
03358                 oldmask = sigblock(sigmask(SIGHUP));
03359                 FD_ZERO(&set);
03360                 FD_SET(api_rw_sock, &set);
03361                 FD_SET(api_ro_sock, &set);
03362                 for (node = list_get_first(&config.interfaces); node != NULL;
03363                      node = list_get_next(node)) {
03364                         iface = (struct interface_entry *) node;
03365                         FD_SET(iface->udp_sock, &set);
03366                         if (iface->ha_disc && iface->udp_bc_sock > -1)
03367                                 FD_SET(iface->udp_bc_sock, &set);
03368                         if (iface->ha_disc && iface->udp_bc_sock2 > -1)
03369                                 FD_SET(iface->udp_bc_sock2, &set);
03370                         FD_SET(iface->icmp_sock, &set);
03371                 }
03372 
03373                 set_expr_timer(&tv, next_agentadv);
03374                 sigsetmask(oldmask);
03375 
03376                 if (select(FD_SETSIZE, &set, NULL, NULL,
03377                            tv.tv_sec == -1 ? NULL : &tv) < 0) {
03378                         /* don't exit on e.g. SIGHUP */
03379                         if (errno != EINTR) {
03380                                 LOG2(LOG_ERR, "select - %s", strerror(errno));
03381                                 clean_up(1);
03382                         }
03383                         continue;
03384                 }
03385                        
03386                 /* we don't want to reread the configuration file
03387                  * while we are handling requests; hold the signal
03388                  * until we are ready */
03389                 oldmask = sigblock(sigmask(SIGHUP));
03390 
03391                 if (FD_ISSET(api_rw_sock, &set)) {
03392                         /* privileged API call */
03393                         handle_api(api_rw_sock, 1);
03394                 }
03395 
03396                 if (FD_ISSET(api_ro_sock, &set)) {
03397                         /* unprivileged API call */
03398                         handle_api(api_ro_sock, 0);
03399                 }
03400 
03401                 for (node = list_get_first(&config.interfaces); node != NULL;
03402                      node = list_get_next(node)) {
03403                         iface = (struct interface_entry *) node;
03404                         if (FD_ISSET(iface->udp_sock, &set)) {
03405                                 LOG(LOG_INFO, "Got UDP message(%s)\n",
03406                                       iface->dev);
03407 
03408                                 handle_reg_msg(iface, iface->udp_sock);
03409                                 
03410                                 
03411                         }
03412                         if (iface->ha_disc && iface->udp_bc_sock > -1 &&
03413                             FD_ISSET(iface->udp_bc_sock, &set)) {
03414                                 DEBUG(DEBUG_FLAG, "Got UDP (BC) message(%s)\n",
03415                                       iface->dev);
03416 
03417                 
03418                                 handle_reg_msg(iface, iface->udp_bc_sock);
03419                         }
03420                         if (iface->ha_disc && iface->udp_bc_sock2 > -1 &&
03421                             FD_ISSET(iface->udp_bc_sock2, &set)) {
03422                                 DEBUG(DEBUG_FLAG, "Got UDP (BC "
03423                                       "255.255.255.255) message(%s)\n",
03424                                       iface->dev);
03425         
03426                                 
03427                                 handle_reg_msg(iface, iface->udp_bc_sock2);
03428                         }
03429                         if (FD_ISSET(iface->icmp_sock, &set)) {
03430                                 handle_icmp(iface);
03431                         }
03432                         
03433                 }
03434 
03435 
03436                 if (timerisset(&next_agentadv))
03437                         send_agent_advs(&next_agentadv);
03438 
03439                 check_bindings();
03440                 tunnel_check_delayed(tunnels, 0);
03441                 check_queued_gratuitous_arp();
03442 
03443                 sigsetmask(oldmask);
03444                 
03445         }
03446 
03447         /* not reached */
03448         return 0;
03449 }

Generated on Tue Jan 15 12:24:45 2008 for Dynamics 0.8.1.Dynamo.1 by  doxygen 1.5.1