mirror of
https://code.semirocket.science/wrapsix
synced 2024-11-09 15:51:14 +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 "transmitter.h"
|
||||||
#include "wrapper.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.
|
* Process ARP packets and reply to them.
|
||||||
*
|
*
|
||||||
* @param ethq Ethernet header of the packet
|
* @param ethq Ethernet header of the packet
|
||||||
* @param payload Data of the packet
|
* @param payload Data of the packet
|
||||||
|
* @param payload_size Size of the data payload
|
||||||
*
|
*
|
||||||
* @return 0 for success
|
* @return 0 for success
|
||||||
* @return 1 for failure
|
* @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_arp *arpq, *arpr; /* request and reply */
|
||||||
struct s_ethernet *ethr;
|
struct s_ethernet *ethr;
|
||||||
@ -50,6 +51,12 @@ int arp(struct s_ethernet *ethq, char *payload)
|
|||||||
return 1;
|
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 */
|
/* test if this packet belongs to us */
|
||||||
if (memcmp(&wrapsix_ipv4_addr, &arpq->ip_dest, 4)) {
|
if (memcmp(&wrapsix_ipv4_addr, &arpq->ip_dest, 4)) {
|
||||||
log_debug("This is unfamiliar ARP packet");
|
log_debug("This is unfamiliar ARP packet");
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* WrapSix
|
* 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
|
* 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
|
* 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 */
|
struct s_ipv4_addr ip_dest; /* 32 b; target protocol addr */
|
||||||
} __attribute__ ((__packed__));
|
} __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 */
|
#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 eth4 Ethernet header
|
||||||
* @param ip4 IPv4 header
|
* @param ip4 IPv4 header
|
||||||
* @param payload ICMPv4 data
|
* @param payload ICMPv4 data
|
||||||
* @param payload_size Size of payload; needed because IPv4 header has
|
* @param payload_size Size of the data payload
|
||||||
* dynamic length
|
|
||||||
*
|
*
|
||||||
* @return 0 for success
|
* @return 0 for success
|
||||||
* @return 1 for failure
|
* @return 1 for failure
|
||||||
*/
|
*/
|
||||||
int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4,
|
int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
||||||
char *payload, unsigned short payload_size)
|
unsigned short payload_size)
|
||||||
{
|
{
|
||||||
struct s_icmp *icmp;
|
struct s_icmp *icmp;
|
||||||
unsigned int *icmp_extra;
|
unsigned int *icmp_extra;
|
||||||
@ -86,7 +85,7 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4,
|
|||||||
|
|
||||||
/* ICMP checksum recheck */
|
/* ICMP checksum recheck */
|
||||||
orig_checksum = icmp->checksum;
|
orig_checksum = icmp->checksum;
|
||||||
icmp->checksum = 0;
|
icmp->checksum = 0x0;
|
||||||
icmp->checksum = checksum((char *) icmp, payload_size);
|
icmp->checksum = checksum((char *) icmp, payload_size);
|
||||||
|
|
||||||
if (icmp->checksum != orig_checksum) {
|
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;
|
echo->id = connection->ipv6_port_src;
|
||||||
|
|
||||||
/* override information in original ICMP header */
|
/* override information in the original ICMP header */
|
||||||
icmp->type = ICMPV6_ECHO_REPLY;
|
icmp->type = ICMPV6_ECHO_REPLY;
|
||||||
|
|
||||||
/* copy the payload data */
|
/* copy the payload data */
|
||||||
@ -164,18 +163,25 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4,
|
|||||||
} else if (icmp->code == 4) {
|
} else if (icmp->code == 4) {
|
||||||
icmp->type = ICMPV6_PKT_TOO_BIG;
|
icmp->type = ICMPV6_PKT_TOO_BIG;
|
||||||
icmp->code = 0;
|
icmp->code = 0;
|
||||||
|
/* here to write new 4B MTU value */
|
||||||
icmp_extra = (unsigned int *)
|
icmp_extra = (unsigned int *)
|
||||||
((char *) icmp +
|
((char *) icmp +
|
||||||
sizeof(struct s_icmp));
|
sizeof(struct s_icmp));
|
||||||
|
/* from here read original 2B MTU value
|
||||||
|
* after skipping 2 unused bytes */
|
||||||
icmp_extra_s = (unsigned short *)
|
icmp_extra_s = (unsigned short *)
|
||||||
((char *) icmp +
|
((char *) icmp +
|
||||||
sizeof(struct s_icmp) + 2);
|
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 = htonl(
|
||||||
*icmp_extra_s + 20 <
|
ntohs(*icmp_extra_s) +
|
||||||
mtu ? (unsigned int)
|
20 < mtu ?
|
||||||
*icmp_extra_s + 20 :
|
(unsigned int)
|
||||||
|
(ntohs(*icmp_extra_s) +
|
||||||
|
20) :
|
||||||
(unsigned int) mtu);
|
(unsigned int) mtu);
|
||||||
|
/* does not => leverage packet length */
|
||||||
} else {
|
} else {
|
||||||
/* RFC1191 */
|
/* RFC1191 */
|
||||||
/* NOTE: >= would cause infinite
|
/* NOTE: >= would cause infinite
|
||||||
@ -186,17 +192,19 @@ int icmp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4,
|
|||||||
if (ntohs(eip4->len) >
|
if (ntohs(eip4->len) >
|
||||||
1006) {
|
1006) {
|
||||||
*icmp_extra =
|
*icmp_extra =
|
||||||
htonl(1006);
|
htonl(1006 +
|
||||||
|
20);
|
||||||
} else if (ntohs(eip4->len) >
|
} else if (ntohs(eip4->len) >
|
||||||
508) {
|
508) {
|
||||||
*icmp_extra =
|
*icmp_extra =
|
||||||
htonl(508);
|
htonl(508 + 20);
|
||||||
} else if (ntohs(eip4->len) >
|
} else if (ntohs(eip4->len) >
|
||||||
296) {
|
296) {
|
||||||
*icmp_extra =
|
*icmp_extra =
|
||||||
htonl(296);
|
htonl(296 + 20);
|
||||||
} else {
|
} else {
|
||||||
*icmp_extra = htonl(68);
|
*icmp_extra =
|
||||||
|
htonl(68 + 20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (icmp->code == 3) {
|
} 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 */
|
/* decide the type of the ICMP packet */
|
||||||
switch (icmp->type) {
|
switch (icmp->type) {
|
||||||
case ICMPV6_ECHO_REQUEST:
|
case ICMPV6_ECHO_REQUEST:
|
||||||
|
/* this option is already sanitized */
|
||||||
|
|
||||||
echo = (struct s_icmp_echo *) icmp_data;
|
echo = (struct s_icmp_echo *) icmp_data;
|
||||||
|
|
||||||
connection = nat_out(nat6_icmp, nat4_icmp, eth6->src,
|
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 */
|
/* sanity check */
|
||||||
if (payload_size < sizeof(struct s_icmp) +
|
if (payload_size < sizeof(struct s_icmp) +
|
||||||
sizeof(struct s_icmp_ndp_ns)) {
|
sizeof(struct s_icmp_ndp_ns)) {
|
||||||
log_debug("Too short NDP NS");
|
log_debug("Too short packet for NDP NS");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,7 +571,8 @@ int icmp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
|
|||||||
/* sanity check */
|
/* sanity check */
|
||||||
if (payload_size < sizeof(struct s_icmp) + 4 +
|
if (payload_size < sizeof(struct s_icmp) + 4 +
|
||||||
sizeof(struct s_ipv6)) {
|
sizeof(struct s_ipv6)) {
|
||||||
log_debug("Too short ICMPv6 packet 6");
|
log_debug("Too short ICMPv6 packet"
|
||||||
|
"PacketTooBig");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -897,13 +908,13 @@ int sub_icmp4_error(char *payload, unsigned short payload_size,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
payload_size -= eip4_hlen;
|
payload_size -= eip4_hlen;
|
||||||
|
|
||||||
payload += eip4_hlen;
|
payload += eip4_hlen;
|
||||||
|
|
||||||
/* define new inner IPv6 header */
|
/* define new inner IPv6 header */
|
||||||
/* new_len+4+4+40=102 < 1280 */
|
/* new_len+4+4+40=102 < 1280 */
|
||||||
eip6 = (struct s_ipv6 *) (packet + *packet_len + sizeof(struct s_icmp) +
|
eip6 = (struct s_ipv6 *) (packet + *packet_len + sizeof(struct s_icmp) +
|
||||||
4);
|
4);
|
||||||
|
|
||||||
/* we'll need this right now */
|
/* we'll need this right now */
|
||||||
ipv4_to_ipv6(&eip4->ip_dest, &eip6->ip_dest);
|
ipv4_to_ipv6(&eip4->ip_dest, &eip6->ip_dest);
|
||||||
|
|
||||||
@ -955,7 +966,8 @@ int sub_icmp4_error(char *payload, unsigned short payload_size,
|
|||||||
/* else: */
|
/* else: */
|
||||||
|
|
||||||
/* sanity check */
|
/* 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");
|
log_debug("Too short ICMPv4 packet 4");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -986,7 +998,7 @@ int sub_icmp4_error(char *payload, unsigned short payload_size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* copy ICMP header to new packet */
|
/* 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);
|
*icmp = (struct s_icmp *) (packet + *packet_len);
|
||||||
|
|
||||||
/* complete inner IPv6 header */
|
/* complete inner IPv6 header */
|
||||||
@ -1074,7 +1086,7 @@ int sub_icmp6_error(struct s_ethernet *eth6,
|
|||||||
|
|
||||||
unsigned char skip_l4 = 0;
|
unsigned char skip_l4 = 0;
|
||||||
|
|
||||||
/* sanity check */
|
/* sanity check; redundant only for rare 'Packet too big' */
|
||||||
if (payload_size < sizeof(struct s_ipv6)) {
|
if (payload_size < sizeof(struct s_ipv6)) {
|
||||||
log_debug("Too short ICMPv6 packet 2");
|
log_debug("Too short ICMPv6 packet 2");
|
||||||
return 1;
|
return 1;
|
||||||
@ -1103,6 +1115,7 @@ int sub_icmp6_error(struct s_ethernet *eth6,
|
|||||||
|
|
||||||
eip4->id = htons(ntohl(eip6_frag->id));
|
eip4->id = htons(ntohl(eip6_frag->id));
|
||||||
if (ntohs(eip6_frag->offset_flag) & 0xfff8) {
|
if (ntohs(eip6_frag->offset_flag) & 0xfff8) {
|
||||||
|
/* this is not the first fragment */
|
||||||
skip_l4 = 1;
|
skip_l4 = 1;
|
||||||
}
|
}
|
||||||
if (ntohs(eip6_frag->offset_flag) & IPV6_FLAG_MORE_FRAGMENTS) {
|
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 += sizeof(struct s_ipv6_fragment);
|
||||||
payload_size -= sizeof(struct s_ipv6_fragment);
|
payload_size -= sizeof(struct s_ipv6_fragment);
|
||||||
} else {
|
} else {
|
||||||
|
eip4->id = 0x0;
|
||||||
|
eip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look for the original connection */
|
||||||
|
if (skip_l4 == 0) {
|
||||||
/* sanity check */
|
/* sanity check */
|
||||||
/* 4 B -> L4 addrs */
|
/* 4 B -> L4 addrs */
|
||||||
if (payload_size < 4) {
|
if (payload_size < 4) {
|
||||||
@ -1125,12 +1144,6 @@ int sub_icmp6_error(struct s_ethernet *eth6,
|
|||||||
return 1;
|
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) {
|
switch (eip6->next_header) {
|
||||||
case IPPROTO_TCP:
|
case IPPROTO_TCP:
|
||||||
etcp = (struct s_tcp *) payload;
|
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);
|
memcpy(packet + *packet_len, *icmp, sizeof(struct s_icmp) + 4);
|
||||||
*icmp = (struct s_icmp *) (packet + *packet_len);
|
*icmp = (struct s_icmp *) (packet + *packet_len);
|
||||||
|
|
||||||
|
26
src/ipv4.c
26
src/ipv4.c
@ -31,16 +31,16 @@
|
|||||||
*
|
*
|
||||||
* @param eth Ethernet header
|
* @param eth Ethernet header
|
||||||
* @param packet Packet data
|
* @param packet Packet data
|
||||||
|
* @param length Packet data length
|
||||||
*
|
*
|
||||||
* @return 0 for success
|
* @return 0 for success
|
||||||
* @return 1 for failure
|
* @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;
|
struct s_ipv4 *ip;
|
||||||
char *payload;
|
char *payload;
|
||||||
unsigned short header_size;
|
unsigned short header_size;
|
||||||
unsigned short data_size;
|
|
||||||
|
|
||||||
/* load IP header */
|
/* load IP header */
|
||||||
ip = (struct s_ipv4 *) packet;
|
ip = (struct s_ipv4 *) packet;
|
||||||
@ -51,25 +51,34 @@ int ipv4(struct s_ethernet *eth, char *packet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* compute sizes and get payload */
|
/* compute sizes and get payload */
|
||||||
header_size = (ip->ver_hdrlen & 0x0f) * 4; /* # of 4 byte words */
|
header_size = (ip->ver_hdrlen & 0x0f) * 4; /* # of 4-byte words */
|
||||||
data_size = htons(ip->len) - header_size;
|
|
||||||
|
/* 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;
|
payload = packet + header_size;
|
||||||
|
|
||||||
/* check and decrease TTL */
|
/* check and decrease TTL */
|
||||||
if (ip->ttl <= 1) {
|
if (ip->ttl <= 1) {
|
||||||
/* deny this error for ICMP (except ping/pong)
|
/* deny this error for ICMP (except ping/pong)
|
||||||
* and for non-first fragments */
|
* and for non-first fragments */
|
||||||
if ((ip->proto != IPPROTO_ICMP || payload[0] & 0x0 ||
|
if ((ip->proto != IPPROTO_ICMP ||
|
||||||
payload[0] & 0x08) && !(ip->flags_offset & htons(0x1fff))) {
|
payload[0] == ICMPV4_ECHO_REPLY ||
|
||||||
/* code 0 = ttl exceeded in transmit */
|
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,
|
icmp4_error(ip->ip_src, ICMPV4_TIME_EXCEEDED, 0,
|
||||||
packet, htons(ip->len));
|
packet, length);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
ip->ttl--;
|
ip->ttl--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define data_size length - header_size
|
||||||
switch (ip->proto) {
|
switch (ip->proto) {
|
||||||
case IPPROTO_TCP:
|
case IPPROTO_TCP:
|
||||||
log_debug("IPv4 Protocol: TCP");
|
log_debug("IPv4 Protocol: TCP");
|
||||||
@ -85,4 +94,5 @@ int ipv4(struct s_ethernet *eth, char *packet)
|
|||||||
ip->proto, ip->proto);
|
ip->proto, ip->proto);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#undef data_size
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* WrapSix
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -64,6 +64,6 @@ struct s_ipv4_pseudo_delta {
|
|||||||
address */
|
address */
|
||||||
} __attribute__ ((__packed__));
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
int ipv4(struct s_ethernet *eth, char *packet);
|
int ipv4(struct s_ethernet *eth, char *packet, unsigned short length);
|
||||||
|
|
||||||
#endif /* IPV4_H */
|
#endif /* IPV4_H */
|
||||||
|
17
src/ipv6.c
17
src/ipv6.c
@ -31,11 +31,12 @@
|
|||||||
*
|
*
|
||||||
* @param eth Ethernet header
|
* @param eth Ethernet header
|
||||||
* @param packet Packet data
|
* @param packet Packet data
|
||||||
|
* @param length Packet data length
|
||||||
*
|
*
|
||||||
* @return 0 for success
|
* @return 0 for success
|
||||||
* @return 1 for failure
|
* @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;
|
struct s_ipv6 *ip;
|
||||||
char *payload;
|
char *payload;
|
||||||
@ -44,6 +45,12 @@ int ipv6(struct s_ethernet *eth, char *packet)
|
|||||||
ip = (struct s_ipv6 *) packet;
|
ip = (struct s_ipv6 *) packet;
|
||||||
payload = packet + sizeof(struct s_ipv6);
|
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 */
|
/* test if this packet belongs to us */
|
||||||
if (memcmp(&wrapsix_ipv6_prefix, &ip->ip_dest, 12) != 0 &&
|
if (memcmp(&wrapsix_ipv6_prefix, &ip->ip_dest, 12) != 0 &&
|
||||||
memcmp(&ndp_multicast_addr, &ip->ip_dest, 13) != 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--;
|
ip->hop_limit--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define data_size length - sizeof(struct s_ipv6)
|
||||||
switch (ip->next_header) {
|
switch (ip->next_header) {
|
||||||
case IPPROTO_TCP:
|
case IPPROTO_TCP:
|
||||||
log_debug("IPv6 Protocol: TCP");
|
log_debug("IPv6 Protocol: TCP");
|
||||||
return tcp_ipv6(eth, ip, payload);
|
return tcp_ipv6(eth, ip, payload, data_size);
|
||||||
case IPPROTO_UDP:
|
case IPPROTO_UDP:
|
||||||
log_debug("IPv6 Protocol: UDP");
|
log_debug("IPv6 Protocol: UDP");
|
||||||
return udp_ipv6(eth, ip, payload);
|
return udp_ipv6(eth, ip, payload, data_size);
|
||||||
case IPPROTO_ICMPV6:
|
case IPPROTO_ICMPV6:
|
||||||
log_debug("IPv6 Protocol: ICMP");
|
log_debug("IPv6 Protocol: ICMP");
|
||||||
return icmp_ipv6(eth, ip, payload);
|
return icmp_ipv6(eth, ip, payload, data_size);
|
||||||
default:
|
default:
|
||||||
log_debug("IPv6 Protocol: unknown [%d/0x%x]",
|
log_debug("IPv6 Protocol: unknown [%d/0x%x]",
|
||||||
ip->next_header, ip->next_header);
|
ip->next_header, ip->next_header);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#undef data_size
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* WrapSix
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -68,6 +68,6 @@ struct s_ipv6_pseudo_delta {
|
|||||||
address */
|
address */
|
||||||
} __attribute__ ((__packed__));
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
int ipv6(struct s_ethernet *eth, char *packet);
|
int ipv6(struct s_ethernet *eth, char *packet, unsigned short length);
|
||||||
|
|
||||||
#endif /* IPV6_H */
|
#endif /* IPV6_H */
|
||||||
|
70
src/tcp.c
70
src/tcp.c
@ -36,11 +36,13 @@
|
|||||||
* Processing of incoming TCPv4 packets. Directly sends translated TCPv6
|
* Processing of incoming TCPv4 packets. Directly sends translated TCPv6
|
||||||
* packets.
|
* packets.
|
||||||
*
|
*
|
||||||
|
* The IPv4 packet, although split into several parts, is expected to be stored
|
||||||
|
* in a continuous memory.
|
||||||
|
*
|
||||||
* @param eth4 Ethernet header
|
* @param eth4 Ethernet header
|
||||||
* @param ip4 IPv4 header
|
* @param ip4 IPv4 header
|
||||||
* @param payload TCPv4 data
|
* @param payload TCPv4 data
|
||||||
* @param payload_size Size of payload; needed because IPv4 header has
|
* @param payload_size Size of the data payload
|
||||||
* dynamic length
|
|
||||||
*
|
*
|
||||||
* @return 0 for success
|
* @return 0 for success
|
||||||
* @return 1 for failure
|
* @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)) ==
|
if ((ip4->flags_offset | htons(IPV4_FLAG_DONT_FRAGMENT)) ==
|
||||||
htons(IPV4_FLAG_DONT_FRAGMENT) ||
|
htons(IPV4_FLAG_DONT_FRAGMENT) ||
|
||||||
((ip4->flags_offset & htons(IPV4_FLAG_MORE_FRAGMENTS)) &&
|
((ip4->flags_offset & htons(IPV4_FLAG_MORE_FRAGMENTS)) &&
|
||||||
(ip4->flags_offset & htons(0x1fff)) == 0x0000 &&
|
(ip4->flags_offset & htons(0x1fff)) == 0x0000)) {
|
||||||
payload_size >= sizeof(struct s_tcp))) {
|
/* sanity check */
|
||||||
|
if (payload_size < sizeof(struct s_tcp)) {
|
||||||
|
log_debug("Too short TCPv4 packet");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* parse TCP header */
|
/* parse TCP header */
|
||||||
tcp = (struct s_tcp *) payload;
|
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) {
|
if (tcp->checksum != tmp_short) {
|
||||||
/* packet is corrupted and shouldn't be
|
/* packet is corrupted and shouldn't be
|
||||||
* processed */
|
* processed */
|
||||||
log_debug("Wrong checksum");
|
log_debug("Wrong TCPv4 checksum");
|
||||||
return 1;
|
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);
|
tcp->port_src, tcp->port_dest);
|
||||||
|
|
||||||
if (connection == NULL) {
|
if (connection == NULL) {
|
||||||
log_debug("Incoming connection wasn't found in NAT");
|
log_debug("Incoming TCP connection wasn't found in "
|
||||||
|
"NAT");
|
||||||
return 1;
|
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 */
|
/* check if there are any saved fragments */
|
||||||
if (frag_conn->queue != NULL) {
|
if (frag_conn->queue != NULL) {
|
||||||
log_debug("Processing TCP fragments of %d",
|
log_debug("Processing TCPv4 fragments of %d",
|
||||||
ip4->id);
|
ip4->id);
|
||||||
llnode = frag_conn->queue->first.next;
|
llnode = frag_conn->queue->first.next;
|
||||||
while (llnode->next != NULL) {
|
while (llnode->next != NULL) {
|
||||||
llnode = llnode->next;
|
llnode = llnode->next;
|
||||||
memcpy(&tmp_short, llnode->prev->data,
|
/* first is fragment size */
|
||||||
sizeof(unsigned short));
|
|
||||||
tcp_ipv4((struct s_ethernet *) (
|
tcp_ipv4((struct s_ethernet *) (
|
||||||
(char *) llnode->prev->data +
|
(char *) llnode->prev->data +
|
||||||
sizeof(unsigned short)),
|
sizeof(unsigned short)),
|
||||||
@ -188,7 +195,8 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
|||||||
sizeof(unsigned short) +
|
sizeof(unsigned short) +
|
||||||
sizeof(struct s_ethernet) +
|
sizeof(struct s_ethernet) +
|
||||||
sizeof(struct s_ipv4),
|
sizeof(struct s_ipv4),
|
||||||
tmp_short);
|
*((unsigned short *)
|
||||||
|
llnode->prev->data));
|
||||||
free(llnode->prev->data);
|
free(llnode->prev->data);
|
||||||
linkedlist_delete(frag_conn->queue,
|
linkedlist_delete(frag_conn->queue,
|
||||||
llnode->prev);
|
llnode->prev);
|
||||||
@ -289,7 +297,7 @@ int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (frag_conn->connection == NULL) {
|
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");
|
"fragments table -- saving it");
|
||||||
|
|
||||||
if ((saved_packet = (char *) malloc(
|
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,
|
memcpy(saved_packet, &payload_size,
|
||||||
sizeof(unsigned short));
|
sizeof(unsigned short));
|
||||||
memcpy(saved_packet + sizeof(unsigned short),
|
memcpy(saved_packet + sizeof(unsigned short),
|
||||||
(char *) eth4, sizeof(struct s_ethernet));
|
(char *) eth4, sizeof(struct s_ethernet) +
|
||||||
memcpy(saved_packet + sizeof(unsigned short) +
|
sizeof(struct s_ipv4));
|
||||||
sizeof(struct s_ethernet),
|
/* just in case the original IPv4 header had options */
|
||||||
(char *) ip4, sizeof(struct s_ipv4));
|
|
||||||
memcpy(saved_packet + sizeof(unsigned short) +
|
memcpy(saved_packet + sizeof(unsigned short) +
|
||||||
sizeof(struct s_ethernet) +
|
sizeof(struct s_ethernet) +
|
||||||
sizeof(struct s_ipv4), payload, payload_size);
|
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 */
|
/* build IPv6 fragment header */
|
||||||
frag->next_header = IPPROTO_TCP;
|
frag->next_header = IPPROTO_TCP;
|
||||||
frag->zeros = 0x0;
|
frag->zeros = 0x0;
|
||||||
frag->id = htonl(htons(ip4->id));
|
frag->id = htonl(ntohs(ip4->id));
|
||||||
|
|
||||||
/* fragment the fragment or not? */
|
/* fragment the fragment or not? */
|
||||||
if (payload_size > mtu - sizeof(struct s_ipv6) -
|
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));
|
sizeof(struct s_ipv6_fragment));
|
||||||
|
|
||||||
/* fill in missing IPv6 fragment header fields */
|
/* fill in missing IPv6 fragment header fields */
|
||||||
frag->offset_flag = htons((htons(ip4->flags_offset) <<
|
frag->offset_flag = htons((ntohs(ip4->flags_offset) <<
|
||||||
3) |
|
3) |
|
||||||
IPV6_FLAG_MORE_FRAGMENTS);
|
IPV6_FLAG_MORE_FRAGMENTS);
|
||||||
|
|
||||||
/* copy the payload data */
|
/* 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 +
|
ip6->len = htons(payload_size +
|
||||||
sizeof(struct s_ipv6_fragment) -
|
sizeof(struct s_ipv6_fragment) -
|
||||||
FRAGMENT_LEN);
|
FRAGMENT_LEN);
|
||||||
frag->offset_flag = htons(((htons(ip4->flags_offset) &
|
frag->offset_flag = htons(((ntohs(ip4->flags_offset) &
|
||||||
0x1fff) +
|
0x1fff) +
|
||||||
FRAGMENT_LEN / 8) << 3);
|
FRAGMENT_LEN / 8) << 3);
|
||||||
if (ip4->flags_offset &
|
if (ip4->flags_offset &
|
||||||
htons(IPV4_FLAG_MORE_FRAGMENTS)) {
|
htons(IPV4_FLAG_MORE_FRAGMENTS)) {
|
||||||
frag->offset_flag |=
|
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));
|
sizeof(struct s_ipv6_fragment));
|
||||||
|
|
||||||
/* fill in missing IPv6 fragment header fields */
|
/* fill in missing IPv6 fragment header fields */
|
||||||
frag->offset_flag = htons(htons(ip4->flags_offset) <<
|
frag->offset_flag = htons(ntohs(ip4->flags_offset) <<
|
||||||
3);
|
3);
|
||||||
if (ip4->flags_offset &
|
if (ip4->flags_offset &
|
||||||
htons(IPV4_FLAG_MORE_FRAGMENTS)) {
|
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 eth6 Ethernet header
|
||||||
* @param ip6 IPv6 header
|
* @param ip6 IPv6 header
|
||||||
* @param payload TCPv6 data
|
* @param payload TCPv6 data
|
||||||
|
* @param payload_size Size of the data payload (L4+)
|
||||||
*
|
*
|
||||||
* @return 0 for success
|
* @return 0 for success
|
||||||
* @return 1 for failure
|
* @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_tcp *tcp;
|
||||||
struct s_nat *connection;
|
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;
|
struct s_ipv4 *ip4;
|
||||||
char packet[PACKET_BUFFER];
|
char packet[PACKET_BUFFER];
|
||||||
|
|
||||||
|
/* sanity check */
|
||||||
|
if (payload_size < sizeof(struct s_tcp)) {
|
||||||
|
log_debug("Too short TCPv6 packet");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* parse TCP header */
|
/* parse TCP header */
|
||||||
tcp = (struct s_tcp *) payload;
|
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;
|
orig_checksum = tcp->checksum;
|
||||||
tcp->checksum = 0;
|
tcp->checksum = 0;
|
||||||
tcp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest,
|
tcp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest,
|
||||||
htons(ip6->len), IPPROTO_TCP,
|
payload_size, IPPROTO_TCP,
|
||||||
(char *) payload);
|
(char *) payload);
|
||||||
|
|
||||||
if (tcp->checksum != orig_checksum) {
|
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->ver_hdrlen = 0x45; /* ver 4, header length 20 B */
|
||||||
ip4->tos = ((ip6->ver & 0x0f) << 4) |
|
ip4->tos = ((ip6->ver & 0x0f) << 4) |
|
||||||
((ip6->traffic_class & 0xf0) >> 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->id = 0x0;
|
||||||
ip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT);
|
ip4->flags_offset = htons(IPV4_FLAG_DONT_FRAGMENT);
|
||||||
ip4->ttl = ip6->hop_limit;
|
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);
|
connection->ipv4_port_src);
|
||||||
|
|
||||||
/* copy the payload data (with new checksum) */
|
/* 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 */
|
/* compute IPv4 checksum */
|
||||||
ip4->checksum = 0x0;
|
ip4->checksum = 0x0;
|
||||||
ip4->checksum = checksum(ip4, sizeof(struct s_ipv4));
|
ip4->checksum = checksum(ip4, sizeof(struct s_ipv4));
|
||||||
|
|
||||||
/* send translated packet */
|
/* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* WrapSix
|
* 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
|
* 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
|
* 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,
|
int tcp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
||||||
unsigned short payload_size);
|
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 */
|
#endif /* TCP_H */
|
||||||
|
29
src/udp.c
29
src/udp.c
@ -38,8 +38,7 @@
|
|||||||
* @param eth4 Ethernet header
|
* @param eth4 Ethernet header
|
||||||
* @param ip4 IPv4 header
|
* @param ip4 IPv4 header
|
||||||
* @param payload UDPv4 data
|
* @param payload UDPv4 data
|
||||||
* @param payload_size Size of payload; needed because IPv4 header has
|
* @param payload_size Size of the data payload
|
||||||
* dynamic length
|
|
||||||
*
|
*
|
||||||
* @return 0 for success
|
* @return 0 for success
|
||||||
* @return 1 for failure
|
* @return 1 for failure
|
||||||
@ -58,6 +57,13 @@ int udp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
|||||||
/* parse UDP header */
|
/* parse UDP header */
|
||||||
udp = (struct s_udp *) payload;
|
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 */
|
/* checksum recheck */
|
||||||
if (udp->checksum != 0x0000) {
|
if (udp->checksum != 0x0000) {
|
||||||
orig_checksum = udp->checksum;
|
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 eth6 Ethernet header
|
||||||
* @param ip6 IPv6 header
|
* @param ip6 IPv6 header
|
||||||
* @param payload UDPv6 data
|
* @param payload UDPv6 data
|
||||||
|
* @param payload_size Size of the data payload
|
||||||
*
|
*
|
||||||
* @return 0 for success
|
* @return 0 for success
|
||||||
* @return 1 for failure
|
* @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_udp *udp;
|
||||||
struct s_nat *connection;
|
struct s_nat *connection;
|
||||||
@ -154,11 +162,18 @@ int udp_ipv6(struct s_ethernet *eth6, struct s_ipv6 *ip6, char *payload)
|
|||||||
/* parse UDP header */
|
/* parse UDP header */
|
||||||
udp = (struct s_udp *) payload;
|
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 */
|
/* checksum recheck */
|
||||||
orig_checksum = udp->checksum;
|
orig_checksum = udp->checksum;
|
||||||
udp->checksum = 0;
|
udp->checksum = 0;
|
||||||
udp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest,
|
udp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest, payload_size,
|
||||||
htons(ip6->len), IPPROTO_UDP, payload);
|
IPPROTO_UDP, payload);
|
||||||
|
|
||||||
if (udp->checksum != orig_checksum) {
|
if (udp->checksum != orig_checksum) {
|
||||||
/* packet is corrupted and shouldn't be processed */
|
/* 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 */
|
/* translated packet */
|
||||||
ip4 = (struct s_ipv4 *) 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 */
|
/* build IPv4 packet */
|
||||||
ip4->ver_hdrlen = 0x45; /* ver 4, header length 20 B */
|
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);
|
connection->ipv4_port_src);
|
||||||
|
|
||||||
/* copy the payload data (with new checksum) */
|
/* 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 */
|
/* compute IPv4 checksum */
|
||||||
ip4->checksum = 0x0;
|
ip4->checksum = 0x0;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* WrapSix
|
* 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
|
* 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
|
* 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,
|
int udp_ipv4(struct s_ethernet *eth4, struct s_ipv4 *ip4, char *payload,
|
||||||
unsigned short payload_size);
|
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 */
|
#endif /* UDP_H */
|
||||||
|
@ -24,9 +24,11 @@
|
|||||||
#include <net/if.h> /* struct ifreq */
|
#include <net/if.h> /* struct ifreq */
|
||||||
#include <netinet/in.h> /* htons */
|
#include <netinet/in.h> /* htons */
|
||||||
#include <netpacket/packet.h> /* struct packet_mreq, struct sockaddr_ll */
|
#include <netpacket/packet.h> /* struct packet_mreq, struct sockaddr_ll */
|
||||||
|
#include <stdio.h> /* perror */
|
||||||
#include <stdlib.h> /* srand */
|
#include <stdlib.h> /* srand */
|
||||||
#include <string.h> /* strncpy */
|
#include <string.h> /* strncpy */
|
||||||
#include <sys/ioctl.h> /* ioctl, SIOCGIFINDEX */
|
#include <sys/ioctl.h> /* ioctl, SIOCGIFINDEX */
|
||||||
|
#include <sys/types.h> /* caddr_t */
|
||||||
#include <time.h> /* time, time_t */
|
#include <time.h> /* time, time_t */
|
||||||
#include <unistd.h> /* close */
|
#include <unistd.h> /* close */
|
||||||
|
|
||||||
@ -36,6 +38,7 @@
|
|||||||
#endif /* HAVE_CONFIG_H */
|
#endif /* HAVE_CONFIG_H */
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "ethernet.h"
|
#include "ethernet.h"
|
||||||
|
#include "icmp.h"
|
||||||
#include "ipv4.h"
|
#include "ipv4.h"
|
||||||
#include "ipv6.h"
|
#include "ipv6.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -53,7 +56,7 @@ struct s_ipv4_addr wrapsix_ipv4_addr;
|
|||||||
struct s_ipv6_addr host_ipv6_addr;
|
struct s_ipv6_addr host_ipv6_addr;
|
||||||
struct s_ipv4_addr host_ipv4_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)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -177,13 +180,21 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
/* sniff! :c) */
|
/* sniff! :c) */
|
||||||
for (i = 1;; i++) {
|
for (i = 1;; i++) {
|
||||||
if ((length = recv(sniff_sock, buffer, PACKET_BUFFER, 0)) ==
|
length = recv(sniff_sock, buffer, PACKET_BUFFER, MSG_TRUNC);
|
||||||
-1) {
|
if (length == -1) {
|
||||||
|
perror("recv");
|
||||||
log_error("Unable to retrieve data from socket");
|
log_error("Unable to retrieve data from socket");
|
||||||
return 1;
|
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) {
|
if (i % 250000) {
|
||||||
curtime = time(NULL);
|
curtime = time(NULL);
|
||||||
@ -217,29 +228,46 @@ int main(int argc, char **argv)
|
|||||||
return 0;
|
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 */
|
struct s_ethernet *eth;
|
||||||
char *payload; /* the IP header + packet
|
|
||||||
payload */
|
/* 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 */
|
/* parse ethernet header */
|
||||||
eth = (struct s_ethernet *) (packet);
|
eth = (struct s_ethernet *) packet;
|
||||||
payload = packet + sizeof(struct s_ethernet);
|
|
||||||
|
#define payload packet + sizeof(struct s_ethernet)
|
||||||
|
#define payload_length length - sizeof(struct s_ethernet)
|
||||||
|
|
||||||
switch (htons(eth->type)) {
|
switch (htons(eth->type)) {
|
||||||
case ETHERTYPE_IP:
|
case ETHERTYPE_IP:
|
||||||
return ipv4(eth, payload);
|
return ipv4(eth, payload, payload_length);
|
||||||
case ETHERTYPE_IPV6:
|
case ETHERTYPE_IPV6:
|
||||||
return ipv6(eth, payload);
|
return ipv6(eth, payload, payload_length);
|
||||||
case ETHERTYPE_ARP:
|
case ETHERTYPE_ARP:
|
||||||
log_debug("HW Protocol: ARP");
|
return arp(eth, payload, payload_length);
|
||||||
return arp(eth, payload);
|
|
||||||
default:
|
default:
|
||||||
log_debug("HW Protocol: unknown [%d/0x%04x]",
|
log_debug("HW Protocol: unknown [%d/0x%04x]",
|
||||||
htons(eth->type), htons(eth->type));
|
htons(eth->type), htons(eth->type));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef payload_length
|
||||||
|
#undef payload
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user