mirror of
https://code.semirocket.science/wrapsix
synced 2024-11-23 12:09:42 +02: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:
parent
8d68658e3f
commit
4dbbcf7fc1
15
src/arp.c
15
src/arp.c
@ -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");
|
||||
|
@ -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 */
|
||||
|
67
src/icmp.c
67
src/icmp.c
@ -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);
|
||||
|
||||
|
26
src/ipv4.c
26
src/ipv4.c
@ -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
|
||||
}
|
||||
|
@ -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 */
|
||||
|
17
src/ipv6.c
17
src/ipv6.c
@ -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
|
||||
}
|
||||
|
@ -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 */
|
||||
|
70
src/tcp.c
70
src/tcp.c
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
29
src/udp.c
29
src/udp.c
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user