« May 2008
SunMonTueWedThuFriSat
    
1
2
3
4
5
6
7
8
9
10
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
       
Today
XML

Tom Haynes

loghyr.com
excfb.com

Blogs to Gander At

Navigation

Editing

AllMarks

Referers

Today's Page Hits: 560

Powered by Roller Weblogger.

statcounter.com

clustrmaps.com

Locations of visitors to this page

technorati.com

www.alesti.org

Add to Alesti RSS Reader

South Park as I was 10 years ago

South Park Fantasy

South Park today

South Park Reality

I have more hair and it isn't so grey. :->

10 years ago, really

Toon Tom

Today, literally

Tom Today

Site notes

This page validates as XHTML 1.0, and will look much better in a browser that supports web standards, but it is accessible to any browser or Internet device. It was created using techniques detailed at glish.com/css/.

« Second pass at the... | Main | Reading and storing... »
20080119 Saturday January 19, 2008
Reversing a network address from an uint_t

So mountd maps network addresses into unsigned integers. I want to map them back. My first pass at it fails:

% cat a.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>

int
main (int argc, char *argv[])
{
        char    *p = argv[1];
        uint_t  addr = 0;
        uint_t  rev;
        int     i;
        char    sep = ' ';

        for (i = 0; i < 4; i++) {
                addr |= atoi(p) << ((3-i) * 8);
                p = strchr(p, '.');
                if (p == NULL)
                        break;
                p++;
        }

        printf("%s yields %u and that reverse maps to ", argv[1], addr);

        for (i = 0; i < 4; i++) {
                rev = addr >> ((3-i) * 8);
                printf("%c%u", sep, rev);
                sep = '.';
        }

        printf("\n");

        return (0);
}
% ./a.out 192.168.1.2
192.168.1.2 yields 3232235778 and that reverse maps to  192.49320.12625921.3232235776

We see the idea works in that it gets the first octet correct. If we were to mask each octet again, it would probably also work.

The next simple approach also fails:

        printf("%u.%u.%u.%u\n", addr & 0xff000000, addr & 0x00ff0000,
                addr & 0x0000ff00, addr & 0x000000ff);

as this shows

./a.out 192.168.1.256
192.168.1.256 yields 3232235776 and that reverse maps to 3221225472.11010048.256.0

This gets us the right number, but it keeps it too far out. We need to get the right number and then shift it back down. (Note my earlier comment about remasking in the first approach):

        for (i = 0; i < 4; i++) {
                shift = ((3-i) * 8);

                rev = (addr & (0xff << shift)) >> shift;

                printf("%c%u", sep, rev);
                sep = '.';
        }

We are close, oh so close:

./a.out 192.168.1.256
192.168.1.256 yields 3232235776 and that reverse maps to  192.168.1.0

Perhaps we are really there, look at the ip I gave, it is invalid. :-> What does valid input yield?

% ./a.out 192.168.1.255
192.168.1.255 yields 3232236031 and that reverse maps to  192.168.1.255
% ./a.out 192.168.1.2
192.168.1.2 yields 3232235778 and that reverse maps to  192.168.1.2
% ./a.out 192.168.1.3
192.168.1.3 yields 3232235779 and that reverse maps to  192.168.1.3
% ./a.out 192.168.1.4
192.168.1.4 yields 3232235780 and that reverse maps to  192.168.1.4
% ./a.out 192.168.1.0
192.168.1.0 yields 3232235776 and that reverse maps to  192.168.1.0

So, even when prototyping, you should be doing some validity checking. I might have spent a chunk of time trying to fix code that was really working. I grabbed that test case from my command line history. It was the first that looked correct. We can add some simple checking in the first loop:

        for (i = 0; i < 4; i++) {
                t = strtol(p, &junk, 10) << ((3-i) * 8);
                if (junk && junk[0] != '.') {
                        fprintf(stderr, "%s is wrong in the %d octet,"
                                " %s has non-digits as %s\n", argv[1],
                                4-i, p, junk);
                        exit (-1);
                } else if (rev > 255 || t < 0) {
                        fprintf(stderr, "%s is wrong in the %d octet,"
                                " %d is out of range\n", argv[1],
                                4-i, t);
                        exit (-1);
                }

                addr |= t;

Which yields this incorrect result:

% ./a.out 192.168.1.1
192.168.1.1 is wrong in the 1 octet, -1073741824 is out of range

Took me a while to realize I was shifting too early. This fix:

                t = strtol(p, &junk, 10);
                if (junk && junk[0] != '.' && junk[0] != '\0') {
...
                addr |= t << ((3-i) * 8);

works:

% ./a.out 192.168.1.1
192.168.1.1 yields 3232235777 and that reverse maps to  192.168.1.1
% ./a.out 192.168.1aa.1
192.168.1aa.1 is wrong in the 3 octet, 1aa.1 has non-digits as |aa.1|
% ./a.out 192.168.1.256
192.168.1.256 is wrong in the 4 octet, 256 is out of range

Note that I had to change the junk check because strtol(3C) will return a pointer to the EOS. Which I had never hit before in coding - it seems counterintuitive.

In editing this, I noticed that the first approach was actually very close to being correct and a simple change would have sufficed:

        for (i = 0; i < 4; i++) {
                rev = (addr >> ((3-i) * 8)) & 0xff;

                printf("%c%u", sep, rev);
                sep = '.';
        }

This change makes use of the fact we know exactly which bits we want to mask off. It removes another shifting operation and would be preferred over the other final solution.

So I now have the ability to store the attribute-expressions as parse trees and convert those back to human readable rules. This will allow me to not store the string representation. As a bonus, I've also got most of the network error checking ready to add to the prototype.


Originally posted on Kool Aid Served Daily
Copyright (C) 2008, Kool Aid Served Daily

Trackback URL: http://blogs.sun.com/tdh/entry/reversing_a_network_address_from
Comments:

Post a Comment:

Name:
E-Mail:
URL:

Your Comment:

HTML Syntax: NOT allowed
Copyright (C) 2007, Kool Aid Served Daily