From 5af1a5ca7cd753f7e518f74e86ae9587993c0b60 Mon Sep 17 00:00:00 2001 From: Michal Zima Date: Thu, 14 Feb 2013 14:26:01 +0100 Subject: [PATCH] Reacting to exceeded TTL/HL --- src/icmp.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/icmp.h | 9 ++- src/ipv4.c | 17 +++++- src/ipv6.c | 16 +++++- src/wrapper.c | 10 ++++ src/wrapper.h | 2 + 6 files changed, 205 insertions(+), 3 deletions(-) diff --git a/src/icmp.c b/src/icmp.c index 76b598d..7c56865 100644 --- a/src/icmp.c +++ b/src/icmp.c @@ -353,3 +353,157 @@ int icmp_ndp(struct s_ethernet *ethq, struct s_ipv6 *ipq, return 0; } + +/** + * Sends ICMPv4 error. + * + * @param ip_dest Destination IPv4 address + * @param type Type of ICMP error + * @param code Code of ICMP error + * @param data Original packet + * @param length Length of the original packet + * + * @return 0 for success + * @return 1 for failure + */ +int icmp4_error(struct s_ipv4_addr ip_dest, unsigned char type, + unsigned char code, unsigned char *data, unsigned short length) +{ + unsigned char *packet, *payload; + struct s_ipv4 *ip4; + struct s_icmp *icmp; + + /* 4 = unused space after ICMP header */ + unsigned short payload_size = length > 1500 - sizeof(struct s_ipv4) - + sizeof(struct s_icmp) - 4 ? + 1500 - sizeof(struct s_ipv4) - sizeof(struct s_icmp) - 4 : + length; + + if ((packet = (unsigned char *) malloc(sizeof(struct s_ipv4) + + sizeof(struct s_icmp) + 4 + payload_size)) == NULL) { + log_error("Lack of free memory"); + return 1; + } + + ip4 = (struct s_ipv4 *) packet; + icmp = (struct s_icmp *) (packet + sizeof(struct s_ipv4)); + payload = (unsigned char *) (packet + sizeof(struct s_ipv4) + + sizeof(struct s_icmp) + 4); + + /* build IPv4 packet */ + ip4->ver_hdrlen = 0x45; /* ver 4, header length 20 B */ + ip4->tos = 0x0; + ip4->len = htons(sizeof(struct s_ipv4) + + sizeof(struct s_icmp) + 4 + payload_size); + ip4->id = 0x0; + ip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT); + ip4->ttl = 255; + ip4->proto = IPPROTO_ICMP; + ip4->ip_src = host_ipv4_addr; + ip4->ip_dest = ip_dest; + + /* build ICMP header */ + icmp->type = type; + icmp->code = code; + icmp->checksum = 0x0; + + /* copy the payload data */ + memcpy(payload, data, payload_size); + + /* compute ICMP checksum */ + icmp->checksum = checksum((unsigned char *) icmp, + payload_size + 4 + sizeof(struct s_icmp)); + + /* compute IPv4 checksum */ + ip4->checksum = checksum_ipv4(ip4->ip_src, ip4->ip_dest, + htons(ip4->len), IPPROTO_ICMP, + (unsigned char *) icmp); + + /* send packet */ + transmit_ipv4(&ip4->ip_dest, packet, htons(ip4->len)); + + /* clean-up */ + free(packet); + + return 0; +} + +/** + * Sends ICMPv6 error. + * + * @param mac_dest Destination MAC address + * @param ip_dest Destination IPv6 address + * @param type Type of ICMP error + * @param code Code of ICMP error + * @param data Original packet + * @param length Length of the original packet + * + * @return 0 for success + * @return 1 for failure + */ +int icmp6_error(struct s_mac_addr mac_dest, struct s_ipv6_addr ip_dest, + unsigned char type, unsigned char code, unsigned char *data, + unsigned short length) +{ + unsigned char *packet, *payload; + struct s_ethernet *eth; + struct s_ipv6 *ip6; + struct s_icmp *icmp; + + /* 4 = unused space after ICMP header */ + unsigned short payload_size = length > 1280 - sizeof(struct s_ipv6) - + sizeof(struct s_icmp) - 4 ? + 1280 - sizeof(struct s_ipv6) - sizeof(struct s_icmp) - 4 : + length; + + if ((packet = (unsigned char *) malloc(sizeof(struct s_ethernet) + + sizeof(struct s_ipv6) + sizeof(struct s_icmp) + 4 + + payload_size)) == NULL) { + log_error("Lack of free memory"); + return 1; + } + + eth = (struct s_ethernet *) packet; + ip6 = (struct s_ipv6 *) (packet + sizeof(struct s_ethernet)); + icmp = (struct s_icmp *) (packet + sizeof(struct s_ethernet) + + sizeof(struct s_ipv6)); + payload = (unsigned char *) (packet + sizeof(struct s_ethernet) + + sizeof(struct s_ipv6) + + sizeof(struct s_icmp) + 4); + + /* ethernet */ + eth->dest = mac_dest; + eth->src = mac; + eth->type = htons(ETHERTYPE_IPV6); + + /* IPv6 */ + ip6->ver = 0x60; + ip6->len = htons(sizeof(struct s_icmp) + 4 + payload_size); + ip6->next_header = IPPROTO_ICMPV6; + ip6->hop_limit = 255; + ip6->ip_src = host_ipv6_addr; + ip6->ip_dest = ip_dest; + + /* ICMP */ + icmp->type = type; + icmp->code = code; + icmp->checksum = 0x0; + + /* copy the payload data */ + memcpy(payload, data, payload_size); + + /* compute ICMP checksum */ + icmp->checksum = checksum_ipv6(host_ipv6_addr, ip_dest, + sizeof(struct s_icmp) + 4 + payload_size, + IPPROTO_ICMPV6, + (unsigned char *) icmp); + + /* send packet */ + transmit_raw(packet, sizeof(struct s_ethernet) + sizeof(struct s_ipv6) + + sizeof(struct s_icmp) + 4 + payload_size); + + /* clean-up */ + free(packet); + + return 0; +} diff --git a/src/icmp.h b/src/icmp.h index b3fe7e8..7cb9652 100644 --- a/src/icmp.h +++ b/src/icmp.h @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2012 Michal Zima + * Copyright (C) 2008-2013 Michal Zima * * 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 @@ -25,6 +25,7 @@ /* ICMP types */ #define ICMPV4_ECHO_REPLY 0x0 #define ICMPV4_ECHO_REQUEST 0x8 +#define ICMPV4_TIME_EXCEEDED 0xb /* ICMPv6 types */ #define ICMPV6_DST_UNREACHABLE 0x1 @@ -80,4 +81,10 @@ int icmp_ipv6(struct s_ethernet *eth, struct s_ipv6 *ip6, char *payload); int icmp_ndp(struct s_ethernet *ethq, struct s_ipv6 *ipq, struct s_icmp_ndp_ns *ndp_ns); +int icmp4_error(struct s_ipv4_addr ip_dest, unsigned char type, + unsigned char code, unsigned char *data, unsigned short length); +int icmp6_error(struct s_mac_addr mac_dest, struct s_ipv6_addr ip_dest, + unsigned char type, unsigned char code, unsigned char *data, + unsigned short length); + #endif /* ICMP_H */ diff --git a/src/ipv4.c b/src/ipv4.c index b14993b..26a0204 100644 --- a/src/ipv4.c +++ b/src/ipv4.c @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2012 Michal Zima + * Copyright (C) 2008-2013 Michal Zima * * 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 @@ -55,6 +55,21 @@ int ipv4(struct s_ethernet *eth, char *packet) data_size = htons(ip->len) - header_size; payload = packet + header_size; + /* check and decrease TTL */ + if (ip->ttl <= 1) { + /* deny this error for ICMP (except ping/pong) + * and for non-first fragments */ + if ((ip->proto != IPPROTO_ICMP || payload[0] & 0x0 || + payload[0] & 0x08) && !(ip->flags_offset & htons(0x1fff))) { + /* code 0 = ttl exceeded in transmit */ + icmp4_error(ip->ip_src, ICMPV4_TIME_EXCEEDED, 0, + (unsigned char *) packet, htons(ip->len)); + } + return 1; + } else { + ip->ttl--; + } + switch (ip->proto) { case IPPROTO_TCP: log_debug("IPv4 Protocol: TCP"); diff --git a/src/ipv6.c b/src/ipv6.c index 34dce3f..9c5cefa 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -1,6 +1,6 @@ /* * WrapSix - * Copyright (C) 2008-2012 Michal Zima + * Copyright (C) 2008-2013 Michal Zima * * 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 @@ -50,6 +50,20 @@ int ipv6(struct s_ethernet *eth, char *packet) return 1; } + /* check and decrease hop limit */ + if (ip->hop_limit <= 1) { + /* deny this error for error ICMP messages */ + if (ip->next_header != IPPROTO_ICMPV6 || payload[0] & 0x80) { + /* code 0 = hl exceeded in transmit */ + icmp6_error(eth->src, ip->ip_src, ICMPV6_TIME_EXCEEDED, + 0, (unsigned char *) packet, + htons(ip->len) + sizeof(struct s_ipv6)); + } + return 1; + } else { + ip->hop_limit--; + } + switch (ip->next_header) { case IPPROTO_TCP: log_debug("IPv6 Protocol: TCP"); diff --git a/src/wrapper.c b/src/wrapper.c index 5ab8f76..3533343 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -41,6 +41,8 @@ #define INTERFACE "eth0" /* be sure to turn off generic-segmentation-offload! */ #define PREFIX "64:ff9b::" #define IPV4_ADDR "192.168.0.111" +#define HOST_IPV6_ADDR "fd77::1:0:1" +#define HOST_IPV4_ADDR "192.168.0.19" /* --- CONFIGURATION --- */ @@ -49,6 +51,8 @@ struct s_mac_addr mac; struct s_ipv6_addr ndp_multicast_addr; struct s_ipv6_addr wrapsix_ipv6_prefix; struct s_ipv4_addr wrapsix_ipv4_addr; +struct s_ipv6_addr host_ipv6_addr; +struct s_ipv4_addr host_ipv4_addr; int process(char *packet); @@ -115,6 +119,12 @@ int main(int argc, char **argv) /* compute binary IPv4 address of WrapSix */ inet_pton(AF_INET, IPV4_ADDR, &wrapsix_ipv4_addr); + /* compute binary IPv6 address of WrapSix host */ + inet_pton(AF_INET6, HOST_IPV6_ADDR, &host_ipv6_addr); + + /* compute binary IPv4 address of WrapSix host */ + inet_pton(AF_INET, HOST_IPV4_ADDR, &host_ipv4_addr); + /* initiate sending socket */ if (transmission_init()) { log_error("Unable to initiate sending socket"); diff --git a/src/wrapper.h b/src/wrapper.h index cd6c0cd..94c495f 100644 --- a/src/wrapper.h +++ b/src/wrapper.h @@ -32,6 +32,8 @@ extern struct s_mac_addr mac; extern struct s_ipv6_addr ndp_multicast_addr; extern struct s_ipv6_addr wrapsix_ipv6_prefix; extern struct s_ipv4_addr wrapsix_ipv4_addr; +extern struct s_ipv6_addr host_ipv6_addr; +extern struct s_ipv4_addr host_ipv4_addr; void ipv6_to_ipv4(struct s_ipv6_addr *ipv6_addr, struct s_ipv4_addr *ipv4_addr); void ipv4_to_ipv6(struct s_ipv4_addr *ipv4_addr, struct s_ipv6_addr *ipv6_addr);