mirror of
https://code.semirocket.science/wrapsix
synced 2024-11-10 00:01:01 +02:00
Partial checksum updates for TCP and UDP
This commit is contained in:
parent
88882ea5ca
commit
e35adde820
121
src/checksum.c
121
src/checksum.c
@ -64,6 +64,49 @@ unsigned short checksum(const void *data, int length)
|
|||||||
return ~sum;
|
return ~sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General checksum update computation function. Inspired by algorithm
|
||||||
|
* in RFC3022.
|
||||||
|
*
|
||||||
|
* @param old_sum Old checksum
|
||||||
|
* @param old_data Pointer to old part of data. Must be of even
|
||||||
|
* number of octets
|
||||||
|
* @param old_len Length of old data
|
||||||
|
* @param new_data Pointer to new part of data. Must be of even
|
||||||
|
* number of octets
|
||||||
|
* @param new_len Length of new data
|
||||||
|
*
|
||||||
|
* @return Updated checksum
|
||||||
|
*/
|
||||||
|
unsigned short checksum_update(unsigned short old_sum,
|
||||||
|
unsigned short *old_data, short old_len,
|
||||||
|
unsigned short *new_data, short new_len)
|
||||||
|
{
|
||||||
|
unsigned int sum;
|
||||||
|
|
||||||
|
sum = ~old_sum & 0xffff;
|
||||||
|
|
||||||
|
while (old_len) {
|
||||||
|
sum -= *old_data++;
|
||||||
|
if (sum & 0x80000000) {
|
||||||
|
sum--;
|
||||||
|
sum &= 0xffff;
|
||||||
|
}
|
||||||
|
old_len -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (new_len) {
|
||||||
|
sum += *new_data++;
|
||||||
|
if (sum & 0x00010000) {
|
||||||
|
sum++;
|
||||||
|
sum &= 0xffff;
|
||||||
|
}
|
||||||
|
new_len -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ~sum & 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IPv4 checksum computation function
|
* IPv4 checksum computation function
|
||||||
*
|
*
|
||||||
@ -147,3 +190,81 @@ unsigned short checksum_ipv6(struct s_ipv6_addr ip_src,
|
|||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IPv4 checksum update computation function
|
||||||
|
*
|
||||||
|
* @param old_sum Old checksum
|
||||||
|
* @param ip6_src Original source IPv6 address
|
||||||
|
* @param ip6_dest Original destination IPv6 address
|
||||||
|
* @param old_port Original transport layer address (port)
|
||||||
|
* @param ip4_src New source IPv4 address
|
||||||
|
* @param ip4_dest New destination IPv4 address
|
||||||
|
* @param new_port New transport layer address (port)
|
||||||
|
*
|
||||||
|
* @return Checksum
|
||||||
|
*/
|
||||||
|
unsigned short checksum_ipv4_update(unsigned short old_sum,
|
||||||
|
struct s_ipv6_addr ip6_src,
|
||||||
|
struct s_ipv6_addr ip6_dest,
|
||||||
|
unsigned short old_port,
|
||||||
|
struct s_ipv4_addr ip4_src,
|
||||||
|
struct s_ipv4_addr ip4_dest,
|
||||||
|
unsigned short new_port)
|
||||||
|
{
|
||||||
|
struct s_ipv4_pseudo_delta delta4;
|
||||||
|
struct s_ipv6_pseudo_delta delta6;
|
||||||
|
|
||||||
|
delta4.ip_src = ip4_src;
|
||||||
|
delta4.ip_dest = ip4_dest;
|
||||||
|
delta4.port = new_port;
|
||||||
|
|
||||||
|
delta6.ip_src = ip6_src;
|
||||||
|
delta6.ip_dest = ip6_dest;
|
||||||
|
delta6.port = old_port;
|
||||||
|
|
||||||
|
return checksum_update(old_sum,
|
||||||
|
(unsigned short *) &delta6,
|
||||||
|
sizeof(struct s_ipv6_pseudo_delta),
|
||||||
|
(unsigned short *) &delta4,
|
||||||
|
sizeof(struct s_ipv4_pseudo_delta));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IPv6 checksum update computation function
|
||||||
|
*
|
||||||
|
* @param old_sum Old checksum
|
||||||
|
* @param ip4_src Original source IPv4 address
|
||||||
|
* @param ip4_dest Original destination IPv4 address
|
||||||
|
* @param old_port Original transport layer address (port)
|
||||||
|
* @param ip6_src New source IPv6 address
|
||||||
|
* @param ip6_dest New destination IPv6 address
|
||||||
|
* @param new_port New transport layer address (port)
|
||||||
|
*
|
||||||
|
* @return Checksum
|
||||||
|
*/
|
||||||
|
unsigned short checksum_ipv6_update(unsigned short old_sum,
|
||||||
|
struct s_ipv4_addr ip4_src,
|
||||||
|
struct s_ipv4_addr ip4_dest,
|
||||||
|
unsigned short old_port,
|
||||||
|
struct s_ipv6_addr ip6_src,
|
||||||
|
struct s_ipv6_addr ip6_dest,
|
||||||
|
unsigned short new_port)
|
||||||
|
{
|
||||||
|
struct s_ipv4_pseudo_delta delta4;
|
||||||
|
struct s_ipv6_pseudo_delta delta6;
|
||||||
|
|
||||||
|
delta4.ip_src = ip4_src;
|
||||||
|
delta4.ip_dest = ip4_dest;
|
||||||
|
delta4.port = old_port;
|
||||||
|
|
||||||
|
delta6.ip_src = ip6_src;
|
||||||
|
delta6.ip_dest = ip6_dest;
|
||||||
|
delta6.port = new_port;
|
||||||
|
|
||||||
|
return checksum_update(old_sum,
|
||||||
|
(unsigned short *) &delta4,
|
||||||
|
sizeof(struct s_ipv4_pseudo_delta),
|
||||||
|
(unsigned short *) &delta6,
|
||||||
|
sizeof(struct s_ipv6_pseudo_delta));
|
||||||
|
}
|
||||||
|
@ -23,11 +23,28 @@
|
|||||||
#include "ipv6.h"
|
#include "ipv6.h"
|
||||||
|
|
||||||
unsigned short checksum(const void *data, int length);
|
unsigned short checksum(const void *data, int length);
|
||||||
|
unsigned short checksum_update(unsigned short old_sum,
|
||||||
|
unsigned short *old_data, short old_len,
|
||||||
|
unsigned short *new_data, short new_len);
|
||||||
unsigned short checksum_ipv4(struct s_ipv4_addr ip_src,
|
unsigned short checksum_ipv4(struct s_ipv4_addr ip_src,
|
||||||
struct s_ipv4_addr ip_dest, unsigned short length,
|
struct s_ipv4_addr ip_dest, unsigned short length,
|
||||||
unsigned char proto, unsigned char *payload);
|
unsigned char proto, unsigned char *payload);
|
||||||
unsigned short checksum_ipv6(struct s_ipv6_addr ip_src,
|
unsigned short checksum_ipv6(struct s_ipv6_addr ip_src,
|
||||||
struct s_ipv6_addr ip_dest, unsigned short length,
|
struct s_ipv6_addr ip_dest, unsigned short length,
|
||||||
unsigned char proto, unsigned char *payload);
|
unsigned char proto, unsigned char *payload);
|
||||||
|
unsigned short checksum_ipv4_update(unsigned short old_sum,
|
||||||
|
struct s_ipv6_addr ip6_src,
|
||||||
|
struct s_ipv6_addr ip6_dest,
|
||||||
|
unsigned short old_port,
|
||||||
|
struct s_ipv4_addr ip4_src,
|
||||||
|
struct s_ipv4_addr ip4_dest,
|
||||||
|
unsigned short new_port);
|
||||||
|
unsigned short checksum_ipv6_update(unsigned short old_sum,
|
||||||
|
struct s_ipv4_addr ip4_src,
|
||||||
|
struct s_ipv4_addr ip4_dest,
|
||||||
|
unsigned short old_port,
|
||||||
|
struct s_ipv6_addr ip6_src,
|
||||||
|
struct s_ipv6_addr ip6_dest,
|
||||||
|
unsigned short new_port);
|
||||||
|
|
||||||
#endif /* CHECKSUM_H */
|
#endif /* CHECKSUM_H */
|
||||||
|
@ -56,6 +56,13 @@ struct s_ipv4_pseudo {
|
|||||||
unsigned short len; /* 16 b; payload length */
|
unsigned short len; /* 16 b; payload length */
|
||||||
} __attribute__ ((__packed__));
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
|
/* IPv4 pseudoheader structure for checksum update */
|
||||||
|
struct s_ipv4_pseudo_delta {
|
||||||
|
struct s_ipv4_addr ip_src; /* 32 b; source address */
|
||||||
|
struct s_ipv4_addr ip_dest; /* 32 b; destination address */
|
||||||
|
unsigned short port; /* 16 b; transport layer address */
|
||||||
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
int ipv4(struct s_ethernet *eth, char *packet);
|
int ipv4(struct s_ethernet *eth, char *packet);
|
||||||
|
|
||||||
#endif /* IPV4_H */
|
#endif /* IPV4_H */
|
||||||
|
@ -47,6 +47,13 @@ struct s_ipv6_pseudo {
|
|||||||
unsigned char next_header; /* 8 b; next header */
|
unsigned char next_header; /* 8 b; next header */
|
||||||
} __attribute__ ((__packed__));
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
|
/* IPv6 pseudoheader structure for checksum update */
|
||||||
|
struct s_ipv6_pseudo_delta {
|
||||||
|
struct s_ipv6_addr ip_src; /* 128 b; source address */
|
||||||
|
struct s_ipv6_addr ip_dest; /* 128 b; destination address */
|
||||||
|
unsigned short port; /* 16 b; transport layer address */
|
||||||
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
int ipv6(struct s_ethernet *eth, char *packet);
|
int ipv6(struct s_ethernet *eth, char *packet);
|
||||||
|
|
||||||
#endif /* IPV6_H */
|
#endif /* IPV6_H */
|
||||||
|
17
src/tcp.c
17
src/tcp.c
@ -110,9 +110,11 @@ int tcp_ipv4(struct s_ethernet *eth, struct s_ipv4 *ip4, char *payload,
|
|||||||
tcp->port_dest = connection->ipv6_port_src;
|
tcp->port_dest = connection->ipv6_port_src;
|
||||||
|
|
||||||
/* compute TCP checksum */
|
/* compute TCP checksum */
|
||||||
tcp->checksum = 0x0;
|
tcp->checksum = checksum_ipv6_update(tcp->checksum,
|
||||||
tcp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest, payload_size,
|
ip4->ip_src, ip4->ip_dest,
|
||||||
IPPROTO_TCP, (unsigned char *) tcp);
|
connection->ipv4_port_src,
|
||||||
|
ip6->ip_src, ip6->ip_dest,
|
||||||
|
connection->ipv6_port_src);
|
||||||
|
|
||||||
/* copy the payload data (with new checksum) */
|
/* copy the payload data (with new checksum) */
|
||||||
memcpy(packet + sizeof(struct s_ethernet) + sizeof(struct s_ipv6),
|
memcpy(packet + sizeof(struct s_ethernet) + sizeof(struct s_ipv6),
|
||||||
@ -198,10 +200,11 @@ int tcp_ipv6(struct s_ethernet *eth, struct s_ipv6 *ip6, char *payload)
|
|||||||
tcp->port_src = connection->ipv4_port_src;
|
tcp->port_src = connection->ipv4_port_src;
|
||||||
|
|
||||||
/* compute TCP checksum */
|
/* compute TCP checksum */
|
||||||
tcp->checksum = 0;
|
tcp->checksum = checksum_ipv4_update(tcp->checksum,
|
||||||
tcp->checksum = checksum_ipv4(ip4->ip_src, ip4->ip_dest,
|
ip6->ip_src, ip6->ip_dest,
|
||||||
htons(ip6->len), IPPROTO_TCP,
|
connection->ipv6_port_src,
|
||||||
(unsigned char *) tcp);
|
ip4->ip_src, ip4->ip_dest,
|
||||||
|
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, htons(ip6->len));
|
||||||
|
19
src/udp.c
19
src/udp.c
@ -110,9 +110,17 @@ int udp_ipv4(struct s_ethernet *eth, struct s_ipv4 *ip4, char *payload,
|
|||||||
udp->port_dest = connection->ipv6_port_src;
|
udp->port_dest = connection->ipv6_port_src;
|
||||||
|
|
||||||
/* compute UDP checksum */
|
/* compute UDP checksum */
|
||||||
udp->checksum = 0x0;
|
if (udp->checksum) {
|
||||||
|
udp->checksum = checksum_ipv6_update(udp->checksum,
|
||||||
|
ip4->ip_src, ip4->ip_dest,
|
||||||
|
connection->ipv4_port_src,
|
||||||
|
ip6->ip_src, ip6->ip_dest,
|
||||||
|
connection->ipv6_port_src);
|
||||||
|
} else {
|
||||||
|
/* if original checksum was 0x0000, we need to compute it */
|
||||||
udp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest, payload_size,
|
udp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest, payload_size,
|
||||||
IPPROTO_UDP, (unsigned char *) udp);
|
IPPROTO_UDP, (unsigned char *) udp);
|
||||||
|
}
|
||||||
|
|
||||||
/* copy the payload data (with new checksum) */
|
/* copy the payload data (with new checksum) */
|
||||||
memcpy(packet + sizeof(struct s_ethernet) + sizeof(struct s_ipv6),
|
memcpy(packet + sizeof(struct s_ethernet) + sizeof(struct s_ipv6),
|
||||||
@ -198,10 +206,11 @@ int udp_ipv6(struct s_ethernet *eth, struct s_ipv6 *ip6, char *payload)
|
|||||||
udp->port_src = connection->ipv4_port_src;
|
udp->port_src = connection->ipv4_port_src;
|
||||||
|
|
||||||
/* compute UDP checksum */
|
/* compute UDP checksum */
|
||||||
udp->checksum = 0x0;
|
udp->checksum = checksum_ipv4_update(udp->checksum,
|
||||||
udp->checksum = checksum_ipv4(ip4->ip_src, ip4->ip_dest,
|
ip6->ip_src, ip6->ip_dest,
|
||||||
htons(ip6->len), IPPROTO_UDP,
|
connection->ipv6_port_src,
|
||||||
(unsigned char *) payload);
|
ip4->ip_src, ip4->ip_dest,
|
||||||
|
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, htons(ip6->len));
|
||||||
|
Loading…
Reference in New Issue
Block a user