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