I am trying to build a TCP packet using libnet library. I use '0' for autocomputation of checksum value in the libnet_build_tcp function. However, it seems the checksum ignores the pseudo-header when being computed resulting in a useless packet because of checksum error. Does anyone know how to solve this?
As far as I can see in the code, as long as you haven't used libnet_toggle_checksum(l, ptag, 1); your 0 in the sum parameter of libnet_build_tcp() should be causing it to autocompute a checksum for you by calling libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM).
I couldn't really tell you how to solve it but since you are the one building the packet maybe you could opt for creating your own checksum?
The TCP pseudoheader is a 12 byte field containing the source and destination IP addresses which are both 4 bytes each, a reserved field which is 2 bytes and always set to zeros, and a 4 byte TCP segment length which is equal to the size of the TCP header + the payload length.
You could create something like this:
First create your variables:
int bytesRead;
int pseudoHeaderLength;
int payloadLength;
int tcpHdrLength;
int tcpSegmentLength;
int ipHdrLength;
int headerLengths;
int ethIPHdrLengths;
struct ethhdr *ethHdr;
struct iphdr *ipHdr;
struct tcphdr *tcpHdr;
u_int8_t *pkt_data;
u_int8_t pseudoHeader[12];
u_int8_t packetBuffer[1600];
u_int16_t newChecksum;
Then create the actual function where b->len is the total size of the packet (just add all the headers + the payload and get the total size) and you would just have to memcpy your header and data to pkt_data:
ethHdr = (struct ethhdr*)pkt_data;
ipHdr = (struct iphdr*)(pkt_data + ETH_HLEN);
ipHdrLength = ipHdr->ihl * 4;
ethIPHdrLengths = ETH_HLEN + ipHdrLength;
tcpHdr = (struct tcphdr*)(pkt_data + ethIPHdrLengths);
tcpHdrLength = tcpHdr->doff * 4;
headerLengths = ethIPHdrLengths + tcpHdrLength;
payloadLength = b->len - headerLengths;
tcpSegmentLength = tcpHdrLength + payloadLength;
pseudoHeaderLength = tcpSegmentLength + 12;
pseudoHeader[0] = pkt_data[30];
pseudoHeader[1] = pkt_data[31];
pseudoHeader[2] = pkt_data[32];
pseudoHeader[3] = pkt_data[33];
pseudoHeader[4] = pkt_data[26];
pseudoHeader[5] = pkt_data[27];
pseudoHeader[6] = pkt_data[28];
pseudoHeader[7] = pkt_data[29];
pseudoHeader[8] = 0x00;
pseudoHeader[9] = 0x06;
pseudoHeader[10] = (tcpSegmentLength >> 8) & 0xFF;
pseudoHeader[11] = tcpSegmentLength & 0xFF;
bytesRead = 0;
for(i = 0; i < 12; i++) {
packetBuffer[bytesRead] = pseudoHeader[i];
bytesRead++;
}
for(i = ethIPHdrLengths; i < headerLengths; i++) {
packetBuffer[bytesRead] = pkt_data[i];
bytesRead++;
}
for(i = b->len - payloadLength; i < b->len; i++) {
packetBuffer[bytesRead] = pkt_data[i];
bytesRead++;
}
newChecksum = checksum((uint16_t *)packetBuffer, pseudoHeaderLength);
And just use the checksum function provided by https://www.rfc-editor.org/rfc/rfc1071 to calculate the checksum over the buffer:
uint16_t checksum(uint16_t *addr, int len)
{
int count = len;
register uint32_t sum = 0;
uint16_t answer = 0;
while (count > 1) {
sum += *(addr++);
count -= 2;
}
if (count > 0) {
sum += *(uint8_t *) addr;
}
while (sum >> 16) {
sum = (sum & 0xffff) + (sum >> 16);
}
answer = ~sum;
return (answer);
}
I use this in a realistic environment to calculate checksums at 5 million PPS.
Related
I have been using raw sockets to create custom TCP packets in C. To verify, I sent them to the loopback interface, and when I checked the received packets using TCPDUMP, the checksum did not match for the TCP packet. Here are the fields in the TCP header :
tcp->th_sport = temp_port; // The TCP structure. The source port, spoofed, we accept through the command line
tcp->th_dport = atoi(argv[2]); // The destination port, we accept through command line
tcp->th_seq = htonl(random_id()%1000);
tcp->th_ack = htonl(random_id()%1000);
tcp->th_off = 5;
tcp->th_flags = TH_SYN;
tcp->th_win = 10000;
tcp->th_sum = 0;
tcp->th_urp = 0;
//pseudo header for TCP checksum calculation
p_hdr->source = t1->s_addr;
p_hdr->dest = t2->s_addr;
p_hdr->reserved = 0;
p_hdr->protocol = IPPROTO_TCP; //TCP
p_hdr->tcp_size = sizeof(struct tcphdr);
memcpy(buffer2 + sizeof(struct pseudo_tcp_header) , tcp , sizeof(struct tcphdr) );
tcp->th_sum = htons(csum((unsigned short *) (buffer2 ), sizeof(struct tcphdr) + sizeof(struct pseudo_tcp_header)));
This is the random_id function :
int random_id()
{
int lower = 1, upper = 65535,number;
number = (rand() % (upper - lower + 1)) + lower;
return number;
}
And the checksum is computed by the function,
unsigned short csum(unsigned short *buf, int len)
{
unsigned long sum;
for(sum=0; len>0; len--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
Is there a default function to compute the tcpchecksum in C ?
I understand that there is no default function for calculating the ip/tcp checksum. It can be found by the following code :
unsigned short csum(unsigned short *buf, int len)
{
unsigned long sum;
for(sum=0; len>0; len--)
sum += *buf++;
while (sum>>16)
sum = (sum >> 16) + (sum &0xffff);
return (unsigned short)(~sum);
}
Where the input, buf if the data with the pseudo header.
This calculation is only required if the data packet only traverses through the localhost. If it passes the network card to an external network, leave the sum field blank. The network card will automatically compute the header value.
I am trying to use a 16-bit Fletcher checksum here. Basically, my program simulates traffic over the physical layer by "sending" and "receiving" packets between two virtual entities. I am printing out the packets at both sides and they do match, but I am getting a different checksum calculated at the receiving end.
Packet structure:
#define MESSAGE_LENGTH 20
struct pkt {
int seqnum;
int acknum;
int checksum;
char payload[MESSAGE_LENGTH];
};
This is the code I'm using to compute the checksum of each packet:
/*
* Computes the fletcher checksum of the input packet
*/
uint16_t calcChecksum(struct pkt *packet) {
/* the data for the checksum needs to be continuous, so here I am making
a temporary block of memory to hold everything except the packet checksum */
size_t sizeint = sizeof(int);
size_t size = sizeof(struct pkt) - sizeint;
uint8_t *temp = malloc(size);
memcpy(temp, packet, sizeint * 2); // copy the seqnum and acknum
memcpy(temp + (2*sizeint), &packet->payload, MESSAGE_LENGTH); // copy data
// calculate checksum
uint16_t checksum = fletcher16((uint8_t const *) &temp, size);
free(temp);
return checksum;
}
/*
* This is a checksum algorithm that I shamelessly copied off a wikipedia page.
*/
uint16_t fletcher16( uint8_t const *data, size_t bytes ) {
uint16_t sum1 = 0xff, sum2 = 0xff;
size_t tlen;
while (bytes) {
tlen = bytes >= 20 ? 20 : bytes;
bytes -= tlen;
do {
sum2 += sum1 += *data++;
} while (--tlen);
sum1 = (sum1 & 0xff) + (sum1 >> 8);
sum2 = (sum2 & 0xff) + (sum2 >> 8);
}
/* Second reduction step to reduce sums to 8 bits */
sum1 = (sum1 & 0xff) + (sum1 >> 8);
sum2 = (sum2 & 0xff) + (sum2 >> 8);
return sum2 << 8 | sum1;
}
I don't know much about checksums and I copied that algorithm off a page I found, so if anyone can understand why the checksums for two otherwise identical packets are different I would greatly appreciate it. Thank you!
The problem occurs because you are not passing the address of temp data to the checksum function but rather the address to where the variable temp is stored on stack.
You should change
uint16_t checksum = fletcher16((uint8_t const *) &temp, size);
to
uint16_t checksum = fletcher16((uint8_t const *) temp, size);
^ no & operator
i'm trying to calculate the checksum of an ip address header(without options), following the algorithm: divide the header in 16 bit words, sum all the words, apply NOT operator on the result to obtain the checksum, but i still got wrong results, sniffing the packets with wireshark i can see that they are wrong, for example, this is my method:
void compute_ip_checksum(struct ip_hdr* ip){
unsigned short* begin = (unsigned short*)ip;
unsigned short* end = begin + (IP_NOPT_HEADER_LENGTH / 2);
unsigned short checksum = 0;
ip->checksum = 0;
for (; begin != end; begin++){
checksum += *begin;
}
ip->checksum = htons(~checksum);
}
the ip header i build is:
ip.version_and_length = (IPV4 << 4) | (IP_NOPT_HEADER_LENGTH/4);
ip.type_of_service = 0;
ip.total_length = htons(IP_NOPT_HEADER_LENGTH + TCP_NOPT_HEADER_LENGTH);
ip.frag_id = 0;
ip.flags_and_frag_offset = htons(DONT_FRAGMENT << 13);
ip.time_to_live = 128;
ip.protocol = TCP_PAYLOAD;
ip.src_ip = inet_addr("1.1.1.1");
ip.dst_ip = inet_addr("1.1.1.2");
Since i'm converting all the values to the network byte order, i'm not doing any conversions in the checksum sum, only after the NOT operation, cause i'm almost sure that my windows is LITTLEENDIAN, and if thats the case the result will be put in this byteorder. the result of my functions is: 0x7a17 and the wireshark result is 0x7917 for this header. Can someone explain what is wrong here? my references are: RFC 791 and How to Calculate IpHeader Checksum
So after reading this link: wikipedia i could see that checksum is a little bit more tricky than expected, now this is the code that works for me:
void compute_ip_checksum(struct ip_hdr* ip, struct ip_options* opt){
unsigned short* begin = (unsigned short*)ip;
unsigned short* end = begin + IP_NOPT_HEADER_LENGTH / 2;
unsigned int checksum = 0, first_half, second_half;
ip->checksum = 0;
for (; begin != end; begin++){
checksum += *begin;
}
first_half = (unsigned short)(checksum >> 16);
while (first_half){
second_half = (unsigned short)((checksum << 16) >> 16);
checksum = first_half + second_half;
first_half = (unsigned short)(checksum >> 16);
}
ip->checksum = ~checksum;
}
as you can see, there is no need for conversion after the NOT operation, i've put the carry calculation in a loop because i don't know how many time i have to do this step, i think that in my case it dont exceed one.
I was just wondering if anyone had any insight on how to convert a uint32_t hex value to a ascii decimal and display it to an LCD. An algorithm would help so I can program it using C code. The hex value i'm getting comes from an ADC that I take and convert to to LCD. The ADC data gives a 16 bit value and the lcd is 16x2
void Hex2DecToLCD(){
Algorithm goes here
}
Regards
void Hex_To_BCD_To_LCD(uint32_t ADCData)
{
char BCD[5];
uint32_t Dig_0, Dig_1, Dig_2, Dig_3, Dig_4;
int i = 0;
uint32_t temp = 0x0;
uint32_t bin_inp = ADCData;
bin_inp *= 0x8; // scale up the ADC value
temp = bin_inp;
Dig_4 = temp/10000;
BCD[4] = Dig_4 + 0x30;
temp = temp - (Dig_4 * 10000);
Dig_3 = temp/1000;
BCD[3] = Dig_3 + 0x30;
temp = temp - (Dig_3 * 1000);
Dig_2 = temp/100;
BCD[2] = Dig_2 + 0x30;
temp = temp - (Dig_2 * 100);
Dig_1 = temp/10;
BCD[1] = Dig_1 + 0x30;
temp = temp - (Dig_1 * 10);
Dig_0 = temp;
BCD[0] = Dig_0 + 0x30;
//Data to LCD
for (i =0; i < 5; i++){
Data_To_LCD(BCD[i++]);
}
}
The answer provided by Julien in 2015 probably works, but I think it's formatting and methodology could be improved a little bit.
My microcontroller relies on uint8_t for most integer values, including the transmission of ASCII bytes over UART.
I hope this answer helps whoever is looking for an easy drop-in uint32_t replacement for %lu in printf.
#include <stdint.h>
void putDwordDecimalValue(uint32_t value) {
if (value == 0) {
putChar('0');
return;
}
uint32_t valueCopy;
valueCopy = value;
int length = 0;
while (valueCopy != 0) {
length++;
valueCopy /= 10;
}
int i;
uint8_t asciiDigits[10]; // Max size of 4294967295 => 10 digits
for (i = 0; i < length; i++) {
uint8_t lastDigit = value % 10;
value /= 10;
asciiDigits[length - (i + 1)] = 0x30 + lastDigit; // 0x30 = 0 in ASCII
}
for (i = 0; i < length; i++)
putChar(asciiDigits[i]);
}
I am doing some programming, I wanna convert the netmask to network prefix length.
For example 255.255.255.0 ----> 24.
Finally I write some code to do so.
const char *network = "255.255.255.0";
int n = inet_addr(netowrk);
int i = 0;
while (n > 0) {
n = n << 1;
i++;
}
i will be the network count
You should first try to compile your code, it can help you a lot. There are compilations errors because you mistyped variable name "netowrk"
To calculate prefix instead to left shift you should try with right shift and instead of using inet_addr try inet_pton().
For more details go through the post IPv4 to decimal different values?
Here you can check the code:
int main()
{
const char *network = "255.255.255.0";
int n;
inet_pton(AF_INET, network, &n);
int i = 0;
while (n > 0) {
n = n >> 1;
i++;
}
printf("network = %s, suffix = %d\n", network, i);
}
I cannot add comments, but be aware that Jaymin's answer is dependent on the host byte order. You should use ntohl(3) to convert the address returned by inet_pton to host byte order, and then left shift, right shift, or bit-count to get the prefix length.
For that matter, you really ought to be passing a struct sockaddr_in into inet_pton...
As for netmask, we know that the value is always a continuous series of set bits followed by zero bits. there are no zero bits in between.
So given that we know that max set bits could be only 32, counting the number of zero bits makes a smaller loop count to calculate the prefix len.
unsigned int n = 0xFFFFFE00; // (255.255.254.0) => 23 bits
int zerobits = 0;
while ((n & 0x1) == 0) {
n = n >> 1;
zerobits++;
}
return (32 - zerobits);
So here , the loop count is only for the number of zero bits (9 in this case).
This works for IPv4 networks.
#include <arpa/inet.h>
#include <iostream>
int main() {
// const char *network = "255.255.255.0";
// const char *network = "255.0.0.0";
// const char *network = "224.0.0.0";
const char *network = "255.255.255.224";
int ret;
int count_ones = 0;
std::uint8_t byte;
std::uint8_t buf[sizeof(struct in_addr)];
ret = inet_pton(AF_INET, network, &buf);
// assert(ret > 0);
for (int i = 0; i < sizeof(struct in_addr); i++) {
// std::cout << int(buf[i]) << std::endl;
byte = buf[i];
for (int j = 0; j < 8; j++) {
count_ones += (byte & 1);
byte >>= 1;
}
}
std::cout << "network: " << network << ", suffix: " << count_ones << std::endl;
}