RFC 1071 - Calculating IP header checksum confusion in C - c

I'm trying to calculate a proper IP header checksum by using the example C code of RFC 1071 but have a problem that is best described with code:
Setting up the IP Header:
#include <linux/ip.h>
typedef struct iphdr tipheader;
int main(int argc, char **argv)
{
tipheader * iphead = (tipheader *) malloc(sizeof(tipheader));
iphead->ihl = 5;
iphead->version = 4;
iphead->tos = 0;
iphead->tot_len = 60;
....
unsigned short checksum = getChecksum((unsigned short *) iphead, 20);
}
Checksum function:
unsigned short getChecksum(unsigned short * iphead, int count)
{
unsigned long int sum = 0;
unsigned short checksum = 0;
printf("\nStarting adress: %p\n", iphead);
while(count > 1) {
sum += * (unsigned short *) (iphead);
count -=2;
printf("a: %p, content is: %d, new sum: %ld\n", iphead, (unsigned short) *(iphead), sum);
iphead++;
}
if(count > 0) {
sum += * (unsigned short *) (iphead);
}
while(sum >> 16) {
sum = (sum & 0xffff) + (sum >> 16);
}
checksum = ~sum;
return checksum;
}
Iterating over the memory pointed to by iphead with an unsigned short pointer displays the following output after the first two iterations:
Starting address: 0x603090
a: 0x603090, content is: 69, new sum: 69
a: 0x603092, content is: 60, new sum: 129
So the pointer works 'as expected' and increases by 2 for every iteration.
But why is the content of the first two bytes interpreted as 69 (0x45) where it should be 0x4500
Thx for the clarification

the first two fields are only 4 bits long so,
in memory is 0x4500.
However, due to Endian'ness, it is read as 0x0045.
When printing, unless forced otherwise, leading 0s are suppressed.
so the result is 0x45 = 69

Related

what if my network like tcp and icmp headers sizes are not multiple of 2 bytes(16 bits)then if I have one end byte how to do checksum on this one byte

So my icmp header is 9 byte long along with ping data. I used a algorithm like following to calculate checksum, but its not working
int calculate_checksum(void *vdata,size_t size)
{
uint16_t *ptr = vdata;
int i = 0;
uint16_t sum = -0xffff;
printf("size = %zu\n",size);
while(i < (size/2))
{
//printf("%d = %x \n",i,*(ptr + i));
sum += ntohs(*(ptr+i));
printf("%x %x\n",ntohs(*(ptr+i)),sum);
if(sum > 0xffff)
{
sum -=0xffff;
}
i++;
}
printf("checksum = %x\n", ~sum&0x0000FFFF);
sum = ~sum;
return htons(sum);
}
problem it looks to be my 9th byte is not being included. but its just one byte with hex value of 0x63 so to make 16 bit number so what do I need to do. Is there a way or solution for this?
what I know calcusum is doing sum on each 16 bits of headers

Converting a hex-string into two different context of decimal num. in C

I have a string say:
char *hexstring = "08fc0021";
this is a concatenation of two information each two bytes long.
The first two bytes of this string, ie.: 08fc corresponds to 2300 in dec.
the last 4 bytes, ie., 0021 -> 33.
My problem is to convert this string into two different variables, say:
int varA, varB;
here varA will have the number 2300, and varB = 33.
normally I would have used sscanf to convert the string into a decimal num.
but now i have this problem of a concatenated string with two different info.
any idea suggestion how to nail this ?
thx in advance
Bitwise AND to the Rescue!
So, doing what you require can be done using the bitwise AND opperator on the resulting 32bit number (int?) you get from sscanf.
You first get the number from the string:
char* hexstring = "0x08fc0021";
int num = 0;
sscanf(hexstring, "%x", &num); //put the number into num.
Then you get the bits you want using &:
int varA=0, varB=0;
varA = num & 0xFFFF; //will get the second half.
varB = num & 0xFFFF0000;
varB = varB >> 16; // now you have the first half as well.
And there you have it.
int main(int argc, char *argv[]) {
char *hexstring = "08fc0021";
unsigned long hexnumber = 0u;
unsigned short a = 0u;
unsigned short b = 0u;
/* Use sscanf() to convert the string to integer */
sscanf(hexstring, "%x", &hexnumber);
/* Use bitwise and to filter out the two higher bytes *
* and shift it 16 bits right */
a = ((hexnumber & 0xFFFF0000u) >> 16u);
/* Use bitwise AND to filter out the two lower bytes */
b = (hexnumber & 0x0000FFFFu);
printf("0x%X 0x%X\n",a,b);
return 0;
}
You can use this approach (bit operations):
char *hexstring = "08fc0021";
int aux;
sscanf(hexstring, "%x", &aux);
printf("aux = 0x%x = %d\n", aux, aux);
int varA = (aux & 0xFFFF0000) >> 16, varB = aux & 0x0000FFFF;
printf("varA = 0x%x = %d\n", varA, varA);
printf("varB = 0x%x = %d\n", varB, varB);
Result:
aux = 0x8fc0021 = 150732833
varA = 0x8fc = 2300
varB = 0x21 = 33
EDIT:
Or this approach (string manipulation):
// requires a hexstring length of 8 or more sophisticated logic
char *hexstring = "08fc0021";
int len = strlen(hexstring);
char varA[5], varB[5];
for(int i = 0; i<len; i++)
{
if(i < 4) varA[i] = hexstring[i];
else varB[i-4] = hexstring[i];
}
varA[4] = varB[4] = '\0';
int varAi, varBi;
sscanf(varA, "%x", &varAi);
sscanf(varB, "%x", &varBi);
printf("varAi = 0x%x = %d\n", varAi, varAi);
printf("varBi = 0x%x = %d\n", varBi, varBi);
Same result:
varAi = 0x8fc = 2300
varBi = 0x21 = 33

How to convert netmask to network prefix length?

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;
}

Bit Manipulation on char array in c

If I am given a char array of size 8, where I know the the first 3 bytes are the id, the next byte is the message, and the last 3 bytes are the values. How could I use bit manipulation in order to extract the message.
Example: a char array contains 9990111 (one integer per position), where 999 is the id, 0 is the message, and 111 is the value.
Any tips? Thanks!
Given:
the array contains {'9','9','9','0','1','1','1'}
Then you can convert with sscanf():
char buffer[8] = { '9', '9', '9', '0', '1', '1', '1', '\0' };
//char buffer[] = "9990111"; // More conventional but equivalent notation
int id;
int message;
int value;
if (sscanf(buffer, "%3d%1d%3d", &id, &message, &value) != 3)
…conversion failed…inexplicably in this context…
assert(id == 999);
assert(message == 0);
assert(value == 111);
But there's no bit manipulation needed there.
Well, if you want bit manipulation, no matter what, here it goes:
#include <stdio.h>
#include <arpa/inet.h>
int main(void) {
char arr[8] = "9997111";
int msg = 0;
msg = ((ntohl(*(uint32_t *) arr)) & 0xff) - 48;
printf("%d\n", msg);
return 0;
}
Output:
7
Just remember one thing... this does not comply with strict aliasing rules. But you can use some memcpy() stuff to solve it.
Edit #1 (parsing it all, granting compliance with strict aliasing rules, and making you see that this does not make any sense):
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <arpa/inet.h>
int main(void) {
char arr[8] = "9997111";
uint32_t a[2];
unsigned int id = 0, msg = 0, val = 0;
memcpy(a, arr, 4);
memcpy(&a[1], arr + 4, 4);
a[0] = ntohl(a[0]);
a[1] = ntohl(a[1]);
id = ((((a[0] & 0xff000000) >> 24) - 48) * 100) + ((((a[0] & 0xff0000) >> 16)- 48) * 10) + (((a[0] & 0xff00) >> 8)- 48);
msg = (a[0] & 0xff) - 48;
val = ((((a[1] & 0xff000000) >> 24) - 48) * 100) + ((((a[1] & 0xff0000) >> 16)- 48) * 10) + (((a[1] & 0xff00) >> 8)- 48);
printf("%d\n", id);
printf("%d\n", msg);
printf("%d\n", val);
return 0;
}
Output:
999
7
111
The usual way would be to define a structure with members which are bit fields and correspond to the segmented information in your array. (oh, re-reading your question: is the array filled with { '9', '9',...}?? Then you'd just sscanf the values with the proper offset into the array.
You can use Memory Copy to extract the values. Here is an example
char *info = malloc(sizeof(int)*3);
char *info2 = malloc(sizeof(int)*1);
char *info3 = malloc(sizeof(int)*3);
memcpy(info,msgTest, 3);
memcpy(info2,msgTest+3, 1);
memcpy(info3,msgTest+4, 3);
printf("%s\n", msgTest);
printf("ID is %s\n", info);
printf("Code is %s\n", info2);
printf("Val is %s\n", info3);
Lets say string msgTest = "0098457
The print statement willl goes as follows..
ID is 009
Code is 8
Val is 457
Hope this helps, Good luck!
here is an example in which i don't use malloc or memory copy for a good implementation on embedded devices, where the stack is limited. Note there is no need to use compact because it is only 1 byte. This is C11 implementation. If you have 4 Bytes for example to be analyzed, create another struct with 4 charbits, and copy the address to the new struct instead. This is coinstance with design patterns concept for embedded.
#include <stdio.h>
// start by creating a struct for the bits
typedef struct {
unsigned int bit0:1; //this is LSB
unsigned int bit1:1; //bit 1
unsigned int bit2:1;
unsigned int bit3:1;
unsigned int bit4:1;
unsigned int bit5:1;
unsigned int bit6:1;
unsigned int bit7:1;
unsigned int bit8:1;
}charbits;
int main()
{
// now assume we have a char to be converted into its bits
char a = 'a'; //asci of a is 97
charbits *x; //this is the character bits to be converted to
// first convert the char a to void pointer
void* p; //this is a void pointer
p=&a; // put the address of a into p
//now convert the void pointer to the struct pointer
x=(charbits *) p;
// now print the contents of the struct
printf("b0 %d b1 %d b2 %d b3 %d b4 %d b5 %d b6 %d b7 %d", x->bit0,x->bit1, x->bit2,x->bit3, x->bit4, x->bit5, x->bit6, x->bit7, x->bit8);
// 97 has bits like this 01100001
//b0 1 b1 0 b2 0 b3 0 b4 0 b5 1 b6 1 b7 0
// now we see that bit 0 is the LSB which is the first one in the struct
return 0;
}
// thank you and i hope this helps

Going below zero in unsigned integer operations

I want to deduce a list of 16-bit unsigned integers from another list of 16-bit unsigned integers.
For example, given the list:
10000, 12349, 32333, 3342
and I know the first integer of the other list is 0, now I want to deduce the rest. The mapping is to subtract 10000 from them, I got
0, 2349, 22333, 58878
where 58878 = (3342-10000+65536) modulo 65536 as the result of a wrapping.
The pseudocode is something like:
void deduce(u_int16_t list1[100], u_int16_t *list2[100], u_int16_t first)
{
int diff = first - list1[0];
for (i = 0; i < 100; i++)
(*list2)[i] = (list1[i] + diff + 65536) % 65536;
}
but we know that there is no minus number in unsigned integers.
so how to do the mapping(or deduction)?
thanks!
unsigned integers variables can be subtracted more than they contain - if I understand correctly the question.
u_int16_t u = 10;
u -= 20; // => u = u - 20;
printf("%x, %u\n", u, u); // => fff6, 65526
The difference is
when displayed, u does not show a negative value - ie the MSb (most significant bit, ie bit 15) is interpreted (here) as 215, the next as 214 etc...
when extended (eg to 32 bits) the MBb is not propagated from bit 16 to bit 31 (as they would be if signed) - they're 0
when right shifted the value MSb is always 0 (would be the same as previous MSb if signed, e.g 1 for a negative value)
So your mapping will keep working with u_int16_t (and you don't need the % modulo 65536 if you work with that type everywhere since anyway the values are on 16 bits - the modulo is implicit).
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
void deduce(uint16_t list1[], uint16_t list2[], size_t size){
int32_t i, first = list1[0];
for(i=0;i<size;++i){
// list2[i]= list1[i] - first;
int32_t wk = list1[i];
wk -= first;
if(wk<0)
wk += 65536;
list2[i] = wk;
}
}
int main(void){
uint16_t list1[100] = {
10000,
12349,
32333,
3342
};
uint16_t list2[100];
int i;
deduce(list1, list2, 4);
for(i = 0; i<4; ++i)
printf("%5" PRIu16 "\n", list2[i]);
return 0;
}
I'm not quite understand your question, but if what you want is to subtract every element of the first list by the different between the first element of both list. This code should work.
void deduce(uint16_t list1[], uint16_t list2[], int size)
{
uint16_t diff = list1[0] - list2[0];
int i;
for (i=0; i<size; i++)
list2[i] = list1[i] - diff;
}
You don't need to pass list2 as u_int16_t* list2[] because you actually can edit the content of the array with u_int16_t list2[]. Only use u_int16_t* list2[] if you want to do dynamic memory allocation in this function.

Resources