Advertisement
Guest User

Untitled

a guest
Apr 24th, 2012
302
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.94 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <time.h>
  6.  
  7. #include <linux/if_ether.h>
  8. #include <sys/ioctl.h>
  9. #include <netpacket/packet.h>
  10.  
  11. #include <net/if_arp.h>
  12. #include <net/if.h>
  13. #include <netinet/ip.h>
  14. #include <netinet/ip_icmp.h>
  15.  
  16. #include "headers.h"
  17.  
  18.  
  19.  
  20. /* Global variables */
  21.  
  22. #define MACSIZ 6
  23.  
  24. int p_socket;
  25. struct sockaddr_ll sa_ll;   /* L2 address of gateway */
  26.  
  27. u_int32_t src_ip, dst_ip;   /* src & dst ip addresses */
  28. u_int16_t icmp_id_num;      /* id number of last ICMP sent */
  29.  
  30. size_t packet_size;         /* how many bytes to send or were received */
  31. char packet_buf[1600];      /* raw packet buffer */
  32.  
  33.  
  34. /* Declarations */
  35.  
  36. void init_session(char *ifname, char *gw_ip, char *dst);
  37. void close_session();
  38. size_t create_icmp_hdr(void *buf, size_t buf_size);
  39. size_t add_ip_opt_rroute(void *buf, size_t buf_size, int count);
  40. size_t create_ip_hdr(void *buf, size_t buf_size, int ttl, size_t data_len);
  41. void send_icmp(int ttl);
  42. void send_packet();
  43. void receive_packet();
  44. void receive_icmp_reply();
  45. void print_record_route();
  46. u_int16_t calc_checksum(void *buff, int len);
  47.  
  48.  
  49. /*
  50.     Main function
  51. */
  52. int main(int argc, char **argv) {
  53.     if (argc < 4) {
  54.         fprintf(stderr, "Usage: %s <output-dev> <gateway-ip> <dst-ip>\n", *argv);
  55.         exit(1);
  56.     }
  57.  
  58.     init_session(argv[1], argv[2], argv[3]);
  59.  
  60.     printf("Jesli po paru chwilach nic sie nie pojawi to pakiet IP zostal pewnie odrzucony przez host docelowy (ze wzgledu na opcje Record Route) - najlepiej sprawdzic tcpdumpem/wiresharkiem lub sprobowac dla innego docelowego IP.\n\n");
  61.  
  62.     send_icmp(56);
  63.     receive_icmp_reply();
  64.     print_record_route();
  65.  
  66.     close_session();
  67. }
  68.  
  69.  
  70. /*
  71.     Initializes global variables and opens packet socket.
  72.  
  73.     @param dev Output device name, e.g. eth0, wlan0
  74.     @param gw IP address of default gateway
  75.     @param dst Destination IP address
  76. */
  77. void init_session(char *ifname, char *gw_ip, char *dst) {
  78.     int fd;
  79.     struct ifreq ifr;
  80.     struct arpreq arpreq;
  81.     struct sockaddr_in *in;
  82.  
  83.     char gw_mac[MACSIZ];        /* gateway MAC address */
  84.     int ifindex;                /* index number of output interface */
  85.  
  86.  
  87.     fd = socket(AF_INET, SOCK_DGRAM, 0);
  88.  
  89.     /* copying ifname */
  90.     /*strncpy(ifname, dev, sizeof(ifname)-1);*/
  91.  
  92.     /* getting gateway mac */
  93.     bzero(&arpreq, sizeof(arpreq));
  94.     in = (struct sockaddr_in *)&arpreq.arp_pa;
  95.     in->sin_family = AF_INET;
  96.     inet_pton(AF_INET, gw_ip, &(in->sin_addr.s_addr));
  97.     strncpy(arpreq.arp_dev, ifname, 15);
  98.    
  99.     if (ioctl(fd, SIOCGARP, &arpreq) < 0) {
  100.         fprintf(stderr, "Error /ioctl(fd, SIOCGARP, &arpreq)/: %s\n", strerror(errno));
  101.         exit(1);
  102.     }
  103.  
  104.     memcpy(gw_mac, arpreq.arp_ha.sa_data, MACSIZ);
  105.  
  106.     /* getting index number of output interface */
  107.     bzero(&ifr, sizeof(ifr));
  108.     strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1);
  109.  
  110.     if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
  111.         fprintf(stderr, "Error /ioctl(fd, SIOCGIFINDEX, &ifr)/: %s\n", strerror(errno));
  112.         exit(1);
  113.     }
  114.  
  115.     ifindex = ifr.ifr_ifindex;
  116.  
  117.     /* getting ip number of output interface (our src ip address) */
  118.     bzero(&ifr, sizeof(ifr));
  119.     strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1);
  120.  
  121.     if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
  122.         fprintf(stderr, "Error /ioctl(fd, SIOCGIFADDR, &ifr)/: %s\n", strerror(errno));
  123.         exit(1);
  124.     }
  125.    
  126.     src_ip = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
  127.  
  128.     /* destination ip */
  129.     if (inet_pton(AF_INET, dst, &dst_ip) < 1) {
  130.         fprintf(stderr, "Error %s:%d: %s\n", __FILE__, __LINE__, "Invalid dst ip");
  131.         exit(1);
  132.     }
  133.  
  134.     close(fd);
  135.  
  136.  
  137.     /* creating packet socket */
  138.     if ((p_socket = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
  139.         fprintf(stderr, "ERROR: %s\n", strerror(errno));
  140.         exit(1);
  141.     }
  142.  
  143.     /* setting values in sockaddr_ll */
  144.     bzero(&sa_ll, sizeof(sa_ll));
  145.  
  146.     sa_ll.sll_family = AF_PACKET;
  147.     memcpy(&sa_ll.sll_addr, gw_mac, sizeof(gw_mac));
  148.     sa_ll.sll_halen = sizeof(gw_mac);
  149.     sa_ll.sll_ifindex = ifindex;
  150.     sa_ll.sll_protocol = htons(ETH_P_IP);
  151.  
  152.     /* binding */
  153.     if (bind(p_socket, (const struct sockaddr *)&sa_ll, sizeof(sa_ll)) < 0) {
  154.         fprintf(stderr, "ERROR (bind): %s\n", strerror(errno));
  155.         exit(1);
  156.     }
  157. }
  158.  
  159. /*
  160.     Closes sessions.
  161. */
  162. void close_session() {
  163.     close(p_socket);
  164. }
  165.  
  166.  
  167. /*
  168.     Creates icmp header (ICMP_ECHO).
  169.  
  170.     @param buf Pointer to buffer where to put header
  171.     @param buf_size Buffer size
  172.     @return Number of bytes added
  173. */
  174. size_t create_icmp_hdr(void *buf, size_t buf_size) {
  175.     struct icmphdr *icmp;
  176.  
  177.     srand(time(0));
  178.     icmp_id_num = random() % 0xFFFF;
  179.  
  180.     bzero(buf, buf_size);
  181.     icmp = (struct icmphdr *)buf;
  182.  
  183.     icmp->type = ICMP_ECHO;
  184.     icmp->un.echo.id = icmp_id_num;
  185.     icmp->checksum = calc_checksum(buf, sizeof(struct icmphdr));
  186.  
  187.     return sizeof(struct icmphdr);
  188. }
  189.  
  190.  
  191. /*
  192.     Adds IP option Record Route with ability to record 'count'
  193.     hops (count in 0 .. 10). Adds padding if necessary.
  194.  
  195.     @param buf Pointer to buffer where to add RR option
  196.     @param buf_size Bufer size
  197.     @return Number of bytes added
  198. */
  199. size_t add_ip_opt_rroute(void *buf, size_t buf_size, int count) {
  200.     struct opt_ip_route *opt;
  201.     size_t opt_len;
  202.  
  203.     /* padding is always 1 byte for this option */
  204.  
  205.     opt_len = sizeof(struct opt_ip_route) + 4*count + 1;
  206.  
  207.     if (opt_len > buf_size || count > 9) {
  208.         perror("Record Route option is too long (count>9 or no space left in buffer)");
  209.         return 0;
  210.     }
  211.  
  212.     *(char *)(buf++) = OPT_IP_NOP; /* padding */
  213.  
  214.     opt = (struct opt_ip_route *)buf;
  215.    
  216.     opt->cpy_flag = 0;
  217.     opt->class_opt = 0;
  218.     opt->option = OPT_IP_RR;
  219.     opt->length = opt_len-1; /* minus padding */
  220.     opt->ptr = 4;
  221.  
  222.     return opt_len;
  223. }
  224.  
  225.  
  226.  
  227. /*
  228.     Creates IPv4 header with given TTL
  229.  
  230.     @param buf Pointer to buffer where to put header
  231.     @param buf_size Buffer size
  232.     @return Number of bytes added
  233. */
  234. size_t create_ip_hdr(void *buf, size_t buf_size, int ttl, size_t data_len) {
  235.     static short ip_id = 0;
  236.     struct iphdr *iphdr;
  237.     size_t hdr_len;
  238.    
  239.     /* assuming buf was already zeroed */
  240.  
  241.     iphdr = (struct iphdr *)buf;
  242.  
  243.     iphdr->version = 4;                    /* IPv4 */
  244.     iphdr->id = htons(ip_id++);               /* Ip id */
  245.     iphdr->ttl = ttl;                      /* TTL */
  246.     iphdr->protocol = IPPROTO_ICMP;        /* L4 protocol */
  247.     iphdr->saddr = src_ip;                 /* Src IP address */
  248.     iphdr->daddr = dst_ip;                 /* Dst IP address */
  249.  
  250.     hdr_len = sizeof(struct iphdr);
  251.  
  252.     /* adding IP options */
  253.    
  254.     hdr_len += add_ip_opt_rroute(buf+hdr_len, buf_size-hdr_len, 9);
  255.     /*hdr_len += add_ip_opt_lsr(buf+hdr_len, buf_size-hdr_len);*/
  256.  
  257.     /* correcting 'length' fields in header */
  258.  
  259.     if (hdr_len > 60) {
  260.         fprintf(stderr, "IP header is too long (%d/60 bytes): change IP options", hdr_len);
  261.         exit(1);
  262.     }
  263.  
  264.     iphdr->ihl = hdr_len/4;
  265.     iphdr->tot_len = htons(hdr_len + data_len);
  266.  
  267.     /* calculating checksum */
  268.  
  269.     iphdr->check = calc_checksum(buf, hdr_len);
  270.  
  271.     return hdr_len;
  272. }
  273.  
  274.  
  275. /*
  276.     Sends icmp packet with given ttl value.
  277. */
  278. void send_icmp(int ttl) {
  279.     char icmp_header[128];
  280.     char ip_header[128];
  281.     size_t icmp_size, ip_size, eth_size;
  282.  
  283.     /* cleaning buffers */
  284.     bzero(packet_buf, sizeof(packet_buf));
  285.     bzero(icmp_header, sizeof(icmp_header));
  286.     bzero(ip_header, sizeof(ip_header));
  287.  
  288.     /* preparing headers */
  289.     icmp_size = create_icmp_hdr(icmp_header, sizeof(icmp_header));
  290.     ip_size = create_ip_hdr(ip_header, sizeof(ip_header), ttl, icmp_size);
  291.  
  292.     /* preparing final packet and sending */
  293.     memcpy(packet_buf, ip_header, ip_size);
  294.     memcpy(packet_buf+ip_size, icmp_header, icmp_size);
  295.     packet_size = ip_size + icmp_size;
  296.  
  297.     send_packet();
  298. }
  299.  
  300.  
  301. /*
  302.     Prints IP Record Route values from packet
  303.     stored in packet_buf.
  304. */
  305. void print_record_route() {
  306.     struct iphdr *iphdr;
  307.     struct opt_ip_route *opt;
  308.  
  309.     int hdr_len;
  310.     void *opt_start;
  311.  
  312.     int rr_end;
  313.     char ip_addr[24];
  314.  
  315.  
  316.     iphdr = (struct iphdr*)packet_buf;
  317.     hdr_len = iphdr->ihl*4;
  318.    
  319.     hdr_len -= sizeof(struct iphdr);
  320.     opt_start = packet_buf+sizeof(struct iphdr);
  321.  
  322.     while (hdr_len > 0) {
  323.         opt = (struct opt_ip_route *)opt_start;
  324.  
  325.         if (opt->option == OPT_IP_NOP || opt->option == OPT_IP_EOP) {
  326.             ++opt_start;
  327.             --hdr_len;
  328.             continue;
  329.         } else if (opt->option == OPT_IP_RR) {
  330.             /* printing... */
  331.             rr_end = opt->ptr;
  332.             opt->ptr -= 4;
  333.  
  334.             while (opt->ptr > 0) {
  335.                 /* a little black magic with pointers & indexes ];-> */
  336.                 inet_ntop(AF_INET, opt_start+rr_end-opt->ptr-1, ip_addr, sizeof(ip_addr));
  337.                 printf("%s\n", ip_addr);
  338.                 opt->ptr -= 4;
  339.             }
  340.  
  341.             hdr_len -= opt->length;
  342.             opt_start += opt->length;
  343.  
  344.         } else {
  345.             fprintf(stderr, "Unknown ip option : %d\n", opt->option);
  346.             exit(1);
  347.         }
  348.  
  349.     }
  350. }
  351.  
  352.  
  353. /*
  354.     Receives icmp reply
  355. */
  356. void receive_icmp_reply() {
  357.     struct iphdr *iphdr;    
  358.     struct icmphdr *icmphdr;
  359.  
  360.     while(1) {
  361.         receive_packet();
  362.         iphdr = (struct iphdr *)packet_buf;
  363.  
  364.         if (iphdr->protocol == IPPROTO_ICMP) {
  365.             icmphdr = (struct icmphdr *)(packet_buf + iphdr->ihl*4);
  366.  
  367.             /* checking if received ICMP is our reply */
  368.             if (icmphdr->un.echo.id != icmp_id_num)
  369.                 continue;
  370.  
  371.             break;
  372.         }
  373.     }
  374. }
  375.  
  376.  
  377. /*
  378.     Sends raw packet
  379. */
  380. void send_packet() {
  381.     int rtn;
  382.  
  383.     rtn = sendto(p_socket, (void *)packet_buf, packet_size, 0, (const struct sockaddr *)&sa_ll, sizeof(sa_ll));
  384.  
  385.     if (rtn < 0) {
  386.         fprintf(stderr, "ERROR(send): %s\n", strerror(errno));
  387.         exit(1);
  388.     }
  389. }
  390.  
  391.  
  392. /*
  393.     Receives next packet to packet_buf
  394. */
  395. void receive_packet() {
  396.     int rtn;
  397.     struct sockaddr_ll sa;
  398.     int size = sizeof(sa);
  399.    
  400.     bzero(packet_buf, sizeof(packet_buf));
  401.     rtn = recvfrom(p_socket, (void*)packet_buf, sizeof(packet_buf), 0, (struct sockaddr*)&sa, &size);
  402.  
  403.     if (rtn < 0) {
  404.         fprintf(stderr, "ERROR(receive): %s\n", strerror(errno));
  405.     }
  406.  
  407.     packet_size = rtn;
  408. }
  409.  
  410.  
  411. /*
  412.     Calculates checksum using 1's complement.
  413.     Based on example in RFC-1071 (4.1)
  414.    
  415.     @param buff Pointer to buffer with data
  416.     @param len Data length in buffer
  417.     @return 16bit checksum
  418. */
  419. u_int16_t calc_checksum(void *buff, int len) {
  420.     register long sum = 0;
  421.  
  422.     while (len > 1) {
  423.         sum += *((unsigned short *)buff);
  424.         buff += 2;
  425.         len -= 2;
  426.     }
  427.  
  428.     if (len > 0)
  429.         sum += *((unsigned char *)buff);
  430.  
  431.     while (sum>>16)
  432.         sum = (sum & 0xffff) + (sum >> 16);
  433.  
  434.     return ~sum;
  435. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement