Parsing a Section of Binary String Data!

Z

zoltan

Nick said:
zoltan said:
Nick said:
zoltan wrote:
Nick Keighley wrote:
zoltan wrote:
(e-mail address removed) wrote:
zoltan wrote:
I am supposed to implement a DNS Query. The Information to be processed
resides in RRs ( Resource Records). The header <arpa/nameser.h>
contains the following structure to store the data of these RRs as :

typedef struct __ns_rr {
char name[NS_MAXDNAME];
uint16_t type;
uint16_t rr_class;
uint32_t ttl;
uint16_t rdlength;
const uchar_t *rdata;
} ns_rr;

Now, the rdata part can have several fields depending on the specific
type of Record.
For instance, the SRV type has only the following fields : priority,
weight, port ( all of unsigned int type) and a target string ( the
hostname).

For my requirement, I have to use the data stored in a NAPTR record.
The "rdata" contains the following fields for this type of record :

order, preference ( unsigned int) and
flags, services, regexp and replacement ( all of type char *).

Now, because the definition of the rdata in the ns_rr structure is
generic, I have defined ( as I need to ) a structure as follows, to
store the actual data :

struct NAPTR
{
unsigned int order;
unsigned int preference;
char * flags;
char * services;
char * regexp;
char * replacement;
};


So my question is this : How can I extract the string fields from the
rdata portion of the ns_rr structure and store them into the respective
fields in my user-defined structure?

The integer fields ( order and preference ) are easy enough, being of
fixed size. What about the strings which can be of variable size?

I hope that is clear enough to elicit a suggestion or a positive
response in the least!

I gather uchar_t is an unsigned char. How about:-

struct NAPTR *naptr;
ns_rr ns_rr_data;

/* load somehow ns_rr_data */

naptr = (struct NAPTR*)ns_rr_data.rdata;
printf ("services = \"%s\"\n", naptr->services);

this assumes your structure is laid out in the same way as the data in
ns_rr.
Check if they define something like your struct NAPTR and use that.

To test the hypothesis, I wrote this sample program.... Can u tell
me why it does not work? The program segment faults... ( after the
printf("%s",record.rdata); statement).


// Program to test the rdata parsing capability.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <malloc.h>

struct NAPTR
{

unsigned int order;
unsigned int preference;
char * flags;
char * services;
char * regexp;
char * replacement;
};

struct nsrr
{

char name[255];
unsigned type;
unsigned class;
unsigned ttl;
unsigned rdlength;
char *rdata;
};


int main(void)
{

struct NAPTR *naptr;
struct nsrr record;

record.rdata=(char*)malloc(1024);

cast not needed. Test for malloc failure
strcpy(record.name,"www.foo.com");


record.type=1;
record.class=1;
record.ttl=8640;
strcpy(record.rdata,"100 10 s sip+e2u !http://[^/:](.*)!\1!i
www.foo.com");
record.rdlength=sizeof(record.rdata);

try your debugger (I can't believe I said that...). The rdata doesn't
seem
to be in the same format as NAPTR...

printf("%s",record.rdata);

naptr=(struct NAPTR*)(record.rdata);

this trick is dangerous if the data is not formatted as struct NAPTR.
and yours isn't
printf("\nThe Record contents are : ");

printf("%s",naptr->flags);
printf("\n%s",naptr->services);
printf("\n%s",naptr->regexp);
printf("\n%s",naptr->replacement);
return 0;
}


--



- Show quoted text -
I suppose u are referring to the fact that I havent' mentioned anything

about the Domain Name, class etc.


The structure of the NAPTR record acc to RFC 2915 is :


Domain TTL Class Type Order Preference Flags Services Regexp
Replacement. ( in this order ).

The ns_rr structure defined is <arpa/nameser.h> actually
has separate fields for Domain, TTL, Type and Class. These are
considered as the Header. The remaining fields form the rdata portion.


I just require to extract the fields in the rdata section, so I wrote
this simple program. How is the RDATA section not the same as the one
in the example?


Thanks and Regards,


Timmy Jose.
 
Z

zoltan

Nick said:
zoltan said:
Nick said:
zoltan wrote:
Nick Keighley wrote:
zoltan wrote:
(e-mail address removed) wrote:
zoltan wrote:
I am supposed to implement a DNS Query. The Information to be processed
resides in RRs ( Resource Records). The header <arpa/nameser.h>
contains the following structure to store the data of these RRs as :

typedef struct __ns_rr {
char name[NS_MAXDNAME];
uint16_t type;
uint16_t rr_class;
uint32_t ttl;
uint16_t rdlength;
const uchar_t *rdata;
} ns_rr;

Now, the rdata part can have several fields depending on the specific
type of Record.
For instance, the SRV type has only the following fields : priority,
weight, port ( all of unsigned int type) and a target string ( the
hostname).

For my requirement, I have to use the data stored in a NAPTR record.
The "rdata" contains the following fields for this type of record :

order, preference ( unsigned int) and
flags, services, regexp and replacement ( all of type char *).

Now, because the definition of the rdata in the ns_rr structure is
generic, I have defined ( as I need to ) a structure as follows, to
store the actual data :

struct NAPTR
{
unsigned int order;
unsigned int preference;
char * flags;
char * services;
char * regexp;
char * replacement;
};


So my question is this : How can I extract the string fields from the
rdata portion of the ns_rr structure and store them into the respective
fields in my user-defined structure?

The integer fields ( order and preference ) are easy enough, being of
fixed size. What about the strings which can be of variable size?

I hope that is clear enough to elicit a suggestion or a positive
response in the least!

I gather uchar_t is an unsigned char. How about:-

struct NAPTR *naptr;
ns_rr ns_rr_data;

/* load somehow ns_rr_data */

naptr = (struct NAPTR*)ns_rr_data.rdata;
printf ("services = \"%s\"\n", naptr->services);

this assumes your structure is laid out in the same way as the data in
ns_rr.
Check if they define something like your struct NAPTR and use that.

To test the hypothesis, I wrote this sample program.... Can u tell
me why it does not work? The program segment faults... ( after the
printf("%s",record.rdata); statement).


// Program to test the rdata parsing capability.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <malloc.h>

struct NAPTR
{

unsigned int order;
unsigned int preference;
char * flags;
char * services;
char * regexp;
char * replacement;
};

struct nsrr
{

char name[255];
unsigned type;
unsigned class;
unsigned ttl;
unsigned rdlength;
char *rdata;
};


int main(void)
{

struct NAPTR *naptr;
struct nsrr record;

record.rdata=(char*)malloc(1024);

cast not needed. Test for malloc failure
strcpy(record.name,"www.foo.com");


record.type=1;
record.class=1;
record.ttl=8640;
strcpy(record.rdata,"100 10 s sip+e2u !http://[^/:](.*)!\1!i
www.foo.com");
record.rdlength=sizeof(record.rdata);

try your debugger (I can't believe I said that...). The rdata doesn't
seem
to be in the same format as NAPTR...

printf("%s",record.rdata);

naptr=(struct NAPTR*)(record.rdata);

this trick is dangerous if the data is not formatted as struct NAPTR.
and yours isn't
printf("\nThe Record contents are : ");

printf("%s",naptr->flags);
printf("\n%s",naptr->services);
printf("\n%s",naptr->regexp);
printf("\n%s",naptr->replacement);
return 0;
}


--



- Show quoted text -
I suppose u are referring to the fact that I havent' mentioned anything

about the Domain Name, class etc.


The structure of the NAPTR record acc to RFC 2915 is :


Domain TTL Class Type Order Preference Flags Services Regexp
Replacement. ( in this order ).

The ns_rr structure defined is <arpa/nameser.h> actually
has separate fields for Domain, TTL, Type and Class. These are
considered as the Header. The remaining fields form the rdata portion.


I just require to extract the fields in the rdata section, so I wrote
this simple program. How is the RDATA section not the same as the one
in the example?


Thanks and Regards,


Timmy Jose.
 
N

Nick Keighley

zoltan said:
I am supposed to implement a DNS Query. The Information to be processed
resides in RRs ( Resource Records). The header <arpa/nameser.h>
contains the following structure to store the data of these RRs as :

typedef struct __ns_rr {
char name[NS_MAXDNAME];
uint16_t type;
uint16_t rr_class;
uint32_t ttl;
uint16_t rdlength;
const uchar_t *rdata;
} ns_rr;

Now, the rdata part can have several fields depending on the specific
type of Record.
For instance, the SRV type has only the following fields : priority,
weight, port ( all of unsigned int type) and a target string ( the
hostname).

For my requirement, I have to use the data stored in a NAPTR record.
The "rdata" contains the following fields for this type of record :

order, preference ( unsigned int) and
flags, services, regexp and replacement ( all of type char *).

Now, because the definition of the rdata in the ns_rr structure is
generic, I have defined ( as I need to ) a structure as follows, to
store the actual data :

struct NAPTR
{
unsigned int order;
unsigned int preference;
char * flags;
char * services;
char * regexp;
char * replacement;
};


So my question is this : How can I extract the string fields from the
rdata portion of the ns_rr structure and store them into the respective
fields in my user-defined structure?

The integer fields ( order and preference ) are easy enough, being of
fixed size. What about the strings which can be of variable size?

I hope that is clear enough to elicit a suggestion or a positive
response in the least!

I gather uchar_t is an unsigned char. How about:-

struct NAPTR *naptr;
ns_rr ns_rr_data;

/* load somehow ns_rr_data */

naptr = (struct NAPTR*)ns_rr_data.rdata;
printf ("services = \"%s\"\n", naptr->services);

this assumes your structure is laid out in the same way as the data in
ns_rr.
Check if they define something like your struct NAPTR and use that.

To test the hypothesis, I wrote this sample program.... Can u tell
me why it does not work? The program segment faults... ( after the
printf("%s",record.rdata); statement).


// Program to test the rdata parsing capability.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <malloc.h>

don't use malloc.h. The correct header is stdlib.h

I refer to this later as FRAGMENT-1

struct nsrr
{

char name[255];
unsigned type;
unsigned class;
unsigned ttl;
unsigned rdlength;
char *rdata;
};


int main(void)
{
struct NAPTR *naptr;
struct nsrr record;

record.rdata=(char*)malloc(1024);

cast not needed. Test for malloc failure
strcpy(record.name,"www.foo.com");
record.type=1;
record.class=1;
record.ttl=8640;
FRAGMENT-2
strcpy(record.rdata,"100 10 s sip+e2u !http://[^/:](.*)!\1!iwww.foo.com");
record.rdlength=sizeof(record.rdata);

try your debugger (I can't believe I said that...). The rdata doesn't
seem to be in the same format as NAPTR...
printf("%s",record.rdata);
FRAGMENT-3
this trick is dangerous if the data is not formatted as struct NAPTR.
and yours isn't

I suppose u are referring to the fact that I havent' mentioned anything

this is not a text message please write "you" rather than "u"
about the Domain Name, class etc.

no. What's "Domain Name"? I don't remeber you mentioning it before.
You seem to think I know something about DNS lookup or whatever it
is you are trying. I am only answering questions about standard C.

Look, you define your structure NAPTR (it is unusual to use all upper
case for a type or type alias) as 2 unsigned int followed by 4 char*
(see FRAGMENT-1) then you stuff a single char* into the field rdata
(see FRAGMENT-2) then you cast rdata into an NPTR (see FRAGMENT-3)
and then you try to read the various fields. And it crashes. Well, duh!

Prtinting the unsigned ints may "work" but treating a char as a char*
is
Really Bad.

I'm sure one of is confused and I'm pretty sure it's not me... Which
means about 12 clc regulars are about to tell me how much tosh I've
been talking for the last few posts.
The structure of the NAPTR record acc to RFC 2915 is :

I don't care.
Domain TTL Class Type Order Preference Flags Services Regexp
Replacement. ( in this order ).

The ns_rr structure defined is <arpa/nameser.h> actually
has separate fields for Domain, TTL, Type and Class. These are
considered as the Header. The remaining fields form the rdata portion.

I just require to extract the fields in the rdata section, so I wrote
this simple program. How is the RDATA section not the same as the one
in the example?

<snip>
 
Z

zoltan

Nick said:
zoltan said:
Nick said:
zoltan wrote:
Nick Keighley wrote:
zoltan wrote:
I am supposed to implement a DNS Query. The Information to be processed
resides in RRs ( Resource Records). The header <arpa/nameser.h>
contains the following structure to store the data of these RRs as :

typedef struct __ns_rr {
char name[NS_MAXDNAME];
uint16_t type;
uint16_t rr_class;
uint32_t ttl;
uint16_t rdlength;
const uchar_t *rdata;
} ns_rr;

Now, the rdata part can have several fields depending on the specific
type of Record.
For instance, the SRV type has only the following fields : priority,
weight, port ( all of unsigned int type) and a target string ( the
hostname).

For my requirement, I have to use the data stored in a NAPTR record.
The "rdata" contains the following fields for this type of record :

order, preference ( unsigned int) and
flags, services, regexp and replacement ( all of type char *).

Now, because the definition of the rdata in the ns_rr structure is
generic, I have defined ( as I need to ) a structure as follows, to
store the actual data :

struct NAPTR
{
unsigned int order;
unsigned int preference;
char * flags;
char * services;
char * regexp;
char * replacement;
};


So my question is this : How can I extract the string fields from the
rdata portion of the ns_rr structure and store them into the respective
fields in my user-defined structure?

The integer fields ( order and preference ) are easy enough, being of
fixed size. What about the strings which can be of variable size?

I hope that is clear enough to elicit a suggestion or a positive
response in the least!

I gather uchar_t is an unsigned char. How about:-

struct NAPTR *naptr;
ns_rr ns_rr_data;

/* load somehow ns_rr_data */

naptr = (struct NAPTR*)ns_rr_data.rdata;
printf ("services = \"%s\"\n", naptr->services);

this assumes your structure is laid out in the same way as the data in
ns_rr.
Check if they define something like your struct NAPTR and use that.

To test the hypothesis, I wrote this sample program.... Can u tell
me why it does not work? The program segment faults... ( after the
printf("%s",record.rdata); statement).


// Program to test the rdata parsing capability.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <malloc.h>

don't use malloc.h. The correct header is stdlib.h
Touche


I refer to this later as FRAGMENT-1
struct NAPTR
{
unsigned int order;
unsigned int preference;
char * flags;
char * services;
char * regexp;
char * replacement;
};

struct nsrr
{

char name[255];
unsigned type;
unsigned class;
unsigned ttl;
unsigned rdlength;
char *rdata;
};


int main(void)
{
struct NAPTR *naptr;
struct nsrr record;

record.rdata=(char*)malloc(1024);

cast not needed. Test for malloc failure

strcpy(record.name,"www.foo.com");
record.type=1;
record.class=1;
record.ttl=8640;
FRAGMENT-2
strcpy(record.rdata,"100 10 s sip+e2u !http://[^/:](.*)!\1!iwww.foo.com");
record.rdlength=sizeof(record.rdata);

try your debugger (I can't believe I said that...). The rdata doesn't
seem to be in the same format as NAPTR...

printf("%s",record.rdata);
FRAGMENT-3
naptr=(struct NAPTR*)(record.rdata);

this trick is dangerous if the data is not formatted as struct NAPTR.
and yours isn't

printf("\nThe Record contents are : ");

printf("%s",naptr->flags);
printf("\n%s",naptr->services);
printf("\n%s",naptr->regexp);
printf("\n%s",naptr->replacement);
return 0;
}

I suppose u are referring to the fact that I havent' mentioned anything

this is not a text message please write "you" rather than "u"
about the Domain Name, class etc.

no. What's "Domain Name"? I don't remeber you mentioning it before.
You seem to think I know something about DNS lookup or whatever it
is you are trying. I am only answering questions about standard C.

Well I had supposed that anyone who uses the net in this century would
surely know what a "domain name" is. It is nothing but a URL ( like
www.google.com ). My apologies.
Look, you define your structure NAPTR (it is unusual to use all upper
case for a type or type alias) as 2 unsigned int followed by 4 char*
(see FRAGMENT-1) then you stuff a single char* into the field rdata
(see FRAGMENT-2) then you cast rdata into an NPTR (see FRAGMENT-3)
and then you try to read the various fields. And it crashes. Well, duh!
Isn't that what you had suggested? I suggest that you check your own
post.
Prtinting the unsigned ints may "work" but treating a char as a char*
is
Really Bad.

I suppose "s" is not a string but a char?
I'm sure one of is confused and I'm pretty sure it's not me... Which
means about 12 clc regulars are about to tell me how much tosh I've
been talking for the last few posts.

Well I know I am confused that's why I thought I'd find some actual
help here and not some grammar lessons! Well, seems it's just as murky
in here.
I don't care.

Frankly I don't either. However, that was just additional information
to clear up your confusion whether it was in the right format or not!

Thanks lot for the verbal help but no real solution? I will surely
post the solution to this problem soon.

Thanks and regards,

Timmy Jose.
 
D

Default User

Could you guys start trimming your quotes? I had to scroll through
screens worth of up to six deep quotes to get to any new material.



Brian
 
N

Nick Keighley

Default said:
Could you guys start trimming your quotes? I had to scroll through
screens worth of up to six deep quotes to get to any new material.

normally I would, but in this case I want to refer to things he posted.
 
N

Nick Keighley

zoltan said:
Nick said:
zoltan said:
Nick Keighley wrote:
zoltan wrote:
Nick Keighley wrote:
zoltan wrote:
I am supposed to implement a DNS Query. The Information to be processed
resides in RRs ( Resource Records). The header <arpa/nameser.h>
contains the following structure to store the data of these RRs as :

typedef struct __ns_rr {
char name[NS_MAXDNAME];
uint16_t type;
uint16_t rr_class;
uint32_t ttl;
uint16_t rdlength;
const uchar_t *rdata;
} ns_rr;

Now, the rdata part can have several fields depending on the specific
type of Record.

note this step. I didn't say "stuff anything I have handy into the data

structure". I expected you to (somehow) load valid data into the
structure.
The reason I keep stressing I don't know anything about your
application,
is because I *don't*. I don't know how you are supposed to load
ns_rr_data.
Try reading the documentation?


Note this well

I thought you wanted help with your program?
I refer to this later as FRAGMENT-1
struct NAPTR
{
unsigned int order;
unsigned int preference;
char * flags;
char * services;
char * regexp;
char * replacement;
};
struct nsrr
{

char name[255];
unsigned type;
unsigned class;
unsigned ttl;
unsigned rdlength;
char *rdata;
};

int main(void)
{
struct NAPTR *naptr;
struct nsrr record;

record.rdata=(char*)malloc(1024);

cast not needed. Test for malloc failure

strcpy(record.name,"www.foo.com");
record.type=1;
record.class=1;
record.ttl=8640;
FRAGMENT-2
strcpy(record.rdata,"100 10 s sip+e2u !http://[^/:](.*)!\1!iwww.foo.com");
record.rdlength=sizeof(record.rdata);

try your debugger (I can't believe I said that...). The rdata doesn't
seem to be in the same format as NAPTR...
hello!

this is not a text message please write "you" rather than "u"


no. What's "Domain Name"? I don't remeber you mentioning it before.
You seem to think I know something about DNS lookup or whatever it
is you are trying. I am only answering questions about standard C.

Well I had supposed that anyone who uses the net in this century would
surely know what a "domain name" is. It is nothing but a URL ( like
www.google.com ). My apologies.

perhaps I do, but I'm trying to answer questions about standard C

Isn't that what you had suggested? I suggest that you check your own
post.

I suggest you re-read the post. I (twice) stated that the data had to
be in the
right format.
I suppose "s" is not a string but a char?

what's "s"? Look if you tell printf() you've given it a char* (which is
an address)
and you've really given it a char then it will break.
Well I know I am confused that's why I thought I'd find some actual
help here and not some grammar lessons!

what grammar lesson. I just suggested you didn't use text-speak
abbreviations (i'm not the only one on this ng that doesn't like them).
Well, seems it's just as murky in here.

and there was thinking I was giving you help..
Frankly I don't either. However, that was just additional information
to clear up your confusion whether it was in the right format or not!

how did it help?


Thanks lot for the verbal help but no real solution?

you want me to write the code for you?
I will surely post the solution to this problem soon.

I think you should read my replies carefully. Then consult a good book
and r
e-read the section on pointers. I suspect you just one "ah! now I see"
from
working this out, but at the moment we just seem to be talking across
each other.
 
D

Default User

Nick said:
normally I would, but in this case I want to refer to things he
posted.

Things three screens up? I didn't see ANY reference to that stuff at
all. If you were responding to it, your reply should have been
immediately following that particular line or paragraph.



Brian
 
D

Dave Thompson

zoltan wrote:

It depends on how the data in rdata is structured.

rdata is a pointer to unsigned char, hiding the real data it holds.
You have to come up with a way to get that data into suitable C objects.

I didn't follow the links posted else-thread (where probably the rdata
structure is documented) so I'll just make it up:


rdata = "\x01\x02\x03\x04" /* order (32-bit unsigned int) */
"\x05\x06\x07\x08" /* preference (32-bit unsigned int) */
"\x41\x00" /* flags (NUL terminated string) */
"\x54\x43\x50\x00" /* services (NUL terminated string) */
"\x28\x2E\x2A\x29\x00" /* regexp (NUL terminated string) */
"\x3d\x00"; /* replacement (NUL terminated string) */

struct NAPTR data;
/* assuming `unsigned int` bit representation is LSB first */

Guesses wrong. (All nontextual?) Internet protocols like DNS use MSB
first, aka "network byte order". And DNS represents character-string
items with a prefix length byte/octet and no terminator. Although
domain names, and 'replacement' is actually a domain name, are
terminated by a null _label_ which consists of a single zero
byte/octet, looking sort of like a C character string. (Unless
compressed, and newer stds like 2915 prohibit compression.)

Aside: your data was only an example, but nowhere in IP is "TCP"
called a service; it's a protocol, particularly a next-layer protocol
from IP or ESP etc. Generally IP "services" are things that map to
WKports, like TELNET, FTP, NTP, etc. But the "services" in 2915 are
separate and distinct from those and off in their own little world.
data.order = rdata[0] + (rdata[1]<<8) + (rdata[2]<<16) + (rdata[3]<<24);
data.preference = rdata[4] + (rdata[5]<<8) + (rdata[6]<<16) + (rdata[7]<<24);

ObTopic: the left operand of << is implicitly promoted only to int or
in very rare systems unsigned int. If int is 16 bits, as is allowed,
this won't work; if int is 32 bits but signed << doesn't handle
overflow, as is allowed, ditto. You need to cast or otherwise convert
to (at least) uint32_least_t (C99) or unsigned long _before_ shifting.
data.flags = rdata+8;
data.services = data.flags + strlen(data.flags) + 1;
data.regexp = data.services + strlen(data.services) + 1;
data.replacement = data.regexp + strlen(data.regexp) + 1;

This data sharing depended on your mistaken assumption, without which
you can't just point into the rdata unless you (can afford to) clobber
bits of it; instead the OP will need to allocate space and copy these.
Or change the declaration to preallocate space in his struct directly.

- David.Thompson1 at worldnet.att.net
 
P

Pedro Graca

Dave said:
rdata is a pointer to unsigned char [...]

rdata = "\x01\x02\x03\x04" /* order (32-bit unsigned int) */ /* a few lines of bad assumptions snipped */
"\x3d\x00"; /* replacement (NUL terminated string) */

struct NAPTR data;

[snip internet protocols details for which I thank you]
data.order = rdata[0] + (rdata[1]<<8) + (rdata[2]<<16) + (rdata[3]<<24);

ObTopic: the left operand of << is implicitly promoted only to int or
in very rare systems unsigned int. If int is 16 bits, as is allowed,
this won't work; if int is 32 bits but signed << doesn't handle
overflow, as is allowed, ditto. You need to cast or otherwise convert
to (at least) uint32_least_t (C99) or unsigned long _before_ shifting.

Wow! "With C you *really* can shoot yourself in the foot easily".
Thank you for catching and, especially, for showing the error in that
construction.



[snip code with mistaken assumptions and your attention calling for it]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top