1 /******************************************************************************/ 2 /* */ 3 /* Copyright (c) International Business Machines Corp., 2005, 2006 */ 4 /* */ 5 /* This program is free software; you can redistribute it and/or modify */ 6 /* it under the terms of the GNU General Public License as published by */ 7 /* the Free Software Foundation; either version 2 of the License, or */ 8 /* (at your option) any later version. */ 9 /* */ 10 /* This program is distributed in the hope that it will be useful, */ 11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ 13 /* the GNU General Public License for more details. */ 14 /* */ 15 /* You should have received a copy of the GNU General Public License */ 16 /* along with this program; if not, write to the Free Software */ 17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 18 /* */ 19 /******************************************************************************/ 20 21 /* 22 * File: 23 * ns-common.c 24 * 25 * Description: 26 * Common functions and variables in the ns-tools 27 * 28 * Author: 29 * Mitsuru Chinen <mitch (at) jp.ibm.com> 30 * 31 * History: 32 * Oct 19 2005 - Created (Mitsuru Chinen) 33 * May 1 2006 - Added functions for broken_ip, route, multicast tests 34 *---------------------------------------------------------------------------*/ 35 36 /* 37 * Fixed values 38 */ 39 #define PROC_RMEM_MAX "/proc/sys/net/core/rmem_max" 40 #define PROC_WMEM_MAX "/proc/sys/net/core/wmem_max" 41 42 /* 43 * Standard Header Files 44 */ 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <sys/ioctl.h> 49 #include <sys/types.h> 50 #include <sys/socket.h> 51 #include <net/ethernet.h> 52 #include <net/if.h> 53 #include <net/if_arp.h> 54 55 #include "ns-mcast.h" 56 #define NS_COMMON 1 57 #include "ns-traffic.h" 58 59 /* 60 * Function: fatal_error() 61 * 62 * Description: 63 * Output an error message then exit the program with EXIT_FAILURE 64 * 65 * Argument: 66 * errmsg: message printed by perror() 67 * 68 * Return value: 69 * This function does not return. 70 */ 71 void fatal_error(char *errmsg) 72 { 73 perror(errmsg); 74 exit(EXIT_FAILURE); 75 } 76 77 /* 78 * Function: maximize_sockbuf() 79 * 80 * Descripton: 81 * This function maximize the send and receive buffer size of a socket 82 * 83 * Argument: 84 * sd: target socket descriptor 85 * 86 * Return value: 87 * None 88 */ 89 void maximize_sockbuf(int sd) 90 { 91 size_t idx; 92 int level[] = { SO_RCVBUF, SO_SNDBUF }; 93 char *procfile[] = { PROC_RMEM_MAX, PROC_WMEM_MAX }; 94 char *bufname[] = { "rcvbuf", "sndbuf" }; 95 96 for (idx = 0; idx < (sizeof(level) / sizeof(int)); idx++) { 97 FILE *fp; /* File pointer to a proc file */ 98 int bufsiz; /* buffer size of socket */ 99 unsigned int optlen; /* size of sd option parameter */ 100 101 if ((fp = fopen(procfile[idx], "r")) == NULL) { 102 fprintf(stderr, "Failed to open %s\n", procfile[idx]); 103 fatal_error("fopen()"); 104 } 105 if ((fscanf(fp, "%d", &bufsiz)) != 1) { 106 fprintf(stderr, "Failed to read from %s\n", 107 procfile[idx]); 108 fatal_error("fscanf()"); 109 } 110 if (setsockopt 111 (sd, SOL_SOCKET, level[idx], &bufsiz, sizeof(int))) { 112 fatal_error("setsockopt()"); 113 } 114 if (fclose(fp)) { 115 fprintf(stderr, "Failed to close to %s\n", 116 procfile[idx]); 117 fatal_error("fopen()"); 118 } 119 120 if (debug) { 121 optlen = sizeof(bufsiz); 122 if (getsockopt 123 (sd, SOL_SOCKET, level[idx], &bufsiz, 124 &optlen) < 0) { 125 fatal_error("getsockopt()"); 126 } 127 fprintf(stderr, "socket %s size is %d\n", bufname[idx], 128 bufsiz); 129 } 130 } 131 } 132 133 /* 134 * Function: calc_checksum() 135 * 136 * Description: 137 * This function calculate the checksum of IPv4 or ICMP 138 * 139 * Argument: 140 * data: pointer to target data for checksum 141 * size: target data size 142 * 143 * Return value: 144 * None 145 */ 146 u_int16_t calc_checksum(u_int16_t * data, size_t size) 147 { 148 u_int32_t sum; 149 u_int16_t *pos; 150 size_t rest; 151 152 sum = 0; 153 pos = data; 154 for (rest = size; rest > 1; rest -= 2) 155 sum += *(pos++); 156 157 if (rest > 0) 158 sum += (*pos) & 0xff00; 159 160 sum = (sum & 0xffff) + (sum >> 16); 161 sum = (sum & 0xffff) + (sum >> 16); 162 sum = ~sum; 163 164 return sum; 165 } 166 167 /* 168 * Function: fill_payload() 169 * 170 * Description: 171 * This function fills the payload 172 * 173 * Argument: 174 * payload_p: pointer to data of payload 175 * size: payload size 176 * 177 * Return value: 178 * None 179 */ 180 void fill_payload(unsigned char *payload_p, size_t size) 181 { 182 size_t idx; 183 184 for (idx = 0; idx < size; idx++) 185 *(payload_p + idx) = idx % 0x100; 186 } 187 188 /* 189 * Function: rand_within() 190 * 191 * Description: 192 * This function returns a presudo-random integer within specified range 193 * 194 * Argument: 195 * first: Fisrt value of the range. If negative, assumed 0 196 * last : Last value of the range. If bigger than RAND_MAX, assumed RAND_MAX 197 * 198 * Return value: 199 * integer value between first to last 200 */ 201 int rand_within(int first, int last) 202 { 203 unsigned int num; 204 int rand_val; 205 206 first = first < 0 ? 0 : first; 207 last = RAND_MAX < (unsigned int)last ? RAND_MAX : last; 208 209 num = last - first + 1U; 210 rand_val = rand() / ((RAND_MAX + 1U) / num) + first; 211 212 return rand_val; 213 } 214 215 /* 216 * Function: bit_change_seed 217 * 218 * Description: 219 * This function creates a seed to change 1 bit at random position 220 * 221 * Argument: 222 * bitsize : bit size of data whose bit would be changed 223 * oversize: This value controls whether a bit is changed or not 224 * 225 * Return value: 226 * seed of the bit for change. 227 */ 228 u_int32_t bit_change_seed(size_t bitsize, size_t oversize) 229 { 230 int rand_val; 231 u_int32_t seed; 232 rand_val = rand() / ((RAND_MAX + 1U) / (bitsize + oversize)); 233 234 seed = (rand_val < bitsize) ? (0x00000001 << rand_val) : 0; 235 236 if (debug) 237 fprintf(stderr, "Bit seed is %08x\n", seed); 238 239 return seed; 240 } 241 242 /* 243 * Function: eth_pton() 244 * 245 * Description: 246 * This function convert a string to struct sockaddr_ll (Ethernet) 247 * Note) The ifindex is set to `any'. 248 * 249 * Argument: 250 * af : AF_INET or AF_INET6 251 * str: Pointer to a string which represents MAC address 252 * ll : pointer to struct sockaddr_ll 253 * 254 * Return value: 255 * 0 : Success 256 * 1 : Fail 257 */ 258 int eth_pton(int af, const char *str, struct sockaddr_ll *ll) 259 { 260 size_t idx; 261 unsigned char *addr_p; 262 unsigned int val[ETH_ALEN]; 263 264 ll->sll_family = AF_PACKET; /* Always AF_PACKET */ 265 if (af == AF_INET) 266 ll->sll_protocol = htons(ETH_P_IP); /* IPv4 */ 267 else 268 ll->sll_protocol = htons(ETH_P_IPV6); /* IPv6 */ 269 ll->sll_ifindex = 0; /* any interface */ 270 ll->sll_hatype = ARPHRD_ETHER; /* Header type */ 271 ll->sll_pkttype = PACKET_OTHERHOST; /* Packet type */ 272 ll->sll_halen = ETH_ALEN; /* Length of address */ 273 274 /* Physical layer address */ 275 if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x", &val[0], &val[1], 276 &val[2], &val[3], &val[4], &val[5]) != ETH_ALEN) { 277 fprintf(stderr, "%s is not a valid MAC address", str); 278 return 1; 279 } 280 281 addr_p = (unsigned char *)ll->sll_addr; 282 for (idx = 0; idx < ETH_ALEN; idx++) 283 addr_p[idx] = val[idx]; 284 285 return 0; 286 } 287 288 /* 289 * Function: get_ifinfo() 290 * 291 * Description: 292 * This function gets the interface information with ioctl() 293 * 294 * Argument: 295 * ans : ifreq structure to store the information 296 * sock_fd : socket file descriptor 297 * ifname : interface name 298 * query : ioctl request value 299 * 300 * Return value: 301 * None 302 * 303 */ 304 void get_ifinfo(struct ifreq *ans, int sock_fd, const char *ifname, int query) 305 { 306 memset(ans, '\0', sizeof(struct ifreq)); 307 strncpy(ans->ifr_name, ifname, (IFNAMSIZ - 1)); 308 309 if (ioctl(sock_fd, query, ans) < 0) 310 fatal_error("ioctl()"); 311 } 312 313 /* 314 * Function: strtotimespec() 315 * 316 * Description: 317 * This function converts a string to timespec structure 318 * 319 * Argument: 320 * str : nano second value in character representation 321 * ts_p : pointer to a timespec structure 322 * 323 * Return value: 324 * 0: Success 325 * 1: Fail 326 */ 327 int strtotimespec(const char *str, struct timespec *ts_p) 328 { 329 size_t len; 330 char *sec_str; 331 unsigned long sec = 0; 332 unsigned long nsec = 0; 333 334 len = strlen(str); 335 if (len > 9) { /* Check the specified value is bigger than 999999999 */ 336 sec_str = calloc((len - 9 + 1), sizeof(char)); 337 strncpy(sec_str, str, len - 9); 338 sec = strtoul(sec_str, NULL, 0); 339 if (sec > 0x7fffffff) 340 return 1; 341 free(sec_str); 342 nsec = strtoul(str + len - 9, NULL, 0); 343 } else { 344 nsec = strtoul(str, NULL, 0); 345 } 346 347 ts_p->tv_sec = sec; 348 ts_p->tv_nsec = nsec; 349 350 return 0; 351 } 352 353 /* 354 * Function: get_a_lla_byifindex() 355 * 356 * Description: 357 * This function gets one of the link-local addresses which is specified 358 * by interface index 359 * 360 * Argument: 361 * lla_p : pointer to a sockaddr_in6 sturcture which stores the lla 362 * ifindex : index of the interface 363 * 364 * Return value: 365 * 0: Success 366 * 1: Fail 367 */ 368 int get_a_lla_byifindex(struct sockaddr_in6 *lla_p, int ifindex) 369 { 370 FILE *fp; 371 int ret; 372 unsigned int oct[16]; 373 int ifidx, prefixlen, scope; 374 char line[PROC_IFINET6_FILE_LINELENGTH]; 375 int pos; 376 377 if ((fp = fopen(PROC_IFINET6_FILE, "r")) == NULL) { 378 fprintf(stderr, "Faile to open %s\n", PROC_IFINET6_FILE); 379 return 1; 380 } 381 382 while (fgets(line, PROC_IFINET6_FILE_LINELENGTH, fp) != NULL) { 383 ret = sscanf(line, 384 "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x %x %x %x", 385 &oct[0], &oct[1], &oct[2], &oct[3], 386 &oct[4], &oct[5], &oct[6], &oct[7], 387 &oct[8], &oct[9], &oct[10], &oct[11], 388 &oct[12], &oct[13], &oct[14], &oct[15], 389 &ifidx, &prefixlen, &scope); 390 391 if (ret == EOF) 392 fatal_error("scanf()"); 393 else if (ret != 19) 394 fatal_error 395 ("The number of input item is less than the expected"); 396 397 if (ifidx != ifindex) 398 continue; 399 400 if (prefixlen != 64) 401 continue; 402 403 if (scope != PROC_IFINET6_LINKLOCAL) 404 continue; 405 406 /* Find a link-local address */ 407 lla_p->sin6_family = AF_INET6; 408 lla_p->sin6_port = 0; 409 lla_p->sin6_flowinfo = 0; 410 lla_p->sin6_scope_id = ifindex; 411 412 for (pos = 0; pos < 16; pos++) 413 lla_p->sin6_addr.s6_addr[pos] = oct[pos]; 414 415 return 0; 416 } 417 418 fprintf(stderr, "No link-local address is found.\n"); 419 return 1; 420 } 421 422 /* 423 * Function: get_maddrinfo() 424 * 425 * Description: 426 * This function translates multicast address informantion into the addrinfo 427 * structure 428 * 429 * Argument: 430 * family: protocol family 431 * maddr: multicast address in character string 432 * portnum: port number in character string 433 * 434 * Return value: 435 * pointer to the addrinfo which stores the multicast address information 436 */ 437 struct addrinfo *get_maddrinfo(sa_family_t family, const char *maddr, 438 const char *portnum) 439 { 440 struct addrinfo hints; /* hints for getaddrinfo() */ 441 struct addrinfo *res; /* pointer to addrinfo structure */ 442 int err; /* return value of getaddrinfo */ 443 444 memset(&hints, '\0', sizeof(struct addrinfo)); 445 hints.ai_family = family; 446 hints.ai_socktype = SOCK_DGRAM; 447 hints.ai_protocol = IPPROTO_UDP; 448 hints.ai_flags |= AI_NUMERICHOST; 449 450 err = getaddrinfo(maddr, portnum, &hints, &res); 451 if (err) { 452 fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(err)); 453 exit(EXIT_FAILURE); 454 } 455 if (res->ai_next) { 456 fprintf(stderr, "getaddrinfo(): multiple address is found."); 457 exit(EXIT_FAILURE); 458 } 459 460 return res; 461 } 462 463 /* 464 * Function: create_group_info() 465 * 466 * Description: 467 * This function create a group information to join the group 468 * This function calls malloc to store the information 469 * 470 * Argument: 471 * ifindex: interface index 472 * mainfo_p: pointer to addrinfo structure for multicast address 473 * 474 * Return value: 475 * pointer to allocated group_filter structure 476 */ 477 struct group_req *create_group_info(uint32_t ifindex, struct addrinfo *mainfo_p) 478 { 479 struct group_req *greq; 480 481 /* allocate memory for group_filter */ 482 greq = (struct group_req *)calloc(1, sizeof(struct group_req)); 483 if (greq == NULL) 484 fatal_error("calloc()"); 485 486 /* substitute informations */ 487 greq->gr_interface = ifindex; 488 memcpy(&greq->gr_group, mainfo_p->ai_addr, mainfo_p->ai_addrlen); 489 490 return greq; 491 } 492 493 /* 494 * Function: create_source_filter() 495 * 496 * Description: 497 * This function create a source filter. 498 * This function calls malloc to store the source filter. 499 * 500 * Argument: 501 * ifindex: interface index 502 * mainfo_p: pointer to addrinfo structure for multicast address 503 * fmode: filter mode 504 * saddrs: comma separated array of the source addresses 505 * 506 * Return value: 507 * pointer to allocated group_filter structure 508 */ 509 struct group_filter *create_source_filter(uint32_t ifindex, 510 struct addrinfo *mainfo_p, 511 uint32_t fmode, char *saddrs) 512 { 513 struct group_filter *gsf; /* pointer to group_filter structure */ 514 uint32_t numsrc; /* number of source address */ 515 struct addrinfo hints; /* hints for getaddrinfo() */ 516 struct addrinfo *res; /* pointer to addrinfo structure */ 517 int err; /* return value of getaddrinfo */ 518 uint32_t idx; 519 char *sp, *ep; 520 521 /* calculate the number of source address */ 522 numsrc = 1; 523 for (sp = saddrs; *sp != '\0'; sp++) 524 if (*sp == ',') 525 numsrc++; 526 527 if (debug) 528 fprintf(stderr, "number of source address is %u\n", numsrc); 529 530 /* allocate memory for group_filter */ 531 gsf = (struct group_filter *)calloc(1, GROUP_FILTER_SIZE(numsrc)); 532 if (gsf == NULL) 533 fatal_error("calloc()"); 534 535 /* substitute interface index, multicast address, filter mode */ 536 gsf->gf_interface = ifindex; 537 memcpy(&gsf->gf_group, mainfo_p->ai_addr, mainfo_p->ai_addrlen); 538 gsf->gf_fmode = fmode; 539 gsf->gf_numsrc = numsrc; 540 541 /* extract source address aray and substitute the addersses */ 542 memset(&hints, '\0', sizeof(struct addrinfo)); 543 hints.ai_family = mainfo_p->ai_family; 544 hints.ai_socktype = SOCK_DGRAM; 545 hints.ai_protocol = IPPROTO_UDP; 546 hints.ai_flags |= AI_NUMERICHOST; 547 548 /* extract source address aray and substitute the addersses */ 549 memset(&hints, '\0', sizeof(struct addrinfo)); 550 hints.ai_family = mainfo_p->ai_family; 551 hints.ai_socktype = SOCK_DGRAM; 552 hints.ai_protocol = IPPROTO_UDP; 553 hints.ai_flags |= AI_NUMERICHOST; 554 555 sp = saddrs; 556 for (idx = 0; idx < numsrc; idx++) { 557 ep = strchr(sp, ','); 558 if (ep != NULL) 559 *ep = '\0'; 560 if (debug) 561 fprintf(stderr, "source address[%u]: %s\n", idx, sp); 562 563 err = getaddrinfo(sp, NULL, &hints, &res); 564 if (err) { 565 fprintf(stderr, "getaddrinfo(): %s\n", 566 gai_strerror(err)); 567 exit(EXIT_FAILURE); 568 } 569 570 memcpy(&gsf->gf_slist[idx], res->ai_addr, res->ai_addrlen); 571 freeaddrinfo(res); 572 sp = ep + 1; 573 } 574 575 return gsf; 576 } 577