Advertisement
sedrector

Untitled

Apr 9th, 2020
1,422
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 17.33 KB | None | 0 0
  1. /*  Copyright (C) 2011-2015  P.D. Buchan (pdbuchan@yahoo.com)
  2.  
  3.     This program is free software: you can redistribute it and/or modify
  4.     it under the terms of the GNU General Public License as published by
  5.     the Free Software Foundation, either version 3 of the License, or
  6.     (at your option) any later version.
  7.  
  8.     This program is distributed in the hope that it will be useful,
  9.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.     GNU General Public License for more details.
  12.  
  13.     You should have received a copy of the GNU General Public License
  14.     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  15. */
  16.  
  17. // Send an IPv4 ICMP echo request packet via raw socket at the link layer (ethernet frame),
  18. // and receive echo reply packet (i.e., ping). Includes some ICMP data.
  19. // Need to have destination MAC address.
  20.  
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <unistd.h>           // close()
  24. #include <string.h>           // strcpy, memset(), and memcpy()
  25.  
  26. #include <netdb.h>            // struct addrinfo
  27. #include <sys/types.h>        // needed for socket(), uint8_t, uint16_t, uint32_t
  28. #include <sys/socket.h>       // needed for socket()
  29. #include <netinet/in.h>       // IPPROTO_ICMP, INET_ADDRSTRLEN
  30. #include <netinet/ip.h>       // struct ip and IP_MAXPACKET (which is 65535)
  31. #include <netinet/ip_icmp.h>  // struct icmp, ICMP_ECHO
  32. #include <arpa/inet.h>        // inet_pton() and inet_ntop()
  33. #include <sys/ioctl.h>        // macro ioctl is defined
  34. #include <bits/ioctls.h>      // defines values for argument "request" of ioctl.
  35. #include <net/if.h>           // struct ifreq
  36. #include <linux/if_ether.h>   // ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD
  37. #include <linux/if_packet.h>  // struct sockaddr_ll (see man 7 packet)
  38. #include <net/ethernet.h>
  39. #include <sys/time.h>         // gettimeofday()
  40.  
  41. #include <errno.h>            // errno, perror()
  42.  
  43. // Define some constants.
  44. #define ETH_HDRLEN 14  // Ethernet header length
  45. #define IP4_HDRLEN 20  // IPv4 header length
  46. #define ICMP_HDRLEN 8  // ICMP header length for echo request, excludes data
  47.  
  48. // Function prototypes
  49. uint16_t checksum (uint16_t *, int);
  50. uint16_t icmp4_checksum (struct icmp, uint8_t *, int);
  51. char *allocate_strmem (int);
  52. uint8_t *allocate_ustrmem (int);
  53. int *allocate_intmem (int);
  54.  
  55. int
  56. main (int argc, char **argv)
  57. {
  58.   int i, status, datalen, frame_length, sendsd, recvsd, bytes, *ip_flags, timeout, trycount, trylim, done;
  59.   char *interface, *target, *src_ip, *dst_ip, *rec_ip;
  60.   struct ip send_iphdr, *recv_iphdr;
  61.   struct icmp send_icmphdr, *recv_icmphdr;
  62.   uint8_t *data, *src_mac, *dst_mac, *send_ether_frame, *recv_ether_frame;
  63.   struct addrinfo hints, *res;
  64.   struct sockaddr_in *ipv4;
  65.   struct sockaddr_ll device;
  66.   struct ifreq ifr;
  67.   struct sockaddr from;
  68.   socklen_t fromlen;
  69.   struct timeval wait, t1, t2;
  70.   struct timezone tz;
  71.   double dt;
  72.   void *tmp;
  73.  
  74.   // Allocate memory for various arrays.
  75.   src_mac = allocate_ustrmem (6);
  76.   dst_mac = allocate_ustrmem (6);
  77.   data = allocate_ustrmem (IP_MAXPACKET);
  78.   send_ether_frame = allocate_ustrmem (IP_MAXPACKET);
  79.   recv_ether_frame = allocate_ustrmem (IP_MAXPACKET);
  80.   interface = allocate_strmem (40);
  81.   target = allocate_strmem (40);
  82.   src_ip = allocate_strmem (INET_ADDRSTRLEN);
  83.   dst_ip = allocate_strmem (INET_ADDRSTRLEN);
  84.   rec_ip = allocate_strmem (INET_ADDRSTRLEN);
  85.   ip_flags = allocate_intmem (4);
  86.  
  87.   // Interface to send packet through.
  88.   strcpy (interface, "eth0");
  89.  
  90.   // Submit request for a socket descriptor to look up interface.
  91.   // We'll use it to send packets as well, so we leave it open.
  92.   if ((sendsd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {
  93.     perror ("socket() failed to get socket descriptor for using ioctl() ");
  94.     exit (EXIT_FAILURE);
  95.   }
  96.  
  97.   // Use ioctl() to look up interface name and get its MAC address.
  98.   memset (&ifr, 0, sizeof (ifr));
  99.   snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
  100.   if (ioctl (sendsd, SIOCGIFHWADDR, &ifr) < 0) {
  101.     perror ("ioctl() failed to get source MAC address ");
  102.     return (EXIT_FAILURE);
  103.   }
  104.  
  105.   // Copy source MAC address.
  106.   memcpy (src_mac, ifr.ifr_hwaddr.sa_data, 6);
  107.  
  108.   // Report source MAC address to stdout.
  109.   printf ("MAC address for interface %s is ", interface);
  110.   for (i=0; i<5; i++) {
  111.     printf ("%02x:", src_mac[i]);
  112.   }
  113.   printf ("%02x\n", src_mac[5]);
  114.  
  115.   // Find interface index from interface name and store index in
  116.   // struct sockaddr_ll device, which will be used as an argument of sendto().
  117.   memset (&device, 0, sizeof (device));
  118.   if ((device.sll_ifindex = if_nametoindex (interface)) == 0) {
  119.     perror ("if_nametoindex() failed to obtain interface index ");
  120.     exit (EXIT_FAILURE);
  121.   }
  122.   printf ("Index for interface %s is %i\n", interface, device.sll_ifindex);
  123.  
  124.   // Set destination MAC address: you need to fill these out
  125.   dst_mac[0] = 0xff;
  126.   dst_mac[1] = 0xff;
  127.   dst_mac[2] = 0xff;
  128.   dst_mac[3] = 0xff;
  129.   dst_mac[4] = 0xff;
  130.   dst_mac[5] = 0xff;
  131.  
  132.   // Source IPv4 address: you need to fill this out
  133.   strcpy (src_ip, "192.168.1.132");
  134.  
  135.   // Destination URL or IPv4 address: you need to fill this out
  136.   strcpy (target, "www.google.com");
  137.  
  138.   // Fill out hints for getaddrinfo().
  139.   memset (&hints, 0, sizeof (struct addrinfo));
  140.   hints.ai_family = AF_INET;
  141.   hints.ai_socktype = SOCK_STREAM;
  142.   hints.ai_flags = hints.ai_flags | AI_CANONNAME;
  143.  
  144.   // Resolve target using getaddrinfo().
  145.   if ((status = getaddrinfo (target, NULL, &hints, &res)) != 0) {
  146.     fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (status));
  147.     exit (EXIT_FAILURE);
  148.   }
  149.   ipv4 = (struct sockaddr_in *) res->ai_addr;
  150.   tmp = &(ipv4->sin_addr);
  151.   if (inet_ntop (AF_INET, tmp, dst_ip, INET_ADDRSTRLEN) == NULL) {
  152.     status = errno;
  153.     fprintf (stderr, "inet_ntop() failed.\nError message: %s", strerror (status));
  154.     exit (EXIT_FAILURE);
  155.   }
  156.   freeaddrinfo (res);
  157.  
  158.   // Fill out sockaddr_ll.
  159.   device.sll_family = AF_PACKET;
  160.   memcpy (device.sll_addr, src_mac, 6);
  161.   device.sll_halen = 6;
  162.  
  163.   // ICMP data
  164.   datalen = 4;
  165.   data[0] = 'T';
  166.   data[1] = 'e';
  167.   data[2] = 's';
  168.   data[3] = 't';
  169.  
  170.   // IPv4 header
  171.  
  172.   // IPv4 header length (4 bits): Number of 32-bit words in header = 5
  173.   send_iphdr.ip_hl = IP4_HDRLEN / sizeof (uint32_t);
  174.  
  175.   // Internet Protocol version (4 bits): IPv4
  176.   send_iphdr.ip_v = 4;
  177.  
  178.   // Type of service (8 bits)
  179.   send_iphdr.ip_tos = 0;
  180.  
  181.   // Total length of datagram (16 bits): IP header + ICMP header + ICMP data
  182.   send_iphdr.ip_len = htons (IP4_HDRLEN + ICMP_HDRLEN + datalen);
  183.  
  184.   // ID sequence number (16 bits): unused, since single datagram
  185.   send_iphdr.ip_id = htons (0);
  186.  
  187.   // Flags, and Fragmentation offset (3, 13 bits): 0 since single datagram
  188.  
  189.   // Zero (1 bit)
  190.   ip_flags[0] = 0;
  191.  
  192.   // Do not fragment flag (1 bit)
  193.   ip_flags[1] = 0;
  194.  
  195.   // More fragments following flag (1 bit)
  196.   ip_flags[2] = 0;
  197.  
  198.   // Fragmentation offset (13 bits)
  199.   ip_flags[3] = 0;
  200.  
  201.   send_iphdr.ip_off = htons ((ip_flags[0] << 15)
  202.                       + (ip_flags[1] << 14)
  203.                       + (ip_flags[2] << 13)
  204.                       +  ip_flags[3]);
  205.  
  206.   // Time-to-Live (8 bits): default to maximum value
  207.   send_iphdr.ip_ttl = 255;
  208.  
  209.   // Transport layer protocol (8 bits): 1 for ICMP
  210.   send_iphdr.ip_p = IPPROTO_ICMP;
  211.  
  212.   // Source IPv4 address (32 bits)
  213.   if ((status = inet_pton (AF_INET, src_ip, &(send_iphdr.ip_src))) != 1) {
  214.     fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
  215.     exit (EXIT_FAILURE);
  216.   }
  217.  
  218.   // Destination IPv4 address (32 bits)
  219.   if ((status = inet_pton (AF_INET, dst_ip, &(send_iphdr.ip_dst))) != 1) {
  220.     fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
  221.     exit (EXIT_FAILURE);
  222.   }
  223.  
  224.   // IPv4 header checksum (16 bits): set to 0 when calculating checksum
  225.   send_iphdr.ip_sum = 0;
  226.   send_iphdr.ip_sum = checksum ((uint16_t *) &send_iphdr, IP4_HDRLEN);
  227.  
  228.   // ICMP header
  229.  
  230.   // Message Type (8 bits): echo request
  231.   send_icmphdr.icmp_type = ICMP_ECHO;
  232.  
  233.   // Message Code (8 bits): echo request
  234.   send_icmphdr.icmp_code = 0;
  235.  
  236.   // Identifier (16 bits): usually pid of sending process - pick a number
  237.   send_icmphdr.icmp_id = htons (1000);
  238.  
  239.   // Sequence Number (16 bits): starts at 0
  240.   send_icmphdr.icmp_seq = htons (0);
  241.  
  242.   // ICMP header checksum (16 bits): set to 0 when calculating checksum
  243.   send_icmphdr.icmp_cksum = icmp4_checksum (send_icmphdr, data, datalen);
  244.  
  245.   // Fill out ethernet frame header.
  246.  
  247.   // Ethernet frame length = ethernet header (MAC + MAC + ethernet type) + ethernet data (IP header + ICMP header + ICMP data)
  248.   frame_length = 6 + 6 + 2 + IP4_HDRLEN + ICMP_HDRLEN + datalen;
  249.  
  250.   // Destination and Source MAC addresses
  251.   memcpy (send_ether_frame, dst_mac, 6);
  252.   memcpy (send_ether_frame + 6, src_mac, 6);
  253.  
  254.   // Next is ethernet type code (ETH_P_IP for IPv4).
  255.   // http://www.iana.org/assignments/ethernet-numbers
  256.   send_ether_frame[12] = ETH_P_IP / 256;
  257.   send_ether_frame[13] = ETH_P_IP % 256;
  258.  
  259.   // Next is ethernet frame data (IPv4 header + ICMP header + ICMP data).
  260.  
  261.   // IPv4 header
  262.   memcpy (send_ether_frame + ETH_HDRLEN, &send_iphdr, IP4_HDRLEN);
  263.  
  264.   // ICMP header
  265.   memcpy (send_ether_frame + ETH_HDRLEN + IP4_HDRLEN, &send_icmphdr, ICMP_HDRLEN);
  266.  
  267.   // ICMP data
  268.   memcpy (send_ether_frame + ETH_HDRLEN + IP4_HDRLEN + ICMP_HDRLEN, data, datalen);
  269.  
  270.   // Submit request for a raw socket descriptor to receive packets.
  271.   if ((recvsd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {
  272.     perror ("socket() failed to obtain a receive socket descriptor ");
  273.     exit (EXIT_FAILURE);
  274.   }
  275.  
  276.   // Set maximum number of tries to ping remote host before giving up.
  277.   trylim = 3;
  278.   trycount = 0;
  279.  
  280.   // Cast recv_iphdr as pointer to IPv4 header within received ethernet frame.
  281.   recv_iphdr = (struct ip *) (recv_ether_frame + ETH_HDRLEN);
  282.  
  283.   // Cast recv_icmphdr as pointer to ICMP header within received ethernet frame.
  284.   recv_icmphdr = (struct icmp *) (recv_ether_frame + ETH_HDRLEN + IP4_HDRLEN);
  285.  
  286.   done = 0;
  287.   for (;;) {
  288.  
  289.     // SEND
  290.  
  291.     // Send ethernet frame to socket.
  292.     if ((bytes = sendto (sendsd, send_ether_frame, frame_length, 0, (struct sockaddr *) &device, sizeof (device))) <= 0) {
  293.       perror ("sendto() failed ");
  294.       exit (EXIT_FAILURE);
  295.     }
  296.  
  297.     // Start timer.
  298.     (void) gettimeofday (&t1, &tz);
  299.  
  300.     // Set time for the socket to timeout and give up waiting for a reply.
  301.     timeout = 2;
  302.     wait.tv_sec  = timeout;  
  303.     wait.tv_usec = 0;
  304.     setsockopt (recvsd, SOL_SOCKET, SO_RCVTIMEO, (char *) &wait, sizeof (struct timeval));
  305.  
  306.     // Listen for incoming ethernet frame from socket recvsd.
  307.     // We expect an ICMP ethernet frame of the form:
  308.     //     MAC (6 bytes) + MAC (6 bytes) + ethernet type (2 bytes)
  309.     //     + ethernet data (IPv4 header + ICMP header)
  310.     // Keep at it for 'timeout' seconds, or until we get an ICMP reply.
  311.  
  312.     // RECEIVE LOOP
  313.     for (;;) {
  314.  
  315.       memset (recv_ether_frame, 0, IP_MAXPACKET * sizeof (uint8_t));
  316.       memset (&from, 0, sizeof (from));
  317.       fromlen = sizeof (from);
  318.       if ((bytes = recvfrom (recvsd, recv_ether_frame, IP_MAXPACKET, 0, (struct sockaddr *) &from, &fromlen)) < 0) {
  319.  
  320.         status = errno;
  321.  
  322.         // Deal with error conditions first.
  323.         if (status == EAGAIN) {  // EAGAIN = 11
  324.           printf ("No reply within %i seconds.\n", timeout);
  325.           trycount++;
  326.           break;  // Break out of Receive loop.
  327.         } else if (status == EINTR) {  // EINTR = 4
  328.           continue;  // Something weird happened, but let's keep listening.
  329.         } else {
  330.           perror ("recvfrom() failed ");
  331.           exit (EXIT_FAILURE);
  332.         }
  333.       }  // End of error handling conditionals.
  334.  
  335.       // Check for an IP ethernet frame, carrying ICMP echo reply. If not, ignore and keep listening.
  336.       if ((((recv_ether_frame[12] << 8) + recv_ether_frame[13]) == ETH_P_IP) &&
  337.          (recv_iphdr->ip_p == IPPROTO_ICMP) && (recv_icmphdr->icmp_type == ICMP_ECHOREPLY) && (recv_icmphdr->icmp_code == 0)) {
  338.  
  339.         // Stop timer and calculate how long it took to get a reply.
  340.         (void) gettimeofday (&t2, &tz);
  341.         dt = (double) (t2.tv_sec - t1.tv_sec) * 1000.0 + (double) (t2.tv_usec - t1.tv_usec) / 1000.0;
  342.  
  343.         // Extract source IP address from received ethernet frame.
  344.         if (inet_ntop (AF_INET, &(recv_iphdr->ip_src.s_addr), rec_ip, INET_ADDRSTRLEN) == NULL) {
  345.           status = errno;
  346.           fprintf (stderr, "inet_ntop() failed.\nError message: %s", strerror (status));
  347.           exit (EXIT_FAILURE);
  348.         }
  349.  
  350.         // Report source IPv4 address and time for reply.
  351.         printf ("%s  %g ms (%i bytes received)\n", rec_ip, dt, bytes);
  352.         done = 1;
  353.         break;  // Break out of Receive loop.
  354.       }  // End if IP ethernet frame carrying ICMP_ECHOREPLY
  355.     }  // End of Receive loop.
  356.  
  357.     // The 'done' flag was set because an echo reply was received; break out of send loop.
  358.     if (done == 1) {
  359.       break;  // Break out of Send loop.
  360.     }
  361.  
  362.     // We ran out of tries, so let's give up.
  363.     if (trycount == trylim) {
  364.       printf ("Recognized no echo replies from remote host after %i tries.\n", trylim);
  365.       break;
  366.     }
  367.  
  368.   }  // End of Send loop.
  369.  
  370.   // Close socket descriptors.
  371.   close (sendsd);
  372.   close (recvsd);
  373.  
  374.   // Free allocated memory.
  375.   free (src_mac);
  376.   free (dst_mac);
  377.   free (data);
  378.   free (send_ether_frame);
  379.   free (recv_ether_frame);
  380.   free (interface);
  381.   free (target);
  382.   free (src_ip);
  383.   free (dst_ip);
  384.   free (rec_ip);
  385.   free (ip_flags);
  386.  
  387.   return (EXIT_SUCCESS);
  388. }
  389.  
  390. // Build IPv4 ICMP pseudo-header and call checksum function.
  391. uint16_t
  392. icmp4_checksum (struct icmp icmphdr, uint8_t *payload, int payloadlen)
  393. {
  394.   char buf[IP_MAXPACKET];
  395.   char *ptr;
  396.   int chksumlen = 0;
  397.   int i;
  398.  
  399.   ptr = &buf[0];  // ptr points to beginning of buffer buf
  400.  
  401.   // Copy Message Type to buf (8 bits)
  402.   memcpy (ptr, &icmphdr.icmp_type, sizeof (icmphdr.icmp_type));
  403.   ptr += sizeof (icmphdr.icmp_type);
  404.   chksumlen += sizeof (icmphdr.icmp_type);
  405.  
  406.   // Copy Message Code to buf (8 bits)
  407.   memcpy (ptr, &icmphdr.icmp_code, sizeof (icmphdr.icmp_code));
  408.   ptr += sizeof (icmphdr.icmp_code);
  409.   chksumlen += sizeof (icmphdr.icmp_code);
  410.  
  411.   // Copy ICMP checksum to buf (16 bits)
  412.   // Zero, since we don't know it yet
  413.   *ptr = 0; ptr++;
  414.   *ptr = 0; ptr++;
  415.   chksumlen += 2;
  416.  
  417.   // Copy Identifier to buf (16 bits)
  418.   memcpy (ptr, &icmphdr.icmp_id, sizeof (icmphdr.icmp_id));
  419.   ptr += sizeof (icmphdr.icmp_id);
  420.   chksumlen += sizeof (icmphdr.icmp_id);
  421.  
  422.   // Copy Sequence Number to buf (16 bits)
  423.   memcpy (ptr, &icmphdr.icmp_seq, sizeof (icmphdr.icmp_seq));
  424.   ptr += sizeof (icmphdr.icmp_seq);
  425.   chksumlen += sizeof (icmphdr.icmp_seq);
  426.  
  427.   // Copy payload to buf
  428.   memcpy (ptr, payload, payloadlen);
  429.   ptr += payloadlen;
  430.   chksumlen += payloadlen;
  431.  
  432.   // Pad to the next 16-bit boundary
  433.   for (i=0; i<payloadlen%2; i++, ptr++) {
  434.     *ptr = 0;
  435.     ptr++;
  436.     chksumlen++;
  437.   }
  438.  
  439.   return checksum ((uint16_t *) buf, chksumlen);
  440. }
  441.  
  442. // Computing the internet checksum (RFC 1071).
  443. // Note that the internet checksum does not preclude collisions.
  444. uint16_t
  445. checksum (uint16_t *addr, int len)
  446. {
  447.   int count = len;
  448.   register uint32_t sum = 0;
  449.   uint16_t answer = 0;
  450.  
  451.   // Sum up 2-byte values until none or only one byte left.
  452.   while (count > 1) {
  453.     sum += *(addr++);
  454.     count -= 2;
  455.   }
  456.  
  457.   // Add left-over byte, if any.
  458.   if (count > 0) {
  459.     sum += *(uint8_t *) addr;
  460.   }
  461.  
  462.   // Fold 32-bit sum into 16 bits; we lose information by doing this,
  463.   // increasing the chances of a collision.
  464.   // sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
  465.   while (sum >> 16) {
  466.     sum = (sum & 0xffff) + (sum >> 16);
  467.   }
  468.  
  469.   // Checksum is one's compliment of sum.
  470.   answer = ~sum;
  471.  
  472.   return (answer);
  473. }
  474.  
  475. // Allocate memory for an array of chars.
  476. char *
  477. allocate_strmem (int len)
  478. {
  479.   void *tmp;
  480.  
  481.   if (len <= 0) {
  482.     fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in allocate_strmem().\n", len);
  483.     exit (EXIT_FAILURE);
  484.   }
  485.  
  486.   tmp = (char *) malloc (len * sizeof (char));
  487.   if (tmp != NULL) {
  488.     memset (tmp, 0, len * sizeof (char));
  489.     return (tmp);
  490.   } else {
  491.     fprintf (stderr, "ERROR: Cannot allocate memory for array allocate_strmem().\n");
  492.     exit (EXIT_FAILURE);
  493.   }
  494. }
  495.  
  496. // Allocate memory for an array of unsigned chars.
  497. uint8_t *
  498. allocate_ustrmem (int len)
  499. {
  500.   void *tmp;
  501.  
  502.   if (len <= 0) {
  503.     fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in allocate_ustrmem().\n", len);
  504.     exit (EXIT_FAILURE);
  505.   }
  506.  
  507.   tmp = (uint8_t *) malloc (len * sizeof (uint8_t));
  508.   if (tmp != NULL) {
  509.     memset (tmp, 0, len * sizeof (uint8_t));
  510.     return (tmp);
  511.   } else {
  512.     fprintf (stderr, "ERROR: Cannot allocate memory for array allocate_ustrmem().\n");
  513.     exit (EXIT_FAILURE);
  514.   }
  515. }
  516.  
  517. // Allocate memory for an array of ints.
  518. int *
  519. allocate_intmem (int len)
  520. {
  521.   void *tmp;
  522.  
  523.   if (len <= 0) {
  524.     fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in allocate_intmem().\n", len);
  525.     exit (EXIT_FAILURE);
  526.   }
  527.  
  528.   tmp = (int *) malloc (len * sizeof (int));
  529.   if (tmp != NULL) {
  530.     memset (tmp, 0, len * sizeof (int));
  531.     return (tmp);
  532.   } else {
  533.     fprintf (stderr, "ERROR: Cannot allocate memory for array allocate_intmem().\n");
  534.     exit (EXIT_FAILURE);
  535.   }
  536. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement