Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Copyright (C) 2011-2015 P.D. Buchan ([email protected])
- 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 3 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, see <http://www.gnu.org/licenses/>.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h> // close()
- #include <string.h> // strcpy, memset(), and memcpy()
- #include <netdb.h> // struct addrinfo
- #include <sys/types.h> // needed for socket(), uint8_t, uint16_t, uint32_t
- #include <sys/socket.h> // needed for socket()
- #include <netinet/in.h> // IPPROTO_RAW, IPPROTO_IP, IPPROTO_TCP, INET_ADDRSTRLEN
- #include <netinet/ip.h> // struct ip and IP_MAXPACKET (which is 65535)
- #include <arpa/inet.h> // inet_pton() and inet_ntop()
- #include <sys/ioctl.h> // macro ioctl is defined
- #include <bits/ioctls.h> // defines values for argument "request" of ioctl.
- #include <net/if.h> // struct ifreq
- #include <errno.h> // errno, perror()
- // Define some constants.
- #define IP4_HDRLEN 20 // IPv4 header length
- // Function prototypes
- uint16_t checksum (uint16_t *, int);
- char *allocate_strmem (int);
- uint8_t *allocate_ustrmem (int);
- int *allocate_intmem (int);
- int
- main (int argc, char **argv)
- {
- int status, sd, *ip_flags;
- const int on = 1;
- char *interface, *target, *src_ip, *dst_ip;
- struct ip iphdr;
- uint8_t *packet;
- struct addrinfo hints, *res;
- struct sockaddr_in *ipv4, sin;
- struct ifreq ifr;
- void *tmp;
- // Allocate memory for various arrays.
- packet = allocate_ustrmem (IP_MAXPACKET);
- interface = allocate_strmem (40);
- target = allocate_strmem (40);
- src_ip = allocate_strmem (INET_ADDRSTRLEN);
- dst_ip = allocate_strmem (INET_ADDRSTRLEN);
- ip_flags = allocate_intmem (4);
- // Interface to send packet through.
- strcpy (interface, "enp2s0");
- // Submit request for a socket descriptor to look up interface.
- if ((sd = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
- perror ("socket() failed to get socket descriptor for using ioctl() ");
- exit (EXIT_FAILURE);
- }
- // Use ioctl() to look up interface index which we will use to
- // bind socket descriptor sd to specified interface with setsockopt() since
- // none of the other arguments of sendto() specify which interface to use.
- memset (&ifr, 0, sizeof (ifr));
- snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
- if (ioctl (sd, SIOCGIFINDEX, &ifr) < 0) {
- perror ("ioctl() failed to find interface ");
- return (EXIT_FAILURE);
- }
- close (sd);
- printf ("Index for interface %s is %i\n", interface, ifr.ifr_ifindex);
- // Source IPv4 address: you need to fill this out
- strcpy (src_ip, "192.168.0.1");
- // Destination URL or IPv4 address: you need to fill this out
- strcpy (target, "192.168.0.168");
- // Fill out hints for getaddrinfo().
- memset (&hints, 0, sizeof (struct addrinfo));
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_RAW;
- hints.ai_flags = hints.ai_flags | AI_CANONNAME;
- // Resolve target using getaddrinfo().
- if ((status = getaddrinfo (target, NULL, &hints, &res)) != 0) {
- fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (status));
- exit (EXIT_FAILURE);
- }
- ipv4 = (struct sockaddr_in *) res->ai_addr;
- tmp = &(ipv4->sin_addr);
- if (inet_ntop (AF_INET, tmp, dst_ip, INET_ADDRSTRLEN) == NULL) {
- status = errno;
- fprintf (stderr, "inet_ntop() failed.\nError message: %s", strerror (status));
- exit (EXIT_FAILURE);
- }
- freeaddrinfo (res);
- // IPv4 header
- // IPv4 header length (4 bits): Number of 32-bit words in header = 5
- iphdr.ip_hl = IP4_HDRLEN / sizeof (uint32_t);
- // Internet Protocol version (4 bits): IPv4
- iphdr.ip_v = 4;
- // Type of service (8 bits)
- iphdr.ip_tos = 0;
- // Total length of datagram (16 bits): IP header
- iphdr.ip_len = htons (IP4_HDRLEN);
- // ID sequence number (16 bits): unused, since single datagram
- iphdr.ip_id = htons (0);
- // Flags, and Fragmentation offset (3, 13 bits): 0 since single datagram
- // Zero (1 bit)
- ip_flags[0] = 0;
- // Do not fragment flag (1 bit)
- ip_flags[1] = 0;
- // More fragments following flag (1 bit)
- ip_flags[2] = 0;
- // Fragmentation offset (13 bits)
- ip_flags[3] = 0;
- iphdr.ip_off = htons ((ip_flags[0] << 15)
- + (ip_flags[1] << 14)
- + (ip_flags[2] << 13)
- + ip_flags[3]);
- // Time-to-Live (8 bits): default to maximum value
- iphdr.ip_ttl = 255;
- iphdr.ip_p = 200;
- // Source IPv4 address (32 bits)
- if ((status = inet_pton (AF_INET, src_ip, &(iphdr.ip_src))) != 1) {
- fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
- exit (EXIT_FAILURE);
- }
- // Destination IPv4 address (32 bits)
- if ((status = inet_pton (AF_INET, dst_ip, &(iphdr.ip_dst))) != 1) {
- fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
- exit (EXIT_FAILURE);
- }
- // IPv4 header checksum (16 bits): set to 0 when calculating checksum
- iphdr.ip_sum = 0;
- iphdr.ip_sum = checksum ((uint16_t *) &iphdr, IP4_HDRLEN);
- // Prepare packet.
- // First part is an IPv4 header.
- memcpy (packet, &iphdr, IP4_HDRLEN * sizeof (uint8_t));
- // The kernel is going to prepare layer 2 information (ethernet frame header) for us.
- // For that, we need to specify a destination for the kernel in order for it
- // to decide where to send the raw datagram. We fill in a struct in_addr with
- // the desired destination IP address, and pass this structure to the sendto() function.
- memset (&sin, 0, sizeof (struct sockaddr_in));
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = iphdr.ip_dst.s_addr;
- // Submit request for a raw socket descriptor.
- if ((sd = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
- perror ("socket() failed ");
- exit (EXIT_FAILURE);
- }
- // Set flag so socket expects us to provide IPv4 header.
- if (setsockopt (sd, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)) < 0) {
- perror ("setsockopt() failed to set IP_HDRINCL ");
- exit (EXIT_FAILURE);
- }
- // Bind socket to interface index.
- if (setsockopt (sd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof (ifr)) < 0) {
- perror ("setsockopt() failed to bind to interface ");
- exit (EXIT_FAILURE);
- }
- // Send packet.
- if (sendto (sd, packet, IP4_HDRLEN, 0, (struct sockaddr *) &sin, sizeof (struct sockaddr)) < 0) {
- perror ("sendto() failed ");
- exit (EXIT_FAILURE);
- }
- printf("packet sent\n");
- // Close socket descriptor.
- close (sd);
- // Free allocated memory.
- free (packet);
- free (interface);
- free (target);
- free (src_ip);
- free (dst_ip);
- free (ip_flags);
- return (EXIT_SUCCESS);
- }
- // Computing the internet checksum (RFC 1071).
- uint16_t
- checksum (uint16_t *addr, int len)
- {
- int count = len;
- register uint32_t sum = 0;
- uint16_t answer = 0;
- // Sum up 2-byte values until none or only one byte left.
- while (count > 1) {
- sum += *(addr++);
- count -= 2;
- }
- // Add left-over byte, if any.
- if (count > 0) {
- sum += *(uint8_t *) addr;
- }
- // Fold 32-bit sum into 16 bits; we lose information by doing this,
- // increasing the chances of a collision.
- // sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
- while (sum >> 16) {
- sum = (sum & 0xffff) + (sum >> 16);
- }
- // Checksum is one's compliment of sum.
- answer = ~sum;
- return (answer);
- }
- // Allocate memory for an array of chars.
- char *
- allocate_strmem (int len)
- {
- char *tmp;
- if (len <= 0) {
- fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in allocate_strmem().\n", len);
- exit (EXIT_FAILURE);
- }
- tmp = (char *) malloc (len * sizeof (char));
- if (tmp != NULL) {
- memset (tmp, 0, len * sizeof (char));
- return (tmp);
- } else {
- fprintf (stderr, "ERROR: Cannot allocate memory for array allocate_strmem().\n");
- exit (EXIT_FAILURE);
- }
- }
- // Allocate memory for an array of unsigned chars.
- uint8_t *
- allocate_ustrmem (int len)
- {
- uint8_t *tmp;
- if (len <= 0) {
- fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in allocate_ustrmem().\n", len);
- exit (EXIT_FAILURE);
- }
- tmp = (uint8_t *) malloc (len * sizeof (uint8_t));
- if (tmp != NULL) {
- memset (tmp, 0, len * sizeof (uint8_t));
- return (tmp);
- } else {
- fprintf (stderr, "ERROR: Cannot allocate memory for array allocate_ustrmem().\n");
- exit (EXIT_FAILURE);
- }
- }
- // Allocate memory for an array of ints.
- int *
- allocate_intmem (int len)
- {
- int *tmp;
- if (len <= 0) {
- fprintf (stderr, "ERROR: Cannot allocate memory because len = %i in allocate_intmem().\n", len);
- exit (EXIT_FAILURE);
- }
- tmp = (int *) malloc (len * sizeof (int));
- if (tmp != NULL) {
- memset (tmp, 0, len * sizeof (int));
- return (tmp);
- } else {
- fprintf (stderr, "ERROR: Cannot allocate memory for array allocate_intmem().\n");
- exit (EXIT_FAILURE);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement