From 009d0b523f4dbda45c395b4e1584b7d6cdb596c3 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 31 May 2015 13:10:58 +0200 Subject: [PATCH] added session5 (unfishied) --- session5/.gitignore | 2 + session5/ping/Makefile | 11 +++ session5/ping/ping.c | 175 ++++++++++++++++++++++++++++++++++++++++ session5/sniff/Makefile | 11 +++ session5/sniff/sniff.c | 111 +++++++++++++++++++++++++ 5 files changed, 310 insertions(+) create mode 100644 session5/.gitignore create mode 100644 session5/ping/Makefile create mode 100644 session5/ping/ping.c create mode 100644 session5/sniff/Makefile create mode 100644 session5/sniff/sniff.c diff --git a/session5/.gitignore b/session5/.gitignore new file mode 100644 index 0000000..906ec23 --- /dev/null +++ b/session5/.gitignore @@ -0,0 +1,2 @@ +ping/ping +sniff/sniff diff --git a/session5/ping/Makefile b/session5/ping/Makefile new file mode 100644 index 0000000..33e8880 --- /dev/null +++ b/session5/ping/Makefile @@ -0,0 +1,11 @@ +TARGETS = ping + +CC = gcc +CFLAGS = -g -lrt + +all: $(TARGETS) Makefile +clean: + rm -f $(TARGETS) + rm -f *.o *~ + +.PHONY: all clean diff --git a/session5/ping/ping.c b/session5/ping/ping.c new file mode 100644 index 0000000..cee77c6 --- /dev/null +++ b/session5/ping/ping.c @@ -0,0 +1,175 @@ +#define _POSIX_C_SOURCE 199309L + +#include +#include +#include +#include +#include +#include +#include + +#define __USE_BSD 1 +#include +#include + +#include +#include +#include + +#define ICMP_FILTER 1 +#define ECHO_DATA "Hello World" + +int hexdump(void *buf, size_t len) +{ + uint16_t *data = (uint16_t *) buf; + + for (size_t i = 0; i < len; i += 2) { + if (i % 16 == 0 && i != 0) + printf("\n"); + + printf("%04hx ", ntohs(data[i/2])); + } + printf("\n"); +} + +uint16_t icmp_checksum(void *vdata, size_t length) +{ + // Cast the data pointer to one that can be indexed. + char *data = (char*)vdata; + + // Initialise the accumulator. + uint32_t acc = 0xffff; + + // Handle complete 16-bit blocks. + for (size_t i = 0; i + 1 < length; i += 2) { + uint16_t word; + memcpy(&word, data+i,2); + acc += ntohs(word); + if (acc > 0xffff) + acc -= 0xffff; + } + + // Handle any partial block at the end of the data. + if (length & 1) { + uint16_t word = 0; + memcpy(&word, data+length-1, 1); + acc += ntohs(word); + if (acc > 0xffff) + acc -= 0xffff; + } + + // Return the checksum in network byte order. + return htons(~acc); +} + +int ping(int sd, uint16_t seq, uint16_t id) +{ + struct icmp pkg = { + .icmp_type = ICMP_ECHO, + .icmp_code = 0, + .icmp_cksum = 0, + .icmp_id = htons(id), + .icmp_seq = htons(seq) + }; + + strcpy(pkg.icmp_data, ECHO_DATA); + + size_t pkg_len = 8 + strlen(pkg.icmp_data); + pkg.icmp_cksum = icmp_checksum(&pkg, pkg_len); + + ssize_t len = send(sd, &pkg, pkg_len, 0); + + return len < 0 ? -1 : 0; +} + +int pong(int sd, uint16_t seq, uint16_t id) +{ + ssize_t len; + char buf[128]; + + len = recv(sd, &buf, sizeof(buf), 0); + if (len < 0) + return -1; + + uint8_t ihl = buf[0] & 0xf; + uint8_t ttl = buf[8]; + + struct icmp *pkg = (struct icmp *) &buf[ihl * 4]; + + if (!icmp_checksum(&pkg, len)) + return -2; + + if (pkg->icmp_type != ICMP_ECHOREPLY || + pkg->icmp_code != 0) + return -3; + + if (pkg->icmp_id != htons(id) || + pkg->icmp_seq != htons(seq)) + return -4; + + if (strcmp(ECHO_DATA, pkg->icmp_data)) + return -5; + + printf("len: %u, ttl: %u, type: %u, code: %u, id: %u, seq: %u, data: %10s", len-ihl*4, ttl, + pkg->icmp_type, pkg->icmp_code, ntohs(pkg->icmp_id), ntohs(pkg->icmp_seq), pkg->icmp_data); + + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret; + struct timespec ts_start, ts_end; + struct sockaddr_in sa = { + .sin_family = AF_INET + }; + + if (argc != 2) + error(-1, 0, "Usage: %s IP-ADDRESS", argv[0]); + + if (inet_pton(AF_INET, argv[1] , &sa.sin_addr) != 1) + error(-1, 0, "Failed to parse IP address"); + + int sd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + if (sd < 0) + error(-1, errno, "Failed to create socket"); + + if (connect(sd, (struct sockaddr*) &sa, sizeof(sa))) + error(-1, errno, "Failed to connect socket"); + + /* We only want to receive echo replies */ + uint32_t data = ~(1 << ICMP_ECHOREPLY); + if (setsockopt(sd, SOL_RAW, ICMP_FILTER, &data, sizeof(data))) + error(-1, errno, "Failed socketopt"); + + time_t t; + time(&t); + srand((unsigned int) t); + + uint16_t seq = 0; + uint16_t id = rand(); + for (; seq < 10; seq++) { + clock_gettime(CLOCK_MONOTONIC, &ts_start); + + ret = ping(sd, seq, id); + if (ret) + error(-1, errno, "Failed ping: %d (%s)", ret, strerror(errno)); + + do { + ret = pong(sd, seq, id); + if (ret) + error(0, errno, "Failed pong: %d (%s)", ret, strerror(errno)); + } while(ret); + + clock_gettime(CLOCK_MONOTONIC, &ts_end); + + double rtt = 1e3 * (ts_end.tv_sec - ts_start.tv_sec) + 1e-6 * (ts_end.tv_nsec - ts_start.tv_nsec); + printf(", rtt: %f ms\n", rtt); + + sleep(1); + } + + close(sd); + + return 0; +} \ No newline at end of file diff --git a/session5/sniff/Makefile b/session5/sniff/Makefile new file mode 100644 index 0000000..45a324c --- /dev/null +++ b/session5/sniff/Makefile @@ -0,0 +1,11 @@ +TARGETS = sniff + +CC = gcc +CFLAGS = -g + +all: $(TARGETS) Makefile +clean: + rm -f $(TARGETS) + rm -f *.o *~ + +.PHONY: all clean diff --git a/session5/sniff/sniff.c b/session5/sniff/sniff.c new file mode 100644 index 0000000..1c2bd1a --- /dev/null +++ b/session5/sniff/sniff.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define SNAPLEN 1024 + +const char* icmp_type_str = { + [ 0 ] = "Echo Reply", + [ 1..2 ] = NULL, + [ 3 ] = "Destination Unreachable", + [ 4 ] = "Source Quench", + [ 5 ] = "Redirect", + [ 6 ] = "Alternate Host Address", + [ 7 ] = NULL, + [ 8 ] = "Echo", + [ 9 ] = "Router Advertisement", + [ 10 ] = "Router Solicitation", + [ 11 ] = "Time Exceeded", + [ 12 ] = "Parameter Problem", + [ 13 ] = "Timestamp", + [ 14 ] = "Timestamp Reply", + [ 15 ] = "Information Request", + [ 16 ] = "Information Reply", + [ 17 ] = "Address Mask Request", + [ 18 ] = "Address Mask Reply" +} + +int hexdump(void *buf, size_t len) +{ + uint16_t *data = (uint16_t *) buf; + + for (size_t i = 0; i < len; i += 2) { + if (i % 16 == 0 && i != 0) + printf("\n"); + + printf("%04hx ", ntohs(data[i/2])); + } + printf("\n"); +} + +int parse_packet(uint8_t *data, size_t len) +{ + /* Parse Ethertype */ + struct ether_header *ehdr = data; + + printf("ether_src: %s ", ether_ntoa(ehdr->ether_shost)); + printf("ether_dst: %s ", ether_ntoa(ehdr->ether_dhost)); + printf("ether_type: %#04x ", ehdr->ether_type); + + if (ehdr->ether_type == ETHERTYPE_IP) { + /* Parse IP protocol */ + struct ip *iphdr = (char *) ehdr + sizeof(*ehdr) + + printf("ip_version: %u ", iphdr->ip_v); + printf("ip_ihl: %u ", iphdr->ip_hl); + printf("ip_ttl: %u ", iphdr->ip_ttl); + printf("ip_protocol: %u ", iphdr->ip_p); + printf("ip_src: %u ", iphdr->ip_p); + printf("ip_dst: %u ", iphdr->ip_p); + + if (iphdr->p == IPPROTO_ICMP) { + /* Parse ICMP */ + struct icmphdr *icmphdr = (char *) iphdr + iphdr->ip_hl * 4; + + printf("icmp_type: %u (%s) "); + printf("icmp_code: %u ") + } + else if (iphdr->p == IPPROTO_UDP) { + /* Parse UDP */ + struct udphdr *udphdr = (char *) udphdr + iphdr->ip_hl * 4; + + } + else if (iphdr->p == IPPROTO_TCP) { + /* Parse TCP */ + struct udphdr *udphdr = (char *) udphdr + iphdr->ip_hl * 4; + + } + } +} + +int main (int argc, char *argv[]) +{ + uint8_t packet[SNAPLEN]; + + int sd = socket(AF_INET, SOCK_RAW, htons(ETH_P_ALL)); + if (sd < 0) + error(-1, errno, "Failed to create socket"); + + + while (1) { + if (recv(sd, packet, sizeof(packet), 0) > 0) + parse_packet(packet, sizeof(packet)); + } + + close(sd); + + return 0; +} \ No newline at end of file