aboutsummaryrefslogtreecommitdiff
path: root/Semestr 4/sieci/pracownia1/traceroute.c
blob: 791895735ba868940e5eb5e738d979a36cc4d481 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <stdio.h>
#include <errno.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/ip_icmp.h>
#include <assert.h>

#define MAX_TTL 30
#define MESSAGES_PER_TTL 3

void print_as_bytes (unsigned char* buff, ssize_t length)
{
	for (ssize_t i = 0; i < length; i++, buff++)
		printf ("%.2x ", *buff);	
}

struct sockaddr_in get_sockaddr_from_ip(char *ip) {
    struct sockaddr_in sock;
    bzero(&sock, sizeof(sock));
    sock.sin_family = AF_INET;
    if (!inet_pton(AF_INET, ip, &sock.sin_addr)) {
        fprintf(stderr, "Given ip is invalid: %s\n", ip);
        exit(EXIT_FAILURE);
    }
    return sock;
}

int create_raw_icmp_socket() {
    int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sockfd < 0) {
        fprintf(stderr, "socket error: %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }
    return sockfd;
}

uint16_t compute_icmp_checksum (const void *buff, int length)
{
	uint32_t sum;
	const uint16_t* ptr = buff;
	assert (length % 2 == 0);
	for (sum = 0; length > 0; length -= 2)
		sum += *ptr++;
	sum = (sum >> 16) + (sum & 0xffff);
	return (uint16_t)(~(sum + (sum >> 16)));
}

struct icmp create_icmp_header() {
    static uint16_t pid = 0;
    static uint16_t seq = 0;
    
    struct icmp header;
    header.icmp_type = ICMP_ECHO;
    header.icmp_code = 0;
    header.icmp_id = ++pid;
    header.icmp_seq = ++seq;
    header.icmp_cksum = 0;
    header.icmp_cksum = compute_icmp_checksum(
        (uint16_t*)&header, sizeof(header));

    return header;
}

void send_icmp_packet(int sockfd, struct sockaddr_in *destination, int ttl) {
    struct icmp header = create_icmp_header();
    setsockopt(sockfd, IPPROTO_IP, IP_TTL, &ttl, sizeof(int));

    printf("%ld %d\n", destination->sin_addr.s_addr, sockfd);
    ssize_t bytes_sent = sendto(
        sockfd,
        &header,
        sizeof(header),
        0,
        (struct sockaddr*)destination,
        sizeof(*destination)
    );
    if (bytes_sent == -1) {
        fprintf(stderr, "Error while sending ICMP packet: %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }
    fprintf(stdout, "Bytes sent: %ld\n", bytes_sent);
}

int traceroute(struct sockaddr_in *destination) {
    int sockfd = create_raw_icmp_socket();

    struct sockaddr_in  sender;
    socklen_t           sender_len = sizeof(sender);
    uint8_t             buffer[IP_MAXPACKET];
    for (int ttl = 1; ttl <= MAX_TTL; ++ttl) {
        send_icmp_packet(sockfd, destination, ttl);
    }
}     

int main(int argc, char * argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage:\n\t%s [host ip]\n", argv[0]);
        return 1;
    }

    struct sockaddr_in destination = get_sockaddr_from_ip(argv[1]);
    traceroute(&destination);
}