cc++11dhcp

Any builtin C/C++ library functions to encode domain names to DHCP option code 119 domain-search list?


Any builtin C/C++ library functions to encode domain names to DHCP option code 119 domain-search list

Example: I want to convert "google.com" to "0x06'google'0x03'com'0x00"

Any sample optimised programs would help too.


Solution

  • Here is an example implementation:

    #define _GNU_SOURCE
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    void compress(char **data, size_t *data_len, const char *domain) {
        char *tmp = realloc(*data, *data_len + 1 + strlen(domain) + 1);
        if(!tmp) {
            printf("realloc failed\n");
            return;
        }
        *data = tmp;
        size_t old_data_len = *data_len;
        for(size_t j = 0;;) {
            const char *sep = strchr(domain + j, '.');
            size_t len = sep ? sep - domain - j : strlen(domain + j);
            if(len > 255) {
                printf("TBD: long labels\n");
                return;
            }
            (*data)[*data_len] = len;
            strncpy(*data + *data_len + 1, domain + j, len);
            j += len + 1;
            *data_len += 1 + len;
            if(!sep) {
                (*data)[(*data_len)++] = '\0';
                break;
            }
        }
        // Can we compress the string by using a pointer?
        for(size_t j = old_data_len; j < *data_len; ) {
            char *p = memmem(*data, old_data_len, *data + j, *data_len - j);
            if(p) {
                if(*data - p > 0x3f) {
                    printf("overflow\n");
                    return;
                }
                (*data)[j] = 0xc0 | (*data - p);
                *data_len = j + 1;
                char *tmp = realloc(*data, *data_len);
                if(!tmp) {
                    printf("realloc failed\n");
                    return;
                }
                *data = tmp;
                break;
            }
            j += 1 + (*data)[j];
        }
    }
    
    
    int main() {
        char *data = NULL;
        size_t data_len = 0;
        compress(&data, &data_len, "example.com");
        compress(&data, &data_len, "www.example.com");
        write(STDOUT_FILENO, data, data_len);
        free(data);
    }
    

    and the result is:

    $ ./a.out | od -c
    0000000  \a   e   x   a   m   p   l   e 003   c   o   m  \0 003   w   w
    0000020   w 300
    0000022
    

    You could optimize this by having caller allocate a sufficient amount of memory (stack or heap) then if heap realloc when compress is done. I have not measured it but it's possible searching for the pointer is faster by looking at each successive labels in reverse. You would probably need a size_t[] with a length of each net string to do so. The benefit is that no match returns with a single call to memmem() instead of 3ish.

    For DHCP, you split the data into blocks of option_length and prefix each block with two bytes { 119, option_length }.