mirror of
https://code.semirocket.science/wrapsix
synced 2024-12-22 12:30:18 +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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@ -147,3 +190,81 @@ unsigned short checksum_ipv6(struct s_ipv6_addr ip_src,
|
||||
|
||||
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"
|
||||
|
||||
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,
|
||||
struct s_ipv4_addr ip_dest, unsigned short length,
|
||||
unsigned char proto, unsigned char *payload);
|
||||
unsigned short checksum_ipv6(struct s_ipv6_addr ip_src,
|
||||
struct s_ipv6_addr ip_dest, unsigned short length,
|
||||
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 */
|
||||
|
@ -56,6 +56,13 @@ struct s_ipv4_pseudo {
|
||||
unsigned short len; /* 16 b; payload length */
|
||||
} __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);
|
||||
|
||||
#endif /* IPV4_H */
|
||||
|
@ -47,6 +47,13 @@ struct s_ipv6_pseudo {
|
||||
unsigned char next_header; /* 8 b; next header */
|
||||
} __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);
|
||||
|
||||
#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;
|
||||
|
||||
/* compute TCP checksum */
|
||||
tcp->checksum = 0x0;
|
||||
tcp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest, payload_size,
|
||||
IPPROTO_TCP, (unsigned char *) tcp);
|
||||
tcp->checksum = checksum_ipv6_update(tcp->checksum,
|
||||
ip4->ip_src, ip4->ip_dest,
|
||||
connection->ipv4_port_src,
|
||||
ip6->ip_src, ip6->ip_dest,
|
||||
connection->ipv6_port_src);
|
||||
|
||||
/* copy the payload data (with new checksum) */
|
||||
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;
|
||||
|
||||
/* compute TCP checksum */
|
||||
tcp->checksum = 0;
|
||||
tcp->checksum = checksum_ipv4(ip4->ip_src, ip4->ip_dest,
|
||||
htons(ip6->len), IPPROTO_TCP,
|
||||
(unsigned char *) tcp);
|
||||
tcp->checksum = checksum_ipv4_update(tcp->checksum,
|
||||
ip6->ip_src, ip6->ip_dest,
|
||||
connection->ipv6_port_src,
|
||||
ip4->ip_src, ip4->ip_dest,
|
||||
connection->ipv4_port_src);
|
||||
|
||||
/* copy the payload data (with new checksum) */
|
||||
memcpy(packet + sizeof(struct s_ipv4), payload, htons(ip6->len));
|
||||
|
23
src/udp.c
23
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;
|
||||
|
||||
/* compute UDP checksum */
|
||||
udp->checksum = 0x0;
|
||||
udp->checksum = checksum_ipv6(ip6->ip_src, ip6->ip_dest, payload_size,
|
||||
IPPROTO_UDP, (unsigned char *) udp);
|
||||
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,
|
||||
IPPROTO_UDP, (unsigned char *) udp);
|
||||
}
|
||||
|
||||
/* copy the payload data (with new checksum) */
|
||||
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;
|
||||
|
||||
/* compute UDP checksum */
|
||||
udp->checksum = 0x0;
|
||||
udp->checksum = checksum_ipv4(ip4->ip_src, ip4->ip_dest,
|
||||
htons(ip6->len), IPPROTO_UDP,
|
||||
(unsigned char *) payload);
|
||||
udp->checksum = checksum_ipv4_update(udp->checksum,
|
||||
ip6->ip_src, ip6->ip_dest,
|
||||
connection->ipv6_port_src,
|
||||
ip4->ip_src, ip4->ip_dest,
|
||||
connection->ipv4_port_src);
|
||||
|
||||
/* copy the payload data (with new checksum) */
|
||||
memcpy(packet + sizeof(struct s_ipv4), payload, htons(ip6->len));
|
||||
|
Loading…
Reference in New Issue
Block a user