1
0
mirror of https://code.semirocket.science/wrapsix synced 2024-09-18 22:44:58 +03:00

Propagation of packet/payload size

More sanity checks
Fixed expiration of TTL in IPv4 packets
Optimisations
Fixed subtle mistakes
This commit is contained in:
xHire 2017-10-21 10:17:32 +02:00
parent 8d68658e3f
commit 4dbbcf7fc1
12 changed files with 201 additions and 101 deletions

View File

@ -25,18 +25,19 @@
#include "transmitter.h"
#include "wrapper.h"
#define ARP_PACKET_SIZE sizeof(struct s_ethernet) + sizeof(struct s_arp)
#define ARP_PACKET_SIZE sizeof(struct s_ethernet) + sizeof(struct s_arp)
/**
* Process ARP packets and reply to them.
*
* @param ethq Ethernet header of the packet
* @param payload Data of the packet
* @param ethq Ethernet header of the packet
* @param payload Data of the packet
* @param payload_size Size of the data payload
*
* @return 0 for success
* @return 1 for failure
*/
int arp(struct s_ethernet *ethq, char *payload)
int arp(struct s_ethernet *ethq, char *payload, unsigned short payload_size)
{
struct s_arp *arpq, *arpr; /* request and reply */
struct s_ethernet *ethr;
@ -50,6 +51,12 @@ int arp(struct s_ethernet *ethq, char *payload)
return 1;
}
/* sanity check (it's OK to do it here) */
if (payload_size < sizeof(struct s_arp)) {
log_debug("Too short ARP packet");
return 1;
}
/* test if this packet belongs to us */
if (memcmp(&wrapsix_ipv4_addr, &arpq->ip_dest, 4)) {
log_debug("This is unfamiliar ARP packet");

View File

@ -1,6 +1,6 @@
/*
* WrapSix
* Copyright (C) 2008-2013 xHire <xhire@wrapsix.org>
* Copyright (C) 2008-2017 xHire <xhire@wrapsix.org>
*
* 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
@ -46,6 +46,6 @@ struct s_arp {
struct s_ipv4_addr ip_dest; /* 32 b; target protocol addr */
} __attribute__ ((__packed__));
int arp(struct s_ethernet *ethq, char *payload);
int arp(struct s_ethernet *ethq, char *payload, unsigned short payload_size);
#endif /* ARP_H */

View File

@ -47,14 +47,13 @@ int sub_icmp6_error(struct s_ethernet *eth6,
* @param eth4 Ethernet header
* @param ip4 IPv4 header
* @param payload ICMPv4 data
* @param payload_size Size of payload; needed because IPv4 header has
* dynamic length
* @param payload_size Size of the data payload
*
* @return 0 for success
* @return 1 for failure
*/
int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4,
char *payload, unsigned short payload_size)
int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
unsigned short payload_size)
{
struct s_icmp *icmp;
unsigned int *icmp_extra;
@ -86,7 +85,7 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4,
/* ICMP checksum recheck */
orig_checksum = icmp->checksum;
icmp->checksum = 0;
icmp->checksum = 0x0;
icmp->checksum = checksum((char *) icmp, payload_size);
if (icmp->checksum != orig_checksum) {
@ -114,7 +113,7 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4,
echo->id = connection->ipv6_port_src;
/* override information in original ICMP header */
/* override information in the original ICMP header */
icmp->type = ICMPV6_ECHO_REPLY;
/* copy the payload data */
@ -164,18 +163,25 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4,
} else if (icmp->code == 4) {
icmp->type = ICMPV6_PKT_TOO_BIG;
icmp->code = 0;
/* here to write new 4B MTU value */
icmp_extra = (unsigned int *)
((char *) icmp +
sizeof(struct s_icmp));
/* from here read original 2B MTU value
* after skipping 2 unused bytes */
icmp_extra_s = (unsigned short *)
((char *) icmp +
sizeof(struct s_icmp) + 2);
if (ntohs(*icmp_extra_s) < 68) {
/* router supports path MTU discovery */
if (ntohs(*icmp_extra_s) >= 68) {
*icmp_extra = htonl(
*icmp_extra_s + 20 <
mtu ? (unsigned int)
*icmp_extra_s + 20 :
ntohs(*icmp_extra_s) +
20 < mtu ?
(unsigned int)
(ntohs(*icmp_extra_s) +
20) :
(unsigned int) mtu);
/* does not => leverage packet length */
} else {
/* RFC1191 */
/* NOTE: >= would cause infinite
@ -186,17 +192,19 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4,
if (ntohs(eip4->len) >
1006) {
*icmp_extra =
htonl(1006);
htonl(1006 +
20);
} else if (ntohs(eip4->len) >
508) {
*icmp_extra =
htonl(508);
htonl(508 + 20);
} else if (ntohs(eip4->len) >
296) {
*icmp_extra =
htonl(296);
htonl(296 + 20);
} else {
*icmp_extra = htonl(68);
*icmp_extra =
htonl(68 + 20);
}
}
} else if (icmp->code == 3) {
@ -391,6 +399,8 @@ int icmp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
/* decide the type of the ICMP packet */
switch (icmp->type) {
case ICMPV6_ECHO_REQUEST:
/* this option is already sanitized */
echo = (struct s_icmp_echo *) icmp_data;
connection = nat_out(nat6_icmp, nat4_icmp, eth6->src,
@ -437,7 +447,7 @@ int icmp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
/* sanity check */
if (payload_size < sizeof(struct s_icmp) +
sizeof(struct s_icmp_ndp_ns)) {
log_debug("Too short NDP NS");
log_debug("Too short packet for NDP NS");
return 1;
}
@ -561,7 +571,8 @@ int icmp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
/* sanity check */
if (payload_size < sizeof(struct s_icmp) + 4 +
sizeof(struct s_ipv6)) {
log_debug("Too short ICMPv6 packet 6");
log_debug("Too short ICMPv6 packet"
"PacketTooBig");
return 1;
}
@ -897,13 +908,13 @@ int sub_icmp4_error(char *payload, unsigned short payload_size,
return 1;
}
payload_size -= eip4_hlen;
payload += eip4_hlen;
/* define new inner IPv6 header */
/* new_len+4+4+40=102 < 1280 */
eip6 = (struct s_ipv6 *) (packet + *packet_len + sizeof(struct s_icmp) +
4);
/* we'll need this right now */
ipv4_to_ipv6(&eip4->ip_dest, &eip6->ip_dest);
@ -955,7 +966,8 @@ int sub_icmp4_error(char *payload, unsigned short payload_size,
/* else: */
/* sanity check */
if (payload_size < 8) {
if (payload_size < sizeof(struct s_icmp) +
sizeof(struct s_icmp_echo)) {
log_debug("Too short ICMPv4 packet 4");
return 1;
}
@ -986,7 +998,7 @@ int sub_icmp4_error(char *payload, unsigned short payload_size,
}
/* copy ICMP header to new packet */
memcpy(packet + *packet_len, *icmp, sizeof(struct s_icmp) + 4);
memcpy(packet + *packet_len, (char *) *icmp, sizeof(struct s_icmp) + 4);
*icmp = (struct s_icmp *) (packet + *packet_len);
/* complete inner IPv6 header */
@ -1074,7 +1086,7 @@ int sub_icmp6_error(struct s_ethernet *eth6,
unsigned char skip_l4 = 0;
/* sanity check */
/* sanity check; redundant only for rare 'Packet too big' */
if (payload_size < sizeof(struct s_ipv6)) {
log_debug("Too short ICMPv6 packet 2");
return 1;
@ -1103,6 +1115,7 @@ int sub_icmp6_error(struct s_ethernet *eth6,
eip4->id = htons(ntohl(eip6_frag->id));
if (ntohs(eip6_frag->offset_flag) & 0xfff8) {
/* this is not the first fragment */
skip_l4 = 1;
}
if (ntohs(eip6_frag->offset_flag) & IPV6_FLAG_MORE_FRAGMENTS) {
@ -1118,6 +1131,12 @@ int sub_icmp6_error(struct s_ethernet *eth6,
payload += sizeof(struct s_ipv6_fragment);
payload_size -= sizeof(struct s_ipv6_fragment);
} else {
eip4->id = 0x0;
eip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT);
}
/* look for the original connection */
if (skip_l4 == 0) {
/* sanity check */
/* 4 B -> L4 addrs */
if (payload_size < 4) {
@ -1125,12 +1144,6 @@ int sub_icmp6_error(struct s_ethernet *eth6,
return 1;
}
eip4->id = 0x0;
eip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT);
}
/* look for the original connection */
if (skip_l4 == 0) {
switch (eip6->next_header) {
case IPPROTO_TCP:
etcp = (struct s_tcp *) payload;
@ -1216,7 +1229,7 @@ int sub_icmp6_error(struct s_ethernet *eth6,
}
}
/* copy ICMP header to new packet */
/* copy ICMP header (with updated data) to new packet */
memcpy(packet + *packet_len, *icmp, sizeof(struct s_icmp) + 4);
*icmp = (struct s_icmp *) (packet + *packet_len);

View File

@ -31,16 +31,16 @@
*
* @param eth Ethernet header
* @param packet Packet data
* @param length Packet data length
*
* @return 0 for success
* @return 1 for failure
*/
int ipv4(struct s_ethernet *eth, char *packet)
int ipv4(struct s_ethernet *eth, char *packet, unsigned short length)
{
struct s_ipv4 *ip;
char *payload;
unsigned short header_size;
unsigned short data_size;
/* load IP header */
ip = (struct s_ipv4 *) packet;
@ -51,25 +51,34 @@ int ipv4(struct s_ethernet *eth, char *packet)
}
/* compute sizes and get payload */
header_size = (ip->ver_hdrlen & 0x0f) * 4; /* # of 4 byte words */
data_size = htons(ip->len) - header_size;
header_size = (ip->ver_hdrlen & 0x0f) * 4; /* # of 4-byte words */
/* sanity check */
if (header_size > length || ntohs(ip->len) != length) {
log_debug("IPv4 packet of an inconsistent length [dropped]");
return 1;
}
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 */
if ((ip->proto != IPPROTO_ICMP ||
payload[0] == ICMPV4_ECHO_REPLY ||
payload[0] == ICMPV4_ECHO_REQUEST) &&
!(ip->flags_offset & htons(0x1fff))) {
/* code 0 = TTL exceeded in transmit */
icmp4_error(ip->ip_src, ICMPV4_TIME_EXCEEDED, 0,
packet, htons(ip->len));
packet, length);
}
return 1;
} else {
ip->ttl--;
}
#define data_size length - header_size
switch (ip->proto) {
case IPPROTO_TCP:
log_debug("IPv4 Protocol: TCP");
@ -85,4 +94,5 @@ int ipv4(struct s_ethernet *eth, char *packet)
ip->proto, ip->proto);
return 1;
}
#undef data_size
}

View File

@ -1,6 +1,6 @@
/*
* WrapSix
* Copyright (C) 2008-2013 xHire <xhire@wrapsix.org>
* Copyright (C) 2008-2017 xHire <xhire@wrapsix.org>
*
* 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
@ -64,6 +64,6 @@ struct s_ipv4_pseudo_delta {
address */
} __attribute__ ((__packed__));
int ipv4(struct s_ethernet *eth, char *packet);
int ipv4(struct s_ethernet *eth, char *packet, unsigned short length);
#endif /* IPV4_H */

View File

@ -31,11 +31,12 @@
*
* @param eth Ethernet header
* @param packet Packet data
* @param length Packet data length
*
* @return 0 for success
* @return 1 for failure
*/
int ipv6(struct s_ethernet *eth, char *packet)
int ipv6(struct s_ethernet *eth, char *packet, unsigned short length)
{
struct s_ipv6 *ip;
char *payload;
@ -44,6 +45,12 @@ int ipv6(struct s_ethernet *eth, char *packet)
ip = (struct s_ipv6 *) packet;
payload = packet + sizeof(struct s_ipv6);
/* sanity check; len is already covered */
if (ntohs(ip->len) + sizeof(struct s_ipv6) != length) {
log_debug("IPv6 packet of an inconsistent length [dropped]");
return 1;
}
/* test if this packet belongs to us */
if (memcmp(&wrapsix_ipv6_prefix, &ip->ip_dest, 12) != 0 &&
memcmp(&ndp_multicast_addr, &ip->ip_dest, 13) != 0) {
@ -64,19 +71,21 @@ int ipv6(struct s_ethernet *eth, char *packet)
ip->hop_limit--;
}
#define data_size length - sizeof(struct s_ipv6)
switch (ip->next_header) {
case IPPROTO_TCP:
log_debug("IPv6 Protocol: TCP");
return tcp_ipv6(eth, ip, payload);
return tcp_ipv6(eth, ip, payload, data_size);
case IPPROTO_UDP:
log_debug("IPv6 Protocol: UDP");
return udp_ipv6(eth, ip, payload);
return udp_ipv6(eth, ip, payload, data_size);
case IPPROTO_ICMPV6:
log_debug("IPv6 Protocol: ICMP");
return icmp_ipv6(eth, ip, payload);
return icmp_ipv6(eth, ip, payload, data_size);
default:
log_debug("IPv6 Protocol: unknown [%d/0x%x]",
ip->next_header, ip->next_header);
return 1;
}
#undef data_size
}

View File

@ -1,6 +1,6 @@
/*
* WrapSix
* Copyright (C) 2008-2013 xHire <xhire@wrapsix.org>
* Copyright (C) 2008-2017 xHire <xhire@wrapsix.org>
*
* 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
@ -68,6 +68,6 @@ struct s_ipv6_pseudo_delta {
address */
} __attribute__ ((__packed__));
int ipv6(struct s_ethernet *eth, char *packet);
int ipv6(struct s_ethernet *eth, char *packet, unsigned short length);
#endif /* IPV6_H */

View File

@ -36,11 +36,13 @@
* Processing of incoming TCPv4 packets. Directly sends translated TCPv6
* packets.
*
* The IPv4 packet, although split into several parts, is expected to be stored
* in a continuous memory.
*
* @param eth4 Ethernet header
* @param ip4 IPv4 header
* @param payload TCPv4 data
* @param payload_size Size of payload; needed because IPv4 header has
* dynamic length
* @param payload_size Size of the data payload
*
* @return 0 for success
* @return 1 for failure
@ -67,8 +69,13 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
if ((ip4->flags_offset | htons(IPV4_FLAG_DONT_FRAGMENT)) ==
htons(IPV4_FLAG_DONT_FRAGMENT) ||
((ip4->flags_offset & htons(IPV4_FLAG_MORE_FRAGMENTS)) &&
(ip4->flags_offset & htons(0x1fff)) == 0x0000 &&
payload_size >= sizeof(struct s_tcp))) {
(ip4->flags_offset & htons(0x1fff)) == 0x0000)) {
/* sanity check */
if (payload_size < sizeof(struct s_tcp)) {
log_debug("Too short TCPv4 packet");
return 1;
}
/* parse TCP header */
tcp = (struct s_tcp *) payload;
@ -84,7 +91,7 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
if (tcp->checksum != tmp_short) {
/* packet is corrupted and shouldn't be
* processed */
log_debug("Wrong checksum");
log_debug("Wrong TCPv4 checksum");
return 1;
}
}
@ -94,7 +101,8 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
tcp->port_src, tcp->port_dest);
if (connection == NULL) {
log_debug("Incoming connection wasn't found in NAT");
log_debug("Incoming TCP connection wasn't found in "
"NAT");
return 1;
}
@ -170,13 +178,12 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
/* check if there are any saved fragments */
if (frag_conn->queue != NULL) {
log_debug("Processing TCP fragments of %d",
log_debug("Processing TCPv4 fragments of %d",
ip4->id);
llnode = frag_conn->queue->first.next;
while (llnode->next != NULL) {
llnode = llnode->next;
memcpy(&tmp_short, llnode->prev->data,
sizeof(unsigned short));
/* first is fragment size */
tcp_ipv4((struct s_ethernet *) (
(char *) llnode->prev->data +
sizeof(unsigned short)),
@ -188,7 +195,8 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
sizeof(unsigned short) +
sizeof(struct s_ethernet) +
sizeof(struct s_ipv4),
tmp_short);
*((unsigned short *)
llnode->prev->data));
free(llnode->prev->data);
linkedlist_delete(frag_conn->queue,
llnode->prev);
@ -289,7 +297,7 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
}
if (frag_conn->connection == NULL) {
log_debug("Incoming connection wasn't found in "
log_debug("Incoming TCPv4 connection wasn't found in "
"fragments table -- saving it");
if ((saved_packet = (char *) malloc(
@ -312,10 +320,9 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
memcpy(saved_packet, &payload_size,
sizeof(unsigned short));
memcpy(saved_packet + sizeof(unsigned short),
(char *) eth4, sizeof(struct s_ethernet));
memcpy(saved_packet + sizeof(unsigned short) +
sizeof(struct s_ethernet),
(char *) ip4, sizeof(struct s_ipv4));
(char *) eth4, sizeof(struct s_ethernet) +
sizeof(struct s_ipv4));
/* just in case the original IPv4 header had options */
memcpy(saved_packet + sizeof(unsigned short) +
sizeof(struct s_ethernet) +
sizeof(struct s_ipv4), payload, payload_size);
@ -349,7 +356,7 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
/* build IPv6 fragment header */
frag->next_header = IPPROTO_TCP;
frag->zeros = 0x0;
frag->id = htonl(htons(ip4->id));
frag->id = htonl(ntohs(ip4->id));
/* fragment the fragment or not? */
if (payload_size > mtu - sizeof(struct s_ipv6) -
@ -359,8 +366,8 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
sizeof(struct s_ipv6_fragment));
/* fill in missing IPv6 fragment header fields */
frag->offset_flag = htons((htons(ip4->flags_offset) <<
3) |
frag->offset_flag = htons((ntohs(ip4->flags_offset) <<
3) |
IPV6_FLAG_MORE_FRAGMENTS);
/* copy the payload data */
@ -374,9 +381,9 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
ip6->len = htons(payload_size +
sizeof(struct s_ipv6_fragment) -
FRAGMENT_LEN);
frag->offset_flag = htons(((htons(ip4->flags_offset) &
0x1fff) +
FRAGMENT_LEN / 8) << 3);
frag->offset_flag = htons(((ntohs(ip4->flags_offset) &
0x1fff) +
FRAGMENT_LEN / 8) << 3);
if (ip4->flags_offset &
htons(IPV4_FLAG_MORE_FRAGMENTS)) {
frag->offset_flag |=
@ -399,7 +406,7 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
sizeof(struct s_ipv6_fragment));
/* fill in missing IPv6 fragment header fields */
frag->offset_flag = htons(htons(ip4->flags_offset) <<
frag->offset_flag = htons(ntohs(ip4->flags_offset) <<
3);
if (ip4->flags_offset &
htons(IPV4_FLAG_MORE_FRAGMENTS)) {
@ -430,11 +437,13 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
* @param eth6 Ethernet header
* @param ip6 IPv6 header
* @param payload TCPv6 data
* @param payload_size Size of the data payload (L4+)
*
* @return 0 for success
* @return 1 for failure
*/
int tcp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
int tcp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload,
unsigned short payload_size)
{
struct s_tcp *tcp;
struct s_nat *connection;
@ -442,6 +451,12 @@ int tcp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
struct s_ipv4 *ip4;
char packet[PACKET_BUFFER];
/* sanity check */
if (payload_size < sizeof(struct s_tcp)) {
log_debug("Too short TCPv6 packet");
return 1;
}
/* parse TCP header */
tcp = (struct s_tcp *) payload;
@ -449,7 +464,7 @@ int tcp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
orig_checksum = tcp->checksum;
tcp->checksum = 0;
tcp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest,
htons(ip6->len), IPPROTO_TCP,
payload_size, IPPROTO_TCP,
(char *) payload);
if (tcp->checksum != orig_checksum) {
@ -540,7 +555,7 @@ int tcp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
ip4->ver_hdrlen = 0x45; /* ver 4, header length 20 B */
ip4->tos = ((ip6->ver & 0x0f) << 4) |
((ip6->traffic_class & 0xf0) >> 4);
ip4->len = htons(sizeof(struct s_ipv4) + htons(ip6->len));
ip4->len = htons(sizeof(struct s_ipv4) + payload_size);
ip4->id = 0x0;
ip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT);
ip4->ttl = ip6->hop_limit;
@ -559,14 +574,15 @@ int tcp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
connection->ipv4_port_src);
/* copy the payload data (with new checksum) */
memcpy(packet + sizeof(struct s_ipv4), payload, htons(ip6->len));
memcpy(packet + sizeof(struct s_ipv4), payload, payload_size);
/* compute IPv4 checksum */
ip4->checksum = 0x0;
ip4->checksum = checksum(ip4, sizeof(struct s_ipv4));
/* send translated packet */
transmit_ipv4(&ip4->ip_dest, packet, htons(ip4->len));
transmit_ipv4(&ip4->ip_dest, packet, sizeof(struct s_ipv4) +
payload_size);
return 0;
}

View File

@ -1,6 +1,6 @@
/*
* WrapSix
* Copyright (C) 2008-2012 xHire <xhire@wrapsix.org>
* Copyright (C) 2008-2017 xHire <xhire@wrapsix.org>
*
* 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
@ -45,6 +45,7 @@ struct s_tcp {
int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
unsigned short payload_size);
int tcp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload);
int tcp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload,
unsigned short payload_size);
#endif /* TCP_H */

View File

@ -38,8 +38,7 @@
* @param eth4 Ethernet header
* @param ip4 IPv4 header
* @param payload UDPv4 data
* @param payload_size Size of payload; needed because IPv4 header has
* dynamic length
* @param payload_size Size of the data payload
*
* @return 0 for success
* @return 1 for failure
@ -58,6 +57,13 @@ int udp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
/* parse UDP header */
udp = (struct s_udp *) payload;
/* sanity check again; the second one is not strictly needed */
if (payload_size < sizeof(struct s_udp) ||
payload_size != ntohs(udp->len)) {
log_debug("Too short/malformed UDPv4 packet");
return 1;
}
/* checksum recheck */
if (udp->checksum != 0x0000) {
orig_checksum = udp->checksum;
@ -138,11 +144,13 @@ int udp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
* @param eth6 Ethernet header
* @param ip6 IPv6 header
* @param payload UDPv6 data
* @param payload_size Size of the data payload
*
* @return 0 for success
* @return 1 for failure
*/
int udp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
int udp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload,
unsigned short payload_size)
{
struct s_udp *udp;
struct s_nat *connection;
@ -154,11 +162,18 @@ int udp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
/* parse UDP header */
udp = (struct s_udp *) payload;
/* sanity check again; the second one is not strictly needed */
if (payload_size < sizeof(struct s_udp) ||
payload_size != ntohs(udp->len)) {
log_debug("Too short/malformed UDPv6 packet");
return 1;
}
/* checksum recheck */
orig_checksum = udp->checksum;
udp->checksum = 0;
udp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest,
htons(ip6->len), IPPROTO_UDP, payload);
udp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest, payload_size,
IPPROTO_UDP, payload);
if (udp->checksum != orig_checksum) {
/* packet is corrupted and shouldn't be processed */
@ -185,7 +200,7 @@ int udp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
/* translated packet */
ip4 = (struct s_ipv4 *) packet;
packet_size = sizeof(struct s_ipv4) + htons(ip6->len);
packet_size = sizeof(struct s_ipv4) + payload_size;
/* build IPv4 packet */
ip4->ver_hdrlen = 0x45; /* ver 4, header length 20 B */
@ -210,7 +225,7 @@ int udp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
connection->ipv4_port_src);
/* copy the payload data (with new checksum) */
memcpy(packet + sizeof(struct s_ipv4), payload, htons(ip6->len));
memcpy(packet + sizeof(struct s_ipv4), payload, payload_size);
/* compute IPv4 checksum */
ip4->checksum = 0x0;

View File

@ -1,6 +1,6 @@
/*
* WrapSix
* Copyright (C) 2008-2012 xHire <xhire@wrapsix.org>
* Copyright (C) 2008-2017 xHire <xhire@wrapsix.org>
*
* 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
@ -29,6 +29,7 @@ struct s_udp {
int udp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
unsigned short payload_size);
int udp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload);
int udp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload,
unsigned short payload_size);
#endif /* UDP_H */

View File

@ -24,9 +24,11 @@
#include <net/if.h> /* struct ifreq */
#include <netinet/in.h> /* htons */
#include <netpacket/packet.h> /* struct packet_mreq, struct sockaddr_ll */
#include <stdio.h> /* perror */
#include <stdlib.h> /* srand */
#include <string.h> /* strncpy */
#include <sys/ioctl.h> /* ioctl, SIOCGIFINDEX */
#include <sys/types.h> /* caddr_t */
#include <time.h> /* time, time_t */
#include <unistd.h> /* close */
@ -36,6 +38,7 @@
#endif /* HAVE_CONFIG_H */
#include "config.h"
#include "ethernet.h"
#include "icmp.h"
#include "ipv4.h"
#include "ipv6.h"
#include "log.h"
@ -53,7 +56,7 @@ 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);
static int process(char *packet, unsigned short length);
int main(int argc, char **argv)
{
@ -177,13 +180,21 @@ int main(int argc, char **argv)
/* sniff! :c) */
for (i = 1;; i++) {
if ((length = recv(sniff_sock, buffer, PACKET_BUFFER, 0)) ==
-1) {
length = recv(sniff_sock, buffer, PACKET_BUFFER, MSG_TRUNC);
if (length == -1) {
perror("recv");
log_error("Unable to retrieve data from socket");
return 1;
}
process((char *) &buffer);
if (length > PACKET_BUFFER) {
log_error("Received packet is too big (%d B). Please "
"tune NIC offloading features and report "
"this issue to " PACKAGE_BUGREPORT, length);
continue;
}
process(buffer, length);
if (i % 250000) {
curtime = time(NULL);
@ -217,29 +228,46 @@ int main(int argc, char **argv)
return 0;
}
int process(char *packet)
/**
* Decide what to do with a packet and pass it for further processing.
*
* @param packet Packet data
* @param length Packet data length
*
* @return 0 for success
* @return 1 for failure
*/
static int process(char *packet, unsigned short length)
{
struct s_ethernet *eth; /* the ethernet header */
char *payload; /* the IP header + packet
payload */
struct s_ethernet *eth;
/* sanity check: out of every combination this is the smallest one */
if (length < sizeof(struct s_ethernet) + sizeof(struct s_ipv4) +
sizeof(struct s_icmp)) {
return 1;
}
/* parse ethernet header */
eth = (struct s_ethernet *) (packet);
payload = packet + sizeof(struct s_ethernet);
eth = (struct s_ethernet *) packet;
#define payload packet + sizeof(struct s_ethernet)
#define payload_length length - sizeof(struct s_ethernet)
switch (htons(eth->type)) {
case ETHERTYPE_IP:
return ipv4(eth, payload);
return ipv4(eth, payload, payload_length);
case ETHERTYPE_IPV6:
return ipv6(eth, payload);
return ipv6(eth, payload, payload_length);
case ETHERTYPE_ARP:
log_debug("HW Protocol: ARP");
return arp(eth, payload);
return arp(eth, payload, payload_length);
default:
log_debug("HW Protocol: unknown [%d/0x%04x]",
htons(eth->type), htons(eth->type));
return 1;
}
#undef payload_length
#undef payload
}
/**