1
0
mirror of https://code.semirocket.science/wrapsix synced 2024-11-08 15:21:00 +02:00

Reacting to exceeded TTL/HL

This commit is contained in:
Michal Zima 2013-02-14 14:26:01 +01:00
parent e722e80149
commit 5af1a5ca7c
6 changed files with 205 additions and 3 deletions

View File

@ -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;
}

View File

@ -1,6 +1,6 @@
/*
* WrapSix
* Copyright (C) 2008-2012 Michal Zima <xhire@mujmalysvet.cz>
* Copyright (C) 2008-2013 Michal Zima <xhire@mujmalysvet.cz>
*
* 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 */

View File

@ -1,6 +1,6 @@
/*
* WrapSix
* Copyright (C) 2008-2012 Michal Zima <xhire@mujmalysvet.cz>
* Copyright (C) 2008-2013 Michal Zima <xhire@mujmalysvet.cz>
*
* 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");

View File

@ -1,6 +1,6 @@
/*
* WrapSix
* Copyright (C) 2008-2012 Michal Zima <xhire@mujmalysvet.cz>
* Copyright (C) 2008-2013 Michal Zima <xhire@mujmalysvet.cz>
*
* 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");

View File

@ -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");

View File

@ -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);