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 { 63354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao int sd; 64354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao char *ifname; 65354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao double timeout; 6697903da2202008733f50e69997029d7a5cfffcb8mreed}; 6797903da2202008733f50e69997029d7a5cfffcb8mreed 6897903da2202008733f50e69997029d7a5cfffcb8mreedstruct ip4_gateway_info { 69354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao unsigned char hd_addr[ETH_ALEN]; 70354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao unsigned char ip_addr[4]; 71354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao unsigned char nexthop[4]; 7297903da2202008733f50e69997029d7a5cfffcb8mreed}; 7397903da2202008733f50e69997029d7a5cfffcb8mreed 7497903da2202008733f50e69997029d7a5cfffcb8mreedstruct ip6_gateway_info { 75354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao unsigned char hd_addr[ETH_ALEN]; 76354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct in6_addr ip_addr; 77354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 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 */ 100354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaovoid usage(char *program_name, int exit_value) 10197903da2202008733f50e69997029d7a5cfffcb8mreed{ 102354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao FILE *stream = stdout; /* stream where the usage is output */ 103354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 104354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (exit_value == EXIT_FAILURE) 105354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao stream = stderr; 106354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 107354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stream, "%s [OPTION]\n" 108354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao "\t-I if_name\tInterface where input/output packets\n" 109354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao "\t-t value\ttimeout [sec]\n" 110354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao "\t-b\t\ttimeout [sec]\n" 111354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao "\t-d\t\tdisplay debug informations\n" 112354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao "\t-h\t\tdisplay this usage\n", program_name); 113354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao exit(exit_value); 11497903da2202008733f50e69997029d7a5cfffcb8mreed} 11597903da2202008733f50e69997029d7a5cfffcb8mreed 11697903da2202008733f50e69997029d7a5cfffcb8mreed/* 11797903da2202008733f50e69997029d7a5cfffcb8mreed * Function: set_signal_flag() 11897903da2202008733f50e69997029d7a5cfffcb8mreed * 11997903da2202008733f50e69997029d7a5cfffcb8mreed * Description: 12097903da2202008733f50e69997029d7a5cfffcb8mreed * This function sets global variables according to a signal 12197903da2202008733f50e69997029d7a5cfffcb8mreed * 12297903da2202008733f50e69997029d7a5cfffcb8mreed * Argument: 12397903da2202008733f50e69997029d7a5cfffcb8mreed * type: type of signal 12497903da2202008733f50e69997029d7a5cfffcb8mreed * 12597903da2202008733f50e69997029d7a5cfffcb8mreed * Return value: 12697903da2202008733f50e69997029d7a5cfffcb8mreed * None 12797903da2202008733f50e69997029d7a5cfffcb8mreed */ 128354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaovoid set_signal_flag(int type) 12997903da2202008733f50e69997029d7a5cfffcb8mreed{ 130354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (debug) 131354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "Catch signal. type is %d\n", type); 13297903da2202008733f50e69997029d7a5cfffcb8mreed 133354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao switch (type) { 13497903da2202008733f50e69997029d7a5cfffcb8mreed case SIGHUP: 135354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao catch_sighup = 1; 136354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao handler.sa_handler = SIG_IGN; 137354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (sigaction(type, &handler, NULL) < 0) 138354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("sigaction()"); 139354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 14097903da2202008733f50e69997029d7a5cfffcb8mreed 14197903da2202008733f50e69997029d7a5cfffcb8mreed default: 142354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "Unexpected signal (%d) is caught\n", type); 143354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao exit(EXIT_FAILURE); 144354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 14597903da2202008733f50e69997029d7a5cfffcb8mreed} 14697903da2202008733f50e69997029d7a5cfffcb8mreed 14797903da2202008733f50e69997029d7a5cfffcb8mreed/* 14897903da2202008733f50e69997029d7a5cfffcb8mreed * Function: parse_options() 14997903da2202008733f50e69997029d7a5cfffcb8mreed * 15097903da2202008733f50e69997029d7a5cfffcb8mreed * Description: 15197903da2202008733f50e69997029d7a5cfffcb8mreed * This function parse the options 15297903da2202008733f50e69997029d7a5cfffcb8mreed * 15397903da2202008733f50e69997029d7a5cfffcb8mreed * Argument: 15497903da2202008733f50e69997029d7a5cfffcb8mreed * argc: number of argument 15597903da2202008733f50e69997029d7a5cfffcb8mreed * argv: arguments 15697903da2202008733f50e69997029d7a5cfffcb8mreed * redirector_p: pointer to data for the redirector information 15797903da2202008733f50e69997029d7a5cfffcb8mreed * bg_p: pointer to the flag of working in backgrond 15897903da2202008733f50e69997029d7a5cfffcb8mreed * 15997903da2202008733f50e69997029d7a5cfffcb8mreed * Return value: 16097903da2202008733f50e69997029d7a5cfffcb8mreed * None 16197903da2202008733f50e69997029d7a5cfffcb8mreed */ 16297903da2202008733f50e69997029d7a5cfffcb8mreedvoid 163354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoparse_options(int argc, char *argv[], struct redirector_info *redirector_p, 164354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao int *bg_p) 16597903da2202008733f50e69997029d7a5cfffcb8mreed{ 166354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao int optc; /* option */ 167354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao double opt_d; /* option value in double */ 168354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 169354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao while ((optc = getopt(argc, argv, "I:N:t:bdh")) != EOF) { 170354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao switch (optc) { 171354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao case 'I': 172354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao redirector_p->ifname = strdup(optarg); 173354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (redirector_p->ifname == NULL) 174354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("strdup() failed."); 175354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 176354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 177354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao case 't': 178354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao opt_d = strtod(optarg, NULL); 179354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (opt_d < 0.0) { 180354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, 181354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao "Timeout should be positive value\n"); 182354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao usage(program_name, EXIT_FAILURE); 183354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 184354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao redirector_p->timeout = opt_d; 185354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 186354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 187354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao case 'b': 188354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao *bg_p = 1; 189354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 190354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 191354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao case 'd': 192354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao debug = 1; 193354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 194354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 195354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao case 'h': 196354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao usage(program_name, EXIT_SUCCESS); 197354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 198354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 199354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao default: 200354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao usage(program_name, EXIT_FAILURE); 20197903da2202008733f50e69997029d7a5cfffcb8mreed } 202354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 20397903da2202008733f50e69997029d7a5cfffcb8mreed 204354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (redirector_p->ifname == NULL) { 205354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "Interface name is not specified\n"); 20697903da2202008733f50e69997029d7a5cfffcb8mreed usage(program_name, EXIT_FAILURE); 20797903da2202008733f50e69997029d7a5cfffcb8mreed } 20897903da2202008733f50e69997029d7a5cfffcb8mreed} 20997903da2202008733f50e69997029d7a5cfffcb8mreed 21097903da2202008733f50e69997029d7a5cfffcb8mreed/* 21197903da2202008733f50e69997029d7a5cfffcb8mreed * Function: open_socket() 21297903da2202008733f50e69997029d7a5cfffcb8mreed * 21397903da2202008733f50e69997029d7a5cfffcb8mreed * Description: 21497903da2202008733f50e69997029d7a5cfffcb8mreed * This function opens a socket for capture/sending 21597903da2202008733f50e69997029d7a5cfffcb8mreed * 21697903da2202008733f50e69997029d7a5cfffcb8mreed * Argument: 21797903da2202008733f50e69997029d7a5cfffcb8mreed * ifname: interface name 21897903da2202008733f50e69997029d7a5cfffcb8mreed * 21997903da2202008733f50e69997029d7a5cfffcb8mreed * Return value: 22097903da2202008733f50e69997029d7a5cfffcb8mreed * socket file descriptor for receiving packets 22197903da2202008733f50e69997029d7a5cfffcb8mreed */ 222354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoint open_socket(const char *ifname) 22397903da2202008733f50e69997029d7a5cfffcb8mreed{ 224354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao int sd; /* Socket to packets */ 225354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ifreq ifinfo; /* Interface information */ 226354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct sockaddr_ll lla; /* Link-local address info for receiving */ 227354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 228354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Create a socket for capture */ 229354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) 230354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("socket()"); 231354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 232354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Make a socket into non-blocking mode */ 233354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (fcntl(sd, F_SETFL, O_NONBLOCK) < 0) 234354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("fcntl()"); 235354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 236354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Get the logical interface number */ 237354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao get_ifinfo(&ifinfo, sd, ifname, SIOCGIFINDEX); 238354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 239354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Bind to the interface */ 240354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(&lla, '\0', sizeof(struct sockaddr_ll)); 241354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao lla.sll_family = PF_PACKET; 242354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao lla.sll_protocol = htons(ETH_P_ALL); 243354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao lla.sll_ifindex = ifinfo.ifr_ifindex; 244354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (bind(sd, (struct sockaddr *)&lla, sizeof(struct sockaddr_ll)) < 0) 245354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("bind()"); 246354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 247354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Change into the promiscuous mode */ 248354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao get_ifinfo(&ifinfo, sd, ifname, SIOCGIFFLAGS); 249354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao ifinfo.ifr_flags = ifinfo.ifr_flags | IFF_PROMISC; 250354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (ioctl(sd, SIOCSIFFLAGS, &ifinfo) < 0) 251354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("ioctl()"); 252354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (debug) 253354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "%s is changed into promiscuous mode\n", 254354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao ifname); 255354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 256354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (debug) 257354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "Packet receiving socket is %d\n", sd); 258354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao return sd; 25997903da2202008733f50e69997029d7a5cfffcb8mreed} 26097903da2202008733f50e69997029d7a5cfffcb8mreed 26197903da2202008733f50e69997029d7a5cfffcb8mreed/* 26297903da2202008733f50e69997029d7a5cfffcb8mreed * Function: return_arp_reply() 26397903da2202008733f50e69997029d7a5cfffcb8mreed * 26497903da2202008733f50e69997029d7a5cfffcb8mreed * Description: 26597903da2202008733f50e69997029d7a5cfffcb8mreed * This function returns arp reply message to arp request message. 26697903da2202008733f50e69997029d7a5cfffcb8mreed * And it updates the IPv4 gateway information. 26797903da2202008733f50e69997029d7a5cfffcb8mreed * 26897903da2202008733f50e69997029d7a5cfffcb8mreed * Argument: 26997903da2202008733f50e69997029d7a5cfffcb8mreed * sd : socket to send arp reply message 27097903da2202008733f50e69997029d7a5cfffcb8mreed * rcveth_p : pointer to ether frame data 27197903da2202008733f50e69997029d7a5cfffcb8mreed * gateway_p : pointer to IPv4 gateway information 27297903da2202008733f50e69997029d7a5cfffcb8mreed * 27397903da2202008733f50e69997029d7a5cfffcb8mreed * Return value: 27497903da2202008733f50e69997029d7a5cfffcb8mreed * None 27597903da2202008733f50e69997029d7a5cfffcb8mreed */ 27697903da2202008733f50e69997029d7a5cfffcb8mreedvoid 277354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoreturn_arp_reply(int sd, struct eth_frame *rcveth_p, 278354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip4_gateway_info *gateway_p) 27997903da2202008733f50e69997029d7a5cfffcb8mreed{ 280354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao int retval; 281354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct arp_datagram *rcvarp_p; /* ARP part of receiving frame */ 282354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao unsigned char new_hd_addr[ETH_ALEN]; /* New MAC address */ 283354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao unsigned char new_nexthop[4]; /* New next hop */ 284354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao size_t sndeth_size; /* Size of sending frame */ 285354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct eth_frame sndeth; /* sending frame */ 286354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct arp_datagram *sndarp_p; /* ARP part of sending frame */ 287354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 288354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao rcvarp_p = (struct arp_datagram *)&(rcveth_p->data); 289354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 290354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* If arp message is not arp request, do nothing */ 291354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (debug) 292354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "ARP OP code is %02x\n", 293354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao ntohs(rcvarp_p->hdr.ar_op)); 294354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (rcvarp_p->hdr.ar_op != htons(ARPOP_REQUEST)) 295354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao return; 296354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 297354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Update the gateway information */ 298354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(new_hd_addr, '\0', ETH_ALEN); /* MAC address */ 299354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao for (;;) { 300354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao new_hd_addr[3] = rand_within(0, 254); 301354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao new_hd_addr[4] = rand_within(0, 254); 302354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao new_hd_addr[5] = rand_within(1, 254); 303354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (memcmp(gateway_p->hd_addr, new_hd_addr, ETH_ALEN)) { 304354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(gateway_p->hd_addr, new_hd_addr, ETH_ALEN); 305354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 306354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 30797903da2202008733f50e69997029d7a5cfffcb8mreed } 30897903da2202008733f50e69997029d7a5cfffcb8mreed 309354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(gateway_p->ip_addr, rcvarp_p->ar_tip, 4); /* IP address */ 31097903da2202008733f50e69997029d7a5cfffcb8mreed 311354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao for (;;) { /* next hop */ 312354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(new_nexthop, gateway_p->ip_addr, 4); 313354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao new_nexthop[3] = rand_within(1, 254); 314354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (memcmp(gateway_p->nexthop, new_nexthop, 4)) { 315354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(gateway_p->nexthop, new_nexthop, 4); 316354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 317354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 31897903da2202008733f50e69997029d7a5cfffcb8mreed } 319354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 320354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Build a frame to send */ 321354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(&sndeth, '\0', sizeof(struct eth_frame)); 322354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndarp_p = (struct arp_datagram *)&(sndeth.data); 323354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndeth_size = sizeof(struct ethhdr) + sizeof(struct arp_datagram); 324354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 325354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Ether */ 326354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndeth.hdr.h_dest, rcveth_p->hdr.h_source, ETH_ALEN); 327354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndeth.hdr.h_source, gateway_p->hd_addr, ETH_ALEN); 328354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndeth.hdr.h_proto = htons(ETH_P_ARP); 329354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 330354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Arp */ 331354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndarp_p->hdr.ar_hrd = htons(ARPHRD_ETHER); 332354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndarp_p->hdr.ar_pro = htons(ETH_P_IP); 333354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndarp_p->hdr.ar_hln = ETH_ALEN; 334354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndarp_p->hdr.ar_pln = 4; 335354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndarp_p->hdr.ar_op = htons(ARPOP_REPLY); 336354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndarp_p->ar_sha, gateway_p->hd_addr, ETH_ALEN); 337354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndarp_p->ar_sip, gateway_p->ip_addr, 4); 338354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndarp_p->ar_tha, rcvarp_p->ar_sha, ETH_ALEN); 339354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndarp_p->ar_tip, rcvarp_p->ar_sip, 4); 340354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 341354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Send ARP reply */ 342354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao retval = write(sd, &sndeth, sndeth_size); 343354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (retval != sndeth_size) 344354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("write()"); 34597903da2202008733f50e69997029d7a5cfffcb8mreed} 34697903da2202008733f50e69997029d7a5cfffcb8mreed 34797903da2202008733f50e69997029d7a5cfffcb8mreed/* 34897903da2202008733f50e69997029d7a5cfffcb8mreed * Function: return_icmp4_redirect() 34997903da2202008733f50e69997029d7a5cfffcb8mreed * 35097903da2202008733f50e69997029d7a5cfffcb8mreed * Description: 35197903da2202008733f50e69997029d7a5cfffcb8mreed * This function returns icmp redirect message 35297903da2202008733f50e69997029d7a5cfffcb8mreed * 35397903da2202008733f50e69997029d7a5cfffcb8mreed * Argument: 35497903da2202008733f50e69997029d7a5cfffcb8mreed * sd : socket to send arp reply message 35597903da2202008733f50e69997029d7a5cfffcb8mreed * rcveth_p : pointer to ether frame data 35697903da2202008733f50e69997029d7a5cfffcb8mreed * rcveth_size: size of received ehter frame 35797903da2202008733f50e69997029d7a5cfffcb8mreed * new_gw_p : pointer to new IPv4 gateway information 35897903da2202008733f50e69997029d7a5cfffcb8mreed * 35997903da2202008733f50e69997029d7a5cfffcb8mreed * Return value: 36097903da2202008733f50e69997029d7a5cfffcb8mreed * None 36197903da2202008733f50e69997029d7a5cfffcb8mreed */ 36297903da2202008733f50e69997029d7a5cfffcb8mreedvoid 363354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoreturn_icmp4_redirect(int sd, struct eth_frame *rcveth_p, size_t rcveth_size, 364354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip4_gateway_info *new_gw_p) 36597903da2202008733f50e69997029d7a5cfffcb8mreed{ 366354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao static struct ip4_gateway_info *gw_p; /* pointor to gateway */ 367354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 368354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao int retval; 369354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip4_datagram *rcvip_p; /* IPv4 part of receiving frame */ 370354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao size_t sndeth_size; /* Size of sending frame */ 371354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct eth_frame sndeth; /* sending frame */ 372354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip4_datagram *sndip_p; /* IPv4 part of sending frame */ 373354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct icmp4_segment *sndicmp_p; /* ICMPv4 part of sending frame */ 374354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao size_t icmp4_datasize; /* Size of sending ICMPv4 */ 375354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 376354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* If MAC address in received frame is changed, update the gateway info */ 377354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (memcmp(rcveth_p->hdr.h_dest, new_gw_p->hd_addr, ETH_ALEN) == 0) { 378354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (gw_p == NULL) 379d218f348c12b42a78fa0306d9a033bfa4f67238bCyril Hrubis if ((gw_p = malloc(sizeof(struct ip4_gateway_info))) == NULL) 380354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("malloc()"); 381354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao *gw_p = *new_gw_p; 382354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } else if (gw_p == NULL 383354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao || memcmp(rcveth_p->hdr.h_dest, gw_p->hd_addr, ETH_ALEN)) 384354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao return; 385354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 386354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao rcvip_p = (struct ip4_datagram *)&(rcveth_p->data); 387354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 388354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Build a frame to send */ 389354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndeth_size = sizeof(struct ethhdr) /* Ether header */ 390354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao +sizeof(struct iphdr) /* IPv4 header */ 391354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao +sizeof(struct icmphdr) /* ICMPv4 header */ 392354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao +rcveth_size - sizeof(struct ethhdr); /* ICMPv4 payload */ 393354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndeth_size = (sndeth_size < ETH_DATA_MAXSIZE) 394354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao ? sndeth_size : ETH_DATA_MAXSIZE; 395354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(&sndeth, '\0', sizeof(struct eth_frame)); 396354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip_p = (struct ip4_datagram *)&(sndeth.data); 397354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndicmp_p = (struct icmp4_segment *)&(sndip_p->payload); 398354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 399354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Ether */ 400354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndeth.hdr.h_dest, rcveth_p->hdr.h_source, ETH_ALEN); 401354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndeth.hdr.h_source, gw_p->hd_addr, ETH_ALEN); 402354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndeth.hdr.h_proto = htons(ETH_P_IP); 403354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 404354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* IP */ 405354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip_p->hdr.version = 4; 406354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip_p->hdr.ihl = sizeof(struct iphdr) / 4; 407354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip_p->hdr.tos = 0; 408354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip_p->hdr.tot_len = htons(sndeth_size - sizeof(struct ethhdr)); 409354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip_p->hdr.id = htons(IPV4_PACKET_ID); 410354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip_p->hdr.frag_off = htons(IPV4_DEFAULT_FLAG); 411354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip_p->hdr.ttl = IPV4_DEFAULT_TTL; 412354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip_p->hdr.protocol = IPPROTO_ICMP; 413354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip_p->hdr.check = 0; /* Calculate later */ 414354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy((unsigned char *)&sndip_p->hdr.saddr, gw_p->ip_addr, 4); 415354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip_p->hdr.daddr = rcvip_p->hdr.saddr; 416354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip_p->hdr.check = calc_checksum((u_int16_t *) & (sndip_p->hdr), 417354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sizeof(struct iphdr)); 418354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 419354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* ICMP */ 420354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndicmp_p->hdr.type = ICMP_REDIRECT; 421354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndicmp_p->hdr.code = ICMP_REDIR_HOST; 422354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndicmp_p->hdr.checksum = 0; /* Calculate later */ 423354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy((unsigned char *)&(sndicmp_p->hdr.un.gateway), gw_p->nexthop, 4); 424354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 425354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* ICMP payload */ 426354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao icmp4_datasize = rcveth_size - sizeof(struct ethhdr); 427354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao icmp4_datasize = 428354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao (icmp4_datasize < 429354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao ICMPV4_DATA_MAXSIZE) ? icmp4_datasize : ICMPV4_DATA_MAXSIZE; 430354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndicmp_p->data, rcvip_p, icmp4_datasize); 431354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 432354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Calculate ICMP checksum */ 433354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndicmp_p->hdr.checksum = calc_checksum((u_int16_t *) sndicmp_p, 434354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sizeof(struct icmphdr) + 435354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao icmp4_datasize); 436354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 437354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Send ICMP redirect */ 438354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao retval = write(sd, &sndeth, sndeth_size); 439354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (retval != sndeth_size) 440354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("write()"); 44197903da2202008733f50e69997029d7a5cfffcb8mreed} 44297903da2202008733f50e69997029d7a5cfffcb8mreed 44397903da2202008733f50e69997029d7a5cfffcb8mreed/* 44497903da2202008733f50e69997029d7a5cfffcb8mreed * Function: return_neigh_adv() 44597903da2202008733f50e69997029d7a5cfffcb8mreed * 44697903da2202008733f50e69997029d7a5cfffcb8mreed * Description: 44797903da2202008733f50e69997029d7a5cfffcb8mreed * This function returns neighbor advertisement message 44897903da2202008733f50e69997029d7a5cfffcb8mreed * And this updates the gateway information. 44997903da2202008733f50e69997029d7a5cfffcb8mreed * 45097903da2202008733f50e69997029d7a5cfffcb8mreed * Argument: 45197903da2202008733f50e69997029d7a5cfffcb8mreed * sd : socket to send arp reply message 45297903da2202008733f50e69997029d7a5cfffcb8mreed * rcveth_p : pointer to ether frame data 45397903da2202008733f50e69997029d7a5cfffcb8mreed * current_eth: current MAC address 45497903da2202008733f50e69997029d7a5cfffcb8mreed * gateway_p : pointer to IPv6 gateway information 45597903da2202008733f50e69997029d7a5cfffcb8mreed * 45697903da2202008733f50e69997029d7a5cfffcb8mreed * Return value: 45797903da2202008733f50e69997029d7a5cfffcb8mreed * None 45897903da2202008733f50e69997029d7a5cfffcb8mreed */ 45997903da2202008733f50e69997029d7a5cfffcb8mreedvoid 460354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoreturn_neigh_adv(int sd, struct eth_frame *rcveth_p, 461354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip6_gateway_info *gateway_p) 46297903da2202008733f50e69997029d7a5cfffcb8mreed{ 463354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao int retval; 464354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip6_datagram *rcvip6_p; /* IPv6 part of receiving frame */ 465354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct neighbor_sol *rcvns_p; /* NS part of receiving frame */ 466354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao unsigned char new_hd_addr[ETH_ALEN]; /* new MAC address */ 467354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct in6_addr new_nexthop; /* new next hop */ 468354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao size_t sndeth_size; /* size of sending frame */ 469354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct eth_frame sndeth; /* sending frame */ 470354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip6_datagram *sndip6_p; /* IPv6 part of sending frame */ 471354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct pseudo_ip6_datagram p_ip6; /* pseudo IP header */ 472354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct neighbor_adv *sndna_p; /* NA part of sending frame */ 473354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 474354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao rcvip6_p = (struct ip6_datagram *)&(rcveth_p->data); 475354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao rcvns_p = (struct neighbor_sol *)&(rcvip6_p->payload); 476354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 477354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* If NS is DAD NS, do nothing */ 478354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (memcmp 479354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao (&(rcvip6_p->hdr.ip6_src), &in6addr_any, 480354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sizeof(struct in6_addr)) == 0) { 481354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (debug) { 482354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "Received NS is a DAD NS\n"); 483354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao return; 484354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 48597903da2202008733f50e69997029d7a5cfffcb8mreed } 486354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 487354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Update the gateway information */ 488354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(new_hd_addr, '\0', ETH_ALEN); /* MAC address */ 489354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao for (;;) { 490354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao new_hd_addr[3] = rand_within(0, 254); 491354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao new_hd_addr[4] = rand_within(0, 254); 492354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao new_hd_addr[5] = rand_within(1, 254); 493354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (memcmp(gateway_p->hd_addr, new_hd_addr, ETH_ALEN)) { 494354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(gateway_p->hd_addr, new_hd_addr, ETH_ALEN); 495354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 496354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 49797903da2202008733f50e69997029d7a5cfffcb8mreed } 498354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 499354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao gateway_p->ip_addr = rcvns_p->defs.nd_ns_target; /* IP address */ 500354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 501354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao for (;;) { /* next hop */ 502354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(&new_nexthop, '\0', sizeof(struct in6_addr)); 503354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao new_nexthop.s6_addr[0] = 0xfe; 504354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao new_nexthop.s6_addr[1] = 0x80; 505354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao new_nexthop.s6_addr[15] = rand_within(1, 254); 506354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (memcmp 507354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao (&(gateway_p->nexthop), &new_nexthop, 508354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sizeof(struct in6_addr))) { 509354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao gateway_p->nexthop = new_nexthop; 510354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 511354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 51297903da2202008733f50e69997029d7a5cfffcb8mreed } 513354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 514354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Build a frame to send */ 515354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndeth_size = sizeof(struct ethhdr) + sizeof(struct ip6_hdr) 516354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao + sizeof(struct neighbor_adv); 517354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(&sndeth, '\0', sizeof(struct eth_frame)); 518354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p = (struct ip6_datagram *)&(sndeth.data); 519354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndna_p = (struct neighbor_adv *)&(sndip6_p->payload); 520354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 521354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Ether */ 522354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndeth.hdr.h_dest, rcvns_p->src_laddr, ETH_ALEN); 523354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndeth.hdr.h_source, gateway_p->hd_addr, ETH_ALEN); 524354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndeth.hdr.h_proto = htons(ETH_P_IPV6); 525354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 526354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* IPv6 */ 527354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_vfc = 6 << 4; 528354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_flow |= 0; 529354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_plen = htons(sizeof(struct neighbor_adv)); 530354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_nxt = IPPROTO_ICMPV6; 531354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_hlim = 255; 532354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_src = gateway_p->ip_addr; 533354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_dst = rcvip6_p->hdr.ip6_src; 534354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 535354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Neighbor Advertisement */ 536354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndna_p->defs.nd_na_type = ND_NEIGHBOR_ADVERT; 537354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndna_p->defs.nd_na_code = 0; 538354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndna_p->defs.nd_na_cksum = 0; /* Calculate later */ 539354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndna_p->defs.nd_na_target = gateway_p->ip_addr; 540354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndna_p->defs.nd_na_flags_reserved 541354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao = ND_NA_FLAG_ROUTER | ND_NA_FLAG_SOLICITED | ND_NA_FLAG_OVERRIDE; 542354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndna_p->tla_opt.nd_opt_type = ND_OPT_TARGET_LINKADDR; 543354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndna_p->tla_opt.nd_opt_len = 1; 544354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndna_p->tgt_laddr, &(gateway_p->hd_addr), ETH_ALEN); 545354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 546354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Pseudo IPv6 datagram for checksum calculation */ 547354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(&p_ip6, '\0', sizeof(struct pseudo_ip6_datagram)); 548354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao p_ip6.hdr.p_ip6_src = sndip6_p->hdr.ip6_src; 549354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao p_ip6.hdr.p_ip6_dst = sndip6_p->hdr.ip6_dst; 550354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao p_ip6.hdr.p_ip6_plen = sndip6_p->hdr.ip6_plen; 551354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao p_ip6.hdr.p_ip6_zero1 = 0; 552354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao p_ip6.hdr.p_ip6_zero2 = 0; 553354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao p_ip6.hdr.p_ip6_nxt = sndip6_p->hdr.ip6_nxt; 554354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(p_ip6.payload, sndna_p, sizeof(struct neighbor_adv)); 555354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 556354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Calculate checksum */ 557354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndna_p->defs.nd_na_cksum = calc_checksum((u_int16_t *) (&p_ip6), 558354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sizeof(struct pseudo_ip6_hdr) 559354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao + 560354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sizeof(struct neighbor_adv)); 561354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 562354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Send Neighbor Advertisement reply */ 563354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao retval = write(sd, &sndeth, sndeth_size); 564354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (retval != sndeth_size) 565354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("write()"); 56697903da2202008733f50e69997029d7a5cfffcb8mreed} 56797903da2202008733f50e69997029d7a5cfffcb8mreed 56897903da2202008733f50e69997029d7a5cfffcb8mreed/* 56997903da2202008733f50e69997029d7a5cfffcb8mreed * Function: return_icmp6_redirect() 57097903da2202008733f50e69997029d7a5cfffcb8mreed * 57197903da2202008733f50e69997029d7a5cfffcb8mreed * Description: 5722c28215423293e443469a07ae7011135d058b671Garrett Cooper * This function returns an ICMPv6 redirect message 57397903da2202008733f50e69997029d7a5cfffcb8mreed * 57497903da2202008733f50e69997029d7a5cfffcb8mreed * Argument: 57597903da2202008733f50e69997029d7a5cfffcb8mreed * sd : socket to send arp reply message 57697903da2202008733f50e69997029d7a5cfffcb8mreed * rcveth_p : pointer to ether frame data 57797903da2202008733f50e69997029d7a5cfffcb8mreed * rcveth_size: size of received ehter frame 57897903da2202008733f50e69997029d7a5cfffcb8mreed * new_gw_p : pointer to new IPv4 gateway information 57997903da2202008733f50e69997029d7a5cfffcb8mreed * 58097903da2202008733f50e69997029d7a5cfffcb8mreed * Return value: 58197903da2202008733f50e69997029d7a5cfffcb8mreed * None 58297903da2202008733f50e69997029d7a5cfffcb8mreed */ 58397903da2202008733f50e69997029d7a5cfffcb8mreedvoid 584354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoreturn_icmp6_redirect(int sd, struct eth_frame *rcveth_p, size_t rcveth_size, 585354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip6_gateway_info *new_gw_p) 58697903da2202008733f50e69997029d7a5cfffcb8mreed{ 587354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao static struct ip6_gateway_info *gw_p = NULL; /* pointor to gateway */ 588354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 589354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao int retval; 590354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip6_datagram *rcvip6_p; /* IPv6 part of receiving frame */ 591354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct eth_frame sndeth; /* sending frame */ 592354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao size_t sndeth_size; /* size of sending frame */ 593354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip6_datagram *sndip6_p; /* IPv6 part of sending frame */ 594354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao size_t ip6_payload_size; /* payload size of IPv6 part */ 595354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct pseudo_ip6_datagram p_ip6; /* pseudo header for checksum */ 596354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct neighbor_redirect *sndrd_p; /* ICMPv6 part of sending frame */ 597354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao size_t redirect_optsize; /* Option size of ICMPv6 */ 598354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 599354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao rcvip6_p = (struct ip6_datagram *)&(rcveth_p->data); 600354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 601354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* If MAC address in received frame is changed, update the gateway info */ 602354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (memcmp(rcveth_p->hdr.h_dest, new_gw_p->hd_addr, ETH_ALEN) == 0) { 603354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (gw_p == NULL) 604354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if ((gw_p = malloc(sizeof(struct in6_addr))) == NULL) 605354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("malloc()"); 606354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao *gw_p = *new_gw_p; 607354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } else if (gw_p == NULL 608354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao || memcmp(rcveth_p->hdr.h_dest, gw_p->hd_addr, ETH_ALEN)) 609354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao return; 610354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 611354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Build a frame to send */ 612354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(&sndeth, '\0', sizeof(struct eth_frame)); 613354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p = (struct ip6_datagram *)&(sndeth.data); 614354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndrd_p = (struct neighbor_redirect *)&(sndip6_p->payload); 615354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao redirect_optsize = sizeof(struct nd_opt_rd_hdr) 616354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao + rcveth_size - sizeof(struct ethhdr); 617354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao redirect_optsize = (redirect_optsize < RDOPT_MAXSIZE) 618354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao ? redirect_optsize : RDOPT_MAXSIZE; 619354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao ip6_payload_size = sizeof(struct nd_redirect) + redirect_optsize; 620354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndeth_size = sizeof(struct ethhdr) + sizeof(struct ip6_hdr) 621354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao + ip6_payload_size; 622354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 623354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Ether */ 624354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndeth.hdr.h_dest, rcveth_p->hdr.h_source, ETH_ALEN); 625354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndeth.hdr.h_source, gw_p->hd_addr, ETH_ALEN); 626354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndeth.hdr.h_proto = htons(ETH_P_IPV6); 627354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 628354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* IPv6 */ 629354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_vfc = 6 << 4; 630354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_flow |= 0; 631354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_plen = htons(ip6_payload_size); 632354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_nxt = IPPROTO_ICMPV6; 633354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_hlim = 255; 634354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_src = gw_p->ip_addr; 635354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndip6_p->hdr.ip6_dst = rcvip6_p->hdr.ip6_src; 636354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 637354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Rediret Message */ 638354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndrd_p->defs.nd_rd_type = ND_REDIRECT; 639354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndrd_p->defs.nd_rd_code = 0; 640354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndrd_p->defs.nd_rd_cksum = 0; /* Calculate later */ 641354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndrd_p->defs.nd_rd_reserved = 0; 642354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndrd_p->defs.nd_rd_target = gw_p->nexthop; 643354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndrd_p->defs.nd_rd_dst = rcvip6_p->hdr.ip6_dst;; 644354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndrd_p->rdopt_hdr.nd_opt_rh_type = ND_OPT_REDIRECTED_HEADER; 645354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndrd_p->rdopt_hdr.nd_opt_rh_len = redirect_optsize / 8; 646354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(sndrd_p->rdopt_data, rcvip6_p, redirect_optsize); 647354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 648354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Pseudo IPv6 datagram for checksum calculation */ 649354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(&p_ip6, '\0', sizeof(struct pseudo_ip6_datagram)); 650354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao p_ip6.hdr.p_ip6_src = sndip6_p->hdr.ip6_src; 651354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao p_ip6.hdr.p_ip6_dst = sndip6_p->hdr.ip6_dst; 652354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao p_ip6.hdr.p_ip6_plen = sndip6_p->hdr.ip6_plen; 653354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao p_ip6.hdr.p_ip6_zero1 = 0; 654354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao p_ip6.hdr.p_ip6_zero2 = 0; 655354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao p_ip6.hdr.p_ip6_nxt = sndip6_p->hdr.ip6_nxt; 656354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memcpy(p_ip6.payload, sndrd_p, ip6_payload_size); 657354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 658354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Calculate checksum */ 659354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sndrd_p->defs.nd_rd_cksum = calc_checksum((u_int16_t *) (&p_ip6), 660354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao sizeof(struct pseudo_ip6_hdr) 661354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao + ip6_payload_size); 662354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 663354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Send ICMPv6 redirct message */ 664354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao retval = write(sd, &sndeth, sndeth_size); 665354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (retval != sndeth_size) 666354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("write()"); 66797903da2202008733f50e69997029d7a5cfffcb8mreed} 66897903da2202008733f50e69997029d7a5cfffcb8mreed 66997903da2202008733f50e69997029d7a5cfffcb8mreed/* 67097903da2202008733f50e69997029d7a5cfffcb8mreed * Function: analyze_ip6_datagram() 67197903da2202008733f50e69997029d7a5cfffcb8mreed * 67297903da2202008733f50e69997029d7a5cfffcb8mreed * Description: 67397903da2202008733f50e69997029d7a5cfffcb8mreed * This function analyze captured IPv6 datagram 67497903da2202008733f50e69997029d7a5cfffcb8mreed * 67597903da2202008733f50e69997029d7a5cfffcb8mreed * Argument: 67697903da2202008733f50e69997029d7a5cfffcb8mreed * sd : socket to send arp reply message 67797903da2202008733f50e69997029d7a5cfffcb8mreed * rcveth_p : pointer to ether frame data 67897903da2202008733f50e69997029d7a5cfffcb8mreed * rcveth_size : size of received ehter frame 67997903da2202008733f50e69997029d7a5cfffcb8mreed * gateway_p : pointer to IPv6 gateway information 68097903da2202008733f50e69997029d7a5cfffcb8mreed * 68197903da2202008733f50e69997029d7a5cfffcb8mreed * Return value: 68297903da2202008733f50e69997029d7a5cfffcb8mreed * None 68397903da2202008733f50e69997029d7a5cfffcb8mreed */ 68497903da2202008733f50e69997029d7a5cfffcb8mreedvoid 685354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoanalyze_ip6_datagram(int sd, struct eth_frame *rcveth_p, size_t rcveth_size, 686354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip6_gateway_info *gateway_p) 68797903da2202008733f50e69997029d7a5cfffcb8mreed{ 688354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip6_datagram *rcvip6_p; /* IPv6 Part of receiving frame */ 689354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct icmp6_segment *rcvicmp6_p; /* ICMPv6 Part of receiving frame */ 690354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao uint8_t nxt_hdr; /* Next header of IPv6 */ 691354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao uint8_t icmp6_type; /* Type of ICMPv6 */ 69297903da2202008733f50e69997029d7a5cfffcb8mreed 693354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao rcvip6_p = (struct ip6_datagram *)&(rcveth_p->data); 694354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao rcvicmp6_p = (struct icmp6_segment *)&(rcvip6_p->payload); 69597903da2202008733f50e69997029d7a5cfffcb8mreed 696354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao nxt_hdr = rcvip6_p->hdr.ip6_nxt; 697354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao switch (nxt_hdr) { 69897903da2202008733f50e69997029d7a5cfffcb8mreed case IPPROTO_ICMPV6: 699354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao icmp6_type = rcvicmp6_p->hdr.icmp6_type; 700354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao switch (icmp6_type) { 70197903da2202008733f50e69997029d7a5cfffcb8mreed case ND_NEIGHBOR_SOLICIT: 702354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (debug) 703354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "Received ICMP NS\n"); 704354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao return_neigh_adv(sd, rcveth_p, gateway_p); 705354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 70697903da2202008733f50e69997029d7a5cfffcb8mreed 70797903da2202008733f50e69997029d7a5cfffcb8mreed case ICMP6_ECHO_REQUEST: 708354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (debug) 709354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "Received ICMP Echo Request\n"); 710354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao return_icmp6_redirect(sd, rcveth_p, rcveth_size, 711354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao gateway_p); 712354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 713354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 714354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 71597903da2202008733f50e69997029d7a5cfffcb8mreed 71697903da2202008733f50e69997029d7a5cfffcb8mreed case IPPROTO_UDP: 717354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (debug) 718354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "Received UDP message\n"); 719354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao return_icmp6_redirect(sd, rcveth_p, rcveth_size, gateway_p); 720354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 721354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 72297903da2202008733f50e69997029d7a5cfffcb8mreed} 72397903da2202008733f50e69997029d7a5cfffcb8mreed 72497903da2202008733f50e69997029d7a5cfffcb8mreed/* 72597903da2202008733f50e69997029d7a5cfffcb8mreed * Function: capture_frames() 72697903da2202008733f50e69997029d7a5cfffcb8mreed * 72797903da2202008733f50e69997029d7a5cfffcb8mreed * Description: 72897903da2202008733f50e69997029d7a5cfffcb8mreed * This function captures frames 72997903da2202008733f50e69997029d7a5cfffcb8mreed * 73097903da2202008733f50e69997029d7a5cfffcb8mreed * Argument: 73197903da2202008733f50e69997029d7a5cfffcb8mreed * redirector_p: pointer to data for the redirector information 73297903da2202008733f50e69997029d7a5cfffcb8mreed * 73397903da2202008733f50e69997029d7a5cfffcb8mreed * Return value: 73497903da2202008733f50e69997029d7a5cfffcb8mreed * socket file descriptor for receiving packets 73597903da2202008733f50e69997029d7a5cfffcb8mreed */ 736354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaovoid capture_frames(struct redirector_info *redirector_p) 73797903da2202008733f50e69997029d7a5cfffcb8mreed{ 738354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip4_gateway_info ip4_gateway; /* IPv4 gateway information */ 739354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct ip6_gateway_info ip6_gateway; /* IPv6 gateway information */ 740354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct eth_frame frame; /* captured frame data */ 741354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao ssize_t frame_size; /* captured frame size */ 742354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao double start_time; /* capture starting time */ 743354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao int sd = redirector_p->sd; /* socket fd for capture */ 744354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 745354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Initialize gateway information */ 746354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(&ip4_gateway, '\0', sizeof(struct ip4_gateway_info)); 747354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(&ip6_gateway, '\0', sizeof(struct ip6_gateway_info)); 748354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 749354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* Set singal hander for SIGHUP */ 750354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao handler.sa_handler = set_signal_flag; 751354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao handler.sa_flags = 0; 752354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (sigfillset(&handler.sa_mask) < 0) 753354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("sigfillset()"); 754354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (sigaction(SIGHUP, &handler, NULL) < 0) 755354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("sigfillset()"); 756354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 757354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* 758354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao * loop for capture 759354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao */ 760354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao start_time = time(NULL); 761354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 762354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao for (;;) { 763354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao frame_size = read(sd, (void *)(&frame), sizeof(frame)); 764354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (frame_size < 0) { 765354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (errno != EAGAIN) 766354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("read()"); 767354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } else { 768354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao switch (ntohs(frame.hdr.h_proto)) { 769354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao case ETH_P_ARP: 770354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (debug) 771354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "Get ARP packet\n"); 772354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao return_arp_reply(sd, &frame, &ip4_gateway); 773354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 774354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 775354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao case ETH_P_IP: 776354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (debug) 777354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "Get IPv4 packet\n"); 778354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao return_icmp4_redirect(sd, &frame, frame_size, 779354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao &ip4_gateway); 780354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 781354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao 782354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao case ETH_P_IPV6: 783354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (debug) 784354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fprintf(stderr, "Get IPv6 packet\n"); 785354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao analyze_ip6_datagram(sd, &frame, frame_size, 786354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao &ip6_gateway); 787354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 788354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 789354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 79097903da2202008733f50e69997029d7a5cfffcb8mreed 791354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (redirector_p->timeout) 792354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (redirector_p->timeout < 793354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao difftime(time(NULL), start_time)) 794354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 79597903da2202008733f50e69997029d7a5cfffcb8mreed 796354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (catch_sighup) /* catch SIGHUP */ 797354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao break; 798354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } 79997903da2202008733f50e69997029d7a5cfffcb8mreed} 80097903da2202008733f50e69997029d7a5cfffcb8mreed 80197903da2202008733f50e69997029d7a5cfffcb8mreed/* 80297903da2202008733f50e69997029d7a5cfffcb8mreed * 80397903da2202008733f50e69997029d7a5cfffcb8mreed * Function: main() 80497903da2202008733f50e69997029d7a5cfffcb8mreed * 80597903da2202008733f50e69997029d7a5cfffcb8mreed */ 806354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaoint main(int argc, char *argv[]) 80797903da2202008733f50e69997029d7a5cfffcb8mreed{ 808354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao struct redirector_info redirector; 809354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao int background = 0; 81097903da2202008733f50e69997029d7a5cfffcb8mreed 811354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao debug = 0; 812354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao program_name = strdup(argv[0]); 813354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao srand(getpid()); 81497903da2202008733f50e69997029d7a5cfffcb8mreed 815354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao memset(&redirector, '\0', sizeof(struct redirector_info)); 816354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao parse_options(argc, argv, &redirector, &background); 81797903da2202008733f50e69997029d7a5cfffcb8mreed 818354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao redirector.sd = open_socket(redirector.ifname); 81997903da2202008733f50e69997029d7a5cfffcb8mreed 820354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (background) /* Work in the background */ 821354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (daemon(0, 0) < 0) 822354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao fatal_error("daemon()"); 82397903da2202008733f50e69997029d7a5cfffcb8mreed 824354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao capture_frames(&redirector); 82597903da2202008733f50e69997029d7a5cfffcb8mreed 826354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao close(redirector.sd); 827354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao exit(EXIT_SUCCESS); 828ec6edca7aa42b6affd989ef91b5897f96795e40fChris Dearman} 829