You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
577 lines
14 KiB
577 lines
14 KiB
/******************************************************************************/
|
|
/* */
|
|
/* Copyright (c) International Business Machines Corp., 2005, 2006 */
|
|
/* */
|
|
/* This program is free software; you can redistribute it and/or modify */
|
|
/* it under the terms of the GNU General Public License as published by */
|
|
/* the Free Software Foundation; either version 2 of the License, or */
|
|
/* (at your option) any later version. */
|
|
/* */
|
|
/* This program is distributed in the hope that it will be useful, */
|
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
|
|
/* the GNU General Public License for more details. */
|
|
/* */
|
|
/* You should have received a copy of the GNU General Public License */
|
|
/* along with this program; if not, write to the Free Software */
|
|
/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
/* */
|
|
/******************************************************************************/
|
|
|
|
/*
|
|
* File:
|
|
* ns-common.c
|
|
*
|
|
* Description:
|
|
* Common functions and variables in the ns-tools
|
|
*
|
|
* Author:
|
|
* Mitsuru Chinen <mitch@jp.ibm.com>
|
|
*
|
|
* History:
|
|
* Oct 19 2005 - Created (Mitsuru Chinen)
|
|
* May 1 2006 - Added functions for broken_ip, route, multicast tests
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
* Fixed values
|
|
*/
|
|
#define PROC_RMEM_MAX "/proc/sys/net/core/rmem_max"
|
|
#define PROC_WMEM_MAX "/proc/sys/net/core/wmem_max"
|
|
|
|
/*
|
|
* Standard Header Files
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <net/ethernet.h>
|
|
#include <net/if.h>
|
|
#include <net/if_arp.h>
|
|
|
|
#include "ns-mcast.h"
|
|
#define NS_COMMON 1
|
|
#include "ns-traffic.h"
|
|
|
|
/*
|
|
* Function: fatal_error()
|
|
*
|
|
* Description:
|
|
* Output an error message then exit the program with EXIT_FAILURE
|
|
*
|
|
* Argument:
|
|
* errmsg: message printed by perror()
|
|
*
|
|
* Return value:
|
|
* This function does not return.
|
|
*/
|
|
void fatal_error(char *errmsg)
|
|
{
|
|
perror(errmsg);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/*
|
|
* Function: maximize_sockbuf()
|
|
*
|
|
* Descripton:
|
|
* This function maximize the send and receive buffer size of a socket
|
|
*
|
|
* Argument:
|
|
* sd: target socket descriptor
|
|
*
|
|
* Return value:
|
|
* None
|
|
*/
|
|
void maximize_sockbuf(int sd)
|
|
{
|
|
size_t idx;
|
|
int level[] = { SO_RCVBUF, SO_SNDBUF };
|
|
char *procfile[] = { PROC_RMEM_MAX, PROC_WMEM_MAX };
|
|
char *bufname[] = { "rcvbuf", "sndbuf" };
|
|
|
|
for (idx = 0; idx < (sizeof(level) / sizeof(int)); idx++) {
|
|
FILE *fp; /* File pointer to a proc file */
|
|
int bufsiz; /* buffer size of socket */
|
|
unsigned int optlen; /* size of sd option parameter */
|
|
|
|
if ((fp = fopen(procfile[idx], "r")) == NULL) {
|
|
fprintf(stderr, "Failed to open %s\n", procfile[idx]);
|
|
fatal_error("fopen()");
|
|
}
|
|
if ((fscanf(fp, "%d", &bufsiz)) != 1) {
|
|
fprintf(stderr, "Failed to read from %s\n",
|
|
procfile[idx]);
|
|
fatal_error("fscanf()");
|
|
}
|
|
if (setsockopt
|
|
(sd, SOL_SOCKET, level[idx], &bufsiz, sizeof(int))) {
|
|
fatal_error("setsockopt()");
|
|
}
|
|
if (fclose(fp)) {
|
|
fprintf(stderr, "Failed to close to %s\n",
|
|
procfile[idx]);
|
|
fatal_error("fopen()");
|
|
}
|
|
|
|
if (debug) {
|
|
optlen = sizeof(bufsiz);
|
|
if (getsockopt
|
|
(sd, SOL_SOCKET, level[idx], &bufsiz,
|
|
&optlen) < 0) {
|
|
fatal_error("getsockopt()");
|
|
}
|
|
fprintf(stderr, "socket %s size is %d\n", bufname[idx],
|
|
bufsiz);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function: calc_checksum()
|
|
*
|
|
* Description:
|
|
* This function calculate the checksum of IPv4 or ICMP
|
|
*
|
|
* Argument:
|
|
* data: pointer to target data for checksum
|
|
* size: target data size
|
|
*
|
|
* Return value:
|
|
* None
|
|
*/
|
|
u_int16_t calc_checksum(u_int16_t * data, size_t size)
|
|
{
|
|
u_int32_t sum;
|
|
u_int16_t *pos;
|
|
size_t rest;
|
|
|
|
sum = 0;
|
|
pos = data;
|
|
for (rest = size; rest > 1; rest -= 2)
|
|
sum += *(pos++);
|
|
|
|
if (rest > 0)
|
|
sum += (*pos) & 0xff00;
|
|
|
|
sum = (sum & 0xffff) + (sum >> 16);
|
|
sum = (sum & 0xffff) + (sum >> 16);
|
|
sum = ~sum;
|
|
|
|
return sum;
|
|
}
|
|
|
|
/*
|
|
* Function: fill_payload()
|
|
*
|
|
* Description:
|
|
* This function fills the payload
|
|
*
|
|
* Argument:
|
|
* payload_p: pointer to data of payload
|
|
* size: payload size
|
|
*
|
|
* Return value:
|
|
* None
|
|
*/
|
|
void fill_payload(unsigned char *payload_p, size_t size)
|
|
{
|
|
size_t idx;
|
|
|
|
for (idx = 0; idx < size; idx++)
|
|
*(payload_p + idx) = idx % 0x100;
|
|
}
|
|
|
|
/*
|
|
* Function: rand_within()
|
|
*
|
|
* Description:
|
|
* This function returns a presudo-random integer within specified range
|
|
*
|
|
* Argument:
|
|
* first: Fisrt value of the range. If negative, assumed 0
|
|
* last : Last value of the range. If bigger than RAND_MAX, assumed RAND_MAX
|
|
*
|
|
* Return value:
|
|
* integer value between first to last
|
|
*/
|
|
int rand_within(int first, int last)
|
|
{
|
|
unsigned int num;
|
|
int rand_val;
|
|
|
|
first = first < 0 ? 0 : first;
|
|
last = RAND_MAX < (unsigned int)last ? RAND_MAX : last;
|
|
|
|
num = last - first + 1U;
|
|
rand_val = rand() / ((RAND_MAX + 1U) / num) + first;
|
|
|
|
return rand_val;
|
|
}
|
|
|
|
/*
|
|
* Function: bit_change_seed
|
|
*
|
|
* Description:
|
|
* This function creates a seed to change 1 bit at random position
|
|
*
|
|
* Argument:
|
|
* bitsize : bit size of data whose bit would be changed
|
|
* oversize: This value controls whether a bit is changed or not
|
|
*
|
|
* Return value:
|
|
* seed of the bit for change.
|
|
*/
|
|
u_int32_t bit_change_seed(size_t bitsize, size_t oversize)
|
|
{
|
|
int rand_val;
|
|
u_int32_t seed;
|
|
rand_val = rand() / ((RAND_MAX + 1U) / (bitsize + oversize));
|
|
|
|
seed = (rand_val < bitsize) ? (0x00000001 << rand_val) : 0;
|
|
|
|
if (debug)
|
|
fprintf(stderr, "Bit seed is %08x\n", seed);
|
|
|
|
return seed;
|
|
}
|
|
|
|
/*
|
|
* Function: eth_pton()
|
|
*
|
|
* Description:
|
|
* This function convert a string to struct sockaddr_ll (Ethernet)
|
|
* Note) The ifindex is set to `any'.
|
|
*
|
|
* Argument:
|
|
* af : AF_INET or AF_INET6
|
|
* str: Pointer to a string which represents MAC address
|
|
* ll : pointer to struct sockaddr_ll
|
|
*
|
|
* Return value:
|
|
* 0 : Success
|
|
* 1 : Fail
|
|
*/
|
|
int eth_pton(int af, const char *str, struct sockaddr_ll *ll)
|
|
{
|
|
size_t idx;
|
|
unsigned char *addr_p;
|
|
unsigned int val[ETH_ALEN];
|
|
|
|
ll->sll_family = AF_PACKET; /* Always AF_PACKET */
|
|
if (af == AF_INET)
|
|
ll->sll_protocol = htons(ETH_P_IP); /* IPv4 */
|
|
else
|
|
ll->sll_protocol = htons(ETH_P_IPV6); /* IPv6 */
|
|
ll->sll_ifindex = 0; /* any interface */
|
|
ll->sll_hatype = ARPHRD_ETHER; /* Header type */
|
|
ll->sll_pkttype = PACKET_OTHERHOST; /* Packet type */
|
|
ll->sll_halen = ETH_ALEN; /* Length of address */
|
|
|
|
/* Physical layer address */
|
|
if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x", &val[0], &val[1],
|
|
&val[2], &val[3], &val[4], &val[5]) != ETH_ALEN) {
|
|
fprintf(stderr, "%s is not a valid MAC address", str);
|
|
return 1;
|
|
}
|
|
|
|
addr_p = (unsigned char *)ll->sll_addr;
|
|
for (idx = 0; idx < ETH_ALEN; idx++)
|
|
addr_p[idx] = val[idx];
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Function: get_ifinfo()
|
|
*
|
|
* Description:
|
|
* This function gets the interface information with ioctl()
|
|
*
|
|
* Argument:
|
|
* ans : ifreq structure to store the information
|
|
* sock_fd : socket file descriptor
|
|
* ifname : interface name
|
|
* query : ioctl request value
|
|
*
|
|
* Return value:
|
|
* None
|
|
*
|
|
*/
|
|
void get_ifinfo(struct ifreq *ans, int sock_fd, const char *ifname, int query)
|
|
{
|
|
memset(ans, '\0', sizeof(struct ifreq));
|
|
strncpy(ans->ifr_name, ifname, (IFNAMSIZ - 1));
|
|
|
|
if (ioctl(sock_fd, query, ans) < 0)
|
|
fatal_error("ioctl()");
|
|
}
|
|
|
|
/*
|
|
* Function: strtotimespec()
|
|
*
|
|
* Description:
|
|
* This function converts a string to timespec structure
|
|
*
|
|
* Argument:
|
|
* str : nano second value in character representation
|
|
* ts_p : pointer to a timespec structure
|
|
*
|
|
* Return value:
|
|
* 0: Success
|
|
* 1: Fail
|
|
*/
|
|
int strtotimespec(const char *str, struct timespec *ts_p)
|
|
{
|
|
size_t len;
|
|
char *sec_str;
|
|
unsigned long sec = 0;
|
|
unsigned long nsec = 0;
|
|
|
|
len = strlen(str);
|
|
if (len > 9) { /* Check the specified value is bigger than 999999999 */
|
|
sec_str = calloc((len - 9 + 1), sizeof(char));
|
|
strncpy(sec_str, str, len - 9);
|
|
sec = strtoul(sec_str, NULL, 0);
|
|
if (sec > 0x7fffffff)
|
|
return 1;
|
|
free(sec_str);
|
|
nsec = strtoul(str + len - 9, NULL, 0);
|
|
} else {
|
|
nsec = strtoul(str, NULL, 0);
|
|
}
|
|
|
|
ts_p->tv_sec = sec;
|
|
ts_p->tv_nsec = nsec;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Function: get_a_lla_byifindex()
|
|
*
|
|
* Description:
|
|
* This function gets one of the link-local addresses which is specified
|
|
* by interface index
|
|
*
|
|
* Argument:
|
|
* lla_p : pointer to a sockaddr_in6 structure which stores the lla
|
|
* ifindex : index of the interface
|
|
*
|
|
* Return value:
|
|
* 0: Success
|
|
* 1: Fail
|
|
*/
|
|
int get_a_lla_byifindex(struct sockaddr_in6 *lla_p, int ifindex)
|
|
{
|
|
FILE *fp;
|
|
int ret;
|
|
unsigned int oct[16];
|
|
int ifidx, prefixlen, scope;
|
|
char line[PROC_IFINET6_FILE_LINELENGTH];
|
|
int pos;
|
|
|
|
if ((fp = fopen(PROC_IFINET6_FILE, "r")) == NULL) {
|
|
fprintf(stderr, "Faile to open %s\n", PROC_IFINET6_FILE);
|
|
return 1;
|
|
}
|
|
|
|
while (fgets(line, PROC_IFINET6_FILE_LINELENGTH, fp) != NULL) {
|
|
ret = sscanf(line,
|
|
"%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x %x %x %x",
|
|
&oct[0], &oct[1], &oct[2], &oct[3],
|
|
&oct[4], &oct[5], &oct[6], &oct[7],
|
|
&oct[8], &oct[9], &oct[10], &oct[11],
|
|
&oct[12], &oct[13], &oct[14], &oct[15],
|
|
&ifidx, &prefixlen, &scope);
|
|
|
|
if (ret == EOF)
|
|
fatal_error("scanf()");
|
|
else if (ret != 19)
|
|
fatal_error
|
|
("The number of input item is less than the expected");
|
|
|
|
if (ifidx != ifindex)
|
|
continue;
|
|
|
|
if (prefixlen != 64)
|
|
continue;
|
|
|
|
if (scope != PROC_IFINET6_LINKLOCAL)
|
|
continue;
|
|
|
|
/* Find a link-local address */
|
|
lla_p->sin6_family = AF_INET6;
|
|
lla_p->sin6_port = 0;
|
|
lla_p->sin6_flowinfo = 0;
|
|
lla_p->sin6_scope_id = ifindex;
|
|
|
|
for (pos = 0; pos < 16; pos++)
|
|
lla_p->sin6_addr.s6_addr[pos] = oct[pos];
|
|
|
|
return 0;
|
|
}
|
|
|
|
fprintf(stderr, "No link-local address is found.\n");
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Function: get_maddrinfo()
|
|
*
|
|
* Description:
|
|
* This function translates multicast address informantion into the addrinfo
|
|
* structure
|
|
*
|
|
* Argument:
|
|
* family: protocol family
|
|
* maddr: multicast address in character string
|
|
* portnum: port number in character string
|
|
*
|
|
* Return value:
|
|
* pointer to the addrinfo which stores the multicast address information
|
|
*/
|
|
struct addrinfo *get_maddrinfo(sa_family_t family, const char *maddr,
|
|
const char *portnum)
|
|
{
|
|
struct addrinfo hints; /* hints for getaddrinfo() */
|
|
struct addrinfo *res; /* pointer to addrinfo structure */
|
|
int err; /* return value of getaddrinfo */
|
|
|
|
memset(&hints, '\0', sizeof(struct addrinfo));
|
|
hints.ai_family = family;
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
hints.ai_protocol = IPPROTO_UDP;
|
|
hints.ai_flags |= AI_NUMERICHOST;
|
|
|
|
err = getaddrinfo(maddr, portnum, &hints, &res);
|
|
if (err) {
|
|
fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(err));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
if (res->ai_next) {
|
|
fprintf(stderr, "getaddrinfo(): multiple address is found.");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
* Function: create_group_info()
|
|
*
|
|
* Description:
|
|
* This function create a group information to join the group
|
|
* This function calls malloc to store the information
|
|
*
|
|
* Argument:
|
|
* ifindex: interface index
|
|
* mainfo_p: pointer to addrinfo structure for multicast address
|
|
*
|
|
* Return value:
|
|
* pointer to allocated group_filter structure
|
|
*/
|
|
struct group_req *create_group_info(uint32_t ifindex, struct addrinfo *mainfo_p)
|
|
{
|
|
struct group_req *greq;
|
|
|
|
/* allocate memory for group_filter */
|
|
greq = (struct group_req *)calloc(1, sizeof(struct group_req));
|
|
if (greq == NULL)
|
|
fatal_error("calloc()");
|
|
|
|
/* substitute informations */
|
|
greq->gr_interface = ifindex;
|
|
memcpy(&greq->gr_group, mainfo_p->ai_addr, mainfo_p->ai_addrlen);
|
|
|
|
return greq;
|
|
}
|
|
|
|
/*
|
|
* Function: create_source_filter()
|
|
*
|
|
* Description:
|
|
* This function create a source filter.
|
|
* This function calls malloc to store the source filter.
|
|
*
|
|
* Argument:
|
|
* ifindex: interface index
|
|
* mainfo_p: pointer to addrinfo structure for multicast address
|
|
* fmode: filter mode
|
|
* saddrs: comma separated array of the source addresses
|
|
*
|
|
* Return value:
|
|
* pointer to allocated group_filter structure
|
|
*/
|
|
struct group_filter *create_source_filter(uint32_t ifindex,
|
|
struct addrinfo *mainfo_p,
|
|
uint32_t fmode, char *saddrs)
|
|
{
|
|
struct group_filter *gsf; /* pointer to group_filter structure */
|
|
uint32_t numsrc; /* number of source address */
|
|
struct addrinfo hints; /* hints for getaddrinfo() */
|
|
struct addrinfo *res; /* pointer to addrinfo structure */
|
|
int err; /* return value of getaddrinfo */
|
|
uint32_t idx;
|
|
char *sp, *ep;
|
|
|
|
/* calculate the number of source address */
|
|
numsrc = 1;
|
|
for (sp = saddrs; *sp != '\0'; sp++)
|
|
if (*sp == ',')
|
|
numsrc++;
|
|
|
|
if (debug)
|
|
fprintf(stderr, "number of source address is %u\n", numsrc);
|
|
|
|
/* allocate memory for group_filter */
|
|
gsf = (struct group_filter *)calloc(1, GROUP_FILTER_SIZE(numsrc));
|
|
if (gsf == NULL)
|
|
fatal_error("calloc()");
|
|
|
|
/* substitute interface index, multicast address, filter mode */
|
|
gsf->gf_interface = ifindex;
|
|
memcpy(&gsf->gf_group, mainfo_p->ai_addr, mainfo_p->ai_addrlen);
|
|
gsf->gf_fmode = fmode;
|
|
gsf->gf_numsrc = numsrc;
|
|
|
|
/* extract source address aray and substitute the addersses */
|
|
memset(&hints, '\0', sizeof(struct addrinfo));
|
|
hints.ai_family = mainfo_p->ai_family;
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
hints.ai_protocol = IPPROTO_UDP;
|
|
hints.ai_flags |= AI_NUMERICHOST;
|
|
|
|
/* extract source address aray and substitute the addersses */
|
|
memset(&hints, '\0', sizeof(struct addrinfo));
|
|
hints.ai_family = mainfo_p->ai_family;
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
hints.ai_protocol = IPPROTO_UDP;
|
|
hints.ai_flags |= AI_NUMERICHOST;
|
|
|
|
sp = saddrs;
|
|
for (idx = 0; idx < numsrc; idx++) {
|
|
ep = strchr(sp, ',');
|
|
if (ep != NULL)
|
|
*ep = '\0';
|
|
if (debug)
|
|
fprintf(stderr, "source address[%u]: %s\n", idx, sp);
|
|
|
|
err = getaddrinfo(sp, NULL, &hints, &res);
|
|
if (err) {
|
|
fprintf(stderr, "getaddrinfo(): %s\n",
|
|
gai_strerror(err));
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
memcpy(&gsf->gf_slist[idx], res->ai_addr, res->ai_addrlen);
|
|
freeaddrinfo(res);
|
|
sp = ep + 1;
|
|
}
|
|
|
|
return gsf;
|
|
}
|