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