📄 mh.c
字号:
/*---------------------------------------------------------------------------- Copyright (C) 1995-6, Vipul Gupta and Abhijit Dixit. Created 1995-6. All rights reserved. Linux-Mobile-IP An implementation of Mobile IP for the LINUX operating system developed at the State University of New York, Binghamton (with partial support from the Center for Computing Technologies). Except as noted in the accompanying documentation, this implementation complies with revision 16 of the Internet Engineering Task Force (IETF) Mobile-IP draft. More information can be obtained from: http://anchor.cs.binghamton.edu/~mobileip/ Version: 1.00 05/23/1996 Authors: Abhijit Dixit <abhijit@cs.binghamton.edu> Vipul Gupta <vgupta@cs.binghamton.edu> Benjamin Lancki <ben@anchor.cs.binghamton.edu> Permission is hereby granted to redistribute this code and/or modify it under the terms of the GNU Genral Public License as published by the Free Software Foundation; either version two or (at your option) any later version provided this ENTIRE notice is retained in any copies or any part of this software. A copy of the GNU General Public License can be obtained by contacting the Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA. -----------------------------------------------------------------------------*/ /* * * mh.c : Design of the Mobile Host * * Command line arguments: * -a : mobile host's IP address on its home network * -m : network mask corresponding to the IP address above * -g : IP address on the mobility interface of the homeagent. * * * * History of Changes: * Jul 25, 1995 First version coded - V.G. * Aug 1, 1995 Removed bug in processURhere. Now we * turn off REGAWAY when we move home and * turn off REGHOME when we move away - V.G. * Aug 2, 1995 Moved URhere gathering in alarm_handler() * as part of preventing a flip-flop effect * when a mobile host hears URhere messages * from multiple mobility agents * alternately - V.G. * Aug 9, 1995 Added support for MD5 authentication in * processing the registration and registration * reply - B.L. * Aug 13, 1995 Agent now reads config file /etc/mip-mh.ok to * initialize mhinfo struct - B.L. * Aug 14, 1995 Agent keeps a log in event of system crash * or shutdown and recovers on startup - B.L. * * * Sept 20, 1995 Low level routine added for adding and * deleting route to a network -A.D. * * * * Sept 22, 1995 Changed the code so Registerme mesgs are * now sent to FA instead of home agent; * because of this change , reply from home * agent forwarded by foreign agent. * Separate mobile subnet is * not required. -A.D. * * Sept 30, 1995 mh does not exit when select fails on * INTR -A.D * * Oct 5, 1995 ARP cache is flushed when MH moves to * new network.-A.D. * * Oct 10, 1995 mh does not exit when sendto fails * because of network or host unreachable * condition. -A.D. * * Nov 10, 1995 Due to addition of a 'special sleep' * mh consumes very little cpu time.- A.D. * * Dec 5, 1995 Router Solicitation * Messages changed to use ICMP -A.D. * * April 1996 Complete redesign of the Mobile Host. * MH now operates without Foreign Agent (Self * Decapsulation) and some of the other * inefficiencies are removed. * - V.G. and A.D. * * May 1996 MH now sends gratuitous ARP after to coming to home network. * -A.D.*/#include <stdio.h>#include <sys/types.h>#include <sys/time.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <signal.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <netinet/ip.h>#include "mh.h"#include "low.h"#define did_reboot(new,prev) (((new)<(prev))&((new)<256))/* Application required flags */#define APREF 0x00int debug = 2;short doit = 0;char *state[] = { "INIT", "ATHOME", "ATFOREIGN", "ASPOPUP"};extern int errno;extern void testprint(char *,int);extern void appendauth(char *,int *,char *,int,unsigned long);extern int authextfound(char *,int,int);extern int authok(char *,int,int,char *,int,unsigned long);extern void printext(char *,int,int);extern void printtime();extern int in_cksum(u_short*,int);extern int lowdefifcreq(u_long*,u_long*,char*);void sendRegisterMe(int, unsigned char, unsigned short, unsigned long, unsigned long, unsigned long);int routersolId, URheresid, Regreplysid, RegisterMesid;int ioctlsid;void usage(char *), cleanup();struct sockaddr_in routersolto = { (short) AF_INET, (unsigned short) 0, (unsigned long) 0, (unsigned long) 0 };char lastreq[1024]; /* this is the last request on which we are awaiting a reply */void init();myinfo Myinfo;dm_info Dminfo;short backoff[] = {1,2,4,8,16,32,64};short renewal[] = {2,4,8};struct stats { unsigned long badurhere; unsigned long badregreply; unsigned long idmismatch; unsigned long authfailed; unsigned long regsent; unsigned long regfailed; unsigned long regsuccessful;} mhstats = { (long) 0, (long) 0, (long) 0, (long) 0, (long) 0, (long) 0, (long) 0 };voidinitsockets() { struct sockaddr_in sa; int enable = 1; bzero((void*)&sa,sizeof(sa)); routersolId = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); Regreplysid = RegisterMesid = socket(AF_INET, SOCK_DGRAM, 0); URheresid = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); ioctlsid = socket(AF_INET, SOCK_DGRAM, 0); if (Regreplysid < 0 || URheresid < 0 || routersolId < 0 || RegisterMesid < 0 || ioctlsid < 0) { fprintf(stderr, "initsockets(): could not create sockets.\n"); exit(-1); } sa.sin_family = AF_INET; sa.sin_addr.s_addr = htonl(INADDR_ANY); if (setsockopt(routersolId, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(int)) < 0) { perror("initsockets(): setsockopt SO_BROADCAST failed"); cleanup(); exit(-1); } /* This is where we receive regreplies and send registermes from */ sa.sin_port = 0; if (bind(RegisterMesid, (struct sockaddr *) &sa, sizeof(sa)) < 0) { perror("initsockets(): Bind RegisterMesid failed.\n"); cleanup(); exit(-1); } if (debug > 0) fprintf(stderr, "Initialized sockets ...\n");}voidcleanup() { if (debug > 1) fprintf(stderr, "Done cleaning up ... \n");}voidgraceful_exit() { struct sockaddr_in sock; unsigned char flags = 0x00; cleanup(); if ((Myinfo.status & 0x03)== ATFOREIGN || (Myinfo.status & 0x03) == ASPOPUP) { Myinfo.retries = 0; sendRegisterMe((int) 0, flags, (unsigned short) 0, Myinfo.homeaddr, Myinfo.homeagent, Myinfo.coaddr); } /* deregister ourselves if we were registered or this will * tie up a tunnel for atmost MAXLIFETIME period */ exit(0);}voidsendroutersol(struct sockaddr_in *toaddr){ struct icmp msg; memset((char*)&msg,0,sizeof(struct icmp)); if (debug > 0) fprintf(stderr, "\n-- RouterSol to %s.\n", inet_ntoa(toaddr->sin_addr)); msg.type = ROUTERSOLTYPE; msg.code = 0; msg.cksum = 0; msg.cksum = in_cksum((u_short*)&msg,sizeof(struct icmp)); if (sendto(routersolId, (char *) &msg, sizeof(msg), 0, (struct sockaddr *) toaddr, sizeof(struct sockaddr)) < 0) { perror("sendroutersol(): send to failed.\n"); if(errno == ECONNREFUSED || errno == ENETUNREACH || errno == EHOSTUNREACH); else { cleanup(); exit(-1); } }}voidsendRegisterMe(int attempt, unsigned char flags, unsigned short lifetime, unsigned long homeaddr, unsigned long homeagent, unsigned long coaddr){ struct sockaddr_in toaddr; struct registerme *req; static int len; toaddr.sin_family = AF_INET; toaddr.sin_port = htons(MIPREGPORT); /* Depending upon ASPOPUP and ATFOREIGN states toaddr is selected */ if(Myinfo.status & 0x03 == ASPOPUP) toaddr.sin_addr.s_addr = Myinfo.homeagent; else toaddr.sin_addr.s_addr = Myinfo.closeagentaddr; if(attempt != 0) { fprintf(stderr,"Retransmitting the same (earlier) request\n"); if (sendto(RegisterMesid, (char *) lastreq, len, 0, (struct sockaddr *) &toaddr, sizeof(struct sockaddr)) < 0) { perror("sendRegisterMe(): send to failed.\n"); if(errno == ECONNREFUSED || errno == ENETUNREACH || errno == EHOSTUNREACH); else { cleanup(); exit(-1); } }; return; } len = sizeof(struct registerme); req = (struct registerme *) lastreq; req->type = REGISTERMETYPE; req->flags = flags; req->lifetime = lifetime; req->homeaddr = homeaddr; req->ha = homeagent; req->coaddr = coaddr; /* we generate a new 64-bit Id unless this is a retransmission */ if (attempt == 0) NewId(&Myinfo.RequestId, &Myinfo.RequestId); req->Id.high = Myinfo.RequestId.high; req->Id.low = Myinfo.RequestId.low; appendauth(lastreq, &len, Myinfo.secret, Myinfo.secretlen,Myinfo.SPIval); if (debug > 0) { fprintf(stderr, "\n==========================\n"); printtime(); if (req->lifetime == 0) fprintf(stderr, "-- DEREGISTERME to %s at port %d (attempt %d).\n", inet_ntoa(toaddr.sin_addr), (unsigned int) toaddr.sin_port, attempt); else fprintf(stderr, "-- REGISTERME to %s at port %d (attempt %d).\n", inet_ntoa(toaddr.sin_addr), (unsigned int) toaddr.sin_port, attempt); if (debug > 1) { fprintf(stderr, "[%8lx:%8lx] Type %2d Flags %2x Lifetime %8d\n", req->Id.high, req->Id.low, req->type, req->flags, req->lifetime); fprintf(stderr, "Homeaddr: %8lx, Homeagent: %8lx, Careof: %8lx", htonl(req->homeaddr), htonl(req->ha), htonl(req->coaddr)); if (debug > 2) { fprintf(stderr, "\n--------------------\n"); printext(lastreq, len, 0); testprint(lastreq, len); fprintf(stderr, "--------------------"); } } fprintf(stderr, "\n==========================\n"); } if (sendto(RegisterMesid, (char *) lastreq, len, 0, (struct sockaddr *) &toaddr, sizeof(struct sockaddr)) < 0) { perror("sendRegisterMe(): send to failed.\n"); if(errno == ECONNREFUSED || errno == ENETUNREACH || errno == EHOSTUNREACH); else { cleanup(); exit(-1); } };}void dsn_maker(int);voidalarm_handler() { struct registerme *req; if(debug >2) fprintf(stderr,"The current state is %s\n",state[Myinfo.status & 0x03]); if((Myinfo.status & 0x03)== INIT) sendroutersol(&routersolto); dsn_maker(URheresid); /* we take care of our registration renewals */ if (!((Myinfo.status & 0x03) == ATHOME && (Myinfo.status & DEREGISTERED)||Myinfo.status == INIT)) { Myinfo.timeleft-=2; if(Myinfo.status & REGISTERED) { if(Myinfo.retries <3){ if(Myinfo.timeleft <= Myinfo.lifetime/renewal[Myinfo.retries]) { /* Send new registration request */ Myinfo.status |= AWAITINGREPLY; sendRegisterMe((int) 0, Myinfo.flags,Myinfo.lifetime,Myinfo.homeaddr, Myinfo.homeagent, Myinfo.coaddr); Myinfo.retries++; } } else if (Myinfo.timeleft <= 0) { Myinfo.timeleft = 0; /* Restore normal POPUP state so we ca have at least simple connectivity */ if((Myinfo.status & 0x03)==ASPOPUP) { lowifaceset(Myinfo.infname, Myinfo.coaddr, Myinfo.foreignnetmask); lowifacedown("dummy"); } init((int)1); if (debug > 1) { fprintf(stderr, "Registration expired ... \n"); } } } /* Take care of an request Retransmissions if NOT YET registered */ else { if (Myinfo.timeleft <= 0) { Myinfo.timeleft = 0; if(Myinfo.retries < 6) { Myinfo.timeleft = (backoff[Myinfo.retries++])*RETRYINTERVAL; req = (struct registerme *) lastreq; sendRegisterMe(Myinfo.retries, req->flags, req->lifetime, req->homeaddr, req->ha, req->coaddr); } else { /* MH has retransmitted this request enough times and and now it goes back to INIT state */ init((int)1); if (debug > 1) { fprintf(stderr, "We have retransmitted enough ... \n"); } } } } } signal(SIGALRM, alarm_handler); alarm(1);}slp(double sec){ struct timeval tv; tv.tv_sec = 0; tv.tv_usec = sec*1000000 ; if((select(FD_SETSIZE, NULL, NULL, NULL, &tv)) < 0) { if(errno == EINTR || errno == ERESTART); else perror("select() failed in main loop.\n"); } }voidinit(int level) { Myinfo.timeleft = Myinfo.closeagentaddr = Myinfo.retries =0; Myinfo.agentflags = Myinfo.seqno = Myinfo.lifetime =0; Myinfo.coaddr = 0; Myinfo.status = 0x00; /*INIT*/ if(level == 0){ bzero((void*)&Dminfo,sizeof(dm_info)); initsockets(); routersolto.sin_addr.s_addr = inet_addr(ADVERTISEON); readhadata("/etc/mip-ha.dat"); signal(SIGTERM, graceful_exit); signal(SIGINT, graceful_exit); signal(SIGALRM, alarm_handler); alarm(1); }} intIsOurAddress(unsigned long addr) { return((Myinfo.homeaddr == addr) ? 1:0);}intIsOurAgent(unsigned long addr) { return((Myinfo.homeagent == addr) ? 1:0);}intmhIdcmp(struct id *id1, struct id *id2) { return((id1->low == id2->low) ? 0:1);}intNewId(struct id *id1, struct id *id2) { static count = 0; struct timeval tv; if (count++ == 0) { gettimeofday(&tv, NULL); srandom((int) tv.tv_usec); }; id1->high = id2->high; id1->low = (unsigned long) random();}void processRegreply(char *msg, int len, struct sockaddr_in *from) { struct regreply *reply; int authoffset; char hwaddr[10]; reply = (struct regreply *) msg; /* This should never happen (probability is very very low) because after we get a good reply we change the Id that we now expect to a value we never sent */ if (Myinfo.status & AWAITINGREPLY == 0) { fprintf(stderr, "Got a reply when we weren't expecting it.\n"); return; } /* Print contents of received message */ if (debug > 0) { fprintf(stderr, "\n==========================\n"); printtime(); fprintf(stderr, "-- REPLY from %s ", inet_ntoa(from->sin_addr)); if ((reply->code != 0) && (reply->code != 1)) fprintf(stderr, "(Rejection)\n"); else fprintf(stderr, "(Acceptance)\n"); if (debug > 1) { fprintf(stderr, "[%8lx:%8lx] Type %2d Code %3d Lifetime %8d\n", reply->Id.high, reply->Id.low, reply->type, reply->code, reply->lifetime); fprintf(stderr, "Homeaddr: %8lx, Homeagent: %8lx", htonl(reply->homeaddr), htonl(reply->ha)); if (debug > 2) { fprintf(stderr, "\n--------------------\n"); printext(msg, len, 1); testprint(msg, len); fprintf(stderr, "--------------------"); } } fprintf(stderr, "\n==========================\n"); } Myinfo.RequestId.high = reply->Id.high; Myinfo.retries = 0; if (mhIdcmp(&Myinfo.RequestId, &(reply->Id)) != 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -