ns-icmp_redirector.c revision df3eb16e38c6a163b0a7367c885679eed6140964
197903da2202008733f50e69997029d7a5cfffcb8mreed/******************************************************************************/
297903da2202008733f50e69997029d7a5cfffcb8mreed/*                                                                            */
397903da2202008733f50e69997029d7a5cfffcb8mreed/*   Copyright (c) International Business Machines  Corp., 2006               */
497903da2202008733f50e69997029d7a5cfffcb8mreed/*                                                                            */
597903da2202008733f50e69997029d7a5cfffcb8mreed/*   This program is free software;  you can redistribute it and/or modify    */
697903da2202008733f50e69997029d7a5cfffcb8mreed/*   it under the terms of the GNU General Public License as published by     */
797903da2202008733f50e69997029d7a5cfffcb8mreed/*   the Free Software Foundation; either version 2 of the License, or        */
897903da2202008733f50e69997029d7a5cfffcb8mreed/*   (at your option) any later version.                                      */
997903da2202008733f50e69997029d7a5cfffcb8mreed/*                                                                            */
1097903da2202008733f50e69997029d7a5cfffcb8mreed/*   This program is distributed in the hope that it will be useful,          */
1197903da2202008733f50e69997029d7a5cfffcb8mreed/*   but WITHOUT ANY WARRANTY;  without even the implied warranty of          */
1297903da2202008733f50e69997029d7a5cfffcb8mreed/*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                */
1397903da2202008733f50e69997029d7a5cfffcb8mreed/*   the GNU General Public License for more details.                         */
1497903da2202008733f50e69997029d7a5cfffcb8mreed/*                                                                            */
1597903da2202008733f50e69997029d7a5cfffcb8mreed/*   You should have received a copy of the GNU General Public License        */
1697903da2202008733f50e69997029d7a5cfffcb8mreed/*   along with this program;  if not, write to the Free Software             */
1797903da2202008733f50e69997029d7a5cfffcb8mreed/*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA  */
1897903da2202008733f50e69997029d7a5cfffcb8mreed/*                                                                            */
1997903da2202008733f50e69997029d7a5cfffcb8mreed/******************************************************************************/
2097903da2202008733f50e69997029d7a5cfffcb8mreed
2197903da2202008733f50e69997029d7a5cfffcb8mreed
2297903da2202008733f50e69997029d7a5cfffcb8mreed/*
2397903da2202008733f50e69997029d7a5cfffcb8mreed * File:
2497903da2202008733f50e69997029d7a5cfffcb8mreed *	ns-icmp_redirector.c
2597903da2202008733f50e69997029d7a5cfffcb8mreed *
2697903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
2797903da2202008733f50e69997029d7a5cfffcb8mreed *	This is ICMPv4/ICMPv6 redirect message sender.
2897903da2202008733f50e69997029d7a5cfffcb8mreed *	The host under test assume the host where this utility run is a
2997903da2202008733f50e69997029d7a5cfffcb8mreed *	gateway. When the utility receives the packet from the host
3097903da2202008733f50e69997029d7a5cfffcb8mreed *	under test. This utility reply ICMP redirect message.
3197903da2202008733f50e69997029d7a5cfffcb8mreed *
3297903da2202008733f50e69997029d7a5cfffcb8mreed * Author:
3397903da2202008733f50e69997029d7a5cfffcb8mreed *	Mitsuru Chinen <mitch@jp.ibm.com>
3497903da2202008733f50e69997029d7a5cfffcb8mreed *
3597903da2202008733f50e69997029d7a5cfffcb8mreed * History:
3697903da2202008733f50e69997029d7a5cfffcb8mreed *	Mar 31 2006 - Created (Mitsuru Chinen)
3797903da2202008733f50e69997029d7a5cfffcb8mreed *---------------------------------------------------------------------------*/
3897903da2202008733f50e69997029d7a5cfffcb8mreed
3997903da2202008733f50e69997029d7a5cfffcb8mreed/*
4097903da2202008733f50e69997029d7a5cfffcb8mreed * Header Files
4197903da2202008733f50e69997029d7a5cfffcb8mreed */
4297903da2202008733f50e69997029d7a5cfffcb8mreed#include <stdio.h>
4397903da2202008733f50e69997029d7a5cfffcb8mreed#include <stdlib.h>
4497903da2202008733f50e69997029d7a5cfffcb8mreed#include <string.h>
4597903da2202008733f50e69997029d7a5cfffcb8mreed#include <errno.h>
4697903da2202008733f50e69997029d7a5cfffcb8mreed#include <fcntl.h>
4797903da2202008733f50e69997029d7a5cfffcb8mreed#include <netdb.h>
4897903da2202008733f50e69997029d7a5cfffcb8mreed#include <signal.h>
4997903da2202008733f50e69997029d7a5cfffcb8mreed#include <time.h>
5097903da2202008733f50e69997029d7a5cfffcb8mreed#include <unistd.h>
5197903da2202008733f50e69997029d7a5cfffcb8mreed#include <sys/ioctl.h>
5297903da2202008733f50e69997029d7a5cfffcb8mreed#include <sys/socket.h>
5397903da2202008733f50e69997029d7a5cfffcb8mreed#include <arpa/inet.h>
5497903da2202008733f50e69997029d7a5cfffcb8mreed#include <net/ethernet.h>
5597903da2202008733f50e69997029d7a5cfffcb8mreed#include <net/if_arp.h>
5697903da2202008733f50e69997029d7a5cfffcb8mreed#include <netinet/if_ether.h>
5797903da2202008733f50e69997029d7a5cfffcb8mreed
5897903da2202008733f50e69997029d7a5cfffcb8mreed#include "ns-traffic.h"
5997903da2202008733f50e69997029d7a5cfffcb8mreed
6097903da2202008733f50e69997029d7a5cfffcb8mreed/*
6197903da2202008733f50e69997029d7a5cfffcb8mreed * Structure definition
6297903da2202008733f50e69997029d7a5cfffcb8mreed */
6397903da2202008733f50e69997029d7a5cfffcb8mreedstruct redirector_info {
6497903da2202008733f50e69997029d7a5cfffcb8mreed    int sd;
6597903da2202008733f50e69997029d7a5cfffcb8mreed    char *ifname;
6697903da2202008733f50e69997029d7a5cfffcb8mreed    double timeout;
6797903da2202008733f50e69997029d7a5cfffcb8mreed};
6897903da2202008733f50e69997029d7a5cfffcb8mreed
6997903da2202008733f50e69997029d7a5cfffcb8mreedstruct ip4_gateway_info {
7097903da2202008733f50e69997029d7a5cfffcb8mreed    unsigned char hd_addr[ETH_ALEN];
7197903da2202008733f50e69997029d7a5cfffcb8mreed    unsigned char ip_addr[4];
7297903da2202008733f50e69997029d7a5cfffcb8mreed    unsigned char nexthop[4];
7397903da2202008733f50e69997029d7a5cfffcb8mreed};
7497903da2202008733f50e69997029d7a5cfffcb8mreed
7597903da2202008733f50e69997029d7a5cfffcb8mreedstruct ip6_gateway_info {
7697903da2202008733f50e69997029d7a5cfffcb8mreed    unsigned char hd_addr[ETH_ALEN];
7797903da2202008733f50e69997029d7a5cfffcb8mreed    struct in6_addr ip_addr;
7897903da2202008733f50e69997029d7a5cfffcb8mreed    struct in6_addr nexthop;
7997903da2202008733f50e69997029d7a5cfffcb8mreed};
8097903da2202008733f50e69997029d7a5cfffcb8mreed
8197903da2202008733f50e69997029d7a5cfffcb8mreed
8297903da2202008733f50e69997029d7a5cfffcb8mreed/*
8397903da2202008733f50e69997029d7a5cfffcb8mreed * Gloval variables
8497903da2202008733f50e69997029d7a5cfffcb8mreed */
8597903da2202008733f50e69997029d7a5cfffcb8mreedchar *program_name;		/* program name */
8697903da2202008733f50e69997029d7a5cfffcb8mreedstruct sigaction handler;	/* Behavior for a signal */
8797903da2202008733f50e69997029d7a5cfffcb8mreedint catch_sighup;		/* When catch the SIGHUP, set to non-zero */
8897903da2202008733f50e69997029d7a5cfffcb8mreed
8997903da2202008733f50e69997029d7a5cfffcb8mreed
9097903da2202008733f50e69997029d7a5cfffcb8mreed/*
9197903da2202008733f50e69997029d7a5cfffcb8mreed * Function: usage()
9297903da2202008733f50e69997029d7a5cfffcb8mreed *
9397903da2202008733f50e69997029d7a5cfffcb8mreed * Descripton:
9497903da2202008733f50e69997029d7a5cfffcb8mreed *  Print the usage of this program. Then, terminate this program with
9597903da2202008733f50e69997029d7a5cfffcb8mreed *  the specified exit value.
9697903da2202008733f50e69997029d7a5cfffcb8mreed *
9797903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
9897903da2202008733f50e69997029d7a5cfffcb8mreed *  exit_value:	exit value
9997903da2202008733f50e69997029d7a5cfffcb8mreed *
10097903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
10197903da2202008733f50e69997029d7a5cfffcb8mreed *  This function does not return.
10297903da2202008733f50e69997029d7a5cfffcb8mreed */
10397903da2202008733f50e69997029d7a5cfffcb8mreedvoid
10497903da2202008733f50e69997029d7a5cfffcb8mreedusage (char *program_name, int exit_value)
10597903da2202008733f50e69997029d7a5cfffcb8mreed{
10697903da2202008733f50e69997029d7a5cfffcb8mreed    FILE *stream = stdout;	/* stream where the usage is output */
10797903da2202008733f50e69997029d7a5cfffcb8mreed
10897903da2202008733f50e69997029d7a5cfffcb8mreed    if (exit_value == EXIT_FAILURE)
10997903da2202008733f50e69997029d7a5cfffcb8mreed	stream = stderr;
11097903da2202008733f50e69997029d7a5cfffcb8mreed
11197903da2202008733f50e69997029d7a5cfffcb8mreed    fprintf (stream, "%s [OPTION]\n"
11297903da2202008733f50e69997029d7a5cfffcb8mreed		     "\t-I if_name\tInterface where input/output packets\n"
11397903da2202008733f50e69997029d7a5cfffcb8mreed		     "\t-t value\ttimeout [sec]\n"
11497903da2202008733f50e69997029d7a5cfffcb8mreed		     "\t-b\t\ttimeout [sec]\n"
11597903da2202008733f50e69997029d7a5cfffcb8mreed		     "\t-d\t\tdisplay debug informations\n"
11697903da2202008733f50e69997029d7a5cfffcb8mreed		     "\t-h\t\tdisplay this usage\n"
11797903da2202008733f50e69997029d7a5cfffcb8mreed			    , program_name);
11897903da2202008733f50e69997029d7a5cfffcb8mreed    exit (exit_value);
11997903da2202008733f50e69997029d7a5cfffcb8mreed}
12097903da2202008733f50e69997029d7a5cfffcb8mreed
12197903da2202008733f50e69997029d7a5cfffcb8mreed
12297903da2202008733f50e69997029d7a5cfffcb8mreed/*
12397903da2202008733f50e69997029d7a5cfffcb8mreed * Function: set_signal_flag()
12497903da2202008733f50e69997029d7a5cfffcb8mreed *
12597903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
12697903da2202008733f50e69997029d7a5cfffcb8mreed *  This function sets global variables according to a signal
12797903da2202008733f50e69997029d7a5cfffcb8mreed *
12897903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
12997903da2202008733f50e69997029d7a5cfffcb8mreed *  type: type of signal
13097903da2202008733f50e69997029d7a5cfffcb8mreed *
13197903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
13297903da2202008733f50e69997029d7a5cfffcb8mreed *  None
13397903da2202008733f50e69997029d7a5cfffcb8mreed */
13497903da2202008733f50e69997029d7a5cfffcb8mreedvoid
13597903da2202008733f50e69997029d7a5cfffcb8mreedset_signal_flag(int type)
13697903da2202008733f50e69997029d7a5cfffcb8mreed{
13797903da2202008733f50e69997029d7a5cfffcb8mreed    if (debug)
13897903da2202008733f50e69997029d7a5cfffcb8mreed	fprintf(stderr, "Catch signal. type is %d\n", type);
13997903da2202008733f50e69997029d7a5cfffcb8mreed
14097903da2202008733f50e69997029d7a5cfffcb8mreed    switch (type) {
14197903da2202008733f50e69997029d7a5cfffcb8mreed	case SIGHUP:
14297903da2202008733f50e69997029d7a5cfffcb8mreed	    catch_sighup = 1;
14397903da2202008733f50e69997029d7a5cfffcb8mreed	    handler.sa_handler = SIG_IGN;
14497903da2202008733f50e69997029d7a5cfffcb8mreed	    if (sigaction(type, &handler, NULL) < 0)
14597903da2202008733f50e69997029d7a5cfffcb8mreed		fatal_error("sigaction()");
14697903da2202008733f50e69997029d7a5cfffcb8mreed	    break;
14797903da2202008733f50e69997029d7a5cfffcb8mreed
14897903da2202008733f50e69997029d7a5cfffcb8mreed	default:
14997903da2202008733f50e69997029d7a5cfffcb8mreed	    fprintf(stderr, "Unexpected signal (%d) is caught\n", type);
15097903da2202008733f50e69997029d7a5cfffcb8mreed	    exit(EXIT_FAILURE);
15197903da2202008733f50e69997029d7a5cfffcb8mreed    }
15297903da2202008733f50e69997029d7a5cfffcb8mreed}
15397903da2202008733f50e69997029d7a5cfffcb8mreed
15497903da2202008733f50e69997029d7a5cfffcb8mreed
15597903da2202008733f50e69997029d7a5cfffcb8mreed/*
15697903da2202008733f50e69997029d7a5cfffcb8mreed * Function: parse_options()
15797903da2202008733f50e69997029d7a5cfffcb8mreed *
15897903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
15997903da2202008733f50e69997029d7a5cfffcb8mreed *  This function parse the options
16097903da2202008733f50e69997029d7a5cfffcb8mreed *
16197903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
16297903da2202008733f50e69997029d7a5cfffcb8mreed *     argc:	    number of argument
16397903da2202008733f50e69997029d7a5cfffcb8mreed *     argv:	    arguments
16497903da2202008733f50e69997029d7a5cfffcb8mreed *  redirector_p:   pointer to data for the redirector information
16597903da2202008733f50e69997029d7a5cfffcb8mreed *     bg_p:	    pointer to the flag of working in backgrond
16697903da2202008733f50e69997029d7a5cfffcb8mreed *
16797903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
16897903da2202008733f50e69997029d7a5cfffcb8mreed *  None
16997903da2202008733f50e69997029d7a5cfffcb8mreed */
17097903da2202008733f50e69997029d7a5cfffcb8mreedvoid
17197903da2202008733f50e69997029d7a5cfffcb8mreedparse_options(int argc, char *argv[], struct redirector_info *redirector_p, int *bg_p)
17297903da2202008733f50e69997029d7a5cfffcb8mreed{
17397903da2202008733f50e69997029d7a5cfffcb8mreed    int optc;			/* option */
17497903da2202008733f50e69997029d7a5cfffcb8mreed    double opt_d;		/* option value in double */
17597903da2202008733f50e69997029d7a5cfffcb8mreed
17697903da2202008733f50e69997029d7a5cfffcb8mreed    while ((optc = getopt(argc, argv, "I:N:t:bdh")) != EOF ) {
17797903da2202008733f50e69997029d7a5cfffcb8mreed	switch (optc) {
17897903da2202008733f50e69997029d7a5cfffcb8mreed	    case 'I':
17997903da2202008733f50e69997029d7a5cfffcb8mreed		redirector_p->ifname = strdup(optarg);
18097903da2202008733f50e69997029d7a5cfffcb8mreed		if (redirector_p->ifname == NULL)
18197903da2202008733f50e69997029d7a5cfffcb8mreed		    fatal_error("strdup() failed.");
18297903da2202008733f50e69997029d7a5cfffcb8mreed		break;
18397903da2202008733f50e69997029d7a5cfffcb8mreed
18497903da2202008733f50e69997029d7a5cfffcb8mreed	    case 't':
18597903da2202008733f50e69997029d7a5cfffcb8mreed		opt_d = strtod(optarg, NULL);
18697903da2202008733f50e69997029d7a5cfffcb8mreed		if (opt_d < 0.0) {
18797903da2202008733f50e69997029d7a5cfffcb8mreed		    fprintf(stderr, "Timeout should be positive value\n");
18897903da2202008733f50e69997029d7a5cfffcb8mreed		    usage(program_name, EXIT_FAILURE);
18997903da2202008733f50e69997029d7a5cfffcb8mreed		}
19097903da2202008733f50e69997029d7a5cfffcb8mreed		redirector_p->timeout = opt_d;
19197903da2202008733f50e69997029d7a5cfffcb8mreed		break;
19297903da2202008733f50e69997029d7a5cfffcb8mreed
19397903da2202008733f50e69997029d7a5cfffcb8mreed	    case 'b':
19497903da2202008733f50e69997029d7a5cfffcb8mreed		*bg_p = 1;
19597903da2202008733f50e69997029d7a5cfffcb8mreed		break;
19697903da2202008733f50e69997029d7a5cfffcb8mreed
19797903da2202008733f50e69997029d7a5cfffcb8mreed	    case 'd':
19897903da2202008733f50e69997029d7a5cfffcb8mreed		debug = 1;
19997903da2202008733f50e69997029d7a5cfffcb8mreed		break;
20097903da2202008733f50e69997029d7a5cfffcb8mreed
20197903da2202008733f50e69997029d7a5cfffcb8mreed	    case 'h':
20297903da2202008733f50e69997029d7a5cfffcb8mreed		usage(program_name, EXIT_SUCCESS);
20397903da2202008733f50e69997029d7a5cfffcb8mreed		break;
20497903da2202008733f50e69997029d7a5cfffcb8mreed
20597903da2202008733f50e69997029d7a5cfffcb8mreed	    default:
20697903da2202008733f50e69997029d7a5cfffcb8mreed		usage(program_name, EXIT_FAILURE);
20797903da2202008733f50e69997029d7a5cfffcb8mreed	}
20897903da2202008733f50e69997029d7a5cfffcb8mreed    }
20997903da2202008733f50e69997029d7a5cfffcb8mreed
21097903da2202008733f50e69997029d7a5cfffcb8mreed    if (redirector_p->ifname == NULL) {
21197903da2202008733f50e69997029d7a5cfffcb8mreed	fprintf(stderr, "Interface name is not specified\n");
21297903da2202008733f50e69997029d7a5cfffcb8mreed	usage(program_name, EXIT_FAILURE);
21397903da2202008733f50e69997029d7a5cfffcb8mreed    }
21497903da2202008733f50e69997029d7a5cfffcb8mreed}
21597903da2202008733f50e69997029d7a5cfffcb8mreed
21697903da2202008733f50e69997029d7a5cfffcb8mreed
21797903da2202008733f50e69997029d7a5cfffcb8mreed/*
21897903da2202008733f50e69997029d7a5cfffcb8mreed * Function: open_socket()
21997903da2202008733f50e69997029d7a5cfffcb8mreed *
22097903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
22197903da2202008733f50e69997029d7a5cfffcb8mreed *  This function opens a socket for capture/sending
22297903da2202008733f50e69997029d7a5cfffcb8mreed *
22397903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
22497903da2202008733f50e69997029d7a5cfffcb8mreed *  ifname: interface name
22597903da2202008733f50e69997029d7a5cfffcb8mreed *
22697903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
22797903da2202008733f50e69997029d7a5cfffcb8mreed *  socket file descriptor for receiving packets
22897903da2202008733f50e69997029d7a5cfffcb8mreed */
22997903da2202008733f50e69997029d7a5cfffcb8mreedint
23097903da2202008733f50e69997029d7a5cfffcb8mreedopen_socket(const char *ifname)
23197903da2202008733f50e69997029d7a5cfffcb8mreed{
23297903da2202008733f50e69997029d7a5cfffcb8mreed    int sd;			    /* Socket to packets */
23397903da2202008733f50e69997029d7a5cfffcb8mreed    struct ifreq ifinfo;	    /* Interface information */
23497903da2202008733f50e69997029d7a5cfffcb8mreed    struct sockaddr_ll lla;	    /* Link-local address info for receiving */
23597903da2202008733f50e69997029d7a5cfffcb8mreed
23697903da2202008733f50e69997029d7a5cfffcb8mreed    /* Create a socket for capture */
23797903da2202008733f50e69997029d7a5cfffcb8mreed    if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0)
23897903da2202008733f50e69997029d7a5cfffcb8mreed	fatal_error("socket()");
23997903da2202008733f50e69997029d7a5cfffcb8mreed
24097903da2202008733f50e69997029d7a5cfffcb8mreed    /* Make a socket into non-blocking mode */
24197903da2202008733f50e69997029d7a5cfffcb8mreed    if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0)
24297903da2202008733f50e69997029d7a5cfffcb8mreed    	fatal_error("fcntl()");
24397903da2202008733f50e69997029d7a5cfffcb8mreed
24497903da2202008733f50e69997029d7a5cfffcb8mreed    /* Get the logical interface number */
24597903da2202008733f50e69997029d7a5cfffcb8mreed    get_ifinfo(&ifinfo, sd, ifname, SIOCGIFINDEX);
24697903da2202008733f50e69997029d7a5cfffcb8mreed
24797903da2202008733f50e69997029d7a5cfffcb8mreed    /* Bind to the interface */
24897903da2202008733f50e69997029d7a5cfffcb8mreed    memset(&lla, '\0', sizeof(struct sockaddr_ll));
24997903da2202008733f50e69997029d7a5cfffcb8mreed    lla.sll_family = PF_PACKET;
25097903da2202008733f50e69997029d7a5cfffcb8mreed    lla.sll_protocol = htons(ETH_P_ALL);
25197903da2202008733f50e69997029d7a5cfffcb8mreed    lla.sll_ifindex = ifinfo.ifr_ifindex;
25297903da2202008733f50e69997029d7a5cfffcb8mreed    if (bind(sd, (struct sockaddr *)&lla, sizeof(struct sockaddr_ll)) < 0)
25397903da2202008733f50e69997029d7a5cfffcb8mreed	fatal_error("bind()");
25497903da2202008733f50e69997029d7a5cfffcb8mreed
25597903da2202008733f50e69997029d7a5cfffcb8mreed    /* Change into the promiscuous mode */
25697903da2202008733f50e69997029d7a5cfffcb8mreed    get_ifinfo(&ifinfo, sd, ifname, SIOCGIFFLAGS);
25797903da2202008733f50e69997029d7a5cfffcb8mreed    ifinfo.ifr_flags = ifinfo.ifr_flags | IFF_PROMISC;
25897903da2202008733f50e69997029d7a5cfffcb8mreed    if (ioctl(sd, SIOCSIFFLAGS, &ifinfo) < 0)
25997903da2202008733f50e69997029d7a5cfffcb8mreed	fatal_error("ioctl()");
26097903da2202008733f50e69997029d7a5cfffcb8mreed    if (debug)
26197903da2202008733f50e69997029d7a5cfffcb8mreed	fprintf(stderr, "%s is changed into promiscuous mode\n", ifname);
26297903da2202008733f50e69997029d7a5cfffcb8mreed
26397903da2202008733f50e69997029d7a5cfffcb8mreed    if (debug)
26497903da2202008733f50e69997029d7a5cfffcb8mreed	fprintf(stderr, "Packet receiving socket is %d\n", sd);
26597903da2202008733f50e69997029d7a5cfffcb8mreed    return sd;
26697903da2202008733f50e69997029d7a5cfffcb8mreed}
26797903da2202008733f50e69997029d7a5cfffcb8mreed
26897903da2202008733f50e69997029d7a5cfffcb8mreed
26997903da2202008733f50e69997029d7a5cfffcb8mreed/*
27097903da2202008733f50e69997029d7a5cfffcb8mreed * Function: return_arp_reply()
27197903da2202008733f50e69997029d7a5cfffcb8mreed *
27297903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
27397903da2202008733f50e69997029d7a5cfffcb8mreed *  This function returns arp reply message to arp request message.
27497903da2202008733f50e69997029d7a5cfffcb8mreed *  And it updates the IPv4 gateway information.
27597903da2202008733f50e69997029d7a5cfffcb8mreed *
27697903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
27797903da2202008733f50e69997029d7a5cfffcb8mreed *      sd     : socket to send arp reply message
27897903da2202008733f50e69997029d7a5cfffcb8mreed *   rcveth_p  : pointer to ether frame data
27997903da2202008733f50e69997029d7a5cfffcb8mreed *   gateway_p : pointer to IPv4 gateway information
28097903da2202008733f50e69997029d7a5cfffcb8mreed *
28197903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
28297903da2202008733f50e69997029d7a5cfffcb8mreed *  None
28397903da2202008733f50e69997029d7a5cfffcb8mreed */
28497903da2202008733f50e69997029d7a5cfffcb8mreedvoid
28597903da2202008733f50e69997029d7a5cfffcb8mreedreturn_arp_reply(int sd, struct eth_frame *rcveth_p, struct ip4_gateway_info *gateway_p)
28697903da2202008733f50e69997029d7a5cfffcb8mreed{
28797903da2202008733f50e69997029d7a5cfffcb8mreed    int retval;
28897903da2202008733f50e69997029d7a5cfffcb8mreed    struct arp_datagram *rcvarp_p;	/* ARP part of receiving frame */
28997903da2202008733f50e69997029d7a5cfffcb8mreed    unsigned char new_hd_addr[ETH_ALEN];    /* New MAC address */
29097903da2202008733f50e69997029d7a5cfffcb8mreed    unsigned char new_nexthop[4];	/* New next hop */
29197903da2202008733f50e69997029d7a5cfffcb8mreed    size_t sndeth_size;			/* Size of sending frame */
29297903da2202008733f50e69997029d7a5cfffcb8mreed    struct eth_frame sndeth;		/* sending frame */
29397903da2202008733f50e69997029d7a5cfffcb8mreed    struct arp_datagram *sndarp_p;	/* ARP part of sending frame */
29497903da2202008733f50e69997029d7a5cfffcb8mreed
29597903da2202008733f50e69997029d7a5cfffcb8mreed    rcvarp_p = (struct arp_datagram *)&(rcveth_p->data);
29697903da2202008733f50e69997029d7a5cfffcb8mreed
29797903da2202008733f50e69997029d7a5cfffcb8mreed    /* If arp message is not arp request, do nothing */
29897903da2202008733f50e69997029d7a5cfffcb8mreed    if (debug)
29997903da2202008733f50e69997029d7a5cfffcb8mreed	fprintf(stderr, "ARP OP code is %02x\n", ntohs(rcvarp_p->hdr.ar_op));
30097903da2202008733f50e69997029d7a5cfffcb8mreed    if (rcvarp_p->hdr.ar_op != htons(ARPOP_REQUEST))
30197903da2202008733f50e69997029d7a5cfffcb8mreed	return;
30297903da2202008733f50e69997029d7a5cfffcb8mreed
30397903da2202008733f50e69997029d7a5cfffcb8mreed    /* Update the gateway information */
30497903da2202008733f50e69997029d7a5cfffcb8mreed    memset(new_hd_addr, '\0', ETH_ALEN);		/* MAC address */
30597903da2202008733f50e69997029d7a5cfffcb8mreed    for (;;) {
30697903da2202008733f50e69997029d7a5cfffcb8mreed	new_hd_addr[3] = rand_within(0, 254);
30797903da2202008733f50e69997029d7a5cfffcb8mreed	new_hd_addr[4] = rand_within(0, 254);
30897903da2202008733f50e69997029d7a5cfffcb8mreed	new_hd_addr[5] = rand_within(1, 254);
30997903da2202008733f50e69997029d7a5cfffcb8mreed	if (memcmp(gateway_p->hd_addr, new_hd_addr, ETH_ALEN)) {
31097903da2202008733f50e69997029d7a5cfffcb8mreed	    memcpy(gateway_p->hd_addr, new_hd_addr, ETH_ALEN);
31197903da2202008733f50e69997029d7a5cfffcb8mreed	    break;
31297903da2202008733f50e69997029d7a5cfffcb8mreed	}
31397903da2202008733f50e69997029d7a5cfffcb8mreed    }
31497903da2202008733f50e69997029d7a5cfffcb8mreed
31597903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(gateway_p->ip_addr, rcvarp_p->ar_tip, 4);	/* IP address */
31697903da2202008733f50e69997029d7a5cfffcb8mreed
31797903da2202008733f50e69997029d7a5cfffcb8mreed    for (;;) {						/* next hop */
31897903da2202008733f50e69997029d7a5cfffcb8mreed	memcpy(new_nexthop, gateway_p->ip_addr, 4);
31997903da2202008733f50e69997029d7a5cfffcb8mreed	new_nexthop[3] = rand_within(1, 254);
32097903da2202008733f50e69997029d7a5cfffcb8mreed	if (memcmp(gateway_p->nexthop, new_nexthop, 4)) {
32197903da2202008733f50e69997029d7a5cfffcb8mreed	    memcpy(gateway_p->nexthop, new_nexthop, 4);
32297903da2202008733f50e69997029d7a5cfffcb8mreed	    break;
32397903da2202008733f50e69997029d7a5cfffcb8mreed	}
32497903da2202008733f50e69997029d7a5cfffcb8mreed    }
32597903da2202008733f50e69997029d7a5cfffcb8mreed
32697903da2202008733f50e69997029d7a5cfffcb8mreed    /* Build a frame to send */
32797903da2202008733f50e69997029d7a5cfffcb8mreed    memset(&sndeth, '\0', sizeof(struct eth_frame));
32897903da2202008733f50e69997029d7a5cfffcb8mreed    sndarp_p = (struct arp_datagram *)&(sndeth.data);
32997903da2202008733f50e69997029d7a5cfffcb8mreed    sndeth_size = sizeof(struct ethhdr) + sizeof(struct arp_datagram);
33097903da2202008733f50e69997029d7a5cfffcb8mreed
33197903da2202008733f50e69997029d7a5cfffcb8mreed    /* Ether */
33297903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndeth.hdr.h_dest, rcveth_p->hdr.h_source, ETH_ALEN);
33397903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndeth.hdr.h_source, gateway_p->hd_addr, ETH_ALEN);
33497903da2202008733f50e69997029d7a5cfffcb8mreed    sndeth.hdr.h_proto = htons(ETH_P_ARP);
33597903da2202008733f50e69997029d7a5cfffcb8mreed
33697903da2202008733f50e69997029d7a5cfffcb8mreed    /* Arp */
33797903da2202008733f50e69997029d7a5cfffcb8mreed    sndarp_p->hdr.ar_hrd = htons(ARPHRD_ETHER);
33897903da2202008733f50e69997029d7a5cfffcb8mreed    sndarp_p->hdr.ar_pro = htons(ETH_P_IP);
33997903da2202008733f50e69997029d7a5cfffcb8mreed    sndarp_p->hdr.ar_hln = ETH_ALEN;
34097903da2202008733f50e69997029d7a5cfffcb8mreed    sndarp_p->hdr.ar_pln = 4;
34197903da2202008733f50e69997029d7a5cfffcb8mreed    sndarp_p->hdr.ar_op  = htons(ARPOP_REPLY);
34297903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndarp_p->ar_sha, gateway_p->hd_addr, ETH_ALEN);
34397903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndarp_p->ar_sip, gateway_p->ip_addr, 4);
34497903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndarp_p->ar_tha, rcvarp_p->ar_sha, ETH_ALEN);
34597903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndarp_p->ar_tip, rcvarp_p->ar_sip, 4);
34697903da2202008733f50e69997029d7a5cfffcb8mreed
34797903da2202008733f50e69997029d7a5cfffcb8mreed    /* Send ARP reply */
34897903da2202008733f50e69997029d7a5cfffcb8mreed    retval = write(sd, &sndeth, sndeth_size);
34997903da2202008733f50e69997029d7a5cfffcb8mreed    if (retval != sndeth_size)
35097903da2202008733f50e69997029d7a5cfffcb8mreed	fatal_error("write()");
35197903da2202008733f50e69997029d7a5cfffcb8mreed}
35297903da2202008733f50e69997029d7a5cfffcb8mreed
35397903da2202008733f50e69997029d7a5cfffcb8mreed
35497903da2202008733f50e69997029d7a5cfffcb8mreed/*
35597903da2202008733f50e69997029d7a5cfffcb8mreed * Function: return_icmp4_redirect()
35697903da2202008733f50e69997029d7a5cfffcb8mreed *
35797903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
35897903da2202008733f50e69997029d7a5cfffcb8mreed *  This function returns icmp redirect message
35997903da2202008733f50e69997029d7a5cfffcb8mreed *
36097903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
36197903da2202008733f50e69997029d7a5cfffcb8mreed *      sd     : socket to send arp reply message
36297903da2202008733f50e69997029d7a5cfffcb8mreed *   rcveth_p  : pointer to ether frame data
36397903da2202008733f50e69997029d7a5cfffcb8mreed *  rcveth_size: size of received ehter frame
36497903da2202008733f50e69997029d7a5cfffcb8mreed *    new_gw_p : pointer to new IPv4 gateway information
36597903da2202008733f50e69997029d7a5cfffcb8mreed *
36697903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
36797903da2202008733f50e69997029d7a5cfffcb8mreed *  None
36897903da2202008733f50e69997029d7a5cfffcb8mreed */
36997903da2202008733f50e69997029d7a5cfffcb8mreedvoid
37097903da2202008733f50e69997029d7a5cfffcb8mreedreturn_icmp4_redirect(int sd, struct eth_frame *rcveth_p, size_t rcveth_size, struct ip4_gateway_info *new_gw_p)
37197903da2202008733f50e69997029d7a5cfffcb8mreed{
37297903da2202008733f50e69997029d7a5cfffcb8mreed    static struct ip4_gateway_info *gw_p;	/* pointor to gateway */
37397903da2202008733f50e69997029d7a5cfffcb8mreed
37497903da2202008733f50e69997029d7a5cfffcb8mreed    int retval;
37597903da2202008733f50e69997029d7a5cfffcb8mreed    struct ip4_datagram *rcvip_p;	/* IPv4 part of receiving frame */
37697903da2202008733f50e69997029d7a5cfffcb8mreed    size_t sndeth_size;			/* Size of sending frame */
37797903da2202008733f50e69997029d7a5cfffcb8mreed    struct eth_frame sndeth;		/* sending frame */
37897903da2202008733f50e69997029d7a5cfffcb8mreed    struct ip4_datagram *sndip_p;	/* IPv4 part of sending frame */
37997903da2202008733f50e69997029d7a5cfffcb8mreed    struct icmp4_segment *sndicmp_p;	/* ICMPv4 part of sending frame */
38097903da2202008733f50e69997029d7a5cfffcb8mreed    size_t icmp4_datasize;		/* Size of sending ICMPv4 */
38197903da2202008733f50e69997029d7a5cfffcb8mreed
38297903da2202008733f50e69997029d7a5cfffcb8mreed    /* If MAC address in received frame is changed, update the gateway info */
38397903da2202008733f50e69997029d7a5cfffcb8mreed    if (memcmp(rcveth_p->hdr.h_dest, new_gw_p->hd_addr, ETH_ALEN) == 0) {
38497903da2202008733f50e69997029d7a5cfffcb8mreed	if (gw_p == NULL)
38597903da2202008733f50e69997029d7a5cfffcb8mreed	    if ((gw_p = malloc(sizeof(struct ip4_gateway_info))) == NULL)
38697903da2202008733f50e69997029d7a5cfffcb8mreed		fatal_error("malloc()");
38797903da2202008733f50e69997029d7a5cfffcb8mreed	*gw_p = *new_gw_p;
38897903da2202008733f50e69997029d7a5cfffcb8mreed    } else if (gw_p == NULL
38997903da2202008733f50e69997029d7a5cfffcb8mreed		|| memcmp(rcveth_p->hdr.h_dest, gw_p->hd_addr, ETH_ALEN))
39097903da2202008733f50e69997029d7a5cfffcb8mreed	return;
39197903da2202008733f50e69997029d7a5cfffcb8mreed
39297903da2202008733f50e69997029d7a5cfffcb8mreed    rcvip_p = (struct ip4_datagram *)&(rcveth_p->data);
39397903da2202008733f50e69997029d7a5cfffcb8mreed
39497903da2202008733f50e69997029d7a5cfffcb8mreed    /* Build a frame to send */
39597903da2202008733f50e69997029d7a5cfffcb8mreed    sndeth_size = sizeof(struct ethhdr)			    /* Ether header */
39697903da2202008733f50e69997029d7a5cfffcb8mreed		    + sizeof(struct iphdr)		    /* IPv4 header */
39797903da2202008733f50e69997029d7a5cfffcb8mreed		    + sizeof(struct icmphdr)		    /* ICMPv4 header */
39897903da2202008733f50e69997029d7a5cfffcb8mreed		    + rcveth_size - sizeof(struct ethhdr);  /* ICMPv4 payload */
39997903da2202008733f50e69997029d7a5cfffcb8mreed    sndeth_size = (sndeth_size < ETH_DATA_MAXSIZE)
40097903da2202008733f50e69997029d7a5cfffcb8mreed			? sndeth_size : ETH_DATA_MAXSIZE;
40197903da2202008733f50e69997029d7a5cfffcb8mreed    memset(&sndeth,  '\0', sizeof(struct eth_frame));
40297903da2202008733f50e69997029d7a5cfffcb8mreed    sndip_p   = (struct ip4_datagram *)&(sndeth.data);
40397903da2202008733f50e69997029d7a5cfffcb8mreed    sndicmp_p = (struct icmp4_segment *)&(sndip_p->payload);
40497903da2202008733f50e69997029d7a5cfffcb8mreed
40597903da2202008733f50e69997029d7a5cfffcb8mreed    /* Ether */
40697903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndeth.hdr.h_dest, rcveth_p->hdr.h_source, ETH_ALEN);
40797903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndeth.hdr.h_source, gw_p->hd_addr, ETH_ALEN);
40897903da2202008733f50e69997029d7a5cfffcb8mreed    sndeth.hdr.h_proto = htons(ETH_P_IP);
40997903da2202008733f50e69997029d7a5cfffcb8mreed
41097903da2202008733f50e69997029d7a5cfffcb8mreed    /* IP */
41197903da2202008733f50e69997029d7a5cfffcb8mreed    sndip_p->hdr.version    = 4;
41297903da2202008733f50e69997029d7a5cfffcb8mreed    sndip_p->hdr.ihl	    = sizeof(struct iphdr) / 4;
41397903da2202008733f50e69997029d7a5cfffcb8mreed    sndip_p->hdr.tos	    = 0;
41497903da2202008733f50e69997029d7a5cfffcb8mreed    sndip_p->hdr.tot_len    = htons(sndeth_size - sizeof(struct ethhdr));
41597903da2202008733f50e69997029d7a5cfffcb8mreed    sndip_p->hdr.id	    = htons(IPV4_PACKET_ID);
41697903da2202008733f50e69997029d7a5cfffcb8mreed    sndip_p->hdr.frag_off   = htons(IPV4_DEFAULT_FLAG);
41797903da2202008733f50e69997029d7a5cfffcb8mreed    sndip_p->hdr.ttl	    = IPV4_DEFAULT_TTL;
41897903da2202008733f50e69997029d7a5cfffcb8mreed    sndip_p->hdr.protocol   = IPPROTO_ICMP;
41997903da2202008733f50e69997029d7a5cfffcb8mreed    sndip_p->hdr.check	    = 0;	/* Calculate later */
42097903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy((unsigned char *)&sndip_p->hdr.saddr, gw_p->ip_addr, 4);
42197903da2202008733f50e69997029d7a5cfffcb8mreed    sndip_p->hdr.daddr	    = rcvip_p->hdr.saddr;
42297903da2202008733f50e69997029d7a5cfffcb8mreed    sndip_p->hdr.check	    = calc_checksum((u_int16_t *)&(sndip_p->hdr),
42397903da2202008733f50e69997029d7a5cfffcb8mreed	                                    sizeof(struct iphdr));
42497903da2202008733f50e69997029d7a5cfffcb8mreed
42597903da2202008733f50e69997029d7a5cfffcb8mreed    /* ICMP */
42697903da2202008733f50e69997029d7a5cfffcb8mreed    sndicmp_p->hdr.type	    = ICMP_REDIRECT;
42797903da2202008733f50e69997029d7a5cfffcb8mreed    sndicmp_p->hdr.code	    = ICMP_REDIR_HOST;
42897903da2202008733f50e69997029d7a5cfffcb8mreed    sndicmp_p->hdr.checksum = 0;	/* Calculate later */
42997903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy((unsigned char *)&(sndicmp_p->hdr.un.gateway), gw_p->nexthop, 4);
43097903da2202008733f50e69997029d7a5cfffcb8mreed
43197903da2202008733f50e69997029d7a5cfffcb8mreed    /* ICMP payload */
43297903da2202008733f50e69997029d7a5cfffcb8mreed    icmp4_datasize = rcveth_size - sizeof(struct ethhdr);
43397903da2202008733f50e69997029d7a5cfffcb8mreed    icmp4_datasize = (icmp4_datasize < ICMPV4_DATA_MAXSIZE) ? icmp4_datasize : ICMPV4_DATA_MAXSIZE;
43497903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndicmp_p->data, rcvip_p, icmp4_datasize);
43597903da2202008733f50e69997029d7a5cfffcb8mreed
43697903da2202008733f50e69997029d7a5cfffcb8mreed    /* Calculate ICMP checksum */
43797903da2202008733f50e69997029d7a5cfffcb8mreed    sndicmp_p->hdr.checksum = calc_checksum((u_int16_t *)sndicmp_p,
43897903da2202008733f50e69997029d7a5cfffcb8mreed				sizeof(struct icmphdr) + icmp4_datasize);
43997903da2202008733f50e69997029d7a5cfffcb8mreed
44097903da2202008733f50e69997029d7a5cfffcb8mreed    /* Send ICMP redirect */
44197903da2202008733f50e69997029d7a5cfffcb8mreed    retval = write(sd, &sndeth, sndeth_size);
44297903da2202008733f50e69997029d7a5cfffcb8mreed    if (retval != sndeth_size)
44397903da2202008733f50e69997029d7a5cfffcb8mreed	fatal_error("write()");
44497903da2202008733f50e69997029d7a5cfffcb8mreed}
44597903da2202008733f50e69997029d7a5cfffcb8mreed
44697903da2202008733f50e69997029d7a5cfffcb8mreed
44797903da2202008733f50e69997029d7a5cfffcb8mreed/*
44897903da2202008733f50e69997029d7a5cfffcb8mreed * Function: return_neigh_adv()
44997903da2202008733f50e69997029d7a5cfffcb8mreed *
45097903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
45197903da2202008733f50e69997029d7a5cfffcb8mreed *  This function returns neighbor advertisement message
45297903da2202008733f50e69997029d7a5cfffcb8mreed *  And this updates the gateway information.
45397903da2202008733f50e69997029d7a5cfffcb8mreed *
45497903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
45597903da2202008733f50e69997029d7a5cfffcb8mreed *      sd     : socket to send arp reply message
45697903da2202008733f50e69997029d7a5cfffcb8mreed *   rcveth_p  : pointer to ether frame data
45797903da2202008733f50e69997029d7a5cfffcb8mreed *  current_eth: current MAC address
45897903da2202008733f50e69997029d7a5cfffcb8mreed *   gateway_p : pointer to IPv6 gateway information
45997903da2202008733f50e69997029d7a5cfffcb8mreed *
46097903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
46197903da2202008733f50e69997029d7a5cfffcb8mreed *  None
46297903da2202008733f50e69997029d7a5cfffcb8mreed */
46397903da2202008733f50e69997029d7a5cfffcb8mreedvoid
46497903da2202008733f50e69997029d7a5cfffcb8mreedreturn_neigh_adv(int sd, struct eth_frame *rcveth_p, struct ip6_gateway_info *gateway_p)
46597903da2202008733f50e69997029d7a5cfffcb8mreed{
46697903da2202008733f50e69997029d7a5cfffcb8mreed    int retval;
46797903da2202008733f50e69997029d7a5cfffcb8mreed    struct ip6_datagram *rcvip6_p;	/* IPv6 part of receiving frame */
46897903da2202008733f50e69997029d7a5cfffcb8mreed    struct neighbor_sol *rcvns_p;	/* NS part of receiving frame */
46997903da2202008733f50e69997029d7a5cfffcb8mreed    unsigned char new_hd_addr[ETH_ALEN];    /* new MAC address */
47097903da2202008733f50e69997029d7a5cfffcb8mreed    struct in6_addr new_nexthop;	/* new next hop */
47197903da2202008733f50e69997029d7a5cfffcb8mreed    size_t sndeth_size;			/* size of sending frame */
47297903da2202008733f50e69997029d7a5cfffcb8mreed    struct eth_frame sndeth;		/* sending frame */
47397903da2202008733f50e69997029d7a5cfffcb8mreed    struct ip6_datagram *sndip6_p;	/* IPv6 part of sending frame */
47497903da2202008733f50e69997029d7a5cfffcb8mreed    struct pseudo_ip6_datagram p_ip6;	/* pseudo IP header */
47597903da2202008733f50e69997029d7a5cfffcb8mreed    struct neighbor_adv *sndna_p;	/* NA part of sending frame */
47697903da2202008733f50e69997029d7a5cfffcb8mreed
47797903da2202008733f50e69997029d7a5cfffcb8mreed    rcvip6_p = (struct ip6_datagram *)&(rcveth_p->data);
47897903da2202008733f50e69997029d7a5cfffcb8mreed    rcvns_p  = (struct neighbor_sol *)&(rcvip6_p->payload);
47997903da2202008733f50e69997029d7a5cfffcb8mreed
48097903da2202008733f50e69997029d7a5cfffcb8mreed    /* If NS is DAD NS, do nothing */
48197903da2202008733f50e69997029d7a5cfffcb8mreed    if (memcmp(&(rcvip6_p->hdr.ip6_src), &in6addr_any, sizeof(struct in6_addr)) == 0) {
48297903da2202008733f50e69997029d7a5cfffcb8mreed	if (debug) {
48397903da2202008733f50e69997029d7a5cfffcb8mreed	    fprintf(stderr, "Received NS is a DAD NS\n");
48497903da2202008733f50e69997029d7a5cfffcb8mreed	    return;
48597903da2202008733f50e69997029d7a5cfffcb8mreed	}
48697903da2202008733f50e69997029d7a5cfffcb8mreed    }
48797903da2202008733f50e69997029d7a5cfffcb8mreed
48897903da2202008733f50e69997029d7a5cfffcb8mreed    /* Update the gateway information */
48997903da2202008733f50e69997029d7a5cfffcb8mreed    memset(new_hd_addr, '\0', ETH_ALEN);		/* MAC address */
49097903da2202008733f50e69997029d7a5cfffcb8mreed    for (;;) {
49197903da2202008733f50e69997029d7a5cfffcb8mreed	new_hd_addr[3] = rand_within(0, 254);
49297903da2202008733f50e69997029d7a5cfffcb8mreed	new_hd_addr[4] = rand_within(0, 254);
49397903da2202008733f50e69997029d7a5cfffcb8mreed	new_hd_addr[5] = rand_within(1, 254);
49497903da2202008733f50e69997029d7a5cfffcb8mreed	if (memcmp(gateway_p->hd_addr, new_hd_addr, ETH_ALEN)) {
49597903da2202008733f50e69997029d7a5cfffcb8mreed	    memcpy(gateway_p->hd_addr, new_hd_addr, ETH_ALEN);
49697903da2202008733f50e69997029d7a5cfffcb8mreed	    break;
49797903da2202008733f50e69997029d7a5cfffcb8mreed	}
49897903da2202008733f50e69997029d7a5cfffcb8mreed    }
49997903da2202008733f50e69997029d7a5cfffcb8mreed
50097903da2202008733f50e69997029d7a5cfffcb8mreed    gateway_p->ip_addr = rcvns_p->defs.nd_ns_target;	/* IP address */
50197903da2202008733f50e69997029d7a5cfffcb8mreed
50297903da2202008733f50e69997029d7a5cfffcb8mreed    for (;;) {						/* next hop */
50397903da2202008733f50e69997029d7a5cfffcb8mreed	memset(&new_nexthop, '\0', sizeof(struct in6_addr));
50497903da2202008733f50e69997029d7a5cfffcb8mreed	new_nexthop.s6_addr[0]  = 0xfe;
50597903da2202008733f50e69997029d7a5cfffcb8mreed	new_nexthop.s6_addr[1]  = 0x80;
50697903da2202008733f50e69997029d7a5cfffcb8mreed	new_nexthop.s6_addr[15] = rand_within(1, 254);
50797903da2202008733f50e69997029d7a5cfffcb8mreed	if (memcmp(&(gateway_p->nexthop), &new_nexthop, sizeof(struct in6_addr))) {
50897903da2202008733f50e69997029d7a5cfffcb8mreed	    gateway_p->nexthop = new_nexthop;
50997903da2202008733f50e69997029d7a5cfffcb8mreed	    break;
51097903da2202008733f50e69997029d7a5cfffcb8mreed	}
51197903da2202008733f50e69997029d7a5cfffcb8mreed    }
51297903da2202008733f50e69997029d7a5cfffcb8mreed
51397903da2202008733f50e69997029d7a5cfffcb8mreed    /* Build a frame to send */
51497903da2202008733f50e69997029d7a5cfffcb8mreed    sndeth_size = sizeof(struct ethhdr) + sizeof(struct ip6_hdr)
51597903da2202008733f50e69997029d7a5cfffcb8mreed					+ sizeof(struct neighbor_adv);
51697903da2202008733f50e69997029d7a5cfffcb8mreed    memset(&sndeth,  '\0', sizeof(struct eth_frame));
51797903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p = (struct ip6_datagram *)&(sndeth.data);
51897903da2202008733f50e69997029d7a5cfffcb8mreed    sndna_p  = (struct neighbor_adv *)&(sndip6_p->payload);
51997903da2202008733f50e69997029d7a5cfffcb8mreed
52097903da2202008733f50e69997029d7a5cfffcb8mreed    /* Ether */
52197903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndeth.hdr.h_dest, rcvns_p->src_laddr, ETH_ALEN);
52297903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndeth.hdr.h_source, gateway_p->hd_addr, ETH_ALEN);
52397903da2202008733f50e69997029d7a5cfffcb8mreed    sndeth.hdr.h_proto = htons(ETH_P_IPV6);
52497903da2202008733f50e69997029d7a5cfffcb8mreed
52597903da2202008733f50e69997029d7a5cfffcb8mreed    /* IPv6 */
52697903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_vfc	= 6 << 4;
52797903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_flow	|= 0;
52897903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_plen	= htons(sizeof(struct neighbor_adv));
52997903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_nxt	= IPPROTO_ICMPV6;
53097903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_hlim	= 255;
53197903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_src	= gateway_p->ip_addr;
53297903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_dst	= rcvip6_p->hdr.ip6_src;
53397903da2202008733f50e69997029d7a5cfffcb8mreed
53497903da2202008733f50e69997029d7a5cfffcb8mreed    /* Neighbor Advertisement */
53597903da2202008733f50e69997029d7a5cfffcb8mreed    sndna_p->defs.nd_na_type	= ND_NEIGHBOR_ADVERT;
53697903da2202008733f50e69997029d7a5cfffcb8mreed    sndna_p->defs.nd_na_code	= 0;
53797903da2202008733f50e69997029d7a5cfffcb8mreed    sndna_p->defs.nd_na_cksum	= 0;		/* Calculate later */
53897903da2202008733f50e69997029d7a5cfffcb8mreed    sndna_p->defs.nd_na_target	= gateway_p->ip_addr;
53997903da2202008733f50e69997029d7a5cfffcb8mreed    sndna_p->defs.nd_na_flags_reserved
54097903da2202008733f50e69997029d7a5cfffcb8mreed	= ND_NA_FLAG_ROUTER | ND_NA_FLAG_SOLICITED | ND_NA_FLAG_OVERRIDE;
54197903da2202008733f50e69997029d7a5cfffcb8mreed    sndna_p->tla_opt.nd_opt_type    = ND_OPT_TARGET_LINKADDR;
54297903da2202008733f50e69997029d7a5cfffcb8mreed    sndna_p->tla_opt.nd_opt_len     = 1;
54397903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndna_p->tgt_laddr, &(gateway_p->hd_addr), ETH_ALEN);
54497903da2202008733f50e69997029d7a5cfffcb8mreed
54597903da2202008733f50e69997029d7a5cfffcb8mreed    /* Pseudo IPv6 datagram for checksum calculation */
54697903da2202008733f50e69997029d7a5cfffcb8mreed    memset(&p_ip6, '\0', sizeof(struct pseudo_ip6_datagram));
54797903da2202008733f50e69997029d7a5cfffcb8mreed    p_ip6.hdr.p_ip6_src	    = sndip6_p->hdr.ip6_src;
54897903da2202008733f50e69997029d7a5cfffcb8mreed    p_ip6.hdr.p_ip6_dst	    = sndip6_p->hdr.ip6_dst;
54997903da2202008733f50e69997029d7a5cfffcb8mreed    p_ip6.hdr.p_ip6_plen    = sndip6_p->hdr.ip6_plen;
55097903da2202008733f50e69997029d7a5cfffcb8mreed    p_ip6.hdr.p_ip6_zero1   = 0;
55197903da2202008733f50e69997029d7a5cfffcb8mreed    p_ip6.hdr.p_ip6_zero2   = 0;
55297903da2202008733f50e69997029d7a5cfffcb8mreed    p_ip6.hdr.p_ip6_nxt	    = sndip6_p->hdr.ip6_nxt;
55397903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(p_ip6.payload, sndna_p, sizeof(struct neighbor_adv));
55497903da2202008733f50e69997029d7a5cfffcb8mreed
55597903da2202008733f50e69997029d7a5cfffcb8mreed    /* Calculate checksum */
55697903da2202008733f50e69997029d7a5cfffcb8mreed    sndna_p->defs.nd_na_cksum	= calc_checksum((u_int16_t *)(&p_ip6),
55797903da2202008733f50e69997029d7a5cfffcb8mreed		sizeof(struct pseudo_ip6_hdr) + sizeof(struct neighbor_adv));
55897903da2202008733f50e69997029d7a5cfffcb8mreed
55997903da2202008733f50e69997029d7a5cfffcb8mreed    /* Send Neighbor Advertisement reply */
56097903da2202008733f50e69997029d7a5cfffcb8mreed    retval = write(sd, &sndeth, sndeth_size);
56197903da2202008733f50e69997029d7a5cfffcb8mreed    if (retval != sndeth_size)
56297903da2202008733f50e69997029d7a5cfffcb8mreed	fatal_error("write()");
56397903da2202008733f50e69997029d7a5cfffcb8mreed}
56497903da2202008733f50e69997029d7a5cfffcb8mreed
56597903da2202008733f50e69997029d7a5cfffcb8mreed
56697903da2202008733f50e69997029d7a5cfffcb8mreed/*
56797903da2202008733f50e69997029d7a5cfffcb8mreed * Function: return_icmp6_redirect()
56897903da2202008733f50e69997029d7a5cfffcb8mreed *
56997903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
57097903da2202008733f50e69997029d7a5cfffcb8mreed *  This function returns an ICMPv6 redirect message
57197903da2202008733f50e69997029d7a5cfffcb8mreed *
57297903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
57397903da2202008733f50e69997029d7a5cfffcb8mreed *      sd     : socket to send arp reply message
57497903da2202008733f50e69997029d7a5cfffcb8mreed *   rcveth_p  : pointer to ether frame data
57597903da2202008733f50e69997029d7a5cfffcb8mreed *  rcveth_size: size of received ehter frame
57697903da2202008733f50e69997029d7a5cfffcb8mreed *   new_gw_p  : pointer to new IPv4 gateway information
57797903da2202008733f50e69997029d7a5cfffcb8mreed *
57897903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
57997903da2202008733f50e69997029d7a5cfffcb8mreed *  None
58097903da2202008733f50e69997029d7a5cfffcb8mreed */
58197903da2202008733f50e69997029d7a5cfffcb8mreedvoid
58297903da2202008733f50e69997029d7a5cfffcb8mreedreturn_icmp6_redirect(int sd, struct eth_frame *rcveth_p, size_t rcveth_size, struct ip6_gateway_info *new_gw_p)
58397903da2202008733f50e69997029d7a5cfffcb8mreed{
58497903da2202008733f50e69997029d7a5cfffcb8mreed    static struct ip6_gateway_info *gw_p = NULL;	/* pointor to gateway */
58597903da2202008733f50e69997029d7a5cfffcb8mreed
58697903da2202008733f50e69997029d7a5cfffcb8mreed    int retval;
58797903da2202008733f50e69997029d7a5cfffcb8mreed    struct ip6_datagram *rcvip6_p;	/* IPv6 part of receiving frame */
58897903da2202008733f50e69997029d7a5cfffcb8mreed    struct eth_frame sndeth;		/* sending frame */
58997903da2202008733f50e69997029d7a5cfffcb8mreed    size_t sndeth_size;			/* size of sending frame */
59097903da2202008733f50e69997029d7a5cfffcb8mreed    struct ip6_datagram *sndip6_p;	/* IPv6 part of sending frame */
59197903da2202008733f50e69997029d7a5cfffcb8mreed    size_t ip6_payload_size;		/* payload size of IPv6 part */
59297903da2202008733f50e69997029d7a5cfffcb8mreed    struct pseudo_ip6_datagram p_ip6;	/* pseudo header for checksum */
59397903da2202008733f50e69997029d7a5cfffcb8mreed    struct neighbor_redirect *sndrd_p;	/* ICMPv6 part of sending frame */
59497903da2202008733f50e69997029d7a5cfffcb8mreed    size_t redirect_optsize;		/* Option size of ICMPv6 */
59597903da2202008733f50e69997029d7a5cfffcb8mreed
59697903da2202008733f50e69997029d7a5cfffcb8mreed    rcvip6_p = (struct ip6_datagram *)&(rcveth_p->data);
59797903da2202008733f50e69997029d7a5cfffcb8mreed
59897903da2202008733f50e69997029d7a5cfffcb8mreed     /* If MAC address in received frame is changed, update the gateway info */
59997903da2202008733f50e69997029d7a5cfffcb8mreed    if (memcmp(rcveth_p->hdr.h_dest, new_gw_p->hd_addr, ETH_ALEN) == 0) {
60097903da2202008733f50e69997029d7a5cfffcb8mreed	if (gw_p == NULL)
60197903da2202008733f50e69997029d7a5cfffcb8mreed	    if ((gw_p = malloc(sizeof(struct in6_addr))) == NULL)
60297903da2202008733f50e69997029d7a5cfffcb8mreed		fatal_error("malloc()");
60397903da2202008733f50e69997029d7a5cfffcb8mreed	*gw_p = *new_gw_p;
60497903da2202008733f50e69997029d7a5cfffcb8mreed    } else if (gw_p == NULL
60597903da2202008733f50e69997029d7a5cfffcb8mreed	    || memcmp(rcveth_p->hdr.h_dest, gw_p->hd_addr, ETH_ALEN))
60697903da2202008733f50e69997029d7a5cfffcb8mreed	return;
60797903da2202008733f50e69997029d7a5cfffcb8mreed
60897903da2202008733f50e69997029d7a5cfffcb8mreed
60997903da2202008733f50e69997029d7a5cfffcb8mreed    /* Build a frame to send */
61097903da2202008733f50e69997029d7a5cfffcb8mreed    memset(&sndeth,  '\0', sizeof(struct eth_frame));
61197903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p = (struct ip6_datagram *)&(sndeth.data);
61297903da2202008733f50e69997029d7a5cfffcb8mreed    sndrd_p  = (struct neighbor_redirect *)&(sndip6_p->payload);
61397903da2202008733f50e69997029d7a5cfffcb8mreed    redirect_optsize = sizeof(struct nd_opt_rd_hdr)
61497903da2202008733f50e69997029d7a5cfffcb8mreed			+ rcveth_size - sizeof(struct ethhdr);
61597903da2202008733f50e69997029d7a5cfffcb8mreed    redirect_optsize = (redirect_optsize < RDOPT_MAXSIZE)
61697903da2202008733f50e69997029d7a5cfffcb8mreed				? redirect_optsize : RDOPT_MAXSIZE;
61797903da2202008733f50e69997029d7a5cfffcb8mreed    ip6_payload_size = sizeof(struct nd_redirect) + redirect_optsize;
61897903da2202008733f50e69997029d7a5cfffcb8mreed    sndeth_size = sizeof(struct ethhdr) + sizeof(struct ip6_hdr)
61997903da2202008733f50e69997029d7a5cfffcb8mreed			+ ip6_payload_size;
62097903da2202008733f50e69997029d7a5cfffcb8mreed
62197903da2202008733f50e69997029d7a5cfffcb8mreed    /* Ether */
62297903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndeth.hdr.h_dest, rcveth_p->hdr.h_source, ETH_ALEN);
62397903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndeth.hdr.h_source, gw_p->hd_addr, ETH_ALEN);
62497903da2202008733f50e69997029d7a5cfffcb8mreed    sndeth.hdr.h_proto = htons(ETH_P_IPV6);
62597903da2202008733f50e69997029d7a5cfffcb8mreed
62697903da2202008733f50e69997029d7a5cfffcb8mreed    /* IPv6 */
62797903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_vfc	= 6 << 4;
62897903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_flow	|= 0;
62997903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_plen	= htons(ip6_payload_size);
63097903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_nxt	= IPPROTO_ICMPV6;
63197903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_hlim	= 255;
63297903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_src	= gw_p->ip_addr;
63397903da2202008733f50e69997029d7a5cfffcb8mreed    sndip6_p->hdr.ip6_dst	= rcvip6_p->hdr.ip6_src;
63497903da2202008733f50e69997029d7a5cfffcb8mreed
63597903da2202008733f50e69997029d7a5cfffcb8mreed    /* Rediret Message */
63697903da2202008733f50e69997029d7a5cfffcb8mreed    sndrd_p->defs.nd_rd_type		= ND_REDIRECT;
63797903da2202008733f50e69997029d7a5cfffcb8mreed    sndrd_p->defs.nd_rd_code		= 0;
63897903da2202008733f50e69997029d7a5cfffcb8mreed    sndrd_p->defs.nd_rd_cksum		= 0;	/* Calculate later */
63997903da2202008733f50e69997029d7a5cfffcb8mreed    sndrd_p->defs.nd_rd_reserved	= 0;
64097903da2202008733f50e69997029d7a5cfffcb8mreed    sndrd_p->defs.nd_rd_target		= gw_p->nexthop;
64197903da2202008733f50e69997029d7a5cfffcb8mreed    sndrd_p->defs.nd_rd_dst		= rcvip6_p->hdr.ip6_dst;;
64297903da2202008733f50e69997029d7a5cfffcb8mreed    sndrd_p->rdopt_hdr.nd_opt_rh_type	= ND_OPT_REDIRECTED_HEADER;
64397903da2202008733f50e69997029d7a5cfffcb8mreed    sndrd_p->rdopt_hdr.nd_opt_rh_len	= redirect_optsize / 8;
64497903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(sndrd_p->rdopt_data, rcvip6_p, redirect_optsize);
64597903da2202008733f50e69997029d7a5cfffcb8mreed
64697903da2202008733f50e69997029d7a5cfffcb8mreed    /* Pseudo IPv6 datagram for checksum calculation */
64797903da2202008733f50e69997029d7a5cfffcb8mreed    memset(&p_ip6, '\0', sizeof(struct pseudo_ip6_datagram));
64897903da2202008733f50e69997029d7a5cfffcb8mreed    p_ip6.hdr.p_ip6_src	    = sndip6_p->hdr.ip6_src;
64997903da2202008733f50e69997029d7a5cfffcb8mreed    p_ip6.hdr.p_ip6_dst	    = sndip6_p->hdr.ip6_dst;
65097903da2202008733f50e69997029d7a5cfffcb8mreed    p_ip6.hdr.p_ip6_plen    = sndip6_p->hdr.ip6_plen;
65197903da2202008733f50e69997029d7a5cfffcb8mreed    p_ip6.hdr.p_ip6_zero1   = 0;
65297903da2202008733f50e69997029d7a5cfffcb8mreed    p_ip6.hdr.p_ip6_zero2   = 0;
65397903da2202008733f50e69997029d7a5cfffcb8mreed    p_ip6.hdr.p_ip6_nxt	    = sndip6_p->hdr.ip6_nxt;
65497903da2202008733f50e69997029d7a5cfffcb8mreed    memcpy(p_ip6.payload, sndrd_p, ip6_payload_size);
65597903da2202008733f50e69997029d7a5cfffcb8mreed
65697903da2202008733f50e69997029d7a5cfffcb8mreed    /* Calculate checksum */
65797903da2202008733f50e69997029d7a5cfffcb8mreed    sndrd_p->defs.nd_rd_cksum	= calc_checksum((u_int16_t *)(&p_ip6),
65897903da2202008733f50e69997029d7a5cfffcb8mreed		sizeof(struct pseudo_ip6_hdr) + ip6_payload_size);
65997903da2202008733f50e69997029d7a5cfffcb8mreed
66097903da2202008733f50e69997029d7a5cfffcb8mreed    /* Send ICMPv6 redirct message */
66197903da2202008733f50e69997029d7a5cfffcb8mreed    retval = write(sd, &sndeth, sndeth_size);
66297903da2202008733f50e69997029d7a5cfffcb8mreed    if (retval != sndeth_size)
66397903da2202008733f50e69997029d7a5cfffcb8mreed	fatal_error("write()");
66497903da2202008733f50e69997029d7a5cfffcb8mreed}
66597903da2202008733f50e69997029d7a5cfffcb8mreed
66697903da2202008733f50e69997029d7a5cfffcb8mreed
66797903da2202008733f50e69997029d7a5cfffcb8mreed/*
66897903da2202008733f50e69997029d7a5cfffcb8mreed * Function: analyze_ip6_datagram()
66997903da2202008733f50e69997029d7a5cfffcb8mreed *
67097903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
67197903da2202008733f50e69997029d7a5cfffcb8mreed *  This function analyze captured IPv6 datagram
67297903da2202008733f50e69997029d7a5cfffcb8mreed *
67397903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
67497903da2202008733f50e69997029d7a5cfffcb8mreed *       sd      : socket to send arp reply message
67597903da2202008733f50e69997029d7a5cfffcb8mreed *    rcveth_p   : pointer to ether frame data
67697903da2202008733f50e69997029d7a5cfffcb8mreed *   rcveth_size : size of received ehter frame
67797903da2202008733f50e69997029d7a5cfffcb8mreed *    gateway_p  : pointer to IPv6 gateway information
67897903da2202008733f50e69997029d7a5cfffcb8mreed *
67997903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
68097903da2202008733f50e69997029d7a5cfffcb8mreed *  None
68197903da2202008733f50e69997029d7a5cfffcb8mreed */
68297903da2202008733f50e69997029d7a5cfffcb8mreedvoid
68397903da2202008733f50e69997029d7a5cfffcb8mreedanalyze_ip6_datagram(int sd, struct eth_frame *rcveth_p, size_t rcveth_size, struct ip6_gateway_info *gateway_p)
68497903da2202008733f50e69997029d7a5cfffcb8mreed{
68597903da2202008733f50e69997029d7a5cfffcb8mreed    struct ip6_datagram *rcvip6_p;	/* IPv6 Part of receiving frame */
68697903da2202008733f50e69997029d7a5cfffcb8mreed    struct icmp6_segment *rcvicmp6_p;	/* ICMPv6 Part of receiving frame */
68797903da2202008733f50e69997029d7a5cfffcb8mreed    uint8_t nxt_hdr;			/* Next header of IPv6 */
68897903da2202008733f50e69997029d7a5cfffcb8mreed    uint8_t icmp6_type;			/* Type of ICMPv6 */
68997903da2202008733f50e69997029d7a5cfffcb8mreed
69097903da2202008733f50e69997029d7a5cfffcb8mreed    rcvip6_p  = (struct ip6_datagram *)&(rcveth_p->data);
69197903da2202008733f50e69997029d7a5cfffcb8mreed    rcvicmp6_p = (struct icmp6_segment *)&(rcvip6_p->payload);
69297903da2202008733f50e69997029d7a5cfffcb8mreed
69397903da2202008733f50e69997029d7a5cfffcb8mreed    nxt_hdr = rcvip6_p->hdr.ip6_nxt;
69497903da2202008733f50e69997029d7a5cfffcb8mreed    switch (nxt_hdr) {
69597903da2202008733f50e69997029d7a5cfffcb8mreed	case IPPROTO_ICMPV6:
69697903da2202008733f50e69997029d7a5cfffcb8mreed	    icmp6_type = rcvicmp6_p->hdr.icmp6_type;
69797903da2202008733f50e69997029d7a5cfffcb8mreed	    switch (icmp6_type) {
69897903da2202008733f50e69997029d7a5cfffcb8mreed		case ND_NEIGHBOR_SOLICIT:
69997903da2202008733f50e69997029d7a5cfffcb8mreed		    if (debug)
70097903da2202008733f50e69997029d7a5cfffcb8mreed			fprintf(stderr, "Received ICMP NS\n");
70197903da2202008733f50e69997029d7a5cfffcb8mreed		    return_neigh_adv(sd, rcveth_p, gateway_p);
70297903da2202008733f50e69997029d7a5cfffcb8mreed		    break;
70397903da2202008733f50e69997029d7a5cfffcb8mreed
70497903da2202008733f50e69997029d7a5cfffcb8mreed		case ICMP6_ECHO_REQUEST:
70597903da2202008733f50e69997029d7a5cfffcb8mreed		    if (debug)
70697903da2202008733f50e69997029d7a5cfffcb8mreed			fprintf(stderr, "Received ICMP Echo Request\n");
70797903da2202008733f50e69997029d7a5cfffcb8mreed		    return_icmp6_redirect(sd, rcveth_p, rcveth_size, gateway_p);
70897903da2202008733f50e69997029d7a5cfffcb8mreed		    break;
70997903da2202008733f50e69997029d7a5cfffcb8mreed	    }
71097903da2202008733f50e69997029d7a5cfffcb8mreed	    break;
71197903da2202008733f50e69997029d7a5cfffcb8mreed
71297903da2202008733f50e69997029d7a5cfffcb8mreed	case IPPROTO_UDP:
71397903da2202008733f50e69997029d7a5cfffcb8mreed	    if (debug)
71497903da2202008733f50e69997029d7a5cfffcb8mreed		fprintf(stderr, "Received UDP message\n");
71597903da2202008733f50e69997029d7a5cfffcb8mreed	    return_icmp6_redirect(sd, rcveth_p, rcveth_size, gateway_p);
71697903da2202008733f50e69997029d7a5cfffcb8mreed	    break;
71797903da2202008733f50e69997029d7a5cfffcb8mreed    }
71897903da2202008733f50e69997029d7a5cfffcb8mreed}
71997903da2202008733f50e69997029d7a5cfffcb8mreed
72097903da2202008733f50e69997029d7a5cfffcb8mreed
72197903da2202008733f50e69997029d7a5cfffcb8mreed/*
72297903da2202008733f50e69997029d7a5cfffcb8mreed * Function: capture_frames()
72397903da2202008733f50e69997029d7a5cfffcb8mreed *
72497903da2202008733f50e69997029d7a5cfffcb8mreed * Description:
72597903da2202008733f50e69997029d7a5cfffcb8mreed *  This function captures frames
72697903da2202008733f50e69997029d7a5cfffcb8mreed *
72797903da2202008733f50e69997029d7a5cfffcb8mreed * Argument:
72897903da2202008733f50e69997029d7a5cfffcb8mreed *  redirector_p: pointer to data for the redirector information
72997903da2202008733f50e69997029d7a5cfffcb8mreed *
73097903da2202008733f50e69997029d7a5cfffcb8mreed * Return value:
73197903da2202008733f50e69997029d7a5cfffcb8mreed *  socket file descriptor for receiving packets
73297903da2202008733f50e69997029d7a5cfffcb8mreed */
73397903da2202008733f50e69997029d7a5cfffcb8mreedvoid
73497903da2202008733f50e69997029d7a5cfffcb8mreedcapture_frames(struct redirector_info *redirector_p)
73597903da2202008733f50e69997029d7a5cfffcb8mreed{
73697903da2202008733f50e69997029d7a5cfffcb8mreed    struct ip4_gateway_info ip4_gateway;	/* IPv4 gateway information */
73797903da2202008733f50e69997029d7a5cfffcb8mreed    struct ip6_gateway_info ip6_gateway;	/* IPv6 gateway information */
73897903da2202008733f50e69997029d7a5cfffcb8mreed    struct eth_frame frame;			/* captured frame data */
73997903da2202008733f50e69997029d7a5cfffcb8mreed    ssize_t frame_size;				/* captured frame size */
74097903da2202008733f50e69997029d7a5cfffcb8mreed    double start_time;				/* capture starting time */
74197903da2202008733f50e69997029d7a5cfffcb8mreed    int sd = redirector_p->sd;			/* socket fd for capture */
74297903da2202008733f50e69997029d7a5cfffcb8mreed
74397903da2202008733f50e69997029d7a5cfffcb8mreed    /* Initialize gateway information */
74497903da2202008733f50e69997029d7a5cfffcb8mreed    memset(&ip4_gateway, '\0', sizeof(struct ip4_gateway_info));
74597903da2202008733f50e69997029d7a5cfffcb8mreed    memset(&ip6_gateway, '\0', sizeof(struct ip6_gateway_info));
74697903da2202008733f50e69997029d7a5cfffcb8mreed
74797903da2202008733f50e69997029d7a5cfffcb8mreed    /* Set singal hander for SIGHUP */
74897903da2202008733f50e69997029d7a5cfffcb8mreed    handler.sa_handler = set_signal_flag;
74997903da2202008733f50e69997029d7a5cfffcb8mreed    handler.sa_flags = 0;
75097903da2202008733f50e69997029d7a5cfffcb8mreed    if (sigfillset(&handler.sa_mask) < 0)
75197903da2202008733f50e69997029d7a5cfffcb8mreed	fatal_error("sigfillset()");
75297903da2202008733f50e69997029d7a5cfffcb8mreed    if (sigaction(SIGHUP, &handler, NULL) < 0)
75397903da2202008733f50e69997029d7a5cfffcb8mreed	fatal_error("sigfillset()");
75497903da2202008733f50e69997029d7a5cfffcb8mreed
75597903da2202008733f50e69997029d7a5cfffcb8mreed    /*
75697903da2202008733f50e69997029d7a5cfffcb8mreed     * loop for capture
75797903da2202008733f50e69997029d7a5cfffcb8mreed     */
75897903da2202008733f50e69997029d7a5cfffcb8mreed    start_time = time(NULL);
75997903da2202008733f50e69997029d7a5cfffcb8mreed
760df3eb16e38c6a163b0a7367c885679eed6140964Garrett Cooper    for (;;) {
76197903da2202008733f50e69997029d7a5cfffcb8mreed	frame_size = read(sd, (void *)(&frame), sizeof (frame));
76297903da2202008733f50e69997029d7a5cfffcb8mreed	if (frame_size < 0) {
76397903da2202008733f50e69997029d7a5cfffcb8mreed	    if (errno != EAGAIN)
76497903da2202008733f50e69997029d7a5cfffcb8mreed		fatal_error("read()");
76597903da2202008733f50e69997029d7a5cfffcb8mreed	} else {
76697903da2202008733f50e69997029d7a5cfffcb8mreed	    switch (ntohs(frame.hdr.h_proto)) {
76797903da2202008733f50e69997029d7a5cfffcb8mreed		case ETH_P_ARP:
76897903da2202008733f50e69997029d7a5cfffcb8mreed		    if (debug)
76997903da2202008733f50e69997029d7a5cfffcb8mreed			fprintf(stderr, "Get ARP packet\n");
77097903da2202008733f50e69997029d7a5cfffcb8mreed		    return_arp_reply(sd, &frame, &ip4_gateway);
77197903da2202008733f50e69997029d7a5cfffcb8mreed		    break;
77297903da2202008733f50e69997029d7a5cfffcb8mreed
77397903da2202008733f50e69997029d7a5cfffcb8mreed		case ETH_P_IP:
77497903da2202008733f50e69997029d7a5cfffcb8mreed		    if (debug)
77597903da2202008733f50e69997029d7a5cfffcb8mreed			fprintf(stderr, "Get IPv4 packet\n");
77697903da2202008733f50e69997029d7a5cfffcb8mreed		    return_icmp4_redirect(sd, &frame, frame_size, &ip4_gateway);
77797903da2202008733f50e69997029d7a5cfffcb8mreed		    break;
77897903da2202008733f50e69997029d7a5cfffcb8mreed
77997903da2202008733f50e69997029d7a5cfffcb8mreed		case ETH_P_IPV6:
78097903da2202008733f50e69997029d7a5cfffcb8mreed		    if (debug)
78197903da2202008733f50e69997029d7a5cfffcb8mreed			fprintf(stderr, "Get IPv6 packet\n");
78297903da2202008733f50e69997029d7a5cfffcb8mreed		    analyze_ip6_datagram(sd, &frame, frame_size, &ip6_gateway);
78397903da2202008733f50e69997029d7a5cfffcb8mreed		    break;
78497903da2202008733f50e69997029d7a5cfffcb8mreed	    }
78597903da2202008733f50e69997029d7a5cfffcb8mreed	}
78697903da2202008733f50e69997029d7a5cfffcb8mreed
78797903da2202008733f50e69997029d7a5cfffcb8mreed	if (redirector_p->timeout)
78897903da2202008733f50e69997029d7a5cfffcb8mreed	    if (redirector_p->timeout < difftime(time(NULL), start_time))
78997903da2202008733f50e69997029d7a5cfffcb8mreed		break;
79097903da2202008733f50e69997029d7a5cfffcb8mreed
79197903da2202008733f50e69997029d7a5cfffcb8mreed	if (catch_sighup) /* catch SIGHUP */
79297903da2202008733f50e69997029d7a5cfffcb8mreed	    break;
79397903da2202008733f50e69997029d7a5cfffcb8mreed    }
79497903da2202008733f50e69997029d7a5cfffcb8mreed}
79597903da2202008733f50e69997029d7a5cfffcb8mreed
79697903da2202008733f50e69997029d7a5cfffcb8mreed
79797903da2202008733f50e69997029d7a5cfffcb8mreed/*
79897903da2202008733f50e69997029d7a5cfffcb8mreed *
79997903da2202008733f50e69997029d7a5cfffcb8mreed *  Function: main()
80097903da2202008733f50e69997029d7a5cfffcb8mreed *
80197903da2202008733f50e69997029d7a5cfffcb8mreed */
80297903da2202008733f50e69997029d7a5cfffcb8mreedint
80397903da2202008733f50e69997029d7a5cfffcb8mreedmain(int argc, char *argv[])
80497903da2202008733f50e69997029d7a5cfffcb8mreed{
80597903da2202008733f50e69997029d7a5cfffcb8mreed    struct redirector_info redirector;
80697903da2202008733f50e69997029d7a5cfffcb8mreed    int background = 0;
80797903da2202008733f50e69997029d7a5cfffcb8mreed
80897903da2202008733f50e69997029d7a5cfffcb8mreed    debug = 0;
80997903da2202008733f50e69997029d7a5cfffcb8mreed    program_name = strdup(argv[0]);
81097903da2202008733f50e69997029d7a5cfffcb8mreed    srand(getpid());
81197903da2202008733f50e69997029d7a5cfffcb8mreed
81297903da2202008733f50e69997029d7a5cfffcb8mreed    memset(&redirector, '\0', sizeof(struct redirector_info));
81397903da2202008733f50e69997029d7a5cfffcb8mreed    parse_options(argc, argv, &redirector, &background);
81497903da2202008733f50e69997029d7a5cfffcb8mreed
81597903da2202008733f50e69997029d7a5cfffcb8mreed    redirector.sd = open_socket(redirector.ifname);
81697903da2202008733f50e69997029d7a5cfffcb8mreed
81797903da2202008733f50e69997029d7a5cfffcb8mreed    if (background)     /* Work in the background */
81897903da2202008733f50e69997029d7a5cfffcb8mreed	if (daemon(0, 0) < 0)
81997903da2202008733f50e69997029d7a5cfffcb8mreed	    fatal_error("daemon()");
82097903da2202008733f50e69997029d7a5cfffcb8mreed
82197903da2202008733f50e69997029d7a5cfffcb8mreed    capture_frames(&redirector);
82297903da2202008733f50e69997029d7a5cfffcb8mreed
82397903da2202008733f50e69997029d7a5cfffcb8mreed    close(redirector.sd);
82497903da2202008733f50e69997029d7a5cfffcb8mreed    exit(EXIT_SUCCESS);
82597903da2202008733f50e69997029d7a5cfffcb8mreed}
826