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